summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--configure.ac310
-rw-r--r--plugins/Makefile.am11
-rw-r--r--plugins/apihashing/Makefile.am65
-rw-r--r--plugins/apihashing/apihash.c134
-rw-r--r--plugins/apihashing/apihash.h55
-rw-r--r--plugins/apihashing/classics/Makefile.am14
-rw-r--r--plugins/apihashing/classics/crc32.c332
-rw-r--r--plugins/apihashing/classics/crc32.h58
-rw-r--r--plugins/apihashing/classics/djb2.c323
-rw-r--r--plugins/apihashing/classics/djb2.h58
-rw-r--r--plugins/apihashing/classics/ror13.c323
-rw-r--r--plugins/apihashing/classics/ror13.h58
-rw-r--r--plugins/apihashing/core.c110
-rw-r--r--plugins/apihashing/core.h38
-rw-r--r--plugins/apihashing/custom/Makefile.am18
-rw-r--r--plugins/apihashing/custom/add1505-shl5.c325
-rw-r--r--plugins/apihashing/custom/add1505-shl5.h58
-rw-r--r--plugins/apihashing/custom/enigma-murmur.c377
-rw-r--r--plugins/apihashing/custom/enigma-murmur.h58
-rw-r--r--plugins/apihashing/custom/imul21-add.c326
-rw-r--r--plugins/apihashing/custom/imul21-add.h58
-rw-r--r--plugins/apihashing/custom/imul83-add.c326
-rw-r--r--plugins/apihashing/custom/imul83-add.h58
-rw-r--r--plugins/apihashing/custom/sll1-add-hash32.c326
-rw-r--r--plugins/apihashing/custom/sll1-add-hash32.h58
-rw-r--r--plugins/apihashing/custom/sub-index1.c291
-rw-r--r--plugins/apihashing/custom/sub-index1.h58
-rw-r--r--plugins/apihashing/custom/sub42.c291
-rw-r--r--plugins/apihashing/custom/sub42.h58
-rw-r--r--plugins/apihashing/python/Makefile.am20
-rw-r--r--plugins/apihashing/python/apihash.c212
-rw-r--r--plugins/apihashing/python/apihash.h45
-rw-r--r--plugins/apihashing/python/classics/Makefile.am16
-rw-r--r--plugins/apihashing/python/classics/crc32.c211
-rw-r--r--plugins/apihashing/python/classics/crc32.h45
-rw-r--r--plugins/apihashing/python/classics/djb2.c211
-rw-r--r--plugins/apihashing/python/classics/djb2.h45
-rw-r--r--plugins/apihashing/python/classics/module.c68
-rw-r--r--plugins/apihashing/python/classics/module.h38
-rw-r--r--plugins/apihashing/python/classics/ror13.c211
-rw-r--r--plugins/apihashing/python/classics/ror13.h45
-rw-r--r--plugins/apihashing/python/custom/Makefile.am20
-rw-r--r--plugins/apihashing/python/custom/add1505-shl5.c211
-rw-r--r--plugins/apihashing/python/custom/add1505-shl5.h45
-rw-r--r--plugins/apihashing/python/custom/enigma-murmur.c211
-rw-r--r--plugins/apihashing/python/custom/enigma-murmur.h45
-rw-r--r--plugins/apihashing/python/custom/imul21-add.c211
-rw-r--r--plugins/apihashing/python/custom/imul21-add.h45
-rw-r--r--plugins/apihashing/python/custom/imul83-add.c211
-rw-r--r--plugins/apihashing/python/custom/imul83-add.h45
-rw-r--r--plugins/apihashing/python/custom/module.c76
-rw-r--r--plugins/apihashing/python/custom/module.h38
-rw-r--r--plugins/apihashing/python/custom/sll1-add-hash32.c211
-rw-r--r--plugins/apihashing/python/custom/sll1-add-hash32.h45
-rw-r--r--plugins/apihashing/python/custom/sub-index1.c213
-rw-r--r--plugins/apihashing/python/custom/sub-index1.h45
-rw-r--r--plugins/apihashing/python/custom/sub42.c212
-rw-r--r--plugins/apihashing/python/custom/sub42.h45
-rw-r--r--plugins/apihashing/python/module.c87
-rw-r--r--plugins/apihashing/python/module.h38
-rw-r--r--plugins/arm/Makefile.am33
-rw-r--r--plugins/arm/core.c7
-rw-r--r--plugins/arm/python/Makefile.am16
-rw-r--r--plugins/arm/python/instruction.c12
-rw-r--r--plugins/arm/python/processor.c9
-rw-r--r--plugins/arm/python/v7/Makefile.am15
-rw-r--r--plugins/arm/python/v7/instruction.c11
-rw-r--r--plugins/arm/python/v7/processor.c10
-rw-r--r--plugins/arm/v7/Makefile.am45
-rw-r--r--plugins/arm/v7/opcodes/Makefile.am7
-rw-r--r--plugins/arm/v7/operands/Makefile.am27
-rw-r--r--plugins/arm/v7/operands/estate.c2
-rw-r--r--plugins/arm/v7/operands/iflags.c2
-rw-r--r--plugins/arm/v7/operands/it.c2
-rw-r--r--plugins/arm/v7/operands/limitation.c2
-rw-r--r--plugins/arm/v7/operands/maccess.c2
-rw-r--r--plugins/arm/v7/operands/offset.c2
-rw-r--r--plugins/arm/v7/operands/register.c2
-rw-r--r--plugins/arm/v7/operands/reglist.c2
-rw-r--r--plugins/arm/v7/operands/rotation.c2
-rw-r--r--plugins/arm/v7/operands/shift.c2
-rw-r--r--plugins/arm/v7/registers/Makefile.am17
-rw-r--r--plugins/arm/v7/registers/banked.c2
-rw-r--r--plugins/arm/v7/registers/basic.c2
-rw-r--r--plugins/arm/v7/registers/coproc.c2
-rw-r--r--plugins/arm/v7/registers/simd.c2
-rw-r--r--plugins/arm/v7/registers/special.c2
-rw-r--r--plugins/bhash/Makefile.am8
-rw-r--r--plugins/bhash/core.c7
-rw-r--r--plugins/bhash/python/Makefile.am17
-rw-r--r--plugins/bootimg/Makefile.am16
-rw-r--r--plugins/bootimg/core.c7
-rw-r--r--plugins/bootimg/python/Makefile.am15
-rw-r--r--plugins/bootimg/python/format.c7
-rw-r--r--plugins/dalvik/Makefile.am39
-rw-r--r--plugins/dalvik/context.c4
-rw-r--r--plugins/dalvik/context.h2
-rw-r--r--plugins/dalvik/core.c7
-rw-r--r--plugins/dalvik/operands/Makefile.am16
-rw-r--r--plugins/dalvik/operands/args.c2
-rw-r--r--plugins/dalvik/operands/pool.c2
-rw-r--r--plugins/dalvik/pseudo/Makefile.am13
-rw-r--r--plugins/dalvik/python/Makefile.am16
-rw-r--r--plugins/dalvik/python/instruction.c5
-rw-r--r--plugins/dalvik/python/processor.c5
-rw-r--r--plugins/dalvik/python/v35/Makefile.am15
-rw-r--r--plugins/dalvik/python/v35/instruction.c5
-rw-r--r--plugins/dalvik/python/v35/processor.c5
-rw-r--r--plugins/dalvik/register.c2
-rw-r--r--plugins/dalvik/v35/Makefile.am17
-rw-r--r--plugins/dalvik/v35/opcodes/Makefile.am7
-rw-r--r--plugins/devdbg/Makefile.am9
-rw-r--r--plugins/dex/Makefile.am28
-rw-r--r--plugins/dex/core.c7
-rw-r--r--plugins/dex/loading.h4
-rw-r--r--plugins/dex/python/Makefile.am27
-rw-r--r--plugins/dex/python/class.c6
-rw-r--r--plugins/dex/python/field.c6
-rw-r--r--plugins/dex/python/format.c5
-rw-r--r--plugins/dex/python/method.c6
-rw-r--r--plugins/dex/python/pool.c2
-rw-r--r--plugins/dex/python/routine.c5
-rw-r--r--plugins/dexbnf/Makefile.am20
-rw-r--r--plugins/dexbnf/core.c7
-rw-r--r--plugins/dexbnf/python/Makefile.am13
-rw-r--r--plugins/dexbnf/python/demangler.c10
-rw-r--r--plugins/dwarf/Makefile.am30
-rw-r--r--plugins/dwarf/core.c3
-rw-r--r--plugins/dwarf/info.h1
-rw-r--r--plugins/dwarf/v2/Makefile.am9
-rw-r--r--plugins/dwarf/v3/Makefile.am9
-rw-r--r--plugins/dwarf/v4/Makefile.am9
-rw-r--r--plugins/elf/Makefile.am32
-rw-r--r--plugins/elf/core.c7
-rw-r--r--plugins/elf/loading.h2
-rw-r--r--plugins/elf/python/Makefile.am25
-rw-r--r--plugins/elf/python/format.c12
-rw-r--r--plugins/elf/strings.h2
-rw-r--r--plugins/elf/symbols.h2
-rw-r--r--plugins/encodings/Makefile.am64
-rw-r--r--plugins/encodings/base64.c139
-rw-r--r--plugins/encodings/base64.h43
-rw-r--r--plugins/encodings/core.c89
-rw-r--r--plugins/encodings/core.h38
-rw-r--r--plugins/encodings/python/Makefile.am21
-rw-r--r--plugins/encodings/python/base64.c139
-rw-r--r--plugins/encodings/python/base64.h39
-rw-r--r--plugins/encodings/python/module.c87
-rw-r--r--plugins/encodings/python/module.h38
-rw-r--r--plugins/encodings/python/rost/Makefile.am15
-rw-r--r--plugins/encodings/python/rost/base64.c211
-rw-r--r--plugins/encodings/python/rost/base64.h45
-rw-r--r--plugins/encodings/python/rost/module.c64
-rw-r--r--plugins/encodings/python/rost/module.h38
-rw-r--r--plugins/encodings/rost/Makefile.am12
-rw-r--r--plugins/encodings/rost/base64.c555
-rw-r--r--plugins/encodings/rost/base64.h58
-rw-r--r--plugins/fmtp/Makefile.am11
-rw-r--r--plugins/gdbrsp/python/gdb.c5
-rw-r--r--plugins/itanium/Makefile.am20
-rw-r--r--plugins/itanium/core.c7
-rw-r--r--plugins/itanium/python/Makefile.am13
-rw-r--r--plugins/itanium/python/demangler.c10
-rw-r--r--plugins/java/Makefile.am7
-rw-r--r--plugins/javadesc/Makefile.am18
-rw-r--r--plugins/javadesc/core.c7
-rw-r--r--plugins/javadesc/python/Makefile.am13
-rw-r--r--plugins/javadesc/python/demangler.c10
-rw-r--r--plugins/kaitai/Makefile.am93
-rw-r--r--plugins/kaitai/array-int.h51
-rw-r--r--plugins/kaitai/array.c376
-rw-r--r--plugins/kaitai/array.h76
-rw-r--r--plugins/kaitai/core.c81
-rw-r--r--plugins/kaitai/core.h38
-rw-r--r--plugins/kaitai/expression.h134
-rw-r--r--plugins/kaitai/grammar.y1919
-rw-r--r--plugins/kaitai/import.c300
-rw-r--r--plugins/kaitai/import.h41
-rw-r--r--plugins/kaitai/parser-int.h55
-rw-r--r--plugins/kaitai/parser.c166
-rw-r--r--plugins/kaitai/parser.h63
-rw-r--r--plugins/kaitai/parsers/Makefile.am25
-rw-r--r--plugins/kaitai/parsers/attribute-int.h107
-rw-r--r--plugins/kaitai/parsers/attribute.c2213
-rw-r--r--plugins/kaitai/parsers/attribute.h158
-rw-r--r--plugins/kaitai/parsers/enum-int.h79
-rw-r--r--plugins/kaitai/parsers/enum.c765
-rw-r--r--plugins/kaitai/parsers/enum.h76
-rw-r--r--plugins/kaitai/parsers/instance-int.h59
-rw-r--r--plugins/kaitai/parsers/instance.c503
-rw-r--r--plugins/kaitai/parsers/instance.h71
-rw-r--r--plugins/kaitai/parsers/meta-int.h60
-rw-r--r--plugins/kaitai/parsers/meta.c (renamed from plugins/yaml/line.c)325
-rw-r--r--plugins/kaitai/parsers/meta.h71
-rw-r--r--plugins/kaitai/parsers/struct-int.h77
-rw-r--r--plugins/kaitai/parsers/struct.c837
-rw-r--r--plugins/kaitai/parsers/struct.h80
-rw-r--r--plugins/kaitai/parsers/switch-int.h78
-rw-r--r--plugins/kaitai/parsers/switch.c644
-rw-r--r--plugins/kaitai/parsers/switch.h61
-rw-r--r--plugins/kaitai/parsers/type-int.h58
-rw-r--r--plugins/kaitai/parsers/type.c (renamed from plugins/yaml/reader.c)276
-rw-r--r--plugins/kaitai/parsers/type.h65
-rw-r--r--plugins/kaitai/python/Makefile.am26
-rw-r--r--plugins/kaitai/python/array.c265
-rw-r--r--plugins/kaitai/python/array.h45
-rw-r--r--plugins/kaitai/python/module.c135
-rw-r--r--plugins/kaitai/python/module.h41
-rw-r--r--plugins/kaitai/python/parser.c205
-rw-r--r--plugins/kaitai/python/parser.h (renamed from plugins/yaml/python/reader.h)18
-rw-r--r--plugins/kaitai/python/parsers/Makefile.am19
-rw-r--r--plugins/kaitai/python/parsers/attribute.c425
-rw-r--r--plugins/kaitai/python/parsers/attribute.h45
-rw-r--r--plugins/kaitai/python/parsers/enum.c468
-rw-r--r--plugins/kaitai/python/parsers/enum.h45
-rw-r--r--plugins/kaitai/python/parsers/instance.c280
-rw-r--r--plugins/kaitai/python/parsers/instance.h45
-rw-r--r--plugins/kaitai/python/parsers/meta.c414
-rw-r--r--plugins/kaitai/python/parsers/meta.h (renamed from plugins/yaml/python/scalar.h)18
-rw-r--r--plugins/kaitai/python/parsers/module.c124
-rw-r--r--plugins/kaitai/python/parsers/module.h41
-rw-r--r--plugins/kaitai/python/parsers/struct.c376
-rw-r--r--plugins/kaitai/python/parsers/struct.h45
-rw-r--r--plugins/kaitai/python/parsers/type.c278
-rw-r--r--plugins/kaitai/python/parsers/type.h45
-rw-r--r--plugins/kaitai/python/record.c (renamed from plugins/yaml/python/line.c)338
-rw-r--r--plugins/kaitai/python/record.h (renamed from plugins/yaml/python/tree.h)18
-rw-r--r--plugins/kaitai/python/records/Makefile.am19
-rw-r--r--plugins/kaitai/python/records/bits.c318
-rw-r--r--plugins/kaitai/python/records/bits.h45
-rw-r--r--plugins/kaitai/python/records/delayed.c341
-rw-r--r--plugins/kaitai/python/records/delayed.h45
-rw-r--r--plugins/kaitai/python/records/empty.c286
-rw-r--r--plugins/kaitai/python/records/empty.h45
-rw-r--r--plugins/kaitai/python/records/group.c305
-rw-r--r--plugins/kaitai/python/records/group.h45
-rw-r--r--plugins/kaitai/python/records/item.c394
-rw-r--r--plugins/kaitai/python/records/item.h (renamed from plugins/yaml/python/line.h)18
-rw-r--r--plugins/kaitai/python/records/list.c (renamed from plugins/yaml/python/scalar.c)248
-rw-r--r--plugins/kaitai/python/records/list.h45
-rw-r--r--plugins/kaitai/python/records/module.c124
-rw-r--r--plugins/kaitai/python/records/module.h41
-rw-r--r--plugins/kaitai/python/rost/Makefile.am14
-rw-r--r--plugins/kaitai/python/rost/module.c115
-rw-r--r--plugins/kaitai/python/rost/module.h41
-rw-r--r--plugins/kaitai/python/rost/trigger.c236
-rw-r--r--plugins/kaitai/python/rost/trigger.h45
-rw-r--r--plugins/kaitai/python/scope.c542
-rw-r--r--plugins/kaitai/python/scope.h51
-rw-r--r--plugins/kaitai/python/stream.c278
-rw-r--r--plugins/kaitai/python/stream.h45
-rw-r--r--plugins/kaitai/record-int.h73
-rw-r--r--plugins/kaitai/record.c416
-rw-r--r--plugins/kaitai/record.h88
-rw-r--r--plugins/kaitai/records/Makefile.am23
-rw-r--r--plugins/kaitai/records/bits-int.h59
-rw-r--r--plugins/kaitai/records/bits.c283
-rw-r--r--plugins/kaitai/records/bits.h62
-rw-r--r--plugins/kaitai/records/delayed-int.h60
-rw-r--r--plugins/kaitai/records/delayed.c352
-rw-r--r--plugins/kaitai/records/delayed.h65
-rw-r--r--plugins/kaitai/records/empty-int.h57
-rw-r--r--plugins/kaitai/records/empty.c236
-rw-r--r--plugins/kaitai/records/empty.h58
-rw-r--r--plugins/kaitai/records/group-int.h58
-rw-r--r--plugins/kaitai/records/group.c382
-rw-r--r--plugins/kaitai/records/group.h65
-rw-r--r--plugins/kaitai/records/item-int.h58
-rw-r--r--plugins/kaitai/records/item.c (renamed from plugins/yaml/scalar.c)293
-rw-r--r--plugins/kaitai/records/item.h65
-rw-r--r--plugins/kaitai/records/list-int.h60
-rw-r--r--plugins/kaitai/records/list.c424
-rw-r--r--plugins/kaitai/records/list.h71
-rw-r--r--plugins/kaitai/rost/Makefile.am18
-rw-r--r--plugins/kaitai/rost/browser-int.h58
-rw-r--r--plugins/kaitai/rost/browser.c478
-rw-r--r--plugins/kaitai/rost/browser.h58
-rw-r--r--plugins/kaitai/rost/core.c66
-rw-r--r--plugins/kaitai/rost/core.h37
-rw-r--r--plugins/kaitai/rost/space-int.h55
-rw-r--r--plugins/kaitai/rost/space.c254
-rw-r--r--plugins/kaitai/rost/space.h59
-rw-r--r--plugins/kaitai/rost/trigger-int.h59
-rw-r--r--plugins/kaitai/rost/trigger.c320
-rw-r--r--plugins/kaitai/rost/trigger.h61
-rw-r--r--plugins/kaitai/scope.c257
-rw-r--r--plugins/kaitai/scope.h72
-rw-r--r--plugins/kaitai/stream-int.h55
-rw-r--r--plugins/kaitai/stream.c237
-rw-r--r--plugins/kaitai/stream.h65
-rw-r--r--plugins/kaitai/tokens.l329
-rw-r--r--plugins/libcsem/Makefile.am11
-rw-r--r--plugins/lnxsyscalls/Makefile.am25
-rw-r--r--plugins/lnxsyscalls/hunter.h2
-rw-r--r--plugins/mobicore/Makefile.am17
-rw-r--r--plugins/pe/Makefile.am24
-rw-r--r--plugins/pe/core.c7
-rw-r--r--plugins/pe/python/Makefile.am20
-rw-r--r--plugins/pe/python/format.c7
-rw-r--r--plugins/pe/python/routine.c8
-rw-r--r--plugins/pe/symbols.h2
-rw-r--r--plugins/pychrysalide/Makefile.am66
-rw-r--r--plugins/pychrysalide/analysis/Makefile.am35
-rw-r--r--plugins/pychrysalide/analysis/binary.c2
-rw-r--r--plugins/pychrysalide/analysis/block.c4
-rw-r--r--plugins/pychrysalide/analysis/cattribs.c2
-rw-r--r--plugins/pychrysalide/analysis/content.c87
-rw-r--r--plugins/pychrysalide/analysis/contents/Makefile.am19
-rw-r--r--plugins/pychrysalide/analysis/contents/encapsulated.c52
-rw-r--r--plugins/pychrysalide/analysis/contents/file.c52
-rw-r--r--plugins/pychrysalide/analysis/contents/memory.c54
-rw-r--r--plugins/pychrysalide/analysis/contents/restricted.c55
-rw-r--r--plugins/pychrysalide/analysis/db/Makefile.am28
-rw-r--r--plugins/pychrysalide/analysis/db/admin.c10
-rw-r--r--plugins/pychrysalide/analysis/db/analyst.c8
-rw-r--r--plugins/pychrysalide/analysis/db/client.c2
-rw-r--r--plugins/pychrysalide/analysis/db/collection.c2
-rw-r--r--plugins/pychrysalide/analysis/db/item.c2
-rw-r--r--plugins/pychrysalide/analysis/db/items/Makefile.am19
-rw-r--r--plugins/pychrysalide/analysis/db/items/bookmark.c8
-rw-r--r--plugins/pychrysalide/analysis/db/items/comment.c8
-rw-r--r--plugins/pychrysalide/analysis/db/items/switcher.c8
-rw-r--r--plugins/pychrysalide/analysis/db/server.c2
-rw-r--r--plugins/pychrysalide/analysis/disass/Makefile.am15
-rw-r--r--plugins/pychrysalide/analysis/disass/block.c5
-rw-r--r--plugins/pychrysalide/analysis/loaded.c32
-rw-r--r--plugins/pychrysalide/analysis/loading.c4
-rw-r--r--plugins/pychrysalide/analysis/module.c3
-rw-r--r--plugins/pychrysalide/analysis/project.c2
-rw-r--r--plugins/pychrysalide/analysis/routine.c2
-rw-r--r--plugins/pychrysalide/analysis/scan/Makefile.am28
-rw-r--r--plugins/pychrysalide/analysis/scan/constants.c128
-rw-r--r--plugins/pychrysalide/analysis/scan/constants.h42
-rw-r--r--plugins/pychrysalide/analysis/scan/context.c432
-rw-r--r--plugins/pychrysalide/analysis/scan/context.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/core.c179
-rw-r--r--plugins/pychrysalide/analysis/scan/core.h39
-rw-r--r--plugins/pychrysalide/analysis/scan/expr.c393
-rw-r--r--plugins/pychrysalide/analysis/scan/expr.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/exprs/Makefile.am15
-rw-r--r--plugins/pychrysalide/analysis/scan/exprs/constants.c128
-rw-r--r--plugins/pychrysalide/analysis/scan/exprs/constants.h42
-rw-r--r--plugins/pychrysalide/analysis/scan/exprs/literal.c281
-rw-r--r--plugins/pychrysalide/analysis/scan/exprs/literal.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/exprs/module.c103
-rw-r--r--plugins/pychrysalide/analysis/scan/exprs/module.h42
-rw-r--r--plugins/pychrysalide/analysis/scan/item.c740
-rw-r--r--plugins/pychrysalide/analysis/scan/item.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/module.c125
-rw-r--r--plugins/pychrysalide/analysis/scan/module.h42
-rw-r--r--plugins/pychrysalide/analysis/scan/options.c511
-rw-r--r--plugins/pychrysalide/analysis/scan/options.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/Makefile.am22
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backend.c202
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backend.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am15
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backends/acism.c214
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backends/acism.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c214
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backends/module.c106
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/backends/module.h42
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifier.c416
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifier.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am18
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c211
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c320
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c112
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h42
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c211
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c211
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c210
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/module.c114
-rw-r--r--plugins/pychrysalide/analysis/scan/patterns/module.h42
-rw-r--r--plugins/pychrysalide/analysis/scan/scanner.c487
-rw-r--r--plugins/pychrysalide/analysis/scan/scanner.h45
-rw-r--r--plugins/pychrysalide/analysis/scan/space.c283
-rw-r--r--plugins/pychrysalide/analysis/scan/space.h45
-rw-r--r--plugins/pychrysalide/analysis/storage/Makefile.am13
-rw-r--r--plugins/pychrysalide/analysis/storage/cache.c4
-rw-r--r--plugins/pychrysalide/analysis/storage/storage.c4
-rw-r--r--plugins/pychrysalide/analysis/storage/tpmem.c4
-rw-r--r--plugins/pychrysalide/analysis/type.c4
-rw-r--r--plugins/pychrysalide/analysis/types/Makefile.am33
-rw-r--r--plugins/pychrysalide/analysis/types/array.c2
-rw-r--r--plugins/pychrysalide/analysis/types/basic.c2
-rw-r--r--plugins/pychrysalide/analysis/types/cse.c2
-rw-r--r--plugins/pychrysalide/analysis/types/encaps.c2
-rw-r--r--plugins/pychrysalide/analysis/types/expr.c2
-rw-r--r--plugins/pychrysalide/analysis/types/literal.c2
-rw-r--r--plugins/pychrysalide/analysis/types/override.c2
-rw-r--r--plugins/pychrysalide/analysis/types/proto.c2
-rw-r--r--plugins/pychrysalide/analysis/types/template.c2
-rw-r--r--plugins/pychrysalide/analysis/variable.c2
-rw-r--r--plugins/pychrysalide/arch/Makefile.am28
-rw-r--r--plugins/pychrysalide/arch/context.c10
-rw-r--r--plugins/pychrysalide/arch/instruction.c282
-rw-r--r--plugins/pychrysalide/arch/instructions/Makefile.am19
-rw-r--r--plugins/pychrysalide/arch/instructions/raw.c4
-rw-r--r--plugins/pychrysalide/arch/instructions/undefined.c4
-rw-r--r--plugins/pychrysalide/arch/operand.c18
-rw-r--r--plugins/pychrysalide/arch/operands/Makefile.am33
-rw-r--r--plugins/pychrysalide/arch/operands/immediate.c2
-rw-r--r--plugins/pychrysalide/arch/operands/known.c2
-rw-r--r--plugins/pychrysalide/arch/operands/proxy.c7
-rw-r--r--plugins/pychrysalide/arch/operands/register.c7
-rw-r--r--plugins/pychrysalide/arch/operands/target.c7
-rw-r--r--plugins/pychrysalide/arch/processor.c4
-rw-r--r--plugins/pychrysalide/arch/register.c4
-rw-r--r--plugins/pychrysalide/common/Makefile.am26
-rw-r--r--plugins/pychrysalide/common/bits.c245
-rw-r--r--plugins/pychrysalide/common/bits.h3
-rw-r--r--plugins/pychrysalide/common/itoa.c124
-rw-r--r--plugins/pychrysalide/common/itoa.h39
-rw-r--r--plugins/pychrysalide/common/module.c2
-rw-r--r--plugins/pychrysalide/core.c167
-rw-r--r--plugins/pychrysalide/core/Makefile.am25
-rw-r--r--plugins/pychrysalide/core/global.c47
-rw-r--r--plugins/pychrysalide/debug/Makefile.am17
-rw-r--r--plugins/pychrysalide/debug/debugger.c2
-rw-r--r--plugins/pychrysalide/format/Makefile.am32
-rw-r--r--plugins/pychrysalide/format/executable.c2
-rw-r--r--plugins/pychrysalide/format/flat.c2
-rw-r--r--plugins/pychrysalide/format/format.c4
-rw-r--r--plugins/pychrysalide/format/known.c4
-rw-r--r--plugins/pychrysalide/format/module.c2
-rw-r--r--plugins/pychrysalide/format/preload.c207
-rw-r--r--plugins/pychrysalide/format/preload.h45
-rw-r--r--plugins/pychrysalide/format/strsym.c4
-rw-r--r--plugins/pychrysalide/format/symbol.c4
-rw-r--r--plugins/pychrysalide/glibext/Makefile.am40
-rw-r--r--plugins/pychrysalide/glibext/binarycursor.c2
-rw-r--r--plugins/pychrysalide/glibext/binportion.c4
-rw-r--r--plugins/pychrysalide/glibext/buffercache.c16
-rw-r--r--plugins/pychrysalide/glibext/bufferline.c4
-rw-r--r--plugins/pychrysalide/glibext/bufferview.c2
-rw-r--r--plugins/pychrysalide/glibext/comparison.c341
-rw-r--r--plugins/pychrysalide/glibext/comparison.h45
-rw-r--r--plugins/pychrysalide/glibext/configuration.c8
-rw-r--r--plugins/pychrysalide/glibext/constants.c53
-rw-r--r--plugins/pychrysalide/glibext/constants.h7
-rw-r--r--plugins/pychrysalide/glibext/linecursor.c2
-rw-r--r--plugins/pychrysalide/glibext/module.c6
-rw-r--r--plugins/pychrysalide/glibext/singleton.c4
-rw-r--r--plugins/pychrysalide/gtkext/Makefile.am25
-rw-r--r--plugins/pychrysalide/gtkext/blockdisplay.c2
-rw-r--r--plugins/pychrysalide/gtkext/bufferdisplay.c2
-rw-r--r--plugins/pychrysalide/gtkext/displaypanel.c25
-rw-r--r--plugins/pychrysalide/gtkext/graph/Makefile.am17
-rw-r--r--plugins/pychrysalide/gtkext/graph/cluster.c2
-rw-r--r--plugins/pychrysalide/gtkext/graph/edge.c2
-rw-r--r--plugins/pychrysalide/gtkext/named.c4
-rw-r--r--plugins/pychrysalide/gui/Makefile.am22
-rw-r--r--plugins/pychrysalide/gui/core/Makefile.am17
-rw-r--r--plugins/pychrysalide/gui/item.c2
-rw-r--r--plugins/pychrysalide/gui/menubar.c5
-rw-r--r--plugins/pychrysalide/gui/panel.c5
-rw-r--r--plugins/pychrysalide/gui/panels/Makefile.am13
-rw-r--r--plugins/pychrysalide/helpers.c147
-rw-r--r--plugins/pychrysalide/helpers.h100
-rw-r--r--plugins/pychrysalide/mangling/Makefile.am17
-rw-r--r--plugins/pychrysalide/mangling/demangler.c4
-rw-r--r--plugins/pychrysalide/mangling/demangler.h2
-rw-r--r--plugins/pychrysalide/plugins/Makefile.am21
-rw-r--r--plugins/pychrysalide/plugins/plugin.c606
-rw-r--r--plugins/pychrysalide/plugins/plugin.h32
-rw-r--r--plugins/pychrysalide/weak.h6
-rw-r--r--plugins/python/scripting/core.py3
-rw-r--r--plugins/readdex/Makefile.am17
-rw-r--r--plugins/readdex/class.h2
-rw-r--r--plugins/readdex/ids.h2
-rw-r--r--plugins/readelf/Makefile.am18
-rw-r--r--plugins/readmc/Makefile.am19
-rw-r--r--plugins/ropgadgets/Makefile.am7
-rw-r--r--plugins/ropgadgets/plugin.c3
-rw-r--r--plugins/ropgadgets/select.c2
-rw-r--r--plugins/winordinals/Makefile.am6
-rw-r--r--plugins/winordinals/assign.h2
-rw-r--r--plugins/winordinals/core.c6
-rw-r--r--plugins/winordinals/python/Makefile.am9
-rw-r--r--plugins/yaml/Makefile.am15
-rw-r--r--plugins/yaml/collection-int.h60
-rw-r--r--plugins/yaml/collection.c164
-rw-r--r--plugins/yaml/collection.h19
-rw-r--r--plugins/yaml/core.c8
-rw-r--r--plugins/yaml/core.h2
-rw-r--r--plugins/yaml/line.h75
-rw-r--r--plugins/yaml/node-int.h20
-rw-r--r--plugins/yaml/node.c130
-rw-r--r--plugins/yaml/node.h23
-rw-r--r--plugins/yaml/pair-int.h66
-rw-r--r--plugins/yaml/pair.c427
-rw-r--r--plugins/yaml/pair.h28
-rw-r--r--plugins/yaml/parser.c299
-rw-r--r--plugins/yaml/parser.h43
-rw-r--r--plugins/yaml/python/Makefile.am15
-rw-r--r--plugins/yaml/python/collection.c81
-rw-r--r--plugins/yaml/python/collection.h6
-rw-r--r--plugins/yaml/python/constants.c127
-rw-r--r--plugins/yaml/python/constants.h42
-rw-r--r--plugins/yaml/python/module.c29
-rw-r--r--plugins/yaml/python/node.c199
-rw-r--r--plugins/yaml/python/node.h6
-rw-r--r--plugins/yaml/python/pair.c314
-rw-r--r--plugins/yaml/python/pair.h6
-rw-r--r--plugins/yaml/python/parser.c186
-rw-r--r--plugins/yaml/python/parser.h39
-rw-r--r--plugins/yaml/python/reader.c388
-rw-r--r--plugins/yaml/python/tree.c427
-rw-r--r--plugins/yaml/reader.h69
-rw-r--r--plugins/yaml/scalar.h72
-rw-r--r--plugins/yaml/tree.c421
-rw-r--r--plugins/yaml/tree.h69
-rw-r--r--src/Makefile.am106
-rw-r--r--src/analysis/Makefile.am11
-rw-r--r--src/analysis/binary.c36
-rw-r--r--src/analysis/block-int.h8
-rw-r--r--src/analysis/block.c10
-rw-r--r--src/analysis/block.h8
-rw-r--r--src/analysis/content-int.h29
-rw-r--r--src/analysis/content.c384
-rw-r--r--src/analysis/content.h23
-rw-r--r--src/analysis/contents/Makefile.am14
-rw-r--r--src/analysis/contents/encapsulated-int.h62
-rw-r--r--src/analysis/contents/encapsulated.c195
-rw-r--r--src/analysis/contents/file-int.h58
-rw-r--r--src/analysis/contents/file.c166
-rw-r--r--src/analysis/contents/memory-int.h12
-rw-r--r--src/analysis/contents/memory.c179
-rw-r--r--src/analysis/contents/restricted-int.h59
-rw-r--r--src/analysis/contents/restricted.c177
-rw-r--r--src/analysis/contents/restricted.h3
-rw-r--r--src/analysis/db/Makefile.am8
-rw-r--r--src/analysis/db/cdb.c2
-rw-r--r--src/analysis/db/items/Makefile.am11
-rw-r--r--src/analysis/db/items/comment.c2
-rw-r--r--src/analysis/db/items/move.c12
-rw-r--r--src/analysis/db/misc/Makefile.am11
-rw-r--r--src/analysis/disass/Makefile.am7
-rw-r--r--src/analysis/disass/area.h2
-rw-r--r--src/analysis/disass/block.c14
-rw-r--r--src/analysis/disass/disassembler.c6
-rw-r--r--src/analysis/disass/fetch.h2
-rw-r--r--src/analysis/disass/instructions.h2
-rw-r--r--src/analysis/disass/limit.c2
-rw-r--r--src/analysis/disass/output.h2
-rw-r--r--src/analysis/disass/routines.h2
-rw-r--r--src/analysis/human/Makefile.am8
-rw-r--r--src/analysis/human/asm/Makefile.am11
-rw-r--r--src/analysis/loaded-int.h8
-rw-r--r--src/analysis/loaded.c32
-rw-r--r--src/analysis/loaded.h16
-rw-r--r--src/analysis/project.c6
-rw-r--r--src/analysis/project.h8
-rw-r--r--src/analysis/routine.c7
-rw-r--r--src/analysis/routine.h3
-rw-r--r--src/analysis/scan/Makefile.am67
-rw-r--r--src/analysis/scan/cond-int.h63
-rw-r--r--src/analysis/scan/cond.c220
-rw-r--r--src/analysis/scan/cond.h65
-rw-r--r--src/analysis/scan/context-int.h100
-rw-r--r--src/analysis/scan/context.c841
-rw-r--r--src/analysis/scan/context.h111
-rw-r--r--src/analysis/scan/core.c385
-rw-r--r--src/analysis/scan/core.h53
-rw-r--r--src/analysis/scan/decl.h40
-rw-r--r--src/analysis/scan/expr-int.h88
-rw-r--r--src/analysis/scan/expr.c638
-rw-r--r--src/analysis/scan/expr.h89
-rw-r--r--src/analysis/scan/exprs/Makefile.am40
-rw-r--r--src/analysis/scan/exprs/access-int.h74
-rw-r--r--src/analysis/scan/exprs/access.c508
-rw-r--r--src/analysis/scan/exprs/access.h66
-rw-r--r--src/analysis/scan/exprs/arithmetic-int.h60
-rw-r--r--src/analysis/scan/exprs/arithmetic.c641
-rw-r--r--src/analysis/scan/exprs/arithmetic.h67
-rw-r--r--src/analysis/scan/exprs/call-int.h58
-rw-r--r--src/analysis/scan/exprs/call.c467
-rw-r--r--src/analysis/scan/exprs/call.h56
-rw-r--r--src/analysis/scan/exprs/extract-int.h57
-rw-r--r--src/analysis/scan/exprs/extract.c396
-rw-r--r--src/analysis/scan/exprs/extract.h56
-rw-r--r--src/analysis/scan/exprs/handler-int.h68
-rw-r--r--src/analysis/scan/exprs/handler.c622
-rw-r--r--src/analysis/scan/exprs/handler.h80
-rw-r--r--src/analysis/scan/exprs/intersect-int.h58
-rw-r--r--src/analysis/scan/exprs/intersect.c290
-rw-r--r--src/analysis/scan/exprs/intersect.h55
-rw-r--r--src/analysis/scan/exprs/item-int.h58
-rw-r--r--src/analysis/scan/exprs/item.c353
-rw-r--r--src/analysis/scan/exprs/item.h55
-rw-r--r--src/analysis/scan/exprs/literal-int.h71
-rw-r--r--src/analysis/scan/exprs/literal.c734
-rw-r--r--src/analysis/scan/exprs/literal.h90
-rw-r--r--src/analysis/scan/exprs/logical-int.h60
-rw-r--r--src/analysis/scan/exprs/logical.c518
-rw-r--r--src/analysis/scan/exprs/logical.h65
-rw-r--r--src/analysis/scan/exprs/range-int.h58
-rw-r--r--src/analysis/scan/exprs/range.c355
-rw-r--r--src/analysis/scan/exprs/range.h55
-rw-r--r--src/analysis/scan/exprs/relational-int.h60
-rw-r--r--src/analysis/scan/exprs/relational.c411
-rw-r--r--src/analysis/scan/exprs/relational.h56
-rw-r--r--src/analysis/scan/exprs/set-int.h58
-rw-r--r--src/analysis/scan/exprs/set.c407
-rw-r--r--src/analysis/scan/exprs/set.h58
-rw-r--r--src/analysis/scan/exprs/setcounter-int.h69
-rw-r--r--src/analysis/scan/exprs/setcounter.c477
-rw-r--r--src/analysis/scan/exprs/setcounter.h81
-rw-r--r--src/analysis/scan/exprs/strop-int.h62
-rw-r--r--src/analysis/scan/exprs/strop.c455
-rw-r--r--src/analysis/scan/exprs/strop.h67
-rw-r--r--src/analysis/scan/grammar.y1905
-rw-r--r--src/analysis/scan/item-int.h74
-rw-r--r--src/analysis/scan/item.c325
-rw-r--r--src/analysis/scan/item.h72
-rw-r--r--src/analysis/scan/items/Makefile.am37
-rw-r--r--src/analysis/scan/items/console/Makefile.am13
-rw-r--r--src/analysis/scan/items/console/log.c304
-rw-r--r--src/analysis/scan/items/console/log.h58
-rw-r--r--src/analysis/scan/items/count.c251
-rw-r--r--src/analysis/scan/items/count.h58
-rw-r--r--src/analysis/scan/items/datasize.c272
-rw-r--r--src/analysis/scan/items/datasize.h58
-rw-r--r--src/analysis/scan/items/magic/Makefile.am16
-rw-r--r--src/analysis/scan/items/magic/cookie.c122
-rw-r--r--src/analysis/scan/items/magic/cookie.h44
-rw-r--r--src/analysis/scan/items/magic/mime-encoding.c270
-rw-r--r--src/analysis/scan/items/magic/mime-encoding.h58
-rw-r--r--src/analysis/scan/items/magic/mime-type.c270
-rw-r--r--src/analysis/scan/items/magic/mime-type.h58
-rw-r--r--src/analysis/scan/items/magic/type.c270
-rw-r--r--src/analysis/scan/items/magic/type.h58
-rw-r--r--src/analysis/scan/items/math/Makefile.am13
-rw-r--r--src/analysis/scan/items/math/to_string.c381
-rw-r--r--src/analysis/scan/items/math/to_string.h58
-rw-r--r--src/analysis/scan/items/maxcommon.c374
-rw-r--r--src/analysis/scan/items/maxcommon.h58
-rw-r--r--src/analysis/scan/items/modpath.c306
-rw-r--r--src/analysis/scan/items/modpath.h58
-rw-r--r--src/analysis/scan/items/string/Makefile.am16
-rw-r--r--src/analysis/scan/items/string/lower.c270
-rw-r--r--src/analysis/scan/items/string/lower.h58
-rw-r--r--src/analysis/scan/items/string/to_int.c303
-rw-r--r--src/analysis/scan/items/string/to_int.h58
-rw-r--r--src/analysis/scan/items/string/upper.c270
-rw-r--r--src/analysis/scan/items/string/upper.h58
-rw-r--r--src/analysis/scan/items/string/wide.c270
-rw-r--r--src/analysis/scan/items/string/wide.h58
-rw-r--r--src/analysis/scan/items/time/Makefile.am14
-rw-r--r--src/analysis/scan/items/time/make.c350
-rw-r--r--src/analysis/scan/items/time/make.h58
-rw-r--r--src/analysis/scan/items/time/now.c243
-rw-r--r--src/analysis/scan/items/time/now.h58
-rw-r--r--src/analysis/scan/items/uint-int.h58
-rw-r--r--src/analysis/scan/items/uint.c388
-rw-r--r--src/analysis/scan/items/uint.h59
-rw-r--r--src/analysis/scan/matches-int.h71
-rw-r--r--src/analysis/scan/matches.c319
-rw-r--r--src/analysis/scan/matches.h80
-rw-r--r--src/analysis/scan/matches/Makefile.am15
-rw-r--r--src/analysis/scan/matches/area.c57
-rw-r--r--src/analysis/scan/matches/area.h85
-rw-r--r--src/analysis/scan/matches/bytes-int.h54
-rw-r--r--src/analysis/scan/matches/bytes.c712
-rw-r--r--src/analysis/scan/matches/bytes.h75
-rw-r--r--src/analysis/scan/matches/pending.c677
-rw-r--r--src/analysis/scan/matches/pending.h129
-rw-r--r--src/analysis/scan/options-int.h60
-rw-r--r--src/analysis/scan/options.c490
-rw-r--r--src/analysis/scan/options.h98
-rw-r--r--src/analysis/scan/pattern-int.h63
-rw-r--r--src/analysis/scan/pattern.c425
-rw-r--r--src/analysis/scan/pattern.h79
-rw-r--r--src/analysis/scan/patterns/Makefile.am30
-rw-r--r--src/analysis/scan/patterns/backend-int.h78
-rw-r--r--src/analysis/scan/patterns/backend.c311
-rw-r--r--src/analysis/scan/patterns/backend.h79
-rw-r--r--src/analysis/scan/patterns/backends/Makefile.am29
-rw-r--r--src/analysis/scan/patterns/backends/acism-int.h206
-rw-r--r--src/analysis/scan/patterns/backends/acism.c1522
-rw-r--r--src/analysis/scan/patterns/backends/acism.h59
-rw-r--r--src/analysis/scan/patterns/backends/bitap-int.h132
-rw-r--r--src/analysis/scan/patterns/backends/bitap.c2785
-rw-r--r--src/analysis/scan/patterns/backends/bitap.h59
-rw-r--r--src/analysis/scan/patterns/backends/hyperscan-int.h67
-rw-r--r--src/analysis/scan/patterns/backends/hyperscan.c1063
-rw-r--r--src/analysis/scan/patterns/backends/hyperscan.h59
-rw-r--r--src/analysis/scan/patterns/customizer-int.h58
-rw-r--r--src/analysis/scan/patterns/customizer.c377
-rw-r--r--src/analysis/scan/patterns/customizer.h65
-rw-r--r--src/analysis/scan/patterns/modarg.h91
-rw-r--r--src/analysis/scan/patterns/modifier-int.h71
-rw-r--r--src/analysis/scan/patterns/modifier.c278
-rw-r--r--src/analysis/scan/patterns/modifier.h73
-rw-r--r--src/analysis/scan/patterns/modifiers/Makefile.am23
-rw-r--r--src/analysis/scan/patterns/modifiers/hex.c296
-rw-r--r--src/analysis/scan/patterns/modifiers/hex.h58
-rw-r--r--src/analysis/scan/patterns/modifiers/list-int.h54
-rw-r--r--src/analysis/scan/patterns/modifiers/list.c438
-rw-r--r--src/analysis/scan/patterns/modifiers/list.h68
-rw-r--r--src/analysis/scan/patterns/modifiers/lower.c301
-rw-r--r--src/analysis/scan/patterns/modifiers/lower.h58
-rw-r--r--src/analysis/scan/patterns/modifiers/pipe-int.h54
-rw-r--r--src/analysis/scan/patterns/modifiers/pipe.c405
-rw-r--r--src/analysis/scan/patterns/modifiers/pipe.h68
-rw-r--r--src/analysis/scan/patterns/modifiers/plain.c289
-rw-r--r--src/analysis/scan/patterns/modifiers/plain.h58
-rw-r--r--src/analysis/scan/patterns/modifiers/rev.c291
-rw-r--r--src/analysis/scan/patterns/modifiers/rev.h58
-rw-r--r--src/analysis/scan/patterns/modifiers/upper.c301
-rw-r--r--src/analysis/scan/patterns/modifiers/upper.h58
-rw-r--r--src/analysis/scan/patterns/modifiers/wide.c291
-rw-r--r--src/analysis/scan/patterns/modifiers/wide.h58
-rw-r--r--src/analysis/scan/patterns/modifiers/xor.c438
-rw-r--r--src/analysis/scan/patterns/modifiers/xor.h58
-rw-r--r--src/analysis/scan/patterns/patid.h36
-rw-r--r--src/analysis/scan/patterns/token-int.h62
-rw-r--r--src/analysis/scan/patterns/token.c491
-rw-r--r--src/analysis/scan/patterns/token.h75
-rw-r--r--src/analysis/scan/patterns/tokens/Makefile.am26
-rw-r--r--src/analysis/scan/patterns/tokens/atom.c543
-rw-r--r--src/analysis/scan/patterns/tokens/atom.h88
-rw-r--r--src/analysis/scan/patterns/tokens/hex-int.h56
-rw-r--r--src/analysis/scan/patterns/tokens/hex.c259
-rw-r--r--src/analysis/scan/patterns/tokens/hex.h59
-rw-r--r--src/analysis/scan/patterns/tokens/node-int.h108
-rw-r--r--src/analysis/scan/patterns/tokens/node.c675
-rw-r--r--src/analysis/scan/patterns/tokens/node.h127
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/Makefile.am24
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any-int.h60
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any.c765
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any.h61
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice-int.h54
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice.c646
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice.h61
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked-int.h64
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked.c1135
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked.h63
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not-int.h57
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not.c416
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not.h59
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain-int.h64
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.c1377
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.h83
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence-int.h58
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence.c504
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence.h67
-rw-r--r--src/analysis/scan/patterns/tokens/offset.c438
-rw-r--r--src/analysis/scan/patterns/tokens/offset.h111
-rw-r--r--src/analysis/scan/patterns/tokens/plain-int.h56
-rw-r--r--src/analysis/scan/patterns/tokens/plain.c266
-rw-r--r--src/analysis/scan/patterns/tokens/plain.h59
-rw-r--r--src/analysis/scan/rule-int.h69
-rw-r--r--src/analysis/scan/rule.c1084
-rw-r--r--src/analysis/scan/rule.h119
-rw-r--r--src/analysis/scan/scanner-int.h65
-rw-r--r--src/analysis/scan/scanner.c808
-rw-r--r--src/analysis/scan/scanner.h89
-rw-r--r--src/analysis/scan/scope-int.h54
-rw-r--r--src/analysis/scan/scope.c209
-rw-r--r--src/analysis/scan/scope.h59
-rw-r--r--src/analysis/scan/space-int.h61
-rw-r--r--src/analysis/scan/space.c451
-rw-r--r--src/analysis/scan/space.h65
-rw-r--r--src/analysis/scan/tokens.l1236
-rw-r--r--src/analysis/storage/Makefile.am11
-rw-r--r--src/analysis/type.c6
-rw-r--r--src/analysis/types/Makefile.am11
-rw-r--r--src/arch/Makefile.am45
-rw-r--r--src/arch/instruction.c14
-rw-r--r--src/arch/instruction.h12
-rw-r--r--src/arch/instructions/Makefile.am18
-rw-r--r--src/arch/instructions/raw.c2
-rw-r--r--src/arch/instructions/undefined.c2
-rw-r--r--src/arch/operand-int.h6
-rw-r--r--src/arch/operand.c6
-rw-r--r--src/arch/operand.h4
-rw-r--r--src/arch/operands/Makefile.am12
-rw-r--r--src/arch/operands/immediate.c14
-rw-r--r--src/arch/operands/known.c2
-rw-r--r--src/arch/operands/target.c14
-rw-r--r--src/arch/vmpa.h56
-rw-r--r--src/common/Makefile.am24
-rw-r--r--src/common/bits.c550
-rw-r--r--src/common/bits.h28
-rw-r--r--src/common/cpp.h2
-rw-r--r--src/common/cpu.c100
-rw-r--r--src/common/cpu.h50
-rw-r--r--src/common/dllist.c195
-rw-r--r--src/common/dllist.h34
-rw-r--r--src/common/extstr.c147
-rw-r--r--src/common/extstr.h9
-rw-r--r--src/common/itoa.c135
-rw-r--r--src/common/itoa.h34
-rw-r--r--src/common/sort.c147
-rw-r--r--src/common/sort.h12
-rw-r--r--src/common/szstr.h112
-rw-r--r--src/core/Makefile.am10
-rw-r--r--src/core/collections.h2
-rw-r--r--src/core/columns.h59
-rw-r--r--src/core/core.c111
-rw-r--r--src/core/core.h14
-rw-r--r--src/core/demanglers.c6
-rw-r--r--src/core/global.c51
-rw-r--r--src/core/global.h7
-rw-r--r--src/core/logs.c13
-rw-r--r--src/core/paths.c49
-rw-r--r--src/debug/Makefile.am11
-rw-r--r--src/format/Makefile.am11
-rw-r--r--src/format/format-int.h1
-rw-r--r--src/format/format.h1
-rw-r--r--src/format/known.h1
-rw-r--r--src/format/strsym.c2
-rw-r--r--src/format/symbol.c22
-rw-r--r--src/glibext/Makefile.am79
-rw-r--r--src/glibext/buffercache-int.h2
-rw-r--r--src/glibext/buffercache.c168
-rw-r--r--src/glibext/buffercache.h28
-rw-r--r--src/glibext/bufferline.c15
-rw-r--r--src/glibext/bufferline.h8
-rw-r--r--src/glibext/comparison-int.h58
-rw-r--r--src/glibext/comparison.c199
-rw-r--r--src/glibext/comparison.h80
-rw-r--r--src/glibext/configuration.c8
-rw-r--r--src/glibext/configuration.h23
-rw-r--r--src/glibext/delayed-int.h2
-rw-r--r--src/glibext/delayed.c10
-rw-r--r--src/glibext/delayed.h5
-rw-r--r--src/glibext/gbinarycursor.c105
-rw-r--r--src/glibext/gbinportion-int.h2
-rw-r--r--src/glibext/gbinportion.c113
-rw-r--r--src/glibext/gbinportion.h22
-rw-r--r--src/glibext/generators/Makefile.am20
-rw-r--r--src/glibext/generators/hex.c32
-rw-r--r--src/glibext/generators/prologue.c37
-rw-r--r--src/glibext/generators/rborder.c37
-rw-r--r--src/glibext/glinecursor-int.h2
-rw-r--r--src/glibext/glinecursor.h6
-rw-r--r--src/glibext/linecolumn.c20
-rw-r--r--src/glibext/linecolumn.h14
-rw-r--r--src/glibext/linesegment.c67
-rw-r--r--src/glibext/linesegment.h26
-rw-r--r--src/glibext/notifier.h74
-rw-r--r--src/glibext/seq.h2
-rw-r--r--src/glibext/umemslice-int.h71
-rw-r--r--src/glibext/umemslice.c423
-rw-r--r--src/glibext/umemslice.h80
-rw-r--r--src/glibext/widthtracker.h3
-rw-r--r--src/gtkext/Makefile.am6
-rw-r--r--src/gtkext/graph/Makefile.am11
-rw-r--r--src/gtkext/gtkblockdisplay.c1
-rw-r--r--src/gtkext/gtkblockdisplay.h16
-rw-r--r--src/gtkext/gtkstatusstack.c60
-rw-r--r--src/gtkext/gtkstatusstack.h4
-rw-r--r--src/gtkext/hexdisplay.c1
-rw-r--r--src/gtkext/hexdisplay.h13
-rw-r--r--src/gtkext/rendering.c1
-rw-r--r--src/gtkext/rendering.h2
-rw-r--r--src/gui/Makefile.am6
-rw-r--r--src/gui/core/Makefile.am9
-rw-r--r--src/gui/core/core.c3
-rw-r--r--src/gui/core/items.c1
-rw-r--r--src/gui/dialogs/Makefile.am9
-rw-r--r--src/gui/dialogs/export_disass.c1
-rw-r--r--src/gui/dialogs/gotox.c1
-rw-r--r--src/gui/editor.c1
-rw-r--r--src/gui/menus/Makefile.am11
-rw-r--r--src/gui/panels/Makefile.am9
-rw-r--r--src/gui/panels/bintree.c1
-rw-r--r--src/gui/panels/bookmarks.c1
-rw-r--r--src/gui/panels/errors.c1
-rw-r--r--src/gui/panels/strings.c2
-rw-r--r--src/gui/panels/updating.h1
-rw-r--r--src/gui/panels/welcome.c1
-rw-r--r--src/gui/tb/Makefile.am9
-rw-r--r--src/hub.c7
-rw-r--r--src/main.c69
-rw-r--r--src/mangling/Makefile.am11
-rw-r--r--src/plugins/Makefile.am11
-rw-r--r--src/plugins/dt.c33
-rw-r--r--src/plugins/pglist.c14
-rw-r--r--src/plugins/pglist.h4
-rw-r--r--src/plugins/plugin-int.h6
-rw-r--r--src/plugins/plugin.c21
-rw-r--r--src/plugins/plugin.h8
-rw-r--r--src/plugins/self.h3
-rw-r--r--src/rost.c560
-rw-r--r--tests/analysis/scan/booleans.py98
-rw-r--r--tests/analysis/scan/common.py54
-rw-r--r--tests/analysis/scan/examples.py70
-rw-r--r--tests/analysis/scan/functions.py239
-rw-r--r--tests/analysis/scan/fuzzing.py289
-rw-r--r--tests/analysis/scan/grammar.py484
-rw-r--r--tests/analysis/scan/matches.py64
-rw-r--r--tests/analysis/scan/pyapi.py297
-rw-r--r--tests/analysis/scan/scanning_hex.py716
-rw-r--r--tests/analysis/scan/scanning_str.py194
-rw-r--r--tests/analysis/scan/sets.py118
-rw-r--r--tests/common/bitfield.py145
-rw-r--r--tests/common/itoa.py28
-rw-r--r--tests/plugins/encodings/all.py23
-rw-r--r--tests/plugins/kaitai/__init__.py0
-rw-r--r--tests/plugins/kaitai/language.py2474
-rw-r--r--tests/plugins/kaitai/rost.py170
-rw-r--r--tests/plugins/yaml.py175
-rw-r--r--tests/plugins/yamlrdr.py277
-rw-r--r--tools/Makefile.am2
-rw-r--r--tools/d2c/decl.h2
-rw-r--r--tools/d2c/format/decl.h2
-rw-r--r--tools/d2c/grammar.y4
-rw-r--r--tools/d2c/id/decl.h2
-rw-r--r--tools/fuzzing/rost/Makefile.am14
-rw-r--r--tools/fuzzing/rost/convert.py452
-rw-r--r--tools/fuzzing/rost/fast-rost.c283
-rwxr-xr-xtools/fuzzing/rost/gen-dict.sh81
-rwxr-xr-xtools/fuzzing/rost/minall.sh25
-rwxr-xr-xtools/fuzzing/rost/rerun.sh27
-rw-r--r--tools/fuzzing/rost/test.rost12
-rw-r--r--tools/maint/extra.supp777
-rw-r--r--tools/yara2rost/Makefile.am36
-rw-r--r--tools/yara2rost/decl.h37
-rw-r--r--tools/yara2rost/demo.yar27
-rw-r--r--tools/yara2rost/enums.h47
-rw-r--r--tools/yara2rost/grammar.y1332
-rw-r--r--tools/yara2rost/tokens.l292
-rw-r--r--tools/yara2rost/yara2rost.c295
933 files changed, 106848 insertions, 6421 deletions
diff --git a/.gitignore b/.gitignore
index 58ea9c8..7fa51d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ grammar.[ch]
grammar.output
tokens.[ch]
ylwrap
+lex.backup
# i18n
gettext.h
@@ -69,11 +70,16 @@ resources.[ch]
# Binaries
src/chrysalide
src/chrysalide-hub
+src/rost
tools/d2c/d2c
+tools/fuzzing/rost/fast-rost
+tools/yara2rost/yara2rost
+
# Misc
plugins/python/androperms/androperms.db
system/pkgconfig/chrysalide.pc
+tools/fuzzing/rost/rost.dict
# Themes
*.ctm
diff --git a/configure.ac b/configure.ac
index b9377b2..cfb94bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,8 +6,8 @@
m4_include([gitrev.m4])
-AC_PREREQ(2.59)
-AC_INIT([chrysalide], [gitversion], [nocbos@gmail.com])
+AC_PREREQ([2.71])
+AC_INIT([chrysalide],[gitversion],[nocbos@gmail.com])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
@@ -33,7 +33,9 @@ AC_PROG_LEX
AC_PROG_YACC
AC_PROG_INSTALL
AC_PROG_MAKE_SET
-AC_PROG_LIBTOOL
+LT_INIT
+
+CFLAGS=""
AC_EGREP_CPP(yes,
[#ifdef __PIE__
@@ -49,6 +51,11 @@ AC_PATH_PROG(YACC_INST, $YACC)
AC_PATH_PROG(LEX_INST, $LEX)
+#--- Checks for CPU
+
+AX_EXT
+
+
#--- Checks for libraries
AC_CHECK_LIB([dl], [dlopen])
@@ -58,7 +65,15 @@ AC_CHECK_LIB([dl], [dlopen])
AC_HEADER_DIRENT
AC_HEADER_STDBOOL
-AC_HEADER_STDC
+m4_warn([obsolete],
+[The preprocessor macro `STDC_HEADERS' is obsolete.
+ Except in unusual embedded environments, you can safely include all
+ ISO C90 headers unconditionally.])dnl
+# Autoupdate added the next two lines to ensure that your configure
+# script's behavior did not change. They are probably safe to remove.
+AC_CHECK_INCLUDES_DEFAULT
+AC_PROG_EGREP
+
AC_CHECK_HEADERS([malloc.h])
AC_CHECK_HEADERS([netdb.h])
AC_CHECK_HEADERS([stdlib.h])
@@ -214,6 +229,18 @@ AC_ARG_ENABLE([debug],
AS_HELP_STRING([--enable-debug], [compile with debugging support [default=no]]),
[], [enable_debug=no])
+AC_ARG_ENABLE([gtk-support],
+ AS_HELP_STRING([--disable-gtk-support], [disable GTK support [default=no]]),
+ [], [enable_gtk_support=yes])
+
+AC_ARG_ENABLE([curl-support],
+ AS_HELP_STRING([--disable-curl-support], [disable cURL support [default=no]]),
+ [], [enable_curl_support=yes])
+
+AC_ARG_ENABLE([magic-support],
+ AS_HELP_STRING([--disable-magic-support], [disable magic number recognition [default=no]]),
+ [], [enable_magic_support=yes])
+
AC_ARG_ENABLE([python-bindings],
AS_HELP_STRING([--disable-python-bindings], [disable Python bindings [default=no]]),
[], [enable_python_bindings=yes])
@@ -234,7 +261,7 @@ AC_ARG_WITH([desktop-dir],
AC_ARG_WITH([local-resources],
AS_HELP_STRING([--with-local-resources],
[define if built components located in the sources are used at runtime [default=no]]),
- [with_local_resources=yes], [with_local_resources=no])
+ [with_local_resources=$withval], [with_local_resources=no])
AM_CONDITIONAL([BUILD_PYTHON_PACKAGE], [test "x$build_python_package" = "xyes"])
@@ -249,52 +276,70 @@ if test "x$enable_rpath" = "xno"; then
fi
-#--- Small enumerations
+#--- Small enumerations and other basic flags
-CFLAGS="$CFLAGS -fshort-enums -D_LARGEFILE64_SOURCE"
+CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE"
+CFLAGS="$CFLAGS -fshort-enums"
-#--- Is debug mode needed ?
-if test "x$with_gobject_leak_tracker" = "xyes"; then
- enable_debug="yes"
+#--- Build binaries for Python package only?
+
+if test "x$build_python_package" = "xyes"; then
+ CPPFLAGS="$CPPFLAGS -DPYTHON_PACKAGE"
fi
-if test "x$enable_debug" = "xyes"; then
- DEBUG_CFLAGS="$DEBUG_CFLAGS -O0 -ggdb -gdwarf-2 -DDEBUG"
-else
- DEBUG_CFLAGS="$DEBUG_CFLAGS -DNDEBUG"
+
+#--- Discard local sources when looking for resources?
+
+if test "x$with_local_resources" = "xno"; then
+ CPPFLAGS="$CPPFLAGS -DDISCARD_LOCAL"
fi
-AC_SUBST(DEBUG_CFLAGS)
+
+#--- Is debug mode needed?
AM_CONDITIONAL([TRACK_GOBJECT_LEAKS], [test "x$with_gobject_leak_tracker" = "xyes"])
if test "x$with_gobject_leak_tracker" = "xyes"; then
- AC_DEFINE(TRACK_GOBJECT_LEAKS, 1,
- [Define to 1 to enable code for dumping remaining GObject instances at exit.])
+ # Enable code for dumping remaining GObject instances at exit
+ CPPFLAGS="$CPPFLAGS -DTRACK_GOBJECT_LEAKS"
+ enable_debug="yes"
fi
+if test "x$enable_debug" = "xyes"; then
+ DEBUG_CPPFLAGS="-DDEBUG"
+ DEBUG_CFLAGS="-O0 -ggdb -gdwarf-2"
+else
+ DEBUG_CPPFLAGS="-Ofast -DNDEBUG"
+fi
-#--- Discard local sources when looking for resources ?
-if test "x$build_python_package" = "xyes"; then
- CFLAGS="$CFLAGS -DPYTHON_PACKAGE"
-fi
+#--- Compilation warnings
-AC_SUBST(CFLAGS)
+WARNING_CFLAGS="-Wall -Wimplicit -Wreturn-type -Wunused -Wswitch -Wcomment -Wuninitialized -Wparentheses -Wpointer-arith -Wmissing-prototypes"
+#-Wcast-qual -Wconversion -Wsign-compare -Wdisabled-optimization
-#--- Discard local sources when looking for resources ?
+# _BSD_SOURCE: htobe64, be64toh
+# _XOPEN_SOURCE: strdup, snprintf
+# _ISOC99_SOURCE: INFINITY; NAN
+# _GNU_SOURCE: strcasestr
+# GTK_DISABLE_DEPRECATED: on reste conforme au C99
+#COMPLIANCE_FLAGS="-D_BSD_SOURCE -D_GNU_SOURCE -DGTK_DISABLE_DEPRECATED"
+COMPLIANCE_CPPFLAGS="-D_DEFAULT_SOURCE -D_GNU_SOURCE"
-if test "x$with_local_resources" = "xno"; then
- CFLAGS="$CFLAGS -DDISCARD_LOCAL"
-fi
+#--- Final exports
+
+CPPFLAGS="$CPPFLAGS $DEBUG_CPPFLAGS $COMPLIANCE_CPPFLAGS"
+CFLAGS="$CFLAGS $DEBUG_CFLAGS $WARNING_CFLAGS"
+
+AC_SUBST(CPPFLAGS)
AC_SUBST(CFLAGS)
-#--- Custom destination for desktop resources ?
+#--- Custom destination for desktop resources?
if test "x$with_desktop_dir" != x; then
DESKTOP_DATADIR=$with_desktop_dir
@@ -306,26 +351,40 @@ AM_CONDITIONAL(DESKTOP_DATADIR, test "x$with_desktop_dir" != xno)
AC_SUBST(DESKTOP_DATADIR)
-#--- Compilation warnings
+#--- Checks for GTK 3.0 / GObject 2.0
-#-Wall -Wimplicit -Wreturn-type -Wunused -Wswitch -Wcomment -Wuninitialized -Wparentheses -Wpointer-arith -Wmissing-prototypes
+AM_CONDITIONAL([BUILD_GTK_SUPPORT], [test "x$enable_gtk_support" = "xyes"])
-WARNING_FLAGS="-Wall -Wimplicit -Wreturn-type -Wunused -Wswitch -Wcomment -Wuninitialized -Wparentheses -Wpointer-arith -Wmissing-prototypes"
+if test "x$BUILD_GTK_SUPPORT_TRUE" = "x"; then
+ # GTK support is available and enabled
+ CPPFLAGS="$CPPFLAGS -DINCLUDE_GTK_SUPPORT"
+fi
-#-Wcast-qual -Wconversion -Wsign-compare -Wdisabled-optimization
-AC_SUBST(WARNING_FLAGS)
+PKG_CHECK_MODULES(LIBGOBJ,gobject-2.0 >= 2.66.8,[libgobj_found=yes],[libgobj_found=no])
-# _BSD_SOURCE: htobe64, be64toh
-# _XOPEN_SOURCE: strdup, snprintf
-# _ISOC99_SOURCE: INFINITY; NAN
-# GTK_DISABLE_DEPRECATED: on reste conforme au C99
-#COMPLIANCE_FLAGS="-D_BSD_SOURCE -D_GNU_SOURCE -DGTK_DISABLE_DEPRECATED"
-COMPLIANCE_FLAGS="-D_DEFAULT_SOURCE -D_GNU_SOURCE"
+if test "$libgobj_found" = "yes"; then
+ libgobj_version=`pkg-config gobject-2.0 --modversion`
+else
+ libgobj_version='-'
+fi
-AC_SUBST(COMPLIANCE_FLAGS)
+PKG_CHECK_MODULES(LIBGTHREAD,gthread-2.0 >= 2.66.8,[libgthread_found=yes],[libgthread_found=no])
+
+if test "$libgthread_found" = "yes"; then
+ libgthread_version=`pkg-config gthread-2.0 --modversion`
+else
+ libgthread_version='-'
+fi
+
+PKG_CHECK_MODULES(LIBGMOD,gmodule-2.0 >= 2.66.8,[libgmod_found=yes],[libgmod_found=no])
+
+if test "$libgmod_found" = "yes"; then
+ libgmod_version=`pkg-config gmodule-2.0 --modversion`
+else
+ libgmod_version='-'
+fi
-#--- Checks for GTK 2.0
PKG_CHECK_MODULES(LIBGTK,gtk+-3.0 >= 3.8.6,[libgtk_found=yes],[libgtk_found=no])
@@ -335,8 +394,24 @@ else
libgtk_version='-'
fi
-AC_SUBST(LIBGTK_CFLAGS)
-AC_SUBST(LIBGTK_LIBS)
+
+if test "x$enable_gtk_support" = "xyes"; then
+
+ TOOLKIT_CFLAGS="$LIBGTK_CFLAGS $LIBGTHREAD_CFLAGS $LIBGMOD_CFLAGS"
+ TOOLKIT_LIBS="$LIBGTK_LIBS $LIBGTHREAD_LIBS $LIBGMOD_LIBS"
+
+ AC_SUBST(TOOLKIT_CFLAGS)
+ AC_SUBST(TOOLKIT_LIBS)
+
+else
+
+ TOOLKIT_CFLAGS="$LIBGOBJ_CFLAGS $LIBGTHREAD_CFLAGS $LIBGMOD_CFLAGS"
+ TOOLKIT_LIBS="$LIBGOBJ_LIBS $LIBGTHREAD_LIBS $LIBGMOD_LIBS"
+
+ AC_SUBST(TOOLKIT_CFLAGS)
+ AC_SUBST(TOOLKIT_LIBS)
+
+fi
#--- Checks for libxml2
@@ -383,10 +458,10 @@ AC_SUBST(LIBSQLITE_LIBS)
#--- Checks for libssl
-PKG_CHECK_MODULES(LIBSSL,libssl >= 1.0.1k,[libssl_found=yes],[libssl_found=no])
+PKG_CHECK_MODULES(LIBSSL,openssl >= 3.0.9,[libssl_found=yes],[libssl_found=no])
if test "$libssl_found" = "yes"; then
- libssl_version=`pkg-config libssl --modversion`
+ libssl_version=`pkg-config openssl --modversion`
else
libssl_version='-'
fi
@@ -397,6 +472,14 @@ AC_SUBST(LIBSSL_LIBS)
#--- Checks for libcurl
+AM_CONDITIONAL([BUILD_CURL_SUPPORT], [test "x$enable_curl_support" = "xyes"])
+
+if test "x$BUILD_CURL_SUPPORT_TRUE" = "x"; then
+ # cURL support is available and enabled
+ CPPFLAGS="$CPPFLAGS -DINCLUDE_CURL_SUPPORT"
+fi
+
+
PKG_CHECK_MODULES(LIBCURL,libcurl >= 7.64,[libcurl_found=yes],[libcurl_found=no])
if test "$libcurl_found" = "yes"; then
@@ -405,8 +488,71 @@ else
libcurl_version='-'
fi
-AC_SUBST(LIBCURL_CFLAGS)
-AC_SUBST(LIBCURL_LIBS)
+if test "x$enable_curl_support" = "xyes"; then
+
+ AC_SUBST(LIBCURL_CFLAGS)
+ AC_SUBST(LIBCURL_LIBS)
+
+ true # empty if/then body not allowed
+
+fi
+
+
+#--- Checks for libyaml
+
+PKG_CHECK_MODULES(LIBYAML,yaml-0.1 >= 0.2.5,[libyaml_found=yes],[libyaml_found=no])
+
+if test "$libyaml_found" = "yes"; then
+ libyaml_version=`pkg-config yaml-0.1 --modversion`
+else
+ libyaml_version='-'
+fi
+
+AC_SUBST(LIBYAML_CFLAGS)
+AC_SUBST(LIBYAML_LIBS)
+
+
+#--- Checks for libmagic
+
+AM_CONDITIONAL([BUILD_MAGIC_SUPPORT], [test "x$enable_magic_support" = "xyes"])
+
+if test "x$BUILD_MAGIC_SUPPORT_TRUE" = "x"; then
+ # Magic support is available and enabled
+ CPPFLAGS="$CPPFLAGS -DINCLUDE_MAGIC_SUPPORT"
+fi
+
+
+PKG_CHECK_MODULES(LIBMAGIC,libmagic >= 5.44,[libmagic_found=yes],[libmagic_found=no])
+
+if test "$libmagic_found" = "yes"; then
+ libmagic_version=`pkg-config libmagic --modversion`
+else
+ libmagic_version='-'
+fi
+
+
+if test "x$enable_magic_support" = "xyes"; then
+
+ AC_SUBST(LIBMAGIC_CFLAGS)
+ AC_SUBST(LIBMAGIC_LIBS)
+
+ true # empty if/then body not allowed
+
+fi
+
+
+#--- Checks for Hyperscan
+
+PKG_CHECK_MODULES(LIBHS,libhs >= 5.4.9,[libhs_found=yes],[libhs_found=no])
+
+if test "$libhs_found" = "yes"; then
+ libhs_version=`pkg-config libhs --modversion`
+else
+ libhs_version='-'
+fi
+
+AC_SUBST(LIBHS_CFLAGS)
+AC_SUBST(LIBHS_LIBS)
#--- Checks for Python
@@ -420,8 +566,8 @@ fi
AM_CONDITIONAL([BUILD_PYTHON3_BINDINGS], [test "x$enable_python_bindings$python3_cfg_binary" = "xyesyes"])
if test "x$BUILD_PYTHON3_BINDINGS_TRUE" = "x"; then
- AC_DEFINE(HAVE_PYTHON3_BINDINGS, 1,
- [Define to 1 if the Python bindings are available and enabled.])
+ # Python bindings are available and enabled
+ CPPFLAGS="$CPPFLAGS -DINCLUDE_PYTHON3_BINDINGS"
fi
if test "x$python3_cfg_binary" = "xyes"; then
@@ -434,7 +580,7 @@ if test "x$python3_cfg_binary" = "xyes"; then
LIBPYTHON_CFLAGS=`$pyprefix-config --cflags`
LIBPYTHON_LIBS=`$pyprefix-config --libs`
- LIBPYTHON_INTERPRETER_CFLAGS=`$pyprefix-config --cflags --embed`
+ LIBPYTHON_INTERPRETER_CFLAGS="`$pyprefix-config --cflags --embed` -DPY_SSIZE_T_CLEAN"
LIBPYTHON_INTERPRETER_LIBS=`$pyprefix-config --libs --embed`
LIBPYTHON_ABI_FLAGS=`$pyprefix-config --abiflags`
pythondep=$pyprefix
@@ -498,6 +644,12 @@ AC_CONFIG_FILES([Makefile
doc/Makefile
pixmaps/Makefile
plugins/Makefile
+ plugins/apihashing/Makefile
+ plugins/apihashing/classics/Makefile
+ plugins/apihashing/custom/Makefile
+ plugins/apihashing/python/Makefile
+ plugins/apihashing/python/classics/Makefile
+ plugins/apihashing/python/custom/Makefile
plugins/arm/Makefile
plugins/arm/python/Makefile
plugins/arm/python/v7/Makefile
@@ -527,6 +679,10 @@ AC_CONFIG_FILES([Makefile
plugins/dwarf/v2/Makefile
plugins/dwarf/v3/Makefile
plugins/dwarf/v4/Makefile
+ plugins/encodings/Makefile
+ plugins/encodings/python/Makefile
+ plugins/encodings/python/rost/Makefile
+ plugins/encodings/rost/Makefile
plugins/elf/Makefile
plugins/elf/python/Makefile
plugins/fmtp/Makefile
@@ -537,6 +693,14 @@ AC_CONFIG_FILES([Makefile
plugins/java/Makefile
plugins/javadesc/Makefile
plugins/javadesc/python/Makefile
+ plugins/kaitai/Makefile
+ plugins/kaitai/parsers/Makefile
+ plugins/kaitai/records/Makefile
+ plugins/kaitai/rost/Makefile
+ plugins/kaitai/python/Makefile
+ plugins/kaitai/python/parsers/Makefile
+ plugins/kaitai/python/records/Makefile
+ plugins/kaitai/python/rost/Makefile
plugins/libcsem/Makefile
plugins/lnxsyscalls/Makefile
plugins/mobicore/Makefile
@@ -548,6 +712,11 @@ AC_CONFIG_FILES([Makefile
plugins/pychrysalide/analysis/db/Makefile
plugins/pychrysalide/analysis/db/items/Makefile
plugins/pychrysalide/analysis/disass/Makefile
+ plugins/pychrysalide/analysis/scan/Makefile
+ plugins/pychrysalide/analysis/scan/exprs/Makefile
+ plugins/pychrysalide/analysis/scan/patterns/Makefile
+ plugins/pychrysalide/analysis/scan/patterns/backends/Makefile
+ plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile
plugins/pychrysalide/analysis/storage/Makefile
plugins/pychrysalide/analysis/types/Makefile
plugins/pychrysalide/arch/Makefile
@@ -589,6 +758,20 @@ AC_CONFIG_FILES([Makefile
src/analysis/disass/Makefile
src/analysis/human/Makefile
src/analysis/human/asm/Makefile
+ src/analysis/scan/Makefile
+ src/analysis/scan/exprs/Makefile
+ src/analysis/scan/items/Makefile
+ src/analysis/scan/items/console/Makefile
+ src/analysis/scan/items/magic/Makefile
+ src/analysis/scan/items/math/Makefile
+ src/analysis/scan/items/string/Makefile
+ src/analysis/scan/items/time/Makefile
+ src/analysis/scan/matches/Makefile
+ src/analysis/scan/patterns/Makefile
+ src/analysis/scan/patterns/backends/Makefile
+ src/analysis/scan/patterns/modifiers/Makefile
+ src/analysis/scan/patterns/tokens/Makefile
+ src/analysis/scan/patterns/tokens/nodes/Makefile
src/analysis/storage/Makefile
src/analysis/types/Makefile
src/arch/Makefile
@@ -622,6 +805,8 @@ AC_CONFIG_FILES([Makefile
tools/d2c/id/Makefile
tools/d2c/pattern/Makefile
tools/d2c/rules/Makefile
+ tools/fuzzing/rost/Makefile
+ tools/yara2rost/Makefile
system/Makefile
system/desktop/Makefile
system/pkgconfig/Makefile
@@ -640,12 +825,18 @@ echo -n $PACKAGE r
echo AC_PACKAGE_VERSION
echo
+echo The GLib type, object and signal library..... : $libgobj_version
+echo The thread support for GLib.................. : $libgthread_version
+echo The dynamic module loader for GLib........... : $libgmod_version
echo The GNU Image Manipulation Program Toolkit... : $libgtk_version
echo The XML C parser and toolkit of Gnome........ : $libxml_version
echo The flexible interface for archives I/O...... : $libarchive_version
echo The small, fast and reliable database engine. : $libsqlite_version
echo The cryptography and SSL/TLS toolkit......... : $libssl_version
echo The client URL library....................... : $libcurl_version
+echo The YAML support library..................... : $libyaml_version
+echo The magic number recognition library......... : $libmagic_version
+echo The high-performance matching library........ : $libhs_version
echo
echo Available Python programming language........ : $python3_version
@@ -655,6 +846,24 @@ echo
echo Found lexical analyzer generator............. : $LEX_INST
echo Found general-purpose parser generator....... : $YACC_INST
+if test "x$enable_gtk_support" = "xyes"; then
+ disable_gtk_support="no"
+else
+ disable_gtk_support="yes"
+fi
+
+if test "x$enable_curl_support" = "xyes"; then
+ disable_curl_support="no"
+else
+ disable_curl_support="yes"
+fi
+
+if test "x$enable_magic_support" = "xyes"; then
+ disable_magic_support="no"
+else
+ disable_magic_support="yes"
+fi
+
if test "x$enable_python_bindings" = "xyes"; then
disable_python_bindings="no"
else
@@ -664,6 +873,9 @@ fi
echo
echo Print debugging messages..................... : $enable_debug
echo Consider local resources..................... : $with_local_resources
+echo Disable GTK support.......................... : $disable_gtk_support
+echo Disable cURL support......................... : $disable_curl_support
+echo Disable Magic support........................ : $disable_magic_support
echo Disable Python bindings...................... : $disable_python_bindings
echo Build a Python binary distribution........... : $build_python_package
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 8d39c37..1cda6e0 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -5,6 +5,12 @@ PYTHON3_SUBDIRS = pychrysalide python
endif
+if BUILD_GTK_SUPPORT
+
+ROPGADGETS_SUBDIRS = ropgadgets
+
+endif
+
# androhelpers
SUBDIRS = \
$(PYTHON3_SUBDIRS) \
@@ -18,15 +24,18 @@ SUBDIRS = \
fmtp \
itanium \
javadesc \
+ kaitai \
mobicore \
pe \
yaml \
+ apihashing \
bhash \
dalvik \
+ encodings \
libcsem \
lnxsyscalls \
readdex \
readelf \
readmc \
- ropgadgets \
+ $(ROPGADGETS_SUBDIRS) \
winordinals
diff --git a/plugins/apihashing/Makefile.am b/plugins/apihashing/Makefile.am
new file mode 100644
index 0000000..d73f8b0
--- /dev/null
+++ b/plugins/apihashing/Makefile.am
@@ -0,0 +1,65 @@
+
+lib_LTLIBRARIES = libapihashing.la
+
+libdir = $(pluginslibdir)
+
+
+if BUILD_PYTHON_PACKAGE
+
+RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs:$$ORIGIN'
+
+else
+
+RUN_PATH = -Wl,-rpath,'$$ORIGIN'
+
+endif
+
+if BUILD_PYTHON3_BINDINGS
+
+PYTHON3_LIBADD = python/libapihashingpython.la
+
+if BUILD_DISCARD_LOCAL
+
+if BUILD_PYTHON_PACKAGE
+PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN/..'
+else
+PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN'
+endif
+
+else
+
+PYTHON3_RUN_PATH = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs
+
+endif
+
+PYTHON3_LDFLAGS = $(PYTHON3_RUN_PATH) -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so
+
+PYTHON3_SUBDIRS = python
+
+endif
+
+
+libapihashing_la_SOURCES = \
+ apihash.h apihash.c \
+ core.h core.c
+
+libapihashing_la_LIBADD = \
+ $(PYTHON3_LIBADD) \
+ classics/libapihashingclassics.la \
+ custom/libapihashingcustom.la
+
+libapihashing_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+libapihashing_la_LDFLAGS = \
+ -avoid-version \
+ -L$(top_srcdir)/src/.libs -lchrysacore \
+ -L$(top_srcdir)/plugins/pe/.libs -lpe \
+ $(RUN_PATH) $(PYTHON3_LDFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libapihashing_la_SOURCES:%c=)
+
+
+SUBDIRS = $(PYTHON3_SUBDIRS) classics custom
diff --git a/plugins/apihashing/apihash.c b/plugins/apihashing/apihash.c
new file mode 100644
index 0000000..3313073
--- /dev/null
+++ b/plugins/apihashing/apihash.c
@@ -0,0 +1,134 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * apihash.c - détermination d'API par empreinte de fonction
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "apihash.h"
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en empreintes d'API. */
+static void g_api_hash_modifier_class_init(GApiHashModifierClass *klass);
+
+/* Initialise une instance de transmission en empreinte d'API. */
+static void g_api_hash_modifier_init(GApiHashModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_api_hash_modifier_dispose(GApiHashModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_api_hash_modifier_finalize(GApiHashModifier *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte d'API. */
+G_DEFINE_TYPE(GApiHashModifier, g_api_hash_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en empreintes d'API. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_api_hash_modifier_class_init(GApiHashModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_api_hash_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_api_hash_modifier_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en empreinte d'API. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_api_hash_modifier_init(GApiHashModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_api_hash_modifier_dispose(GApiHashModifier *modifier)
+{
+ G_OBJECT_CLASS(g_api_hash_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_api_hash_modifier_finalize(GApiHashModifier *modifier)
+{
+ G_OBJECT_CLASS(g_api_hash_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
diff --git a/plugins/apihashing/apihash.h b/plugins/apihashing/apihash.h
new file mode 100644
index 0000000..cfc3365
--- /dev/null
+++ b/plugins/apihashing/apihash.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * apihash.h - prototypes pour la détermination d'API par empreinte de fonction
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_APIHASH_H
+#define _PLUGINS_APIHASHING_APIHASH_H
+
+
+#include <glib-object.h>
+
+
+#include <analysis/scan/patterns/modifier.h>
+
+
+
+#define G_TYPE_API_HASH_MODIFIER g_api_hash_modifier_get_type()
+#define G_API_HASH_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_API_HASH_MODIFIER, GApiHashModifier))
+#define G_IS_API_HASH_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_API_HASH_MODIFIER))
+#define G_API_HASH_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_API_HASH_MODIFIER, GApiHashModifierClass))
+#define G_IS_API_HASH_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_API_HASH_MODIFIER))
+#define G_API_HASH_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_API_HASH_MODIFIER, GApiHashModifierClass))
+
+
+/* Transormation en empreinte d'API (instance) */
+typedef GScanTokenModifier GApiHashModifier;
+
+/* Transormation en empreinte d'API (classe) */
+typedef GScanTokenModifierClass GApiHashModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte d'API. */
+GType g_api_hash_modifier_get_type(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_APIHASH_H */
diff --git a/plugins/apihashing/classics/Makefile.am b/plugins/apihashing/classics/Makefile.am
new file mode 100644
index 0000000..9f97b47
--- /dev/null
+++ b/plugins/apihashing/classics/Makefile.am
@@ -0,0 +1,14 @@
+
+noinst_LTLIBRARIES = libapihashingclassics.la
+
+libapihashingclassics_la_SOURCES = \
+ crc32.h crc32.c \
+ djb2.h djb2.c \
+ ror13.h ror13.c
+
+libapihashingclassics_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libapihashingclassics_la_SOURCES:%c=)
diff --git a/plugins/apihashing/classics/crc32.c b/plugins/apihashing/classics/crc32.c
new file mode 100644
index 0000000..98f9a6b
--- /dev/null
+++ b/plugins/apihashing/classics/crc32.c
@@ -0,0 +1,332 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * crc32.c - transormation en empreinte d'API crc32
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "crc32.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en empreintes crc32. */
+static void g_scan_crc32_modifier_class_init(GScanCrc32ModifierClass *klass);
+
+/* Initialise une instance de transmission en empreinte crc32. */
+static void g_scan_crc32_modifier_init(GScanCrc32Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_crc32_modifier_dispose(GScanCrc32Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_crc32_modifier_finalize(GScanCrc32Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_crc32_modifier_get_name(const GScanCrc32Modifier *);
+
+/* Calcule l'empreinte crc32 d'un motif de recherche. */
+static uint32_t compute_crc32(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_crc32_modifier_transform(const GScanCrc32Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_crc32_modifier_get_path(const GScanCrc32Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en encodage Crc32. */
+G_DEFINE_TYPE(GScanCrc32Modifier, g_scan_crc32_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en empreintes crc32. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_crc32_modifier_class_init(GScanCrc32ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_crc32_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_crc32_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_crc32_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_crc32_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_crc32_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en empreinte crc32. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_crc32_modifier_init(GScanCrc32Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_crc32_modifier_dispose(GScanCrc32Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_crc32_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_crc32_modifier_finalize(GScanCrc32Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_crc32_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des empreintes crc32. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_crc32_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_CRC32_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_crc32_modifier_get_name(const GScanCrc32Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("crc32");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte crc32 d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_crc32(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = 0xffffffff;
+
+ for (i = 0; i < src->len; i++)
+ {
+ result ^= src->data[i];
+
+ for (k = 0; k < 8; k++)
+ result = result & 1 ? (result >> 1) ^ 0xedb88320 : result >> 1;
+
+ }
+
+ result = ~result;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_crc32_modifier_transform(const GScanCrc32Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_crc32(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_crc32_modifier_get_path(const GScanCrc32Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("crc32");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/classics/crc32.h b/plugins/apihashing/classics/crc32.h
new file mode 100644
index 0000000..0198c5d
--- /dev/null
+++ b/plugins/apihashing/classics/crc32.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * crc32.h - prototypes pour la transormation en empreinte d'API crc32
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CLASSICS_CRC32_H
+#define _PLUGINS_APIHASHING_CLASSICS_CRC32_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_CRC32_MODIFIER g_scan_crc32_modifier_get_type()
+#define G_SCAN_CRC32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_CRC32_MODIFIER, GScanCrc32Modifier))
+#define G_IS_SCAN_CRC32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_CRC32_MODIFIER))
+#define G_SCAN_CRC32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_CRC32_MODIFIER, GScanCrc32ModifierClass))
+#define G_IS_SCAN_CRC32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_CRC32_MODIFIER))
+#define G_SCAN_CRC32_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_CRC32_MODIFIER, GScanCrc32ModifierClass))
+
+
+/* Transormation en empreinte d'API crc32 (instance) */
+typedef GApiHashModifier GScanCrc32Modifier;
+
+/* Transormation en empreinte d'API crc32 (classe) */
+typedef GApiHashModifierClass GScanCrc32ModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte crc32. */
+GType g_scan_crc32_modifier_get_type(void);
+
+/* Construit un modificateur livrant des empreintes crc32. */
+GScanTokenModifier *g_scan_crc32_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CLASSICS_CRC32_H */
diff --git a/plugins/apihashing/classics/djb2.c b/plugins/apihashing/classics/djb2.c
new file mode 100644
index 0000000..524218f
--- /dev/null
+++ b/plugins/apihashing/classics/djb2.c
@@ -0,0 +1,323 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * djb2.c - transormation en empreinte d'API djb2
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "djb2.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en empreintes djb2. */
+static void g_scan_djb2_modifier_class_init(GScanDjb2ModifierClass *klass);
+
+/* Initialise une instance de transmission en empreinte djb2. */
+static void g_scan_djb2_modifier_init(GScanDjb2Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_djb2_modifier_dispose(GScanDjb2Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_djb2_modifier_finalize(GScanDjb2Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_djb2_modifier_get_name(const GScanDjb2Modifier *);
+
+/* Calcule l'empreinte djb2 d'un motif de recherche. */
+static uint32_t compute_djb2(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_djb2_modifier_transform(const GScanDjb2Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_djb2_modifier_get_path(const GScanDjb2Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en encodage Djb2. */
+G_DEFINE_TYPE(GScanDjb2Modifier, g_scan_djb2_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en empreintes djb2. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_djb2_modifier_class_init(GScanDjb2ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_djb2_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_djb2_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_djb2_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_djb2_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_djb2_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en empreinte djb2. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_djb2_modifier_init(GScanDjb2Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_djb2_modifier_dispose(GScanDjb2Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_djb2_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_djb2_modifier_finalize(GScanDjb2Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_djb2_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des empreintes djb2. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_djb2_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_DJB2_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_djb2_modifier_get_name(const GScanDjb2Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("djb2");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte djb2 d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_djb2(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = 0x1505; /* 5381 */
+
+ for (i = 0; i < src->len; i++)
+ result = ((result << 5) + result) + src->data[i]; /* hash * 33 + c */
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_djb2_modifier_transform(const GScanDjb2Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_djb2(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_djb2_modifier_get_path(const GScanDjb2Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("djb2");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/classics/djb2.h b/plugins/apihashing/classics/djb2.h
new file mode 100644
index 0000000..04df1df
--- /dev/null
+++ b/plugins/apihashing/classics/djb2.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * djb2.h - prototypes pour la transormation en empreinte d'API djb2
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CLASSICS_DJB2_H
+#define _PLUGINS_APIHASHING_CLASSICS_DJB2_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_DJB2_MODIFIER g_scan_djb2_modifier_get_type()
+#define G_SCAN_DJB2_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_DJB2_MODIFIER, GScanDjb2Modifier))
+#define G_IS_SCAN_DJB2_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_DJB2_MODIFIER))
+#define G_SCAN_DJB2_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_DJB2_MODIFIER, GScanDjb2ModifierClass))
+#define G_IS_SCAN_DJB2_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_DJB2_MODIFIER))
+#define G_SCAN_DJB2_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_DJB2_MODIFIER, GScanDjb2ModifierClass))
+
+
+/* Transormation en empreinte d'API DJB2 (instance) */
+typedef GApiHashModifier GScanDjb2Modifier;
+
+/* Transormation en empreinte d'API DJB2 (classe) */
+typedef GApiHashModifierClass GScanDjb2ModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte djb2. */
+GType g_scan_djb2_modifier_get_type(void);
+
+/* Construit un modificateur livrant des empreintes djb2. */
+GScanTokenModifier *g_scan_djb2_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CLASSICS_DJB2_H */
diff --git a/plugins/apihashing/classics/ror13.c b/plugins/apihashing/classics/ror13.c
new file mode 100644
index 0000000..e557804
--- /dev/null
+++ b/plugins/apihashing/classics/ror13.c
@@ -0,0 +1,323 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * ror13.c - transormation en empreinte d'API ror13
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "ror13.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en empreintes ror13. */
+static void g_scan_ror13_modifier_class_init(GScanRor13ModifierClass *klass);
+
+/* Initialise une instance de transmission en empreinte ror13. */
+static void g_scan_ror13_modifier_init(GScanRor13Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_ror13_modifier_dispose(GScanRor13Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_ror13_modifier_finalize(GScanRor13Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_ror13_modifier_get_name(const GScanRor13Modifier *);
+
+/* Calcule l'empreinte ror13 d'un motif de recherche. */
+static uint32_t compute_ror13(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_ror13_modifier_transform(const GScanRor13Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_ror13_modifier_get_path(const GScanRor13Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte ror13. */
+G_DEFINE_TYPE(GScanRor13Modifier, g_scan_ror13_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en empreintes ror13. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_ror13_modifier_class_init(GScanRor13ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_ror13_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_ror13_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_ror13_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_ror13_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_ror13_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en empreinte ror13. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_ror13_modifier_init(GScanRor13Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_ror13_modifier_dispose(GScanRor13Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_ror13_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_ror13_modifier_finalize(GScanRor13Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_ror13_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des empreintes ror13. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_ror13_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_ROR13_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_ror13_modifier_get_name(const GScanRor13Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("ror13");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte ror13 d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_ror13(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = 0;
+
+ for (i = 0; i < src->len; i++)
+ result = src->data[i] + ((result << 19) | (result >> 13));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_ror13_modifier_transform(const GScanRor13Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_ror13(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_ror13_modifier_get_path(const GScanRor13Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("ror13");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/classics/ror13.h b/plugins/apihashing/classics/ror13.h
new file mode 100644
index 0000000..43480bd
--- /dev/null
+++ b/plugins/apihashing/classics/ror13.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * ror13.h - prototypes pour la transormation en empreinte d'API ror13
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CLASSICS_ROR13_H
+#define _PLUGINS_APIHASHING_CLASSICS_ROR13_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_ROR13_MODIFIER g_scan_ror13_modifier_get_type()
+#define G_SCAN_ROR13_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ROR13_MODIFIER, GScanRor13Modifier))
+#define G_IS_SCAN_ROR13_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ROR13_MODIFIER))
+#define G_SCAN_ROR13_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ROR13_MODIFIER, GScanRor13ModifierClass))
+#define G_IS_SCAN_ROR13_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ROR13_MODIFIER))
+#define G_SCAN_ROR13_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ROR13_MODIFIER, GScanRor13ModifierClass))
+
+
+/* Transormation en empreinte d'API ror13 (instance) */
+typedef GApiHashModifier GScanRor13Modifier;
+
+/* Transormation en empreinte d'API ror13 (classe) */
+typedef GApiHashModifierClass GScanRor13ModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte ror13. */
+GType g_scan_ror13_modifier_get_type(void);
+
+/* Construit un modificateur livrant des empreintes ror13. */
+GScanTokenModifier *g_scan_ror13_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CLASSICS_ROR13_H */
diff --git a/plugins/apihashing/core.c b/plugins/apihashing/core.c
new file mode 100644
index 0000000..a74a637
--- /dev/null
+++ b/plugins/apihashing/core.c
@@ -0,0 +1,110 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - prototypes pour le calcul d'encodages
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <analysis/scan/core.h>
+#include <plugins/self.h>
+
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+# include "python/module.h"
+# include "python/classics/module.h"
+#endif
+#include "classics/crc32.h"
+#include "classics/djb2.h"
+#include "classics/ror13.h"
+#include "custom/add1505-shl5.h"
+#include "custom/enigma-murmur.h"
+#include "custom/imul21-add.h"
+#include "custom/imul83-add.h"
+#include "custom/sll1-add-hash32.h"
+#include "custom/sub-index1.h"
+#include "custom/sub42.h"
+
+
+#ifdef INCLUDE_PYTHON3_BINDINGS_
+# define PG_REQ RL("PyChrysalide")
+#else
+# define PG_REQ NO_REQ
+#endif
+
+
+
+DEFINE_CHRYSALIDE_PLUGIN("ApiHashing", "API hash computing as ROST modifiers",
+ PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/formats"),
+ PG_REQ, AL(PGA_PLUGIN_INIT));
+
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Prend acte du chargement du greffon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+#define REGISTER_SCAN_MODIFIER(m) \
+ ({ \
+ GScanTokenModifier *__mod; \
+ bool __status; \
+ __mod = m; \
+ __status = register_scan_token_modifier(__mod); \
+ g_object_unref(G_OBJECT(__mod)); \
+ __status; \
+ })
+
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_crc32_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_djb2_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_ror13_modifier_new());
+
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_add1505_shl5_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_enigma_murmur_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_imul21_add_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_imul83_add_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_sll1_add_hash32_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_sub42_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_sub_index1_modifier_new());
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+
+ if (result) result = add_apihashing_module_to_python_module();
+ if (result) result = register_apihashing_classics_modifiers();
+
+#endif
+
+ return result;
+
+}
diff --git a/plugins/apihashing/core.h b/plugins/apihashing/core.h
new file mode 100644
index 0000000..75a6e73
--- /dev/null
+++ b/plugins/apihashing/core.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour le calcul d'encodages
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_CORE_H
+#define _PLUGINS_ENCODINGS_CORE_H
+
+
+#include <plugins/plugin.h>
+#include <plugins/plugin-int.h>
+
+
+
+/* Prend acte du chargement du greffon. */
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_CORE_H */
diff --git a/plugins/apihashing/custom/Makefile.am b/plugins/apihashing/custom/Makefile.am
new file mode 100644
index 0000000..026addc
--- /dev/null
+++ b/plugins/apihashing/custom/Makefile.am
@@ -0,0 +1,18 @@
+
+noinst_LTLIBRARIES = libapihashingcustom.la
+
+libapihashingcustom_la_SOURCES = \
+ add1505-shl5.h add1505-shl5.c \
+ enigma-murmur.h enigma-murmur.c \
+ imul21-add.h imul21-add.c \
+ imul83-add.h imul83-add.c \
+ sll1-add-hash32.h sll1-add-hash32.c \
+ sub-index1.h sub-index1.c \
+ sub42.h sub42.c
+
+libapihashingcustom_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libapihashingcustom_la_SOURCES:%c=)
diff --git a/plugins/apihashing/custom/add1505-shl5.c b/plugins/apihashing/custom/add1505-shl5.c
new file mode 100644
index 0000000..db96cf1
--- /dev/null
+++ b/plugins/apihashing/custom/add1505-shl5.c
@@ -0,0 +1,325 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * add1505-shl5.c - transormation en empreinte d'API add1505-shl5
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "add1505-shl5.h"
+
+
+#include <malloc.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en empreintes add1505-shl5. */
+static void g_scan_add1505_shl5_modifier_class_init(GScanAdd1505Shl5ModifierClass *);
+
+/* Initialise une instance de transmission en empreinte add1505-shl5. */
+static void g_scan_add1505_shl5_modifier_init(GScanAdd1505Shl5Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_add1505_shl5_modifier_dispose(GScanAdd1505Shl5Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_add1505_shl5_modifier_finalize(GScanAdd1505Shl5Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_add1505_shl5_modifier_get_name(const GScanAdd1505Shl5Modifier *);
+
+/* Calcule l'empreinte add1505-shl5 d'un motif de recherche. */
+static uint32_t compute_add1505_shl5_hash32(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_add1505_shl5_modifier_transform(const GScanAdd1505Shl5Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_add1505_shl5_modifier_get_path(const GScanAdd1505Shl5Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte add1505-shl5. */
+G_DEFINE_TYPE(GScanAdd1505Shl5Modifier, g_scan_add1505_shl5_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en empreintes add1505-shl5. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_add1505_shl5_modifier_class_init(GScanAdd1505Shl5ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_add1505_shl5_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_add1505_shl5_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_add1505_shl5_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_add1505_shl5_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_add1505_shl5_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en empreinte add1505-shl5. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_add1505_shl5_modifier_init(GScanAdd1505Shl5Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_add1505_shl5_modifier_dispose(GScanAdd1505Shl5Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_add1505_shl5_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_add1505_shl5_modifier_finalize(GScanAdd1505Shl5Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_add1505_shl5_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des empreintes add1505-shl5. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_add1505_shl5_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_add1505_shl5_modifier_get_name(const GScanAdd1505Shl5Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("add1505-shl5");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte add1505-shl5 d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_add1505_shl5_hash32(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = 0x1505;
+
+ for (i = 0; i < src->len; i++)
+ {
+ result += (result << 5);
+ result += src->data[i];
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_add1505_shl5_modifier_transform(const GScanAdd1505Shl5Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_add1505_shl5_hash32(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_add1505_shl5_modifier_get_path(const GScanAdd1505Shl5Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("add1505-shl5");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/custom/add1505-shl5.h b/plugins/apihashing/custom/add1505-shl5.h
new file mode 100644
index 0000000..5e71987
--- /dev/null
+++ b/plugins/apihashing/custom/add1505-shl5.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * add1505-shl5.h - prototypes pour la transormation en empreinte d'API add1505-shl5
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CUSTOM_ADD1505_SHL5_H
+#define _PLUGINS_APIHASHING_CUSTOM_ADD1505_SHL5_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_ADD1505_SHL5_MODIFIER g_scan_add1505_shl5_modifier_get_type()
+#define G_SCAN_ADD1505_SHL5_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, GScanAdd1505Shl5Modifier))
+#define G_IS_SCAN_ADD1505_SHL5_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER))
+#define G_SCAN_ADD1505_SHL5_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, GScanAdd1505Shl5ModifierClass))
+#define G_IS_SCAN_ADD1505_SHL5_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER))
+#define G_SCAN_ADD1505_SHL5_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, GScanAdd1505Shl5ModifierClass))
+
+
+/* Transormation en empreinte d'API add1505-shl5 (instance) */
+typedef GApiHashModifier GScanAdd1505Shl5Modifier;
+
+/* Transormation en empreinte d'API add1505-shl5 (classe) */
+typedef GApiHashModifierClass GScanAdd1505Shl5ModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte add1505-shl5. */
+GType g_scan_add1505_shl5_modifier_get_type(void);
+
+/* Construit un modificateur livrant des empreintes add1505-shl5. */
+GScanTokenModifier *g_scan_add1505_shl5_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CUSTOM_ADD1505_SHL5_H */
diff --git a/plugins/apihashing/custom/enigma-murmur.c b/plugins/apihashing/custom/enigma-murmur.c
new file mode 100644
index 0000000..cdc35b0
--- /dev/null
+++ b/plugins/apihashing/custom/enigma-murmur.c
@@ -0,0 +1,377 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enigma-murmur.c - transormation en empreinte d'API enigma-murmur
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "enigma-murmur.h"
+
+
+#include <malloc.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des empreintes enigma-murmur. */
+static void g_scan_enigma_murmur_modifier_class_init(GScanEnigmaMurmurModifierClass *);
+
+/* Initialise une instance d'empreinte enigma-murmur. */
+static void g_scan_enigma_murmur_modifier_init(GScanEnigmaMurmurModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_enigma_murmur_modifier_dispose(GScanEnigmaMurmurModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_enigma_murmur_modifier_finalize(GScanEnigmaMurmurModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_enigma_murmur_modifier_get_name(const GScanEnigmaMurmurModifier *);
+
+/* Calcule l'empreinte enigma-murmur d'un motif de recherche. */
+static uint32_t compute_enigma_murmur_hash32(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_enigma_murmur_modifier_transform(const GScanEnigmaMurmurModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_enigma_murmur_modifier_get_path(const GScanEnigmaMurmurModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte enigma-murmur. */
+G_DEFINE_TYPE(GScanEnigmaMurmurModifier, g_scan_enigma_murmur_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des empreintes enigma-murmur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_enigma_murmur_modifier_class_init(GScanEnigmaMurmurModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_enigma_murmur_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_enigma_murmur_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_enigma_murmur_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_enigma_murmur_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_enigma_murmur_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance d'empreinte enigma-murmur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_enigma_murmur_modifier_init(GScanEnigmaMurmurModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_enigma_murmur_modifier_dispose(GScanEnigmaMurmurModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_enigma_murmur_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_enigma_murmur_modifier_finalize(GScanEnigmaMurmurModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_enigma_murmur_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur pour des empreintes enigma-murmur. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_enigma_murmur_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_enigma_murmur_modifier_get_name(const GScanEnigmaMurmurModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("enigma-murmur");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte enigma-murmur d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_enigma_murmur_hash32(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t blk_count; /* Nombre de blocs présents */
+ size_t i; /* Boucle de parcours */
+ uint32_t k; /* Valeur pour un bloc */
+ const bin_t *tail; /* Fragement de bloc final */
+
+ result = 0x4a03bdfa;
+
+ /* Traitement par blocs de 4 octets */
+
+ blk_count = src->len / 4;
+
+ for (i = 0; i < blk_count; i++)
+ {
+ k = ((uint32_t *)src->data)[i];
+
+ k *= 0xcc9e2d51;
+ k = (k << 15) | (k >> 17);
+ k *= 0x1b873593;
+
+ result ^= k;
+ result = (result << 13) | (result >> 19);
+ result = result * 5 + 0xe6546b64;
+
+ }
+
+ /* Traitement du reste */
+
+ tail = src->static_bin_data + 4 * blk_count;
+
+ k = 0;
+
+ switch (src->len & 3)
+ {
+ case 3:
+ k ^= (tail[2] << 16);
+
+ case 2:
+ k ^= (tail[1] << 8);
+
+ case 1:
+ k ^= tail[0];
+ k *= 0xcc9e2d51;
+ k = (k << 15) | (k >> (17));
+ k *= 0x1b873593;
+ result ^= k;
+ break;
+
+ case 0:
+ break;
+
+ }
+
+ /* Conclusion */
+
+ result ^= src->len;
+
+ result ^= (result >> 16);
+ result *= 0x85ebca6b;
+ result ^= (result >> 13);
+ result *= 0xc2b2ae35;
+ result ^= (result >> 16);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_enigma_murmur_modifier_transform(const GScanEnigmaMurmurModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_enigma_murmur_hash32(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_enigma_murmur_modifier_get_path(const GScanEnigmaMurmurModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("enigma-murmur");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/custom/enigma-murmur.h b/plugins/apihashing/custom/enigma-murmur.h
new file mode 100644
index 0000000..29ae803
--- /dev/null
+++ b/plugins/apihashing/custom/enigma-murmur.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enigma-murmur.h - prototypes pour la transormation en empreinte d'API enigma-murmur
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CUSTOM_ENIGMA_MURMUR_H
+#define _PLUGINS_APIHASHING_CUSTOM_ENIGMA_MURMUR_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER g_scan_enigma_murmur_modifier_get_type()
+#define G_SCAN_ENIGMA_MURMUR_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, GScanEnigmaMurmurModifier))
+#define G_IS_SCAN_ENIGMA_MURMUR_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER))
+#define G_SCAN_ENIGMA_MURMUR_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, GScanEnigmaMurmurModifierClass))
+#define G_IS_SCAN_ENIGMA_MURMUR_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER))
+#define G_SCAN_ENIGMA_MURMUR_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, GScanEnigmaMurmurModifierClass))
+
+
+/* Transormation en empreinte d'API enigma-murmur (instance) */
+typedef GApiHashModifier GScanEnigmaMurmurModifier;
+
+/* Transormation en empreinte d'API enigma-murmur (classe) */
+typedef GApiHashModifierClass GScanEnigmaMurmurModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte enigma-murmur. */
+GType g_scan_enigma_murmur_modifier_get_type(void);
+
+/* Construit un modificateur pour des empreintes enigma-murmur. */
+GScanTokenModifier *g_scan_enigma_murmur_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CUSTOM_ENIGMA_MURMUR_H */
diff --git a/plugins/apihashing/custom/imul21-add.c b/plugins/apihashing/custom/imul21-add.c
new file mode 100644
index 0000000..2f71910
--- /dev/null
+++ b/plugins/apihashing/custom/imul21-add.c
@@ -0,0 +1,326 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul21-add.c - transormation en empreinte d'API imul21-add
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "imul21-add.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en imul21-add. */
+static void g_scan_imul21_add_modifier_class_init(GScanImul21AddModifierClass *);
+
+/* Initialise une instance de transmission en imul21-add. */
+static void g_scan_imul21_add_modifier_init(GScanImul21AddModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_imul21_add_modifier_dispose(GScanImul21AddModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_imul21_add_modifier_finalize(GScanImul21AddModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_imul21_add_modifier_get_name(const GScanImul21AddModifier *);
+
+/* Calcule l'empreinte imul21-add d'un motif de recherche. */
+static uint32_t compute_imul21_add(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_imul21_add_modifier_transform(const GScanImul21AddModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_imul21_add_modifier_get_path(const GScanImul21AddModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte imul21-add. */
+G_DEFINE_TYPE(GScanImul21AddModifier, g_scan_imul21_add_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en imul21-add. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul21_add_modifier_class_init(GScanImul21AddModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_imul21_add_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_imul21_add_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_imul21_add_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_imul21_add_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_imul21_add_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en imul21-add. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul21_add_modifier_init(GScanImul21AddModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul21_add_modifier_dispose(GScanImul21AddModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_imul21_add_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul21_add_modifier_finalize(GScanImul21AddModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_imul21_add_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur vers empreintes imul21-add. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_imul21_add_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_IMUL21_ADD_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_imul21_add_modifier_get_name(const GScanImul21AddModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("imul21-add");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte imul21-add d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_imul21_add(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = 0;
+
+ for (i = 0; i < src->len; i++)
+ {
+ result *= 0x21;
+ result += src->data[i];
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_imul21_add_modifier_transform(const GScanImul21AddModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_imul21_add(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_imul21_add_modifier_get_path(const GScanImul21AddModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("imul21-add");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/custom/imul21-add.h b/plugins/apihashing/custom/imul21-add.h
new file mode 100644
index 0000000..fcaa140
--- /dev/null
+++ b/plugins/apihashing/custom/imul21-add.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul21-add.h - prototypes pour la transormation en empreinte d'API imul21-add
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CUSTOM_IMUL21_ADD_H
+#define _PLUGINS_APIHASHING_CUSTOM_IMUL21_ADD_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_IMUL21_ADD_MODIFIER g_scan_imul21_add_modifier_get_type()
+#define G_SCAN_IMUL21_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_IMUL21_ADD_MODIFIER, GScanImul21AddModifier))
+#define G_IS_SCAN_IMUL21_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_IMUL21_ADD_MODIFIER))
+#define G_SCAN_IMUL21_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_IMUL21_ADD_MODIFIER, GScanImul21AddModifierClass))
+#define G_IS_SCAN_IMUL21_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_IMUL21_ADD_MODIFIER))
+#define G_SCAN_IMUL21_ADD_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_IMUL21_ADD_MODIFIER, GScanImul21AddModifierClass))
+
+
+/* Transformation en empreinte d'API imul21-add (instance) */
+typedef GApiHashModifier GScanImul21AddModifier;
+
+/* Transformation en empreinte d'API imul21-add (classe) */
+typedef GApiHashModifierClass GScanImul21AddModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte imul21-add. */
+GType g_scan_imul21_add_modifier_get_type(void);
+
+/* Construit un modificateur vers empreintes imul21-add. */
+GScanTokenModifier *g_scan_imul21_add_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CUSTOM_IMUL21_ADD_H */
diff --git a/plugins/apihashing/custom/imul83-add.c b/plugins/apihashing/custom/imul83-add.c
new file mode 100644
index 0000000..29f8cf5
--- /dev/null
+++ b/plugins/apihashing/custom/imul83-add.c
@@ -0,0 +1,326 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul83-add.c - transormation en empreinte d'API imul83-add
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "imul83-add.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en imul83-add. */
+static void g_scan_imul83_add_modifier_class_init(GScanImul83AddModifierClass *);
+
+/* Initialise une instance de transmission en imul83-add. */
+static void g_scan_imul83_add_modifier_init(GScanImul83AddModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_imul83_add_modifier_dispose(GScanImul83AddModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_imul83_add_modifier_finalize(GScanImul83AddModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_imul83_add_modifier_get_name(const GScanImul83AddModifier *);
+
+/* Calcule l'empreinte imul83-add d'un motif de recherche. */
+static uint32_t compute_imul83_add(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_imul83_add_modifier_transform(const GScanImul83AddModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_imul83_add_modifier_get_path(const GScanImul83AddModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte imul83-add. */
+G_DEFINE_TYPE(GScanImul83AddModifier, g_scan_imul83_add_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en imul83-add. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul83_add_modifier_class_init(GScanImul83AddModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_imul83_add_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_imul83_add_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_imul83_add_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_imul83_add_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_imul83_add_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en imul83-add. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul83_add_modifier_init(GScanImul83AddModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul83_add_modifier_dispose(GScanImul83AddModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_imul83_add_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_imul83_add_modifier_finalize(GScanImul83AddModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_imul83_add_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur vers empreintes imul83-add. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_imul83_add_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_IMUL83_ADD_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_imul83_add_modifier_get_name(const GScanImul83AddModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("imul83-add");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte imul83-add d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_imul83_add(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = 0;
+
+ for (i = 0; i < src->len; i++)
+ {
+ result *= 0x83;
+ result += src->data[i];
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_imul83_add_modifier_transform(const GScanImul83AddModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_imul83_add(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_imul83_add_modifier_get_path(const GScanImul83AddModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("imul83-add");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/custom/imul83-add.h b/plugins/apihashing/custom/imul83-add.h
new file mode 100644
index 0000000..7e376ee
--- /dev/null
+++ b/plugins/apihashing/custom/imul83-add.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul83-add.h - prototypes pour la transormation en empreinte d'API imul83-add
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CUSTOM_IMUL83_ADD_H
+#define _PLUGINS_APIHASHING_CUSTOM_IMUL83_ADD_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_IMUL83_ADD_MODIFIER g_scan_imul83_add_modifier_get_type()
+#define G_SCAN_IMUL83_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_IMUL83_ADD_MODIFIER, GScanImul83AddModifier))
+#define G_IS_SCAN_IMUL83_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_IMUL83_ADD_MODIFIER))
+#define G_SCAN_IMUL83_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_IMUL83_ADD_MODIFIER, GScanImul83AddModifierClass))
+#define G_IS_SCAN_IMUL83_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_IMUL83_ADD_MODIFIER))
+#define G_SCAN_IMUL83_ADD_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_IMUL83_ADD_MODIFIER, GScanImul83AddModifierClass))
+
+
+/* Transformation en empreinte d'API imul83-add (instance) */
+typedef GApiHashModifier GScanImul83AddModifier;
+
+/* Transformation en empreinte d'API imul83-add (classe) */
+typedef GApiHashModifierClass GScanImul83AddModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte imul83-add. */
+GType g_scan_imul83_add_modifier_get_type(void);
+
+/* Construit un modificateur vers empreintes imul83-add. */
+GScanTokenModifier *g_scan_imul83_add_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CUSTOM_IMUL83_ADD_H */
diff --git a/plugins/apihashing/custom/sll1-add-hash32.c b/plugins/apihashing/custom/sll1-add-hash32.c
new file mode 100644
index 0000000..de00f81
--- /dev/null
+++ b/plugins/apihashing/custom/sll1-add-hash32.c
@@ -0,0 +1,326 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sll1-add-hash32.c - transormation en empreinte d'API sll1-add-hash32
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "sll1-add-hash32.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en sll1-add-hash32. */
+static void g_scan_sll1_add_hash32_modifier_class_init(GScanSll1AddHash32ModifierClass *klass);
+
+/* Initialise une instance de transmission en sll1-add-hash32. */
+static void g_scan_sll1_add_hash32_modifier_init(GScanSll1AddHash32Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_sll1_add_hash32_modifier_dispose(GScanSll1AddHash32Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_sll1_add_hash32_modifier_finalize(GScanSll1AddHash32Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_sll1_add_hash32_modifier_get_name(const GScanSll1AddHash32Modifier *);
+
+/* Calcule l'empreinte sll1-add-hash32 d'un motif de recherche. */
+static uint32_t compute_sll1_add_hash32(const sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_sll1_add_hash32_modifier_transform(const GScanSll1AddHash32Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_sll1_add_hash32_modifier_get_path(const GScanSll1AddHash32Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte sll1-add-hash32. */
+G_DEFINE_TYPE(GScanSll1AddHash32Modifier, g_scan_sll1_add_hash32_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en sll1-add-hash32. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sll1_add_hash32_modifier_class_init(GScanSll1AddHash32ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sll1_add_hash32_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_sll1_add_hash32_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_sll1_add_hash32_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_sll1_add_hash32_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_sll1_add_hash32_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en sll1-add-hash32. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sll1_add_hash32_modifier_init(GScanSll1AddHash32Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sll1_add_hash32_modifier_dispose(GScanSll1AddHash32Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_sll1_add_hash32_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sll1_add_hash32_modifier_finalize(GScanSll1AddHash32Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_sll1_add_hash32_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur vers empreintes sll1-add-hash32. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_sll1_add_hash32_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_sll1_add_hash32_modifier_get_name(const GScanSll1AddHash32Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("sll1-add-hash32");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = séquence d'octets à traiter. *
+* *
+* Description : Calcule l'empreinte sll1-add-hash32 d'un motif de recherche. *
+* *
+* Retour : Valeur entière de l'empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint32_t compute_sll1_add_hash32(const sized_binary_t *src)
+{
+ uint32_t result; /* Valeur à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = 0;
+
+ for (i = 0; i < src->len; i++)
+ {
+ result += (src->data[i] | 0x60);
+ result <<= 1;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_sll1_add_hash32_modifier_transform(const GScanSll1AddHash32Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ uint32_t hash; /* Valeur d'empreinte calculée */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ hash = compute_sll1_add_hash32(_src);
+
+ binary->data = malloc(sizeof(hash) * sizeof(bin_t));
+ binary->len = sizeof(hash);
+
+ memcpy(binary->data, &hash, sizeof(hash));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_sll1_add_hash32_modifier_get_path(const GScanSll1AddHash32Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("sll1-add-hash32");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/custom/sll1-add-hash32.h b/plugins/apihashing/custom/sll1-add-hash32.h
new file mode 100644
index 0000000..39abee2
--- /dev/null
+++ b/plugins/apihashing/custom/sll1-add-hash32.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sll1-add-hash32.h - prototypes pour la transormation en empreinte d'API sll1-add-hash32
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CUSTOM_SLL1_ADD_HASH32_H
+#define _PLUGINS_APIHASHING_CUSTOM_SLL1_ADD_HASH32_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER g_scan_sll1_add_hash32_modifier_get_type()
+#define G_SCAN_SLL1_ADD_HASH32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, GScanSll1AddHash32Modifier))
+#define G_IS_SCAN_SLL1_ADD_HASH32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER))
+#define G_SCAN_SLL1_ADD_HASH32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, GScanSll1AddHash32ModifierClass))
+#define G_IS_SCAN_SLL1_ADD_HASH32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER))
+#define G_SCAN_SLL1_ADD_HASH32_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, GScanSll1AddHash32ModifierClass))
+
+
+/* Transormation en empreinte d'API sll1_add_hash32 (instance) */
+typedef GApiHashModifier GScanSll1AddHash32Modifier;
+
+/* Transormation en empreinte d'API sll1_add_hash32 (classe) */
+typedef GApiHashModifierClass GScanSll1AddHash32ModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte sll1-add-hash32. */
+GType g_scan_sll1_add_hash32_modifier_get_type(void);
+
+/* Construit un modificateur vers empreintes sll1-add-hash32. */
+GScanTokenModifier *g_scan_sll1_add_hash32_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CUSTOM_SLL1_ADD_HASH32_H */
diff --git a/plugins/apihashing/custom/sub-index1.c b/plugins/apihashing/custom/sub-index1.c
new file mode 100644
index 0000000..79eafd8
--- /dev/null
+++ b/plugins/apihashing/custom/sub-index1.c
@@ -0,0 +1,291 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub-index1.c - transormation en empreinte d'API sub-index1
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "sub-index1.h"
+
+
+#include <malloc.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en sub-index1. */
+static void g_scan_sub_index1_modifier_class_init(GScanSubIndex1ModifierClass *);
+
+/* Initialise une instance de transmission en sub-index1. */
+static void g_scan_sub_index1_modifier_init(GScanSubIndex1Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_sub_index1_modifier_dispose(GScanSubIndex1Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_sub_index1_modifier_finalize(GScanSubIndex1Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_sub_index1_modifier_get_name(const GScanSubIndex1Modifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_sub_index1_modifier_transform(const GScanSubIndex1Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_sub_index1_modifier_get_path(const GScanSubIndex1Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte sub-index1. */
+G_DEFINE_TYPE(GScanSubIndex1Modifier, g_scan_sub_index1_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en sub-index1. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub_index1_modifier_class_init(GScanSubIndex1ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sub_index1_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_sub_index1_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_sub_index1_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_sub_index1_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_sub_index1_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en sub-index1. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub_index1_modifier_init(GScanSubIndex1Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub_index1_modifier_dispose(GScanSubIndex1Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_sub_index1_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub_index1_modifier_finalize(GScanSubIndex1Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_sub_index1_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des empreintes sub-index1. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_sub_index1_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SUB_INDEX1_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_sub_index1_modifier_get_name(const GScanSubIndex1Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("sub-index1");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_sub_index1_modifier_transform(const GScanSubIndex1Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ binary->data[k] = _src->data[k] + k + 1;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_sub_index1_modifier_get_path(const GScanSubIndex1Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("sub-index1");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/custom/sub-index1.h b/plugins/apihashing/custom/sub-index1.h
new file mode 100644
index 0000000..b2acc06
--- /dev/null
+++ b/plugins/apihashing/custom/sub-index1.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub-index1.h - prototypes pour la transormation en empreinte d'API sub-index1
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CUSTOM_SUB_INDEX1_H
+#define _PLUGINS_APIHASHING_CUSTOM_SUB_INDEX1_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_SUB_INDEX1_MODIFIER g_scan_sub_index1_modifier_get_type()
+#define G_SCAN_SUB_INDEX1_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SUB_INDEX1_MODIFIER, GScanSubIndex1Modifier))
+#define G_IS_SCAN_SUB_INDEX1_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SUB_INDEX1_MODIFIER))
+#define G_SCAN_SUB_INDEX1_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SUB_INDEX1_MODIFIER, GScanSubIndex1ModifierClass))
+#define G_IS_SCAN_SUB_INDEX1_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SUB_INDEX1_MODIFIER))
+#define G_SCAN_SUB_INDEX1_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SUB_INDEX1_MODIFIER, GScanSubIndex1ModifierClass))
+
+
+/* Transormation en empreinte d'API sub-index1 (instance) */
+typedef GApiHashModifier GScanSubIndex1Modifier;
+
+/* Transormation en empreinte d'API sub-index1 (classe) */
+typedef GApiHashModifierClass GScanSubIndex1ModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte sub-index1. */
+GType g_scan_sub_index1_modifier_get_type(void);
+
+/* Construit un modificateur livrant des empreintes sub-index1. */
+GScanTokenModifier *g_scan_sub_index1_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CUSTOM_SUB_INDEX1_H */
diff --git a/plugins/apihashing/custom/sub42.c b/plugins/apihashing/custom/sub42.c
new file mode 100644
index 0000000..95bd49d
--- /dev/null
+++ b/plugins/apihashing/custom/sub42.c
@@ -0,0 +1,291 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub42.c - transormation en empreinte d'API sub42
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "sub42.h"
+
+
+#include <malloc.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en empreintes sub42. */
+static void g_scan_sub42_modifier_class_init(GScanSub42ModifierClass *);
+
+/* Initialise une instance de transmission en empreinte sub42. */
+static void g_scan_sub42_modifier_init(GScanSub42Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_sub42_modifier_dispose(GScanSub42Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_sub42_modifier_finalize(GScanSub42Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_sub42_modifier_get_name(const GScanSub42Modifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_sub42_modifier_transform(const GScanSub42Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_sub42_modifier_get_path(const GScanSub42Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en empreinte sub42. */
+G_DEFINE_TYPE(GScanSub42Modifier, g_scan_sub42_modifier, G_TYPE_API_HASH_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en empreintes sub42. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub42_modifier_class_init(GScanSub42ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sub42_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_sub42_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_sub42_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_sub42_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_sub42_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en empreinte sub42. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub42_modifier_init(GScanSub42Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub42_modifier_dispose(GScanSub42Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_sub42_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sub42_modifier_finalize(GScanSub42Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_sub42_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des empreintes sub42. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_sub42_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SUB42_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_sub42_modifier_get_name(const GScanSub42Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("sub42");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_sub42_modifier_transform(const GScanSub42Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ binary->data[k] = _src->data[k] + 0x42;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_sub42_modifier_get_path(const GScanSub42Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("sub42");
+
+ return result;
+
+}
diff --git a/plugins/apihashing/custom/sub42.h b/plugins/apihashing/custom/sub42.h
new file mode 100644
index 0000000..8a11741
--- /dev/null
+++ b/plugins/apihashing/custom/sub42.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub42.h - prototypes pour la transormation en empreinte d'API sub42
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_CUSTOM_SUB42_H
+#define _PLUGINS_APIHASHING_CUSTOM_SUB42_H
+
+
+#include <glib-object.h>
+
+
+#include "../apihash.h"
+
+
+
+#define G_TYPE_SCAN_SUB42_MODIFIER g_scan_sub42_modifier_get_type()
+#define G_SCAN_SUB42_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SUB42_MODIFIER, GScanSub42Modifier))
+#define G_IS_SCAN_SUB42_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SUB42_MODIFIER))
+#define G_SCAN_SUB42_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SUB42_MODIFIER, GScanSub42ModifierClass))
+#define G_IS_SCAN_SUB42_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SUB42_MODIFIER))
+#define G_SCAN_SUB42_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SUB42_MODIFIER, GScanSub42ModifierClass))
+
+
+/* Transormation en empreinte d'API sub42 (instance) */
+typedef GApiHashModifier GScanSub42Modifier;
+
+/* Transormation en empreinte d'API sub42 (classe) */
+typedef GApiHashModifierClass GScanSub42ModifierClass;
+
+
+/* Indique le type défini pour une transormation en empreinte sub42. */
+GType g_scan_sub42_modifier_get_type(void);
+
+/* Construit un modificateur livrant des empreintes sub42. */
+GScanTokenModifier *g_scan_sub42_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_CUSTOM_SUB42_H */
diff --git a/plugins/apihashing/python/Makefile.am b/plugins/apihashing/python/Makefile.am
new file mode 100644
index 0000000..d94218d
--- /dev/null
+++ b/plugins/apihashing/python/Makefile.am
@@ -0,0 +1,20 @@
+
+noinst_LTLIBRARIES = libapihashingpython.la
+
+libapihashingpython_la_SOURCES = \
+ apihash.h apihash.c \
+ module.h module.c
+
+libapihashingpython_la_LIBADD = \
+ classics/libapihashingpythonclassics.la
+
+libapihashingpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libapihashingpython_la_SOURCES:%c=)
+
+
+SUBDIRS = classics
diff --git a/plugins/apihashing/python/apihash.c b/plugins/apihashing/python/apihash.c
new file mode 100644
index 0000000..a3ae519
--- /dev/null
+++ b/plugins/apihashing/python/apihash.c
@@ -0,0 +1,212 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.c - équivalent Python du fichier "plugins/encodings/rost/base64.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "apihash.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/scan/patterns/modifier.h>
+
+
+#include "../apihash.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(api_hash_modifier, G_TYPE_API_HASH_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_api_hash_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_api_hash_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define API_HASH_MODIFIER_DOC \
+ "The *ApiHashModifier* class is the base object for all algorithms" \
+ " involed in malwares and revolving API functions to call from" \
+ " a hash value.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " ApiHashModifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_api_hash_modifier_type(void)
+{
+ static PyMethodDef py_api_hash_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_api_hash_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_api_hash_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.apihashing.ApiHashModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = API_HASH_MODIFIER_DOC,
+
+ .tp_methods = py_api_hash_modifier_methods,
+ .tp_getset = py_api_hash_modifier_getseters,
+
+ .tp_init = py_api_hash_modifier_init,
+ .tp_new = py_api_hash_modifier_new,
+
+ };
+
+ return &py_api_hash_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.....ApiHashModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_api_hash_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python Base64Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_api_hash_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.apihashing");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_token_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_API_HASH_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation par empreinte d'API. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_api_hash_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_api_hash_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to API hash modifier");
+ break;
+
+ case 1:
+ *((GApiHashModifier **)dst) = G_API_HASH_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/apihash.h b/plugins/apihashing/python/apihash.h
new file mode 100644
index 0000000..5474d49
--- /dev/null
+++ b/plugins/apihashing/python/apihash.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.h - équivalent Python du fichier "plugins/encodings/rost/base64.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H
+#define _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_api_hash_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.apihashing.ApiHashModifier'. */
+bool ensure_python_api_hash_modifier_is_registered(void);
+
+/* Tente de convertir en transformation par empreinte d'API. */
+int convert_to_api_hash_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H */
diff --git a/plugins/apihashing/python/classics/Makefile.am b/plugins/apihashing/python/classics/Makefile.am
new file mode 100644
index 0000000..316e13f
--- /dev/null
+++ b/plugins/apihashing/python/classics/Makefile.am
@@ -0,0 +1,16 @@
+
+noinst_LTLIBRARIES = libapihashingpythonclassics.la
+
+libapihashingpythonclassics_la_SOURCES = \
+ crc32.h crc32.c \
+ djb2.h djb2.c \
+ module.h module.c \
+ ror13.h ror13.c
+
+libapihashingpythonclassics_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libapihashingpythonclassics_la_SOURCES:%c=)
diff --git a/plugins/apihashing/python/classics/crc32.c b/plugins/apihashing/python/classics/crc32.c
new file mode 100644
index 0000000..d7c6f7c
--- /dev/null
+++ b/plugins/apihashing/python/classics/crc32.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * crc32.c - équivalent Python du fichier "plugins/apihashing/classics/crc32.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "crc32.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../classics/crc32.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_crc32_modifier, G_TYPE_SCAN_CRC32_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_crc32_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_crc32_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_CRC32_MODIFIER_DOC \
+ "The *Crc32Modifier* class transforms a byte pattern into its" \
+ " crc32 encoded form.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Crc32Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_crc32_modifier_type(void)
+{
+ static PyMethodDef py_scan_crc32_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_crc32_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_crc32_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Crc32Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_CRC32_MODIFIER_DOC,
+
+ .tp_methods = py_scan_crc32_modifier_methods,
+ .tp_getset = py_scan_crc32_modifier_getseters,
+
+ .tp_init = py_scan_crc32_modifier_init,
+ .tp_new = py_scan_crc32_modifier_new,
+
+ };
+
+ return &py_scan_crc32_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....Crc32Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_crc32_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python Crc32Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_crc32_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_CRC32_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation en empreinte crc32. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_crc32_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_crc32_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to crc32 modifier");
+ break;
+
+ case 1:
+ *((GScanCrc32Modifier **)dst) = G_SCAN_CRC32_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/classics/crc32.h b/plugins/apihashing/python/classics/crc32.h
new file mode 100644
index 0000000..118a916
--- /dev/null
+++ b/plugins/apihashing/python/classics/crc32.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * crc32.h - équivalent Python du fichier "plugins/apihashing/classics/crc32.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_CRC32_H
+#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_CRC32_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_crc32_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Crc32Modifier'. */
+bool ensure_python_scan_crc32_modifier_is_registered(void);
+
+/* Tente de convertir en transformation en empreinte crc32. */
+int convert_to_scan_crc32_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_CRC32_H */
diff --git a/plugins/apihashing/python/classics/djb2.c b/plugins/apihashing/python/classics/djb2.c
new file mode 100644
index 0000000..f3d0844
--- /dev/null
+++ b/plugins/apihashing/python/classics/djb2.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * djb2.c - équivalent Python du fichier "plugins/apihashing/classics/djb2.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "djb2.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../classics/djb2.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_djb2_modifier, G_TYPE_SCAN_DJB2_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_djb2_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_djb2_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_DJB2_MODIFIER_DOC \
+ "The *Djb2Modifier* class transforms a byte pattern into its" \
+ " djb2 encoded form.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Djb2Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_djb2_modifier_type(void)
+{
+ static PyMethodDef py_scan_djb2_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_djb2_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_djb2_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Djb2Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_DJB2_MODIFIER_DOC,
+
+ .tp_methods = py_scan_djb2_modifier_methods,
+ .tp_getset = py_scan_djb2_modifier_getseters,
+
+ .tp_init = py_scan_djb2_modifier_init,
+ .tp_new = py_scan_djb2_modifier_new,
+
+ };
+
+ return &py_scan_djb2_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....Djb2Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_djb2_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python Djb2Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_djb2_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_DJB2_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation en empreinte djb2. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_djb2_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_djb2_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to djb2 modifier");
+ break;
+
+ case 1:
+ *((GScanDjb2Modifier **)dst) = G_SCAN_DJB2_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/classics/djb2.h b/plugins/apihashing/python/classics/djb2.h
new file mode 100644
index 0000000..b4086f8
--- /dev/null
+++ b/plugins/apihashing/python/classics/djb2.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * djb2.h - équivalent Python du fichier "plugins/apihashing/classics/djb2.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_DJB2_H
+#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_DJB2_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_djb2_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Djb2Modifier'. */
+bool ensure_python_scan_djb2_modifier_is_registered(void);
+
+/* Tente de convertir en transformation en empreinte djb2. */
+int convert_to_scan_djb2_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_DJB2_H */
diff --git a/plugins/apihashing/python/classics/module.c b/plugins/apihashing/python/classics/module.c
new file mode 100644
index 0000000..b00757a
--- /dev/null
+++ b/plugins/apihashing/python/classics/module.c
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire classics en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "crc32.h"
+#include "djb2.h"
+#include "ror13.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les modificateurs d'empreintes classiques pour ROST. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool register_apihashing_classics_modifiers(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_scan_crc32_modifier_is_registered();
+ if (result) result = ensure_python_scan_djb2_modifier_is_registered();
+ if (result) result = ensure_python_scan_ror13_modifier_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/classics/module.h b/plugins/apihashing/python/classics/module.h
new file mode 100644
index 0000000..10c817d
--- /dev/null
+++ b/plugins/apihashing/python/classics/module.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire classics en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_MODULE_H
+#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Intègre les modificateurs d'empreintes classiques pour ROST. */
+bool register_apihashing_classics_modifiers(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_MODULE_H */
diff --git a/plugins/apihashing/python/classics/ror13.c b/plugins/apihashing/python/classics/ror13.c
new file mode 100644
index 0000000..429f7da
--- /dev/null
+++ b/plugins/apihashing/python/classics/ror13.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * ror13.c - équivalent Python du fichier "plugins/apihashing/classics/ror13.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "ror13.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../classics/ror13.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_ror13_modifier, G_TYPE_SCAN_ROR13_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_ror13_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_ror13_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_ROR13_MODIFIER_DOC \
+ "The *Ror13Modifier* class transforms a byte pattern into its" \
+ " ror13 encoded form.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Ror13Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_ror13_modifier_type(void)
+{
+ static PyMethodDef py_scan_ror13_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_ror13_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_ror13_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Ror13Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_ROR13_MODIFIER_DOC,
+
+ .tp_methods = py_scan_ror13_modifier_methods,
+ .tp_getset = py_scan_ror13_modifier_getseters,
+
+ .tp_init = py_scan_ror13_modifier_init,
+ .tp_new = py_scan_ror13_modifier_new,
+
+ };
+
+ return &py_scan_ror13_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....Ror13Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_ror13_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python Ror13Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_ror13_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_ROR13_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation en empreinte ror13. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_ror13_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_ror13_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ror13 modifier");
+ break;
+
+ case 1:
+ *((GScanRor13Modifier **)dst) = G_SCAN_ROR13_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/classics/ror13.h b/plugins/apihashing/python/classics/ror13.h
new file mode 100644
index 0000000..021a516
--- /dev/null
+++ b/plugins/apihashing/python/classics/ror13.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * ror13.h - équivalent Python du fichier "plugins/apihashing/classics/ror13.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_ROR13_H
+#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_ROR13_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_ror13_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Ror13Modifier'. */
+bool ensure_python_scan_ror13_modifier_is_registered(void);
+
+/* Tente de convertir en transformation en empreinte ror13. */
+int convert_to_scan_ror13_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_ROR13_H */
diff --git a/plugins/apihashing/python/custom/Makefile.am b/plugins/apihashing/python/custom/Makefile.am
new file mode 100644
index 0000000..5fbb11f
--- /dev/null
+++ b/plugins/apihashing/python/custom/Makefile.am
@@ -0,0 +1,20 @@
+
+noinst_LTLIBRARIES = libapihashingpythoncustom.la
+
+libapihashingpythoncustom_la_SOURCES = \
+ add1505-shl5.h add1505-shl5.c \
+ enigma-murmur.h enigma-murmur.c \
+ imul21-add.h imul21-add.c \
+ imul83-add.h imul83-add.c \
+ module.h module.c \
+ sll1-add-hash32.h sll1-add-hash32.c \
+ sub-index1.h sub-index1.c \
+ sub42.h sub42.c
+
+libapihashingpythoncustom_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libapihashingpythoncustom_la_SOURCES:%c=)
diff --git a/plugins/apihashing/python/custom/add1505-shl5.c b/plugins/apihashing/python/custom/add1505-shl5.c
new file mode 100644
index 0000000..f70323c
--- /dev/null
+++ b/plugins/apihashing/python/custom/add1505-shl5.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * add1505-shl5.c - équivalent Python du fichier "plugins/apihashing/custom/add1505-shl5.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "add1505-shl5.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../custom/add1505-shl5.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_add1505_shl5_modifier, G_TYPE_SCAN_ADD1505_SHL5_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_add1505_shl5_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_add1505_shl5_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_ADD1505_SHL5_MODIFIER_DOC \
+ "The *Add1505Shl5Modifier* class transforms a byte pattern" \
+ " using a add1505-shl5 hash.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Add1505Shl5Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_add1505_shl5_modifier_type(void)
+{
+ static PyMethodDef py_scan_add1505_shl5_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_add1505_shl5_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_add1505_shl5_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Add1505Shl5Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_ADD1505_SHL5_MODIFIER_DOC,
+
+ .tp_methods = py_scan_add1505_shl5_modifier_methods,
+ .tp_getset = py_scan_add1505_shl5_modifier_getseters,
+
+ .tp_init = py_scan_add1505_shl5_modifier_init,
+ .tp_new = py_scan_add1505_shl5_modifier_new,
+
+ };
+
+ return &py_scan_add1505_shl5_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet '...Add1505Shl5Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_add1505_shl5_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Add1505Shl5Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_add1505_shl5_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en empreinte add1505-shl5. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_add1505_shl5_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_add1505_shl5_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to add1505-shl5 modifier");
+ break;
+
+ case 1:
+ *((GScanAdd1505Shl5Modifier **)dst) = G_SCAN_ADD1505_SHL5_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/add1505-shl5.h b/plugins/apihashing/python/custom/add1505-shl5.h
new file mode 100644
index 0000000..941d6ce
--- /dev/null
+++ b/plugins/apihashing/python/custom/add1505-shl5.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * add1505-shl5.h - équivalent Python du fichier "plugins/apihashing/custom/add1505-shl5.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_ADD1505_SHL5_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_ADD1505_SHL5_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_add1505_shl5_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Add1505Shl5Modifier'. */
+bool ensure_python_scan_add1505_shl5_modifier_is_registered(void);
+
+/* Tente de convertir en empreinte add1505-shl5. */
+int convert_to_scan_add1505_shl5_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_ADD1505_SHL5_H */
diff --git a/plugins/apihashing/python/custom/enigma-murmur.c b/plugins/apihashing/python/custom/enigma-murmur.c
new file mode 100644
index 0000000..f544f1a
--- /dev/null
+++ b/plugins/apihashing/python/custom/enigma-murmur.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enigma-murmur.c - équivalent Python du fichier "plugins/apihashing/custom/enigma-murmur.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "enigma-murmur.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../custom/enigma-murmur.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_enigma_murmur_modifier, G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_enigma_murmur_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_enigma_murmur_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_ENIGMA_MURMUR_MODIFIER_DOC \
+ "The *EnigmaMurmurModifier* class transforms a byte pattern" \
+ " using a enigma-murmur hash.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " EnigmaMurmurModifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_enigma_murmur_modifier_type(void)
+{
+ static PyMethodDef py_scan_enigma_murmur_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_enigma_murmur_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_enigma_murmur_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.EnigmaMurmurModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_ENIGMA_MURMUR_MODIFIER_DOC,
+
+ .tp_methods = py_scan_enigma_murmur_modifier_methods,
+ .tp_getset = py_scan_enigma_murmur_modifier_getseters,
+
+ .tp_init = py_scan_enigma_murmur_modifier_init,
+ .tp_new = py_scan_enigma_murmur_modifier_new,
+
+ };
+
+ return &py_scan_enigma_murmur_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet '...EnigmaMurmurModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_enigma_murmur_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type EnigmaMurmurModifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_enigma_murmur_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en empreinte enigma-murmur. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_enigma_murmur_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_enigma_murmur_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to enigma-murmur modifier");
+ break;
+
+ case 1:
+ *((GScanEnigmaMurmurModifier **)dst) = G_SCAN_ENIGMA_MURMUR_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/enigma-murmur.h b/plugins/apihashing/python/custom/enigma-murmur.h
new file mode 100644
index 0000000..8435dae
--- /dev/null
+++ b/plugins/apihashing/python/custom/enigma-murmur.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enigma-murmur.h - équivalent Python du fichier "plugins/apihashing/custom/enigma-murmur.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_ENIGMA_MURMUR_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_ENIGMA_MURMUR_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_enigma_murmur_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.EnigmaMurmurModifier'. */
+bool ensure_python_scan_enigma_murmur_modifier_is_registered(void);
+
+/* Tente de convertir en empreinte enigma-murmur. */
+int convert_to_scan_enigma_murmur_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_ENIGMA_MURMUR_H */
diff --git a/plugins/apihashing/python/custom/imul21-add.c b/plugins/apihashing/python/custom/imul21-add.c
new file mode 100644
index 0000000..aadc6cc
--- /dev/null
+++ b/plugins/apihashing/python/custom/imul21-add.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul21-add.c - équivalent Python du fichier "plugins/apihashing/custom/imul21-add.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "imul21-add.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../custom/imul21-add.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_imul21_add_modifier, G_TYPE_SCAN_IMUL21_ADD_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_imul21_add_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_imul21_add_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_IMUL21_ADD_MODIFIER_DOC \
+ "The *Sll1AddHash32Modifier* class transforms a byte pattern" \
+ " using a variation of the sll1 algorithm.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Sll1AddHash32Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_imul21_add_modifier_type(void)
+{
+ static PyMethodDef py_scan_imul21_add_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_imul21_add_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_imul21_add_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Imul21AddModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_IMUL21_ADD_MODIFIER_DOC,
+
+ .tp_methods = py_scan_imul21_add_modifier_methods,
+ .tp_getset = py_scan_imul21_add_modifier_getseters,
+
+ .tp_init = py_scan_imul21_add_modifier_init,
+ .tp_new = py_scan_imul21_add_modifier_new,
+
+ };
+
+ return &py_scan_imul21_add_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet '...Imul21AddModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_imul21_add_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Sll1AddHash32Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_imul21_add_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_IMUL21_ADD_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en empreinte imul21-add. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_imul21_add_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_imul21_add_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to imul21-add modifier");
+ break;
+
+ case 1:
+ *((GScanImul21AddModifier **)dst) = G_SCAN_IMUL21_ADD_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/imul21-add.h b/plugins/apihashing/python/custom/imul21-add.h
new file mode 100644
index 0000000..3fcc053
--- /dev/null
+++ b/plugins/apihashing/python/custom/imul21-add.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul21-add.h - équivalent Python du fichier "plugins/apihashing/custom/imul21-add.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL21_ADD_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL21_ADD_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_imul21_add_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Imul21AddModifier'. */
+bool ensure_python_scan_imul21_add_modifier_is_registered(void);
+
+/* Tente de convertir en empreinte imul21-add. */
+int convert_to_scan_imul21_add_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL21_ADD_H */
diff --git a/plugins/apihashing/python/custom/imul83-add.c b/plugins/apihashing/python/custom/imul83-add.c
new file mode 100644
index 0000000..5e2d929
--- /dev/null
+++ b/plugins/apihashing/python/custom/imul83-add.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul83-add.c - équivalent Python du fichier "plugins/apihashing/custom/imul83-add.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "imul83-add.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../custom/imul83-add.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_imul83_add_modifier, G_TYPE_SCAN_IMUL83_ADD_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_imul83_add_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_imul83_add_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_IMUL83_ADD_MODIFIER_DOC \
+ "The *Sll1AddHash32Modifier* class transforms a byte pattern" \
+ " using a variation of the sll1 algorithm.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Sll1AddHash32Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_imul83_add_modifier_type(void)
+{
+ static PyMethodDef py_scan_imul83_add_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_imul83_add_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_imul83_add_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Imul83AddModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_IMUL83_ADD_MODIFIER_DOC,
+
+ .tp_methods = py_scan_imul83_add_modifier_methods,
+ .tp_getset = py_scan_imul83_add_modifier_getseters,
+
+ .tp_init = py_scan_imul83_add_modifier_init,
+ .tp_new = py_scan_imul83_add_modifier_new,
+
+ };
+
+ return &py_scan_imul83_add_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet '...Imul83AddModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_imul83_add_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Sll1AddHash32Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_imul83_add_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_IMUL83_ADD_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en empreinte imul83-add. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_imul83_add_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_imul83_add_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to imul83-add modifier");
+ break;
+
+ case 1:
+ *((GScanImul83AddModifier **)dst) = G_SCAN_IMUL83_ADD_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/imul83-add.h b/plugins/apihashing/python/custom/imul83-add.h
new file mode 100644
index 0000000..fd05136
--- /dev/null
+++ b/plugins/apihashing/python/custom/imul83-add.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imul83-add.h - équivalent Python du fichier "plugins/apihashing/custom/imul83-add.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL83_ADD_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL83_ADD_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_imul83_add_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Imul83AddModifier'. */
+bool ensure_python_scan_imul83_add_modifier_is_registered(void);
+
+/* Tente de convertir en empreinte imul83-add. */
+int convert_to_scan_imul83_add_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL83_ADD_H */
diff --git a/plugins/apihashing/python/custom/module.c b/plugins/apihashing/python/custom/module.c
new file mode 100644
index 0000000..07107dd
--- /dev/null
+++ b/plugins/apihashing/python/custom/module.c
@@ -0,0 +1,76 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire custom en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "add1505-shl5.h"
+#include "enigma-murmur.h"
+#include "imul21-add.h"
+#include "imul83-add.h"
+#include "sll1-add-hash32.h"
+#include "sub-index1.h"
+#include "sub42.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les modificateurs d'empreintes particulières à ROST. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool register_apihashing_custom_modifiers(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_scan_add1505_shl5_modifier_is_registered();
+ if (result) result = ensure_python_scan_enigma_murmur_modifier_is_registered();
+ if (result) result = ensure_python_scan_imul21_add_modifier_is_registered();
+ if (result) result = ensure_python_scan_imul83_add_modifier_is_registered();
+ if (result) result = ensure_python_scan_sll1_add_hash32_modifier_is_registered();
+ if (result) result = ensure_python_scan_sub42_modifier_is_registered();
+ if (result) result = ensure_python_scan_sub_index1_modifier_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/module.h b/plugins/apihashing/python/custom/module.h
new file mode 100644
index 0000000..9073651
--- /dev/null
+++ b/plugins/apihashing/python/custom/module.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire custom en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_MODULE_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Intègre les modificateurs d'empreintes particulières à ROST. */
+bool register_apihashing_custom_modifiers(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_MODULE_H */
diff --git a/plugins/apihashing/python/custom/sll1-add-hash32.c b/plugins/apihashing/python/custom/sll1-add-hash32.c
new file mode 100644
index 0000000..c63fcf3
--- /dev/null
+++ b/plugins/apihashing/python/custom/sll1-add-hash32.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sll1-add-hash32.c - équivalent Python du fichier "plugins/apihashing/custom/sll1-add-hash32.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "sll1-add-hash32.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../custom/sll1-add-hash32.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_sll1_add_hash32_modifier, G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_sll1_add_hash32_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_sll1_add_hash32_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_SLL1_ADD_HASH32_MODIFIER_DOC \
+ "The *Sll1AddHash32Modifier* class transforms a byte pattern" \
+ " using a variation of the sll1 algorithm.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Sll1AddHash32Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_sll1_add_hash32_modifier_type(void)
+{
+ static PyMethodDef py_scan_sll1_add_hash32_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_sll1_add_hash32_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_sll1_add_hash32_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Sll1AddHash32Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_SLL1_ADD_HASH32_MODIFIER_DOC,
+
+ .tp_methods = py_scan_sll1_add_hash32_modifier_methods,
+ .tp_getset = py_scan_sll1_add_hash32_modifier_getseters,
+
+ .tp_init = py_scan_sll1_add_hash32_modifier_init,
+ .tp_new = py_scan_sll1_add_hash32_modifier_new,
+
+ };
+
+ return &py_scan_sll1_add_hash32_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet '...Sll1AddHash32Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_sll1_add_hash32_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Sll1AddHash32Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_sll1_add_hash32_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en empreinte sll1-add-hash32. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_sll1_add_hash32_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_sll1_add_hash32_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to sll1-add-hash32 modifier");
+ break;
+
+ case 1:
+ *((GScanSll1AddHash32Modifier **)dst) = G_SCAN_SLL1_ADD_HASH32_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/sll1-add-hash32.h b/plugins/apihashing/python/custom/sll1-add-hash32.h
new file mode 100644
index 0000000..bf11c34
--- /dev/null
+++ b/plugins/apihashing/python/custom/sll1-add-hash32.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sll1-add-hash32.h - équivalent Python du fichier "plugins/apihashing/custom/sll1-add-hash32.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_SLL1_ADD_HASH32_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_SLL1_ADD_HASH32_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_sll1_add_hash32_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Sll1AddHash32Modifier'. */
+bool ensure_python_scan_sll1_add_hash32_modifier_is_registered(void);
+
+/* Tente de convertir en empreinte sll1-add-hash32. */
+int convert_to_scan_sll1_add_hash32_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_SLL1_ADD_HASH32_H */
diff --git a/plugins/apihashing/python/custom/sub-index1.c b/plugins/apihashing/python/custom/sub-index1.c
new file mode 100644
index 0000000..e5c1487
--- /dev/null
+++ b/plugins/apihashing/python/custom/sub-index1.c
@@ -0,0 +1,213 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub-index1.c - équivalent Python du fichier "plugins/apihashing/custom/sub-index1.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "sub-index1.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../custom/sub-index1.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_sub_index1_modifier, G_TYPE_SCAN_SUB_INDEX1_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_sub_index1_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_sub_index1_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_SUB_INDEX1_MODIFIER_DOC \
+ "The *SubIndex1Modifier* class produces the encrypted version" \
+ " of a byte pattern where the index of a byte is added to its" \
+ " value.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Sub-Index1Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_sub_index1_modifier_type(void)
+{
+ static PyMethodDef py_scan_sub_index1_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_sub_index1_modifier_getseters[] = {
+
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_sub_index1_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.SubIndex1Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_SUB_INDEX1_MODIFIER_DOC,
+
+ .tp_methods = py_scan_sub_index1_modifier_methods,
+ .tp_getset = py_scan_sub_index1_modifier_getseters,
+
+ .tp_init = py_scan_sub_index1_modifier_init,
+ .tp_new = py_scan_sub_index1_modifier_new,
+
+ };
+
+ return &py_scan_sub_index1_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....SubIndex1Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_sub_index1_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python Sub-Index1Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_sub_index1_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_SUB_INDEX1_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation en empreinte sub-index1.*
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_sub_index1_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_sub_index1_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to sub-index1 modifier");
+ break;
+
+ case 1:
+ *((GScanSubIndex1Modifier **)dst) = G_SCAN_SUB_INDEX1_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/sub-index1.h b/plugins/apihashing/python/custom/sub-index1.h
new file mode 100644
index 0000000..65186f3
--- /dev/null
+++ b/plugins/apihashing/python/custom/sub-index1.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub-index1.h - équivalent Python du fichier "plugins/apihashing/custom/sub-index1.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB_INDEX1_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB_INDEX1_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_sub_index1_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.SubIndex1Modifier'. */
+bool ensure_python_scan_sub_index1_modifier_is_registered(void);
+
+/* Tente de convertir en transformation en empreinte sub-index1. */
+int convert_to_scan_sub_index1_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB_INDEX1_H */
diff --git a/plugins/apihashing/python/custom/sub42.c b/plugins/apihashing/python/custom/sub42.c
new file mode 100644
index 0000000..238496d
--- /dev/null
+++ b/plugins/apihashing/python/custom/sub42.c
@@ -0,0 +1,212 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub42.c - équivalent Python du fichier "plugins/apihashing/custom/sub42.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "sub42.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../apihash.h"
+#include "../../custom/sub42.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_sub42_modifier, G_TYPE_SCAN_SUB42_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_sub42_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_sub42_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_SUB42_MODIFIER_DOC \
+ "The *Sub42Modifier* class produces the encrypted version of a" \
+ " byte pattern where 0x42 is added to each byte.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Sub42Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_sub42_modifier_type(void)
+{
+ static PyMethodDef py_scan_sub42_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_sub42_modifier_getseters[] = {
+
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_sub42_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Sub42Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_SUB42_MODIFIER_DOC,
+
+ .tp_methods = py_scan_sub42_modifier_methods,
+ .tp_getset = py_scan_sub42_modifier_getseters,
+
+ .tp_init = py_scan_sub42_modifier_init,
+ .tp_new = py_scan_sub42_modifier_new,
+
+ };
+
+ return &py_scan_sub42_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....Sub42Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_sub42_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python Sub42Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_sub42_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_api_hash_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_SUB42_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation en empreinte sub42. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_sub42_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_sub42_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to sub42 modifier");
+ break;
+
+ case 1:
+ *((GScanSub42Modifier **)dst) = G_SCAN_SUB42_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/custom/sub42.h b/plugins/apihashing/python/custom/sub42.h
new file mode 100644
index 0000000..ce3660a
--- /dev/null
+++ b/plugins/apihashing/python/custom/sub42.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sub42.h - équivalent Python du fichier "plugins/apihashing/custom/sub42.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB42_H
+#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB42_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_sub42_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Sub42Modifier'. */
+bool ensure_python_scan_sub42_modifier_is_registered(void);
+
+/* Tente de convertir en transformation en empreinte sub42. */
+int convert_to_scan_sub42_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB42_H */
diff --git a/plugins/apihashing/python/module.c b/plugins/apihashing/python/module.c
new file mode 100644
index 0000000..588a0d8
--- /dev/null
+++ b/plugins/apihashing/python/module.c
@@ -0,0 +1,87 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire apihashing en tant que module
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "apihash.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Ajoute le module 'plugins.apihashing' au module Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_apihashing_module_to_python_module(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *super; /* Module à compléter */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_PLUGINS_APIHASHING_DOC \
+ "apihashing is a module providing a few implementations" \
+ " of algorithms used to resolve API functions by hash."
+
+ static PyModuleDef py_chrysalide_apihashing_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.plugins.apihashing",
+ .m_doc = PYCHRYSALIDE_PLUGINS_APIHASHING_DOC,
+
+ .m_size = -1,
+
+ };
+
+ result = false;
+
+ super = get_access_to_python_module("pychrysalide.plugins");
+
+ module = build_python_module(super, &py_chrysalide_apihashing_module);
+
+ result = (module != NULL);
+
+ if (result) result = ensure_python_api_hash_modifier_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/apihashing/python/module.h b/plugins/apihashing/python/module.h
new file mode 100644
index 0000000..fe628b9
--- /dev/null
+++ b/plugins/apihashing/python/module.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire apihashing en tant que module
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_APIHASHING_PYTHON_MODULE_H
+#define _PLUGINS_APIHASHING_PYTHON_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins.apihashing' au module Python. */
+bool add_apihashing_module_to_python_module(void);
+
+
+
+#endif /* _PLUGINS_APIHASHING_PYTHON_MODULE_H */
diff --git a/plugins/arm/Makefile.am b/plugins/arm/Makefile.am
index a37cbbd..3470256 100644
--- a/plugins/arm/Makefile.am
+++ b/plugins/arm/Makefile.am
@@ -35,23 +35,25 @@ PYTHON3_SUBDIRS = python
endif
-libarm_la_SOURCES = \
- cond.h \
- context-int.h \
- context.h context.c \
- core.h core.c \
- instruction-int.h \
- instruction.h instruction.c \
- link.h link.c \
- processor-int.h \
- processor.h processor.c \
- register-int.h \
+libarm_la_SOURCES = \
+ cond.h \
+ context-int.h \
+ context.h context.c \
+ core.h core.c \
+ instruction-int.h \
+ instruction.h instruction.c \
+ link.h link.c \
+ processor-int.h \
+ processor.h processor.c \
+ register-int.h \
register.h register.c
-libarm_la_LIBADD = \
- $(PYTHON3_LIBADD) \
+libarm_la_LIBADD = \
+ $(PYTHON3_LIBADD) \
v7/libarmv7.la
+libarm_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libarm_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -63,9 +65,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libarm_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
SUBDIRS = v7 $(PYTHON3_SUBDIRS)
diff --git a/plugins/arm/core.c b/plugins/arm/core.c
index c270c85..1c1c6bc 100644
--- a/plugins/arm/core.c
+++ b/plugins/arm/core.c
@@ -24,17 +24,16 @@
#include "core.h"
-#include <config.h>
#include <plugins/self.h>
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
#include "v7/core.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -66,7 +65,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
result = init_armv7_core();
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
if (result)
result = add_arch_arm_module_to_python_module();
#endif
diff --git a/plugins/arm/python/Makefile.am b/plugins/arm/python/Makefile.am
index f09baee..931b2b9 100644
--- a/plugins/arm/python/Makefile.am
+++ b/plugins/arm/python/Makefile.am
@@ -1,15 +1,16 @@
noinst_LTLIBRARIES = libarmpython.la
-libarmpython_la_SOURCES = \
- instruction.h instruction.c \
- module.h module.c \
+libarmpython_la_SOURCES = \
+ instruction.h instruction.c \
+ module.h module.c \
processor.h processor.c
-libarmpython_la_LIBADD = \
+libarmpython_la_LIBADD = \
v7/libarmpythonv7.la
-libarmpython_la_LDFLAGS =
+libarmpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
@@ -17,9 +18,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libarmpython_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = v7
diff --git a/plugins/arm/python/instruction.c b/plugins/arm/python/instruction.c
index 81fd132..8a37d92 100644
--- a/plugins/arm/python/instruction.c
+++ b/plugins/arm/python/instruction.c
@@ -93,17 +93,19 @@ PyTypeObject *get_python_arm_instruction_type(void)
bool register_python_arm_instruction(PyObject *module)
{
- PyTypeObject *py_arm_instruction_type; /* Type Python 'BinContent' */
+ PyTypeObject *type; /* Type Python 'ArmInstruction'*/
PyObject *dict; /* Dictionnaire du module */
- py_arm_instruction_type = get_python_arm_instruction_type();
+ type = get_python_arm_instruction_type();
- APPLY_ABSTRACT_FLAG(py_arm_instruction_type);
+ APPLY_ABSTRACT_FLAG(type);
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ARM_INSTRUCTION,
- py_arm_instruction_type, get_python_arch_instruction_type()))
+ if (!ensure_python_arch_instruction_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ARM_INSTRUCTION, type))
return false;
return true;
diff --git a/plugins/arm/python/processor.c b/plugins/arm/python/processor.c
index 1681f52..6a31611 100644
--- a/plugins/arm/python/processor.c
+++ b/plugins/arm/python/processor.c
@@ -93,14 +93,17 @@ PyTypeObject *get_python_arm_processor_type(void)
bool register_python_arm_processor(PyObject *module)
{
- PyTypeObject *py_arm_processor_type; /* Type Python 'BinContent' */
+ PyTypeObject *type; /* Type Python 'ArmProcessor' */
PyObject *dict; /* Dictionnaire du module */
- py_arm_processor_type = get_python_arm_processor_type();
+ type = get_python_arm_processor_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ARM_PROCESSOR, py_arm_processor_type, get_python_arch_processor_type()))
+ if (!ensure_python_arch_processor_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ARM_PROCESSOR, type))
return false;
return true;
diff --git a/plugins/arm/python/v7/Makefile.am b/plugins/arm/python/v7/Makefile.am
index 06dc4af..a350d90 100644
--- a/plugins/arm/python/v7/Makefile.am
+++ b/plugins/arm/python/v7/Makefile.am
@@ -1,20 +1,15 @@
noinst_LTLIBRARIES = libarmpythonv7.la
-libarmpythonv7_la_SOURCES = \
- instruction.h instruction.c \
- module.h module.c \
+libarmpythonv7_la_SOURCES = \
+ instruction.h instruction.c \
+ module.h module.c \
processor.h processor.c
-libarmpythonv7_la_LDFLAGS =
+libarmpythonv7_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libarmpythonv7_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/arm/python/v7/instruction.c b/plugins/arm/python/v7/instruction.c
index 81b34c3..27171ac 100644
--- a/plugins/arm/python/v7/instruction.c
+++ b/plugins/arm/python/v7/instruction.c
@@ -83,7 +83,7 @@ PyTypeObject *get_python_armv7_instruction_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide....arm.ArmInstruction'.*
+* Description : Prend en charge l'objet 'pychrysalide.....ArmV7Instruction'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -93,15 +93,16 @@ PyTypeObject *get_python_armv7_instruction_type(void)
bool register_python_armv7_instruction(PyObject *module)
{
- PyTypeObject *py_armv7_instruction_type;/* Type Python 'BinContent' */
+ PyTypeObject *type; /* Type 'ArmV7Instruction' */
PyObject *dict; /* Dictionnaire du module */
- py_armv7_instruction_type = get_python_armv7_instruction_type();
+ type = get_python_armv7_instruction_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_INSTRUCTION,
- py_armv7_instruction_type, get_python_arm_instruction_type()))
+ /* TODO : ensure get_python_arm_instruction_type() */
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_INSTRUCTION, type))
return false;
return true;
diff --git a/plugins/arm/python/v7/processor.c b/plugins/arm/python/v7/processor.c
index 6a1e3f0..5d5ea5c 100644
--- a/plugins/arm/python/v7/processor.c
+++ b/plugins/arm/python/v7/processor.c
@@ -83,7 +83,7 @@ PyTypeObject *get_python_armv7_processor_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide.arch.arm.ArmProcessor'.*
+* Description : Prend en charge l'objet 'pychrysalide.....ArmV7Processor'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -93,14 +93,16 @@ PyTypeObject *get_python_armv7_processor_type(void)
bool register_python_armv7_processor(PyObject *module)
{
- PyTypeObject *py_armv7_processor_type; /* Type Python 'BinContent' */
+ PyTypeObject *type; /* Type Python 'ArmV7Processor'*/
PyObject *dict; /* Dictionnaire du module */
- py_armv7_processor_type = get_python_armv7_processor_type();
+ type = get_python_armv7_processor_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_PROCESSOR, py_armv7_processor_type, get_python_arm_processor_type()))
+ /* TODO : ensure get_python_arm_processor_type() */
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_PROCESSOR, type))
return false;
return true;
diff --git a/plugins/arm/v7/Makefile.am b/plugins/arm/v7/Makefile.am
index f75e9b3..d87373a 100644
--- a/plugins/arm/v7/Makefile.am
+++ b/plugins/arm/v7/Makefile.am
@@ -1,38 +1,35 @@
noinst_LTLIBRARIES = libarmv7.la
-libarmv7_la_SOURCES = \
- arm.h arm.c \
- context.h context.c \
- core.h core.c \
- fetch.h fetch.c \
- helpers.h \
- instruction.h instruction.c \
- link.h link.c \
- operand-int.h \
- operand.h operand.c \
- post.h post.c \
- processor.h processor.c \
- pseudo.h pseudo.c \
- register-int.h \
- register.h register.c \
- thumb_16.h thumb_16.c \
+libarmv7_la_SOURCES = \
+ arm.h arm.c \
+ context.h context.c \
+ core.h core.c \
+ fetch.h fetch.c \
+ helpers.h \
+ instruction.h instruction.c \
+ link.h link.c \
+ operand-int.h \
+ operand.h operand.c \
+ post.h post.c \
+ processor.h processor.c \
+ pseudo.h pseudo.c \
+ register-int.h \
+ register.h register.c \
+ thumb_16.h thumb_16.c \
thumb_32.h thumb_32.c
-libarmv7_la_LIBADD = \
- opcodes/libarmv7opcodes.la \
- operands/libarmv7operands.la \
+libarmv7_la_LIBADD = \
+ opcodes/libarmv7opcodes.la \
+ operands/libarmv7operands.la \
registers/libarmv7registers.la
+libarmv7_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libarmv7_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
SUBDIRS = opdefs opcodes operands registers
diff --git a/plugins/arm/v7/opcodes/Makefile.am b/plugins/arm/v7/opcodes/Makefile.am
index 7a35ff9..c7fa4cc 100644
--- a/plugins/arm/v7/opcodes/Makefile.am
+++ b/plugins/arm/v7/opcodes/Makefile.am
@@ -13,7 +13,7 @@ noinst_LTLIBRARIES = libarmv7opcodes.la
libarmv7opcodes_la_SOURCES = $(GENERATED_FILES)
-libarmv7opcodes_la_LIBADD =
+libarmv7opcodes_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
@@ -21,11 +21,6 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libarmv7opcodes_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) -I$(top_srcdir)/src
-
-
CLEANFILES = $(GENERATED_FILES)
dist-hook:
diff --git a/plugins/arm/v7/operands/Makefile.am b/plugins/arm/v7/operands/Makefile.am
index 31f6a8a..fa7ab8b 100644
--- a/plugins/arm/v7/operands/Makefile.am
+++ b/plugins/arm/v7/operands/Makefile.am
@@ -1,26 +1,21 @@
noinst_LTLIBRARIES = libarmv7operands.la
-libarmv7operands_la_SOURCES = \
- estate.h estate.c \
- iflags.h iflags.c \
- it.h it.c \
- limitation.h limitation.c \
- maccess.h maccess.c \
- offset.h offset.c \
- register.h register.c \
- reglist.h reglist.c \
- rotation.h rotation.c \
+libarmv7operands_la_SOURCES = \
+ estate.h estate.c \
+ iflags.h iflags.c \
+ it.h it.c \
+ limitation.h limitation.c \
+ maccess.h maccess.c \
+ offset.h offset.c \
+ register.h register.c \
+ reglist.h reglist.c \
+ rotation.h rotation.c \
shift.h shift.c
-libarmv7operands_la_LIBADD =
+libarmv7operands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libarmv7operands_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/arm/v7/operands/estate.c b/plugins/arm/v7/operands/estate.c
index d82ffa1..accde6d 100644
--- a/plugins/arm/v7/operands/estate.c
+++ b/plugins/arm/v7/operands/estate.c
@@ -24,7 +24,7 @@
#include "estate.h"
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/iflags.c b/plugins/arm/v7/operands/iflags.c
index 2e26810..f0a5e07 100644
--- a/plugins/arm/v7/operands/iflags.c
+++ b/plugins/arm/v7/operands/iflags.c
@@ -24,7 +24,7 @@
#include "iflags.h"
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/it.c b/plugins/arm/v7/operands/it.c
index 0286e06..46e1b4c 100644
--- a/plugins/arm/v7/operands/it.c
+++ b/plugins/arm/v7/operands/it.c
@@ -28,7 +28,7 @@
#include <common/sort.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/limitation.c b/plugins/arm/v7/operands/limitation.c
index fe8d9fb..d9e11cf 100644
--- a/plugins/arm/v7/operands/limitation.c
+++ b/plugins/arm/v7/operands/limitation.c
@@ -26,7 +26,7 @@
#include <arch/operand-int.h>
#include <common/sort.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/maccess.c b/plugins/arm/v7/operands/maccess.c
index b67b65a..77d031f 100644
--- a/plugins/arm/v7/operands/maccess.c
+++ b/plugins/arm/v7/operands/maccess.c
@@ -30,8 +30,8 @@
#include <common/cpp.h>
+#include <core/columns.h>
#include <core/logs.h>
-#include <gtkext/gtkblockdisplay.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/offset.c b/plugins/arm/v7/operands/offset.c
index 79c5cf9..724523d 100644
--- a/plugins/arm/v7/operands/offset.c
+++ b/plugins/arm/v7/operands/offset.c
@@ -29,7 +29,7 @@
#include <string.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/register.c b/plugins/arm/v7/operands/register.c
index 21dc129..fa5b887 100644
--- a/plugins/arm/v7/operands/register.c
+++ b/plugins/arm/v7/operands/register.c
@@ -26,7 +26,7 @@
#include <arch/operands/register-int.h>
#include <common/sort.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
diff --git a/plugins/arm/v7/operands/reglist.c b/plugins/arm/v7/operands/reglist.c
index df93f77..b525f28 100644
--- a/plugins/arm/v7/operands/reglist.c
+++ b/plugins/arm/v7/operands/reglist.c
@@ -31,7 +31,7 @@
#include <arch/register.h>
#include <arch/storage.h>
#include <common/sort.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/rotation.c b/plugins/arm/v7/operands/rotation.c
index 8136401..418e5a4 100644
--- a/plugins/arm/v7/operands/rotation.c
+++ b/plugins/arm/v7/operands/rotation.c
@@ -29,8 +29,8 @@
#include <string.h>
+#include <core/columns.h>
#include <core/logs.h>
-#include <gtkext/gtkblockdisplay.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/operands/shift.c b/plugins/arm/v7/operands/shift.c
index 1e1a8ab..ee18cf0 100644
--- a/plugins/arm/v7/operands/shift.c
+++ b/plugins/arm/v7/operands/shift.c
@@ -30,7 +30,7 @@
#include <common/sort.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../operand-int.h"
diff --git a/plugins/arm/v7/registers/Makefile.am b/plugins/arm/v7/registers/Makefile.am
index 94edf09..5f731f9 100644
--- a/plugins/arm/v7/registers/Makefile.am
+++ b/plugins/arm/v7/registers/Makefile.am
@@ -1,21 +1,16 @@
noinst_LTLIBRARIES = libarmv7registers.la
-libarmv7registers_la_SOURCES = \
- banked.h banked.c \
- basic.h basic.c \
- coproc.h coproc.c \
- simd.h simd.c \
+libarmv7registers_la_SOURCES = \
+ banked.h banked.c \
+ basic.h basic.c \
+ coproc.h coproc.c \
+ simd.h simd.c \
special.h special.c
-libarmv7registers_la_LIBADD =
+libarmv7registers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libarmv7registers_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/arm/v7/registers/banked.c b/plugins/arm/v7/registers/banked.c
index d565f95..6e9fbf3 100644
--- a/plugins/arm/v7/registers/banked.c
+++ b/plugins/arm/v7/registers/banked.c
@@ -27,7 +27,7 @@
#include <stdio.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../register-int.h"
diff --git a/plugins/arm/v7/registers/basic.c b/plugins/arm/v7/registers/basic.c
index 60ef821..358135b 100644
--- a/plugins/arm/v7/registers/basic.c
+++ b/plugins/arm/v7/registers/basic.c
@@ -27,7 +27,7 @@
#include <stdio.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../register-int.h"
diff --git a/plugins/arm/v7/registers/coproc.c b/plugins/arm/v7/registers/coproc.c
index 3d4ee8e..5c256a7 100644
--- a/plugins/arm/v7/registers/coproc.c
+++ b/plugins/arm/v7/registers/coproc.c
@@ -27,7 +27,7 @@
#include <stdio.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../register-int.h"
diff --git a/plugins/arm/v7/registers/simd.c b/plugins/arm/v7/registers/simd.c
index e38de0c..8c8c653 100644
--- a/plugins/arm/v7/registers/simd.c
+++ b/plugins/arm/v7/registers/simd.c
@@ -28,7 +28,7 @@
#include <stdio.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../register-int.h"
diff --git a/plugins/arm/v7/registers/special.c b/plugins/arm/v7/registers/special.c
index d0bfb67..1fc9eb5 100644
--- a/plugins/arm/v7/registers/special.c
+++ b/plugins/arm/v7/registers/special.c
@@ -27,7 +27,7 @@
#include <stdio.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include "../register-int.h"
diff --git a/plugins/bhash/Makefile.am b/plugins/bhash/Makefile.am
index 45c5ee0..31daeb1 100644
--- a/plugins/bhash/Makefile.am
+++ b/plugins/bhash/Makefile.am
@@ -45,9 +45,11 @@ libbhash_la_SOURCES = \
tlsh.h tlsh.c \
rich.h rich.c
-libbhash_la_LIBADD = \
+libbhash_la_LIBADD = \
$(PYTHON3_LIBADD)
+libbhash_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libbhash_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -60,8 +62,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libbhash_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/bhash/core.c b/plugins/bhash/core.c
index 91a0bf2..eb05893 100644
--- a/plugins/bhash/core.c
+++ b/plugins/bhash/core.c
@@ -24,16 +24,15 @@
#include "core.h"
-#include <config.h>
#include <plugins/self.h>
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS_
+#ifdef INCLUDE_PYTHON3_BINDINGS_
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -63,7 +62,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
{
bool result; /* Bilan à retourner */
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
result = add_bhash_module_to_python_module();
#else
result = true;
diff --git a/plugins/bhash/python/Makefile.am b/plugins/bhash/python/Makefile.am
index 822a716..6dd127c 100644
--- a/plugins/bhash/python/Makefile.am
+++ b/plugins/bhash/python/Makefile.am
@@ -1,21 +1,16 @@
noinst_LTLIBRARIES = libbhashpython.la
-libbhashpython_la_SOURCES = \
- imphash.h imphash.c \
- module.h module.c \
- tlsh.h tlsh.c \
+libbhashpython_la_SOURCES = \
+ imphash.h imphash.c \
+ module.h module.c \
+ tlsh.h tlsh.c \
rich.h rich.c
-libbhashpython_la_LDFLAGS =
+libbhashpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libbhashpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/bootimg/Makefile.am b/plugins/bootimg/Makefile.am
index ada1e4e..623c555 100644
--- a/plugins/bootimg/Makefile.am
+++ b/plugins/bootimg/Makefile.am
@@ -35,15 +35,17 @@ PYTHON3_SUBDIRS = python
endif
-libbootimg_la_SOURCES = \
- core.h core.c \
- bootimg-def.h \
- format-int.h format-int.c \
+libbootimg_la_SOURCES = \
+ core.h core.c \
+ bootimg-def.h \
+ format-int.h format-int.c \
format.h format.c
-libbootimg_la_LIBADD = \
+libbootimg_la_LIBADD = \
$(PYTHON3_LIBADD)
+libbootimg_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libbootimg_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -55,8 +57,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libbootimg_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/bootimg/core.c b/plugins/bootimg/core.c
index 9c4bc45..25b21db 100644
--- a/plugins/bootimg/core.c
+++ b/plugins/bootimg/core.c
@@ -24,18 +24,17 @@
#include "core.h"
-#include <config.h>
#include <core/global.h>
#include <plugins/self.h>
#include "format.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
{
bool result; /* Bilan à retourner */
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
result = add_format_bootimg_module_to_python_module();
#else
result = true;
diff --git a/plugins/bootimg/python/Makefile.am b/plugins/bootimg/python/Makefile.am
index 1f11581..d39a521 100644
--- a/plugins/bootimg/python/Makefile.am
+++ b/plugins/bootimg/python/Makefile.am
@@ -1,20 +1,15 @@
noinst_LTLIBRARIES = libbootimgpython.la
-libbootimgpython_la_SOURCES = \
- format.h format.c \
- module.h module.c \
+libbootimgpython_la_SOURCES = \
+ format.h format.c \
+ module.h module.c \
translate.h translate.c
-libbootimgpython_la_LDFLAGS =
+libbootimgpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libbootimgpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/bootimg/python/format.c b/plugins/bootimg/python/format.c
index d5e32d3..273daee 100644
--- a/plugins/bootimg/python/format.c
+++ b/plugins/bootimg/python/format.c
@@ -95,7 +95,7 @@ static PyObject *py_bootimg_format_new(PyTypeObject *type, PyObject *args, PyObj
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -395,7 +395,10 @@ bool register_python_bootimg_format(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BOOTIMG_FORMAT, type, get_python_known_format_type()))
+ if (!ensure_python_known_format_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_BOOTIMG_FORMAT, type))
return false;
return true;
diff --git a/plugins/dalvik/Makefile.am b/plugins/dalvik/Makefile.am
index 644c38a..62ee8a6 100644
--- a/plugins/dalvik/Makefile.am
+++ b/plugins/dalvik/Makefile.am
@@ -39,26 +39,28 @@ PYTHON3_SUBDIRS = python
endif
-libdalvik_la_SOURCES = \
- context.h context.c \
- core.h core.c \
- fetch.h fetch.c \
- helpers.h \
- instruction-int.h \
- instruction.h instruction.c \
- link.h link.c \
- operand.h operand.c \
- post.h post.c \
- processor-int.h \
- processor.h processor.c \
+libdalvik_la_SOURCES = \
+ context.h context.c \
+ core.h core.c \
+ fetch.h fetch.c \
+ helpers.h \
+ instruction-int.h \
+ instruction.h instruction.c \
+ link.h link.c \
+ operand.h operand.c \
+ post.h post.c \
+ processor-int.h \
+ processor.h processor.c \
register.h register.c
-libdalvik_la_LIBADD = \
- operands/libdalvikoperands.la \
- pseudo/libdalvikpseudo.la \
- $(PYTHON3_LIBADD) \
+libdalvik_la_LIBADD = \
+ operands/libdalvikoperands.la \
+ pseudo/libdalvikpseudo.la \
+ $(PYTHON3_LIBADD) \
v35/libdalvik35.la
+libdalvik_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libdalvik_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -71,9 +73,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdalvik_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
SUBDIRS = operands pseudo $(PYTHON3_SUBDIRS) v35
diff --git a/plugins/dalvik/context.c b/plugins/dalvik/context.c
index b08678c..9cf878b 100644
--- a/plugins/dalvik/context.c
+++ b/plugins/dalvik/context.c
@@ -373,7 +373,7 @@ bool g_dalvik_context_register_array_data_padding(GDalvikContext *ctx, const vmp
* *
******************************************************************************/
-GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *ctx, const GBinContent *content, vmpa2t *pos)
+GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *ctx, GBinContent *content, vmpa2t *pos)
{
GArchInstruction *result; /* Instruction à retourner */
raw_data_area *found; /* Zone de couverture trouvée */
@@ -390,7 +390,7 @@ GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *ctx, const GBinC
if (found)
{
- restricted = g_restricted_content_new_ro(content, &found->range);
+ restricted = g_restricted_content_new(content, &found->range);
length = get_mrange_length(&found->range);
count = length / found->item_len;
diff --git a/plugins/dalvik/context.h b/plugins/dalvik/context.h
index bfa2757..f09cfa6 100644
--- a/plugins/dalvik/context.h
+++ b/plugins/dalvik/context.h
@@ -67,7 +67,7 @@ bool g_dalvik_context_register_array_data(GDalvikContext *, const vmpa2t *, uint
bool g_dalvik_context_register_array_data_padding(GDalvikContext *, const vmpa2t *);
/* Place une donnée en tant qu'instruction si besoin est. */
-GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *, const GBinContent *, vmpa2t *);
+GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *, GBinContent *, vmpa2t *);
diff --git a/plugins/dalvik/core.c b/plugins/dalvik/core.c
index 2294ed4..8344825 100644
--- a/plugins/dalvik/core.c
+++ b/plugins/dalvik/core.c
@@ -24,7 +24,6 @@
#include "core.h"
-#include <config.h>
#include <plugins/self.h>
@@ -32,13 +31,13 @@
#include "operands/args.h"
#include "operands/pool.h"
#include "operands/register.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
#include "v35/core.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -100,7 +99,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
result = init_dalvik35_core();
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
if (result)
result = add_arch_dalvik_module_to_python_module();
#endif
diff --git a/plugins/dalvik/operands/Makefile.am b/plugins/dalvik/operands/Makefile.am
index 4ce597a..3a4ddc1 100644
--- a/plugins/dalvik/operands/Makefile.am
+++ b/plugins/dalvik/operands/Makefile.am
@@ -1,20 +1,14 @@
noinst_LTLIBRARIES = libdalvikoperands.la
-libdalvikoperands_la_SOURCES = \
- args.h args.c \
- pool.h pool.c \
+libdalvikoperands_la_SOURCES = \
+ args.h args.c \
+ pool.h pool.c \
register.h register.c
+libdalvikoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdalvikoperands_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
-SUBDIRS =
diff --git a/plugins/dalvik/operands/args.c b/plugins/dalvik/operands/args.c
index 01ed122..64f8eea 100644
--- a/plugins/dalvik/operands/args.c
+++ b/plugins/dalvik/operands/args.c
@@ -32,8 +32,8 @@
#include <arch/operand-int.h>
#include <common/sort.h>
+#include <core/columns.h>
#include <core/logs.h>
-#include <gtkext/gtkblockdisplay.h>
diff --git a/plugins/dalvik/operands/pool.c b/plugins/dalvik/operands/pool.c
index a07b3e0..5b99b45 100644
--- a/plugins/dalvik/operands/pool.c
+++ b/plugins/dalvik/operands/pool.c
@@ -34,7 +34,7 @@
#include <arch/operand-int.h>
#include <arch/operands/targetable-int.h>
#include <common/sort.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
#include <plugins/dex/pool.h>
diff --git a/plugins/dalvik/pseudo/Makefile.am b/plugins/dalvik/pseudo/Makefile.am
index 687aa72..74cc574 100644
--- a/plugins/dalvik/pseudo/Makefile.am
+++ b/plugins/dalvik/pseudo/Makefile.am
@@ -1,19 +1,14 @@
noinst_LTLIBRARIES = libdalvikpseudo.la
-libdalvikpseudo_la_SOURCES = \
- fill.h fill.c \
- identifiers.h \
+libdalvikpseudo_la_SOURCES = \
+ fill.h fill.c \
+ identifiers.h \
switch.h switch.c
-libdalvikpseudo_la_LIBADD =
+libdalvikpseudo_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdalvikpseudo_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/dalvik/python/Makefile.am b/plugins/dalvik/python/Makefile.am
index 90c8924..74fe00d 100644
--- a/plugins/dalvik/python/Makefile.am
+++ b/plugins/dalvik/python/Makefile.am
@@ -1,15 +1,16 @@
noinst_LTLIBRARIES = libdalvikpython.la
-libdalvikpython_la_SOURCES = \
- instruction.h instruction.c \
- module.h module.c \
+libdalvikpython_la_SOURCES = \
+ instruction.h instruction.c \
+ module.h module.c \
processor.h processor.c
-libdalvikpython_la_LIBADD = \
+libdalvikpython_la_LIBADD = \
v35/libdalvikpythonv35.la
-libdalvikpython_la_LDFLAGS =
+libdalvikpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
@@ -17,9 +18,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdalvikpython_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = v35
diff --git a/plugins/dalvik/python/instruction.c b/plugins/dalvik/python/instruction.c
index c9d039f..a6d4ad4 100644
--- a/plugins/dalvik/python/instruction.c
+++ b/plugins/dalvik/python/instruction.c
@@ -102,7 +102,10 @@ bool register_python_dalvik_instruction(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_INSTRUCTION, type, get_python_arch_instruction_type()))
+ if (!ensure_python_arch_instruction_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_INSTRUCTION, type))
return false;
return true;
diff --git a/plugins/dalvik/python/processor.c b/plugins/dalvik/python/processor.c
index 26fd8b7..9885a04 100644
--- a/plugins/dalvik/python/processor.c
+++ b/plugins/dalvik/python/processor.c
@@ -100,7 +100,10 @@ bool register_python_dalvik_processor(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_PROCESSOR, type, get_python_arch_processor_type()))
+ if (!ensure_python_arch_processor_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_PROCESSOR, type))
return false;
return true;
diff --git a/plugins/dalvik/python/v35/Makefile.am b/plugins/dalvik/python/v35/Makefile.am
index 3dda5c1..4464dcc 100644
--- a/plugins/dalvik/python/v35/Makefile.am
+++ b/plugins/dalvik/python/v35/Makefile.am
@@ -1,20 +1,15 @@
noinst_LTLIBRARIES = libdalvikpythonv35.la
-libdalvikpythonv35_la_SOURCES = \
- instruction.h instruction.c \
- module.h module.c \
+libdalvikpythonv35_la_SOURCES = \
+ instruction.h instruction.c \
+ module.h module.c \
processor.h processor.c
-libdalvikpythonv35_la_LDFLAGS =
+libdalvikpythonv35_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdalvikpythonv35_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/dalvik/python/v35/instruction.c b/plugins/dalvik/python/v35/instruction.c
index f5ccc2c..7373e77 100644
--- a/plugins/dalvik/python/v35/instruction.c
+++ b/plugins/dalvik/python/v35/instruction.c
@@ -100,8 +100,9 @@ bool register_python_dalvik35_instruction(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_INSTRUCTION,
- type, get_python_dalvik_instruction_type()))
+ /* TODO : ensure get_python_dalvik_instruction_type() */
+
+ if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_INSTRUCTION, type))
return false;
return true;
diff --git a/plugins/dalvik/python/v35/processor.c b/plugins/dalvik/python/v35/processor.c
index fea342b..8df8249 100644
--- a/plugins/dalvik/python/v35/processor.c
+++ b/plugins/dalvik/python/v35/processor.c
@@ -100,8 +100,9 @@ bool register_python_dalvik35_processor(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_PROCESSOR,
- type, get_python_dalvik_processor_type()))
+ /* TODO : ensure get_python_dalvik_processor_type() */
+
+ if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_PROCESSOR, type))
return false;
return true;
diff --git a/plugins/dalvik/register.c b/plugins/dalvik/register.c
index b350b04..8413108 100644
--- a/plugins/dalvik/register.c
+++ b/plugins/dalvik/register.c
@@ -30,7 +30,7 @@
#include <arch/register-int.h>
#include <common/sort.h>
-#include <gtkext/gtkblockdisplay.h>
+#include <core/columns.h>
diff --git a/plugins/dalvik/v35/Makefile.am b/plugins/dalvik/v35/Makefile.am
index 8a7be09..73e09a0 100644
--- a/plugins/dalvik/v35/Makefile.am
+++ b/plugins/dalvik/v35/Makefile.am
@@ -1,13 +1,15 @@
noinst_LTLIBRARIES = libdalvik35.la
-libdalvik35_la_SOURCES = \
- core.h core.c \
- instruction.h instruction.c \
- operand.h \
+libdalvik35_la_SOURCES = \
+ core.h core.c \
+ instruction.h instruction.c \
+ operand.h \
processor.h processor.c
-libdalvik35_la_LIBADD = \
+libdalvik35_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+libdalvik35_la_LIBADD = \
opcodes/libdalvik35opcodes.la
@@ -16,9 +18,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdalvik35_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
SUBDIRS = opdefs opcodes
diff --git a/plugins/dalvik/v35/opcodes/Makefile.am b/plugins/dalvik/v35/opcodes/Makefile.am
index fd26224..8a766f9 100644
--- a/plugins/dalvik/v35/opcodes/Makefile.am
+++ b/plugins/dalvik/v35/opcodes/Makefile.am
@@ -13,7 +13,7 @@ noinst_LTLIBRARIES = libdalvik35opcodes.la
libdalvik35opcodes_la_SOURCES = $(GENERATED_FILES)
-libdalvik35opcodes_la_LIBADD =
+libdalvik35opcodes_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
@@ -21,11 +21,6 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdalvik35opcodes_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
CLEANFILES = $(GENERATED_FILES)
dist-hook:
diff --git a/plugins/devdbg/Makefile.am b/plugins/devdbg/Makefile.am
index a92744d..0bf81c6 100644
--- a/plugins/devdbg/Makefile.am
+++ b/plugins/devdbg/Makefile.am
@@ -11,9 +11,11 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs'
endif
-libspeed_la_SOURCES = \
+libspeed_la_SOURCES = \
speed.h speed.c
+libspeed_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libspeed_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -23,8 +25,3 @@ libspeed_la_LDFLAGS = \
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libspeed_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/dex/Makefile.am b/plugins/dex/Makefile.am
index 8eb7bde..a587fe2 100644
--- a/plugins/dex/Makefile.am
+++ b/plugins/dex/Makefile.am
@@ -35,21 +35,23 @@ PYTHON3_SUBDIRS = python
endif
-libdex_la_SOURCES = \
- core.h core.c \
- class.h class.c \
- dex-int.h dex-int.c \
- dex_def.h \
- field.h field.c \
- format.h format.c \
- loading.h loading.c \
- method.h method.c \
- pool.h pool.c \
+libdex_la_SOURCES = \
+ core.h core.c \
+ class.h class.c \
+ dex-int.h dex-int.c \
+ dex_def.h \
+ field.h field.c \
+ format.h format.c \
+ loading.h loading.c \
+ method.h method.c \
+ pool.h pool.c \
routine.h routine.c
-libdex_la_LIBADD = \
+libdex_la_LIBADD = \
$(PYTHON3_LIBADD)
+libdex_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libdex_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -61,8 +63,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdex_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/dex/core.c b/plugins/dex/core.c
index 22ebfff..1101a89 100644
--- a/plugins/dex/core.c
+++ b/plugins/dex/core.c
@@ -24,18 +24,17 @@
#include "core.h"
-#include <config.h>
#include <core/global.h>
#include <plugins/self.h>
#include "format.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
{
bool result; /* Bilan à retourner */
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
result = add_format_dex_module_to_python_module();
#else
result = true;
diff --git a/plugins/dex/loading.h b/plugins/dex/loading.h
index 5560e4e..4de6df1 100644
--- a/plugins/dex/loading.h
+++ b/plugins/dex/loading.h
@@ -26,9 +26,11 @@
#include <glib-object.h>
+#include <stdbool.h>
+#include <stdint.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
diff --git a/plugins/dex/python/Makefile.am b/plugins/dex/python/Makefile.am
index e91630e..b627157 100644
--- a/plugins/dex/python/Makefile.am
+++ b/plugins/dex/python/Makefile.am
@@ -1,26 +1,21 @@
noinst_LTLIBRARIES = libdexpython.la
-libdexpython_la_SOURCES = \
- class.h class.c \
- constants.h constants.c \
- field.h field.c \
- format.h format.c \
- method.h method.c \
- module.h module.c \
- pool.h pool.c \
- routine.h routine.c \
+libdexpython_la_SOURCES = \
+ class.h class.c \
+ constants.h constants.c \
+ field.h field.c \
+ format.h format.c \
+ method.h method.c \
+ module.h module.c \
+ pool.h pool.c \
+ routine.h routine.c \
translate.h translate.c
-libdexpython_la_LDFLAGS =
+libdexpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdexpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/dex/python/class.c b/plugins/dex/python/class.c
index e344124..247197c 100644
--- a/plugins/dex/python/class.c
+++ b/plugins/dex/python/class.c
@@ -584,14 +584,14 @@ PyTypeObject *get_python_dex_class_type(void)
bool register_python_dex_class(PyObject *module)
{
- PyTypeObject *py_dex_class_type; /* Type Python 'DexClass' */
+ PyTypeObject *type; /* Type Python 'DexClass' */
PyObject *dict; /* Dictionnaire du module */
- py_dex_class_type = get_python_dex_class_type();
+ type = get_python_dex_class_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DEX_CLASS, py_dex_class_type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_DEX_CLASS, type))
return false;
return true;
diff --git a/plugins/dex/python/field.c b/plugins/dex/python/field.c
index 1381af6..081d0af 100644
--- a/plugins/dex/python/field.c
+++ b/plugins/dex/python/field.c
@@ -181,14 +181,14 @@ PyTypeObject *get_python_dex_field_type(void)
bool register_python_dex_field(PyObject *module)
{
- PyTypeObject *py_dex_field_type; /* Type Python 'DexField' */
+ PyTypeObject *type; /* Type Python 'DexField' */
PyObject *dict; /* Dictionnaire du module */
- py_dex_field_type = get_python_dex_field_type();
+ type = get_python_dex_field_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DEX_FIELD, py_dex_field_type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_DEX_FIELD, type))
return false;
return true;
diff --git a/plugins/dex/python/format.c b/plugins/dex/python/format.c
index fa65b25..4a8939b 100644
--- a/plugins/dex/python/format.c
+++ b/plugins/dex/python/format.c
@@ -281,7 +281,10 @@ bool register_python_dex_format(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DEX_FORMAT, type, get_python_executable_format_type()))
+ if (!ensure_python_executable_format_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_DEX_FORMAT, type))
return false;
if (!define_python_dex_format_common_constants(type))
diff --git a/plugins/dex/python/method.c b/plugins/dex/python/method.c
index fc56f29..ed67176 100644
--- a/plugins/dex/python/method.c
+++ b/plugins/dex/python/method.c
@@ -291,14 +291,14 @@ PyTypeObject *get_python_dex_method_type(void)
bool register_python_dex_method(PyObject *module)
{
- PyTypeObject *py_dex_method_type; /* Type Python 'DexMethod' */
+ PyTypeObject *type; /* Type Python 'DexMethod' */
PyObject *dict; /* Dictionnaire du module */
- py_dex_method_type = get_python_dex_method_type();
+ type = get_python_dex_method_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DEX_METHOD, py_dex_method_type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_DEX_METHOD, type))
return false;
return true;
diff --git a/plugins/dex/python/pool.c b/plugins/dex/python/pool.c
index ddfc900..0c08865 100644
--- a/plugins/dex/python/pool.c
+++ b/plugins/dex/python/pool.c
@@ -822,7 +822,7 @@ bool register_python_dex_pool(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DEX_POOL, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_DEX_POOL, type))
return false;
return true;
diff --git a/plugins/dex/python/routine.c b/plugins/dex/python/routine.c
index 31410c7..af38263 100644
--- a/plugins/dex/python/routine.c
+++ b/plugins/dex/python/routine.c
@@ -165,7 +165,10 @@ bool register_python_dex_routine(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DEX_ROUTINE, type, get_python_binary_routine_type()))
+ if (!ensure_python_binary_routine_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_DEX_ROUTINE, type))
return false;
return true;
diff --git a/plugins/dexbnf/Makefile.am b/plugins/dexbnf/Makefile.am
index 51598ce..222cc35 100644
--- a/plugins/dexbnf/Makefile.am
+++ b/plugins/dexbnf/Makefile.am
@@ -34,17 +34,19 @@ PYTHON3_SUBDIRS = python
endif
-libdexbnf_la_SOURCES = \
- context.h context.c \
- core.h core.c \
- demangler.h demangler.c \
- simple.h simple.c \
- shorty.h shorty.c \
+libdexbnf_la_SOURCES = \
+ context.h context.c \
+ core.h core.c \
+ demangler.h demangler.c \
+ simple.h simple.c \
+ shorty.h shorty.c \
type.h type.c
-libdexbnf_la_LIBADD = \
+libdexbnf_la_LIBADD = \
$(PYTHON3_LIBADD)
+libdexbnf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libdexbnf_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -56,8 +58,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdexbnf_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/dexbnf/core.c b/plugins/dexbnf/core.c
index 37e5a15..07e7545 100644
--- a/plugins/dexbnf/core.c
+++ b/plugins/dexbnf/core.c
@@ -24,18 +24,17 @@
#include "core.h"
-#include <config.h>
#include <core/demanglers.h>
#include <plugins/self.h>
#include "demangler.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -67,7 +66,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
result = register_demangler_type(G_TYPE_DEX_DEMANGLER);
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
if (result)
result = add_mangling_dexbnf_module_to_python_module();
#endif
diff --git a/plugins/dexbnf/python/Makefile.am b/plugins/dexbnf/python/Makefile.am
index 59668eb..95a8b0c 100644
--- a/plugins/dexbnf/python/Makefile.am
+++ b/plugins/dexbnf/python/Makefile.am
@@ -1,19 +1,14 @@
noinst_LTLIBRARIES = libdexbnfpython.la
-libdexbnfpython_la_SOURCES = \
- demangler.h demangler.c \
+libdexbnfpython_la_SOURCES = \
+ demangler.h demangler.c \
module.h module.c
-libdexbnfpython_la_LDFLAGS =
+libdexbnfpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdexbnfpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/dexbnf/python/demangler.c b/plugins/dexbnf/python/demangler.c
index 3682216..8fc93e4 100644
--- a/plugins/dexbnf/python/demangler.c
+++ b/plugins/dexbnf/python/demangler.c
@@ -140,15 +140,17 @@ PyTypeObject *get_python_dex_demangler_type(void)
bool register_python_dex_demangler(PyObject *module)
{
- PyTypeObject *py_dex_demangler_type; /* Type Python 'DexDemangler' */
+ PyTypeObject *type; /* Type Python 'DexDemangler' */
PyObject *dict; /* Dictionnaire du module */
- py_dex_demangler_type = get_python_dex_demangler_type();
+ type = get_python_dex_demangler_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DEX_DEMANGLER,
- py_dex_demangler_type, get_python_compiler_demangler_type()))
+ if (!ensure_python_compiler_demangler_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_DEX_DEMANGLER, type))
return false;
return true;
diff --git a/plugins/dwarf/Makefile.am b/plugins/dwarf/Makefile.am
index 5a8c9c9..c93e302 100644
--- a/plugins/dwarf/Makefile.am
+++ b/plugins/dwarf/Makefile.am
@@ -11,15 +11,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs'
endif
-libdwarf_la_SOURCES = \
- abbrev.h abbrev.c \
- checks.h checks.c \
- core.h core.c \
- def.h \
- die.h die.c \
- form.h form.c \
- format.h format.c \
- info.h info.c \
+libdwarf_la_SOURCES = \
+ abbrev.h abbrev.c \
+ checks.h checks.c \
+ core.h core.c \
+ def.h \
+ die.h die.c \
+ form.h form.c \
+ format.h format.c \
+ info.h info.c \
utils.h utils.c
@@ -33,11 +33,13 @@ libdwarf_la_SOURCES = \
# info.h info.c \
# symbols.h symbols.c
-libdwarf_la_LIBADD = \
- v2/libdwarfv2.la \
- v3/libdwarfv3.la \
+libdwarf_la_LIBADD = \
+ v2/libdwarfv2.la \
+ v3/libdwarfv3.la \
v4/libdwarfv4.la
+libdwarf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libdwarf_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -49,8 +51,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdwarf_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = v2 v3 v4
diff --git a/plugins/dwarf/core.c b/plugins/dwarf/core.c
index bf1e812..7b62fb9 100644
--- a/plugins/dwarf/core.c
+++ b/plugins/dwarf/core.c
@@ -24,14 +24,13 @@
#include "core.h"
-#include <config.h>
#include <plugins/self.h>
#include "format.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
diff --git a/plugins/dwarf/info.h b/plugins/dwarf/info.h
index a2fd961..6ce3e9a 100644
--- a/plugins/dwarf/info.h
+++ b/plugins/dwarf/info.h
@@ -29,6 +29,7 @@
#include <glibext/delayed.h>
+#include <glibext/notifier.h>
#include "format.h"
diff --git a/plugins/dwarf/v2/Makefile.am b/plugins/dwarf/v2/Makefile.am
index 1683ded..5664927 100644
--- a/plugins/dwarf/v2/Makefile.am
+++ b/plugins/dwarf/v2/Makefile.am
@@ -1,17 +1,12 @@
noinst_LTLIBRARIES = libdwarfv2.la
-libdwarfv2_la_SOURCES = \
+libdwarfv2_la_SOURCES = \
checks.h checks.c
-libdwarfv2_la_LDFLAGS = $(LIBGTK_LIBS)
+libdwarfv2_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdwarfv2_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/dwarf/v3/Makefile.am b/plugins/dwarf/v3/Makefile.am
index b821d2a..2078058 100644
--- a/plugins/dwarf/v3/Makefile.am
+++ b/plugins/dwarf/v3/Makefile.am
@@ -1,17 +1,12 @@
noinst_LTLIBRARIES = libdwarfv3.la
-libdwarfv3_la_SOURCES = \
+libdwarfv3_la_SOURCES = \
checks.h checks.c
-libdwarfv3_la_LDFLAGS = $(LIBGTK_LIBS)
+libdwarfv3_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdwarfv3_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/dwarf/v4/Makefile.am b/plugins/dwarf/v4/Makefile.am
index e06e8f5..ef13b2c 100644
--- a/plugins/dwarf/v4/Makefile.am
+++ b/plugins/dwarf/v4/Makefile.am
@@ -1,17 +1,12 @@
noinst_LTLIBRARIES = libdwarfv4.la
-libdwarfv4_la_SOURCES = \
+libdwarfv4_la_SOURCES = \
checks.h checks.c
-libdwarfv4_la_LDFLAGS = $(LIBGTK_LIBS)
+libdwarfv4_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libdwarfv4_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/elf/Makefile.am b/plugins/elf/Makefile.am
index 880ae78..677cf93 100644
--- a/plugins/elf/Makefile.am
+++ b/plugins/elf/Makefile.am
@@ -37,23 +37,25 @@ PYTHON3_SUBDIRS = python
endif
-libelf_la_SOURCES = \
- core.h core.c \
- elf-int.h elf-int.c \
- elf_def.h \
- elf_def_arm.h \
- format.h format.c \
- dynamic.h dynamic.c \
- helper_arm.h helper_arm.c \
- loading.h loading.c \
- program.h program.c \
- section.h section.c \
- strings.h strings.c \
+libelf_la_SOURCES = \
+ core.h core.c \
+ elf-int.h elf-int.c \
+ elf_def.h \
+ elf_def_arm.h \
+ format.h format.c \
+ dynamic.h dynamic.c \
+ helper_arm.h helper_arm.c \
+ loading.h loading.c \
+ program.h program.c \
+ section.h section.c \
+ strings.h strings.c \
symbols.h symbols.c
-libelf_la_LIBADD = \
+libelf_la_LIBADD = \
$(PYTHON3_LIBADD)
+libelf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libelf_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -65,8 +67,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libelf_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/elf/core.c b/plugins/elf/core.c
index 1e98aba..bd829af 100644
--- a/plugins/elf/core.c
+++ b/plugins/elf/core.c
@@ -24,18 +24,17 @@
#include "core.h"
-#include <config.h>
#include <core/global.h>
#include <plugins/self.h>
#include "format.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
{
bool result; /* Bilan à retourner */
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
result = add_format_elf_module_to_python_module();
#else
result = true;
diff --git a/plugins/elf/loading.h b/plugins/elf/loading.h
index e3016d4..270bb0b 100644
--- a/plugins/elf/loading.h
+++ b/plugins/elf/loading.h
@@ -26,7 +26,7 @@
#include <format/symiter.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
#include "format.h"
diff --git a/plugins/elf/python/Makefile.am b/plugins/elf/python/Makefile.am
index 29b7d98..1d4f671 100644
--- a/plugins/elf/python/Makefile.am
+++ b/plugins/elf/python/Makefile.am
@@ -1,25 +1,20 @@
noinst_LTLIBRARIES = libelfpython.la
-libelfpython_la_SOURCES = \
- constants.h constants.c \
- dynamic.h dynamic.c \
- elf_def.h elf_def.c \
- format.h format.c \
- module.h module.c \
- program.h program.c \
- section.h section.c \
+libelfpython_la_SOURCES = \
+ constants.h constants.c \
+ dynamic.h dynamic.c \
+ elf_def.h elf_def.c \
+ format.h format.c \
+ module.h module.c \
+ program.h program.c \
+ section.h section.c \
translate.h translate.c
-libelfpython_la_LDFLAGS =
+libelfpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libelfpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/elf/python/format.c b/plugins/elf/python/format.c
index e0195c4..95eaa9a 100644
--- a/plugins/elf/python/format.c
+++ b/plugins/elf/python/format.c
@@ -244,18 +244,20 @@ PyTypeObject *get_python_elf_format_type(void)
bool register_python_elf_format(PyObject *module)
{
- PyTypeObject *py_elf_format_type; /* Type Python 'ElfFormat' */
+ PyTypeObject *type; /* Type Python 'ElfFormat' */
PyObject *dict; /* Dictionnaire du module */
- py_elf_format_type = get_python_elf_format_type();
+ type = get_python_elf_format_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ELF_FORMAT,
- py_elf_format_type, get_python_executable_format_type()))
+ if (!ensure_python_executable_format_is_registered())
return false;
- if (!define_python_elf_format_constants(py_elf_format_type))
+ if (!register_class_for_pygobject(dict, G_TYPE_ELF_FORMAT, type))
+ return false;
+
+ if (!define_python_elf_format_constants(type))
return false;
return true;
diff --git a/plugins/elf/strings.h b/plugins/elf/strings.h
index 902c2f8..3a07b96 100644
--- a/plugins/elf/strings.h
+++ b/plugins/elf/strings.h
@@ -29,7 +29,7 @@
#include <glibext/delayed.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
diff --git a/plugins/elf/symbols.h b/plugins/elf/symbols.h
index f4a6eec..c736d56 100644
--- a/plugins/elf/symbols.h
+++ b/plugins/elf/symbols.h
@@ -29,7 +29,7 @@
#include <glibext/delayed.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
diff --git a/plugins/encodings/Makefile.am b/plugins/encodings/Makefile.am
new file mode 100644
index 0000000..6dd71fb
--- /dev/null
+++ b/plugins/encodings/Makefile.am
@@ -0,0 +1,64 @@
+
+lib_LTLIBRARIES = libencodings.la
+
+libdir = $(pluginslibdir)
+
+
+if BUILD_PYTHON_PACKAGE
+
+RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs:$$ORIGIN'
+
+else
+
+RUN_PATH = -Wl,-rpath,'$$ORIGIN'
+
+endif
+
+if BUILD_PYTHON3_BINDINGS
+
+PYTHON3_LIBADD = python/libencodingspython.la
+
+if BUILD_DISCARD_LOCAL
+
+if BUILD_PYTHON_PACKAGE
+PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN/..'
+else
+PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN'
+endif
+
+else
+
+PYTHON3_RUN_PATH = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs
+
+endif
+
+PYTHON3_LDFLAGS = $(PYTHON3_RUN_PATH) -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so
+
+PYTHON3_SUBDIRS = python
+
+endif
+
+
+libencodings_la_SOURCES = \
+ base64.h base64.c \
+ core.h core.c
+
+libencodings_la_LIBADD = \
+ $(PYTHON3_LIBADD) \
+ rost/libencodingsrost.la
+
+libencodings_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+libencodings_la_LDFLAGS = \
+ -avoid-version \
+ -L$(top_srcdir)/src/.libs -lchrysacore \
+ -L$(top_srcdir)/plugins/pe/.libs -lpe \
+ $(RUN_PATH) $(PYTHON3_LDFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libencodings_la_SOURCES:%c=)
+
+
+SUBDIRS = $(PYTHON3_SUBDIRS) rost
diff --git a/plugins/encodings/base64.c b/plugins/encodings/base64.c
new file mode 100644
index 0000000..c749a87
--- /dev/null
+++ b/plugins/encodings/base64.c
@@ -0,0 +1,139 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.c - calculs d'encodages en base 64
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "base64.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : input = données d'entrée à traiter. *
+* output = données sortantes constituées. [OUT] *
+* alphabet = alphabet d'encodage mis à disposition. *
+* *
+* Description : Procède à l'encodage d'un contenu en base 64. *
+* *
+* Retour : Bilan de l'opération : true en cas de réussite, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool _base64_encode(const sized_binary_t *input, sized_string_t *output, const sized_string_t *alphabet)
+{
+ bool result; /* Bilan à retourner */
+ const bin_t *src; /* Tête de lecture #1 */
+ const bin_t *alpha; /* Tête de lecture #2 */
+ bin_t *iter; /* Tête d'écriture */
+ size_t i; /* Boucle de parcours */
+
+ result = (alphabet->len == 64);
+ if (!result) goto exit;
+
+ /* Création du réceptacle */
+
+ output->len = input->len * 4 / 3;
+
+ if (output->len % 4 != 0)
+ output->len += (4 - output->len % 4);
+
+ output->data = malloc((output->len + 1) * sizeof(bin_t));
+
+ /* Encodage du corps du message */
+
+ src = input->static_bin_data;
+ alpha = alphabet->static_bin_data;
+
+ iter = output->bin_data;
+
+ if (input->len > 2)
+ for (i = 0; i < (input->len - 2); i += 3)
+ {
+ *iter++ = alpha[(src[i] >> 2) & 0x3f];
+
+ *iter++ = alpha[((src[i] & 0x03) << 4) | ((src[i + 1] & 0xf0) >> 4)];
+
+ *iter++ = alpha[((src[i + 1] & 0x0f) << 2) | ((src[i + 2] & 0xc0) >> 6)];
+
+ *iter++ = alpha[src[i + 2] & 0x3f];
+
+ }
+ else
+ i = 0;
+
+ /* Bourrage final ? */
+
+ if (i < input->len)
+ {
+ *iter++ = alpha[(src[i] >> 2) & 0x3f];
+
+ if (i == (input->len - 1))
+ {
+ *iter++ = alpha[((src[i] & 0x03) << 4)];
+ *iter++ = '=';
+ }
+ else
+ {
+ *iter++ = alpha[((src[i] & 0x03) << 4) | ((src[i + 1] & 0xf0) >> 4)];
+ *iter++ = alpha[((src[i + 1] & 0x0f) << 2)];
+ }
+
+ *iter++ = '=';
+ }
+
+ *iter = 0x00;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : input = données d'entrée à traiter. *
+* output = données sortantes constituées. [OUT] *
+* *
+* Description : Procède à l'encodage par défaut d'un contenu en base 64. *
+* *
+* Retour : Bilan de l'opération : true en cas de réussite, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool base64_encode(const sized_binary_t *input, sized_string_t *output)
+{
+ bool result; /* Bilan à retourner */
+
+ const sized_string_t alphabet = {
+ .static_data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+ .len = 64
+ };
+
+ result = _base64_encode(input, output, &alphabet);
+
+ return result;
+
+}
diff --git a/plugins/encodings/base64.h b/plugins/encodings/base64.h
new file mode 100644
index 0000000..64ddccd
--- /dev/null
+++ b/plugins/encodings/base64.h
@@ -0,0 +1,43 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.h - prototypes pour les calculs d'encodages en base 64
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_BASE64_H
+#define _PLUGINS_ENCODINGS_BASE64_H
+
+
+#include <stdbool.h>
+
+
+#include <common/szstr.h>
+
+
+
+/* Procède à l'encodage d'un contenu en base 64. */
+bool _base64_encode(const sized_binary_t *, sized_string_t *, const sized_string_t *);
+
+/* Procède à l'encodage par défaut d'un contenu en base 64. */
+bool base64_encode(const sized_binary_t *, sized_string_t *);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_BASE64_H */
diff --git a/plugins/encodings/core.c b/plugins/encodings/core.c
new file mode 100644
index 0000000..2ece208
--- /dev/null
+++ b/plugins/encodings/core.c
@@ -0,0 +1,89 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - prototypes pour le calcul d'encodages
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <analysis/scan/core.h>
+#include <plugins/self.h>
+
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+# include "python/module.h"
+# include "python/rost/module.h"
+#endif
+#include "rost/base64.h"
+
+
+#ifdef INCLUDE_PYTHON3_BINDINGS_
+# define PG_REQ RL("PyChrysalide")
+#else
+# define PG_REQ NO_REQ
+#endif
+
+
+
+DEFINE_CHRYSALIDE_PLUGIN("Encodings", "Special encoding methods for binaries",
+ PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/formats"),
+ PG_REQ, AL(PGA_PLUGIN_INIT));
+
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Prend acte du chargement du greffon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
+{
+ bool result; /* Bilan à retourner */
+ GScanTokenModifier *modifier; /* Modificateur à enregistrer */
+
+ modifier = g_scan_base64_modifier_new();
+
+ result = register_scan_token_modifier(modifier);
+
+ g_object_unref(G_OBJECT(modifier));
+
+ if (!result) goto exit;
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+
+ result = add_encodings_module_to_python_module();
+
+ if (result)
+ result = register_encodings_rost_modifiers();
+#endif
+
+ exit:
+
+ return result;
+
+}
diff --git a/plugins/encodings/core.h b/plugins/encodings/core.h
new file mode 100644
index 0000000..75a6e73
--- /dev/null
+++ b/plugins/encodings/core.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour le calcul d'encodages
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_CORE_H
+#define _PLUGINS_ENCODINGS_CORE_H
+
+
+#include <plugins/plugin.h>
+#include <plugins/plugin-int.h>
+
+
+
+/* Prend acte du chargement du greffon. */
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_CORE_H */
diff --git a/plugins/encodings/python/Makefile.am b/plugins/encodings/python/Makefile.am
new file mode 100644
index 0000000..523a6f4
--- /dev/null
+++ b/plugins/encodings/python/Makefile.am
@@ -0,0 +1,21 @@
+
+noinst_LTLIBRARIES = libencodingspython.la
+
+libencodingspython_la_SOURCES = \
+ base64.h base64.c \
+ module.h module.c
+
+libencodingspython_la_LIBADD = \
+ rost/libencodingspythonrost.la
+
+libencodingspython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) \
+ $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libencodingspython_la_SOURCES:%c=)
+
+
+SUBDIRS = rost
diff --git a/plugins/encodings/python/base64.c b/plugins/encodings/python/base64.c
new file mode 100644
index 0000000..3bc84a2
--- /dev/null
+++ b/plugins/encodings/python/base64.c
@@ -0,0 +1,139 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.c - équivalent Python du fichier "plugins/encodings/base64.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "base64.h"
+
+
+#include <pygobject.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../base64.h"
+
+
+
+/* Procède à l'encodage d'un contenu en base 64. */
+static PyObject *py_encodings_base64_encode(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = paramètre à récupérer pour le traitement. *
+* *
+* Description : Procède à l'encodage d'un contenu en base 64. *
+* *
+* Retour : None ou données sortantes constituées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_encodings_base64_encode(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ sized_string_t alphabet; /* Alphabet de traitement ? */
+ Py_ssize_t alen; /* Taille de cet alphabet */
+ sized_binary_t input; /* Données à traiter */
+ Py_ssize_t ilen; /* Quantité de ces données */
+ int ret; /* Bilan de lecture des args. */
+ sized_string_t output; /* Données encodées à exporter */
+ bool status; /* Bilan de l'opération */
+
+#define ENCODINGS_BASE64_ENCODE_METHOD PYTHON_METHOD_DEF \
+( \
+ base64_encode, "input, /, alphabet=None", \
+ METH_VARARGS, py_encodings, \
+ "Encode a given content using Base64.\n" \
+ "\n" \
+ "The *input* argument has to be provided as bytes. The optional" \
+ " *alphabet* is expected to be a 64-byte array if defined.\n" \
+ "\n" \
+ "The returned value is bytes or *None* in case of error." \
+)
+
+ result = NULL;
+
+ alphabet.data = NULL;
+ alen = 0;
+
+ ret = PyArg_ParseTuple(args, "s#|s#", &input.static_data, &ilen, &alphabet.static_data, &alen);
+ if (!ret) goto exit;
+
+ alphabet.len = alen;
+ input.len = ilen;
+
+ if (alphabet.len > 0)
+ status = _base64_encode(&input, &output, &alphabet);
+ else
+ status = base64_encode(&input, &output);
+
+ if (status)
+ {
+ result = PyBytes_FromStringAndSize(output.data, output.len);
+ exit_szstr(&output);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Définit une extension du module 'encodings' à compléter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_encodings_module_with_base64(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+
+ static PyMethodDef py_base64_methods[] = {
+ ENCODINGS_BASE64_ENCODE_METHOD,
+ { NULL }
+ };
+
+ result = register_python_module_methods(super, py_base64_methods);
+
+ return result;
+
+}
diff --git a/plugins/encodings/python/base64.h b/plugins/encodings/python/base64.h
new file mode 100644
index 0000000..1e08cf6
--- /dev/null
+++ b/plugins/encodings/python/base64.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.h - équivalent Python du fichier "plugins/encodings/base64.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_PYTHON_BASE64_H
+#define _PLUGINS_ENCODINGS_PYTHON_BASE64_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit une extension du module 'encodings' à compléter. */
+bool populate_encodings_module_with_base64(PyObject *);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_PYTHON_BASE64_H */
diff --git a/plugins/encodings/python/module.c b/plugins/encodings/python/module.c
new file mode 100644
index 0000000..454159b
--- /dev/null
+++ b/plugins/encodings/python/module.c
@@ -0,0 +1,87 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire encodings en tant que module
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "base64.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Ajoute le module 'plugins.encodings' au module Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_encodings_module_to_python_module(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *super; /* Module à compléter */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_PLUGINS_ENCODINGS_DOC \
+ "encodings is a module providing a few implementations" \
+ " of algorithms used to encode data."
+
+ static PyModuleDef py_chrysalide_encodings_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.plugins.encodings",
+ .m_doc = PYCHRYSALIDE_PLUGINS_ENCODINGS_DOC,
+
+ .m_size = -1,
+
+ };
+
+ result = false;
+
+ super = get_access_to_python_module("pychrysalide.plugins");
+
+ module = build_python_module(super, &py_chrysalide_encodings_module);
+
+ result = (module != NULL);
+
+ if (result) result = populate_encodings_module_with_base64(module);
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/encodings/python/module.h b/plugins/encodings/python/module.h
new file mode 100644
index 0000000..e7dd812
--- /dev/null
+++ b/plugins/encodings/python/module.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire encodings en tant que module
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_PYTHON_MODULE_H
+#define _PLUGINS_ENCODINGS_PYTHON_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins.encodings' au module Python. */
+bool add_encodings_module_to_python_module(void);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_PYTHON_MODULE_H */
diff --git a/plugins/encodings/python/rost/Makefile.am b/plugins/encodings/python/rost/Makefile.am
new file mode 100644
index 0000000..531fb26
--- /dev/null
+++ b/plugins/encodings/python/rost/Makefile.am
@@ -0,0 +1,15 @@
+
+noinst_LTLIBRARIES = libencodingspythonrost.la
+
+libencodingspythonrost_la_SOURCES = \
+ base64.h base64.c \
+ module.h module.c
+
+libencodingspythonrost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) \
+ $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libencodingspythonrost_la_SOURCES:%c=)
diff --git a/plugins/encodings/python/rost/base64.c b/plugins/encodings/python/rost/base64.c
new file mode 100644
index 0000000..57bba76
--- /dev/null
+++ b/plugins/encodings/python/rost/base64.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.c - équivalent Python du fichier "plugins/encodings/rost/base64.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "base64.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/scan/patterns/modifier.h>
+
+
+#include "../../rost/base64.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_base64_modifier, G_TYPE_SCAN_BASE64_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_base64_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_base64_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_BASE64_MODIFIER_DOC \
+ "The *Base64Modifier* class transforms a byte pattern into its" \
+ " base64 encoded form.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " Base64Modifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_base64_modifier_type(void)
+{
+ static PyMethodDef py_scan_base64_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_base64_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_base64_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Base64Modifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_BASE64_MODIFIER_DOC,
+
+ .tp_methods = py_scan_base64_modifier_methods,
+ .tp_getset = py_scan_base64_modifier_getseters,
+
+ .tp_init = py_scan_base64_modifier_init,
+ .tp_new = py_scan_base64_modifier_new,
+
+ };
+
+ return &py_scan_base64_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....Base64Modifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_base64_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python Base64Modifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_base64_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_token_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_BASE64_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation par encodage en Base64. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_base64_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_base64_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Base64 modifier");
+ break;
+
+ case 1:
+ *((GScanBase64Modifier **)dst) = G_SCAN_BASE64_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/encodings/python/rost/base64.h b/plugins/encodings/python/rost/base64.h
new file mode 100644
index 0000000..0ef0834
--- /dev/null
+++ b/plugins/encodings/python/rost/base64.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.h - équivalent Python du fichier "plugins/encodings/rost/base64.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H
+#define _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_base64_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Base64Modifier'. */
+bool ensure_python_scan_base64_modifier_is_registered(void);
+
+/* Tente de convertir en transformation par encodage en Base64. */
+int convert_to_scan_base64_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H */
diff --git a/plugins/encodings/python/rost/module.c b/plugins/encodings/python/rost/module.c
new file mode 100644
index 0000000..4812bb5
--- /dev/null
+++ b/plugins/encodings/python/rost/module.c
@@ -0,0 +1,64 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire rost en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "base64.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les modificateurs pour ROST. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool register_encodings_rost_modifiers(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_scan_base64_modifier_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/encodings/python/rost/module.h b/plugins/encodings/python/rost/module.h
new file mode 100644
index 0000000..ba021cb
--- /dev/null
+++ b/plugins/encodings/python/rost/module.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire rost en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_PYTHON_ROST_MODULE_H
+#define _PLUGINS_ENCODINGS_PYTHON_ROST_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Intègre les modificateurs pour ROST. */
+bool register_encodings_rost_modifiers(void);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_PYTHON_ROST_MODULE_H */
diff --git a/plugins/encodings/rost/Makefile.am b/plugins/encodings/rost/Makefile.am
new file mode 100644
index 0000000..efca690
--- /dev/null
+++ b/plugins/encodings/rost/Makefile.am
@@ -0,0 +1,12 @@
+
+noinst_LTLIBRARIES = libencodingsrost.la
+
+libencodingsrost_la_SOURCES = \
+ base64.h base64.c
+
+libencodingsrost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libencodingsrost_la_SOURCES:%c=)
diff --git a/plugins/encodings/rost/base64.c b/plugins/encodings/rost/base64.c
new file mode 100644
index 0000000..adbb2fb
--- /dev/null
+++ b/plugins/encodings/rost/base64.c
@@ -0,0 +1,555 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.c - transormation en encodage Base64
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "base64.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <string.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+#include "../base64.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en encodage Base64. */
+static void g_scan_base64_modifier_class_init(GScanBase64ModifierClass *klass);
+
+/* Initialise une instance de transmission en encodage Base64. */
+static void g_scan_base64_modifier_init(GScanBase64Modifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_base64_modifier_dispose(GScanBase64Modifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_base64_modifier_finalize(GScanBase64Modifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_base64_modifier_get_name(const GScanBase64Modifier *);
+
+/* Finalise l'encoddage en Base64 d'un motif transformé. */
+static void strip_base64_modifier_output(const sized_binary_t *, const sized_binary_t *, size_t, sized_binary_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_base64_modifier_transform(const GScanBase64Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Détermine si un argument est bien toléré par un modificateur. */
+static bool g_scan_base64_modifier_can_handle_arg(const GScanBase64Modifier *, const modifier_arg_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_base64_modifier_transform_with_arg(const GScanBase64Modifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_base64_modifier_get_path(const GScanBase64Modifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation en encodage Base64. */
+G_DEFINE_TYPE(GScanBase64Modifier, g_scan_base64_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en encodage Base64. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_base64_modifier_class_init(GScanBase64ModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_base64_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_base64_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_base64_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_base64_modifier_transform;
+ modifier->can_handle = (can_token_modifier_handle_arg)g_scan_base64_modifier_can_handle_arg;
+ modifier->transform_with = (transform_scan_token_with_fc)g_scan_base64_modifier_transform_with_arg;
+ modifier->get_path = (get_modifier_path)g_scan_base64_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en encodage Base64. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_base64_modifier_init(GScanBase64Modifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_base64_modifier_dispose(GScanBase64Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_base64_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_base64_modifier_finalize(GScanBase64Modifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_base64_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des encodages en Base64. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_base64_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_BASE64_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_base64_modifier_get_name(const GScanBase64Modifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("base64");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : input = contenu brut d'origine. *
+* tmpput = encodage en Base64 intermédiaire obtenu. *
+* skip = nombre de caractères initiaux à sauter. *
+* output = encodage en Base64 final à conserver. *
+* *
+* Description : Finalise l'encoddage en Base64 d'un motif transformé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void strip_base64_modifier_output(const sized_binary_t *input, const sized_binary_t *tmpput, size_t skip, sized_binary_t *output)
+{
+ size_t keep; /* Nombre d'octets immuables */
+
+ keep = (input->len * 8) / 6;
+
+ assert(keep >= skip);
+
+ if (skip > 0)
+ skip++;
+
+ keep -= skip;
+
+ output->len = keep;
+ output->bin_data = malloc(keep * sizeof(bin_t));
+
+ memcpy(output->bin_data, tmpput->static_bin_data + skip, keep);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_base64_modifier_transform(const GScanBase64Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ sized_binary_t tmp_in; /* Manipulation des variations */
+ sized_binary_t tmp_out; /* Manipulation des variations */
+
+ result = true;
+
+ *dcount = scount * 3;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount && result; i++)
+ {
+ _src = src + i;
+
+ tmp_in.data = malloc((_src->len + 2) * sizeof(bin_t));
+
+ /**
+ * Explications sur la définition des modifications sur les
+ * encodages produits : https://www.leeholmes.com/searching-for-content-in-base-64-strings/
+ */
+
+ /* Encodage premier */
+
+ result = base64_encode(_src, &tmp_out);
+ if (!result) goto exit;
+
+ strip_base64_modifier_output(_src, &tmp_out, 0, binary++);
+
+ exit_szstr(&tmp_out);
+
+ /* Variante 1 */
+
+ tmp_in.data[0] = ' ';
+ memcpy(&tmp_in.data[1], _src->static_bin_data, _src->len);
+
+ tmp_in.len = _src->len + 1;
+
+ result = base64_encode(&tmp_in, &tmp_out);
+ if (!result) goto exit;
+
+ strip_base64_modifier_output(&tmp_in, &tmp_out, 1, binary);
+
+ /**
+ * Lors qu'un unique octet est encodé, cet octet ne produit aucun
+ * caractère que ne dépend que de lui :
+ *
+ * | X |
+ * 1 2 3 4 5 6 | 7 8 1 2 3 4 | 5 6 7 8 1 2 | 3 4 5 6 7 8
+ *
+ * Les compteurs sont alors diminués.
+ */
+
+ if (binary->len == 0)
+ (*dcount)--;
+ else
+ binary++;
+
+ exit_szstr(&tmp_out);
+
+ /* Variante 2 */
+
+ tmp_in.data[0] = ' ';
+ tmp_in.data[2] = ' ';
+ memcpy(&tmp_in.data[2], _src->static_bin_data, _src->len);
+
+ tmp_in.len = _src->len + 2;
+
+ result = base64_encode(&tmp_in, &tmp_out);
+ if (!result) goto exit;
+
+ strip_base64_modifier_output(&tmp_in, &tmp_out, 2, binary++);
+
+ exit_szstr(&tmp_out);
+
+ exit:
+
+ exit_szstr(&tmp_in);
+
+ }
+
+ if (!result)
+ {
+ for (i = 0; i < *dcount; i++)
+ exit_szstr(&(*dest)[i]);
+
+ free(*dest);
+
+ *dcount = 0;
+ *dest = NULL;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* arg = argument de personnalisation. *
+* *
+* Description : Détermine si un argument est bien toléré par un modificateur.*
+* *
+* Retour : Bilan de la consultation : support ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_base64_modifier_can_handle_arg(const GScanBase64Modifier *modifier, const modifier_arg_t *arg)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+
+ switch (arg->type)
+ {
+ case MAT_STRING:
+ result = (arg->value.string.len == 64);
+ break;
+
+ default:
+ result = false;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* arg = argument de personnalisation. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_base64_modifier_transform_with_arg(const GScanBase64Modifier *modifier, const sized_binary_t *src, size_t scount, const modifier_arg_t *arg, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ sized_binary_t tmp_in; /* Manipulation des variations */
+ sized_binary_t tmp_out; /* Manipulation des variations */
+
+ result = (arg->type == MAT_STRING);
+ if (!result) goto bad_arg;
+
+ *dcount = scount * 3;
+ *dest = calloc(*dcount, sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount && result; i++)
+ {
+ _src = src + i;
+
+ tmp_in.data = malloc((_src->len + 2) * sizeof(bin_t));
+
+ /**
+ * Explications sur la définition des modifications sur les
+ * encodages produits : https://www.leeholmes.com/searching-for-content-in-base-64-strings/
+ */
+
+ /* Encodage premier */
+
+ result = _base64_encode(_src, &tmp_out, &arg->value.string);
+ if (!result) goto exit;
+
+ strip_base64_modifier_output(_src, &tmp_out, 0, binary++);
+
+ exit_szstr(&tmp_out);
+
+ /* Variante 1 */
+
+ tmp_in.data[0] = ' ';
+ memcpy(&tmp_in.data[1], _src->static_bin_data, _src->len);
+
+ tmp_in.len = _src->len + 1;
+
+ result = _base64_encode(&tmp_in, &tmp_out, &arg->value.string);
+ if (!result) goto exit;
+
+ strip_base64_modifier_output(&tmp_in, &tmp_out, 1, binary++);
+
+ exit_szstr(&tmp_out);
+
+ /* Variante 2 */
+
+ tmp_in.data[0] = ' ';
+ tmp_in.data[2] = ' ';
+ memcpy(&tmp_in.data[2], _src->static_bin_data, _src->len);
+
+ tmp_in.len = _src->len + 2;
+
+ result = _base64_encode(&tmp_in, &tmp_out, &arg->value.string);
+ if (!result) goto exit;
+
+ strip_base64_modifier_output(&tmp_in, &tmp_out, 2, binary++);
+
+ exit_szstr(&tmp_out);
+
+ exit:
+
+ exit_szstr(&tmp_in);
+
+ }
+
+ if (!result)
+ {
+ for (i = 0; i < *dcount; i++)
+ exit_szstr(&(*dest)[i]);
+
+ free(*dest);
+
+ *dcount = 0;
+ *dest = NULL;
+
+ }
+
+ bad_arg:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_base64_modifier_get_path(const GScanBase64Modifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 3)
+ {
+ result = NULL;
+ (*index) -= 3;
+ }
+
+ else
+ result = strdup("base64");
+
+ return result;
+
+}
diff --git a/plugins/encodings/rost/base64.h b/plugins/encodings/rost/base64.h
new file mode 100644
index 0000000..646b945
--- /dev/null
+++ b/plugins/encodings/rost/base64.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * base64.h - prototypes pour la transormation en encodage Base64
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_ENCODINGS_ROST_BASE64_H
+#define _PLUGINS_ENCODINGS_ROST_BASE64_H
+
+
+#include <glib-object.h>
+
+
+#include <analysis/scan/patterns/modifier.h>
+
+
+
+#define G_TYPE_SCAN_BASE64_MODIFIER g_scan_base64_modifier_get_type()
+#define G_SCAN_BASE64_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_BASE64_MODIFIER, GScanBase64Modifier))
+#define G_IS_SCAN_BASE64_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_BASE64_MODIFIER))
+#define G_SCAN_BASE64_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_BASE64_MODIFIER, GScanBase64ModifierClass))
+#define G_IS_SCAN_BASE64_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_BASE64_MODIFIER))
+#define G_SCAN_BASE64_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_BASE64_MODIFIER, GScanBase64ModifierClass))
+
+
+/* Transormation en encodage Base64 (instance) */
+typedef GScanTokenModifier GScanBase64Modifier;
+
+/* Transormation en encodage Base64 (classe) */
+typedef GScanTokenModifierClass GScanBase64ModifierClass;
+
+
+/* Indique le type défini pour une transormation en encodage Base64. */
+GType g_scan_base64_modifier_get_type(void);
+
+/* Construit un modificateur livrant des encodages en Base64. */
+GScanTokenModifier *g_scan_base64_modifier_new(void);
+
+
+
+#endif /* _PLUGINS_ENCODINGS_ROST_BASE64_H */
diff --git a/plugins/fmtp/Makefile.am b/plugins/fmtp/Makefile.am
index f365c03..388adf3 100644
--- a/plugins/fmtp/Makefile.am
+++ b/plugins/fmtp/Makefile.am
@@ -11,10 +11,12 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs'
endif
-libfmtp_la_SOURCES = \
- def.h \
+libfmtp_la_SOURCES = \
+ def.h \
parser.h parser.c
+libfmtp_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libfmtp_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -24,8 +26,3 @@ libfmtp_la_LDFLAGS = \
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libfmtp_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/gdbrsp/python/gdb.c b/plugins/gdbrsp/python/gdb.c
index 24d9717..15c9f94 100644
--- a/plugins/gdbrsp/python/gdb.c
+++ b/plugins/gdbrsp/python/gdb.c
@@ -163,7 +163,10 @@ bool ensure_python_gdb_debugger_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_GDB_DEBUGGER, type, get_python_binary_debugger_type()))
+ if (!ensure_python_binary_debugger_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_GDB_DEBUGGER, type))
return false;
}
diff --git a/plugins/itanium/Makefile.am b/plugins/itanium/Makefile.am
index e1b2d9e..eee0da4 100644
--- a/plugins/itanium/Makefile.am
+++ b/plugins/itanium/Makefile.am
@@ -35,17 +35,19 @@ PYTHON3_SUBDIRS = python
endif
-libitanium_la_SOURCES = \
- abi.h abi.c \
- component-int.h \
- component.h component.c \
- context.h context.c \
- core.h core.c \
+libitanium_la_SOURCES = \
+ abi.h abi.c \
+ component-int.h \
+ component.h component.c \
+ context.h context.c \
+ core.h core.c \
demangler.h demangler.c
-libitanium_la_LIBADD = \
+libitanium_la_LIBADD = \
$(PYTHON3_LIBADD)
+libitanium_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libitanium_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -57,8 +59,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libitanium_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/itanium/core.c b/plugins/itanium/core.c
index dd74f53..3f3feb0 100644
--- a/plugins/itanium/core.c
+++ b/plugins/itanium/core.c
@@ -24,18 +24,17 @@
#include "core.h"
-#include <config.h>
#include <core/demanglers.h>
#include <plugins/self.h>
#include "demangler.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -67,7 +66,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
result = register_demangler_type(G_TYPE_ITANIUM_DEMANGLER);
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
if (result)
result = add_mangling_itanium_module_to_python_module();
#endif
diff --git a/plugins/itanium/python/Makefile.am b/plugins/itanium/python/Makefile.am
index b0a3da1..a00bda8 100644
--- a/plugins/itanium/python/Makefile.am
+++ b/plugins/itanium/python/Makefile.am
@@ -1,19 +1,14 @@
noinst_LTLIBRARIES = libitaniumpython.la
-libitaniumpython_la_SOURCES = \
- demangler.h demangler.c \
+libitaniumpython_la_SOURCES = \
+ demangler.h demangler.c \
module.h module.c
-libitaniumpython_la_LDFLAGS =
+libitaniumpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libitaniumpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/itanium/python/demangler.c b/plugins/itanium/python/demangler.c
index 5819ac4..12cc6c5 100644
--- a/plugins/itanium/python/demangler.c
+++ b/plugins/itanium/python/demangler.c
@@ -140,15 +140,17 @@ PyTypeObject *get_python_itanium_demangler_type(void)
bool register_python_itanium_demangler(PyObject *module)
{
- PyTypeObject *py_itanium_demangler_type;/* Type 'ItaniumDemangler' */
+ PyTypeObject *type; /* Type 'ItaniumDemangler' */
PyObject *dict; /* Dictionnaire du module */
- py_itanium_demangler_type = get_python_itanium_demangler_type();
+ type = get_python_itanium_demangler_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ITANIUM_DEMANGLER,
- py_itanium_demangler_type, get_python_compiler_demangler_type()))
+ if (!ensure_python_compiler_demangler_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ITANIUM_DEMANGLER, type))
return false;
return true;
diff --git a/plugins/java/Makefile.am b/plugins/java/Makefile.am
index 0e40bfa..cd94927 100644
--- a/plugins/java/Makefile.am
+++ b/plugins/java/Makefile.am
@@ -16,14 +16,9 @@ libformatjava_la_SOURCES = \
# method.h method.c \
# pool.h pool.c
-libformatjava_la_LDFLAGS =
+libformatjava_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=%)
dev_HEADERS = $(libformatjava_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/javadesc/Makefile.am b/plugins/javadesc/Makefile.am
index 7a79b99..8f91010 100644
--- a/plugins/javadesc/Makefile.am
+++ b/plugins/javadesc/Makefile.am
@@ -35,16 +35,18 @@ PYTHON3_SUBDIRS = python
endif
-libjavadesc_la_SOURCES = \
- context.h context.c \
- core.h core.c \
- demangler.h demangler.c \
- field.h field.c \
+libjavadesc_la_SOURCES = \
+ context.h context.c \
+ core.h core.c \
+ demangler.h demangler.c \
+ field.h field.c \
method.h method.c
-libjavadesc_la_LIBADD = \
+libjavadesc_la_LIBADD = \
$(PYTHON3_LIBADD)
+libjavadesc_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libjavadesc_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -56,8 +58,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libjavadesc_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/javadesc/core.c b/plugins/javadesc/core.c
index e7b4773..420d9f5 100644
--- a/plugins/javadesc/core.c
+++ b/plugins/javadesc/core.c
@@ -24,18 +24,17 @@
#include "core.h"
-#include <config.h>
#include <core/demanglers.h>
#include <plugins/self.h>
#include "demangler.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -67,7 +66,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
result = register_demangler_type(G_TYPE_JAVA_DEMANGLER);
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
if (result)
result = add_mangling_javadesc_module_to_python_module();
#endif
diff --git a/plugins/javadesc/python/Makefile.am b/plugins/javadesc/python/Makefile.am
index aa7deeb..2b1a8eb 100644
--- a/plugins/javadesc/python/Makefile.am
+++ b/plugins/javadesc/python/Makefile.am
@@ -1,19 +1,14 @@
noinst_LTLIBRARIES = libjavadescpython.la
-libjavadescpython_la_SOURCES = \
- demangler.h demangler.c \
+libjavadescpython_la_SOURCES = \
+ demangler.h demangler.c \
module.h module.c
-libjavadescpython_la_LDFLAGS =
+libjavadescpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libjavadescpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/javadesc/python/demangler.c b/plugins/javadesc/python/demangler.c
index 3a972cee..62b24c7 100644
--- a/plugins/javadesc/python/demangler.c
+++ b/plugins/javadesc/python/demangler.c
@@ -142,15 +142,17 @@ PyTypeObject *get_python_java_demangler_type(void)
bool register_python_java_demangler(PyObject *module)
{
- PyTypeObject *py_java_demangler_type; /* Type Python 'JavaDemangler' */
+ PyTypeObject *type; /* Type Python 'JavaDemangler' */
PyObject *dict; /* Dictionnaire du module */
- py_java_demangler_type = get_python_java_demangler_type();
+ type = get_python_java_demangler_type();
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_JAVA_DEMANGLER,
- py_java_demangler_type, get_python_compiler_demangler_type()))
+ if (!ensure_python_compiler_demangler_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_JAVA_DEMANGLER, type))
return false;
return true;
diff --git a/plugins/kaitai/Makefile.am b/plugins/kaitai/Makefile.am
new file mode 100644
index 0000000..9a4e112
--- /dev/null
+++ b/plugins/kaitai/Makefile.am
@@ -0,0 +1,93 @@
+
+BUILT_SOURCES = grammar.h
+
+
+# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS
+# afin de conserver des noms de fichiers simples, ie sans le nom de la
+# bibliothèque de sortie en préfixe.
+
+AM_YFLAGS = -v -d -p kaitai_ -Wno-yacc -Wcounterexamples
+
+AM_LFLAGS = -P kaitai_ -o lex.yy.c --header-file=tokens.h \
+ -Dyyget_lineno=kaitai_get_lineno \
+ -Dyy_scan_bytes=kaitai__scan_bytes \
+ -Dyy_delete_buffer=kaitai__delete_buffer
+
+lib_LTLIBRARIES = libkaitai.la
+
+libdir = $(pluginslibdir)
+
+
+if BUILD_PYTHON_PACKAGE
+
+RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs'
+
+endif
+
+if BUILD_PYTHON3_BINDINGS
+
+PYTHON3_LIBADD = python/libkaitaipython.la
+
+if BUILD_DISCARD_LOCAL
+
+if BUILD_PYTHON_PACKAGE
+PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN/..'
+else
+PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN'
+endif
+
+else
+
+PYTHON3_RUN_PATH = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs
+
+endif
+
+PYTHON3_LDFLAGS = $(PYTHON3_RUN_PATH) -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so
+
+PYTHON3_SUBDIRS = python
+
+endif
+
+
+libkaitai_la_SOURCES = \
+ array-int.h \
+ array.h array.c \
+ core.h core.c \
+ expression.h \
+ import.h import.c \
+ parser-int.h \
+ parser.h parser.c \
+ record-int.h \
+ record.h record.c \
+ scope.h scope.c \
+ stream-int.h \
+ stream.h stream.c \
+ tokens.l \
+ grammar.y
+
+libkaitai_la_LIBADD = \
+ parsers/libkaitaiparsers.la \
+ records/libkaitairecords.la \
+ rost/libkaitairost.la \
+ $(PYTHON3_LIBADD)
+
+libkaitai_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+libkaitai_la_LDFLAGS = \
+ -L$(top_srcdir)/src/.libs -lchrysacore \
+ $(PYTHON3_LDFLAGS)
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitai_la_SOURCES:%c=)
+
+
+# Automake fait les choses à moitié
+CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
+
+# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions !
+EXTRA_DIST = tokens.h
+
+
+SUBDIRS = parsers records rost $(PYTHON3_SUBDIRS)
diff --git a/plugins/kaitai/array-int.h b/plugins/kaitai/array-int.h
new file mode 100644
index 0000000..123b16d
--- /dev/null
+++ b/plugins/kaitai/array-int.h
@@ -0,0 +1,51 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * array-int.h - prototypes pour les données associées à un flux de données Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_ARRAY_INT_H
+#define PLUGINS_KAITAI_ARRAY_INT_H
+
+
+#include "array.h"
+
+
+
+/* Tableau rassemblant des éléments divers (instance) */
+struct _GKaitaiArray
+{
+ GObject parent; /* A laisser en premier */
+
+ resolved_value_t *items; /* Eléments du tableau */
+ size_t count; /* Quantité de ces éléments */
+
+};
+
+/* Tableau rassemblant des éléments divers (classe) */
+struct _GKaitaiArrayClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* PLUGINS_KAITAI_ARRAY_INT_H */
diff --git a/plugins/kaitai/array.c b/plugins/kaitai/array.c
new file mode 100644
index 0000000..86f0856
--- /dev/null
+++ b/plugins/kaitai/array.c
@@ -0,0 +1,376 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * array.c - données associées à un flux de données Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "array.h"
+
+
+#include <assert.h>
+#include <limits.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "array-int.h"
+#include "expression.h"
+
+
+
+/* Initialise la classe des flux de données pour Kaitai. */
+static void g_kaitai_array_class_init(GKaitaiArrayClass *);
+
+/* Initialise un flux de données accessibles à Kaitai. */
+static void g_kaitai_array_init(GKaitaiArray *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_array_dispose(GKaitaiArray *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_array_finalize(GKaitaiArray *);
+
+/* Détermine la taille de la séquence d'octets du tableau. */
+static bool g_kaitai_array_compute_bytes_length(const GKaitaiArray *, size_t *);
+
+
+
+/* Indique le type défini pour un tableau rassemblant des éléments Kaitai. */
+G_DEFINE_TYPE(GKaitaiArray, g_kaitai_array, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des tableau d'éléments Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_array_class_init(GKaitaiArrayClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_array_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_array_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : array = instance à initialiser. *
+* *
+* Description : Initialise un tableau rassemblant des éléments divers. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_array_init(GKaitaiArray *array)
+{
+ array->items = NULL;
+ array->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : array = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_array_dispose(GKaitaiArray *array)
+{
+ G_OBJECT_CLASS(g_kaitai_array_parent_class)->dispose(G_OBJECT(array));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : array = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_array_finalize(GKaitaiArray *array)
+{
+ G_OBJECT_CLASS(g_kaitai_array_parent_class)->finalize(G_OBJECT(array));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une amorce de tableau pour rassembler des éléments.*
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiArray *g_kaitai_array_new(void)
+{
+ GKaitaiArray *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_ARRAY, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : array = tableau Kaitai à consulter. *
+* *
+* Description : Dénombre le nombre d'éléments enregistrés. *
+* *
+* Retour : Taille du tableau manipulé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_kaitai_array_count_items(const GKaitaiArray *array)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = array->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : array = tableau Kaitai à compléter. *
+* item = élément Kaitai à archiver. *
+* *
+* Description : Intègre un élément supplémentaire dans un tableau Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_kaitai_array_append_item(GKaitaiArray *array, const resolved_value_t *item)
+{
+ array->items = realloc(array->items, ++array->count * sizeof(resolved_value_t));
+
+ COPY_RESOLVED_VALUE(array->items[array->count - 1], *item);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de correspondances attribut/binaire. *
+* index = indice de la correspondance visée. *
+* item = élément archivé dans le talbeau à fournir. [OUT] *
+* *
+* Description : Fournit un élément ciblé dans un tableau Kaitai. *
+* *
+* Retour : Validité de l'emplacmeent pour élément à renseigner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_array_get_item(const GKaitaiArray *array, size_t index, resolved_value_t *item)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (index < array->count);
+
+ if (result)
+ COPY_RESOLVED_VALUE(*item, array->items[index]);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : array = tableau Kaitai à consulter. *
+* length = nombre d'octets représentés. [OUT] *
+* *
+* Description : Détermine la taille de la séquence d'octets du tableau. *
+* *
+* Retour : true si le tableau peut être converti en octets, ou false. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_array_compute_bytes_length(const GKaitaiArray *array, size_t *length)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ const resolved_value_t *item; /* Elément en cours d'analyse */
+ size_t extra; /* Taille d'un sous-tableau */
+
+ result = true;
+
+ *length = 0;
+
+ for (i = 0; i < array->count && result; i++)
+ {
+ item = &array->items[i];
+
+ switch (item->type)
+ {
+ case GVT_UNSIGNED_INTEGER:
+ result = (item->unsigned_integer <= UCHAR_MAX);
+ if (result) (*length)++;
+ break;
+
+ case GVT_SIGNED_INTEGER:
+ result = (0 <= item->signed_integer && item->signed_integer <= SCHAR_MAX);
+ if (result) (*length)++;
+ break;
+
+ case GVT_BYTES:
+ *length += item->bytes.len;
+ break;
+
+ case GVT_ARRAY:
+ result = g_kaitai_array_compute_bytes_length(item->array, &extra);
+ if (result) *length += extra;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : array = tableau Kaitai à consulter. *
+* bytes = conversion en série d'octets équivalent. [OUT] *
+* *
+* Description : Convertit un tableau d'éléments en séquence d'octets. *
+* *
+* Retour : true si une série d'octets a pu être constituée, ou false. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_array_convert_to_bytes(const GKaitaiArray *array, sized_string_t *bytes)
+{
+ bool result; /* Bilan à retourner */
+ size_t length; /* Taille de la chaîne finale */
+ size_t i; /* Boucle de parcours */
+ const resolved_value_t *item; /* Elément en cours d'analyse */
+ char *iter; /* Tête d'écriture */
+ sized_string_t extra; /* Données d'un sous-tableau */
+
+ /* Détermination de la taille finale */
+
+ result = g_kaitai_array_compute_bytes_length(array, &length);
+
+ /* Construction d'une chaîne d'octets si possible */
+
+ if (result)
+ {
+ bytes->data = malloc(length * sizeof(char));
+ bytes->len = length;
+
+ iter = bytes->data;
+
+ for (i = 0; i < array->count; i++)
+ {
+ item = &array->items[i];
+
+ switch (item->type)
+ {
+ case GVT_UNSIGNED_INTEGER:
+ *iter = item->unsigned_integer;
+ iter++;
+ break;
+
+ case GVT_SIGNED_INTEGER:
+ *iter = item->signed_integer;
+ iter++;
+ break;
+
+ case GVT_BYTES:
+ memcpy(iter, item->bytes.data, item->bytes.len);
+ iter += item->bytes.len;
+ break;
+
+ case GVT_ARRAY:
+ result = g_kaitai_array_convert_to_bytes(item->array, &extra);
+ assert(result);
+
+ memcpy(iter, extra.data, extra.len);
+ iter += extra.len;
+
+ exit_szstr(&extra);
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/array.h b/plugins/kaitai/array.h
new file mode 100644
index 0000000..e93c7c0
--- /dev/null
+++ b/plugins/kaitai/array.h
@@ -0,0 +1,76 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * array.h - prototypes pour les données associées à un flux de données Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_ARRAY_H
+#define PLUGINS_KAITAI_ARRAY_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <common/szstr.h>
+
+
+
+/* expression.h : informations transportées par une expression */
+typedef struct _resolved_value_t resolved_value_t;
+
+
+
+#define G_TYPE_KAITAI_ARRAY g_kaitai_array_get_type()
+#define G_KAITAI_ARRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ARRAY, GKaitaiArray))
+#define G_IS_KAITAI_ARRAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ARRAY))
+#define G_KAITAI_ARRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ARRAY, GKaitaiArrayClass))
+#define G_IS_KAITAI_ARRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ARRAY))
+#define G_KAITAI_ARRAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ARRAY, GKaitaiArrayClass))
+
+
+/* Tableau rassemblant des éléments divers (instance) */
+typedef struct _GKaitaiArray GKaitaiArray;
+
+/* Tableau rassemblant des éléments divers (classe) */
+typedef struct _GKaitaiArrayClass GKaitaiArrayClass;
+
+
+/* Indique le type défini pour un tableau rassemblant des éléments Kaitai. */
+GType g_kaitai_array_get_type(void);
+
+/* Constitue une amorce de tableau pour rassembler des éléments. */
+GKaitaiArray *g_kaitai_array_new(void);
+
+/* Dénombre le nombre d'éléments enregistrés. */
+size_t g_kaitai_array_count_items(const GKaitaiArray *);
+
+/* Intègre un élément supplémentaire dans un tableau Kaitai. */
+void g_kaitai_array_append_item(GKaitaiArray *, const resolved_value_t *);
+
+/* Fournit un élément ciblé dans un tableau Kaitai. */
+bool g_kaitai_array_get_item(const GKaitaiArray *, size_t, resolved_value_t *);
+
+/* Convertit un tableau d'éléments en séquence d'octets. */
+bool g_kaitai_array_convert_to_bytes(const GKaitaiArray *, sized_string_t *);
+
+
+
+#endif /* PLUGINS_KAITAI_ARRAY_H */
diff --git a/plugins/kaitai/core.c b/plugins/kaitai/core.c
new file mode 100644
index 0000000..c41d96d
--- /dev/null
+++ b/plugins/kaitai/core.c
@@ -0,0 +1,81 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - prise en charge des descriptions de binaires au format Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <plugins/self.h>
+
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+# include "python/module.h"
+#endif
+#include "rost/core.h"
+
+
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+# define PG_REQ RL("PyChrysalide")
+#else
+# define PG_REQ NO_REQ
+#endif
+
+
+
+DEFINE_CHRYSALIDE_PLUGIN("Kaitai", "Content parser using Kaitai structure definitions",
+ PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/kaitai"),
+ PG_REQ, AL(PGA_PLUGIN_INIT));
+
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Prend acte du chargement du greffon. *
+* *
+* Retour : Bilan du chargement mené. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
+{
+ bool result; /* Bilan à retourner */
+
+ result = add_kaitai_support_to_rost();
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+
+ if (result)
+ result = add_kaitai_module_to_python_module();
+
+ if (result)
+ result = populate_kaitai_module();
+
+#endif
+
+ return result;
+
+}
diff --git a/plugins/kaitai/core.h b/plugins/kaitai/core.h
new file mode 100644
index 0000000..61241f4
--- /dev/null
+++ b/plugins/kaitai/core.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour la prise en charge des descriptions de binaires au format Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_CORE_H
+#define _PLUGINS_KAITAI_CORE_H
+
+
+#include <plugins/plugin.h>
+#include <plugins/plugin-int.h>
+
+
+
+/* Prend acte du chargement du greffon. */
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+
+
+
+#endif /* _PLUGINS_KAITAI_CORE_H */
diff --git a/plugins/kaitai/expression.h b/plugins/kaitai/expression.h
new file mode 100644
index 0000000..06cf9cf
--- /dev/null
+++ b/plugins/kaitai/expression.h
@@ -0,0 +1,134 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * expression.h - déclarations de prototypes utiles aux résolutions d'expressions
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_EXPRESSION_H
+#define _PLUGINS_KAITAI_EXPRESSION_H
+
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+
+#include <common/szstr.h>
+
+
+#include "array.h"
+#include "scope.h"
+#include "stream.h"
+
+
+
+/* Type de valeur résolue */
+typedef enum _GrammarValueType
+{
+ GVT_ERROR, /* Erreur remontée */
+ GVT_UNSIGNED_INTEGER, /* Valeur entière #1 */
+ GVT_SIGNED_INTEGER, /* Valeur entière #2 */
+ GVT_FLOAT, /* Valeur fractionnée */
+ GVT_BOOLEAN, /* Valeur booléenne */
+ GVT_BYTES, /* Série d'octets dynamique */
+ GVT_ARRAY, /* Tableau d'éléments divers */
+ GVT_RECORD, /* Correspondance en place */
+ GVT_STREAM, /* Flux de données */
+
+} GrammarValueType;
+
+/* Informations transportées par une expression */
+typedef struct _resolved_value_t
+{
+ GrammarValueType type; /* Type de valeur portée */
+
+ union
+ {
+ unsigned long long unsigned_integer;/* Valeur entière #1 */
+ signed long long signed_integer; /* Valeur entière #2 */
+ double floating_number; /* Valeur à virgule flottante */
+ bool status; /* Valeur à deux états */
+ sized_string_t bytes; /* Série d'octets */
+
+ GKaitaiArray *array; /* Tableau d'éléments divers */
+ GMatchRecord *record; /* Correspondance désignée */
+ GKaitaiStream *stream; /* Flux de données pour Kaitai */
+
+ };
+
+} resolved_value_t;
+
+
+#define COPY_RESOLVED_VALUE(dst, src) \
+ do \
+ { \
+ (dst) = (src); \
+ switch ((dst).type) \
+ { \
+ case GVT_ARRAY: \
+ g_object_ref(G_OBJECT((dst).array)); \
+ break; \
+ case GVT_RECORD: \
+ g_object_ref(G_OBJECT((dst).record)); \
+ break; \
+ case GVT_STREAM: \
+ g_object_ref(G_OBJECT((dst).stream)); \
+ break; \
+ default: \
+ break; \
+ } \
+ } \
+ while (0)
+
+
+#define EXIT_RESOLVED_VALUE(v) \
+ switch ((v).type) \
+ { \
+ case GVT_ARRAY: \
+ g_clear_object(&(v).array); \
+ break; \
+ case GVT_RECORD: \
+ g_clear_object(&(v).record); \
+ break; \
+ case GVT_STREAM: \
+ g_clear_object(&(v).stream); \
+ break; \
+ default: \
+ break; \
+ }
+
+
+/* Interprète une expression en une valeur quelconque. */
+bool resolve_kaitai_expression_as_any(const kaitai_scope_t *, const char *, size_t, resolved_value_t *);
+
+/* Interprète une expression en valeur ciblée entière. */
+bool resolve_kaitai_expression_as_integer(const kaitai_scope_t *, const char *, size_t, resolved_value_t *);
+
+/* Interprète une expression en valeur ciblée booléenne. */
+bool resolve_kaitai_expression_as_boolean(const kaitai_scope_t *, const char *, size_t, resolved_value_t *);
+
+/* Interprète une expression en série d'octets. */
+bool resolve_kaitai_expression_as_bytes(const kaitai_scope_t *, const char *, size_t, resolved_value_t *);
+
+/* Interprète une expression en flux de données pour Kaitai. */
+bool resolve_kaitai_expression_as_stream(const kaitai_scope_t *, const char *, size_t, GKaitaiStream **);
+
+
+
+#endif /* _PLUGINS_KAITAI_EXPRESSION_H */
diff --git a/plugins/kaitai/grammar.y b/plugins/kaitai/grammar.y
new file mode 100644
index 0000000..9745dc8
--- /dev/null
+++ b/plugins/kaitai/grammar.y
@@ -0,0 +1,1919 @@
+
+%{
+
+#include "expression.h"
+#include "tokens.h"
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int yyerror(yyscan_t, const kaitai_scope_t *, resolved_value_t *, const char *);
+
+/* Interprète une expression en une valeur quelconque. */
+static bool _resolve_kaitai_expression_as_any(const kaitai_scope_t *, const char *, size_t, resolved_value_t *);
+
+/* Traduit les éventuels champs impliqués dans une expression. */
+static bool reduce_resolved_kaitai_expression(resolved_value_t *);
+
+
+%}
+
+
+%code requires {
+
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void *yyscan_t;
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "expression.h"
+#include "record.h"
+#include "records/bits.h"
+#include "records/delayed.h"
+#include "records/item.h"
+#include "records/list.h"
+
+}
+
+%union {
+
+ resolved_value_t value; /* Valeur portée */
+
+ unsigned long long unsigned_integer; /* Valeur entière #1 */
+ signed long long signed_integer; /* Valeur entière #2 */
+ double floating_number; /* Valeur à virgule flottante */
+ sized_string_t sized_cstring; /* Chaîne de caractères */
+ char byte; /* Octet unique */
+
+}
+
+
+/**
+ * Cf.
+ * http://stackoverflow.com/questions/34418381/how-to-reference-lex-or-parse-parameters-in-flex-rules/34420950
+ */
+
+%define api.pure full
+
+%parse-param { yyscan_t yyscanner } { const kaitai_scope_t *locals } { resolved_value_t *resolved }
+%lex-param { yyscan_t yyscanner }
+
+%code provides {
+
+#define YY_DECL \
+ int kaitai_lex(YYSTYPE *yylval_param, yyscan_t yyscanner)
+
+YY_DECL;
+
+
+
+#define SET_ERR(out) \
+ out.type = GVT_ERROR
+
+#define EXIT_WITH_ERR(out, lbl) \
+ do \
+ { \
+ SET_ERR(out); \
+ goto exit_ ## lbl; \
+ } \
+ while (0)
+
+#define CHECK_TYPE(arg, tp, out, lbl) \
+ if (arg.type != tp) EXIT_WITH_ERR(out, lbl)
+
+#define CHECK_TYPES(arg, tp1, tp2, out, lbl) \
+ if (arg.type != tp1 && arg.type != tp2) EXIT_WITH_ERR(out, lbl)
+
+#define REDUCE_EXPR(arg, out, lbl) \
+ if (!reduce_resolved_kaitai_expression(&arg)) \
+ EXIT_WITH_ERR(out, lbl)
+
+#define REDUCE_NUMERIC_EXPR(arg, out, lbl) \
+ if (!reduce_resolved_kaitai_expression(&arg)) \
+ EXIT_WITH_ERR(out, lbl); \
+ if (arg.type == GVT_SIGNED_INTEGER && arg.signed_integer >= 0) \
+ { \
+ arg.unsigned_integer = arg.signed_integer; \
+ arg.type = GVT_UNSIGNED_INTEGER; \
+ }
+
+
+#define ARITHMETIC_ADD_CODE(op1, op2, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.unsigned_integer + op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ if (op1.unsigned_integer < -op2.signed_integer) \
+ { \
+ out.signed_integer = op1.unsigned_integer + op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.unsigned_integer + op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.unsigned_integer + op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ if (-op1.signed_integer > op2.unsigned_integer) \
+ { \
+ out.signed_integer = op1.signed_integer + op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.signed_integer + op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.signed_integer + op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.signed_integer + op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_FLOAT: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number + op2.unsigned_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number + op2.signed_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.floating_number + op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define ARITHMETIC_SUB_CODE(op1, op2, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ if (op1.unsigned_integer < op2.unsigned_integer) \
+ { \
+ out.signed_integer = op1.unsigned_integer - op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.unsigned_integer - op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.unsigned_integer - op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.unsigned_integer - op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.signed_integer - op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ if (op1.signed_integer < op2.signed_integer) \
+ { \
+ out.signed_integer = op1.signed_integer - op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.signed_integer - op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.signed_integer - op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_FLOAT: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number - op2.unsigned_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number - op2.signed_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.floating_number - op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define ARITHMETIC_GENOP_CODE(op1, op2, _meth_, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.unsigned_integer _meth_ op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.unsigned_integer _meth_ op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.unsigned_integer _meth_ op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.signed_integer _meth_ op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.signed_integer _meth_ op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.signed_integer _meth_ op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_FLOAT: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.floating_number _meth_ op2.unsigned_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.floating_number _meth_ op2.signed_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.floating_number _meth_ op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+/**
+ * Cf. https://stackoverflow.com/questions/11720656/modulo-operation-with-negative-numbers/52529440#52529440
+ */
+#define EUCLIDEAN_MODULO(a, b, r) \
+ r = a % (signed long long)b; \
+ if (r < 0) \
+ r = (b < 0) ? r - b : r + b; \
+
+
+#define ARITHMETIC_MOD_CODE(op1, op2, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.unsigned_integer, op2.unsigned_integer, out.unsigned_integer); \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.unsigned_integer, op2.signed_integer, out.signed_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.signed_integer, op2.unsigned_integer, out.signed_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.signed_integer, op2.signed_integer, out.signed_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define RELATIONAL_CODE(op1, op2, _meth_, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.status = (op1.unsigned_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.status = (op1.unsigned_integer _meth_ op2.signed_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.status = (op1.signed_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.status = (op1.signed_integer _meth_ op2.signed_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_BYTES: \
+ if (op2.type == GVT_BYTES) \
+ { \
+ int __ret; \
+ __ret = szmemcmp(&op1.bytes, &op2.bytes); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_ARRAY) \
+ { \
+ sized_string_t __abytes_2; \
+ int __ret; \
+ if (!g_kaitai_array_convert_to_bytes(op2.array, &__abytes_2)) \
+ EXIT_WITH_ERR(out, lbl); \
+ __ret = szmemcmp(&op1.bytes, &__abytes_2); \
+ exit_szstr(&__abytes_2); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_ARRAY: \
+ if (op2.type == GVT_BYTES) \
+ { \
+ sized_string_t __abytes_1; \
+ int __ret; \
+ if (!g_kaitai_array_convert_to_bytes(op1.array, &__abytes_1)) \
+ EXIT_WITH_ERR(out, lbl); \
+ __ret = szmemcmp(&__abytes_1, &op2.bytes); \
+ exit_szstr(&__abytes_1); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_ARRAY) \
+ { \
+ sized_string_t __abytes_1; \
+ sized_string_t __abytes_2; \
+ int __ret; \
+ if (!g_kaitai_array_convert_to_bytes(op1.array, &__abytes_1)) \
+ EXIT_WITH_ERR(out, lbl); \
+ if (!g_kaitai_array_convert_to_bytes(op2.array, &__abytes_2)) \
+ { \
+ exit_szstr(&__abytes_1); \
+ EXIT_WITH_ERR(out, lbl); \
+ } \
+ __ret = szmemcmp(&__abytes_1, &__abytes_2); \
+ exit_szstr(&__abytes_1); \
+ exit_szstr(&__abytes_2); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_STREAM: \
+ if (op2.type == GVT_STREAM) \
+ { \
+ GBinContent *__cnt_1; \
+ GBinContent *__cnt_2; \
+ __cnt_1 = g_kaitai_stream_get_content(op1.stream); \
+ __cnt_2 = g_kaitai_stream_get_content(op2.stream); \
+ out.status = (__cnt_1 _meth_ __cnt_2); \
+ out.type = GVT_BOOLEAN; \
+ g_object_unref(G_OBJECT(__cnt_1)); \
+ g_object_unref(G_OBJECT(__cnt_2)); \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define BITWISE_CODE(op1, op2, _meth_, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = (op1.unsigned_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.signed_integer = (op1.signed_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+
+
+}
+
+
+%token <unsigned_integer> UNSIGNED_INTEGER
+%token <signed_integer> SIGNED_INTEGER
+%token <floating_number> FLOAT
+
+%token <sized_cstring> IDENTIFIER
+%token <sized_cstring> RAW_BYTES
+%token <byte> RAW_BYTE
+%token <sized_cstring> RAW_BYTES_WITH_ENDING_DOT
+%token <sized_cstring> PLAIN_BYTES
+
+%token <sized_cstring> ENCODING_NAME
+
+
+%token PLUS "+"
+%token MINUS "-"
+%token MUL "*"
+%token DIV "/"
+%token MOD "%"
+
+%token LT "<"
+%token LE "<="
+%token EQ "=="
+%token NE "!="
+%token GT ">"
+%token GE ">="
+
+%token SHIFT_LEFT "<<"
+%token SHIFT_RIGHT ">>"
+%token BIT_AND "&"
+%token BIT_OR "|"
+%token BIT_XOR "^"
+
+%token NOT "not"
+%token AND "and"
+%token OR "or"
+
+%token PAREN_O "("
+%token PAREN_C ")"
+%token HOOK_O "["
+%token HOOK_C "]"
+%token COMMA ","
+%token DOT "."
+
+%token QMARK "?"
+%token COLON ":"
+%token DOUBLE_COLON "::"
+
+%token METH_SIZE ".size"
+%token METH_LENGTH ".length"
+%token METH_REVERSE ".reverse"
+%token METH_SUBSTRING ".substring"
+%token METH_TO_I ".to_i"
+%token METH_TO_I_RAD ".to_i("
+%token METH_TO_S ".to_s"
+%token METH_TO_S_ENC ".to_s("
+
+%token ROOT "_root"
+%token PARENT "_parent"
+%token LAST "_"
+%token IO "_io"
+%token METH_IO "._io"
+%token IO_EOF ".eof"
+
+%token TRUE_CONST "true"
+%token FALSE_CONST "false"
+
+
+ //%type <value> operand
+%type <value> any_expr
+ //%type <value> arithm_expr
+ //%type <value> arithm_op
+
+%type <value> boolean
+
+
+
+%type <value> arithmetic_expr
+%type <value> relational_expr
+%type <value> logical_expr
+%type <value> bitwise_expr
+%type <value> ternary_expr
+
+%type <value> convert_2_bytes
+%type <value> convert_2_integer
+
+
+%type <value> integer
+
+%type <value> float
+
+%type <value> bytes
+
+%type <value> bytes_concat
+%type <value> raw_bytes
+
+
+%type <value> array
+%type <value> array_items
+
+
+%type <value> field
+%type <value> enumeration
+%type <value> stream
+%type <value> stream_meths
+
+
+
+%destructor { printf("----------------------freeing %p...\n", &$$), fflush(NULL); } <*>
+
+
+ //%type <integer> INTEGER
+ //
+
+ //%type <integer> arithm_expr
+ //%type <integer> arithm_op
+
+ //%type <boolean> bool_expr
+ //%type <boolean> relational_op logical_op ternary_op
+
+
+ //%type <integer> constant
+
+
+
+
+
+/**
+ * Cf. https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
+ */
+
+
+
+
+
+%left "?" ":"
+
+%left OR
+%left "and"
+
+/* 13 */
+%left "|"
+
+/* 12 */
+%left "^"
+
+/* 11 */
+%left "&"
+
+%left LT LE EQ NE GT GE
+
+/* 7 */
+%left "<<" ">>"
+
+
+%right NOT
+
+%left PLUS MINUS
+%left "*"
+%left DIV MOD
+
+
+%left "["
+
+
+
+
+%left ".size"
+%left ".length"
+%left ".reverse"
+%left ".substring"
+%left ".to_i"
+%left ".to_i("
+%left ".to_s"
+%left ".to_s("
+
+%left "._io"
+
+%left "."
+
+/* 1 */
+%right "::"
+
+
+%%
+
+ expressions : any_expr { *resolved = $1; }
+ ;
+
+ any_expr : boolean { $$ = $1; }
+ | bytes { $$ = $1; }
+ | integer { $$ = $1; }
+ | float { $$ = $1; }
+ | array { $$ = $1; }
+ | field { $$ = $1; }
+ | enumeration { $$ = $1; }
+ | stream { $$ = $1; }
+ | stream_meths { $$ = $1; }
+ | arithmetic_expr { $$ = $1; }
+ | relational_expr { $$ = $1; }
+ | logical_expr { $$ = $1; }
+ | bitwise_expr { $$ = $1; }
+ | ternary_expr { $$ = $1; }
+ | convert_2_bytes { $$ = $1; }
+ | convert_2_integer { $$ = $1; }
+ | "(" any_expr ")" { $$ = $2; }
+ ;
+
+
+/* Expressions impliquants formules et opérandes */
+
+ arithmetic_expr : any_expr "+" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_plus);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_plus);
+
+ if ($1.type == GVT_BYTES && $3.type == GVT_BYTES)
+ {
+ $$.bytes.len = $1.bytes.len + $3.bytes.len;
+ $$.bytes.data = malloc($$.bytes.len);
+
+ memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len);
+ memcpy($$.bytes.data + $1.bytes.len, $3.bytes.data, $3.bytes.len);
+
+ $$.type = GVT_BYTES;
+
+ }
+
+ else if ($1.type == GVT_BYTES && $3.type == GVT_ARRAY)
+ {
+ sized_string_t __abytes_2;
+
+ if (!g_kaitai_array_convert_to_bytes($3.array, &__abytes_2))
+ EXIT_WITH_ERR($$, arithmetic_expr_plus);
+
+ $$.bytes.len = $1.bytes.len + __abytes_2.len;
+ $$.bytes.data = malloc($$.bytes.len);
+
+ memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len);
+ memcpy($$.bytes.data + $1.bytes.len, __abytes_2.data, __abytes_2.len);
+
+ $$.type = GVT_BYTES;
+
+ exit_szstr(&__abytes_2);
+
+ }
+
+ else
+ {
+ ARITHMETIC_ADD_CODE($1, $3, $$, arithmetic_expr_plus);
+ }
+
+ exit_arithmetic_expr_plus:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "-" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_minus);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_minus);
+ ARITHMETIC_SUB_CODE($1, $3, $$, arithmetic_expr_minus);
+ exit_arithmetic_expr_minus:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "*" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_mul);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_mul);
+ ARITHMETIC_GENOP_CODE($1, $3, *, $$, arithmetic_expr_mul);
+ exit_arithmetic_expr_mul:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "/" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_div);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_div);
+ ARITHMETIC_GENOP_CODE($1, $3, /, $$, arithmetic_expr_div);
+ exit_arithmetic_expr_div:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "%" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_mod);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_mod);
+ ARITHMETIC_MOD_CODE($1, $3, $$, arithmetic_expr_mod);
+ exit_arithmetic_expr_mod:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ relational_expr : any_expr "<" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_lt);
+ REDUCE_EXPR($3, $$, relational_expr_lt);
+ RELATIONAL_CODE($1, $3, <, $$, relational_expr_lt);
+ exit_relational_expr_lt:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "<=" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_le);
+ REDUCE_EXPR($3, $$, relational_expr_le);
+ RELATIONAL_CODE($1, $3, <=, $$, relational_expr_le);
+ exit_relational_expr_le:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "==" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_eq);
+ REDUCE_EXPR($3, $$, relational_expr_eq);
+ RELATIONAL_CODE($1, $3, ==, $$, relational_expr_eq);
+ exit_relational_expr_eq:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "!=" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_ne);
+ REDUCE_EXPR($3, $$, relational_expr_ne);
+ RELATIONAL_CODE($1, $3, !=, $$, relational_expr_ne);
+ exit_relational_expr_ne:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr ">" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_gt);
+ REDUCE_EXPR($3, $$, relational_expr_gt);
+ RELATIONAL_CODE($1, $3, >, $$, relational_expr_gt);
+ exit_relational_expr_gt:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr ">=" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_ge);
+ REDUCE_EXPR($3, $$, relational_expr_ge);
+ RELATIONAL_CODE($1, $3, >=, $$, relational_expr_ge);
+ exit_relational_expr_ge:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ bitwise_expr : any_expr "<<" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_shift_left);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_shift_left);
+ BITWISE_CODE($1, $3, <<, $$, bitwise_expr_shift_left);
+ exit_bitwise_expr_shift_left:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr ">>" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_shift_right);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_shift_right);
+ BITWISE_CODE($1, $3, >>, $$, bitwise_expr_shift_right);
+ exit_bitwise_expr_shift_right:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "&" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_and);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_and);
+ BITWISE_CODE($1, $3, &, $$, bitwise_expr_and);
+ exit_bitwise_expr_and:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "|" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_or);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_or);
+ BITWISE_CODE($1, $3, |, $$, bitwise_expr_or);
+ exit_bitwise_expr_or:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "^" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_xor);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_xor);
+ BITWISE_CODE($1, $3, ^, $$, bitwise_expr_xor);
+ exit_bitwise_expr_xor:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ logical_expr : "not" any_expr
+ {
+ REDUCE_EXPR($2, $$, logical_expr_not);
+ CHECK_TYPE($2, GVT_BOOLEAN, $$, logical_expr_not);
+ $$.status = !$2.status;
+ $$.type = GVT_BOOLEAN;
+ exit_logical_expr_not:
+ EXIT_RESOLVED_VALUE($2);
+ }
+ | any_expr "and" any_expr
+ {
+ REDUCE_EXPR($1, $$, logical_expr_and);
+ CHECK_TYPE($1, GVT_BOOLEAN, $$, logical_expr_and);
+ REDUCE_EXPR($3, $$, logical_expr_and);
+ CHECK_TYPE($3, GVT_BOOLEAN, $$, logical_expr_and);
+ $$.status = $1.status && $3.status;
+ $$.type = GVT_BOOLEAN;
+ exit_logical_expr_and:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "or" any_expr
+ {
+ REDUCE_EXPR($1, $$, logical_expr_or);
+ CHECK_TYPE($1, GVT_BOOLEAN, $$, logical_expr_or);
+ REDUCE_EXPR($3, $$, logical_expr_or);
+ CHECK_TYPE($3, GVT_BOOLEAN, $$, logical_expr_or);
+ $$.status = $1.status || $3.status;
+ $$.type = GVT_BOOLEAN;
+ exit_logical_expr_or:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ ternary_expr : any_expr "?" any_expr ":" any_expr
+ {
+ REDUCE_EXPR($1, $$, ternary_expr);
+ CHECK_TYPE($1, GVT_BOOLEAN, $$, ternary_expr);
+ if ($1.status)
+ COPY_RESOLVED_VALUE($$, $3);
+ else
+ COPY_RESOLVED_VALUE($$, $5);
+ exit_ternary_expr:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ EXIT_RESOLVED_VALUE($5);
+ }
+ ;
+
+
+/* Conversions et méthodes particulières de types */
+
+ convert_2_bytes : any_expr ".to_s"
+ {
+ int __ret;
+
+ if ($1.type == GVT_UNSIGNED_INTEGER)
+ {
+ __ret = asprintf(&$$.bytes.data, "%llu", $1.unsigned_integer);
+ if (__ret == -1) EXIT_WITH_ERR($$, convert_2_bytes_to_s);
+
+ $$.bytes.len = __ret;
+ $$.type = GVT_BYTES;
+
+ }
+ else if ($1.type == GVT_SIGNED_INTEGER)
+ {
+ __ret = asprintf(&$$.bytes.data, "%lld", $1.signed_integer);
+ if (__ret == -1) EXIT_WITH_ERR($$, convert_2_bytes_to_s);
+
+ $$.bytes.len = __ret;
+ $$.type = GVT_BYTES;
+
+ }
+ else
+ EXIT_WITH_ERR($$, convert_2_bytes_to_s);
+
+ exit_convert_2_bytes_to_s:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".to_s(" ENCODING_NAME ")"
+ {
+ /**
+ * Cf. https://fossies.org/linux/libiconv/man/iconv_open.3.html
+ */
+
+ char *__fromcode;
+ gsize __bytes_read;
+ gsize __bytes_written;
+
+ if ($1.type != GVT_BYTES)
+ EXIT_WITH_ERR($$, convert_2_bytes_to_s_encoding);
+
+ __fromcode = strndup($3.data, $3.len);
+
+ $$.bytes.data = g_convert($1.bytes.data, $1.bytes.len,
+ __fromcode, "", &__bytes_read, &__bytes_written, NULL);
+
+ free(__fromcode);
+
+ if (__bytes_read != $1.bytes.len)
+ EXIT_WITH_ERR($$, convert_2_bytes_to_s_encoding);
+
+ $$.bytes.len = __bytes_written;
+ $$.type = GVT_BYTES;
+
+ exit_convert_2_bytes_to_s_encoding:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ ;
+
+
+ convert_2_integer : any_expr ".length"
+ {
+ if ($1.type != GVT_BYTES)
+ EXIT_WITH_ERR($$, convert_2_integer_to_s);
+
+ $$.unsigned_integer = $1.bytes.len;
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ exit_convert_2_integer_to_s:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".to_i"
+ {
+ char *__n;
+ char *__end;
+
+ if ($1.type == GVT_FLOAT)
+ {
+ if ($1.floating_number < 0)
+ {
+ $$.signed_integer = $1.floating_number;
+ $$.type = GVT_SIGNED_INTEGER;
+ }
+ else
+ {
+ $$.unsigned_integer = $1.floating_number;
+ $$.type = GVT_UNSIGNED_INTEGER;
+ }
+
+ }
+
+ else if ($1.type == GVT_BOOLEAN)
+ {
+ $$.unsigned_integer = $1.status ? 1 : 0;
+ $$.type = GVT_UNSIGNED_INTEGER;
+ }
+
+ else if ($1.type == GVT_BYTES)
+ {
+ if ($1.bytes.len == 0)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ __n = malloc($1.bytes.len + 1);
+ memcpy(__n, $1.bytes.data, $1.bytes.len);
+ __n[$1.bytes.len] = '\0';
+
+ if ($1.bytes.data[0] == '-')
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ $$.signed_integer = strtoll(__n, &__end, 10);
+ $$.type = GVT_SIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ }
+ else
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ $$.unsigned_integer = strtoull(__n, &__end, 10);
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ }
+
+ free(__n);
+
+ }
+
+ else EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ exit_convert_2_integer_to_i:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".to_i(" any_expr ")"
+ {
+ int __base;
+ char *__n;
+ char *__end;
+
+ if ($1.type == GVT_BYTES)
+ {
+ if ($1.bytes.len == 0)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ if ($3.type == GVT_UNSIGNED_INTEGER)
+ {
+ __base = $3.unsigned_integer;
+ if (__base < 2)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+ }
+ else if ($3.type == GVT_SIGNED_INTEGER)
+ {
+ __base = $3.signed_integer;
+ if (__base < 2)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+ }
+ else EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ __n = malloc($1.bytes.len + 1);
+ memcpy(__n, $1.bytes.data, $1.bytes.len);
+ __n[$1.bytes.len] = '\0';
+
+ if ($1.bytes.data[0] == '-')
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ $$.signed_integer = strtoll(__n, &__end, __base);
+ $$.type = GVT_SIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ }
+ else
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ $$.unsigned_integer = strtoull(__n, &__end, __base);
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ }
+
+ free(__n);
+
+ }
+
+ else EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ exit_convert_2_integer_to_i_base:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".size"
+ {
+ GRecordList *__list;
+
+ if ($1.type != GVT_RECORD) EXIT_WITH_ERR($$, convert_2_integer_size);
+ if (!G_IS_RECORD_LIST($1.record)) EXIT_WITH_ERR($$, convert_2_integer_size);
+
+ __list = G_RECORD_LIST($1.record);
+
+ $$.unsigned_integer = g_record_list_count_records(__list);
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ exit_convert_2_integer_size:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ ;
+
+
+/* Types de base */
+
+ boolean : "true"
+ {
+ $$.status = true;
+ $$.type = GVT_BOOLEAN;
+ }
+ | "false"
+ {
+ $$.status = false;
+ $$.type = GVT_BOOLEAN;
+ }
+ ;
+
+
+ integer : UNSIGNED_INTEGER
+ {
+ $$.unsigned_integer = $1;
+ $$.type = GVT_UNSIGNED_INTEGER;
+ }
+ | SIGNED_INTEGER
+ {
+ $$.signed_integer = $1;
+ $$.type = GVT_SIGNED_INTEGER;
+ }
+ ;
+
+
+ float : FLOAT
+ {
+ $$.floating_number = $1;
+ $$.type = GVT_FLOAT;
+ }
+ ;
+
+
+ bytes : bytes_concat { $$ = $1; }
+ | PLAIN_BYTES
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+ | any_expr ".reverse"
+ {
+ size_t __i;
+
+ CHECK_TYPE($1, GVT_BYTES, $$, bytes_reverse);
+
+ $$.bytes.data = malloc($1.bytes.len);
+ $$.bytes.len = $1.bytes.len;
+
+ for (__i = 0; __i < $1.bytes.len; __i++)
+ $$.bytes.data[__i] = $1.bytes.data[$1.bytes.len - __i - 1];
+
+ $$.type = GVT_BYTES;
+
+ exit_bytes_reverse:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".substring" "(" any_expr "," any_expr ")"
+ {
+ unsigned long long __from;
+ unsigned long long __to;
+
+ REDUCE_NUMERIC_EXPR($4, $$, bytes_reverse);
+ CHECK_TYPES($4, GVT_UNSIGNED_INTEGER, GVT_SIGNED_INTEGER, $$, bytes_substring);
+ REDUCE_NUMERIC_EXPR($6, $$, bytes_reverse);
+ CHECK_TYPES($6, GVT_UNSIGNED_INTEGER, GVT_SIGNED_INTEGER, $$, bytes_substring);
+
+ __from = ($4.type == GVT_UNSIGNED_INTEGER ? $4.unsigned_integer : $4.signed_integer);
+ __to = ($6.type == GVT_UNSIGNED_INTEGER ? $6.unsigned_integer : $6.signed_integer);
+
+ if (__from > __to) EXIT_WITH_ERR($$, bytes_substring);
+ if (__to >= $1.bytes.len) EXIT_WITH_ERR($$, bytes_substring);
+
+ $$.bytes.len = __to - __from + 1;
+ $$.bytes.data = malloc($$.bytes.len);
+
+ memcpy($$.bytes.data, &$1.bytes.data[__from], $$.bytes.len);
+
+ $$.type = GVT_BYTES;
+
+ exit_bytes_substring:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($4);
+ EXIT_RESOLVED_VALUE($6);
+ }
+ ;
+
+ bytes_concat : raw_bytes { $$ = $1; };
+ | bytes_concat raw_bytes
+ {
+ $$.bytes.len = $1.bytes.len + $2.bytes.len;
+ $$.bytes.data = malloc($$.bytes.len);
+ memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len);
+ memcpy($$.bytes.data + $1.bytes.len, $2.bytes.data, $2.bytes.len);
+ $$.type = GVT_BYTES;
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($2);
+ }
+ ;
+
+ raw_bytes : RAW_BYTES
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+ | RAW_BYTE
+ {
+ $$.bytes.len = 1;
+ $$.bytes.data = malloc(1);
+ $$.bytes.data[0] = $1;
+ $$.type = GVT_BYTES;
+ }
+ | RAW_BYTES_WITH_ENDING_DOT
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+ ;
+
+
+/* Tableau d'éléments variés */
+
+ array : "[" "]"
+ {
+ $$.array = g_kaitai_array_new();
+ $$.type = GVT_ARRAY;
+ }
+ | "[" array_items "]"
+ {
+ $$ = $2;
+ }
+ ;
+
+
+ array_items : any_expr
+ {
+ $$.array = g_kaitai_array_new();
+ $$.type = GVT_ARRAY;
+
+ g_kaitai_array_append_item($$.array, &$1);
+
+ EXIT_RESOLVED_VALUE($1);
+
+ }
+ | array_items "," any_expr
+ {
+ $$ = $1;
+ g_kaitai_array_append_item($$.array, &$3);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+/* Accès aux objets Kaitai manipulés */
+
+ field : IDENTIFIER
+ {
+ $$.record = g_match_record_find_by_name(locals->parent,
+ $1.data, $1.len,
+ DIRECT_SEARCH_DEEP_LEVEL);
+
+ if ($$.record != NULL)
+ $$.type = GVT_RECORD;
+
+ /* Si aucune correspondance, le contenu brut est utilisé */
+ else
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+
+ }
+ | "_root"
+ {
+ $$.record = get_root_record(locals);
+ if ($$.record == NULL) SET_ERR($$);
+ else $$.type = GVT_RECORD;
+ }
+ | "_parent"
+ {
+ $$.record = get_parent_record(locals);
+ if ($$.record == NULL) SET_ERR($$);
+ else $$.type = GVT_RECORD;
+ }
+ | "_"
+ {
+ $$.record = get_last_record(locals);
+ if ($$.record == NULL) SET_ERR($$);
+ else $$.type = GVT_RECORD;
+ }
+ | any_expr "." IDENTIFIER
+ {
+ if ($1.type != GVT_RECORD)
+ EXIT_WITH_ERR($$, field_dot);
+
+ $$.record = g_match_record_find_by_name($1.record,
+ $3.data, $3.len,
+ DIRECT_SEARCH_DEEP_LEVEL);
+
+ if ($$.record == NULL)
+ EXIT_WITH_ERR($$, field_dot);
+
+ $$.type = GVT_RECORD;
+
+ exit_field_dot:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr "[" any_expr "]"
+ {
+ size_t __index;
+ GRecordList *__list;
+ size_t __count;
+ GKaitaiArray *__array;
+
+ /* Indice de l'élément auquel accéder */
+
+ REDUCE_NUMERIC_EXPR($3, $$, field_indexed);
+
+ if ($3.type == GVT_UNSIGNED_INTEGER)
+ __index = $3.unsigned_integer;
+ else
+ EXIT_WITH_ERR($$, field_indexed);
+
+ /* Série à consulter */
+
+ REDUCE_EXPR($1, $$, field_indexed);
+
+ if ($1.type == GVT_RECORD && G_IS_RECORD_LIST($1.record))
+ {
+ __list = G_RECORD_LIST($1.record);
+ __count = g_record_list_count_records(__list);
+
+ if (__index >= __count)
+ EXIT_WITH_ERR($$, field_indexed);
+
+ $$.record = g_record_list_get_record(__list, __index);
+
+ if ($$.record == NULL)
+ EXIT_WITH_ERR($$, field_indexed);
+
+ $$.type = GVT_RECORD;
+
+ }
+
+ else if ($1.type == GVT_ARRAY)
+ {
+ __array = G_KAITAI_ARRAY($1.array);
+ __count = g_kaitai_array_count_items(__array);
+
+ if (__index >= __count)
+ EXIT_WITH_ERR($$, field_indexed);
+
+ if (!g_kaitai_array_get_item(__array, __index, &$$))
+ EXIT_WITH_ERR($$, field_indexed);
+
+ }
+
+ else
+ EXIT_WITH_ERR($$, field_indexed);
+
+ exit_field_indexed:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ enumeration : IDENTIFIER "::" IDENTIFIER
+ {
+ if (!g_match_record_resolve_enum(locals->parent, &$1, &$3, &$$))
+ SET_ERR($$);
+ }
+
+
+ stream : "_io"
+ {
+ GBinContent *__content;
+ mrange_t __range;
+ vmpa2t __next;
+
+ if (locals->last == NULL)
+ {
+ __content = g_match_record_get_content(locals->root);
+
+ g_binary_content_compute_start_pos(__content, &__next);
+
+ }
+ else
+ {
+ __content = g_match_record_get_content(locals->last);
+
+ g_match_record_get_range(locals->last, &__range);
+ compute_mrange_end_addr(&__range, &__next);
+
+ }
+
+ $$.stream = g_kaitai_stream_new(__content, &__next);
+ $$.type = GVT_STREAM;
+
+ g_object_unref(G_OBJECT(__content));
+
+ }
+ | any_expr "._io"
+ {
+ GBinContent *__content;
+ mrange_t __range;
+
+ if ($1.type != GVT_RECORD)
+ EXIT_WITH_ERR($$, stream_io);
+
+ __content = g_match_record_get_content($1.record);
+ g_match_record_get_range($1.record, &__range);
+
+ $$.stream = g_kaitai_stream_new(__content, get_mrange_addr(&__range));
+ $$.type = GVT_STREAM;
+
+ g_object_unref(G_OBJECT(__content));
+
+ exit_stream_io:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ ;
+
+ stream_meths : stream ".eof"
+ {
+ $$.status = g_kaitai_stream_has_reached_eof($1.stream);;
+ $$.type = GVT_BOOLEAN;
+
+ EXIT_RESOLVED_VALUE($1);
+
+ }
+ ;
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : yyscanner = décodeur impliqué dans le processus. *
+* locals = variables locales pour les résolutions de types. *
+* out = valeur entière résultante. [OUT] *
+* msg = message d'erreur. *
+* *
+* Description : Affiche un message d'erreur suite à l'analyse en échec. *
+* *
+* Retour : 0 *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int yyerror(yyscan_t yyscanner, const kaitai_scope_t *locals, resolved_value_t *resolved, const char *msg)
+{
+ printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur générique résultante. [OUT] *
+* *
+* Description : Interprète une expression en une valeur quelconque. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool _resolve_kaitai_expression_as_any(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+ yyscan_t lexstate; /* Gestion d'analyse lexicale */
+ char *real_text; /* Zone de travail effective */
+ size_t real_length; /* Taille associée */
+ YY_BUFFER_STATE state; /* Contexte d'analyse */
+ int status; /* Bilan d'une analyse */
+
+ result = false;
+
+ kaitai_lex_init(&lexstate);
+
+ assert(length > 0);
+
+ if (text[length - 1] == '.')
+ {
+ /**
+ * Si le contenu à analyser se termine par un point, la position finale
+ * de ce point est prise en compte. Pour ce faire, le marqueur "$" des
+ * expressions régulières est sollicité. Hors, ce dernier n'est reconnu
+ * que pour le caractère "\n" terminant une ligne.
+ *
+ * On l'ajoute donc artificiellement.
+ */
+
+ real_length = length + 1;
+
+ real_text = malloc(real_length);
+ memcpy(real_text, text, length);
+ real_text[length] = '\n';
+
+ }
+ else
+ {
+ real_text = (char *)text;
+ real_length = length;
+ }
+
+ state = kaitai__scan_bytes(real_text, real_length, lexstate);
+
+ if (text[length - 1] == '.')
+ free(real_text);
+
+ status = yyparse(lexstate, locals, out);
+
+ result = (status == EXIT_SUCCESS);
+
+ yy_delete_buffer(state, lexstate);
+
+ kaitai_lex_destroy(lexstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur générique résultante. [OUT] *
+* *
+* Description : Interprète une expression en une valeur quelconque. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_any(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ return result;
+
+}
+
+
+
+/******************************************************************************
+* *
+* Paramètres : in_out = expression résolue traitée. [OUT] *
+* *
+* Description : Traduit les éventuels champs impliqués dans une expression. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool reduce_resolved_kaitai_expression(resolved_value_t *in_out)
+{
+ bool result; /* Bilan à renvoyer */
+ resolved_value_t deeper; /* Précision supplémentaire */
+
+ result = true;
+
+ while (result && in_out->type == GVT_RECORD)
+ {
+ if (G_IS_RECORD_BIT_FIELD(in_out->record))
+ result = g_record_bit_field_get_value(G_RECORD_BIT_FIELD(in_out->record), &deeper);
+
+ else if (G_IS_RECORD_DELAYED(in_out->record))
+ result = g_record_delayed_compute_value(G_RECORD_DELAYED(in_out->record), &deeper);
+
+ else if (G_IS_RECORD_ITEM(in_out->record))
+ result = g_record_item_get_value(G_RECORD_ITEM(in_out->record), &deeper);
+
+ else
+ break;
+
+ if (result)
+ {
+ EXIT_RESOLVED_VALUE(*in_out);
+ *in_out = deeper;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur entière résultante. [OUT] *
+* *
+* Description : Interprète une expression en valeur ciblée entière. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_integer(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ if (result)
+ result = reduce_resolved_kaitai_expression(out);
+
+ if (result)
+ result = (out->type == GVT_UNSIGNED_INTEGER || out->type == GVT_SIGNED_INTEGER);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur booléenne résultante. [OUT] *
+* *
+* Description : Interprète une expression en valeur ciblée booléenne. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_boolean(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ if (result)
+ result = reduce_resolved_kaitai_expression(out);
+
+ if (result)
+ {
+ if (out->type == GVT_UNSIGNED_INTEGER)
+ {
+ out->status = (out->unsigned_integer != 0);
+ out->type = GVT_BOOLEAN;
+ }
+ else if (out->type == GVT_SIGNED_INTEGER)
+ {
+ out->status = (out->signed_integer != 0);
+ out->type = GVT_BOOLEAN;
+ }
+ else if (out->type == GVT_FLOAT)
+ {
+ out->status = (out->floating_number != 0);
+ out->type = GVT_BOOLEAN;
+ }
+
+ }
+
+ if (result && out->type != GVT_BOOLEAN)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur booléenne résultante. [OUT] *
+* *
+* Description : Interprète une expression en série d'octets. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_bytes(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+ char ch; /* Caractère unique spécifié */
+ sized_string_t converted; /* Conversion finale ? */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ if (result)
+ result = reduce_resolved_kaitai_expression(out);
+
+ if (result)
+ {
+ if (out->type == GVT_UNSIGNED_INTEGER)
+ {
+ ch = out->unsigned_integer;
+ result = (ch <= 0xff);
+
+ if (result)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+
+ out->bytes.data = malloc(sizeof(char));
+ out->bytes.data[0] = ch;
+ out->bytes.len = 1;
+ out->type = GVT_BYTES;
+
+ }
+
+ }
+
+ else if (out->type == GVT_ARRAY)
+ {
+ result = g_kaitai_array_convert_to_bytes(out->array, &converted);
+
+ if (result)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+
+ out->bytes = converted;
+ out->type = GVT_BYTES;
+
+ }
+
+ }
+
+ }
+
+ if (result && out->type != GVT_BYTES)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* stream = flux de données pour Kaitai résultant. [OUT] *
+* *
+* Description : Interprète une expression en flux de données pour Kaitai. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_stream(const kaitai_scope_t *locals, const char *text, size_t length, GKaitaiStream **stream)
+{
+ bool result; /* Bilan à renvoyer */
+ resolved_value_t out; /* Elément générique obtenu */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, &out);
+
+ if (result)
+ {
+ assert(out.type == GVT_STREAM);
+ *stream = out.stream;
+ }
+ else
+ *stream = NULL;
+
+ return result;
+
+}
diff --git a/plugins/kaitai/import.c b/plugins/kaitai/import.c
new file mode 100644
index 0000000..0412ff7
--- /dev/null
+++ b/plugins/kaitai/import.c
@@ -0,0 +1,300 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * import.c - localisation de fichiers de définitions externes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "import.h"
+
+
+#include <libgen.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include <common/environment.h>
+#include <core/logs.h>
+
+
+
+/* Charge un type Kaitai à partir d'une définition voisine. */
+static GKaitaiType *import_relative_kaitai_definition(const char *, const char *);
+
+/* Charge un type Kaitai depuis un emplacement de $KSPATH. */
+static GKaitaiType *import_kaitai_definition_from_env(const char *);
+
+/* Charge un interpréteur pour une définition voisine. */
+static GKaitaiStruct *load_relative_kaitai_definition(const char *, const char *);
+
+/* Charge un interpréteur depuis un emplacement de $KSPATH. */
+static GKaitaiStruct *load_kaitai_definition_from_env(const char *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de la définition à retrouver. *
+* reference = éventuel fichier pour les positions relatives. *
+* *
+* Description : Charge un type Kaitai à partir d'une définition voisine. *
+* *
+* Retour : Type valide en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GKaitaiType *import_relative_kaitai_definition(const char *target, const char *reference)
+{
+ GKaitaiType *result; /* Structure chargée à renvoyer*/
+ char *tmp; /* Zone de travail temporaire */
+ char *base; /* Base de recherche */
+ char *filename; /* Nom de fichier à tester */
+ int ret; /* Bilan d'une construction */
+
+ result = NULL;
+
+ tmp = strdup(reference);
+ base = dirname(tmp);
+
+ ret = asprintf(&filename, "%s%c%s.ksy", base, G_DIR_SEPARATOR, target);
+ if (ret == -1) goto build_error;
+
+ result = g_kaitai_type_new_as_import(target, filename);
+
+ free(filename);
+
+ build_error:
+
+ free(tmp);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de la définition à retrouver. *
+* *
+* Description : Charge un type Kaitai depuis un emplacement de $KSPATH. *
+* *
+* Retour : Type valide en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GKaitaiType *import_kaitai_definition_from_env(const char *target)
+{
+ GKaitaiType *result; /* Structure chargée à renvoyer*/
+ char *paths; /* Emplacements de greffons */
+ char *save; /* Sauvegarde pour ré-entrance */
+ char *path; /* Chemin à fouiller */
+ char *filename; /* Nom de fichier à tester */
+ int ret; /* Bilan d'une construction */
+
+ result = NULL;
+
+ paths = get_env_var("KSPATH");
+
+ save = NULL; /* gcc... */
+
+ for (path = strtok_r(paths, ":", &save);
+ path != NULL;
+ path = strtok_r(NULL, ":", &save))
+ {
+ ret = asprintf(&filename, "%s%c%s.ksy", path, G_DIR_SEPARATOR, target);
+ if (ret == -1)
+ {
+ LOG_ERROR_N("asprintf");
+ continue;
+ }
+
+ result = g_kaitai_type_new_as_import(target, filename);
+
+ if (result != NULL)
+ log_variadic_message(LMT_PROCESS, _("Found a required Kaitai definition to import: %s"), filename);
+
+ free(filename);
+
+ }
+
+ free(paths);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de la définition à retrouver. *
+* reference = éventuel fichier pour les positions relatives. *
+* *
+* Description : Met en place un type Kaitai pour une définition désignée. *
+* *
+* Retour : Type valide en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiType *import_kaitai_definition(const char *target, const char *reference)
+{
+ GKaitaiType *result; /* Structure chargée à renvoyer*/
+
+ result = NULL;
+
+ if (reference != NULL)
+ result = import_relative_kaitai_definition(target, reference);
+
+ if (result == NULL)
+ result = import_kaitai_definition_from_env(target);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de la définition à retrouver. *
+* reference = éventuel fichier pour les positions relatives. *
+* *
+* Description : Charge un interpréteur pour une définition voisine. *
+* *
+* Retour : Interprétateur valide en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GKaitaiStruct *load_relative_kaitai_definition(const char *target, const char *reference)
+{
+ GKaitaiStruct *result; /* Structure chargée à renvoyer*/
+ char *tmp; /* Zone de travail temporaire */
+ char *base; /* Base de recherche */
+ char *filename; /* Nom de fichier à tester */
+ int ret; /* Bilan d'une construction */
+
+ result = NULL;
+
+ tmp = strdup(reference);
+ base = dirname(tmp);
+
+ ret = asprintf(&filename, "%s%c%s.ksy", base, G_DIR_SEPARATOR, target);
+ if (ret == -1) goto build_error;
+
+ result = g_kaitai_structure_new_from_file(filename);
+
+ free(filename);
+
+ build_error:
+
+ free(tmp);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de la définition à retrouver. *
+* *
+* Description : Charge un interpréteur depuis un emplacement de $KSPATH. *
+* *
+* Retour : Interprétateur valide en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GKaitaiStruct *load_kaitai_definition_from_env(const char *target)
+{
+ GKaitaiStruct *result; /* Structure chargée à renvoyer*/
+ char *paths; /* Emplacements de greffons */
+ char *save; /* Sauvegarde pour ré-entrance */
+ char *path; /* Chemin à fouiller */
+ char *filename; /* Nom de fichier à tester */
+ int ret; /* Bilan d'une construction */
+
+ result = NULL;
+
+ paths = get_env_var("KSPATH");
+
+ save = NULL; /* gcc... */
+
+ for (path = strtok_r(paths, ":", &save);
+ path != NULL;
+ path = strtok_r(NULL, ":", &save))
+ {
+ ret = asprintf(&filename, "%s%c%s.ksy", path, G_DIR_SEPARATOR, target);
+ if (ret == -1)
+ {
+ LOG_ERROR_N("asprintf");
+ continue;
+ }
+
+ result = g_kaitai_structure_new_from_file(filename);
+
+ if (result != NULL)
+ log_variadic_message(LMT_PROCESS, _("Found a required Kaitai definition: %s"), filename);
+
+ free(filename);
+
+ }
+
+ free(paths);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de la définition à retrouver. *
+* reference = éventuel fichier pour les positions relatives. *
+* *
+* Description : Met en place un interpréteur pour une définition désignée. *
+* *
+* Retour : Interprétateur valide en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiStruct *load_kaitai_definition(const char *target, const char *reference)
+{
+ GKaitaiStruct *result; /* Structure chargée à renvoyer*/
+
+ result = NULL;
+
+ if (reference != NULL)
+ result = load_relative_kaitai_definition(target, reference);
+
+ if (result == NULL)
+ result = load_kaitai_definition_from_env(target);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/import.h b/plugins/kaitai/import.h
new file mode 100644
index 0000000..66a0f5a
--- /dev/null
+++ b/plugins/kaitai/import.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * import.h - prototypes pour la localisation de fichiers de définitions externes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_IMPORT_H
+#define _PLUGINS_KAITAI_IMPORT_H
+
+
+#include "parsers/struct.h"
+#include "parsers/type.h"
+
+
+
+/* Met en place un type Kaitai pour une définition désignée. */
+GKaitaiType *import_kaitai_definition(const char *, const char *);
+
+/* Met en place un interpréteur pour une définition désignée. */
+GKaitaiStruct *load_kaitai_definition(const char *, const char *);
+
+
+
+#endif /* _PLUGINS_KAITAI_IMPORT_H */
diff --git a/plugins/kaitai/parser-int.h b/plugins/kaitai/parser-int.h
new file mode 100644
index 0000000..8bac523
--- /dev/null
+++ b/plugins/kaitai/parser-int.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser-int.h - prototypes pour les spécifications internes d'un lecteur Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSER_INT_H
+#define PLUGINS_KAITAI_PARSER_INT_H
+
+
+#include "parser.h"
+
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+typedef bool (* parse_kaitai_fc) (GKaitaiParser *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* Spécification d'un lecteur Kaitai (instance) */
+struct _GKaitaiParser
+{
+ GObject parent; /* A laisser en premier */
+
+};
+
+/* Spécification d'un lecteur Kaitai (classe) */
+struct _GKaitaiParserClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ parse_kaitai_fc parse; /* Phase d'analyse de contenu */
+
+};
+
+
+
+#endif /* PLUGINS_KAITAI_PARSER_INT_H */
diff --git a/plugins/kaitai/parser.c b/plugins/kaitai/parser.c
new file mode 100644
index 0000000..cfe1aa1
--- /dev/null
+++ b/plugins/kaitai/parser.c
@@ -0,0 +1,166 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser.c - spécification d'un lecteur Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "parser.h"
+
+
+#include <assert.h>
+
+
+#include "parser-int.h"
+
+
+
+/* Initialise la classe des lecteurs de spécification Kaitai. */
+static void g_kaitai_parser_class_init(GKaitaiParserClass *);
+
+/* Initialise un lecteur de spécification Kaitai. */
+static void g_kaitai_parser_init(GKaitaiParser *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_parser_dispose(GKaitaiParser *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_parser_finalize(GKaitaiParser *);
+
+
+
+/* Indique le type défini pour un lecteur de spécification Kaitai. */
+G_DEFINE_TYPE(GKaitaiParser, g_kaitai_parser, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des lecteurs de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_parser_class_init(GKaitaiParserClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_parser_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_parser_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parser = instance à initialiser. *
+* *
+* Description : Initialise un lecteur de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_parser_init(GKaitaiParser *parser)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parser = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_parser_dispose(GKaitaiParser *parser)
+{
+ G_OBJECT_CLASS(g_kaitai_parser_parent_class)->dispose(G_OBJECT(parser));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parser = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_parser_finalize(GKaitaiParser *parser)
+{
+ G_OBJECT_CLASS(g_kaitai_parser_parent_class)->finalize(G_OBJECT(parser));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parser = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_parser_parse_content(GKaitaiParser *parser, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ GKaitaiParserClass *class; /* Classe de l'instance */
+
+ *record = NULL;
+
+ class = G_KAITAI_PARSER_GET_CLASS(parser);
+
+ result = class->parse(parser, locals, content, epos, record);
+
+ if (result && *record != NULL)
+ remember_last_record(locals, *record);
+
+ assert((!result && *record == NULL) || result);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parser.h b/plugins/kaitai/parser.h
new file mode 100644
index 0000000..64d759d
--- /dev/null
+++ b/plugins/kaitai/parser.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser.h - prototypes pour la spécification d'un lecteur Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSER_H
+#define PLUGINS_KAITAI_PARSER_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <analysis/content.h>
+
+
+#include "record.h"
+#include "scope.h"
+
+
+
+#define G_TYPE_KAITAI_PARSER g_kaitai_parser_get_type()
+#define G_KAITAI_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_PARSER, GKaitaiParser))
+#define G_IS_KAITAI_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_PARSER))
+#define G_KAITAI_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_PARSER, GKaitaiParserClass))
+#define G_IS_KAITAI_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_PARSER))
+#define G_KAITAI_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_PARSER, GKaitaiParserClass))
+
+
+/* Spécification d'un lecteur Kaitai (instance) */
+typedef struct _GKaitaiParser GKaitaiParser;
+
+/* Spécification d'un lecteur Kaitai (classe) */
+typedef struct _GKaitaiParserClass GKaitaiParserClass;
+
+
+/* Indique le type défini pour un lecteur de spécification Kaitai. */
+GType g_kaitai_parser_get_type(void);
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+bool g_kaitai_parser_parse_content(GKaitaiParser *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSER_H */
diff --git a/plugins/kaitai/parsers/Makefile.am b/plugins/kaitai/parsers/Makefile.am
new file mode 100644
index 0000000..c7e313b
--- /dev/null
+++ b/plugins/kaitai/parsers/Makefile.am
@@ -0,0 +1,25 @@
+
+noinst_LTLIBRARIES = libkaitaiparsers.la
+
+libkaitaiparsers_la_SOURCES = \
+ attribute-int.h \
+ attribute.h attribute.c \
+ enum-int.h \
+ enum.h enum.c \
+ instance-int.h \
+ instance.h instance.c \
+ meta-int.h \
+ meta.h meta.c \
+ struct-int.h \
+ struct.h struct.c \
+ switch-int.h \
+ switch.h switch.c \
+ type-int.h \
+ type.h type.c
+
+libkaitaiparsers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitaiparsers_la_SOURCES:%c=)
diff --git a/plugins/kaitai/parsers/attribute-int.h b/plugins/kaitai/parsers/attribute-int.h
new file mode 100644
index 0000000..7d37af3
--- /dev/null
+++ b/plugins/kaitai/parsers/attribute-int.h
@@ -0,0 +1,107 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute-int.h - prototypes pour les spécifications internes d'un attribut Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H
+#define _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H
+
+
+#include "attribute.h"
+#include "switch.h"
+#include "../parser-int.h"
+
+
+
+/* Indique l'étiquette à utiliser pour identifier un attribut. */
+typedef const char * (* get_attribute_label_fc) (const GKaitaiAttribute *);
+
+/* Spécification d'un attribut Kaitai (instance) */
+struct _GKaitaiAttribute
+{
+ GKaitaiParser parent; /* A laisser en premier */
+
+ char *raw_id; /* Identifiant Kaitai */
+ char *orig_id; /* Identifiant humain */
+
+ char *doc; /* Eventuelle documentation */
+
+ KaitaiAttributePayload payload; /* Forme de la spécialisation */
+
+ struct
+ {
+ /* KAP_FIXED_CONTENT */
+ sized_string_t fixed_content; /* Données brutes attendues */
+
+ /* KAP_BIT_FIELD_TYPE */
+ uint8_t bf_size; /* Nombre de bits visés */
+
+ /* KAP_BASIC_TYPE */
+ struct
+ {
+ BaseType basic; /* Type de base */
+
+ bool is_string; /* Renvoi vers une chaîne */
+
+ SourceEndian endian; /* Boutisme forcé ? */
+ bool has_endian; /* Présence de cette force */
+
+ };
+
+ /* KAP_USER_TYPE */
+ char *named_type; /* Type particulier */
+
+ /* KAP_DYNAMIC_TYPE */
+ GKaitaiSwitch *switchon; /* Détermination dynamique */
+
+ };
+
+ /* KAP_SIZED */
+ char *fixed_size; /* Taille déterminée */
+
+ KaitaiAttributeRepetition repetition; /* Forme de répétition */
+ char *repeat_controller; /* Indication sur la répétition*/
+
+ char *condition; /* Condition de chargement */
+
+ sized_string_t terminator; /* Marqueur de fin éventuel */
+ bool consume; /* Consommation dans le flux */
+ bool include; /* Intégration de ce marqueur */
+ bool eos_error; /* Gestion des erreurs en bout */
+
+};
+
+/* Spécification d'un attribut Kaitai (classe) */
+struct _GKaitaiAttributeClass
+{
+ GKaitaiParserClass parent; /* A laisser en premier */
+
+ get_attribute_label_fc get_label; /* Désignation d'une étiquette */
+
+};
+
+
+/* Met en place un lecteur d'attribut Kaitai. */
+bool g_kaitai_attribute_create(GKaitaiAttribute *, GYamlNode *, bool);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H */
diff --git a/plugins/kaitai/parsers/attribute.c b/plugins/kaitai/parsers/attribute.c
new file mode 100644
index 0000000..6050bb1
--- /dev/null
+++ b/plugins/kaitai/parsers/attribute.c
@@ -0,0 +1,2213 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute.c - spécification d'un attribut Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "attribute.h"
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <analysis/contents/restricted.h>
+#include <plugins/yaml/pair.h>
+
+
+#include "attribute-int.h"
+#include "../expression.h"
+#include "../scope.h"
+#include "../records/bits.h"
+#include "../records/empty.h"
+#include "../records/item.h"
+#include "../records/list.h"
+
+
+
+/* -------------------- CORRESPONDANCE ENTRE ATTRIBUT ET BINAIRE -------------------- */
+
+
+/* Initialise la classe des attributs de spécification Kaitai. */
+static void g_kaitai_attribute_class_init(GKaitaiAttributeClass *);
+
+/* Initialise un attribut de spécification Kaitai. */
+static void g_kaitai_attribute_init(GKaitaiAttribute *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_attribute_dispose(GKaitaiAttribute *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_attribute_finalize(GKaitaiAttribute *);
+
+/* Traduit en champ de bits une chaîne de caractères. */
+static bool g_kaitai_attribute_resolve_bit_field(GKaitaiAttribute *, const char *);
+
+/* Traduit en type concret une chaîne de caractères. */
+static bool g_kaitai_attribute_resolve_type(GKaitaiAttribute *, const char *);
+
+/* Valide la cohérence des informations portées par l'attribut. */
+static bool g_kaitai_attribute_check(const GKaitaiAttribute *);
+
+/* Copie le coeur de la définition d'un lecteur d'attribut. */
+static GKaitaiAttribute *g_kaitai_attribute_dup_for(const GKaitaiAttribute *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+/* Extrait d'un contenu une série d'octets avec terminaison. */
+static bool g_kaitai_attribute_parse_terminated_bytes(GKaitaiAttribute *, const kaitai_scope_t *, GBinContent *, vmpa2t *, GMatchRecord **);
+
+/* Détermine la zone de couverture finale d'une correspondance. */
+static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttribute *, const kaitai_scope_t *, const GBinContent *, const vmpa2t *, phys_t *, mrange_t *);
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CORRESPONDANCE ENTRE ATTRIBUT ET BINAIRE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un attribut de la spécification Kaitai. */
+G_DEFINE_TYPE(GKaitaiAttribute, g_kaitai_attribute, G_TYPE_KAITAI_PARSER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des attributs de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_class_init(GKaitaiAttributeClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_attribute_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_attribute_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_attribute_parse_content;
+
+ klass->get_label = g_kaitai_attribute_get_raw_id;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = instance à initialiser. *
+* *
+* Description : Initialise un attribut de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_init(GKaitaiAttribute *attrib)
+{
+ attrib->raw_id = NULL;
+ attrib->orig_id = NULL;
+
+ attrib->doc = NULL;
+
+ attrib->payload = KAP_UNINITIALIZED;
+
+ attrib->repetition = KAR_NO_REPETITION;
+ attrib->repeat_controller = NULL;
+
+ attrib->condition = NULL;
+
+ init_szstr(&attrib->terminator);
+ attrib->consume = true;
+ attrib->include = false;
+ attrib->eos_error = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_dispose(GKaitaiAttribute *attrib)
+{
+ if (attrib->payload & KAP_DYNAMIC_TYPE)
+ g_clear_object(&attrib->switchon);
+
+ G_OBJECT_CLASS(g_kaitai_attribute_parent_class)->dispose(G_OBJECT(attrib));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_finalize(GKaitaiAttribute *attrib)
+{
+ if (attrib->raw_id != NULL)
+ free(attrib->raw_id);
+
+ if (attrib->orig_id != NULL)
+ free(attrib->orig_id);
+
+ if (attrib->doc != NULL)
+ free(attrib->doc);
+
+ if (attrib->payload & KAP_FIXED_CONTENT)
+ exit_szstr(&attrib->fixed_content);
+
+ else if (attrib->payload & KAP_USER_TYPE)
+ free(attrib->named_type);
+
+ if (attrib->fixed_size != NULL)
+ free(attrib->fixed_size);
+
+ if (attrib->repeat_controller != NULL)
+ free(attrib->repeat_controller);
+
+ if (attrib->condition != NULL)
+ free(attrib->condition);
+
+ exit_szstr(&attrib->terminator);
+
+ G_OBJECT_CLASS(g_kaitai_attribute_parent_class)->finalize(G_OBJECT(attrib));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Construit un lecteur d'attribut Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiAttribute *g_kaitai_attribute_new(GYamlNode *parent)
+{
+ GKaitaiAttribute *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_ATTRIBUTE, NULL);
+
+ if (!g_kaitai_attribute_create(result, parent, false /* TODO : REMME ? */))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à initialiser pleinement.*
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* need_id = encadre la présence d'un champ "id". *
+* *
+* Description : Met en place un lecteur d'attribut Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_create(GKaitaiAttribute *attrib, GYamlNode *parent, bool need_id)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *node; /* Noeud particulier présent */
+ const char *value; /* Valeur Yaml particulière */
+ char *rebuilt_value; /* Valeur Yaml rassemblée */
+ kaitai_scope_t fake; /* Contexte de circonstance */
+ resolved_value_t bytes; /* Données brutes obtenues */
+ GYamlNode *other_node; /* Autre noeud nécessaire */
+
+ result = false;
+
+ /* Identifiant obligatoire */
+
+ node = g_yaml_node_find_first_by_path(parent, "/id");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_id;
+ }
+
+ attrib->raw_id = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ else if (need_id)
+ goto bad_id;
+
+ /* Identifiant facultatif */
+
+ node = g_yaml_node_find_first_by_path(parent, "/-orig-id");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_id;
+ }
+
+ attrib->orig_id = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Eventuelle documentation */
+
+ node = g_yaml_node_find_first_by_path(parent, "/doc");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_doc;
+ }
+
+ attrib->doc = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ contents */
+
+ node = g_yaml_node_find_first_by_path(parent, "/contents");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ rebuilt_value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node));
+
+ if (rebuilt_value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ fake.meta = NULL;
+ fake.root = NULL;
+ fake.parent = NULL;
+ fake.last = NULL;
+
+ if (!resolve_kaitai_expression_as_bytes(&fake, rebuilt_value, strlen(rebuilt_value), &bytes))
+ {
+ free(rebuilt_value);
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ free(rebuilt_value);
+
+ attrib->fixed_content = bytes.bytes;
+
+ g_object_unref(G_OBJECT(node));
+
+ attrib->payload |= KAP_FIXED_CONTENT;
+
+ }
+
+ /* Charge portée par un type */
+
+ node = g_yaml_node_find_first_by_path(parent, "/type");
+
+ if (node != NULL)
+ {
+ if (attrib->payload & KAP_FIXED_CONTENT)
+ {
+ printf("Can not handle fixed content and type definition at the same time for an attribute.\n");
+ goto bad_definition;
+ }
+
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (g_kaitai_attribute_resolve_bit_field(attrib, value))
+ attrib->payload |= KAP_BIT_FIELD_TYPE;
+
+ else if (g_kaitai_attribute_resolve_type(attrib, value))
+ attrib->payload |= KAP_BASIC_TYPE;
+
+ else
+ {
+ attrib->named_type = strdup(value);
+ attrib->payload |= KAP_USER_TYPE;
+ }
+
+ }
+
+ else
+ {
+ attrib->switchon = g_kaitai_switch_new(parent, attrib);
+ if (attrib->switchon == NULL) goto bad_definition;
+
+ attrib->payload |= KAP_DYNAMIC_TYPE;
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Répétitions contrôlées ? */
+
+ node = g_yaml_node_find_first_by_path(parent, "/repeat");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "eos") == 0)
+ attrib->repetition = KAR_END_OF_STREAM;
+
+ else if (strcmp(value, "expr") == 0)
+ {
+ other_node = g_yaml_node_find_first_by_path(parent, "/repeat-expr");
+
+ if (other_node != NULL)
+ {
+ if (G_IS_YAML_PAIR(other_node))
+ {
+ value = g_yaml_pair_get_value(G_YAML_PAIR(other_node));
+
+ if (value != NULL)
+ {
+ attrib->repetition = KAR_EXPRESSION;
+ attrib->repeat_controller = strdup(value);
+ }
+ else
+ printf("Expected repeat expression\n");
+
+ }
+
+ g_object_unref(G_OBJECT(other_node));
+
+ }
+
+ }
+
+ else if (strcmp(value, "until") == 0)
+ {
+ other_node = g_yaml_node_find_first_by_path(parent, "/repeat-until");
+
+ if (other_node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(other_node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(other_node));
+
+ if (value != NULL)
+ {
+ attrib->repetition = KAR_UNTIL;
+ attrib->repeat_controller = strdup(value);
+ }
+ else
+ printf("Expected repeat expression\n");
+
+ }
+
+ g_object_unref(G_OBJECT(other_node));
+
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Intégration sous condition ? */
+
+ node = g_yaml_node_find_first_by_path(parent, "/if");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ attrib->condition = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Taille fixée ? */
+
+ node = g_yaml_node_find_first_by_path(parent, "/size");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ attrib->fixed_size = strdup(value);
+ attrib->payload |= KAP_SIZED;
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ if ((attrib->payload & KAP_SIZED) == 0)
+ goto bad_content;
+
+ }
+
+ /* Prise en considération d'une taille maximale */
+
+ node = g_yaml_node_find_first_by_path(parent, "/size-eos");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL && strcmp(value, "true") == 0)
+ {
+ if (attrib->payload != KAP_UNINITIALIZED)
+ /* printf warning */;
+
+ attrib->payload |= KAP_SIZED_EOS;
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ terminator */
+
+ node = g_yaml_node_find_first_by_path(parent, "/terminator");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ rebuilt_value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node));
+
+ if (rebuilt_value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ fake.meta = NULL;
+ fake.root = NULL;
+ fake.parent = NULL;
+ fake.last = NULL;
+
+ if (!resolve_kaitai_expression_as_bytes(&fake, rebuilt_value, strlen(rebuilt_value), &bytes))
+ {
+ free(rebuilt_value);
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ free(rebuilt_value);
+
+ if (attrib->terminator.data != NULL)
+ printf("A ending content has already been specified (implicitly by the strz type)");
+
+ else
+ {
+ attrib->terminator.data = bytes.bytes.data;
+ attrib->terminator.len = bytes.bytes.len;
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ consume */
+
+ node = g_yaml_node_find_first_by_path(parent, "/consume");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "true") == 0)
+ attrib->consume = true;
+
+ else if (strcmp(value, "false") == 0)
+ attrib->consume = false;
+
+ else
+ printf("Unsupported value for the 'consume' property (expecting true of false)");
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ include */
+
+ node = g_yaml_node_find_first_by_path(parent, "/include");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "true") == 0)
+ attrib->include = true;
+
+ else if (strcmp(value, "false") == 0)
+ attrib->include = false;
+
+ else
+ printf("Unsupported value for the 'include' property (expecting true of false)");
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ eos-error */
+
+ node = g_yaml_node_find_first_by_path(parent, "/eos-error");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "true") == 0)
+ attrib->eos_error = true;
+
+ if (strcmp(value, "false") == 0)
+ attrib->eos_error = false;
+
+ else
+ printf("Unsupported value for the 'eos_error' property (expecting true of false)");
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Validation finale */
+
+ result = g_kaitai_attribute_check(attrib);
+
+ bad_definition:
+
+ bad_doc:
+ bad_id:
+ bad_content:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = attribut Kaitai en cours de constitution. *
+* desc = chaîne de caractère à interpréter en type. *
+* *
+* Description : Traduit en champ de bits une chaîne de caractères. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_resolve_bit_field(GKaitaiAttribute *attrib, const char *desc)
+{
+ bool result; /* Bilan à retourner */
+ size_t len; /* Taille de la chaîne à lire */
+ char *end; /* Prochain caractère à lire */
+ unsigned long size; /* Taille du champ de bits */
+
+ result = false;
+
+ if (desc[0] == 'b')
+ {
+ len = strlen(desc);
+
+ size = strtoul(&desc[1], &end, 10);
+
+ if (size > 64)
+ {
+ printf("Unsupported size for bit field: %lu\n", size);
+ goto exit;
+ }
+
+ result = ((desc + len) == end);
+
+ if (result)
+ attrib->bf_size = size;
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = attribut Kaitai en cours de constitution. *
+* desc = chaîne de caractère à interpréter en type. *
+* *
+* Description : Traduit en type concret une chaîne de caractères. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_resolve_type(GKaitaiAttribute *attrib, const char *desc)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ attrib->basic = BTP_INVALID;
+ attrib->has_endian = false;
+
+ /**
+ * Cf. définition des types de base existants :
+ * http://doc.kaitai.io/user_guide.html#_fixed_size_structures
+ */
+
+#define RESOLVE_ENDIAN \
+ if (desc[2] == 'l') \
+ { \
+ if (desc[3] == 'e') \
+ { \
+ attrib->endian = SRE_LITTLE; \
+ attrib->has_endian = true; \
+ } \
+ } \
+ else if (desc[2] == 'b') \
+ { \
+ if (desc[3] == 'e') \
+ { \
+ attrib->endian = SRE_BIG; \
+ attrib->has_endian = true; \
+ } \
+ } \
+
+ /* Analyse de la chaîne fournie */
+
+ switch (desc[0])
+ {
+ case 'f':
+ switch (desc[1])
+ {
+ case '4':
+ attrib->basic = BTP_754R_32;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '8':
+ attrib->basic = BTP_754R_64;
+ RESOLVE_ENDIAN;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+ break;
+
+ case 's':
+ switch (desc[1])
+ {
+ case '1':
+ attrib->basic = BTP_CHAR;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '2':
+ attrib->basic = BTP_SHORT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '4':
+ attrib->basic = BTP_INT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '8':
+ attrib->basic = BTP_LONG_LONG;
+ RESOLVE_ENDIAN;
+ break;
+
+ case 't':
+ if (desc[2] == 'r')
+ {
+ attrib->basic = BTP_CHAR;
+ attrib->is_string = true;
+ if (desc[3] == 'z')
+ {
+ attrib->terminator.data = strdup("");
+ attrib->terminator.len = 1;
+ }
+ }
+ else
+ result = false;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+ break;
+
+ case 'u':
+ switch (desc[1])
+ {
+ case '1':
+ attrib->basic = BTP_UCHAR;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '2':
+ attrib->basic = BTP_USHORT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '4':
+ attrib->basic = BTP_UINT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '8':
+ attrib->basic = BTP_ULONG_LONG;
+ RESOLVE_ENDIAN;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ /* Vérification d'une comparaison complète */
+ if (result)
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ if (attrib->is_string)
+ {
+ if (attrib->terminator.data != NULL)
+ result = (desc[4] == 0);
+ else
+ result = (desc[3] == 0);
+ }
+ else
+ {
+ if (attrib->has_endian)
+ result = (desc[4] == 0);
+ else
+ result = (desc[2] == 0);
+ }
+ break;
+
+ default:
+ if (attrib->has_endian)
+ result = (desc[4] == 0);
+ else
+ result = (desc[2] == 0);
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = attribut Kaitai à valider. *
+* *
+* Description : Valide la cohérence des informations portées par l'attribut. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_check(const GKaitaiAttribute *attrib)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ /**
+ * Une lecture de tous les octets restants ne doit correspondre qu'à des octets bruts.
+ */
+ if (attrib->payload & KAP_SIZED_EOS && attrib->payload != KAP_SIZED_EOS)
+ {
+ result = (attrib->payload & KAP_BASIC_TYPE) && attrib->is_string;
+
+ if (!result)
+ {
+ printf("Reading all the remaining bytes should only produce bytes.");
+ result = true;
+ }
+
+ }
+
+ /**
+ * Une chaîne (type str[z]) doit comporter une séquence de terminaison.
+ */
+ if ((attrib->payload & KAP_BASIC_TYPE) && attrib->is_string)
+ {
+ result = (attrib->terminator.data != NULL) || (attrib->payload & (KAP_SIZED | KAP_SIZED_EOS));
+
+ if (!result)
+ {
+ printf("An unsized string (str type with no size attribute) has to be link to a terminator sequence.");
+ goto exit;
+ }
+
+ }
+
+ /**
+ * Si une séquence d'octets finaux est spécifiée, alors l'attribut
+ * doit correspondre à un type str[z] (lecture) ou de taille fixée
+ * (validation post-lecture).
+ */
+ if (attrib->terminator.data != NULL)
+ {
+ result = ((attrib->payload & ~(KAP_FIXED_CONTENT | KAP_BASIC_TYPE | KAP_SIZED)) == 0);
+
+ if (result && (attrib->payload & KAP_BASIC_TYPE))
+ result = attrib->is_string;
+
+ if (!result)
+ {
+ printf("A useless terminator is specified.");
+ result = true;
+ goto exit;
+ }
+
+ }
+
+ /**
+ * Il n'est pas possible d'inclure un marqueur de fin sans le consommer.
+ */
+ if (!attrib->consume && attrib->include)
+ {
+ result = false;
+ printf("It is not possible to include a terminator without consuming it.");
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à dupliquer. *
+* type = type utilisateur à associer au nouvel attribut. *
+* *
+* Description : Dérive un lecteur d'attribut Kaitai pour un type utilisateur.*
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiAttribute *g_kaitai_attribute_dup_for_user_type(const GKaitaiAttribute *attrib, const char *type)
+{
+ GKaitaiAttribute *result; /* Structure à retourner */
+
+ result = g_kaitai_attribute_dup_for(attrib);
+
+ result->payload = KAP_USER_TYPE;
+
+ result->named_type = strdup(type);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à dupliquer. *
+* *
+* Description : Copie le coeur de la définition d'un lecteur d'attribut. *
+* *
+* Retour : Nouvelle instance à compléter. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GKaitaiAttribute *g_kaitai_attribute_dup_for(const GKaitaiAttribute *attrib)
+{
+ GKaitaiAttribute *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_ATTRIBUTE, NULL);
+
+ /**
+ * Il n'y a rien à copier dans la structure parente.
+ *
+ * Les travaux de copie ne portent ainsi que sur le présent attribut.
+ */
+
+ if (attrib->raw_id != NULL)
+ result->raw_id = strdup(attrib->raw_id);
+
+ if (attrib->orig_id != NULL)
+ result->orig_id = strdup(attrib->orig_id);
+
+ if (attrib->doc != NULL)
+ result->doc = strdup(attrib->doc);
+
+ if (attrib->fixed_size != NULL)
+ result->fixed_size = strdup(attrib->fixed_size);
+
+ result->repetition = attrib->repetition;
+
+ if (attrib->repeat_controller != NULL)
+ result->repeat_controller = strdup(attrib->repeat_controller);
+
+ if (attrib->condition != NULL)
+ result->condition = strdup(attrib->condition);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique l'étiquette à utiliser pour identifier un attribut. *
+* *
+* Retour : Valeur brute de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_label(const GKaitaiAttribute *attrib)
+{
+ const char *result; /* Valeur à renvoyer */
+ GKaitaiAttributeClass *class; /* Classe de l'instance */
+
+ class = G_KAITAI_ATTRIBUTE_GET_CLASS(attrib);
+
+ result = class->get_label(attrib);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique la désignation brute d'un identifiant Kaitai. *
+* *
+* Retour : Valeur brute de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_raw_id(const GKaitaiAttribute *attrib)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = attrib->raw_id;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique la désignation originelle d'un identifiant Kaitai. *
+* *
+* Retour : Valeur originelle de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_original_id(const GKaitaiAttribute *attrib)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = attrib->orig_id;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Fournit une éventuelle documentation concernant l'attribut. *
+* *
+* Retour : Description enregistrée ou NULL si absente. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_doc(const GKaitaiAttribute *attrib)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = attrib->doc;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique la nature de la charge représentée par l'attribut. *
+* *
+* Retour : Forme de contenu représenté par le lecteur d'attribut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+KaitaiAttributePayload g_kaitai_attribute_get_payload(const GKaitaiAttribute *attrib)
+{
+ KaitaiAttributePayload result; /* Type de charge à renvoyer */
+
+ result = attrib->payload;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* basic = type de base Kaitai reconnu par le lecteur. [OUT]*
+* is_string = nature du type BTP_CHAR en sortie. [OUT] *
+* *
+* Description : Précise un éventuel type de base reconnu par le lecteur. *
+* *
+* Retour : Validité du type renseigné en argument. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_get_basic_type(const GKaitaiAttribute *attrib, BaseType *basic, bool *is_string)
+{
+ bool result; /* Validité à retourner */
+
+ result = (attrib->payload & KAP_BASIC_TYPE);
+
+ if (result)
+ {
+ *basic = attrib->basic;
+ *is_string = attrib->is_string;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* content = contenu binaire à venir lire. *
+* range = espace disponible pour la lecture. *
+* out = tableau d'octets retournés. [OUT] *
+* len = taille de ce tableau alloué. [OUT] *
+* *
+* Description : Lit les octets d'une chaîne représentée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_read_truncated_bytes(const GKaitaiAttribute *attrib, const GBinContent *content, const mrange_t *range, bin_t **out, size_t *len)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t tmppos; /* Localisation modifiable */
+ const bin_t *data; /* Accès aux données brutes */
+
+ result = false;
+
+ if ((attrib->payload & KAP_SIZED) == 0)
+ goto bad_type;
+
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ *len = get_mrange_length(range);
+
+ data = g_binary_content_get_raw_access(content, &tmppos, *len);
+
+ *out = malloc(sizeof(bin_t) * (*len + 1));
+
+ memcpy(*out, data, *len);
+ (*out)[*len] = '\0';
+
+ result = true;
+
+ bad_type:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Détermine si l'attribue porte une valeur entière signée. *
+* *
+* Retour : Bilan de la consultation : true si un entier signé est visé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_handle_signed_integer(const GKaitaiAttribute *attrib)
+{
+ bool result; /* Bilan à retourner */
+
+ result = false;
+
+ if ((attrib->payload & KAP_BASIC_TYPE) == 0)
+ goto bad_type;
+
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ case BTP_SHORT:
+ case BTP_INT:
+ case BTP_LONG_LONG:
+ result = true;
+ break;
+
+ default:
+ break;
+
+ }
+
+ bad_type:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* content = contenu binaire à venir lire. *
+* range = espace de lecture. *
+* endian = boustime des données à respecter. *
+* out = valeur à sauvegarder sous une forme générique.[OUT]*
+* *
+* Description : Lit la valeur d'un élément Kaitai entier représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_read_value(const GKaitaiAttribute *attrib, const GBinContent *content, const mrange_t *range, SourceEndian endian, resolved_value_t *out)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t tmppos; /* Localisation modifiable */
+ const bin_t *data; /* Données brutes restituées */
+ int8_t stmp8; /* Valeur de 8 bits lue */
+ uint8_t tmp8; /* Valeur de 8 bits lue */
+ int16_t stmp16; /* Valeur de 16 bits lue */
+ uint16_t tmp16; /* Valeur de 16 bits lue */
+ int32_t stmp32; /* Valeur de 32 bits lue */
+ uint32_t tmp32; /* Valeur de 32 bits lue */
+ int64_t stmp64; /* Valeur de 64 bits lue */
+ uint64_t tmp64; /* Valeur de 64 bits lue */
+
+ result = false;
+
+ if (attrib->payload & (KAP_FIXED_CONTENT | KAP_SIZED | KAP_SIZED_EOS))
+ {
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ data = g_binary_content_get_raw_access(content, &tmppos, get_mrange_length(range));
+ result = (data != NULL);
+
+ if (result)
+ {
+ out->type = GVT_BYTES;
+
+ out->bytes.len = get_mrange_length(range);
+
+ out->bytes.data = malloc(out->bytes.len);
+ memcpy(out->bytes.data, data, out->bytes.len);
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_BASIC_TYPE)
+ {
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ if (attrib->is_string)
+ {
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ data = g_binary_content_get_raw_access(content, &tmppos, get_mrange_length(range));
+ result = (data != NULL);
+
+ if (result)
+ {
+ out->type = GVT_BYTES;
+
+ out->bytes.len = get_mrange_length(range);
+
+ out->bytes.data = malloc(out->bytes.len);
+ memcpy(out->bytes.data, data, out->bytes.len);
+
+ }
+
+ }
+ else
+ {
+ assert(get_mrange_length(range) == 1);
+ result = g_binary_content_read_s8(content, &tmppos, &stmp8);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp8;
+ }
+ break;
+
+ case BTP_UCHAR:
+ assert(get_mrange_length(range) == 1);
+ result = g_binary_content_read_u8(content, &tmppos, &tmp8);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp8;
+ break;
+
+ case BTP_SHORT:
+ assert(get_mrange_length(range) == 2);
+ result = g_binary_content_read_s16(content, &tmppos, endian, &stmp16);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp16;
+ break;
+
+ case BTP_USHORT:
+ assert(get_mrange_length(range) == 2);
+ result = g_binary_content_read_u16(content, &tmppos, endian, &tmp16);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp16;
+ break;
+
+ case BTP_INT:
+ assert(get_mrange_length(range) == 4);
+ result = g_binary_content_read_s32(content, &tmppos, endian, &stmp32);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp32;
+ break;
+
+ case BTP_UINT:
+ assert(get_mrange_length(range) == 4);
+ result = g_binary_content_read_u32(content, &tmppos, endian, &tmp32);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp32;
+ break;
+
+ case BTP_LONG_LONG:
+ assert(get_mrange_length(range) == 8);
+ result = g_binary_content_read_s64(content, &tmppos, endian, &stmp64);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp64;
+ break;
+
+ case BTP_ULONG_LONG:
+ assert(get_mrange_length(range) == 8);
+ result = g_binary_content_read_u64(content, &tmppos, endian, &tmp64);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp64;
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* content = contenu binaire à venir lire. *
+* epos = tête de lecture avec granularité en bits. *
+* size = quantité de bits à prendre en compte. *
+* endian = boustime des données à respecter. *
+* out = valeur à sauvegarder sous une forme générique.[OUT]*
+* *
+* Description : Lit la valeur d'un champ de bits Kaitai représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_read_bit_field_value(const GKaitaiAttribute *attrib, const GBinContent *content, const ext_vmpa_t *epos, uint8_t size, SourceEndian endian, resolved_value_t *out)
+{
+ bool result; /* Bilan à retourner */
+ ext_vmpa_t tmpepos; /* Localisation modifiable */
+ uint64_t tmp64; /* Valeur de 64 bits lue */
+
+ result = false;
+
+ if (attrib->payload & KAP_BIT_FIELD_TYPE)
+ {
+ copy_evmpa(&tmpepos, epos);
+
+ result = g_binary_content_read_bits(content, &tmpepos, size, endian, &tmp64);
+
+ if (result)
+ {
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp64;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ resolved_value_t authorized; /* Validation des traitements */
+
+ mrange_t work_range; /* Définition de cette aire */
+ GBinContent *work_area; /* Aire de travail */
+ bool has_empty_size; /* Mémorise une taille nulle */
+
+
+ //unsigned long long value; /* Valeur entière finale */
+ //bool status; /* Bilan d'une conversion */
+
+
+ vmpa2t tmp; /* Position de travail */
+ phys_t diff; /* Différentiel de positions */
+ resolved_value_t resolved; /* Valeur entière obtenue */
+ phys_t max_size; /* Taille maximale imposée */
+
+
+ const bin_t *data; /* Données à comparer */
+ GKaitaiType *user_type; /* Définition particulière */
+
+
+ mrange_t range; /* Couverture appliquée */
+ SourceEndian endian; /* Boutisme à observer */
+ phys_t cur_diff; /* Avancée de lecture courante */
+
+
+ result = false;
+ *record = NULL;
+
+ /* Lecture soumise à condition ? */
+
+ if (attrib->condition != NULL)
+ {
+ result = resolve_kaitai_expression_as_boolean(locals,
+ attrib->condition,
+ strlen(attrib->condition),
+ &authorized);
+
+ if (!result || !authorized.status)
+ goto exit;
+
+ }
+
+ /* Zone de travail restreinte */
+
+ g_binary_content_compute_end_pos(content, &tmp);
+ diff = compute_vmpa_diff(&epos->base, &tmp);
+
+ if (epos->consumed_extra_bits > 0 && diff > 0)
+ diff--;
+
+ if (attrib->payload & KAP_SIZED)
+ {
+ result = resolve_kaitai_expression_as_integer(locals,
+ attrib->fixed_size,
+ strlen(attrib->fixed_size),
+ &resolved);
+
+ if (result)
+ {
+ if (resolved.type == GVT_UNSIGNED_INTEGER)
+ max_size = resolved.unsigned_integer;
+ else
+ {
+ assert(resolved.type == GVT_SIGNED_INTEGER);
+
+ if (resolved.signed_integer < 0)
+ result = false;
+ else
+ max_size = resolved.signed_integer;
+
+ }
+
+ if (result)
+ result = (diff >= max_size);
+
+ if (!result)
+ printf("Need more data!\n");
+
+ if (result && max_size < diff)
+ diff = max_size;
+
+ }
+
+ if (!result)
+ goto exit;
+
+ align_evmpa_on_byte(epos);
+
+ init_mrange(&work_range, &epos->base, diff);
+ work_area = g_restricted_content_new(content, &work_range);
+
+ has_empty_size = (diff == 0);
+
+ }
+ else
+ {
+ work_area = content;
+ has_empty_size = false;
+ }
+
+ /* Etablissement d'une zone de correspondance */
+
+ if (attrib->payload == KAP_UNINITIALIZED)
+ assert(false);
+
+ else if (attrib->payload & KAP_SIZED_EOS)
+ {
+ align_evmpa_on_byte(epos);
+ result = true;
+ }
+
+ else if (attrib->payload & KAP_FIXED_CONTENT)
+ {
+ if (diff >= attrib->fixed_content.len)
+ {
+ align_evmpa_on_byte(epos);
+
+ copy_vmpa(&tmp, &epos->base);
+
+ data = g_binary_content_get_raw_access(work_area, &tmp, attrib->fixed_content.len);
+ assert(data != NULL);
+
+ result = (memcmp(data, attrib->fixed_content.data, attrib->fixed_content.len) == 0);
+
+ if (result)
+ diff = attrib->fixed_content.len;
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_BIT_FIELD_TYPE)
+ {
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = g_record_bit_field_new(attrib, work_area, epos, attrib->bf_size, endian);
+
+ result = (*record != NULL);
+
+ if (result)
+ advance_evmpa_bits(epos, attrib->bf_size);
+
+ }
+
+ else if (attrib->payload & KAP_BASIC_TYPE)
+ {
+ align_evmpa_on_byte(epos);
+
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ case BTP_UCHAR:
+ if (attrib->is_string)
+ {
+ if ((attrib->payload & KAP_SIZED) == 0)
+ result = g_kaitai_attribute_parse_terminated_bytes(attrib, locals,
+ work_area, &epos->base, record);
+ }
+ else
+ {
+ result = (diff >= 1);
+ diff = 1;
+ }
+ break;
+
+ case BTP_SHORT:
+ case BTP_USHORT:
+ result = (diff >= 2);
+ diff = 2;
+ break;
+
+ case BTP_INT:
+ case BTP_UINT:
+ case BTP_754R_32:
+ result = (diff >= 4);
+ diff = 4;
+ break;
+
+ case BTP_LONG_LONG:
+ case BTP_ULONG_LONG:
+ case BTP_754R_64:
+ result = (diff >= 8);
+ diff = 8;
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_USER_TYPE)
+ {
+ user_type = find_sub_type(locals, attrib->named_type);
+
+ if (user_type != NULL)
+ {
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(user_type),
+ locals, work_area, epos, record);
+
+ if (result)
+ /**
+ * Le type utilisateur dérive du type GKaitaiStruct, qui ne possède pas
+ * d'identifiant propre. La correspondance produite est ainsi nominalement
+ * anonyme, ce qui empêche toute résolution.
+ *
+ * Le rattachement de l'étiquette de l'attribut d'origine est donc forcée ici.
+ */
+ g_match_record_fix_creator(*record, G_KAITAI_PARSER(attrib));
+
+
+ g_object_unref(G_OBJECT(user_type));
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_DYNAMIC_TYPE)
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib->switchon), locals, work_area, epos, record);
+
+ else if (attrib->payload & KAP_SIZED)
+ {
+ /* Cas déjà traité en début de fonction */
+
+ }
+
+ /* Enregistrement de la correspondance */
+
+ if (result && *record == NULL)
+ {
+ /**
+ * A ce stade, la granularité des travaux est l'octet.
+ */
+ assert(epos->consumed_extra_bits == 0);
+
+ /**
+ * On choisit de laisser la création de correspondances nulles.
+ *
+ * Cela permet de disposer de la présence de champs valides, même vides
+ * (cf. "4.10.3. Repeat until condition is met")
+ */
+
+ /* if (diff > 0) */
+ {
+ result = g_kaitai_attribute_compute_maybe_terminated_range(attrib, locals, content,
+ &epos->base, &diff, &range);
+
+ if (result)
+ {
+ if (has_empty_size)
+ *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(attrib), content, &epos->base));
+
+ else
+ {
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = G_MATCH_RECORD(g_record_item_new(attrib, work_area, &range, endian));
+
+ if (*record != NULL)
+ advance_vmpa(&epos->base, diff);
+ else
+ result = false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Libération de zone de travail restreinte ? */
+
+ if (attrib->payload & KAP_SIZED)
+ {
+ /* Réalignement éventuel suite aux lectures dans la zone périmétrée... */
+ align_evmpa_on_byte(epos);
+
+ cur_diff = compute_vmpa_diff(get_mrange_addr(&work_range), &epos->base);
+
+ /* Pour GCC... */
+ max_size = get_mrange_length(&work_range);
+
+ if (cur_diff < max_size)
+ advance_vmpa(&epos->base, max_size - cur_diff);
+
+ assert(work_area != content);
+ g_object_unref(G_OBJECT(work_area));
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* pos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Extrait d'un contenu une série d'octets avec terminaison. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_parse_terminated_bytes(GKaitaiAttribute *attrib, const kaitai_scope_t *locals, GBinContent *content, vmpa2t *pos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t marker; /* Marqueur potentiel à tester */
+ vmpa2t iter; /* Tête de lecture courante */
+ vmpa2t end; /* Fin du parcours possible */
+ vmpa2t tmp; /* Position à mouvante */
+ phys_t diff; /* Avancée de lecture courante */
+ mrange_t range; /* Couverture appliquée */
+ SourceEndian endian; /* Boutisme à observer */
+
+ result = false;
+
+ /* Recherche du marqueur de fin */
+
+ marker.len = attrib->terminator.len;
+
+ copy_vmpa(&iter, pos);
+ g_binary_content_compute_end_pos(content, &end);
+
+ while (cmp_vmpa_by_phy(&iter, &end) < 0)
+ {
+ copy_vmpa(&tmp, &iter);
+
+ marker.data = (char *)g_binary_content_get_raw_access(content, &tmp, marker.len);
+ if (marker.data == NULL) break;
+
+ if (szmemcmp(&marker, &attrib->terminator) == 0)
+ {
+ result = true;
+ break;
+ }
+
+ advance_vmpa(&iter, 1);
+
+ }
+
+ /* Si la recherche a abouti */
+
+ if (result)
+ {
+ diff = compute_vmpa_diff(pos, &iter);
+
+ if (attrib->include)
+ diff += marker.len;
+
+ init_mrange(&range, pos, diff);
+
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = G_MATCH_RECORD(g_record_item_new(attrib, content, &range, endian));
+
+ copy_vmpa(pos, &iter);
+
+ if (attrib->consume)
+ advance_vmpa(pos, marker.len);
+
+ }
+
+ /* Sinon l'absence de marqueur est-elle tolérée ? */
+
+ else if (!attrib->eos_error)
+ {
+ diff = compute_vmpa_diff(pos, &end);
+
+ init_mrange(&range, pos, diff);
+
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = G_MATCH_RECORD(g_record_item_new(attrib, content, &range, endian));
+
+ copy_vmpa(pos, &end);
+
+ result = true;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* pos = tête de lecture courante. *
+* maxsize = taille maximale de la zone de correspondance. [OUT]*
+* range = zone de couverture à officialiser. [OUT] *
+* *
+* Description : Détermine la zone de couverture finale d'une correspondance. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttribute *attrib, const kaitai_scope_t *locals, const GBinContent *content, const vmpa2t *pos, phys_t *maxsize, mrange_t *range)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t marker; /* Marqueur potentiel à tester */
+ vmpa2t iter; /* Tête de lecture courante */
+ vmpa2t end; /* Fin du parcours possible */
+ vmpa2t tmp; /* Position à mouvante */
+ phys_t diff; /* Avancée de lecture courante */
+
+ if (attrib->terminator.data == NULL)
+ {
+ init_mrange(range, pos, *maxsize);
+ result = true;
+ }
+
+ else
+ {
+ result = false;
+
+ if (attrib->terminator.len > *maxsize)
+ goto exit;
+
+ /* Recherche du marqueur de fin */
+
+ marker.len = attrib->terminator.len;
+
+ copy_vmpa(&iter, pos);
+
+ copy_vmpa(&tmp, pos);
+ advance_vmpa(&tmp, *maxsize - marker.len);
+
+ while (cmp_vmpa_by_phy(&iter, &end) <= 0)
+ {
+ copy_vmpa(&tmp, &iter);
+
+ marker.data = (char *)g_binary_content_get_raw_access(content, &tmp, marker.len);
+ if (marker.data == NULL) break;
+
+ if (szmemcmp(&marker, &attrib->terminator) == 0)
+ {
+ result = true;
+ break;
+ }
+
+ advance_vmpa(&iter, 1);
+
+ }
+
+ /* Si la recherche a abouti */
+
+ if (result)
+ {
+ diff = compute_vmpa_diff(pos, &iter);
+
+ if (attrib->include)
+ init_mrange(range, pos, diff + marker.len);
+ else
+ init_mrange(range, pos, diff);
+
+ assert((diff + marker.len) <= *maxsize);
+
+ if (attrib->consume)
+ *maxsize = diff + marker.len;
+ else
+ *maxsize = diff;
+
+ }
+
+ /* Sinon l'absence de marqueur est-elle tolérée ? */
+
+ else if (!attrib->eos_error)
+ {
+ init_mrange(range, pos, *maxsize);
+ result = true;
+ }
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ resolved_value_t authorized; /* Validation des traitements */
+ GRecordList *list; /* Constitution d'une liste */
+ vmpa2t end; /* Position maximale du flux */
+ phys_t diff; /* Différentiel de positions */
+ GMatchRecord *child; /* Element de liste à intégrer */
+ resolved_value_t resolved; /* Valeur entière obtenue */
+ unsigned long long count; /* Nombre d'itérations à mener */
+ unsigned long long i; /* Boucle de parcours */
+ resolved_value_t loop; /* Poursuite des lectures ? */
+
+ if (attrib->repetition == KAR_NO_REPETITION)
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, record);
+
+ else
+ {
+ /* Lecture soumise à condition ? */
+
+ if (attrib->condition != NULL)
+ {
+ result = resolve_kaitai_expression_as_boolean(locals,
+ attrib->condition,
+ strlen(attrib->condition),
+ &authorized);
+
+ if (!result || !authorized.status)
+ goto exit;
+
+ }
+
+ list = g_record_list_new(attrib, content, &epos->base);
+
+ switch (attrib->repetition)
+ {
+ case KAR_END_OF_STREAM:
+
+ result = true;
+
+ g_binary_content_compute_end_pos(content, &end);
+ diff = compute_vmpa_diff(&epos->base, &end);
+
+ while (diff > 0)
+ {
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
+ if (!result) break;
+
+ g_record_list_add_record(list, child);
+ remember_last_record(locals, child);
+
+ diff = compute_vmpa_diff(&epos->base, &end);
+
+ }
+
+ break;
+
+ case KAR_EXPRESSION:
+
+ result = resolve_kaitai_expression_as_integer(locals,
+ attrib->repeat_controller,
+ strlen(attrib->repeat_controller),
+ &resolved);
+
+ if (resolved.type == GVT_UNSIGNED_INTEGER)
+ count = resolved.unsigned_integer;
+ else
+ {
+ assert(resolved.type == GVT_SIGNED_INTEGER);
+
+ if (resolved.signed_integer < 0)
+ {
+ result = false;
+ break;
+ }
+
+ count = resolved.signed_integer;
+
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
+ if (!result) break;
+
+ g_record_list_add_record(list, child);
+ remember_last_record(locals, child);
+
+ }
+
+ break;
+
+ case KAR_UNTIL:
+
+ do
+ {
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
+ if (!result) break;
+
+ g_record_list_add_record(list, child);
+ remember_last_record(locals, child);
+
+ result = resolve_kaitai_expression_as_boolean(locals,
+ attrib->repeat_controller,
+ strlen(attrib->repeat_controller),
+ &loop);
+ if (!result) break;
+
+ }
+ while (!loop.status);
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (!result) g_clear_object(&list);
+
+ *record = G_MATCH_RECORD(list);
+
+ }
+
+ exit:
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/attribute.h b/plugins/kaitai/parsers/attribute.h
new file mode 100644
index 0000000..9b43936
--- /dev/null
+++ b/plugins/kaitai/parsers/attribute.h
@@ -0,0 +1,158 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute.h - prototypes pour la spécification d'un attribut Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H
+#define _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <analysis/content.h>
+#include <analysis/types/basic.h>
+#include <plugins/yaml/node.h>
+
+
+#include "../expression.h"
+
+
+
+#define G_TYPE_KAITAI_ATTRIBUTE g_kaitai_attribute_get_type()
+#define G_KAITAI_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttribute))
+#define G_IS_KAITAI_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ATTRIBUTE))
+#define G_KAITAI_ATTRIBUTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttributeClass))
+#define G_IS_KAITAI_ATTRIBUTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ATTRIBUTE))
+#define G_KAITAI_ATTRIBUTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttributeClass))
+
+
+/* Spécification d'un attribut Kaitai (instance) */
+typedef struct _GKaitaiAttribute GKaitaiAttribute;
+
+/* Spécification d'un attribut Kaitai (classe) */
+typedef struct _GKaitaiAttributeClass GKaitaiAttributeClass;
+
+
+/* Type de charge associée à un attribut */
+typedef enum _KaitaiAttributePayload
+{
+ KAP_UNINITIALIZED = (0 << 0), /* Type non initialisé */
+
+ KAP_FIXED_CONTENT = (1 << 0), /* Contenu brut attendu */
+ KAP_BIT_FIELD_TYPE = (1 << 1), /* Champ d'un ou plusieurs bits*/
+ KAP_BASIC_TYPE = (1 << 2), /* Type prédéfini */
+ KAP_USER_TYPE = (1 << 3), /* Type personnalisé */
+ KAP_DYNAMIC_TYPE = (1 << 4), /* Type dynmatique */
+ KAP_SIZED = (1 << 5), /* Bourrage dimensionné */
+ KAP_SIZED_EOS = (1 << 6), /* Bourrage final */
+
+} KaitaiAttributePayload;
+
+/* Types de base reconnus par Kaitai */ /* TODO : REMME ? (car non utilisé) */
+typedef enum _KaitaiBasicType
+{
+ KBT_U1, /* Octet non signé */
+ KBT_U2, /* Mot de 16 bits non signé */
+ KBT_U2LE, /* Mot de 16 bits non signé */
+ KBT_U2BE, /* Mot de 16 bits non signé */
+ KBT_U4, /* Mot de 32 bits non signé */
+ KBT_U4LE, /* Mot de 32 bits non signé */
+ KBT_U4BE, /* Mot de 32 bits non signé */
+ KBT_U8, /* Mot de 64 bits non signé */
+ KBT_U8LE, /* Mot de 64 bits non signé */
+ KBT_U8BE, /* Mot de 64 bits non signé */
+ KBT_S1, /* Octet signé */
+ KBT_S2, /* Mot de 16 bits signé */
+ KBT_S2LE, /* Mot de 16 bits signé */
+ KBT_S2BE, /* Mot de 16 bits signé */
+ KBT_S4, /* Mot de 32 bits signé */
+ KBT_S4LE, /* Mot de 32 bits signé */
+ KBT_S4BE, /* Mot de 32 bits signé */
+ KBT_S8, /* Mot de 64 bits signé */
+ KBT_S8LE, /* Mot de 64 bits signé */
+ KBT_S8BE, /* Mot de 64 bits signé */
+ KBT_F4, /* Flottant sur 32 bits */
+ KBT_F4BE, /* Flottant sur 32 bits */
+ KBT_F4LE, /* Flottant sur 32 bits */
+ KBT_F8, /* Flottant sur 64 bits */
+ KBT_F8BE, /* Flottant sur 64 bits */
+ KBT_F8LE, /* Flottant sur 64 bits */
+ KBT_STR, /* Chaîne de caractères */
+ KBT_STRZ, /* Chaîne de caractères + '\0' */
+
+} KaitaiBasicType;
+
+/* Formes de répétition d'une lecture d'attribut */
+typedef enum _KaitaiAttributeRepetition
+{
+ KAR_NO_REPETITION, /* Aucune forme de répétition */
+
+ KAR_END_OF_STREAM, /* Redites autant que possible */
+ KAR_EXPRESSION, /* Répétitions selon quantité */
+ KAR_UNTIL, /* Répétitions sous condition */
+
+} KaitaiAttributeRepetition;
+
+
+/* Indique le type défini pour un attribut de la spécification Kaitai. */
+GType g_kaitai_attribute_get_type(void);
+
+/* Construit un lecteur d'attribut Kaitai. */
+GKaitaiAttribute *g_kaitai_attribute_new(GYamlNode *);
+
+/* Dérive un lecteur d'attribut Kaitai pour un type utilisateur. */
+GKaitaiAttribute *g_kaitai_attribute_dup_for_user_type(const GKaitaiAttribute *, const char *);
+
+/* Indique l'étiquette à utiliser pour identifier un attribut. */
+const char *g_kaitai_attribute_get_label(const GKaitaiAttribute *);
+
+/* Indique la désignation brute d'un identifiant Kaitai. */
+const char *g_kaitai_attribute_get_raw_id(const GKaitaiAttribute *);
+
+/* Indique la désignation originelle d'un identifiant Kaitai. */
+const char *g_kaitai_attribute_get_original_id(const GKaitaiAttribute *);
+
+/* Fournit une éventuelle documentation concernant l'attribut. */
+const char *g_kaitai_attribute_get_doc(const GKaitaiAttribute *);
+
+/* Indique la nature de la charge représentée par l'attribut. */
+KaitaiAttributePayload g_kaitai_attribute_get_payload(const GKaitaiAttribute *);
+
+/* Précise un éventuel type de base reconnu par le lecteur. */
+bool g_kaitai_attribute_get_basic_type(const GKaitaiAttribute *, BaseType *, bool *);
+
+/* Lit les octets d'une chaîne représentée. */
+bool g_kaitai_attribute_read_truncated_bytes(const GKaitaiAttribute *, const GBinContent *, const mrange_t *, bin_t **, size_t *);
+
+/* Détermine si l'attribue porte une valeur entière signée. */
+bool g_kaitai_attribute_handle_signed_integer(const GKaitaiAttribute *);
+
+/* Lit la valeur d'un élément Kaitai entier représenté. */
+bool g_kaitai_attribute_read_value(const GKaitaiAttribute *, const GBinContent *, const mrange_t *, SourceEndian, resolved_value_t *);
+
+/* Lit la valeur d'un champ de bits Kaitai représenté. */
+bool g_kaitai_attribute_read_bit_field_value(const GKaitaiAttribute *, const GBinContent *, const ext_vmpa_t *, uint8_t, SourceEndian, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H */
diff --git a/plugins/kaitai/parsers/enum-int.h b/plugins/kaitai/parsers/enum-int.h
new file mode 100644
index 0000000..b62ae41
--- /dev/null
+++ b/plugins/kaitai/parsers/enum-int.h
@@ -0,0 +1,79 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum-int.h - prototypes internes pour la gestion des énumérations Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSERS_ENUM_INT_H
+#define PLUGINS_KAITAI_PARSERS_ENUM_INT_H
+
+
+#include "enum.h"
+
+
+
+/* ------------------------- MANIPULATION D'UNE ENUMERATION ------------------------- */
+
+
+/* Mémorisation d'une valeur d'énumération */
+typedef struct _enum_value_t
+{
+ resolved_value_t value; /* Valeur entière représentée */
+ char *label; /* Elément associé à une valeur*/
+ char *doc; /* Eventuelle documentation */
+
+} enum_value_t;
+
+
+
+/* ----------------------- GESTION D'UN GROUPE D'ENUMERATIONS ----------------------- */
+
+
+/* Définition d'un ensemble d'énumérations Kaitai (instance) */
+struct _GKaitaiEnum
+{
+ GObject parent; /* A laisser en premier */
+
+ char *name; /* Désignation de l'énumération*/
+
+ enum_value_t **cases_v2l; /* Choix indexés par valeur */
+ size_t cases_v2l_count; /* Quantité de ces choix */
+
+ enum_value_t **cases_l2v; /* Choix indexés par étiquette */
+ size_t cases_l2v_count; /* Quantité de ces choix */
+
+ enum_value_t *defcase; /* Choix par défaut ou NULL */
+
+};
+
+/* Définition d'un ensemble d'énumérations Kaitai (classe) */
+struct _GKaitaiEnumClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un groupe d'énumérations Kaitai. */
+bool g_kaitai_enum_create(GKaitaiEnum *, GYamlNode *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_ENUM_INT_H */
diff --git a/plugins/kaitai/parsers/enum.c b/plugins/kaitai/parsers/enum.c
new file mode 100644
index 0000000..27e5660
--- /dev/null
+++ b/plugins/kaitai/parsers/enum.c
@@ -0,0 +1,765 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum.h - gestion des énumérations Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "enum.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include <common/extstr.h>
+#include <common/sort.h>
+#include <core/logs.h>
+#include <plugins/yaml/collection.h>
+#include <plugins/yaml/pair.h>
+
+
+#include "enum-int.h"
+
+
+
+/* ------------------------- MANIPULATION D'UNE ENUMERATION ------------------------- */
+
+
+/* Construit une valeur d'énumération à partir d'indications. */
+static enum_value_t *build_enum_value(GYamlNode *, bool *);
+
+/* Supprime de la mémoire une valeur d'énumération. */
+static void delete_enum_value(enum_value_t *);
+
+/* Etablit la comparaison entre deux valeurs d'énumération. */
+static int compare_enum_values_by_value(const enum_value_t **, const enum_value_t **);
+
+/* Etablit la comparaison entre deux noms d'énumération. */
+static int compare_enum_values_by_label(const enum_value_t **, const enum_value_t **);
+
+/* Etablit la comparaison entre deux noms d'énumération. */
+static int compare_enum_values_by_sized_label(const sized_string_t *, const enum_value_t **);
+
+
+
+/* ----------------------- GESTION D'UN GROUPE D'ENUMERATIONS ----------------------- */
+
+
+/* Initialise la classe des groupes d'énumérations Kaitai. */
+static void g_kaitai_enum_class_init(GKaitaiEnumClass *);
+
+/* Initialise un groupe d'énumérations Kaitai. */
+static void g_kaitai_enum_init(GKaitaiEnum *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_enum_dispose(GKaitaiEnum *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_enum_finalize(GKaitaiEnum *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION D'UNE ENUMERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud Yaml à venir lire. *
+* defcase = indique si une valeur par défaut est visée. [OUT] *
+* *
+* Description : Construit une valeur d'énumération à partir d'indications. *
+* *
+* Retour : Structure de valeur mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static enum_value_t *build_enum_value(GYamlNode *node, bool *defcase)
+{
+ enum_value_t *result; /* Valeur à retourner */
+ const char *key; /* Clef d'une énumération */
+ kaitai_scope_t fake; /* Contexte de circonstance */
+ resolved_value_t kval; /* Valeur à indexer */
+ const char *value; /* Valeur Yaml particulière */
+ char *path; /* Chemin d'accès suivant */
+ GYamlNode *children; /* Sous-noeuds rattachés */
+ GYamlNode *sub; /* Sous-noeud à considérer */
+
+ result = NULL;
+
+ *defcase = false;
+
+ if (!G_IS_YAML_PAIR(node))
+ goto bad_node;
+
+ /* Identification de la valeur énumérative */
+
+ key = g_yaml_pair_get_key(G_YAML_PAIR(node));
+
+ if (strcmp(key, "_") == 0)
+ {
+ /**
+ * Exemple de choix par défaut :
+ * http://doc.kaitai.io/user_guide.html#tlv
+ */
+
+ kval.type = GVT_UNSIGNED_INTEGER;
+ kval.unsigned_integer = ~0llu;
+
+ *defcase = true;
+
+ }
+
+ else
+ {
+ fake.meta = NULL;
+ fake.root = NULL;
+ fake.parent = NULL;
+ fake.last = NULL;
+
+ if (!resolve_kaitai_expression_as_integer(&fake, key, strlen(key), &kval))
+ goto bad_node;
+
+ }
+
+ /* Récupération des éléments associés à la valeur */
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ result = malloc(sizeof(enum_value_t));
+
+ result->value = kval;
+ result->label = strdup(value);
+ result->doc = NULL;
+
+ }
+ else
+ {
+ /**
+ * Les énumérations peuvent comporter un commentaire associé
+ * sous forme d'un élément de documentation complémentaire.
+ *
+ * Cf. http://doc.kaitai.io/user_guide.html#verbose-enums
+ */
+
+ asprintf(&path, "/%s/", key);
+ children = g_yaml_node_find_first_by_path(node, path);
+ free(path);
+
+ if (!G_IS_YAML_COLLEC(children))
+ goto bad_value;
+
+ /* Identifiant */
+
+ sub = g_yaml_node_find_first_by_path(children, "/id");
+
+ if (!G_IS_YAML_PAIR(sub))
+ goto bad_sub_value;
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(sub));
+
+ if (value == NULL)
+ goto bad_sub_value;
+
+ result = malloc(sizeof(enum_value_t));
+
+ result->value = kval;
+ result->label = strdup(value);
+ result->doc = NULL;
+
+ g_object_unref(G_OBJECT(sub));
+
+ /* Documentation */
+
+ sub = g_yaml_node_find_first_by_path(children, "/doc");
+
+ if (!G_IS_YAML_PAIR(sub))
+ goto bad_sub_value;
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(sub));
+
+ if (value == NULL)
+ goto bad_sub_value;
+
+ result->doc = strdup(value);
+
+ bad_sub_value:
+
+ g_clear_object(&sub);
+
+ g_object_unref(G_OBJECT(children));
+
+ bad_value:
+
+ ;
+
+ }
+
+ bad_node:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur à traiter. *
+* *
+* Description : Supprime de la mémoire une valeur d'énumération. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void delete_enum_value(enum_value_t *value)
+{
+ EXIT_RESOLVED_VALUE(value->value);
+
+ free(value->label);
+
+ if (value->doc != NULL)
+ free(value->doc);
+
+ free(value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premières informations à consulter. *
+* b = secondes informations à consulter. *
+* *
+* Description : Etablit la comparaison entre deux valeurs d'énumération. *
+* *
+* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_enum_values_by_value(const enum_value_t **a, const enum_value_t **b)
+{
+ int result; /* Bilan à retourner */
+ const resolved_value_t *value_a; /* Raccouri d'accès pour a */
+ const resolved_value_t *value_b; /* Raccouri d'accès pour b */
+
+ value_a = &(*a)->value;
+ value_b = &(*b)->value;
+
+ if (value_a->type == GVT_UNSIGNED_INTEGER && value_b->type == GVT_UNSIGNED_INTEGER)
+ result = sort_unsigned_long_long(value_a->unsigned_integer, value_b->unsigned_integer);
+
+ else if (value_a->type == GVT_UNSIGNED_INTEGER && value_b->type == GVT_UNSIGNED_INTEGER)
+ result = sort_signed_long_long(value_a->signed_integer, value_b->signed_integer);
+
+ else
+ {
+ /**
+ * Le code Python a deux options : soit fournir un équivalent à la
+ * structure resolved_value_t lors de l'appel correspondant à cette
+ * fonction compare_enum_values_by_value(), soit fournir un nombre
+ * directement.
+ *
+ * Comme PyArg_ParseTuple() est obligée de trancher entre non-signé
+ * et signé, le parti est pris de considérer le non-signé coté Python.
+ * On s'adapte en conséquence ici.
+ *
+ * La structure resolved_value_t est une union, donc les valeurs
+ * sont potientiellement au mauvais format mais bien présentes.
+ */
+
+ /**
+ * result = sort_unsigned_long_long(value_a->type, value_b->type);
+ */
+
+ result = sort_unsigned_long_long(value_a->unsigned_integer, value_b->unsigned_integer);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premières informations à consulter. *
+* b = secondes informations à consulter. *
+* *
+* Description : Etablit la comparaison entre deux noms d'énumération. *
+* *
+* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_enum_values_by_label(const enum_value_t **a, const enum_value_t **b)
+{
+ int result; /* Bilan à retourner */
+
+ result = strcmp((*a)->label, (*b)->label);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : l = premières informations à consulter. *
+* b = secondes informations à consulter. *
+* *
+* Description : Etablit la comparaison entre deux noms d'énumération. *
+* *
+* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_enum_values_by_sized_label(const sized_string_t *l, const enum_value_t **b)
+{
+ int result; /* Bilan à retourner */
+
+ result = strncmp(l->data, (*b)->label, l->len); // FIXME
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION D'UN GROUPE D'ENUMERATIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un ensemble d'énumérations Kaitai. */
+G_DEFINE_TYPE(GKaitaiEnum, g_kaitai_enum, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des groupes d'énumérations Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_class_init(GKaitaiEnumClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_enum_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_enum_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = instance à initialiser. *
+* *
+* Description : Initialise un groupe d'énumérations Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_init(GKaitaiEnum *kenum)
+{
+ kenum->name = NULL;
+
+ kenum->cases_v2l = NULL;
+ kenum->cases_v2l_count = 0;
+
+ kenum->cases_l2v = NULL;
+ kenum->cases_l2v_count = 0;
+
+ kenum->defcase = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_dispose(GKaitaiEnum *kenum)
+{
+ G_OBJECT_CLASS(g_kaitai_enum_parent_class)->dispose(G_OBJECT(kenum));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_finalize(GKaitaiEnum *kenum)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (kenum->name != NULL)
+ free(kenum->name);
+
+ for (i = 0; i < kenum->cases_v2l_count; i++)
+ delete_enum_value(kenum->cases_v2l[i]);
+
+ if (kenum->cases_v2l != NULL)
+ free(kenum->cases_v2l);
+
+ if (kenum->cases_l2v != NULL)
+ free(kenum->cases_l2v);
+
+ if (kenum->defcase != NULL)
+ delete_enum_value(kenum->defcase);
+
+ G_OBJECT_CLASS(g_kaitai_enum_parent_class)->finalize(G_OBJECT(kenum));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Construit un groupe d'énumérations Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiEnum *g_kaitai_enum_new(GYamlNode *parent)
+{
+ GKaitaiEnum *result; /* Identifiant à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_ENUM, NULL);
+
+ if (!g_kaitai_enum_create(result, parent))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Met en place un groupe d'énumérations Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_enum_create(GKaitaiEnum *kenum, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ char *path; /* Chemin des valeurs */
+ GYamlNode *collec; /* Liste de noeuds à traiter */
+ GYamlNode **nodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+ bool defcase; /* Définition par défaut ? */
+ enum_value_t *value; /* Valeur énumérative nouvelle */
+ bool found; /* Présence de partage existant*/
+ size_t index; /* Indice du point d'insertion */
+
+ result = false;
+
+ /* Récupération du nom */
+
+ if (!G_IS_YAML_PAIR(parent)) goto exit;
+
+ kenum->name = strdup(g_yaml_pair_get_key(G_YAML_PAIR(parent)));
+
+ /* Association de valeurs */
+
+ path = strdup("/");
+ path = stradd(path, kenum->name);
+ path = stradd(path, "/");
+
+ collec = g_yaml_node_find_first_by_path(parent, path);
+
+ free(path);
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ value = build_enum_value(nodes[i], &defcase);
+ if (value == NULL) break;
+
+ if (defcase)
+ {
+ if (kenum->defcase != NULL)
+ {
+ log_variadic_message(LMT_WARNING,
+ _("Multiple definition of the defaut value for the enumeration '%s'"),
+ kenum->name);
+
+ delete_enum_value(value);
+ break;
+
+ }
+
+ /**
+ * Exemple de choix par défaut :
+ * http://doc.kaitai.io/user_guide.html#tlv
+ */
+
+ kenum->defcase = value;
+
+ }
+
+ else
+ {
+ kenum->cases_v2l = qinsert(kenum->cases_v2l, &kenum->cases_v2l_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_value, &value);
+
+ found = bsearch_index(&value, kenum->cases_l2v, kenum->cases_l2v_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_label, &index);
+
+ if (found)
+ log_variadic_message(LMT_WARNING,
+ _("Multiple occurrence of the label %s in the enumeration '%s'"),
+ value->label, kenum->name);
+
+ else
+ kenum->cases_l2v = _qinsert(kenum->cases_l2v, &kenum->cases_l2v_count, sizeof(enum_value_t *),
+ &value, index);
+
+ }
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
+
+ result = (i == count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ free(nodes);
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* *
+* Description : Fournit le nom principal d'une énumération. *
+* *
+* Retour : Désignation de l'énumération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_enum_get_name(const GKaitaiEnum *kenum)
+{
+ const char *result; /* Chaîne à retourner */
+
+ result = kenum->name;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* label = étiquette de l'élément constant à traduire. *
+* value = valeur concrète correspondante. [OUT] *
+* *
+* Description : Traduit une étiquette brute en constante d'énumération. *
+* *
+* Retour : Bilan de la conversion. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_enum_find_value(const GKaitaiEnum *kenum, const sized_string_t *label, resolved_value_t *value)
+{
+ bool result; /* Présence à retourner */
+ size_t index; /* Indice du point d'insertion */
+
+ result = bsearch_index(label, kenum->cases_l2v, kenum->cases_l2v_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_sized_label, &index);
+
+ if (result)
+ *value = kenum->cases_l2v[index]->value;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* value = valeur concrète à transformer. *
+* prefix = détermine l'ajout d'un préfixe éventuel. *
+* *
+* Description : Traduit une constante d'énumération en étiquette brute. *
+* *
+* Retour : Désignation ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_kaitai_enum_find_label(const GKaitaiEnum *kenum, const resolved_value_t *value, bool prefix)
+{
+ char *result; /* Etiquette à retourner */
+ enum_value_t faked; /* Copie d'élément recherché */
+ bool found; /* Présence de partage existant*/
+ size_t index; /* Indice du point d'insertion */
+ const enum_value_t *item; /* Elément retrouvé par valeur */
+
+ faked.value = *value;
+
+ found = bsearch_index(&faked, kenum->cases_v2l, kenum->cases_v2l_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_value, &index);
+
+ if (found)
+ item = kenum->cases_l2v[index];
+ else
+ item = kenum->defcase;
+
+ if (item != NULL)
+ {
+ if (prefix)
+ asprintf(&result, "%s::%s", kenum->name, item->label);
+ else
+ result = strdup(item->label);
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* value = valeur concrète à transformer. *
+* *
+* Description : Traduit une constante d'énumération en documentation. *
+* *
+* Retour : Documentation associée à la valeur indiquée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_kaitai_enum_find_documentation(const GKaitaiEnum *kenum, const resolved_value_t *value)
+{
+ char *result; /* Documentation à retourner */
+ enum_value_t faked; /* Copie d'élément recherché */
+ bool found; /* Présence de partage existant*/
+ size_t index; /* Indice du point d'insertion */
+ const enum_value_t *item; /* Elément retrouvé par valeur */
+
+ faked.value = *value;
+
+ found = bsearch_index(&faked, kenum->cases_v2l, kenum->cases_v2l_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_value, &index);
+
+ if (found)
+ item = kenum->cases_l2v[index];
+ else
+ item = kenum->defcase;
+
+ if (item != NULL)
+ result = strdup(item->doc);
+ else
+ result = NULL;
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/enum.h b/plugins/kaitai/parsers/enum.h
new file mode 100644
index 0000000..9e4bf2a
--- /dev/null
+++ b/plugins/kaitai/parsers/enum.h
@@ -0,0 +1,76 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum.h - prototypes pour la gestion des énumérations Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_ENUM_H
+#define _PLUGINS_KAITAI_PARSERS_ENUM_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+
+#include <common/szstr.h>
+#include <plugins/yaml/node.h>
+
+
+#include "../expression.h"
+
+
+
+#define G_TYPE_KAITAI_ENUM g_kaitai_enum_get_type()
+#define G_KAITAI_ENUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ENUM, GKaitaiEnum))
+#define G_IS_KAITAI_ENUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ENUM))
+#define G_KAITAI_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ENUM, GKaitaiEnumClass))
+#define G_IS_KAITAI_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ENUM))
+#define G_KAITAI_ENUM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ENUM, GKaitaiEnumClass))
+
+
+/* Définition d'un ensemble d'énumérations Kaitai (instance) */
+typedef struct _GKaitaiEnum GKaitaiEnum;
+
+/* Définition d'un ensemble d'énumérations Kaitai (classe) */
+typedef struct _GKaitaiEnumClass GKaitaiEnumClass;
+
+
+/* Indique le type défini pour un ensemble d'énumérations Kaitai. */
+GType g_kaitai_enum_get_type(void);
+
+/* Construit un groupe d'énumérations Kaitai. */
+GKaitaiEnum *g_kaitai_enum_new(GYamlNode *);
+
+/* Fournit le nom principal d'une énumération. */
+const char *g_kaitai_enum_get_name(const GKaitaiEnum *);
+
+/* Traduit une étiquette brute en constante d'énumération. */
+bool g_kaitai_enum_find_value(const GKaitaiEnum *, const sized_string_t *, resolved_value_t *);
+
+/* Traduit une constante d'énumération en étiquette brute. */
+char *g_kaitai_enum_find_label(const GKaitaiEnum *, const resolved_value_t *, bool);
+
+/* Traduit une constante d'énumération en documentation. */
+char *g_kaitai_enum_find_documentation(const GKaitaiEnum *, const resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_ENUM_H */
diff --git a/plugins/kaitai/parsers/instance-int.h b/plugins/kaitai/parsers/instance-int.h
new file mode 100644
index 0000000..6f098b4
--- /dev/null
+++ b/plugins/kaitai/parsers/instance-int.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance-int.h - prototypes pour les spécifications internes d'une instance Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H
+#define _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H
+
+
+#include "attribute-int.h"
+#include "instance.h"
+
+
+
+/* Spécification d'une instance Kaitai (instance) */
+struct _GKaitaiInstance
+{
+ GKaitaiAttribute parent; /* A laisser en premier */
+
+ char *name; /* Nom attribué à l'instance */
+
+ char *io; /* Contenu binaire forcé */
+ char *pos; /* Position forcée */
+ char *value; /* Formule pour calcul */
+
+};
+
+/* Spécification d'une instance Kaitai (classe) */
+struct _GKaitaiInstanceClass
+{
+ GKaitaiAttributeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un lecteur d'instance Kaitai. */
+bool g_kaitai_instance_create(GKaitaiInstance *, GYamlNode *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H */
diff --git a/plugins/kaitai/parsers/instance.c b/plugins/kaitai/parsers/instance.c
new file mode 100644
index 0000000..d62c1f6
--- /dev/null
+++ b/plugins/kaitai/parsers/instance.c
@@ -0,0 +1,503 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance.c - spécification d'une instance Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "instance.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include <plugins/yaml/pair.h>
+
+
+#include "instance-int.h"
+#include "../expression.h"
+#include "../records/delayed.h"
+
+
+
+/* -------------------- CORRESPONDANCE ENTRE INSTANCE ET BINAIRE -------------------- */
+
+
+/* Initialise la classe des instances de spécification Kaitai. */
+static void g_kaitai_instance_class_init(GKaitaiInstanceClass *);
+
+/* Initialise une instance de spécification Kaitai. */
+static void g_kaitai_instance_init(GKaitaiInstance *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_instance_dispose(GKaitaiInstance *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_instance_finalize(GKaitaiInstance *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_instance_parse_content(GKaitaiInstance *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CORRESPONDANCE ENTRE INSTANCE ET BINAIRE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une instance de la spécification Kaitai. */
+G_DEFINE_TYPE(GKaitaiInstance, g_kaitai_instance, G_TYPE_KAITAI_ATTRIBUTE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des instances de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_class_init(GKaitaiInstanceClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Ancêtre parent de la classe */
+ GKaitaiAttributeClass *attrib; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_instance_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_instance_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_instance_parse_content;
+
+ attrib = G_KAITAI_ATTRIBUTE_CLASS(klass);
+
+ attrib->get_label = (get_attribute_label_fc)g_kaitai_instance_get_name;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = instance à initialiser. *
+* *
+* Description : Initialise une instance de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_init(GKaitaiInstance *inst)
+{
+ inst->name = NULL;
+
+ inst->io = NULL;
+ inst->pos = NULL;
+ inst->value = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_dispose(GKaitaiInstance *inst)
+{
+ G_OBJECT_CLASS(g_kaitai_instance_parent_class)->dispose(G_OBJECT(inst));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_finalize(GKaitaiInstance *inst)
+{
+ if (inst->name != NULL)
+ free(inst->name);
+
+ if (inst->io != NULL)
+ free(inst->io);
+
+ if (inst->pos != NULL)
+ free(inst->pos);
+
+ if (inst->value != NULL)
+ free(inst->value);
+
+ G_OBJECT_CLASS(g_kaitai_instance_parent_class)->finalize(G_OBJECT(inst));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'instance à constituer. *
+* *
+* Description : Construit un lecteur d'instance Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiInstance *g_kaitai_instance_new(GYamlNode *parent)
+{
+ GKaitaiInstance *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_INSTANCE, NULL);
+
+ if (!g_kaitai_instance_create(result, parent))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à initialiser pleinement. *
+* parent = noeud Yaml contenant l'instance à constituer. *
+* *
+* Description : Met en place un lecteur d'instance Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_instance_create(GKaitaiInstance *inst, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ const char *name; /* Désignation du type */
+ char *sub_path; /* Chemin d'accès suivant */
+ GYamlNode *sub; /* Contenu Yaml d'un type */
+ GYamlNode *node; /* Noeud particulier présent */
+ const char *value; /* Valeur Yaml particulière */
+
+ result = false;
+
+ /* Extraction du nom */
+
+ if (!G_IS_YAML_PAIR(parent))
+ goto exit;
+
+ name = g_yaml_pair_get_key(G_YAML_PAIR(parent));
+
+ inst->name = strdup(name);
+
+ /* Extraction des bases du type */
+
+ asprintf(&sub_path, "/%s/", name);
+ sub = g_yaml_node_find_first_by_path(parent, sub_path);
+ free(sub_path);
+
+ if (sub == NULL)
+ goto exit;
+
+ result = g_kaitai_attribute_create(G_KAITAI_ATTRIBUTE(inst), sub, false);
+
+ /* Eventuel contenu imposé */
+
+ node = g_yaml_node_find_first_by_path(sub, "/io");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_loading;
+ }
+
+ inst->io = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Eventuelle positiion imposée */
+
+ node = g_yaml_node_find_first_by_path(sub, "/pos");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_loading;
+ }
+
+ inst->pos = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Eventuelle formule de calcul d'une valeur */
+
+ node = g_yaml_node_find_first_by_path(sub, "/value");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ inst->value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node));
+
+ g_object_unref(G_OBJECT(node));
+
+ if (inst->value == NULL)
+ goto bad_loading;
+
+ }
+
+ bad_loading:
+
+ g_object_unref(G_OBJECT(sub));
+
+ exit:
+
+ if (result)
+ result = (inst->pos != NULL || inst->value != NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à consulter. *
+* *
+* Description : Indique le nom attribué à une instance Kaitai. *
+* *
+* Retour : Désignation pointant l'instance. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_instance_get_name(const GKaitaiInstance *inst)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = inst->name;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à consulter. *
+* locals = variables locales pour les résolutions de types. *
+* content = contenu binaire lié à la correspondance. *
+* *
+* Description : Détermine la valeur effective d'un élément Kaitai dynamique. *
+* *
+* Retour : valeur à sauvegarder sous une forme générique. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *g_kaitai_instance_compute_real_record(const GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content)
+{
+ GMatchRecord *result; /* Enregistrement à retourner */
+ GBinContent *work_area; /* Aire de travail */
+ GKaitaiStream *stream; /* Flux de données pour Kaitai */
+ bool status; /* Bilan intermédiaire */
+ vmpa2t forced_pos; /* Tete de lecture constituée */
+ resolved_value_t offset; /* Position à adopter */
+ GKaitaiParserClass *class; /* Classe parente à solliciter */
+ ext_vmpa_t epos; /* Tête de lecture complète */
+
+ result = NULL;
+
+ if (inst->value == NULL)
+ {
+ /* Contenu particulier */
+
+ if (inst->io == NULL)
+ work_area = content;
+
+ else
+ {
+ status = resolve_kaitai_expression_as_stream(locals, inst->io, strlen(inst->io), &stream);
+ if (!status) goto exit;
+
+ work_area = g_kaitai_stream_get_content(stream);
+
+ g_object_unref(G_OBJECT(stream));
+
+ }
+
+ /* Tête de lecture */
+
+ g_binary_content_compute_start_pos(work_area, &forced_pos);
+
+ status = resolve_kaitai_expression_as_integer(locals, inst->pos, strlen(inst->pos), &offset);
+ if (!status) goto exit_with_content;
+
+ if (offset.type == GVT_UNSIGNED_INTEGER)
+ advance_vmpa(&forced_pos, offset.unsigned_integer);
+
+ else
+ {
+ assert(offset.type == GVT_SIGNED_INTEGER);
+
+ if (offset.signed_integer < 0)
+ {
+ status = false;
+ goto exit_with_content;
+ }
+
+ advance_vmpa(&forced_pos, offset.signed_integer);
+
+ }
+
+ /* Lecture */
+
+ class = G_KAITAI_PARSER_CLASS(g_kaitai_instance_parent_class);
+
+ init_evmpa_from_vmpa(&epos, &forced_pos);
+
+ class->parse(G_KAITAI_PARSER(inst), locals, work_area, &epos, &result);
+
+ exit_with_content:
+
+ if (work_area != content)
+ g_object_unref(G_OBJECT(work_area));
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à consulter. *
+* locals = variables locales pour les résolutions de types. *
+* value = valeur à sauvegarder sous une forme générique. [OUT]*
+* *
+* Description : Détermine la valeur d'un élément Kaitai entier calculé. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_instance_compute_value(const GKaitaiInstance *inst, const kaitai_scope_t *locals, resolved_value_t *value)
+{
+ bool result; /* Bilan à retourner */
+
+ if (inst->value == NULL)
+ result = false;
+
+ else
+ result = resolve_kaitai_expression_as_any(locals,
+ inst->value,
+ strlen(inst->value),
+ value);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+
+ *record = G_MATCH_RECORD(g_record_delayed_new(inst, locals, inst->value == NULL ? content : NULL));
+
+ result = (*record != NULL);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/instance.h b/plugins/kaitai/parsers/instance.h
new file mode 100644
index 0000000..4594137
--- /dev/null
+++ b/plugins/kaitai/parsers/instance.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance.h - prototypes pour la spécification d'une instance Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_INSTANCE_H
+#define _PLUGINS_KAITAI_PARSERS_INSTANCE_H
+
+
+#include <glib-object.h>
+
+
+#include <plugins/yaml/node.h>
+
+
+#include "../expression.h"
+#include "../scope.h"
+
+
+
+#define G_TYPE_KAITAI_INSTANCE g_kaitai_instance_get_type()
+#define G_KAITAI_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_INSTANCE, GKaitaiInstance))
+#define G_IS_KAITAI_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_INSTANCE))
+#define G_KAITAI_INSTANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_INSTANCE, GKaitaiInstanceClass))
+#define G_IS_KAITAI_INSTANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_INSTANCE))
+#define G_KAITAI_INSTANCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_INSTANCE, GKaitaiInstanceClass))
+
+
+/* Spécification d'une instance Kaitai (instance) */
+typedef struct _GKaitaiInstance GKaitaiInstance;
+
+/* Spécification d'une instance Kaitai (classe) */
+typedef struct _GKaitaiInstanceClass GKaitaiInstanceClass;
+
+
+/* Indique le type défini pour une instance de la spécification Kaitai. */
+GType g_kaitai_instance_get_type(void);
+
+/* Construit un lecteur d'instance Kaitai. */
+GKaitaiInstance *g_kaitai_instance_new(GYamlNode *);
+
+/* Indique le nom attribué à une instance Kaitai. */
+const char *g_kaitai_instance_get_name(const GKaitaiInstance *);
+
+/* Détermine la valeur effective d'un élément Kaitai dynamique. */
+GMatchRecord *g_kaitai_instance_compute_real_record(const GKaitaiInstance *, const kaitai_scope_t *, GBinContent *);
+
+/* Détermine la valeur d'un élément Kaitai entier calculé. */
+bool g_kaitai_instance_compute_value(const GKaitaiInstance *, const kaitai_scope_t *, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_INSTANCE_H */
diff --git a/plugins/kaitai/parsers/meta-int.h b/plugins/kaitai/parsers/meta-int.h
new file mode 100644
index 0000000..5fe9174
--- /dev/null
+++ b/plugins/kaitai/parsers/meta-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * meta-int.h - prototypes internes pour la description globale d'une définition Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSERS_META_INT_H
+#define PLUGINS_KAITAI_PARSERS_META_INT_H
+
+
+#include "meta.h"
+
+
+
+/* Description globale d'une définition Kaitai (instance) */
+struct _GKaitaiMeta
+{
+ GObject parent; /* A laisser en premier */
+
+ char *id; /* Identifiant attribué */
+ char *title; /* Désignation de la définition*/
+
+ SourceEndian endian; /* Boutisme par défaut */
+
+ char **dependencies; /* Définitions à importer */
+ size_t dep_count; /* Nombre de ces définitions */
+
+};
+
+/* Description globale d'une définition Kaitai (classe) */
+struct _GKaitaiMetaClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une description globale Kaitai. */
+bool g_kaitai_meta_create(GKaitaiMeta *, GYamlNode *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_META_INT_H */
diff --git a/plugins/yaml/line.c b/plugins/kaitai/parsers/meta.c
index 26a1012..132eefd 100644
--- a/plugins/yaml/line.c
+++ b/plugins/kaitai/parsers/meta.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * line.c - ligne de contenu Yaml
+ * meta.c - description globale d'une définition Kaitai
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,66 +21,44 @@
*/
-#include "line.h"
+#include "meta.h"
+#include <assert.h>
#include <malloc.h>
#include <string.h>
-#include <core/logs.h>
+#include <plugins/yaml/pair.h>
+#include "meta-int.h"
-/* Ligne de données au format Yaml (instance) */
-struct _GYamlLine
-{
- GObject parent; /* A laisser en premier */
-
- char *raw; /* Contenu brut de la ligne */
- size_t number; /* Indice associé */
-
- size_t indent; /* Niveau d'indentation */
- bool is_list_item; /* Elément de liste ? */
-
- const char *payload; /* Charge utile du contenu */
-
- char *key; /* Clef de la ligne Yaml */
- char *value; /* Valeyr de la ligne Yaml */
-
-};
-
-/* Ligne de données au format Yaml (classe) */
-struct _GYamlLineClass
-{
- GObjectClass parent; /* A laisser en premier */
-};
+/* Initialise la classe des descriptions globales Kaitai. */
+static void g_kaitai_meta_class_init(GKaitaiMetaClass *);
-/* Initialise la classe des lignes de contenu Yaml. */
-static void g_yaml_line_class_init(GYamlLineClass *);
-
-/* Initialise une instance de ligne de contenu Yaml. */
-static void g_yaml_line_init(GYamlLine *);
+/* Initialise une description globale de définition Kaitai. */
+static void g_kaitai_meta_init(GKaitaiMeta *);
/* Supprime toutes les références externes. */
-static void g_yaml_line_dispose(GYamlLine *);
+static void g_kaitai_meta_dispose(GKaitaiMeta *);
/* Procède à la libération totale de la mémoire. */
-static void g_yaml_line_finalize(GYamlLine *);
+static void g_kaitai_meta_finalize(GKaitaiMeta *);
-/* Indique le type défini pour une ligne de données au format Yaml. */
-G_DEFINE_TYPE(GYamlLine, g_yaml_line, G_TYPE_OBJECT);
+/* Indique le type défini pour une description globale Kaitai. */
+G_DEFINE_TYPE(GKaitaiMeta, g_kaitai_meta, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
-* Description : Initialise la classe des lignes de contenu Yaml. *
+* Description : Initialise la classe des descriptions globales Kaitai. *
* *
* Retour : - *
* *
@@ -88,23 +66,23 @@ G_DEFINE_TYPE(GYamlLine, g_yaml_line, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_yaml_line_class_init(GYamlLineClass *klass)
+static void g_kaitai_meta_class_init(GKaitaiMetaClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_line_dispose;
- object->finalize = (GObjectFinalizeFunc)g_yaml_line_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_meta_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_meta_finalize;
}
/******************************************************************************
* *
-* Paramètres : line = instance à initialiser. *
+* Paramètres : meta = instance à initialiser. *
* *
-* Description : Initialise une instance de ligne de contenu Yaml. *
+* Description : Initialise une description globale de définition Kaitai. *
* *
* Retour : - *
* *
@@ -112,24 +90,22 @@ static void g_yaml_line_class_init(GYamlLineClass *klass)
* *
******************************************************************************/
-static void g_yaml_line_init(GYamlLine *line)
+static void g_kaitai_meta_init(GKaitaiMeta *meta)
{
- line->raw = NULL;
- line->number = -1;
+ meta->id = NULL;
+ meta->title = NULL;
- line->indent = 0;
- line->is_list_item = false;
+ meta->endian = SRE_LITTLE;
- line->payload = NULL;
- line->key = NULL;
- line->value = NULL;
+ meta->dependencies = NULL;
+ meta->dep_count = 0;
}
/******************************************************************************
* *
-* Paramètres : line = instance d'objet GLib à traiter. *
+* Paramètres : meta = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -139,16 +115,16 @@ static void g_yaml_line_init(GYamlLine *line)
* *
******************************************************************************/
-static void g_yaml_line_dispose(GYamlLine *line)
+static void g_kaitai_meta_dispose(GKaitaiMeta *meta)
{
- G_OBJECT_CLASS(g_yaml_line_parent_class)->dispose(G_OBJECT(line));
+ G_OBJECT_CLASS(g_kaitai_meta_parent_class)->dispose(G_OBJECT(meta));
}
/******************************************************************************
* *
-* Paramètres : line = instance d'objet GLib à traiter. *
+* Paramètres : meta = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -158,28 +134,32 @@ static void g_yaml_line_dispose(GYamlLine *line)
* *
******************************************************************************/
-static void g_yaml_line_finalize(GYamlLine *line)
+static void g_kaitai_meta_finalize(GKaitaiMeta *meta)
{
- if (line->raw != NULL)
- free(line->raw);
+ size_t i; /* Boucle de parcours */
+
+ if (meta->id != NULL)
+ free(meta->id);
- if (line->key != NULL)
- free(line->key);
+ if (meta->title != NULL)
+ free(meta->title);
- if (line->value != NULL)
- free(line->value);
+ for (i = 0; i < meta->dep_count; i++)
+ free(meta->dependencies[i]);
- G_OBJECT_CLASS(g_yaml_line_parent_class)->finalize(G_OBJECT(line));
+ if (meta->dependencies != NULL)
+ free(meta->dependencies);
+
+ G_OBJECT_CLASS(g_kaitai_meta_parent_class)->finalize(G_OBJECT(meta));
}
/******************************************************************************
* *
-* Paramètres : raw = contenu brut d'une ligne au format Yaml. *
-* number = indice associé à la ligne. *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
* *
-* Description : Met en place un gestionnaire pour ligne au format Yaml. *
+* Description : Construit une description globale Kaitai. *
* *
* Retour : Instance mise en place ou NULL en cas d'échec. *
* *
@@ -187,120 +167,136 @@ static void g_yaml_line_finalize(GYamlLine *line)
* *
******************************************************************************/
-GYamlLine *g_yaml_line_new(const char *raw, size_t number)
+GKaitaiMeta *g_kaitai_meta_new(GYamlNode *parent)
{
- GYamlLine *result; /* Structure à retourner */
- char *iter; /* Boucle de parcours */
- bool string_content[2]; /* Ouvertures de chaînes */
- bool escape; /* Echappement de marquant */
+ GKaitaiMeta *result; /* Identifiant à retourner */
- result = g_object_new(G_TYPE_YAML_LINE, NULL);
+ result = g_object_new(G_TYPE_KAITAI_META, NULL);
- result->raw = strdup(raw);
- result->number = number;
+ if (!g_kaitai_meta_create(result, parent))
+ g_clear_object(&result);
- /* Indentation */
+ return result;
- for (iter = result->raw; *iter != '\0'; iter++)
- {
- if (*iter != ' ')
- break;
+}
- result->indent++;
- }
+/******************************************************************************
+* *
+* Paramètres : meta = description globale à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Met en place une description globale Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- if (*iter == '-')
+bool g_kaitai_meta_create(GKaitaiMeta *meta, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *node; /* Noeud particulier présent */
+ const char *value; /* Valeur Yaml particulière */
+ GYamlNode **nodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ /* Identifiant */
+
+ node = g_yaml_node_find_first_by_path(parent, "/meta/id");
+
+ if (node != NULL)
{
- result->is_list_item = true;
+ assert(G_IS_YAML_PAIR(node));
- for (iter++; *iter != '\0'; iter++)
- if (*iter != ' ')
- break;
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
- }
+ if (value != NULL)
+ meta->id = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
- result->payload = iter;
+ }
- /* Eventuel couple clef/valeur */
+ /* Titre */
- string_content[0] = false;
- string_content[1] = false;
+ node = g_yaml_node_find_first_by_path(parent, "/meta/title");
- for (; *iter != '\0'; iter++)
+ if (node != NULL)
{
- if (*iter == '\'' && !string_content[1])
- {
- if (iter == result->payload)
- escape = false;
+ assert(G_IS_YAML_PAIR(node));
- else
- escape = *(iter - 1) == '\'';
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
- if (!escape)
- string_content[0] = !string_content[0];
+ if (value != NULL)
+ meta->title = strdup(value);
- }
+ g_object_unref(G_OBJECT(node));
- else if (*iter == '"' && !string_content[0])
- {
- if (iter == result->payload)
- escape = false;
+ }
- else
- escape = *(iter - 1) == '\\';
+ /* Boutisme */
- if (!escape)
- string_content[1] = !string_content[1];
+ node = g_yaml_node_find_first_by_path(parent, "/meta/endian");
- }
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
- else if (!string_content[0] && !string_content[1])
- {
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
- if (*iter == ':')
- break;
+ if (strcmp(value, "le") == 0)
+ meta->endian = SRE_LITTLE;
+ else if (strcmp(value, "be") == 0)
+ meta->endian = SRE_BIG;
- }
+ g_object_unref(G_OBJECT(node));
}
- if (*iter != '\0')
+ /* Imports */
+
+ node = g_yaml_node_find_first_by_path(parent, "/meta/imports/");
+
+ if (node != NULL)
{
- result->key = strndup(result->payload, iter - result->payload);
+ result = G_IS_YAML_COLLEC(node);
- for (iter++; *iter != '\0'; iter++)
- if (*iter != ' ')
- break;
+ if (result)
+ {
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(node), &count);
- if (*iter != '\0')
- result->value = strdup(iter);
+ for (i = 0; i < count; i++)
+ {
+ if (!G_IS_YAML_PAIR(nodes[i]))
+ break;
- }
+ value = g_yaml_pair_get_key(G_YAML_PAIR(nodes[i]));
- return result;
+ meta->dependencies = realloc(meta->dependencies, ++meta->dep_count * sizeof(char *));
-}
+ meta->dependencies[meta->dep_count - 1] = strdup(value);
+ g_object_unref(G_OBJECT(nodes[i]));
-/******************************************************************************
-* *
-* Paramètres : line = ligne au format Yaml à consulter. *
-* *
-* Description : Fournit la taille de l'indentation d'une ligne Yaml. *
-* *
-* Retour : Taille de l'indentation rencontrée. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ }
-size_t g_yaml_line_count_indent(const GYamlLine *line)
-{
- size_t result; /* Quantité à retourner */
+ result = (i == count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
- result = line->indent;
+ if (nodes != NULL)
+ free(nodes);
+
+ }
+
+ }
return result;
@@ -309,21 +305,21 @@ size_t g_yaml_line_count_indent(const GYamlLine *line)
/******************************************************************************
* *
-* Paramètres : line = ligne au format Yaml à consulter. *
+* Paramètres : meta = description globale à consulter. *
* *
-* Description : Indique si la ligne représente un élément de liste. *
+* Description : Fournit l'identifié associé à une définiton Kaitai. *
* *
-* Retour : Statut de l'état lié à une liste d'éléments. *
+* Retour : Identifiant de définition complète ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_yaml_line_is_list_item(const GYamlLine *line)
+const char *g_kaitai_meta_get_id(const GKaitaiMeta *meta)
{
- bool result; /* Statut à retourner */
+ const char *result; /* Chaîne à retourner */
- result = line->is_list_item;
+ result = meta->id;
return result;
@@ -332,21 +328,21 @@ bool g_yaml_line_is_list_item(const GYamlLine *line)
/******************************************************************************
* *
-* Paramètres : line = ligne au format Yaml à consulter. *
+* Paramètres : meta = description globale à consulter. *
* *
-* Description : Fournit la charge utile associée à une ligne Yaml. *
+* Description : Fournit la désignation humaine d'une définiton Kaitai. *
* *
-* Retour : Contenu sous forme de chaîne de caractères. *
+* Retour : Intitulé de définition ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *g_yaml_line_get_payload(const GYamlLine *line)
+const char *g_kaitai_meta_get_title(const GKaitaiMeta *meta)
{
- const char *result; /* Valeur à retourner */
+ const char *result; /* Chaîne à retourner */
- result = line->payload;
+ result = meta->title;
return result;
@@ -355,21 +351,21 @@ const char *g_yaml_line_get_payload(const GYamlLine *line)
/******************************************************************************
* *
-* Paramètres : line = ligne au format Yaml à consulter. *
+* Paramètres : meta = description globale à consulter. *
* *
-* Description : Fournit la clef associée à une ligne Yaml si elle existe. *
+* Description : Indique le boustime observé par défaut par une définiton. *
* *
-* Retour : Clef sous forme de chaîne de caractères ou NULL. *
+* Retour : Boustime, petit par défaut. *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *g_yaml_line_get_key(const GYamlLine *line)
+SourceEndian g_kaitai_meta_get_endian(const GKaitaiMeta *meta)
{
- char *result; /* Valeur à retourner */
+ SourceEndian result; /* Chaîne à retourner */
- result = line->key;
+ result = meta->endian;
return result;
@@ -378,21 +374,24 @@ const char *g_yaml_line_get_key(const GYamlLine *line)
/******************************************************************************
* *
-* Paramètres : line = ligne au format Yaml à consulter. *
+* Paramètres : meta = description globale à consulter. *
+* count = quantité de définitions à importer. [OUT] *
* *
-* Description : Fournit la valeur associée à une ligne Yaml si elle existe. *
+* Description : Indique la liste des définitions à importer. *
* *
-* Retour : Valeur sous forme de chaîne de caractères ou NULL. *
+* Retour : Liste de désignations de définitions ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *g_yaml_line_get_value(const GYamlLine *line)
+const char * const *g_kaitai_meta_get_dependencies(const GKaitaiMeta *meta, size_t *count)
{
- char *result; /* Valeur à retourner */
+ const char * const *result; /* Liste à retourner */
+
+ result = (const char * const *)meta->dependencies;
- result = line->value;
+ *count = meta->dep_count;
return result;
diff --git a/plugins/kaitai/parsers/meta.h b/plugins/kaitai/parsers/meta.h
new file mode 100644
index 0000000..b8b685d
--- /dev/null
+++ b/plugins/kaitai/parsers/meta.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * meta.h - prototypes pour la description globale d'une définition Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_META_H
+#define _PLUGINS_KAITAI_PARSERS_META_H
+
+
+#include <glib-object.h>
+
+
+#include <common/endianness.h>
+#include <plugins/yaml/node.h>
+
+
+
+#define G_TYPE_KAITAI_META g_kaitai_meta_get_type()
+#define G_KAITAI_META(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_META, GKaitaiMeta))
+#define G_IS_KAITAI_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_META))
+#define G_KAITAI_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_META, GKaitaiMetaClass))
+#define G_IS_KAITAI_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_META))
+#define G_KAITAI_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_META, GKaitaiMetaClass))
+
+
+/* Description globale d'une définition Kaitai (instance) */
+typedef struct _GKaitaiMeta GKaitaiMeta;
+
+/* Description globale d'une définition Kaitai (classe) */
+typedef struct _GKaitaiMetaClass GKaitaiMetaClass;
+
+
+/* Indique le type défini pour une description globale Kaitai. */
+GType g_kaitai_meta_get_type(void);
+
+/* Construit une description globale Kaitai. */
+GKaitaiMeta *g_kaitai_meta_new(GYamlNode *);
+
+/* Fournit l'identifié associé à une définiton Kaitai. */
+const char *g_kaitai_meta_get_id(const GKaitaiMeta *);
+
+/* Fournit la désignation humaine d'une définiton Kaitai. */
+const char *g_kaitai_meta_get_title(const GKaitaiMeta *);
+
+/* Indique le boustime observé par défaut par une définiton. */
+SourceEndian g_kaitai_meta_get_endian(const GKaitaiMeta *);
+
+/* Indique la liste des définitions à importer. */
+const char * const *g_kaitai_meta_get_dependencies(const GKaitaiMeta *, size_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_META_H */
diff --git a/plugins/kaitai/parsers/struct-int.h b/plugins/kaitai/parsers/struct-int.h
new file mode 100644
index 0000000..6eb6e53
--- /dev/null
+++ b/plugins/kaitai/parsers/struct-int.h
@@ -0,0 +1,77 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct-int.h - prototypes internes pour la définition d'une structure Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSERS_STRUCT_INT_H
+#define PLUGINS_KAITAI_PARSERS_STRUCT_INT_H
+
+
+#include "attribute.h"
+#include "instance.h"
+#include "struct.h"
+#include "../parser-int.h"
+
+
+
+/* Spécification d'une structure Kaitai (instance) */
+struct _GKaitaiStruct
+{
+ GKaitaiParser parent; /* A laisser en premier */
+
+ char *filename; /* Eventuelle source de données*/
+
+ GKaitaiMeta *meta; /* Description globale */
+
+ GKaitaiAttribute **seq_items; /* Sous-attributs présents */
+ size_t seq_items_count; /* Quantité de ces attributs */
+
+ GKaitaiType **types; /* Types particuliers définis */
+ size_t types_count; /* Quantité de ces types */
+
+ GKaitaiInstance **instances; /* Instances prises en charge */
+ size_t instances_count; /* Quantité de ces instances */
+
+ GKaitaiEnum **enums; /* Enumérations locales */
+ size_t enums_count; /* Quantité de ces énumérations*/
+
+};
+
+/* Spécification d'une structure Kaitai (classe) */
+struct _GKaitaiStructClass
+{
+ GKaitaiParserClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un interpréteur de définitions Kaitai. */
+bool g_kaitai_structure_create_from_text(GKaitaiStruct *, const char *);
+
+/* Met en place un interpréteur de définitions Kaitai. */
+bool g_kaitai_structure_create_from_file(GKaitaiStruct *, const char *);
+
+/* Met en place un lecteur de définitions Kaitai. */
+bool g_kaitai_structure_create(GKaitaiStruct *, GYamlNode *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_STRUCT_INT_H */
diff --git a/plugins/kaitai/parsers/struct.c b/plugins/kaitai/parsers/struct.c
new file mode 100644
index 0000000..d447cf3
--- /dev/null
+++ b/plugins/kaitai/parsers/struct.c
@@ -0,0 +1,837 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct.c - définition d'une structure Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "struct.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include <plugins/yaml/collection.h>
+#include <plugins/yaml/parser.h>
+
+
+#include "struct-int.h"
+#include "../import.h"
+#include "../parser.h"
+#include "../records/empty.h"
+#include "../records/group.h"
+
+
+
+/* ---------------------- LECTURE D'UNE TRANCHE DE DEFINITIONS ---------------------- */
+
+
+/* Initialise la classe des structuts de spécification Kaitai. */
+static void g_kaitai_structure_class_init(GKaitaiStructClass *);
+
+/* Initialise un structut de spécification Kaitai. */
+static void g_kaitai_structure_init(GKaitaiStruct *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_structure_dispose(GKaitaiStruct *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_structure_finalize(GKaitaiStruct *);
+
+/* Charge les éventuelles dépendances de la définition. */
+static bool g_kaitai_structure_load_imports(GKaitaiStruct *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_structure_parse_content(GKaitaiStruct *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* LECTURE D'UNE TRANCHE DE DEFINITIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un structut de la spécification Kaitai. */
+G_DEFINE_TYPE(GKaitaiStruct, g_kaitai_structure, G_TYPE_KAITAI_PARSER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des structuts de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_class_init(GKaitaiStructClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_structure_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_structure_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_structure_parse_content;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = instance à initialiser. *
+* *
+* Description : Initialise un structure de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_init(GKaitaiStruct *kstruct)
+{
+ kstruct->filename = NULL;
+
+ kstruct->meta = NULL;
+
+ kstruct->seq_items = NULL;
+ kstruct->seq_items_count = 0;
+
+ kstruct->types = NULL;
+ kstruct->types_count = 0;
+
+ kstruct->instances = NULL;
+ kstruct->instances_count = 0;
+
+ kstruct->enums = NULL;
+ kstruct->enums_count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_dispose(GKaitaiStruct *kstruct)
+{
+ size_t i; /* Boucle de parcours */
+
+ g_clear_object(&kstruct->meta);
+
+ for (i = 0; i < kstruct->seq_items_count; i++)
+ g_clear_object(&kstruct->seq_items[i]);
+
+ for (i = 0; i < kstruct->types_count; i++)
+ g_clear_object(&kstruct->types[i]);
+
+ for (i = 0; i < kstruct->instances_count; i++)
+ g_clear_object(&kstruct->instances[i]);
+
+ for (i = 0; i < kstruct->enums_count; i++)
+ g_clear_object(&kstruct->enums[i]);
+
+ G_OBJECT_CLASS(g_kaitai_structure_parent_class)->dispose(G_OBJECT(kstruct));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_finalize(GKaitaiStruct *kstruct)
+{
+ if (kstruct->filename != NULL)
+ free(kstruct->filename);
+
+ if (kstruct->seq_items != NULL)
+ free(kstruct->seq_items);
+
+ if (kstruct->types != NULL)
+ free(kstruct->types);
+
+ if (kstruct->instances != NULL)
+ free(kstruct->instances);
+
+ if (kstruct->enums != NULL)
+ free(kstruct->enums);
+
+ G_OBJECT_CLASS(g_kaitai_structure_parent_class)->finalize(G_OBJECT(kstruct));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : text = définitions textuelles d'un contenu brut. *
+* *
+* Description : Crée un nouvel interpréteur de structure Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiStruct *g_kaitai_structure_new_from_text(const char *text)
+{
+ GKaitaiStruct *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_STRUCT, NULL);
+
+ if (!g_kaitai_structure_create_from_text(result, text))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* text = définitions textuelles d'un contenu brut. *
+* *
+* Description : Met en place un interpréteur de définitions Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_structure_create_from_text(GKaitaiStruct *kstruct, const char *text)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *root; /* Noeud racine YAML */
+
+ root = parse_yaml_from_text(text, strlen(text));
+
+ if (root != NULL)
+ {
+ result = g_kaitai_structure_create(kstruct, root);
+ g_object_unref(G_OBJECT(root));
+ }
+ else
+ {
+ fprintf(stderr, "The provided YAML content seems invalid");
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : filename = chemin vers des définitions de règles. *
+* *
+* Description : Crée un nouvel interpréteur de structure Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiStruct *g_kaitai_structure_new_from_file(const char *filename)
+{
+ GKaitaiStruct *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_STRUCT, NULL);
+
+ if (!g_kaitai_structure_create_from_file(result, filename))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* filename = chemin vers des définitions de règles. *
+* *
+* Description : Met en place un interpréteur de définitions Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_structure_create_from_file(GKaitaiStruct *kstruct, const char *filename)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *root; /* Noeud racine YAML */
+
+ kstruct->filename = strdup(filename);
+
+ root = parse_yaml_from_file(filename);
+
+ if (root != NULL)
+ {
+ result = g_kaitai_structure_create(kstruct, root);
+ g_object_unref(G_OBJECT(root));
+ }
+ else
+ {
+ fprintf(stderr, "The provided YAML content seems invalid");
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Met en place un lecteur de définitions Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_structure_create(GKaitaiStruct *kstruct, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *collec; /* Liste de noeuds à traiter */
+ GYamlNode **nodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+ size_t first; /* Premier emplacement dispo. */
+ bool failed; /* Détection d'un échec */
+
+ result = false;
+
+ /* Informations générales */
+
+ kstruct->meta = g_kaitai_meta_new(parent);
+ assert(kstruct->meta != NULL);
+
+ result = g_kaitai_structure_load_imports(kstruct);
+ if (!result) goto bad_loading;
+
+ /* Séquence */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/seq/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ kstruct->seq_items = calloc(count, sizeof(GKaitaiAttribute *));
+ kstruct->seq_items_count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->seq_items[i] = g_kaitai_attribute_new(nodes[i]);
+ if (kstruct->seq_items[i] == NULL) break;
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
+
+ failed = (i < count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ free(nodes);
+
+ if (failed)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Types particuliers éventuels */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/types/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ first = kstruct->types_count;
+
+ kstruct->types_count += count;
+ kstruct->types = realloc(kstruct->types, kstruct->types_count * sizeof(GKaitaiType *));
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->types[first + i] = g_kaitai_type_new(nodes[i]);
+ if (kstruct->types[first + i] == NULL) break;
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
+
+ failed = (i < count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ free(nodes);
+
+ if (failed)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Instances éventuelles */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/instances/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ kstruct->instances = calloc(count, sizeof(GKaitaiInstance *));
+ kstruct->instances_count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->instances[i] = g_kaitai_instance_new(nodes[i]);
+ if (kstruct->instances[i] == NULL) break;
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
+
+ failed = (i < count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ free(nodes);
+
+ if (failed)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Enumérations éventuelles */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/enums/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ kstruct->enums = calloc(count, sizeof(GKaitaiEnum *));
+ kstruct->enums_count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->enums[i] = g_kaitai_enum_new(nodes[i]);
+ if (kstruct->enums[i] == NULL) break;
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
+
+ failed = (i < count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ free(nodes);
+
+ if (failed)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Sortie heureuse */
+
+ result = true;
+
+ bad_loading:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* *
+* Description : Charge les éventuelles dépendances de la définition. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_structure_load_imports(GKaitaiStruct *kstruct)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ const char * const *dependencies; /* Liste d'imports requis */
+ size_t count; /* Quantité de ces imports */
+ size_t i; /* Boucle de parcours */
+ GKaitaiType *imported; /* Structure importée */
+
+ result = true;
+
+ dependencies = g_kaitai_meta_get_dependencies(kstruct->meta, &count);
+
+ for (i = 0; i < count; i++)
+ {
+ imported = import_kaitai_definition(dependencies[i], kstruct->filename);
+ if (imported == NULL) break;
+
+ kstruct->types_count++;
+ kstruct->types = realloc(kstruct->types, kstruct->types_count * sizeof(GKaitaiType *));
+
+ kstruct->types[kstruct->types_count - 1] = imported;
+
+ }
+
+ result = (i == count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai à consulter. *
+* *
+* Description : Fournit la description globale d'une définition Kaitai. *
+* *
+* Retour : Description de la définition Kaitai courante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiMeta *g_kaitai_structure_get_meta(const GKaitaiStruct *kstruct)
+{
+ GKaitaiMeta *result; /* Informations à retourner */
+
+ result = kstruct->meta;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* name = désignation principale des énumérations ciblées. *
+* *
+* Description : Fournit un ensemble d'énumérations locales de la structure. *
+* *
+* Retour : Enumérations locales ou NULL si non trouvée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiEnum *g_kaitai_structure_get_enum(const GKaitaiStruct *kstruct, const sized_string_t *name)
+{
+ GKaitaiEnum *result; /* Instance à retourner */
+ size_t i; /* Boucle de parcours */
+ const char *other; /* Autre désignation à comparer*/
+
+ result = NULL;
+
+ for (i = 0; i < kstruct->enums_count; i++)
+ {
+ other = g_kaitai_enum_get_name(kstruct->enums[i]);
+
+ if (strncmp(name->data, other, name->len) == 0) // FIXME
+ {
+ result = kstruct->enums[i];
+ g_object_ref(G_OBJECT(result));
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* name = désignation du type particulier ciblé. *
+* *
+* Description : Recherche la définition d'un type nouveau pour Kaitai. *
+* *
+* Retour : Type prêt à emploi ou NULL si non trouvé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiType *g_kaitai_structure_find_sub_type(const GKaitaiStruct *kstruct, const char *name)
+{
+ GKaitaiType *result; /* Instance à retourner */
+ size_t i; /* Boucle de parcours */
+ const char *other; /* Autre désignation à comparer*/
+
+ result = NULL;
+
+ for (i = 0; i < kstruct->types_count; i++)
+ {
+ other = g_kaitai_type_get_name(kstruct->types[i]);
+
+ if (strcmp(name, other) == 0)
+ {
+ result = kstruct->types[i];
+ g_object_ref(G_OBJECT(result));
+ break;
+ }
+
+ result = g_kaitai_structure_find_sub_type(G_KAITAI_STRUCT(kstruct->types[i]), name);
+ if (result != NULL) break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* content = contenu binaire en cours de traitement. *
+* *
+* Description : Parcourt un contenu binaire selon une description Kaitai. *
+* *
+* Retour : Arborescence d'éléments rencontrés selon les spécifications. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *kstruct, GBinContent *content)
+{
+ GMatchRecord *result; /* Arborescence à retourner */
+ vmpa2t pos; /* Tête de lecture */
+ kaitai_scope_t locals; /* Variables locales */
+ ext_vmpa_t epos; /* Tête de lecture complète */
+
+ g_binary_content_compute_start_pos(content, &pos);
+
+ init_record_scope(&locals, kstruct->meta);
+
+ init_evmpa_from_vmpa(&epos, &pos);
+
+ g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct), &locals, content, &epos, &result);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ GRecordGroup *group; /* Ensemble à constituer */
+ GMatchRecord *old; /* Sauvegarde de valeur */
+ size_t i; /* Boucle de parcours */
+ GMatchRecord *child; /* Nouvel élément mis en place */
+
+ result = true;
+
+ /* Si le groupe est vide */
+ if ((kstruct->seq_items_count + kstruct->instances_count) == 0)
+ {
+ *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(kstruct), content, &epos->base));
+
+ if (locals->root == NULL)
+ locals->root = *record;
+
+ }
+
+ /* Sinon on construit selon les définitions fournies */
+ else
+ {
+ group = g_record_group_new(kstruct, content);
+ *record = G_MATCH_RECORD(group);
+
+ if (locals->root == NULL)
+ locals->root = *record;
+
+ old = locals->parent;
+ locals->parent = *record;
+
+ /**
+ * Les instances sont à charger avant les éléments fixes car
+ * des références au premières peuvent être attendues dans ces derniers.
+ *
+ * Les évolutions de la tête de lecture n'ont en revanche normalement
+ * pas d'incidence sur le chargement des éléments fixes.
+ */
+
+ for (i = 0; i < kstruct->instances_count; i++)
+ {
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->instances[i]),
+ locals, content, epos, &child);
+ if (!result) goto exit;
+
+ if (child != NULL)
+ {
+ g_record_group_add_record(group, child);
+ g_object_unref(G_OBJECT(child));
+ }
+
+ }
+
+ /**
+ * Seconde phase.
+ */
+
+ locals->parent = *record;
+
+ for (i = 0; i < kstruct->seq_items_count; i++)
+ {
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->seq_items[i]),
+ locals, content, epos, &child);
+ if (!result) goto exit;
+
+ if (child != NULL)
+ {
+ g_record_group_add_record(group, child);
+ g_object_unref(G_OBJECT(child));
+ }
+
+ }
+
+ exit:
+
+ locals->parent = old;
+
+ if (!result)
+ g_clear_object(record);
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/struct.h b/plugins/kaitai/parsers/struct.h
new file mode 100644
index 0000000..4a2397a
--- /dev/null
+++ b/plugins/kaitai/parsers/struct.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct.h - prototypes pour la définition d'une structure Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_STRUCT_H
+#define _PLUGINS_KAITAI_PARSERS_STRUCT_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <analysis/content.h>
+
+
+#include "enum.h"
+#include "meta.h"
+#include "type.h"
+#include "../record.h"
+
+
+
+#define G_TYPE_KAITAI_STRUCT g_kaitai_structure_get_type()
+#define G_KAITAI_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_STRUCT, GKaitaiStruct))
+#define G_IS_KAITAI_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_STRUCT))
+#define G_KAITAI_STRUCT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_STRUCT, GKaitaiStructClass))
+#define G_IS_KAITAI_STRUCT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_STRUCT))
+#define G_KAITAI_STRUCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_STRUCT, GKaitaiStructClass))
+
+
+/* Spécification d'une structure Kaitai (instance) */
+typedef struct _GKaitaiStruct GKaitaiStruct;
+
+/* Spécification d'une structure Kaitai (classe) */
+typedef struct _GKaitaiStructClass GKaitaiStructClass;
+
+
+/* Indique le type défini pour une structure Kaitai. */
+GType g_kaitai_structure_get_type(void);
+
+/* Crée un nouvel interpréteur de structure Kaitai. */
+GKaitaiStruct *g_kaitai_structure_new_from_text(const char *);
+
+/* Crée un nouvel interpréteur de structure Kaitai. */
+GKaitaiStruct *g_kaitai_structure_new_from_file(const char *);
+
+/* Fournit la description globale d'une définition Kaitai. */
+GKaitaiMeta *g_kaitai_structure_get_meta(const GKaitaiStruct *);
+
+/* Recherche la définition d'un type nouveau pour Kaitai. */
+GKaitaiType *g_kaitai_structure_find_sub_type(const GKaitaiStruct *, const char *);
+
+/* Fournit un ensemble d'énumérations locales de la structure. */
+GKaitaiEnum *g_kaitai_structure_get_enum(const GKaitaiStruct *, const sized_string_t *);
+
+/* Parcourt un contenu binaire selon une description Kaitai. */
+GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *, GBinContent *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_STRUCT_H */
diff --git a/plugins/kaitai/parsers/switch-int.h b/plugins/kaitai/parsers/switch-int.h
new file mode 100644
index 0000000..a087e49
--- /dev/null
+++ b/plugins/kaitai/parsers/switch-int.h
@@ -0,0 +1,78 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switch-int.h - prototypes internes pour la gestion des énumérations Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSERS_SWITCH_INT_H
+#define PLUGINS_KAITAI_PARSERS_SWITCH_INT_H
+
+
+#include "switch.h"
+#include "../parser-int.h"
+
+
+
+/* ------------------------ BASCULE DYNAMIQUE SELON CONTEXTE ------------------------ */
+
+
+/* Mémorisation d'une valeur d'énumération */
+typedef struct _switch_case_t
+{
+ char *value; /* Valeur d'association */
+ char *type; /* Désignation du type associé */
+
+} switch_case_t;
+
+
+
+/* ----------------------- SELECTION DYNAMIQUE DE TYPE KAITAI ----------------------- */
+
+
+/* Sélection d'un type selon un contexte (instance) */
+struct _GKaitaiSwitch
+{
+ GKaitaiParser parent; /* A laisser en premier */
+
+ char *target; /* Source de bascule */
+
+ switch_case_t **cases; /* Choix de types potentiels */
+ size_t count; /* Quantité de ces choix */
+
+ switch_case_t *defcase; /* Choix par défaut ou NULL */
+
+ GKaitaiAttribute *generic; /* Attribut à dériver */
+
+};
+
+/* Sélection d'un type selon un contexte (classe) */
+struct _GKaitaiSwitchClass
+{
+ GKaitaiParserClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une sélection dynamique de type Kaitai. */
+bool g_kaitai_switch_create(GKaitaiSwitch *, GYamlNode *, GKaitaiAttribute *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_SWITCH_INT_H */
diff --git a/plugins/kaitai/parsers/switch.c b/plugins/kaitai/parsers/switch.c
new file mode 100644
index 0000000..6cfc96b
--- /dev/null
+++ b/plugins/kaitai/parsers/switch.c
@@ -0,0 +1,644 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switch.h - gestion des énumérations Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "switch.h"
+
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include <common/extstr.h>
+#include <common/sort.h>
+#include <core/logs.h>
+#include <plugins/yaml/pair.h>
+
+
+#include "switch-int.h"
+#include "../expression.h"
+
+
+
+/* ------------------------ BASCULE DYNAMIQUE SELON CONTEXTE ------------------------ */
+
+
+/* Construit une valeur d'énumération à partir d'indications. */
+static switch_case_t *build_switch_case(const GYamlNode *, bool *);
+
+/* Supprime de la mémoire une bascule selon contexte. */
+static void delete_switch_case(switch_case_t *);
+
+/* Détermine si le cas correspond à une valeur de bascule. */
+static const char *is_suitable_switch_case_for_bytes(const switch_case_t *, const resolved_value_t *);
+
+/* Détermine si le cas correspond à une valeur de bascule. */
+static const char *is_suitable_switch_case_for_integer(const switch_case_t *, kaitai_scope_t *, const resolved_value_t *);
+
+
+
+/* ----------------------- SELECTION DYNAMIQUE DE TYPE KAITAI ----------------------- */
+
+
+/* Initialise la classe des sélections dynamiques de types. */
+static void g_kaitai_switch_class_init(GKaitaiSwitchClass *);
+
+/* Initialise une sélection dynamique de type Kaitai. */
+static void g_kaitai_switch_init(GKaitaiSwitch *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_switch_dispose(GKaitaiSwitch *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_switch_finalize(GKaitaiSwitch *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_switch_parse_content(GKaitaiSwitch *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* BASCULE DYNAMIQUE SELON CONTEXTE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud Yaml à venir lire. *
+* defcase = indique si une valeur par défaut est visée. [OUT] *
+* *
+* Description : Construit une valeur d'énumération à partir d'indications. *
+* *
+* Retour : Structure de valeur mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static switch_case_t *build_switch_case(const GYamlNode *node, bool *defcase)
+{
+ switch_case_t *result; /* Enregistrement à retourner */
+ const char *key; /* Clef d'une conversion */
+ const char *value; /* Valeur Yaml particulière */
+
+ result = NULL;
+
+ if (!G_IS_YAML_PAIR(node))
+ goto exit;
+
+ key = g_yaml_pair_get_key(G_YAML_PAIR(node));
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value == NULL)
+ goto exit;
+
+ result = malloc(sizeof(switch_case_t));
+
+ result->value = strdup(key);
+ result->type = strdup(value);
+
+ *defcase = (strcmp(key, "_") == 0);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : swcase = valeur à traiter. *
+* *
+* Description : Supprime de la mémoire une bascule selon contexte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+*****************************************************************************/
+
+static void delete_switch_case(switch_case_t *swcase)
+{
+ free(swcase->value);
+
+ free(swcase->type);
+
+ free(swcase);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : swcase = valeur à analyser. *
+* value = valeur à comparer. *
+* *
+* Description : Détermine si le cas correspond à une valeur de bascule. *
+* *
+* Retour : Type à utiliser ou NULL si aucune correspondance établie. *
+* *
+* Remarques : - *
+* *
+*****************************************************************************/
+
+static const char *is_suitable_switch_case_for_bytes(const switch_case_t *swcase, const resolved_value_t *value)
+{
+ const char *result; /* Désignation à retourner */
+ sized_string_t key; /* Changement de format */
+ bool valid; /* Validité des opérations */
+ int ret; /* Bilan d'une comparaison */
+
+ result = NULL;
+
+ key.data = swcase->value;
+ key.len = strlen(swcase->value);
+
+ valid = (key.len > 2);
+
+ if (valid)
+ valid = (swcase->value[0] == '"' || swcase->value[0] == '\'');
+
+ if (valid)
+ {
+ valid = (key.data[0] == key.data[key.len - 1]);
+
+ key.data++;
+ key.len -= 2;
+
+ }
+
+ if (valid)
+ {
+ if (value->type == GVT_BYTES)
+ {
+ ret = szmemcmp(&key, &value->bytes);
+
+ if (ret == 0)
+ result = swcase->type;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : swcase = valeur à analyser. *
+* locals = variables locales pour les résolutions de types. *
+* value = valeur à comparer. *
+* *
+* Description : Détermine si le cas correspond à une valeur de bascule. *
+* *
+* Retour : Type à utiliser ou NULL si aucune correspondance établie. *
+* *
+* Remarques : - *
+* *
+*****************************************************************************/
+
+static const char *is_suitable_switch_case_for_integer(const switch_case_t *swcase, kaitai_scope_t *locals, const resolved_value_t *value)
+{
+ const char *result; /* Désignation à retourner */
+ bool valid; /* Validité des opérations */
+ resolved_value_t key; /* Changement de format */
+ unsigned long long unsigned_conv; /* Valeur convertie #1 */
+ long long signed_conv; /* Valeur convertie #2 */
+
+ result = NULL;
+
+ valid = (swcase->value[0] != '"' && swcase->value[0] != '\'');
+
+ if (valid)
+ {
+ if (strchr(swcase->value, ':') != NULL)
+ {
+ valid = resolve_kaitai_expression_as_integer(locals, swcase->value, strlen(swcase->value), &key);
+
+ if (valid)
+ {
+ if (key.type == GVT_UNSIGNED_INTEGER)
+ {
+ if (value->type == GVT_UNSIGNED_INTEGER)
+ {
+ if (key.unsigned_integer == value->unsigned_integer)
+ result = swcase->type;
+ }
+ else
+ {
+ if (key.unsigned_integer == value->signed_integer)
+ result = swcase->type;
+ }
+ }
+ else
+ {
+ if (value->type == GVT_UNSIGNED_INTEGER)
+ {
+ if (key.signed_integer == value->unsigned_integer)
+ result = swcase->type;
+ }
+ else
+ {
+ if (key.signed_integer == value->signed_integer)
+ result = swcase->type;
+ }
+ }
+
+ }
+
+ }
+
+ else
+ {
+ if (value->type == GVT_UNSIGNED_INTEGER)
+ {
+ unsigned_conv = strtoull(swcase->value, NULL, 0);
+
+ valid = (errno != ERANGE && errno != EINVAL);
+
+ if (valid && unsigned_conv == value->unsigned_integer)
+ result = swcase->type;
+
+ }
+ else
+ {
+ signed_conv = strtoll(swcase->value, NULL, 0);
+
+ valid = (errno != ERANGE && errno != EINVAL);
+
+ if (valid && signed_conv == value->signed_integer)
+ result = swcase->type;
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* SELECTION DYNAMIQUE DE TYPE KAITAI */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un choix dynamique de type Kaitai. */
+G_DEFINE_TYPE(GKaitaiSwitch, g_kaitai_switch, G_TYPE_KAITAI_PARSER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des sélections dynamiques de types. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_class_init(GKaitaiSwitchClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_switch_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_switch_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_switch_parse_content;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = instance à initialiser. *
+* *
+* Description : Initialise une sélection dynamique de type Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_init(GKaitaiSwitch *kswitch)
+{
+ kswitch->target = NULL;
+
+ kswitch->cases = NULL;
+ kswitch->count = 0;
+
+ kswitch->defcase = NULL;
+
+ kswitch->generic = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_dispose(GKaitaiSwitch *kswitch)
+{
+ g_clear_object(&kswitch->generic);
+
+ G_OBJECT_CLASS(g_kaitai_switch_parent_class)->dispose(G_OBJECT(kswitch));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_finalize(GKaitaiSwitch *kswitch)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (kswitch->target != NULL)
+ free(kswitch->target);
+
+ for (i = 0; i < kswitch->count; i++)
+ delete_switch_case(kswitch->cases[i]);
+
+ if (kswitch->cases != NULL)
+ free(kswitch->cases);
+
+ if (kswitch->defcase != NULL)
+ delete_switch_case(kswitch->defcase);
+
+ G_OBJECT_CLASS(g_kaitai_switch_parent_class)->finalize(G_OBJECT(kswitch));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* generic = lecteur d'attribut Kaitai à dériver. *
+* *
+* Description : Construit une sélection dynamique de type Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiSwitch *g_kaitai_switch_new(GYamlNode *parent, GKaitaiAttribute *generic)
+{
+ GKaitaiSwitch *result; /* Identifiant à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_SWITCH, NULL);
+
+ if (!g_kaitai_switch_create(result, parent, generic))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = sélectionneur de type à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* generic = lecteur d'attribut Kaitai à dériver. *
+* *
+* Description : Met en place une sélection dynamique de type Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_switch_create(GKaitaiSwitch *kswitch, GYamlNode *parent, GKaitaiAttribute *generic)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *node; /* Noeud de définition */
+ GYamlNode *subnode; /* Noeud de précisions */
+ const char *value; /* Valeur Yaml particulière */
+ GYamlNode *collec; /* Liste de noeuds à traiter */
+ GYamlNode **subnodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+ bool defcase; /* Définition par défaut ? */
+ switch_case_t *swcase; /* Bascule à noter */
+
+ result = false;
+
+ node = g_yaml_node_find_first_by_path(parent, "/type/");
+ if (node == NULL) goto exit;
+
+ /* Source de la bascule */
+
+ subnode = g_yaml_node_find_first_by_path(node, "/switch-on");
+ assert(G_IS_YAML_PAIR(subnode));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(subnode));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(subnode));
+ goto bad_definition;
+ }
+
+ kswitch->target = strdup(value);
+
+ g_object_unref(G_OBJECT(subnode));
+
+ /* Conditions de bascule */
+
+ collec = g_yaml_node_find_first_by_path(node, "/cases/");
+ if (collec == NULL) goto bad_definition;
+ if (!G_IS_YAML_COLLEC(collec)) goto bad_definition;
+
+ subnodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+
+ g_object_unref(G_OBJECT(collec));
+
+ if (count == 0) goto bad_definition;
+
+ for (i = 0; i < count; i++)
+ {
+ swcase = build_switch_case(subnodes[i], &defcase);
+ if (swcase == NULL) break;
+
+ g_object_unref(G_OBJECT(subnodes[i]));
+
+ kswitch->cases = realloc(kswitch->cases, ++kswitch->count * sizeof(switch_case_t *));
+ kswitch->cases[kswitch->count - 1] = swcase;
+
+ }
+
+ result = (i == count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(subnodes[i]));
+
+ if (subnodes != NULL)
+ free(subnodes);
+
+ /* Fin des procédures */
+
+ if (result)
+ {
+ kswitch->generic = generic;
+ g_object_ref(G_OBJECT(generic));
+ }
+
+ bad_definition:
+
+ g_object_unref(G_OBJECT(node));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_switch_parse_content(GKaitaiSwitch *kswitch, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ const char *final_type; /* Type à utiliser au final */
+ resolved_value_t value; /* Valeur de cible entière */
+ bool status; /* Bilan intermédiaire */
+ size_t i; /* Boucle de parcours */
+ GKaitaiAttribute *attrib; /* Lecteur approprié */
+
+ result = true;
+
+ final_type = NULL;
+
+ /* Tenative n°1 : version "entier" */
+
+ status = resolve_kaitai_expression_as_integer(locals, kswitch->target, strlen(kswitch->target), &value);
+
+ if (status)
+ for (i = 0; i < kswitch->count; i++)
+ {
+ final_type = is_suitable_switch_case_for_integer(kswitch->cases[i], locals, &value);
+
+ if (final_type != NULL)
+ goto next_step;
+
+ }
+
+ status = resolve_kaitai_expression_as_bytes(locals, kswitch->target, strlen(kswitch->target), &value);
+
+ /* Tenative n°1 : version "chaîne" */
+
+ if (status)
+ for (i = 0; i < kswitch->count; i++)
+ {
+ final_type = is_suitable_switch_case_for_bytes(kswitch->cases[i], &value);
+
+ if (final_type != NULL)
+ goto next_step;
+
+ }
+
+ if (final_type == NULL && kswitch->defcase != NULL)
+ final_type = kswitch->defcase->type;
+
+ next_step:
+
+ /* Mise en place d'un attribut et analyse */
+
+ if (final_type != NULL)
+ {
+ attrib = g_kaitai_attribute_dup_for_user_type(kswitch->generic, final_type);
+
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib), locals, content, epos, record);
+
+ g_object_unref(G_OBJECT(attrib));
+
+ }
+
+ return true;
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/switch.h b/plugins/kaitai/parsers/switch.h
new file mode 100644
index 0000000..c45237a
--- /dev/null
+++ b/plugins/kaitai/parsers/switch.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switch.h - prototypes pour la gestion des énumérations Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_SWITCH_H
+#define _PLUGINS_KAITAI_PARSERS_SWITCH_H
+
+
+#include <glib-object.h>
+
+
+#include <plugins/yaml/node.h>
+
+
+#include "attribute.h"
+
+
+
+#define G_TYPE_KAITAI_SWITCH g_kaitai_switch_get_type()
+#define G_KAITAI_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_SWITCH, GKaitaiSwitch))
+#define G_IS_KAITAI_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_SWITCH))
+#define G_KAITAI_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_SWITCH, GKaitaiSwitchClass))
+#define G_IS_KAITAI_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_SWITCH))
+#define G_KAITAI_SWITCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_SWITCH, GKaitaiSwitchClass))
+
+
+/* Sélection d'un type selon un contexte (instance) */
+typedef struct _GKaitaiSwitch GKaitaiSwitch;
+
+/* Sélection d'un type selon un contexte (classe) */
+typedef struct _GKaitaiSwitchClass GKaitaiSwitchClass;
+
+
+/* Indique le type défini pour un choix dynamique de type Kaitai. */
+GType g_kaitai_switch_get_type(void);
+
+/* Construit une sélection dynamique de type Kaitai. */
+GKaitaiSwitch *g_kaitai_switch_new(GYamlNode *, GKaitaiAttribute *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_SWITCH_H */
diff --git a/plugins/kaitai/parsers/type-int.h b/plugins/kaitai/parsers/type-int.h
new file mode 100644
index 0000000..535ce57
--- /dev/null
+++ b/plugins/kaitai/parsers/type-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type-int.h - prototypes internes pour la définition d'un type particulier pour Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSERS_TYPE_INT_H
+#define PLUGINS_KAITAI_PARSERS_TYPE_INT_H
+
+
+#include "struct-int.h"
+#include "type.h"
+
+
+
+/* Définition d'un type particulier nouveau pour Kaitai (instance) */
+struct _GKaitaiType
+{
+ GKaitaiStruct parent; /* A laisser en premier */
+
+ char *name; /* Nom du type particulier */
+
+};
+
+/* Définition d'un type particulier nouveau pour Kaitai (classe) */
+struct _GKaitaiTypeClass
+{
+ GKaitaiStructClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un lecteur de type pour Kaitai. */
+bool g_kaitai_type_create(GKaitaiType *, GYamlNode *);
+
+/* Met en place un lecteur de type externe pour Kaitai. */
+bool g_kaitai_type_create_as_import(GKaitaiType *, const char *, const char *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_TYPE_INT_H */
diff --git a/plugins/yaml/reader.c b/plugins/kaitai/parsers/type.c
index eebc02b..81efbeb 100644
--- a/plugins/yaml/reader.c
+++ b/plugins/kaitai/parsers/type.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * reader.c - lecteur de contenu Yaml
+ * struct.c - définition d'une structure Kaitai
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,61 +21,42 @@
*/
-#include "reader.h"
+#include "type.h"
#include <malloc.h>
#include <string.h>
-#include <gio/gio.h>
+#include <plugins/yaml/pair.h>
-#include "line.h"
+#include "type-int.h"
+#include "../parser.h"
-/* Lecteur de contenu Yaml (instance) */
-struct _GYamlReader
-{
- GObject parent; /* A laisser en premier */
-
- GYamlLine **lines; /* Lignes Yaml chargées */
- size_t count; /* Quantié de ces lignes */
-
- GYamlTree *tree; /* Arborescence constituée */
-
-};
-
-/* Lecteur de contenu Yaml (classe) */
-struct _GYamlReaderClass
-{
- GObjectClass parent; /* A laisser en premier */
+/* Initialise la classe des types particuliers pour Kaitai. */
+static void g_kaitai_type_class_init(GKaitaiTypeClass *);
-};
-
-
-/* Initialise la classe des lecteurs de contenus Yaml. */
-static void g_yaml_reader_class_init(GYamlReaderClass *);
-
-/* Initialise une instance de lecteur de contenu Yaml. */
-static void g_yaml_reader_init(GYamlReader *);
+/* Initialise un type particulier pour Kaitai. */
+static void g_kaitai_type_init(GKaitaiType *);
/* Supprime toutes les références externes. */
-static void g_yaml_reader_dispose(GYamlReader *);
+static void g_kaitai_type_dispose(GKaitaiType *);
/* Procède à la libération totale de la mémoire. */
-static void g_yaml_reader_finalize(GYamlReader *);
+static void g_kaitai_type_finalize(GKaitaiType *);
-/* Indique le type défini pour un lecteur de contenu Yaml. */
-G_DEFINE_TYPE(GYamlReader, g_yaml_reader, G_TYPE_OBJECT);
+/* Indique le type défini pour un type particulier pour Kaitai. */
+G_DEFINE_TYPE(GKaitaiType, g_kaitai_type, G_TYPE_KAITAI_STRUCT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
-* Description : Initialise la classe des lecteurs de contenus Yaml. *
+* Description : Initialise la classe des types particuliers pour Kaitai. *
* *
* Retour : - *
* *
@@ -83,23 +64,23 @@ G_DEFINE_TYPE(GYamlReader, g_yaml_reader, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_yaml_reader_class_init(GYamlReaderClass *klass)
+static void g_kaitai_type_class_init(GKaitaiTypeClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_reader_dispose;
- object->finalize = (GObjectFinalizeFunc)g_yaml_reader_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_type_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_type_finalize;
}
/******************************************************************************
* *
-* Paramètres : reader = instance à initialiser. *
+* Paramètres : kstruct = instance à initialiser. *
* *
-* Description : Initialise une instance de lecteur de contenu Yaml. *
+* Description : Initialise un type particulier pour Kaitai. *
* *
* Retour : - *
* *
@@ -107,19 +88,16 @@ static void g_yaml_reader_class_init(GYamlReaderClass *klass)
* *
******************************************************************************/
-static void g_yaml_reader_init(GYamlReader *reader)
+static void g_kaitai_type_init(GKaitaiType *type)
{
- reader->lines = NULL;
- reader->count = 0;
-
- reader->tree = NULL;
+ type->name = NULL;
}
/******************************************************************************
* *
-* Paramètres : reader = instance d'objet GLib à traiter. *
+* Paramètres : type = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -129,23 +107,16 @@ static void g_yaml_reader_init(GYamlReader *reader)
* *
******************************************************************************/
-static void g_yaml_reader_dispose(GYamlReader *reader)
+static void g_kaitai_type_dispose(GKaitaiType *type)
{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < reader->count; i++)
- g_clear_object(&reader->lines[i]);
-
- g_clear_object(&reader->tree);
-
- G_OBJECT_CLASS(g_yaml_reader_parent_class)->dispose(G_OBJECT(reader));
+ G_OBJECT_CLASS(g_kaitai_type_parent_class)->dispose(G_OBJECT(type));
}
/******************************************************************************
* *
-* Paramètres : reader = instance d'objet GLib à traiter. *
+* Paramètres : type = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -155,22 +126,21 @@ static void g_yaml_reader_dispose(GYamlReader *reader)
* *
******************************************************************************/
-static void g_yaml_reader_finalize(GYamlReader *reader)
+static void g_kaitai_type_finalize(GKaitaiType *type)
{
- if (reader->lines != NULL)
- free(reader->lines);
+ if (type->name != NULL)
+ free(type->name);
- G_OBJECT_CLASS(g_yaml_reader_parent_class)->finalize(G_OBJECT(reader));
+ G_OBJECT_CLASS(g_kaitai_type_parent_class)->finalize(G_OBJECT(type));
}
/******************************************************************************
* *
-* Paramètres : content = données brutes au format Yaml à charger. *
-* length = quantité de ces données. *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
* *
-* Description : Crée un lecteur pour contenu au format Yaml. *
+* Description : Construit un lecteur de type pour Kaitai. *
* *
* Retour : Instance mise en place ou NULL en cas d'échec. *
* *
@@ -178,135 +148,92 @@ static void g_yaml_reader_finalize(GYamlReader *reader)
* *
******************************************************************************/
-GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
+GKaitaiType *g_kaitai_type_new(GYamlNode *parent)
{
- GYamlReader *result; /* Structure à retourner */
- char *dumped; /* Contenu manipulable */
- char *saved; /* Sauvegarde de position */
- char *iter; /* Boucle de parcours */
- size_t number; /* Indice de ligne courante */
- GYamlLine *line; /* Nouvelle ligne Yaml */
-
- result = g_object_new(G_TYPE_YAML_READER, NULL);
-
- dumped = malloc(length * sizeof(char));
-
- memcpy(dumped, content, length);
-
- for (iter = dumped, saved = strchr(iter, '\n'), number = 0;
- *iter != '\0';
- iter = ++saved, saved = strchr(iter, '\n'), number++)
- {
- if (saved != NULL)
- *saved = '\0';
-
- if (*iter != '\0')
- {
- line = g_yaml_line_new(iter, number);
-
- if (line == NULL)
- goto format_error;
-
- result->lines = realloc(result->lines, ++result->count * sizeof(GYamlLine *));
-
- g_object_ref_sink(G_OBJECT(line));
- result->lines[result->count - 1] = line;
-
- }
-
- if (saved == NULL)
- break;
+ GKaitaiType *result; /* Structure à retourner */
- }
+ result = g_object_new(G_TYPE_KAITAI_TYPE, NULL);
- free(dumped);
-
- result->tree = g_yaml_tree_new(result->lines, result->count);
+ if (!g_kaitai_type_create(result, parent))
+ g_clear_object(&result);
return result;
- format_error:
-
- g_object_unref(G_OBJECT(result));
-
- return NULL;
-
}
/******************************************************************************
* *
-* Paramètres : path = chemin d'accès à un contenu à charger. *
+* Paramètres : type = lecteur de type Kaitai à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
* *
-* Description : Crée un lecteur pour contenu au format Yaml. *
+* Description : Met en place un lecteur de type pour Kaitai. *
* *
-* Retour : Instance mise en place ou NULL en cas d'échec. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlReader *g_yaml_reader_new_from_path(const char *path)
+bool g_kaitai_type_create(GKaitaiType *type, GYamlNode *parent)
{
- GYamlReader *result; /* Structure à retourner */
- char *scheme; /* Préfixe d'URI identifié */
- GFile *file; /* Accès au contenu visé */
- GFileInputStream *stream; /* Flux ouvert en lecture */
- GFileInfo *info; /* Informations du flux */
- size_t length; /* Quantité d'octets présents */
- char *content; /* Données obtenues par lecture*/
-
- result = NULL;
+ bool result; /* Bilan à retourner */
+ const char *name; /* Désignation du type */
+ char *sub_path; /* Chemin d'accès suivant */
+ GYamlNode *sub; /* Contenu Yaml d'un type */
- /* Ouverture du fichier */
+ result = false;
- scheme = g_uri_parse_scheme(path);
+ /* Extraction du nom */
- if (scheme != NULL)
- {
- g_free(scheme);
- file = g_file_new_for_uri(path);
- }
+ if (!G_IS_YAML_PAIR(parent))
+ goto exit;
- else
- file = g_file_new_for_path(path);
+ name = g_yaml_pair_get_key(G_YAML_PAIR(parent));
- stream = g_file_read(file, NULL, NULL);
+ type->name = strdup(name);
- if (stream == NULL)
- goto no_content;
+ /* Extraction des bases du type */
- /* Détermination de sa taille */
+ asprintf(&sub_path, "/%s/", name);
+ sub = g_yaml_node_find_first_by_path(parent, sub_path);
+ free(sub_path);
- info = g_file_input_stream_query_info(stream, G_FILE_ATTRIBUTE_STANDARD_SIZE, NULL, NULL);
+ if (sub == NULL)
+ goto exit;
- if (info == NULL)
- goto no_size_info;
+ result = g_kaitai_structure_create(G_KAITAI_STRUCT(type), sub);
- length = g_file_info_get_size(info);
+ g_object_unref(G_OBJECT(sub));
- /* Lecture des données */
+ exit:
- content = malloc(length + 1 * sizeof(char));
-
- if (!g_input_stream_read_all(G_INPUT_STREAM(stream), content, length, (gsize []) { 0 }, NULL, NULL))
- goto read_error;
-
- content[length] = '\0';
-
- result = g_yaml_reader_new_from_content(content, length + 1);
+ return result;
- read_error:
+}
- free(content);
- no_size_info:
+/******************************************************************************
+* *
+* Paramètres : name = nom à attribuer au futur type. *
+* filename = chemin vers une définition Kaitai à charger. *
+* *
+* Description : Construit un lecteur de type externe pour Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- g_object_unref(G_OBJECT(stream));
+GKaitaiType *g_kaitai_type_new_as_import(const char *name, const char *filename)
+{
+ GKaitaiType *result; /* Structure à retourner */
- no_content:
+ result = g_object_new(G_TYPE_KAITAI_TYPE, NULL);
- g_object_unref(G_OBJECT(file));
+ if (!g_kaitai_type_create_as_import(result, name, filename))
+ g_clear_object(&result);
return result;
@@ -315,31 +242,29 @@ GYamlReader *g_yaml_reader_new_from_path(const char *path)
/******************************************************************************
* *
-* Paramètres : reader = lecteur de contenu Yaml à consulter. *
-* count = taille de la liste constituée. [OUT] *
+* Paramètres : type = lecteur de type Kaitai à initialiser pleinement. *
+* name = nom à attribuer au futur type. *
+* filename = chemin vers une définition Kaitai à charger. *
* *
-* Description : Fournit la liste des lignes lues depuis un contenu Yaml. *
+* Description : Met en place un lecteur de type externe pour Kaitai. *
* *
-* Retour : Liste de lignes correspondant au contenu Yaml lu. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlLine **g_yaml_reader_get_lines(const GYamlReader *reader, size_t *count)
+bool g_kaitai_type_create_as_import(GKaitaiType *type, const char *name, const char *filename)
{
- GYamlLine **result; /* Liste à retourner */
- size_t i; /* Boucle de parcours */
+ bool result; /* Bilan à retourner */
- *count = reader->count;
+ /* Extraction du nom */
- result = malloc(*count * sizeof(GYamlLine *));
+ type->name = strdup(name);
- for (i = 0; i < *count; i++)
- {
- result[i] = reader->lines[i];
- g_object_ref(result[i]);
- }
+ /* Extraction des bases du type */
+
+ result = g_kaitai_structure_create_from_file(G_KAITAI_STRUCT(type), filename);
return result;
@@ -348,24 +273,21 @@ GYamlLine **g_yaml_reader_get_lines(const GYamlReader *reader, size_t *count)
/******************************************************************************
* *
-* Paramètres : reader = lecteur de contenu Yaml à consulter. *
+* Paramètres : type = définition de type particulier à consulter. *
* *
-* Description : Fournit l'arborescence associée à la lecture de lignes Yaml. *
+* Description : Indique le nom de scène du type représenté. *
* *
-* Retour : Arborescence constituée par la lecture du contenu Yaml. *
+* Retour : Désignation humaine. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlTree *g_yaml_reader_get_tree(const GYamlReader *reader)
+const char *g_kaitai_type_get_name(const GKaitaiType *type)
{
- GYamlTree *result; /* Arborescence à retourner */
-
- result = reader->tree;
+ const char *result; /* Nom à retourner */
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
+ result = type->name;
return result;
diff --git a/plugins/kaitai/parsers/type.h b/plugins/kaitai/parsers/type.h
new file mode 100644
index 0000000..d19ab90
--- /dev/null
+++ b/plugins/kaitai/parsers/type.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type.h - prototypes pour la définition d'un type particulier pour Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_TYPE_H
+#define _PLUGINS_KAITAI_PARSERS_TYPE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <plugins/yaml/node.h>
+
+
+
+#define G_TYPE_KAITAI_TYPE g_kaitai_type_get_type()
+#define G_KAITAI_TYPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_TYPE, GKaitaiType))
+#define G_IS_KAITAI_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_TYPE))
+#define G_KAITAI_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_TYPE, GKaitaiTypeClass))
+#define G_IS_KAITAI_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_TYPE))
+#define G_KAITAI_TYPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_TYPE, GKaitaiTypeClass))
+
+
+/* Définition d'un type particulier nouveau pour Kaitai (instance) */
+typedef struct _GKaitaiType GKaitaiType;
+
+/* Définition d'un type particulier nouveau pour Kaitai (classe) */
+typedef struct _GKaitaiTypeClass GKaitaiTypeClass;
+
+
+/* Indique le type défini pour un type particulier pour Kaitai. */
+GType g_kaitai_type_get_type(void);
+
+/* Construit un lecteur de type pour Kaitai. */
+GKaitaiType *g_kaitai_type_new(GYamlNode *);
+
+/* Construit un lecteur de type externe pour Kaitai. */
+GKaitaiType *g_kaitai_type_new_as_import(const char *, const char *);
+
+/* Indique le nom de scène du type représenté. */
+const char *g_kaitai_type_get_name(const GKaitaiType *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_TYPE_H */
diff --git a/plugins/kaitai/python/Makefile.am b/plugins/kaitai/python/Makefile.am
new file mode 100644
index 0000000..f222a66
--- /dev/null
+++ b/plugins/kaitai/python/Makefile.am
@@ -0,0 +1,26 @@
+
+noinst_LTLIBRARIES = libkaitaipython.la
+
+libkaitaipython_la_SOURCES = \
+ array.h array.c \
+ module.h module.c \
+ parser.h parser.c \
+ record.h record.c \
+ scope.h scope.c \
+ stream.h stream.c
+
+libkaitaipython_la_LIBADD = \
+ parsers/libkaitaipythonparsers.la \
+ records/libkaitaipythonrecords.la \
+ rost/libkaitaipythonrost.la
+
+libkaitaipython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitaipython_la_SOURCES:%c=)
+
+
+SUBDIRS = parsers records rost
diff --git a/plugins/kaitai/python/array.c b/plugins/kaitai/python/array.c
new file mode 100644
index 0000000..4973c76
--- /dev/null
+++ b/plugins/kaitai/python/array.c
@@ -0,0 +1,265 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * array.h - équivalent Python du fichier "plugins/kaitai/array.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "array.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../array-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_array, G_TYPE_KAITAI_ARRAY);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_array_init(PyObject *, PyObject *, PyObject *);
+
+/* Convertit un tableau Kaitai en série d'octets si possible. */
+static PyObject *py_kaitai_array___bytes__(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_array_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define KAITAI_ARRAY_DOC \
+ "KaitaiArray defines an array for collecting various Kaitai items." \
+ "\n" \
+ "Instances can be created using following constructor:\n" \
+ "\n" \
+ " KaitaiArray()" \
+ "\n" \
+ "In this implementation, arrays do not have to carry items all" \
+ " belonging to the same type. Access and conversions to bytes are" \
+ " handled and checked at runtime."
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un binaire. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Convertit un tableau Kaitai en série d'octets si possible. *
+* *
+* Retour : Série d'octets ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_array___bytes__(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Représentation à renvoyer */
+ GKaitaiArray *array; /* Tableau à manipuler */
+ sized_string_t bytes; /* Version en série d'octets */
+ bool status; /* Bilan de la conversion */
+
+#define KAITAI_ARRAY_AS_BYTES_METHOD PYTHON_METHOD_DEF \
+( \
+ __bytes__, "$self, /", \
+ METH_NOARGS, py_kaitai_array, \
+ "Provide a bytes representation of the array, when possible" \
+ " and without implementing the Python buffer protocol.\n" \
+ "\n" \
+ "THe result is bytes or a *TypeError* exception is raised if" \
+ " the array is not suitable for a conversion to bytes." \
+)
+
+ array = G_KAITAI_ARRAY(pygobject_get(self));
+
+ status = g_kaitai_array_convert_to_bytes(array, &bytes);
+
+ if (status)
+ {
+ result = PyBytes_FromStringAndSize(bytes.data, bytes.len);
+ exit_szstr(&bytes);
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "unable to convert the Kaitai array to bytes");
+ result = NULL;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_array_type(void)
+{
+ static PyMethodDef py_kaitai_array_methods[] = {
+ KAITAI_ARRAY_AS_BYTES_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_array_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_array_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.KaitaiArray",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = KAITAI_ARRAY_DOC,
+
+ .tp_methods = py_kaitai_array_methods,
+ .tp_getset = py_kaitai_array_getseters,
+
+ .tp_init = py_kaitai_array_init,
+ .tp_new = py_kaitai_array_new,
+
+ };
+
+ return &py_kaitai_array_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiArray. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_array_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'KaitaiArray' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_array_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ARRAY, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en tableau d'éléments Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_array(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_array_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai array");
+ break;
+
+ case 1:
+ *((GKaitaiArray **)dst) = G_KAITAI_ARRAY(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/array.h b/plugins/kaitai/python/array.h
new file mode 100644
index 0000000..aeba541
--- /dev/null
+++ b/plugins/kaitai/python/array.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * array.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/array.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_ARRAY_H
+#define _PLUGINS_KAITAI_PYTHON_ARRAY_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_array_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiArray'. */
+bool ensure_python_kaitai_array_is_registered(void);
+
+/* Tente de convertir en tableau d'éléments Kaitai. */
+int convert_to_kaitai_array(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_ARRAY_H */
diff --git a/plugins/kaitai/python/module.c b/plugins/kaitai/python/module.c
new file mode 100644
index 0000000..07fb962
--- /dev/null
+++ b/plugins/kaitai/python/module.c
@@ -0,0 +1,135 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire kaitai en tant que module
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "array.h"
+#include "parser.h"
+#include "record.h"
+#include "scope.h"
+#include "stream.h"
+#include "parsers/module.h"
+#include "records/module.h"
+#include "rost/module.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Ajoute le module 'plugins.kaitai' au module Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_kaitai_module_to_python_module(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *super; /* Module à compléter */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_PLUGINS_KAITAI_DOC \
+ "kaitai is a module trying to reverse some of the effects produced by ProGuard.\n" \
+ "\n" \
+ "Its action is focused on reverting name obfuscation by running binary diffing against" \
+ " OpenSource packages from the AOSP."
+
+ static PyModuleDef py_chrysalide_kaitai_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.plugins.kaitai",
+ .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_DOC,
+
+ .m_size = -1,
+
+ };
+
+ result = false;
+
+ super = get_access_to_python_module("pychrysalide.plugins");
+
+ module = build_python_module(super, &py_chrysalide_kaitai_module);
+
+ result = (module != NULL);
+
+ assert(result);
+
+ if (result) result = add_kaitai_parsers_module();
+ if (result) result = add_kaitai_records_module();
+ if (result) result = add_kaitai_rost_module();
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'plugins.kaitai'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_kaitai_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_kaitai_array_is_registered();
+ if (result) result = ensure_python_kaitai_parser_is_registered();
+ if (result) result = ensure_python_match_record_is_registered();
+ if (result) result = ensure_python_kaitai_scope_is_registered();
+ if (result) result = ensure_python_kaitai_stream_is_registered();
+
+ if (result) result = populate_kaitai_parsers_module();
+ if (result) result = populate_kaitai_records_module();
+ if (result) result = populate_kaitai_rost_module();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/module.h b/plugins/kaitai/python/module.h
new file mode 100644
index 0000000..939de07
--- /dev/null
+++ b/plugins/kaitai/python/module.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire kaitai en tant que module
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_MODULE_H
+#define _PLUGINS_KAITAI_PYTHON_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins.kaitai' au module Python. */
+bool add_kaitai_module_to_python_module(void);
+
+/* Intègre les objets du module 'plugins.kaitai'. */
+bool populate_kaitai_module(void);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_MODULE_H */
diff --git a/plugins/kaitai/python/parser.c b/plugins/kaitai/python/parser.c
new file mode 100644
index 0000000..067d3b0
--- /dev/null
+++ b/plugins/kaitai/python/parser.c
@@ -0,0 +1,205 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser.h - équivalent Python du fichier "plugins/kaitai/parser.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "parser.h"
+
+
+#include <pygobject.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../parser.h"
+
+
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(kaitai_parser, G_TYPE_KAITAI_PARSER, NULL);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_parser_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_parser_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define KAITAI_PARSER_DOC \
+ "KaitaiParser is the class providing support for parsing binary contents" \
+ " using a special declarative language." \
+ "\n" \
+ "It is the Python bindings for a C implementation of the specifications" \
+ " described at http://kaitai.io/."
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_parser_type(void)
+{
+ static PyMethodDef py_kaitai_parser_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_parser_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_parser_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.KaitaiParser",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = KAITAI_PARSER_DOC,
+
+ .tp_methods = py_kaitai_parser_methods,
+ .tp_getset = py_kaitai_parser_getseters,
+
+ .tp_init = py_kaitai_parser_init,
+ .tp_new = py_kaitai_parser_new,
+
+ };
+
+ return &py_kaitai_parser_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiParser.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_parser_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'KaitaiParser' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_parser_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_PARSER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en lecteur de données Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_parser(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_parser_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai parser");
+ break;
+
+ case 1:
+ *((GKaitaiParser **)dst) = G_KAITAI_PARSER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/yaml/python/reader.h b/plugins/kaitai/python/parser.h
index 19d238b..f4b6c96 100644
--- a/plugins/yaml/python/reader.h
+++ b/plugins/kaitai/python/parser.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * reader.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/reader.h"
+ * parser.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parser.h"
*
* Copyright (C) 2019 Cyrille Bagard
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_YAML_PYTHON_READER_H
-#define _PLUGINS_YAML_PYTHON_READER_H
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSER_H
+#define _PLUGINS_KAITAI_PYTHON_PARSER_H
#include <Python.h>
@@ -32,14 +32,14 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_yaml_reader_type(void);
+PyTypeObject *get_python_kaitai_parser_type(void);
-/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlReader'. */
-bool register_python_yaml_reader(PyObject *);
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiParser'. */
+bool ensure_python_kaitai_parser_is_registered(void);
-/* Tente de convertir en lecteur de données au format Yaml. */
-int convert_to_yaml_reader(PyObject *, void *);
+/* Tente de convertir en lecteur de données Kaitai. */
+int convert_to_kaitai_parser(PyObject *, void *);
-#endif /* _PLUGINS_YAML_PYTHON_READER_H */
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSER_H */
diff --git a/plugins/kaitai/python/parsers/Makefile.am b/plugins/kaitai/python/parsers/Makefile.am
new file mode 100644
index 0000000..4c418af
--- /dev/null
+++ b/plugins/kaitai/python/parsers/Makefile.am
@@ -0,0 +1,19 @@
+
+noinst_LTLIBRARIES = libkaitaipythonparsers.la
+
+libkaitaipythonparsers_la_SOURCES = \
+ attribute.h attribute.c \
+ enum.h enum.c \
+ instance.h instance.c \
+ meta.h meta.c \
+ module.h module.c \
+ struct.h struct.c \
+ type.h type.c
+
+libkaitaipythonparsers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitaipythonparsers_la_SOURCES:%c=)
diff --git a/plugins/kaitai/python/parsers/attribute.c b/plugins/kaitai/python/parsers/attribute.c
new file mode 100644
index 0000000..c2f3db6
--- /dev/null
+++ b/plugins/kaitai/python/parsers/attribute.c
@@ -0,0 +1,425 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute.c - équivalent Python du fichier "plugins/kaitai/parsers/attribute.c"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "attribute.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "../parser.h"
+#include "../../parsers/attribute-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_attribute, G_TYPE_KAITAI_ATTRIBUTE);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_attribute_init(PyObject *, PyObject *, PyObject *);
+
+/* Indique la désignation brute d'un identifiant Kaitai. */
+static PyObject *py_kaitai_attribute_get_raw_id(PyObject *, void *);
+
+/* Indique la désignation originelle d'un identifiant Kaitai. */
+static PyObject *py_kaitai_attribute_get_original_id(PyObject *, void *);
+
+/* Fournit une éventuelle documentation concernant l'attribut. */
+static PyObject *py_kaitai_attribute_get_doc(PyObject *, void *);
+
+/* Détermine si l'attribue porte une valeur entière signée. */
+static PyObject *py_kaitai_attribute_get_handle_signed_integer(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_attribute_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GYamlNode *parent; /* Noeud Yaml de l'attribut */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiAttribute *attrib; /* Création GLib à transmettre */
+
+#define KAITAI_ATTRIBUTE_DOC \
+ "KaitaiAttribute is the class providing support for parsing binary" \
+ " contents using a special declarative language." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " KaitaiAttribute(parent)" \
+ "\n" \
+ "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \
+ " to Yaml data to load.\n" \
+ "\n" \
+ "The class is the Python bindings for a C implementation of the Attribute" \
+ " structure described at https://doc.kaitai.io/ksy_diagram.html."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self));
+
+ if (!g_kaitai_attribute_create(attrib, parent, true))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai attribute."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique la désignation brute d'un identifiant Kaitai. *
+* *
+* Retour : Valeur brute de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_attribute_get_raw_id(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiAttribute *attrib; /* Version native de l'attribut*/
+ const char *value; /* Valeur à transmettre */
+
+#define KAITAI_ATTRIBUTE_RAW_ID_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ raw_id, py_kaitai_attribute, \
+ "Raw value used by Kaitai to identify one attribute" \
+ " among others.\n" \
+ "\n" \
+ "The returned indentifier is a string value." \
+)
+
+ attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self));
+
+ value = g_kaitai_attribute_get_raw_id(attrib);
+
+ if (value == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else
+ result = PyUnicode_FromString(value);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique la désignation originelle d'un identifiant Kaitai. *
+* *
+* Retour : Valeur originelle de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_attribute_get_original_id(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiAttribute *attrib; /* Version native de l'attribut*/
+ const char *value; /* Valeur à transmettre */
+
+#define KAITAI_ATTRIBUTE_ORIGINAL_ID_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ original_id, py_kaitai_attribute, \
+ "Optional alternative identifier for the attribute, as seen in" \
+ " the original specifications.\n" \
+ "\n" \
+ "The returned value is a string or *None*." \
+)
+
+ attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self));
+
+ value = g_kaitai_attribute_get_original_id(attrib);
+
+ if (value == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else
+ result = PyUnicode_FromString(value);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit une éventuelle documentation concernant l'attribut. *
+* *
+* Retour : Description enregistrée ou None si absente. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_attribute_get_doc(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiAttribute *attrib; /* Version native de l'attribut*/
+ const char *doc; /* Documentation à transmettre */
+
+#define KAITAI_ATTRIBUTE_DOC_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ doc, py_kaitai_attribute, \
+ "Optional documentation for the attribute.\n" \
+ "\n" \
+ "The returned value is a string or *None*." \
+)
+
+ attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self));
+
+ doc = g_kaitai_attribute_get_doc(attrib);
+
+ if (doc == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else
+ result = PyUnicode_FromString(doc);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Détermine si l'attribue porte une valeur entière signée. *
+* *
+* Retour : Bilan de la consultation : True si un entier signé est visé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_attribute_get_handle_signed_integer(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiAttribute *attrib; /* Version native de l'attribut*/
+ bool status; /* Bilan d'une consultation */
+
+#define KAITAI_ATTRIBUTE_HANDLE_SIGNED_INTEGER_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ handle_signed_integer, py_kaitai_attribute, \
+ "Sign of the carried integer value, if any: positive or negative?\n" \
+ "\n" \
+ "This status is provided as a boolean value." \
+)
+
+ attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self));
+
+ status = g_kaitai_attribute_handle_signed_integer(attrib);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_attribute_type(void)
+{
+ static PyMethodDef py_kaitai_attribute_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_attribute_getseters[] = {
+ KAITAI_ATTRIBUTE_RAW_ID_ATTRIB,
+ KAITAI_ATTRIBUTE_ORIGINAL_ID_ATTRIB,
+ KAITAI_ATTRIBUTE_DOC_ATTRIB,
+ KAITAI_ATTRIBUTE_HANDLE_SIGNED_INTEGER_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_attribute_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiAttribute",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = KAITAI_ATTRIBUTE_DOC,
+
+ .tp_methods = py_kaitai_attribute_methods,
+ .tp_getset = py_kaitai_attribute_getseters,
+
+ .tp_init = py_kaitai_attribute_init,
+ .tp_new = py_kaitai_attribute_new,
+
+ };
+
+ return &py_kaitai_attribute_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....KaitaiAttribute. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_attribute_is_registered(void)
+{
+ PyTypeObject *type; /* Type 'KaitaiAttribute' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_attribute_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_kaitai_parser_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ATTRIBUTE, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en attribut de données Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_attribute(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_attribute_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai attribute");
+ break;
+
+ case 1:
+ *((GKaitaiAttribute **)dst) = G_KAITAI_ATTRIBUTE(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/parsers/attribute.h b/plugins/kaitai/python/parsers/attribute.h
new file mode 100644
index 0000000..931e769
--- /dev/null
+++ b/plugins/kaitai/python/parsers/attribute.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/attribute.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H
+#define _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_attribute_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiAttribute'. */
+bool ensure_python_kaitai_attribute_is_registered(void);
+
+/* Tente de convertir en attribut de données Kaitai. */
+int convert_to_kaitai_attribute(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H */
diff --git a/plugins/kaitai/python/parsers/enum.c b/plugins/kaitai/python/parsers/enum.c
new file mode 100644
index 0000000..9200c6f
--- /dev/null
+++ b/plugins/kaitai/python/parsers/enum.c
@@ -0,0 +1,468 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum.h - équivalent Python du fichier "plugins/kaitai/parsers/enum.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "enum.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "../../parsers/enum-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_enum, G_TYPE_KAITAI_ENUM);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_enum_init(PyObject *, PyObject *, PyObject *);
+
+/* Traduit une étiquette brute en constante d'énumération. */
+static PyObject *py_kaitai_enum_find_value(PyObject *, PyObject *);
+
+/* Traduit une constante d'énumération en étiquette brute. */
+static PyObject *py_kaitai_enum_find_label(PyObject *, PyObject *);
+
+/* Traduit une constante d'énumération en documentation. */
+static PyObject *py_kaitai_enum_find_documentation(PyObject *, PyObject *);
+
+/* Fournit le nom principal d'une énumération. */
+static PyObject *py_kaitai_enum_get_name(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_enum_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GYamlNode *parent; /* Noeud Yaml de l'attribut */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiEnum *kenum; /* Création GLib à transmettre */
+
+#define KAITAI_ENUM_DOC \
+ "The KaitaiEnum class maps integer constants to symbolic names using" \
+ " Kaitai definitions.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " KaitaiEnum(parent)" \
+ "\n" \
+ "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \
+ " to Yaml data to load.\n" \
+ "\n" \
+ "The class is the Python bindings for a C implementation of the EnumSpec" \
+ " structure described at https://doc.kaitai.io/ksy_diagram.html."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ kenum = G_KAITAI_ENUM(pygobject_get(self));
+
+ if (!g_kaitai_enum_create(kenum, parent))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai enumeration."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = instance de l'énumération Kaitai à manipuler. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Traduit une étiquette brute en constante d'énumération. *
+* *
+* Retour : Valeur retrouvée ou None en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_enum_find_value(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ const char *label; /* Etiquette à rechercher */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiEnum *kenum; /* Enumération Kaitai courante */
+ sized_string_t cstr; /* CHaîne avec sa longueur */
+ bool status; /* Bilan de la conversion */
+ resolved_value_t value; /* valeur à transformer */
+
+#define KAITAI_ENUM_FIND_VALUE_METHOD PYTHON_METHOD_DEF \
+( \
+ find_value, "$self, label", \
+ METH_VARARGS, py_kaitai_enum, \
+ "Translate a given enumeration label into its relative value.\n" \
+ "\n" \
+ "The *label* argument is expected to be a string.\n" \
+ "\n" \
+ "The result is an integer or *None* in case of resolution failure." \
+)
+
+ ret = PyArg_ParseTuple(args, "s", &label);
+ if (!ret) return NULL;
+
+ kenum = G_KAITAI_ENUM(pygobject_get(self));
+
+ cstr.data = (char *)label;
+ cstr.len = strlen(label);
+
+ status = g_kaitai_enum_find_value(kenum, &cstr, &value);
+
+ if (status)
+ {
+ if (value.type == GVT_UNSIGNED_INTEGER)
+ result = PyLong_FromUnsignedLongLong(value.unsigned_integer);
+ else
+ {
+ assert(value.type == GVT_SIGNED_INTEGER);
+ result = PyLong_FromLongLong(value.signed_integer);
+ }
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = instance de l'énumération Kaitai à manipuler. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Traduit une constante d'énumération en étiquette brute. *
+* *
+* Retour : Désignation ou None en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_enum_find_label(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ int prefix; /* Préfixe attendu ? */
+ resolved_value_t value; /* valeur à transformer */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiEnum *kenum; /* Enumération Kaitai courante */
+ char *label; /* Etiquette reconstruite */
+
+#define KAITAI_ENUM_FIND_LABEL_METHOD PYTHON_METHOD_DEF \
+( \
+ find_label, "$self, value, / , prefix=False", \
+ METH_VARARGS, py_kaitai_enum, \
+ "Provide the label linked to a constant value within the current" \
+ " enumeration.\n" \
+ "\n" \
+ "The *value* is a simple integer, and *prefix* is a boolean indicating" \
+ " if the result has to integrate the enumeration name as a prefix.\n" \
+ "\n" \
+ "The result is a string or *None* in case of resolution failure." \
+)
+
+ prefix = 0;
+
+ ret = PyArg_ParseTuple(args, "K|p", &value.unsigned_integer, prefix);
+ if (!ret) return NULL;
+
+ kenum = G_KAITAI_ENUM(pygobject_get(self));
+
+ value.type = GVT_UNSIGNED_INTEGER;
+ label = g_kaitai_enum_find_label(kenum, &value, prefix);
+
+ if (label != NULL)
+ {
+ result = PyUnicode_FromString(label);
+ free(label);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = instance de l'énumération Kaitai à manipuler. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Traduit une constante d'énumération en documentation. *
+* *
+* Retour : Documentation associée à la valeur indiquée ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_enum_find_documentation(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ resolved_value_t value; /* valeur à transformer */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiEnum *kenum; /* Enumération Kaitai courante */
+ char *doc; /* Documentation obtenue */
+
+#define KAITAI_ENUM_FIND_DOCUMENTATION_METHOD PYTHON_METHOD_DEF \
+( \
+ find_documentation, "$self, value", \
+ METH_VARARGS, py_kaitai_enum, \
+ "Provide the optional documentation linked to a constant value within" \
+ " the current enumeration.\n" \
+ "\n" \
+ "The *value* is a simple integer.\n" \
+ "\n" \
+ "The result is a string or *None* if no documentation is registered" \
+ " for the provided value." \
+)
+
+ ret = PyArg_ParseTuple(args, "K", &value.unsigned_integer);
+ if (!ret) return NULL;
+
+ kenum = G_KAITAI_ENUM(pygobject_get(self));
+
+ value.type = GVT_UNSIGNED_INTEGER;
+ doc = g_kaitai_enum_find_documentation(kenum, &value);
+
+ if (doc != NULL)
+ {
+ result = PyUnicode_FromString(doc);
+ free(doc);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit le nom principal d'une énumération. *
+* *
+* Retour : Désignation de l'énumération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_enum_get_name(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiEnum *kenum; /* Version native de l'objet */
+ const char *name; /* Valeur à transmettre */
+
+#define KAITAI_ENUM_NAME_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ name, py_kaitai_enum, \
+ "Name of the enumeration group, as a string value." \
+)
+
+ kenum = G_KAITAI_ENUM(pygobject_get(self));
+
+ name = g_kaitai_enum_get_name(kenum);
+
+ result = PyUnicode_FromString(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_enum_type(void)
+{
+ static PyMethodDef py_kaitai_enum_methods[] = {
+ KAITAI_ENUM_FIND_VALUE_METHOD,
+ KAITAI_ENUM_FIND_LABEL_METHOD,
+ KAITAI_ENUM_FIND_DOCUMENTATION_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_enum_getseters[] = {
+ KAITAI_ENUM_NAME_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_enum_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiEnum",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+
+ .tp_doc = KAITAI_ENUM_DOC,
+
+ .tp_methods = py_kaitai_enum_methods,
+ .tp_getset = py_kaitai_enum_getseters,
+
+ .tp_init = py_kaitai_enum_init,
+ .tp_new = py_kaitai_enum_new
+
+ };
+
+ return &py_kaitai_enum_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiEnum. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_enum_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'KaitaiEnum' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_enum_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ENUM, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en ensemble d'énumérations Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_enum(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_enum_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai enumeration");
+ break;
+
+ case 1:
+ *((GKaitaiEnum **)dst) = G_KAITAI_ENUM(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/parsers/enum.h b/plugins/kaitai/python/parsers/enum.h
new file mode 100644
index 0000000..7172e69
--- /dev/null
+++ b/plugins/kaitai/python/parsers/enum.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/enum.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H
+#define _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_enum_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiEnum'. */
+bool ensure_python_kaitai_enum_is_registered(void);
+
+/* Tente de convertir en ensemble d'énumérations Kaitai. */
+int convert_to_kaitai_enum(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H */
diff --git a/plugins/kaitai/python/parsers/instance.c b/plugins/kaitai/python/parsers/instance.c
new file mode 100644
index 0000000..d55b58c
--- /dev/null
+++ b/plugins/kaitai/python/parsers/instance.c
@@ -0,0 +1,280 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance.h - équivalent Python du fichier "plugins/kaitai/parsers/instance.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "instance.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "attribute.h"
+#include "../../parsers/instance-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_instance, G_TYPE_KAITAI_INSTANCE);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_instance_init(PyObject *, PyObject *, PyObject *);
+
+/* Indique le nom attribué à une instance Kaitai. */
+static PyObject *py_kaitai_instance_get_name(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_instance_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GYamlNode *parent; /* Noeud Yaml de l'attribut */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiInstance *attrib; /* Création GLib à transmettre */
+
+#define KAITAI_INSTANCE_DOC \
+ "KaitaiInstance is the class providing support for Kaitai computed" \
+ " values.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " KaitaiInstance(parent)" \
+ "\n" \
+ "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \
+ " to Yaml data to load.\n" \
+ "\n" \
+ "The class is the Python bindings for a C implementation of the Instance" \
+ " structure described at https://doc.kaitai.io/ksy_diagram.html."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ attrib = G_KAITAI_INSTANCE(pygobject_get(self));
+
+ if (!g_kaitai_instance_create(attrib, parent))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai instance."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique le nom attribué à une instance Kaitai. *
+* *
+* Retour : Désignation pointant l'instance. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_instance_get_name(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiInstance *inst; /* Version native de l'instance*/
+ const char *name; /* Désignation à transmettre */
+
+#define KAITAI_INSTANCE_NAME_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ name, py_kaitai_instance, \
+ "Name used by Kaitai to identify the instance" \
+ " among others.\n" \
+ "\n" \
+ "The returned indentifier is a string value." \
+)
+
+ inst = G_KAITAI_INSTANCE(pygobject_get(self));
+
+ name = g_kaitai_instance_get_name(inst);
+ assert(name != NULL);
+
+ result = PyUnicode_FromString(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_instance_type(void)
+{
+ static PyMethodDef py_kaitai_instance_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_instance_getseters[] = {
+ KAITAI_INSTANCE_NAME_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_instance_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiInstance",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = KAITAI_INSTANCE_DOC,
+
+ .tp_methods = py_kaitai_instance_methods,
+ .tp_getset = py_kaitai_instance_getseters,
+
+ .tp_init = py_kaitai_instance_init,
+ .tp_new = py_kaitai_instance_new,
+
+ };
+
+ return &py_kaitai_instance_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....KaitaiInstance. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_instance_is_registered(void)
+{
+ PyTypeObject *type; /* Type 'KaitaiInstance' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_instance_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_kaitai_attribute_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_INSTANCE, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en instance Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_instance(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_instance_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai instance");
+ break;
+
+ case 1:
+ *((GKaitaiInstance **)dst) = G_KAITAI_INSTANCE(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/parsers/instance.h b/plugins/kaitai/python/parsers/instance.h
new file mode 100644
index 0000000..8a0a6cf
--- /dev/null
+++ b/plugins/kaitai/python/parsers/instance.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/instance.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H
+#define _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_instance_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiInstance'. */
+bool ensure_python_kaitai_instance_is_registered(void);
+
+/* Tente de convertir en instance Kaitai. */
+int convert_to_kaitai_instance(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H */
diff --git a/plugins/kaitai/python/parsers/meta.c b/plugins/kaitai/python/parsers/meta.c
new file mode 100644
index 0000000..0bd7bf9
--- /dev/null
+++ b/plugins/kaitai/python/parsers/meta.c
@@ -0,0 +1,414 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * meta.h - équivalent Python du fichier "plugins/kaitai/parsers/meta.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "meta.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "../../parsers/meta-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_meta, G_TYPE_KAITAI_META);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_meta_init(PyObject *, PyObject *, PyObject *);
+
+/* Fournit l'identifié associé à une définiton Kaitai. */
+static PyObject *py_kaitai_meta_get_id(PyObject *, void *);
+
+/* Fournit la désignation humaine d'une définiton Kaitai. */
+static PyObject *py_kaitai_meta_get_title(PyObject *, void *);
+
+/* Indique la liste des définitions à importer. */
+static PyObject *py_kaitai_meta_get_dependencies(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_meta_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GYamlNode *parent; /* Noeud Yaml de l'attribut */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiMeta *kmeta; /* Création GLib à transmettre */
+
+#define KAITAI_META_DOC \
+ "The KaitaiMeta class stores general information about a Kaitai definition,"\
+ " such as required imports or the default endianness for reading values.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " KaitaiMeta(parent)" \
+ "\n" \
+ "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \
+ " to Yaml data to load.\n" \
+ "\n" \
+ "The class is the Python bindings for a C implementation of the MetaSpec" \
+ " structure described at https://doc.kaitai.io/ksy_diagram.html."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ kmeta = G_KAITAI_META(pygobject_get(self));
+
+ if (!g_kaitai_meta_create(kmeta, parent))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai global description."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit l'identifié associé à une définiton Kaitai. *
+* *
+* Retour : Identifiant de définition complète ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_meta_get_id(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiMeta *meta; /* Version native de l'objet */
+ const char *id; /* Valeur à transmettre */
+
+#define KAITAI_META_ID_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ id, py_kaitai_meta, \
+ "Identifier for the Kaitai definition, as a string" \
+ " value or *None* if any." \
+)
+
+ meta = G_KAITAI_META(pygobject_get(self));
+
+ id = g_kaitai_meta_get_id(meta);
+
+ if (id != NULL)
+ result = PyUnicode_FromString(id);
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit la désignation humaine d'une définiton Kaitai. *
+* *
+* Retour : Intitulé de définition ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_meta_get_title(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiMeta *meta; /* Version native de l'objet */
+ const char *title; /* Valeur à transmettre */
+
+#define KAITAI_META_TITLE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ title, py_kaitai_meta, \
+ "Humain description for the Kaitai definition, as a" \
+ " string value or *None* if any." \
+)
+
+ meta = G_KAITAI_META(pygobject_get(self));
+
+ title = g_kaitai_meta_get_title(meta);
+
+ if (title != NULL)
+ result = PyUnicode_FromString(title);
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit la désignation humaine d'une définiton Kaitai. *
+* *
+* Retour : Intitulé de définition ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_meta_get_endian(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiMeta *meta; /* Version native de l'objet */
+ SourceEndian endian; /* Valeur à transmettre */
+
+#define KAITAI_META_ENDIAN_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ endian, py_kaitai_meta, \
+ "Default endianness for the Kaitai definition, as a" \
+ " pychrysalide.analysis.BinContent.SourceEndian value." \
+)
+
+ meta = G_KAITAI_META(pygobject_get(self));
+
+ endian = g_kaitai_meta_get_endian(meta);
+
+ result = cast_with_constants_group_from_type(get_python_binary_content_type(), "SourceEndian", endian);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique la liste des définitions à importer. *
+* *
+* Retour : Liste de désignations de définitions, vide ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_meta_get_dependencies(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiMeta *meta; /* Version native de l'objet */
+ const char * const *dependencies; /* Liste d'imports requis */
+ size_t count; /* Quantité de ces imports */
+ size_t i; /* Boucle de parcours */
+
+#define KAITAI_META_DEPENDENCIES_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ dependencies, py_kaitai_meta, \
+ "Tuple of all definitions to import for the current" \
+ " definition.\n" \
+ "\n" \
+ "The result may be an empty string list." \
+)
+
+ meta = G_KAITAI_META(pygobject_get(self));
+
+ dependencies = g_kaitai_meta_get_dependencies(meta, &count);
+
+ result = PyTuple_New(count);
+
+ for (i = 0; i < count; i++)
+ PyTuple_SetItem(result, i, PyUnicode_FromString(dependencies[i]));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_meta_type(void)
+{
+ static PyMethodDef py_kaitai_meta_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_meta_getseters[] = {
+ KAITAI_META_ID_ATTRIB,
+ KAITAI_META_TITLE_ATTRIB,
+ KAITAI_META_ENDIAN_ATTRIB,
+ KAITAI_META_DEPENDENCIES_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_meta_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiMeta",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+
+ .tp_doc = KAITAI_META_DOC,
+
+ .tp_methods = py_kaitai_meta_methods,
+ .tp_getset = py_kaitai_meta_getseters,
+
+ .tp_init = py_kaitai_meta_init,
+ .tp_new = py_kaitai_meta_new
+
+ };
+
+ return &py_kaitai_meta_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiMeta. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_meta_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'KaitaiMeta' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_meta_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_META, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en description globale Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_meta(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_meta_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai global description");
+ break;
+
+ case 1:
+ *((GKaitaiMeta **)dst) = G_KAITAI_META(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/yaml/python/scalar.h b/plugins/kaitai/python/parsers/meta.h
index 3812bd7..383cad9 100644
--- a/plugins/yaml/python/scalar.h
+++ b/plugins/kaitai/python/parsers/meta.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * scalar.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/scalar.h"
+ * meta.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/meta.h"
*
* Copyright (C) 2019 Cyrille Bagard
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_YAML_PYTHON_SCALAR_H
-#define _PLUGINS_YAML_PYTHON_SCALAR_H
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_META_H
+#define _PLUGINS_KAITAI_PYTHON_PARSERS_META_H
#include <Python.h>
@@ -32,14 +32,14 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_yaml_scalar_type(void);
+PyTypeObject *get_python_kaitai_meta_type(void);
-/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlScalar'. */
-bool register_python_yaml_scalar(PyObject *);
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiMeta'. */
+bool ensure_python_kaitai_meta_is_registered(void);
-/* Tente de convertir en noeud d'arborescence de format Yaml. */
-int convert_to_yaml_scalar(PyObject *, void *);
+/* Tente de convertir en description globale Kaitai. */
+int convert_to_kaitai_meta(PyObject *, void *);
-#endif /* _PLUGINS_YAML_PYTHON_SCALAR_H */
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_META_H */
diff --git a/plugins/kaitai/python/parsers/module.c b/plugins/kaitai/python/parsers/module.c
new file mode 100644
index 0000000..549f728
--- /dev/null
+++ b/plugins/kaitai/python/parsers/module.c
@@ -0,0 +1,124 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire parsers en tant que module
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "attribute.h"
+#include "enum.h"
+#include "instance.h"
+#include "meta.h"
+#include "struct.h"
+#include "type.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Ajoute le module 'plugins.kaitai.parsers' au module Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_kaitai_parsers_module(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *super; /* Module à compléter */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_PLUGINS_KAITAI_PARSERS_DOC \
+ "This module provides implementation for several Kaitai" \
+ " definitions parsers."
+
+ static PyModuleDef py_chrysalide_kaitai_parsers_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.plugins.kaitai.parsers",
+ .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_PARSERS_DOC,
+
+ .m_size = -1,
+
+ };
+
+ result = false;
+
+ super = get_access_to_python_module("pychrysalide.plugins.kaitai");
+
+ module = build_python_module(super, &py_chrysalide_kaitai_parsers_module);
+
+ result = (module != NULL);
+
+ assert(result);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'plugins.kaitai.parsers'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_kaitai_parsers_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_kaitai_attribute_is_registered();
+ if (result) result = ensure_python_kaitai_enum_is_registered();
+ if (result) result = ensure_python_kaitai_instance_is_registered();
+ if (result) result = ensure_python_kaitai_meta_is_registered();
+ if (result) result = ensure_python_kaitai_structure_is_registered();
+ if (result) result = ensure_python_kaitai_type_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/parsers/module.h b/plugins/kaitai/python/parsers/module.h
new file mode 100644
index 0000000..d0fdd66
--- /dev/null
+++ b/plugins/kaitai/python/parsers/module.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire parsers en tant que module
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H
+#define _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins.kaitai.parsers' au module Python. */
+bool add_kaitai_parsers_module(void);
+
+/* Intègre les objets du module 'plugins.kaitai.parsers'. */
+bool populate_kaitai_parsers_module(void);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H */
diff --git a/plugins/kaitai/python/parsers/struct.c b/plugins/kaitai/python/parsers/struct.c
new file mode 100644
index 0000000..900cd1b
--- /dev/null
+++ b/plugins/kaitai/python/parsers/struct.c
@@ -0,0 +1,376 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct.h - équivalent Python du fichier "plugins/kaitai/struct.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "struct.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+
+
+#include "../parser.h"
+#include "../../parsers/struct-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_structure, G_TYPE_KAITAI_STRUCT);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_structure_init(PyObject *, PyObject *, PyObject *);
+
+/* Parcourt un contenu binaire selon une description Kaitai. */
+static PyObject *py_kaitai_structure_parse(PyObject *, PyObject *);
+
+/* Fournit la désignation humaine d'une définiton Kaitai. */
+static PyObject *py_kaitai_structure_get_meta(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_structure_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ const char *text; /* Contenu de règles à traiter */
+ const char *filename; /* Fichier de définitions */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiStruct *kstruct; /* Création GLib à transmettre */
+
+ static char *kwlist[] = { "text", "filename", NULL };
+
+#define KAITAI_STRUCT_DOC \
+ "KaitaiStruct is the class providing support for parsing binary contents" \
+ " using a special declarative language." \
+ "\n" \
+ "Instances can be created using one of the following constructors:\n" \
+ "\n" \
+ " KaitaiStruct(text=str)" \
+ "\n" \
+ " KaitaiStruct(filename=str)" \
+ "\n" \
+ "Where *text* is a string containg a markup content to parse; the" \
+ " *filename* argument is an alternative string for a path pointing to the" \
+ " same kind of content. This path can be a real filename or a resource" \
+ " URI." \
+ "\n" \
+ "It is the Python bindings for a C implementation of the specifications" \
+ " described at http://kaitai.io/."
+
+ /* Récupération des paramètres */
+
+ text = NULL;
+ filename = NULL;
+
+ ret = PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, &text, &filename);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ kstruct = G_KAITAI_STRUCT(pygobject_get(self));
+
+ if (text != NULL)
+ {
+ if (!g_kaitai_structure_create_from_text(kstruct, text))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai structure."));
+ return -1;
+ }
+
+ }
+
+ else if (filename != NULL)
+ {
+ if (!g_kaitai_structure_create_from_file(kstruct, filename))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai structure."));
+ return -1;
+ }
+
+ }
+
+ else
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create empty Kaitai structure."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = instance de l'interpréteur Kaitai à manipuler. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Parcourt un contenu binaire selon une description Kaitai. *
+* *
+* Retour : Arborescence d'éléments rencontrés selon les spécifications. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_structure_parse(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ GBinContent *content; /* Contenu binaire à traiter */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiStruct *kstruct; /* Interpréteur Kaitai courant */
+ GMatchRecord *record; /* Ensemble de correspondances */
+
+#define KAITAI_STRUCTURE_PARSE_METHOD PYTHON_METHOD_DEF \
+( \
+ parse, "$self, content", \
+ METH_VARARGS, py_kaitai_structure, \
+ "Parse a binary content with the loaded specifications." \
+ "\n" \
+ "The content has to be a pychrysalide.analysis.BinContent instance.\n" \
+ "\n" \
+ "The result is *None* if the parsing failed, or a" \
+ " pychrysalide.plugins.kaitai.MatchRecord object for each attribute" \
+ " met." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_binary_content, &content);
+ if (!ret) return NULL;
+
+ kstruct = G_KAITAI_STRUCT(pygobject_get(self));
+
+ record = g_kaitai_structure_parse(kstruct, content);
+
+ if (record != NULL)
+ {
+ result = pygobject_new(G_OBJECT(record));
+ g_object_unref(G_OBJECT(record));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit la désignation humaine d'une définiton Kaitai. *
+* *
+* Retour : Intitulé de définition OU None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_structure_get_meta(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiStruct *kstruct; /* Version native de l'objet */
+ GKaitaiMeta *meta; /* Informations à transmettre */
+
+#define KAITAI_STRUCTURE_META_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ meta, py_kaitai_structure, \
+ "Global description provided for the Kaitai definition, as a" \
+ " pychrysalide.plugins.kaitai.parsers.KaitaiMeta instance." \
+)
+
+ kstruct = G_KAITAI_STRUCT(pygobject_get(self));
+
+ meta = g_kaitai_structure_get_meta(kstruct);
+
+ if (meta != NULL)
+ {
+ result = pygobject_new(G_OBJECT(meta));
+ g_object_unref(G_OBJECT(meta));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_structure_type(void)
+{
+ static PyMethodDef py_kaitai_structure_methods[] = {
+ KAITAI_STRUCTURE_PARSE_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_structure_getseters[] = {
+ KAITAI_STRUCTURE_META_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_structure_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiStruct",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+
+ .tp_doc = KAITAI_STRUCT_DOC,
+
+ .tp_methods = py_kaitai_structure_methods,
+ .tp_getset = py_kaitai_structure_getseters,
+
+ .tp_init = py_kaitai_structure_init,
+ .tp_new = py_kaitai_structure_new
+
+ };
+
+ return &py_kaitai_structure_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiStruct.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_structure_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'KaitaiStruct' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_structure_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_kaitai_parser_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_STRUCT, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en structure de données Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_structure(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_structure_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai structure");
+ break;
+
+ case 1:
+ *((GKaitaiStruct **)dst) = G_KAITAI_STRUCT(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/parsers/struct.h b/plugins/kaitai/python/parsers/struct.h
new file mode 100644
index 0000000..872f744
--- /dev/null
+++ b/plugins/kaitai/python/parsers/struct.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/struct.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H
+#define _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_structure_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiStruct'. */
+bool ensure_python_kaitai_structure_is_registered(void);
+
+/* Tente de convertir en structure de données Kaitai. */
+int convert_to_kaitai_structure(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H */
diff --git a/plugins/kaitai/python/parsers/type.c b/plugins/kaitai/python/parsers/type.c
new file mode 100644
index 0000000..64a3419
--- /dev/null
+++ b/plugins/kaitai/python/parsers/type.c
@@ -0,0 +1,278 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type.h - équivalent Python du fichier "plugins/kaitai/parsers/type.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "type.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "struct.h"
+#include "../../parsers/type-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_type, G_TYPE_KAITAI_TYPE);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_type_init(PyObject *, PyObject *, PyObject *);
+
+/* Indique le nom de scène du type représenté. */
+static PyObject *py_kaitai_type_get_name(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_type_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GYamlNode *parent; /* Noeud Yaml de l'attribut */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiType *attrib; /* Création GLib à transmettre */
+
+#define KAITAI_TYPE_DOC \
+ "The KaitaiType class provides support for user-defined type used in" \
+ " Kaitai definitions.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " KaitaiType(parent)" \
+ "\n" \
+ "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \
+ " to Yaml data to load.\n" \
+ "\n" \
+ "The class is the Python bindings for a C implementation of the TypesSpec" \
+ " structure described at https://doc.kaitai.io/ksy_diagram.html."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ attrib = G_KAITAI_TYPE(pygobject_get(self));
+
+ if (!g_kaitai_type_create(attrib, parent))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai type."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique le nom de scène du type représenté. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_type_get_name(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiType *type; /* Version native du type */
+ const char *name; /* Désignation à transmettre */
+
+#define KAITAI_TYPE_NAME_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ name, py_kaitai_type, \
+ "Name of the user-defined type, provided as a unique" \
+ " string value." \
+)
+
+ type = G_KAITAI_TYPE(pygobject_get(self));
+
+ name = g_kaitai_type_get_name(type);
+ assert(name != NULL);
+
+ result = PyUnicode_FromString(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_type_type(void)
+{
+ static PyMethodDef py_kaitai_type_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_type_getseters[] = {
+ KAITAI_TYPE_NAME_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_type_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiType",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = KAITAI_TYPE_DOC,
+
+ .tp_methods = py_kaitai_type_methods,
+ .tp_getset = py_kaitai_type_getseters,
+
+ .tp_init = py_kaitai_type_init,
+ .tp_new = py_kaitai_type_new,
+
+ };
+
+ return &py_kaitai_type_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....parsers.KaitaiType. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_type_is_registered(void)
+{
+ PyTypeObject *type; /* Type 'KaitaiType' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_type_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_kaitai_structure_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_TYPE, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en type particulier pour Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_type(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_type_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai type");
+ break;
+
+ case 1:
+ *((GKaitaiType **)dst) = G_KAITAI_TYPE(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/parsers/type.h b/plugins/kaitai/python/parsers/type.h
new file mode 100644
index 0000000..320bc71
--- /dev/null
+++ b/plugins/kaitai/python/parsers/type.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/type.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H
+#define _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_type_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiType'. */
+bool ensure_python_kaitai_type_is_registered(void);
+
+/* Tente de convertir en type particulier pour Kaitai. */
+int convert_to_kaitai_type(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H */
diff --git a/plugins/yaml/python/line.c b/plugins/kaitai/python/record.c
index 11898d2..4194a9a 100644
--- a/plugins/yaml/python/line.c
+++ b/plugins/kaitai/python/record.c
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * line.c - équivalent Python du fichier "plugins/yaml/line.c"
+ * record.h - équivalent Python du fichier "plugins/kaitai/record.h"
*
* Copyright (C) 2019 Cyrille Bagard
*
@@ -22,126 +22,106 @@
*/
-#include "line.h"
+#include "record.h"
#include <pygobject.h>
+#include <plugins/pychrysalide/access.h>
#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
-#include "../line.h"
+#include "parser.h"
+#include "../record.h"
-/* Crée un nouvel objet Python de type 'YamlLine'. */
-static PyObject *py_yaml_line_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(match_record, G_TYPE_MATCH_RECORD, NULL);
-/* Fournit la taille de l'indentation d'une ligne Yaml. */
-static PyObject *py_yaml_line_get_indent(PyObject *, void *);
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_match_record_init(PyObject *, PyObject *, PyObject *);
-/* Indique si la ligne représente un élément de liste. */
-static PyObject *py_yaml_line_is_list_item(PyObject *, void *);
+/* Modifie la référence au créateur de la correspondance. */
+static int py_match_record_set_creator(PyObject *, PyObject *, void *);
-/* Fournit la charge utile associée à une ligne Yaml. */
-static PyObject *py_yaml_line_get_payload(PyObject *, void *);
+/* Renvoie vers le lecteur à l'origine de la correspondance. */
+static PyObject *py_match_record_get_creator(PyObject *, void *);
-/* Fournit la clef associée à une ligne Yaml si elle existe. */
-static PyObject *py_yaml_line_get_key(PyObject *, void *);
+/* Fournit le contenu lié à une correspondance établie. */
+static PyObject *py_match_record_get_content(PyObject *, void *);
-/* Fournit la valeur associée à une ligne Yaml si elle existe. */
-static PyObject *py_yaml_line_get_value(PyObject *, void *);
+/* Calcule ou fournit la zone couverte par une correspondance. */
+static PyObject *py_match_record_get_range(PyObject *, void *);
+
+/* Lit les octets bruts couverts par une correspondance. */
+static PyObject *py_match_record_get_raw_bytes(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'YamlLine'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_line_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_match_record_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
- const char *raw; /* Données Yaml brutes */
- Py_ssize_t index; /* Indice de ligne associée */
int ret; /* Bilan de lecture des args. */
- GYamlLine *line; /* Création GLib à transmettre */
-
-#define YAML_LINE_DOC \
- "YamlLine handles a line of Yaml data.\n" \
- "\n" \
- "The data may be a couple of key/value, a comment, aso.\n" \
- "\n" \
- "Instances can be created using the following constructor:\n" \
- "\n" \
- " YamlTree(raw, number)" \
- "\n" \
- "Where raw is a string providing raw data and number the index" \
- " of the line in the overall stream."
-
- ret = PyArg_ParseTuple(args, "sn", &raw, &index);
- if (!ret) return NULL;
-
- line = g_yaml_line_new(raw, index);
-
- if (line == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
- else
- {
- g_object_ref_sink(G_OBJECT(line));
- result = pygobject_new(G_OBJECT(line));
- g_object_unref(line);
- }
+#define MATCH_RECORD_DOC \
+ "MatchRecord is an abstract class providing mainly location and raw" \
+ " data of an area which has matched a part of a binary content."
- return result;
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
}
/******************************************************************************
* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
+* Paramètres : self = correspondance à manipuler. *
+* value = lecteur à l'origine de la correspondance. *
+* closure = adresse non utilisée ici. *
* *
-* Description : Fournit la taille de l'indentation d'une ligne Yaml. *
+* Description : Modifie la référence au créateur de la correspondance. *
* *
-* Retour : Taille de l'indentation rencontrée. *
+* Retour : Bilan de la définition. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_line_get_indent(PyObject *self, void *closure)
+static int py_match_record_set_creator(PyObject *self, PyObject *value, void *closure)
{
- PyObject *result; /* Résultat à retourner */
- GYamlLine *line; /* Version GLib du type */
- size_t indent; /* Taille de l'indentation */
-
-#define YAML_LINE_INDENT_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- indent, py_yaml_line, \
- "Quantity of characters used for the indentation." \
-)
+ int result; /* Bilan à renvoyer */
+ GMatchRecord *record; /* Version GLib de l'objet */
+ GKaitaiParser *parser; /* Lecteur à l'origine */
- line = G_YAML_LINE(pygobject_get(self));
+ record = G_MATCH_RECORD(pygobject_get(self));
- indent = g_yaml_line_count_indent(line);
+ if (!convert_to_kaitai_parser(value, &parser))
+ result = -1;
- result = PyLong_FromSize_t(indent);
+ else
+ {
+ g_match_record_fix_creator(record, parser);
+ result = 0;
+ }
return result;
@@ -150,35 +130,38 @@ static PyObject *py_yaml_line_get_indent(PyObject *self, void *closure)
/******************************************************************************
* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
+* Paramètres : self = correspondance à manipuler. *
+* closure = adresse non utilisée ici. *
* *
-* Description : Indique si la ligne représente un élément de liste. *
+* Description : Renvoie vers le lecteur à l'origine de la correspondance. *
* *
-* Retour : Statut de l'état lié à une liste d'éléments. *
+* Retour : Lecteur à l'origine de la création. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_line_is_list_item(PyObject *self, void *closure)
+static PyObject *py_match_record_get_creator(PyObject *self, void *closure)
{
- PyObject *result; /* Résultat à retourner */
- GYamlLine *line; /* Version GLib du type */
- bool status; /* Statut de la ligne */
-
-#define YAML_LINE_IS_LIST_ITEM_ATTRIB PYTHON_IS_DEF_FULL \
-( \
- list_item, py_yaml_line, \
- "Tell if the line starts a new list item." \
+ PyObject *result; /* Instance à retourner */
+ GMatchRecord *record; /* Version GLib de l'objet */
+ GKaitaiParser *parser; /* Lecteur à l'origine */
+
+#define MATCH_RECORD_CREATOR_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ creator, py_match_record, \
+ "Provide or define the pychrysalide.plugins.kaitai.KaitaiParser instance" \
+ " which has created the record.\n" \
+ "\n" \
+ "This field should not be defined after the record creation in most cases." \
)
- line = G_YAML_LINE(pygobject_get(self));
+ record = G_MATCH_RECORD(pygobject_get(self));
- status = g_yaml_line_is_list_item(line);
+ parser = g_match_record_get_creator(record);
- result = status ? Py_True : Py_False;
- Py_INCREF(result);
+ result = pygobject_new(G_OBJECT(parser));
+ g_object_unref(parser);
return result;
@@ -190,31 +173,40 @@ static PyObject *py_yaml_line_is_list_item(PyObject *self, void *closure)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit la charge utile associée à une ligne Yaml. *
+* Description : Fournit le contenu lié à une correspondance établie. *
* *
-* Retour : Contenu sous forme de chaîne de caractères. *
+* Retour : Contenu binaire associé. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_line_get_payload(PyObject *self, void *closure)
+static PyObject *py_match_record_get_content(PyObject *self, void *closure)
{
- PyObject *result; /* Résultat à retourner */
- GYamlLine *line; /* Version GLib du type */
- const char *payload; /* Chaîne à transmettre */
-
-#define YAML_LINE_PAYLOAD_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- payload, py_yaml_line, \
- "Payload of the Yaml line." \
-)
+ PyObject *result; /* Valeur à retourner */
+ GMatchRecord *record; /* Conservation à consulter */
+ GBinContent *content; /* Contenu associé */
- line = G_YAML_LINE(pygobject_get(self));
+#define MATCH_RECORD_CONTENT_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ content, py_match_record, \
+ "pychrysalide.analysis.BinContent instance linked to" \
+ " the match record." \
+)
- payload = g_yaml_line_get_payload(line);
+ record = G_MATCH_RECORD(pygobject_get(self));
+ content = g_match_record_get_content(record);
- result = PyUnicode_FromString(payload);
+ if (content != NULL)
+ {
+ result = pygobject_new(G_OBJECT(content));
+ g_object_unref(G_OBJECT(content));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
return result;
@@ -226,38 +218,33 @@ static PyObject *py_yaml_line_get_payload(PyObject *self, void *closure)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit la clef associée à une ligne Yaml si elle existe. *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
* *
-* Retour : Clef sous forme de chaîne de caractères ou None. *
+* Retour : Zone de couverture déterminée. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_line_get_key(PyObject *self, void *closure)
+static PyObject *py_match_record_get_range(PyObject *self, void *closure)
{
- PyObject *result; /* Résultat à retourner */
- GYamlLine *line; /* Version GLib du type */
- const char *key; /* Chaîne à transmettre */
-
-#define YAML_LINE_KEY_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- key, py_yaml_line, \
- "Key linked to the Yaml line or None." \
-)
-
- line = G_YAML_LINE(pygobject_get(self));
+ PyObject *result; /* Valeur à retourner */
+ GMatchRecord *record; /* Conservation à consulter */
+ mrange_t range; /* Couverture courante */
- key = g_yaml_line_get_key(line);
+#define MATCH_RECORD_RANGE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ range, py_match_record, \
+ "Area of the matched data for the parsed attribute" \
+ " against a given binary content.\n" \
+ "\n" \
+ "This property is a pychrysalide.arch.mrange instance." \
+)
- if (key == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
+ record = G_MATCH_RECORD(pygobject_get(self));
+ g_match_record_get_range(record, &range);
- else
- result = PyUnicode_FromString(key);
+ result = build_from_internal_mrange(&range);
return result;
@@ -269,38 +256,33 @@ static PyObject *py_yaml_line_get_key(PyObject *self, void *closure)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit la valeur associée à une ligne Yaml si elle existe. *
+* Description : Lit les octets bruts couverts par une correspondance. *
* *
-* Retour : Valeur sous forme de chaîne de caractères ou None. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_line_get_value(PyObject *self, void *closure)
+static PyObject *py_match_record_get_raw_bytes(PyObject *self, void *closure)
{
- PyObject *result; /* Résultat à retourner */
- GYamlLine *line; /* Version GLib du type */
- const char *value; /* Chaîne à transmettre */
-
-#define YAML_LINE_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- value, py_yaml_line, \
- "Value linked to the Yaml line or None." \
-)
+ PyObject *result; /* Valeur à retourner */
+ GMatchRecord *record; /* Conservation à consulter */
+ bin_t *out; /* Données brutes à transmettre*/
+ size_t len; /* Quantité de ces données */
- line = G_YAML_LINE(pygobject_get(self));
+#define MATCH_RECORD_RAW_BYTES_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ raw_bytes, py_match_record, \
+ "Raw bytes from the area covered by the record." \
+)
- value = g_yaml_line_get_value(line);
+ record = G_MATCH_RECORD(pygobject_get(self));
- if (value == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
+ g_match_record_read_raw_bytes(record, &out, &len);
- else
- result = PyUnicode_FromString(value);
+ result = PyBytes_FromStringAndSize((char *)out, len);
+ free(out);
return result;
@@ -319,48 +301,49 @@ static PyObject *py_yaml_line_get_value(PyObject *self, void *closure)
* *
******************************************************************************/
-PyTypeObject *get_python_yaml_line_type(void)
+PyTypeObject *get_python_match_record_type(void)
{
- static PyMethodDef py_yaml_line_methods[] = {
+ static PyMethodDef py_match_record_methods[] = {
{ NULL }
};
- static PyGetSetDef py_yaml_line_getseters[] = {
- YAML_LINE_INDENT_ATTRIB,
- YAML_LINE_IS_LIST_ITEM_ATTRIB,
- YAML_LINE_PAYLOAD_ATTRIB,
- YAML_LINE_KEY_ATTRIB,
- YAML_LINE_VALUE_ATTRIB,
+ static PyGetSetDef py_match_record_getseters[] = {
+ MATCH_RECORD_CREATOR_ATTRIB,
+ MATCH_RECORD_CONTENT_ATTRIB,
+ MATCH_RECORD_RANGE_ATTRIB,
+ MATCH_RECORD_RAW_BYTES_ATTRIB,
{ NULL }
};
- static PyTypeObject py_yaml_line_type = {
+ static PyTypeObject py_match_record_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.plugins.yaml.YamlLine",
+ .tp_name = "pychrysalide.plugins.kaitai.MatchRecord",
.tp_basicsize = sizeof(PyGObject),
- .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = MATCH_RECORD_DOC,
- .tp_doc = YAML_LINE_DOC,
+ .tp_methods = py_match_record_methods,
+ .tp_getset = py_match_record_getseters,
- .tp_methods = py_yaml_line_methods,
- .tp_getset = py_yaml_line_getseters,
- .tp_new = py_yaml_line_new
+ .tp_init = py_match_record_init,
+ .tp_new = py_match_record_new,
};
- return &py_yaml_line_type;
+ return &py_match_record_type;
}
/******************************************************************************
* *
-* Paramètres : module = module dont la définition est à compléter. *
+* Paramètres : - *
* *
-* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlLine. *
+* Description : Prend en charge l'objet 'pychrysalide.plugins...MatchRecord. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -368,17 +351,24 @@ PyTypeObject *get_python_yaml_line_type(void)
* *
******************************************************************************/
-bool register_python_yaml_line(PyObject *module)
+bool ensure_python_match_record_is_registered(void)
{
- PyTypeObject *type; /* Type Python 'YamlLine' */
+ PyTypeObject *type; /* Type Python 'MatchRecord' */
+ PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
- type = get_python_yaml_line_type();
+ type = get_python_match_record_type();
- dict = PyModule_GetDict(module);
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai");
- if (!register_class_for_pygobject(dict, G_TYPE_YAML_LINE, type, &PyGObject_Type))
- return false;
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_MATCH_RECORD, type))
+ return false;
+
+ }
return true;
@@ -390,7 +380,7 @@ bool register_python_yaml_line(PyObject *module)
* Paramètres : arg = argument quelconque à tenter de convertir. *
* dst = destination des valeurs récupérées en cas de succès. *
* *
-* Description : Tente de convertir en ligne de données au format Yaml. *
+* Description : Tente de convertir en conservation de correspondance. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
* *
@@ -398,11 +388,11 @@ bool register_python_yaml_line(PyObject *module)
* *
******************************************************************************/
-int convert_to_yaml_line(PyObject *arg, void *dst)
+int convert_to_match_record(PyObject *arg, void *dst)
{
int result; /* Bilan à retourner */
- result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_line_type());
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_match_record_type());
switch (result)
{
@@ -412,11 +402,11 @@ int convert_to_yaml_line(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml line");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to match record");
break;
case 1:
- *((GYamlLine **)dst) = G_YAML_LINE(pygobject_get(arg));
+ *((GMatchRecord **)dst) = G_MATCH_RECORD(pygobject_get(arg));
break;
default:
diff --git a/plugins/yaml/python/tree.h b/plugins/kaitai/python/record.h
index df9d5b8..edf75fc 100644
--- a/plugins/yaml/python/tree.h
+++ b/plugins/kaitai/python/record.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * tree.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/tree.h"
+ * record.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/record.h"
*
* Copyright (C) 2019 Cyrille Bagard
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_YAML_PYTHON_TREE_H
-#define _PLUGINS_YAML_PYTHON_TREE_H
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORD_H
+#define _PLUGINS_KAITAI_PYTHON_RECORD_H
#include <Python.h>
@@ -32,14 +32,14 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_yaml_tree_type(void);
+PyTypeObject *get_python_match_record_type(void);
-/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlTree'. */
-bool register_python_yaml_tree(PyObject *);
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.MatchRecord'. */
+bool ensure_python_match_record_is_registered(void);
-/* Tente de convertir en arborescence de lignes au format Yaml. */
-int convert_to_yaml_tree(PyObject *, void *);
+/* Tente de convertir en conservation de correspondance. */
+int convert_to_match_record(PyObject *, void *);
-#endif /* _PLUGINS_YAML_PYTHON_TREE_H */
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORD_H */
diff --git a/plugins/kaitai/python/records/Makefile.am b/plugins/kaitai/python/records/Makefile.am
new file mode 100644
index 0000000..3a3c672
--- /dev/null
+++ b/plugins/kaitai/python/records/Makefile.am
@@ -0,0 +1,19 @@
+
+noinst_LTLIBRARIES = libkaitaipythonrecords.la
+
+libkaitaipythonrecords_la_SOURCES = \
+ bits.h bits.c \
+ delayed.h delayed.c \
+ empty.h empty.c \
+ group.h group.c \
+ item.h item.c \
+ list.h list.c \
+ module.h module.c
+
+libkaitaipythonrecords_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitaipythonrecords_la_SOURCES:%c=)
diff --git a/plugins/kaitai/python/records/bits.c b/plugins/kaitai/python/records/bits.c
new file mode 100644
index 0000000..f94148b
--- /dev/null
+++ b/plugins/kaitai/python/records/bits.c
@@ -0,0 +1,318 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bits.h - équivalent Python du fichier "plugins/kaitai/parsers/bits.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "bits.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
+
+
+#include "../record.h"
+#include "../parsers/attribute.h"
+#include "../../records/bits-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(record_bit_field, G_TYPE_RECORD_BIT_FIELD);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_record_bit_field_init(PyObject *, PyObject *, PyObject *);
+
+/* Lit la valeur d'un élément Kaitai entier représenté. */
+static PyObject *py_record_bit_field_get_value(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_record_bit_field_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+#if 0
+ GKaitaiAttribute *attrib; /* Attribut défini créateur */
+ GBinContent *content; /* Contenu binaire analysé */
+ mrange_t range; /* Espace couvert */
+ SourceEndian endian; /* Boutisme à observer */
+ int ret; /* Bilan de lecture des args. */
+ GRecordBitField *field; /* Création GLib à transmettre */
+#endif
+
+#define RECORD_BIT_FIELD_DOC \
+ "The RecordItem class remembers a match between a described attribute and" \
+ " its concret value read from parsed binary data." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " RecordItem(content, range, endian, attrib)" \
+ "\n" \
+ "Where the *attrib* arguments refers to a" \
+ " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance as the" \
+ " creator of the newly created object, *content* points to a" \
+ " pychrysalide.analysis.BinContent instance, *range* is a" \
+ " pychrysalide.arch.mrange object, *endian* states with a" \
+ " pychrysalide.analysis.BinContent.SourceEndian hint the endianness used" \
+ " to read integer values."
+
+ /* Récupération des paramètres */
+
+#if 0 /* FIXME */
+
+ ret = PyArg_ParseTuple(args, "O&O&O&",
+ convert_to_kaitai_attribute, &attrib,
+ convert_to_binary_content, &content,
+ convert_any_to_mrange, &range,
+ convert_to_binary_content, &endian);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ field = G_RECORD_BIT_FIELD(pygobject_get(self));
+
+ if (!g_record_bit_field_create(field, attrib, content, &range, endian))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create record bit field."));
+ return -1;
+ }
+
+ return 0;
+
+#endif
+
+ PyErr_SetString(PyExc_ValueError, _("Unable to create record bit field at the moment."));
+ return -1;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Lit la valeur d'un élément Kaitai entier représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_record_bit_field_get_value(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GRecordBitField *field; /* Version native de l'élément */
+ resolved_value_t resolved; /* Valeur sous forme générique */
+ bool status; /* Bilan d'opération */
+
+#define RECORD_BIT_FIELD_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ value, py_record_bit_field, \
+ "Carried value (as integer), or None in case of error." \
+)
+
+ result = NULL;
+
+ field = G_RECORD_BIT_FIELD(pygobject_get(self));
+
+ status = g_record_bit_field_get_value(field, &resolved);
+
+ if (status)
+ switch (resolved.type)
+ {
+ case GVT_UNSIGNED_INTEGER:
+ result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer);
+ break;
+
+ default:
+ assert(false);
+ result = Py_None;
+ Py_INCREF(result);
+ break;
+
+ }
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_record_bit_field_type(void)
+{
+ static PyMethodDef py_record_bit_field_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_record_bit_field_getseters[] = {
+ RECORD_BIT_FIELD_VALUE_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_record_bit_field_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.records.RecordBitField",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = RECORD_BIT_FIELD_DOC,
+
+ .tp_methods = py_record_bit_field_methods,
+ .tp_getset = py_record_bit_field_getseters,
+
+ .tp_init = py_record_bit_field_init,
+ .tp_new = py_record_bit_field_new,
+
+ };
+
+ return &py_record_bit_field_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.....RecordBitField. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_record_bit_field_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'RecordItem' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_record_bit_field_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.records");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_match_record_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_RECORD_BIT_FIELD, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en correspondance attribut/binaire. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_record_bit_field(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_record_bit_field_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record bit field");
+ break;
+
+ case 1:
+ *((GRecordBitField **)dst) = G_RECORD_BIT_FIELD(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/records/bits.h b/plugins/kaitai/python/records/bits.h
new file mode 100644
index 0000000..6c833bb
--- /dev/null
+++ b/plugins/kaitai/python/records/bits.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bits.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/bits.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_BITS_H
+#define _PLUGINS_KAITAI_PYTHON_RECORDS_BITS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_record_bit_field_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordBitField'. */
+bool ensure_python_record_bit_field_is_registered(void);
+
+/* Tente de convertir en correspondance attribut/binaire. */
+int convert_to_record_bit_field(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_BITS_H */
diff --git a/plugins/kaitai/python/records/delayed.c b/plugins/kaitai/python/records/delayed.c
new file mode 100644
index 0000000..32e3db1
--- /dev/null
+++ b/plugins/kaitai/python/records/delayed.c
@@ -0,0 +1,341 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * delayed.c - équivalent Python du fichier "plugins/kaitai/parsers/delayed.c"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "delayed.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "../record.h"
+#include "../scope.h"
+#include "../parsers/instance.h"
+#include "../../records/delayed-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(record_delayed, G_TYPE_RECORD_DELAYED);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_record_delayed_init(PyObject *, PyObject *, PyObject *);
+
+/* Lit la valeur d'un élément Kaitai entier représenté. */
+static PyObject *py_record_delayed_get_value(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_record_delayed_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GKaitaiInstance *inst; /* Instance définie créatrice */
+ kaitai_scope_t *locals; /* Environnement local */
+ GBinContent *content; /* Contenu binaire analysé */
+ int ret; /* Bilan de lecture des args. */
+ GRecordDelayed *delayed; /* Création GLib à transmettre */
+
+#define RECORD_DELAYED_DOC \
+ "The RecordDelayed class stores a link to an instance used to compute a" \
+ " given value." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " RecordDelayed(inst, locals, content)" \
+ "\n" \
+ "Where the *inst* arguments refers to a" \
+ " pychrysalide.plugins.kaitai.parsers.KaitaiInstance instance as the" \
+ " creator of the newly created object, *locals* points to a" \
+ " pychrysalide.plugins.kaitai.KaitaiScope structure used as current scope." \
+ " The *content* argument is a pychrysalide.analysis.BinContent instance if" \
+ " the delayed instance does not define a direct value."
+
+ /* Récupération des paramètres */
+
+ content = NULL;
+
+ ret = PyArg_ParseTuple(args, "O&O&|O&",
+ convert_to_kaitai_instance, &inst,
+ convert_to_kaitai_scope, &locals,
+ convert_to_binary_content_or_none, &content);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ delayed = G_RECORD_DELAYED(pygobject_get(self));
+
+ if (!g_record_delayed_create(delayed, inst, locals, content))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create record delayed."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Lit la valeur d'un élément Kaitai entier représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_record_delayed_get_value(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GRecordDelayed *delayed; /* Version native de l'élément */
+ resolved_value_t resolved; /* Valeur sous forme générique */
+ bool status; /* Bilan d'opération */
+
+#define RECORD_DELAYED_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ value, py_record_delayed, \
+ "Carried value (as integer, bytes), or None in case of error." \
+)
+
+ result = NULL;
+
+ delayed = G_RECORD_DELAYED(pygobject_get(self));
+
+ status = g_record_delayed_compute_and_aggregate_value(delayed, &resolved);
+
+ if (status)
+ switch (resolved.type)
+ {
+ case GVT_ERROR:
+ assert(false);
+ PyErr_Format(PyExc_RuntimeError,
+ _("Error got while parsing Kaitai definition should not have been exported!"));
+ result = NULL;
+ break;
+
+ case GVT_UNSIGNED_INTEGER:
+ result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer);
+ break;
+
+ case GVT_SIGNED_INTEGER:
+ result = PyLong_FromLongLong(resolved.signed_integer);
+ break;
+
+ case GVT_FLOAT:
+ result = PyFloat_FromDouble(resolved.floating_number);
+ break;
+
+ case GVT_BOOLEAN:
+ result = resolved.status ? Py_True : Py_False;
+ Py_INCREF(result);
+ break;
+
+ case GVT_BYTES:
+ result = PyBytes_FromStringAndSize(resolved.bytes.data, resolved.bytes.len);
+ exit_szstr(&resolved.bytes);
+ break;
+
+ case GVT_ARRAY:
+ result = pygobject_new(G_OBJECT(resolved.array));
+ break;
+
+ case GVT_RECORD:
+ result = pygobject_new(G_OBJECT(resolved.record));
+ break;
+
+ case GVT_STREAM:
+ result = pygobject_new(G_OBJECT(resolved.stream));
+ break;
+
+ }
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_record_delayed_type(void)
+{
+ static PyMethodDef py_record_delayed_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_record_delayed_getseters[] = {
+ RECORD_DELAYED_VALUE_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_record_delayed_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.records.RecordDelayed",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = RECORD_DELAYED_DOC,
+
+ .tp_methods = py_record_delayed_methods,
+ .tp_getset = py_record_delayed_getseters,
+
+ .tp_init = py_record_delayed_init,
+ .tp_new = py_record_delayed_new,
+
+ };
+
+ return &py_record_delayed_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide..records.RecordDelayed.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_record_delayed_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'RecordDelayed' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_record_delayed_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.records");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_match_record_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_RECORD_DELAYED, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en valeur calculée. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_record_delayed(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_record_delayed_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record delayed");
+ break;
+
+ case 1:
+ *((GRecordDelayed **)dst) = G_RECORD_DELAYED(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/records/delayed.h b/plugins/kaitai/python/records/delayed.h
new file mode 100644
index 0000000..ba2d23a
--- /dev/null
+++ b/plugins/kaitai/python/records/delayed.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * delayed.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/delayed.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_DELAYED_H
+#define _PLUGINS_KAITAI_PYTHON_RECORDS_DELAYED_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_record_delayed_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordDelayed'. */
+bool ensure_python_record_delayed_is_registered(void);
+
+/* Tente de convertir en valeur calculée. */
+int convert_to_record_delayed(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_DELAYED_H */
diff --git a/plugins/kaitai/python/records/empty.c b/plugins/kaitai/python/records/empty.c
new file mode 100644
index 0000000..9861a39
--- /dev/null
+++ b/plugins/kaitai/python/records/empty.c
@@ -0,0 +1,286 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * empty.c - équivalent Python du fichier "plugins/kaitai/parsers/empty.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "empty.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
+
+
+#include "../parser.h"
+#include "../record.h"
+#include "../../records/empty-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(record_empty, G_TYPE_RECORD_EMPTY);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_record_empty_init(PyObject *, PyObject *, PyObject *);
+
+/* Produit une absence de valeur pour la correspondance. */
+static PyObject *py_record_empty_get_value(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_record_empty_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GKaitaiParser *parser; /* Analyseur défini créateur */
+ GBinContent *content; /* Contenu binaire manipulé */
+ vmpa2t *pos; /* Tête de lecture courante */
+ int ret; /* Bilan de lecture des args. */
+ GRecordEmpty *empty; /* Création GLib à transmettre */
+
+#define RECORD_EMPTY_DOC \
+ "The RecordEmpty object reflects absolutely no match and should only get" \
+ " in some rare cases.\n" \
+ "\n" \
+ "Instances can be created using following constructor:\n" \
+ "\n" \
+ " RecordEmpty(parser, content, pos)" \
+ "\n" \
+ "Where *parser* is the creator of the record, as a" \
+ " pychrysalide.plugins.kaitai.KaitaiParser instance, *content* is a" \
+ " pychrysalide.analysis.BinContent instance providing the processed data" \
+ " and *pos* defines the current reading location, as a" \
+ " pychrysalide.arch.vmpa value."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&O&O&",
+ convert_to_kaitai_parser, &parser,
+ convert_to_binary_content, &content,
+ convert_any_to_vmpa, &pos);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ empty = G_RECORD_EMPTY(pygobject_get(self));
+
+ if (!g_record_empty_create(empty, parser, content, pos))
+ {
+ clean_vmpa_arg(pos);
+
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream."));
+ return -1;
+
+ }
+
+ clean_vmpa_arg(pos);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Produit une absence de valeur pour la correspondance. *
+* *
+* Retour : None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_record_empty_get_value(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+
+#define RECORD_EMPTY_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ value, py_record_empty, \
+ "Always *None*.\n" \
+ "\n" \
+ "This attribute is only provided to mimic other" \
+ " record types." \
+)
+
+ result = Py_None;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_record_empty_type(void)
+{
+ static PyMethodDef py_record_empty_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_record_empty_getseters[] = {
+ RECORD_EMPTY_VALUE_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_record_empty_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.records.RecordEmpty",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = RECORD_EMPTY_DOC,
+
+ .tp_methods = py_record_empty_methods,
+ .tp_getset = py_record_empty_getseters,
+
+ .tp_init = py_record_empty_init,
+ .tp_new = py_record_empty_new,
+
+ };
+
+ return &py_record_empty_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide...records.RecordEmpty. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_record_empty_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'RecordEmpty' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_record_empty_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.records");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_match_record_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_RECORD_EMPTY, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en zone de correspondance vide. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_record_empty(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_record_empty_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record empty");
+ break;
+
+ case 1:
+ *((GRecordEmpty **)dst) = G_RECORD_EMPTY(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/records/empty.h b/plugins/kaitai/python/records/empty.h
new file mode 100644
index 0000000..ecd5fc9
--- /dev/null
+++ b/plugins/kaitai/python/records/empty.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * empty.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/empty.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H
+#define _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_record_empty_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordEmpty'. */
+bool ensure_python_record_empty_is_registered(void);
+
+/* Tente de convertir en zone de correspondance vide. */
+int convert_to_record_empty(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H */
diff --git a/plugins/kaitai/python/records/group.c b/plugins/kaitai/python/records/group.c
new file mode 100644
index 0000000..a050043
--- /dev/null
+++ b/plugins/kaitai/python/records/group.c
@@ -0,0 +1,305 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * group.h - équivalent Python du fichier "plugins/kaitai/parsers/group.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "group.h"
+
+
+#include <pygobject.h>
+#include <string.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "../record.h"
+#include "../parsers/struct.h"
+#include "../../records/group-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(record_group, G_TYPE_RECORD_GROUP);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_record_group_init(PyObject *, PyObject *, PyObject *);
+
+/* Assure l'encadrement des accès aux champs d'une séquence. */
+static PyObject *py_record_group_getattr(PyObject *, char *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_record_group_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GKaitaiStruct *kstruct; /* Séquence définie créatrice */
+ GBinContent *content; /* Contenu binaire analysé */
+ int ret; /* Bilan de lecture des args. */
+ GRecordGroup *group; /* Création GLib à transmettre */
+
+#define RECORD_GROUP_DOC \
+ "The RecordGroup class stores a map of parsed attributes with their" \
+ " relative values. Each of theses Kaitai attributes can be accessed as" \
+ " usual Python attribute.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " RecordGroup(kstruct, content)" \
+ "\n" \
+ "Where the *kstruct* refers to a" \
+ " pychrysalide.plugins.kaitai.parsers.KaitaiStructure instance as the" \
+ " creator of the newly created object, and *content* points to a" \
+ " pychrysalide.analysis.BinContent instance."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&O&",
+ convert_to_kaitai_structure, &kstruct,
+ convert_to_binary_content, &content);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ group = G_RECORD_GROUP(pygobject_get(self));
+
+ if (!g_record_group_create(group, kstruct, content))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create record group."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = structure C convertie en Python. *
+* name = nom du champ auquel un accès est demandé. *
+* *
+* Description : Assure l'encadrement des accès aux champs d'une séquence. *
+* *
+* Retour : Valeur du champ demandé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_record_group_getattr(PyObject *self, char *name)
+{
+ PyObject *result; /* Elément à retourner */
+ GRecordGroup *group; /* Version native de l'objet */
+ GMatchRecord *found; /* Sous-élément identifié */
+ PyObject *w; /* Conversion du nom de champ */
+ PyTypeObject *tp; /* Type de l'objet manipulé */
+
+ group = G_RECORD_GROUP(pygobject_get(self));
+
+ found = g_match_record_find_by_name(G_MATCH_RECORD(group), name, strlen(name), DIRECT_SEARCH_DEEP_LEVEL);
+
+ if (found != NULL)
+ {
+ result = pygobject_new(G_OBJECT(found));
+ g_object_unref(G_OBJECT(found));
+ }
+
+ else
+ {
+ w = PyUnicode_InternFromString(name);
+ if (w == NULL) return NULL;
+
+ tp = Py_TYPE(self);
+
+ if (tp->tp_base->tp_getattro != NULL)
+ result = tp->tp_base->tp_getattro(self, w);
+
+ else
+ {
+ PyErr_Format(PyExc_AttributeError,
+ "type object '%.50s' has no attribute '%U'",
+ tp->tp_name, name);
+ result = NULL;
+ }
+
+ Py_DECREF(w);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_record_group_type(void)
+{
+ static PyMethodDef py_record_group_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_record_group_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_record_group_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.records.RecordGroup",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_getattr = py_record_group_getattr,
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = RECORD_GROUP_DOC,
+
+ .tp_methods = py_record_group_methods,
+ .tp_getset = py_record_group_getseters,
+
+ .tp_init = py_record_group_init,
+ .tp_new = py_record_group_new,
+
+ };
+
+ return &py_record_group_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide...records.RecordGroup. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_record_group_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'RecordGroup' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_record_group_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.records");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_match_record_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_RECORD_GROUP, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en correspondances attribut/binaire. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_record_group(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_record_group_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record group");
+ break;
+
+ case 1:
+ *((GRecordGroup **)dst) = G_RECORD_GROUP(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/records/group.h b/plugins/kaitai/python/records/group.h
new file mode 100644
index 0000000..3e12ffc
--- /dev/null
+++ b/plugins/kaitai/python/records/group.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * group.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/group.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H
+#define _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_record_group_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordGroup'. */
+bool ensure_python_record_group_is_registered(void);
+
+/* Tente de convertir en correspondances attribut/binaire. */
+int convert_to_record_group(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H */
diff --git a/plugins/kaitai/python/records/item.c b/plugins/kaitai/python/records/item.c
new file mode 100644
index 0000000..84c2c58
--- /dev/null
+++ b/plugins/kaitai/python/records/item.c
@@ -0,0 +1,394 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.h - équivalent Python du fichier "plugins/kaitai/parsers/item.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "item.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
+#include <plugins/yaml/python/node.h>
+
+
+#include "../record.h"
+#include "../parsers/attribute.h"
+#include "../../records/item-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(record_item, G_TYPE_RECORD_ITEM);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_record_item_init(PyObject *, PyObject *, PyObject *);
+
+/* Lit la série d'octets d'un élément Kaitai entier représenté. */
+static PyObject *py_record_item_get_truncated_bytes(PyObject *, void *);
+
+/* Lit la valeur d'un élément Kaitai entier représenté. */
+static PyObject *py_record_item_get_value(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_record_item_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GKaitaiAttribute *attrib; /* Attribut défini créateur */
+ GBinContent *content; /* Contenu binaire analysé */
+ mrange_t range; /* Espace couvert */
+ SourceEndian endian; /* Boutisme à observer */
+ int ret; /* Bilan de lecture des args. */
+ GRecordItem *item; /* Création GLib à transmettre */
+
+#define RECORD_ITEM_DOC \
+ "The RecordItem class remembers a match between a described attribute and" \
+ " its concret value read from parsed binary data." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " RecordItem(content, range, endian, attrib)" \
+ "\n" \
+ "Where the *attrib* arguments refers to a" \
+ " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance as the" \
+ " creator of the newly created object, *content* points to a" \
+ " pychrysalide.analysis.BinContent instance, *range* is a" \
+ " pychrysalide.arch.mrange object, *endian* states with a" \
+ " pychrysalide.analysis.BinContent.SourceEndian hint the endianness used" \
+ " to read integer values."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&O&O&",
+ convert_to_kaitai_attribute, &attrib,
+ convert_to_binary_content, &content,
+ convert_any_to_mrange, &range,
+ convert_to_binary_content, &endian);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ item = G_RECORD_ITEM(pygobject_get(self));
+
+ if (!g_record_item_create(item, attrib, content, &range, endian))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create record item."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Lit la série d'octets d'un élément Kaitai entier représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_record_item_get_truncated_bytes(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GRecordItem *item; /* Version native de l'élément */
+ bool status; /* Bilan d'opération */
+ bin_t *out; /* Données brutes à transmettre*/
+ size_t len; /* Quantité de ces données */
+
+#define RECORD_ITEM_TRUNCATED_BYTES_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ truncated_bytes, py_record_item, \
+ "Raw bytes carried by the item (truncated if a separator" \
+ " is defined in the linked attribute), or None if irrelevant" \
+ " regarding to the type of the attribute." \
+)
+
+ item = G_RECORD_ITEM(pygobject_get(self));
+
+ status = g_record_item_get_truncated_bytes(item, &out, &len);
+
+ if (status)
+ {
+ result = PyBytes_FromStringAndSize((char *)out, len);
+ free(out);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Lit la valeur d'un élément Kaitai entier représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_record_item_get_value(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GRecordItem *item; /* Version native de l'élément */
+ resolved_value_t resolved; /* Valeur sous forme générique */
+ bool status; /* Bilan d'opération */
+
+#define RECORD_ITEM_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ value, py_record_item, \
+ "Carried value (as integer, bytes), or None in case of error." \
+)
+
+ result = NULL;
+
+ item = G_RECORD_ITEM(pygobject_get(self));
+
+ status = g_record_item_get_value(item, &resolved);
+
+ if (status)
+ switch (resolved.type)
+ {
+ case GVT_ERROR:
+ assert(false);
+ PyErr_Format(PyExc_RuntimeError,
+ _("Error got while parsing Kaitai definition should not have been exported!"));
+ result = NULL;
+ break;
+
+ case GVT_UNSIGNED_INTEGER:
+ result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer);
+ break;
+
+ case GVT_SIGNED_INTEGER:
+ result = PyLong_FromLongLong(resolved.signed_integer);
+ break;
+
+ case GVT_FLOAT:
+ result = PyFloat_FromDouble(resolved.floating_number);
+ break;
+
+ case GVT_BOOLEAN:
+ result = resolved.status ? Py_True : Py_False;
+ Py_INCREF(result);
+ break;
+
+ case GVT_BYTES:
+ result = PyBytes_FromStringAndSize(resolved.bytes.data, resolved.bytes.len);
+ exit_szstr(&resolved.bytes);
+ break;
+
+ case GVT_ARRAY:
+ result = pygobject_new(G_OBJECT(resolved.array));
+ break;
+
+ case GVT_RECORD:
+ result = pygobject_new(G_OBJECT(resolved.record));
+ break;
+
+ case GVT_STREAM:
+ result = pygobject_new(G_OBJECT(resolved.stream));
+ break;
+
+ }
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_record_item_type(void)
+{
+ static PyMethodDef py_record_item_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_record_item_getseters[] = {
+ RECORD_ITEM_TRUNCATED_BYTES_ATTRIB,
+ RECORD_ITEM_VALUE_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_record_item_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.records.RecordItem",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = RECORD_ITEM_DOC,
+
+ .tp_methods = py_record_item_methods,
+ .tp_getset = py_record_item_getseters,
+
+ .tp_init = py_record_item_init,
+ .tp_new = py_record_item_new,
+
+ };
+
+ return &py_record_item_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....records.RecordItem. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_record_item_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'RecordItem' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_record_item_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.records");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_match_record_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_RECORD_ITEM, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en correspondance attribut/binaire. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_record_item(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_record_item_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record item");
+ break;
+
+ case 1:
+ *((GRecordItem **)dst) = G_RECORD_ITEM(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/yaml/python/line.h b/plugins/kaitai/python/records/item.h
index 00dcbd9..bde8a55 100644
--- a/plugins/yaml/python/line.h
+++ b/plugins/kaitai/python/records/item.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * line.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/line.h"
+ * item.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/item.h"
*
* Copyright (C) 2019 Cyrille Bagard
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_YAML_PYTHON_LINE_H
-#define _PLUGINS_YAML_PYTHON_LINE_H
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H
+#define _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H
#include <Python.h>
@@ -32,14 +32,14 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_yaml_line_type(void);
+PyTypeObject *get_python_record_item_type(void);
-/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlLine'. */
-bool register_python_yaml_line(PyObject *);
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordItem'. */
+bool ensure_python_record_item_is_registered(void);
-/* Tente de convertir en ligne de données au format Yaml. */
-int convert_to_yaml_line(PyObject *, void *);
+/* Tente de convertir en correspondance attribut/binaire. */
+int convert_to_record_item(PyObject *, void *);
-#endif /* _PLUGINS_YAML_PYTHON_LINE_H */
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H */
diff --git a/plugins/yaml/python/scalar.c b/plugins/kaitai/python/records/list.c
index 5a33cd1..d2eecbb 100644
--- a/plugins/yaml/python/scalar.c
+++ b/plugins/kaitai/python/records/list.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * scalar.c - équivalent Python du fichier "plugins/yaml/scalar.c"
+ * list.h - équivalent Python du fichier "plugins/kaitai/parsers/list.h"
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,71 +22,110 @@
*/
-#include "scalar.h"
+#include "list.h"
#include <pygobject.h>
+#include <string.h>
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
+#include <plugins/yaml/python/node.h>
-#include "collection.h"
-#include "line.h"
-#include "node.h"
-#include "../scalar.h"
+#include "../record.h"
+#include "../parsers/attribute.h"
+#include "../../records/list-int.h"
-/* Crée un nouvel objet Python de type 'YamlScalar'. */
-static PyObject *py_yaml_scalar_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(record_list, G_TYPE_RECORD_LIST);
-/* Attache une collection de noeuds Yaml à un noeud. */
-static int py_yaml_scalar_set_collection(PyObject *, PyObject *, void *);
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_record_list_init(PyObject *, PyObject *, PyObject *);
-/* Fournit une éventuelle collection rattachée à un noeud. */
-static PyObject *py_yaml_scalar_get_collection(PyObject *, void *);
+/* Dénombre le nombre de correspondances enregistrées. */
+static Py_ssize_t py_record_list_sq_length(PyObject *);
+
+/* Fournit un élément ciblé dans la liste de correspondances. */
+static PyObject *py_record_list_sq_item(PyObject *, Py_ssize_t);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'YamlScalar'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_scalar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_record_list_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
- GYamlLine *key; /* Ligne principale du noeud */
+ int result; /* Bilan à retourner */
+ GKaitaiAttribute *attrib; /* Attribut défini créateur */
+ GBinContent *content; /* Contenu binaire analysé */
+ vmpa2t *addr; /* Adresse de symbole à ajouter*/
int ret; /* Bilan de lecture des args. */
- GYamlScalar *node; /* Création GLib à transmettre */
+ GRecordList *list; /* Création GLib à transmettre */
+
+#define RECORD_LIST_DOC \
+ "The RecordList class collects a list of parsed attributes with their" \
+ " relative values. Each of theses Kaitai attributes can be accessed as" \
+ " subscriptable Python attribute.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " RecordList(content, attrib)" \
+ "\n" \
+ "Where the *attrib* argument refers to the" \
+ " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance used to" \
+ " create each record contained by the list and *content* points to a" \
+ " pychrysalide.analysis.BinContent instance."
+
+ result = 0;
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&O&",
+ convert_to_kaitai_attribute, &attrib,
+ convert_to_binary_content, &content,
+ convert_any_to_vmpa, &addr);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1)
+ {
+ result = -1;
+ goto exit;
+ }
-#define YAML_SCALAR_DOC \
- "YamlScalar handles a scalar node in a Yaml tree.\n" \
- "\n" \
- "Instances can be created using the following constructor:\n" \
- "\n" \
- " YamlScalar(key)\n" \
- "\n" \
- "Where key is the main Yaml line for the scalar."
+ /* Eléments de base */
- ret = PyArg_ParseTuple(args, "O&", &convert_to_yaml_line, &key);
- if (!ret) return NULL;
+ list = G_RECORD_LIST(pygobject_get(self));
- node = g_yaml_scalar_new(key);
+ if (!g_record_list_create(list, attrib, content, addr))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create record list."));
+ result = -1;
+ goto exit;
+ }
- g_object_ref_sink(G_OBJECT(node));
- result = pygobject_new(G_OBJECT(node));
- g_object_unref(node);
+ exit:
+
+ clean_vmpa_arg(addr);
return result;
@@ -95,44 +134,24 @@ static PyObject *py_yaml_scalar_new(PyTypeObject *type, PyObject *args, PyObject
/******************************************************************************
* *
-* Paramètres : self = contenu binaire à manipuler. *
-* value = collection de noeuds Yaml. *
-* closure = adresse non utilisée ici. *
+* Paramètres : self = instance Python manipulée. *
* *
-* Description : Attache une collection de noeuds Yaml à un noeud. *
+* Description : Dénombre le nombre de correspondances enregistrées. *
* *
-* Retour : Jeu d'attributs liés au contenu courant. *
+* Retour : Taille de la liste représentée. *
* *
* Remarques : - *
* *
******************************************************************************/
-static int py_yaml_scalar_set_collection(PyObject *self, PyObject *value, void *closure)
+static Py_ssize_t py_record_list_sq_length(PyObject *self)
{
- int result; /* Bilan à renvoyer */
- GYamlScalar *node; /* Version GLib du noeud */
- GYamlCollection *collec; /* Version GLib de la valeur */
-
- node = G_YAML_SCALAR(pygobject_get(self));
+ Py_ssize_t result; /* Quantité à retourner */
+ GRecordList *list; /* Version native de l'objet */
- if (value == Py_None)
- {
- g_yaml_scalar_set_collection(node, NULL);
- result = 0;
- }
+ list = G_RECORD_LIST(pygobject_get(self));
- else
- {
- if (!convert_to_yaml_collection(value, &collec))
- result = -1;
-
- else
- {
- g_yaml_scalar_set_collection(node, collec);
- result = 0;
- }
-
- }
+ result = g_record_list_count_records(list);
return result;
@@ -141,43 +160,36 @@ static int py_yaml_scalar_set_collection(PyObject *self, PyObject *value, void *
/******************************************************************************
* *
-* Paramètres : self = contenu binaire à manipuler. *
-* closure = adresse non utilisée ici. *
+* Paramètres : self = structure C convertie en Python. *
+* index = indice de la correspondance visée. *
* *
-* Description : Fournit une éventuelle collection rattachée à un noeud. *
+* Description : Fournit un élément ciblé dans la liste de correspondances. *
* *
-* Retour : Collection de noeuds Yaml ou None. *
+* Retour : Instance de correspondance particulière, voire None. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_scalar_get_collection(PyObject *self, void *closure)
+static PyObject *py_record_list_sq_item(PyObject *self, Py_ssize_t index)
{
PyObject *result; /* Instance à retourner */
- GYamlScalar *node; /* Version GLib du noeud */
- GYamlCollection *collec; /* Collection à transmettre */
-
-#define YAML_SCALAR_COLLECTION_ATTRIB PYTHON_GETSET_DEF_FULL \
-( \
- collection, py_yaml_scalar, \
- "Provide or define the collection of nodes attached to another Yaml node." \
-)
+ GRecordList *list; /* Version native de l'objet */
+ GMatchRecord *record; /* Correspondance retrouvée */
- node = G_YAML_SCALAR(pygobject_get(self));
+ list = G_RECORD_LIST(pygobject_get(self));
- collec = g_yaml_scalar_get_collection(node);
+ record = g_record_list_get_record(list, index);
- if (collec == NULL)
+ if (record != NULL)
{
- result = Py_None;
- Py_INCREF(result);
+ result = pygobject_new(G_OBJECT(record));
+ g_object_unref(G_OBJECT(record));
}
-
else
{
- result = pygobject_new(G_OBJECT(collec));
- g_object_unref(collec);
+ result = Py_None;
+ Py_INCREF(result);
}
return result;
@@ -197,44 +209,54 @@ static PyObject *py_yaml_scalar_get_collection(PyObject *self, void *closure)
* *
******************************************************************************/
-PyTypeObject *get_python_yaml_scalar_type(void)
+PyTypeObject *get_python_record_list_type(void)
{
- static PyMethodDef py_yaml_scalar_methods[] = {
+ static PySequenceMethods py_record_list_sequence_methods = {
+
+ .sq_length = py_record_list_sq_length,
+ .sq_item = py_record_list_sq_item,
+
+ };
+
+ static PyMethodDef py_record_list_methods[] = {
{ NULL }
};
- static PyGetSetDef py_yaml_scalar_getseters[] = {
- YAML_SCALAR_COLLECTION_ATTRIB,
+ static PyGetSetDef py_record_list_getseters[] = {
{ NULL }
};
- static PyTypeObject py_yaml_scalar_type = {
+ static PyTypeObject py_record_list_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.plugins.yaml.YamlScalar",
+ .tp_name = "pychrysalide.plugins.kaitai.records.RecordList",
.tp_basicsize = sizeof(PyGObject),
- .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_as_sequence = &py_record_list_sequence_methods,
- .tp_doc = YAML_SCALAR_DOC,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_methods = py_yaml_scalar_methods,
- .tp_getset = py_yaml_scalar_getseters,
- .tp_new = py_yaml_scalar_new
+ .tp_doc = RECORD_LIST_DOC,
+
+ .tp_methods = py_record_list_methods,
+ .tp_getset = py_record_list_getseters,
+
+ .tp_init = py_record_list_init,
+ .tp_new = py_record_list_new,
};
- return &py_yaml_scalar_type;
+ return &py_record_list_type;
}
/******************************************************************************
* *
-* Paramètres : module = module dont la définition est à compléter. *
+* Paramètres : - *
* *
-* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlScalar.*
+* Description : Prend en charge l'objet 'pychrysalide....records.RecordList. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -242,17 +264,27 @@ PyTypeObject *get_python_yaml_scalar_type(void)
* *
******************************************************************************/
-bool register_python_yaml_scalar(PyObject *module)
+bool ensure_python_record_list_is_registered(void)
{
- PyTypeObject *type; /* Type Python 'YamlScalar' */
+ PyTypeObject *type; /* Type Python 'RecordList' */
+ PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
- type = get_python_yaml_scalar_type();
+ type = get_python_record_list_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.records");
+
+ dict = PyModule_GetDict(module);
- dict = PyModule_GetDict(module);
+ if (!ensure_python_match_record_is_registered())
+ return false;
- if (!register_class_for_pygobject(dict, G_TYPE_YAML_SCALAR, type, get_python_yaml_node_type()))
- return false;
+ if (!register_class_for_pygobject(dict, G_TYPE_RECORD_LIST, type))
+ return false;
+
+ }
return true;
@@ -264,7 +296,7 @@ bool register_python_yaml_scalar(PyObject *module)
* Paramètres : arg = argument quelconque à tenter de convertir. *
* dst = destination des valeurs récupérées en cas de succès. *
* *
-* Description : Tente de convertir en noeud d'arborescence de format Yaml. *
+* Description : Tente de convertir en correspondance attribut/binaire. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
* *
@@ -272,11 +304,11 @@ bool register_python_yaml_scalar(PyObject *module)
* *
******************************************************************************/
-int convert_to_yaml_scalar(PyObject *arg, void *dst)
+int convert_to_record_list(PyObject *arg, void *dst)
{
int result; /* Bilan à retourner */
- result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_scalar_type());
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_record_list_type());
switch (result)
{
@@ -286,11 +318,11 @@ int convert_to_yaml_scalar(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml scalar");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record list");
break;
case 1:
- *((GYamlScalar **)dst) = G_YAML_SCALAR(pygobject_get(arg));
+ *((GRecordList **)dst) = G_RECORD_LIST(pygobject_get(arg));
break;
default:
diff --git a/plugins/kaitai/python/records/list.h b/plugins/kaitai/python/records/list.h
new file mode 100644
index 0000000..53572a9
--- /dev/null
+++ b/plugins/kaitai/python/records/list.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/list.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H
+#define _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_record_list_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordList'. */
+bool ensure_python_record_list_is_registered(void);
+
+/* Tente de convertir en correspondance attribut/binaire. */
+int convert_to_record_list(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H */
diff --git a/plugins/kaitai/python/records/module.c b/plugins/kaitai/python/records/module.c
new file mode 100644
index 0000000..af97434
--- /dev/null
+++ b/plugins/kaitai/python/records/module.c
@@ -0,0 +1,124 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire records en tant que module
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "bits.h"
+#include "delayed.h"
+#include "empty.h"
+#include "group.h"
+#include "item.h"
+#include "list.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Ajoute le module 'plugins.kaitai.records' au module Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_kaitai_records_module(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *super; /* Module à compléter */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_PLUGINS_KAITAI_RECORDS_DOC \
+ "This module is providing objects used to link structure" \
+ " definitions with their data."
+
+ static PyModuleDef py_chrysalide_kaitai_records_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.plugins.kaitai.records",
+ .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_RECORDS_DOC,
+
+ .m_size = -1,
+
+ };
+
+ result = false;
+
+ super = get_access_to_python_module("pychrysalide.plugins.kaitai");
+
+ module = build_python_module(super, &py_chrysalide_kaitai_records_module);
+
+ result = (module != NULL);
+
+ assert(result);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'plugins.kaitai.records'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_kaitai_records_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_record_bit_field_is_registered();
+ if (result) result = ensure_python_record_delayed_is_registered();
+ if (result) result = ensure_python_record_empty_is_registered();
+ if (result) result = ensure_python_record_group_is_registered();
+ if (result) result = ensure_python_record_item_is_registered();
+ if (result) result = ensure_python_record_list_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/records/module.h b/plugins/kaitai/python/records/module.h
new file mode 100644
index 0000000..ff631dc
--- /dev/null
+++ b/plugins/kaitai/python/records/module.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire records en tant que module
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H
+#define _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins.kaitai.records' au module Python. */
+bool add_kaitai_records_module(void);
+
+/* Intègre les objets du module 'plugins.kaitai.records'. */
+bool populate_kaitai_records_module(void);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H */
diff --git a/plugins/kaitai/python/rost/Makefile.am b/plugins/kaitai/python/rost/Makefile.am
new file mode 100644
index 0000000..cae0419
--- /dev/null
+++ b/plugins/kaitai/python/rost/Makefile.am
@@ -0,0 +1,14 @@
+
+noinst_LTLIBRARIES = libkaitaipythonrost.la
+
+libkaitaipythonrost_la_SOURCES = \
+ module.h module.c \
+ trigger.h trigger.c
+
+libkaitaipythonrost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitaipythonrost_la_SOURCES:%c=)
diff --git a/plugins/kaitai/python/rost/module.c b/plugins/kaitai/python/rost/module.c
new file mode 100644
index 0000000..66a5a82
--- /dev/null
+++ b/plugins/kaitai/python/rost/module.c
@@ -0,0 +1,115 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire rost en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "trigger.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Ajoute le module 'plugins.kaitai.rost' au module Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_kaitai_rost_module(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *super; /* Module à compléter */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_PLUGINS_KAITAI_ROST_DOC \
+ "This module creates some glue to extend the ROST features" \
+ " using Kaitai definitions for analyzing and filtering" \
+ " contents."
+
+ static PyModuleDef py_chrysalide_kaitai_rost_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.plugins.kaitai.rost",
+ .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_ROST_DOC,
+
+ .m_size = -1,
+
+ };
+
+ result = false;
+
+ super = get_access_to_python_module("pychrysalide.plugins.kaitai");
+
+ module = build_python_module(super, &py_chrysalide_kaitai_rost_module);
+
+ result = (module != NULL);
+
+ assert(result);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'plugins.kaitai.rost'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_kaitai_rost_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_kaitai_trigger_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/rost/module.h b/plugins/kaitai/python/rost/module.h
new file mode 100644
index 0000000..8415c2e
--- /dev/null
+++ b/plugins/kaitai/python/rost/module.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire rost en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_ROST_MODULE_H
+#define _PLUGINS_KAITAI_PYTHON_ROST_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins.kaitai.rost' au module Python. */
+bool add_kaitai_rost_module(void);
+
+/* Intègre les objets du module 'plugins.kaitai.rost'. */
+bool populate_kaitai_rost_module(void);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_ROST_MODULE_H */
diff --git a/plugins/kaitai/python/rost/trigger.c b/plugins/kaitai/python/rost/trigger.c
new file mode 100644
index 0000000..180ef6e
--- /dev/null
+++ b/plugins/kaitai/python/rost/trigger.c
@@ -0,0 +1,236 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * trigger.c - équivalent Python du fichier "plugins/kaitai/rost/trigger.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "trigger.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/scan/item.h>
+
+
+#include "../parsers/struct.h"
+#include "../../parsers/struct.h"
+#include "../../rost/trigger-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_trigger, G_TYPE_KAITAI_TRIGGER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_trigger_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_trigger_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GKaitaiStruct *kstruct; /* Définition Kaitai en place */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiTrigger *trigger; /* Création GLib à transmettre */
+
+#define KAITAI_TRIGGER_DOC \
+ "The KaitaiTrigger object store an access to a loaded Kaitai definition" \
+ " creates as many as required instances from it when ROST filters contents" \
+ " with the help of the Kaitai module.\n" \
+ "\n" \
+ "Instances can be created using following constructor:\n" \
+ "\n" \
+ " KaitaiTrigger(kstruct)" \
+ "\n" \
+ "Where *kstruct* is a pychrysalide.plugins.kaitai.parsers.KaitaiStruct" \
+ " instance loaded with a valid Kaitai definition."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_kaitai_structure, &kstruct);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ trigger = G_KAITAI_TRIGGER(pygobject_get(self));
+
+ if (!g_kaitai_trigger_create(trigger, kstruct))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream."));
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_trigger_type(void)
+{
+ static PyMethodDef py_kaitai_trigger_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_trigger_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_trigger_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.rost.KaitaiTrigger",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = KAITAI_TRIGGER_DOC,
+
+ .tp_methods = py_kaitai_trigger_methods,
+ .tp_getset = py_kaitai_trigger_getseters,
+
+ .tp_init = py_kaitai_trigger_init,
+ .tp_new = py_kaitai_trigger_new,
+
+ };
+
+ return &py_kaitai_trigger_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....rost.KaitaiTrigger. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_trigger_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'RecordEmpty' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_trigger_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai.rost");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_registered_item_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_TRIGGER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en accès à une définition Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_trigger(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_trigger_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai trigger");
+ break;
+
+ case 1:
+ *((GKaitaiTrigger **)dst) = G_KAITAI_TRIGGER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/rost/trigger.h b/plugins/kaitai/python/rost/trigger.h
new file mode 100644
index 0000000..44776f7
--- /dev/null
+++ b/plugins/kaitai/python/rost/trigger.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * trigger.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/rost/trigger.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_ROST_TRIGGER_H
+#define _PLUGINS_KAITAI_PYTHON_ROST_TRIGGER_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_trigger_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.rost.KaitaiTrigger'. */
+bool ensure_python_kaitai_trigger_is_registered(void);
+
+/* Tente de convertir en accès à une définition Kaitai. */
+int convert_to_kaitai_trigger(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_ROST_TRIGGER_H */
diff --git a/plugins/kaitai/python/scope.c b/plugins/kaitai/python/scope.c
new file mode 100644
index 0000000..b11dc81
--- /dev/null
+++ b/plugins/kaitai/python/scope.c
@@ -0,0 +1,542 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scope.c - équivalent Python du fichier "plugins/kaitai/scope.c"
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "scope.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "record.h"
+#include "parsers/meta.h"
+#include "../record.h"
+#include "../parsers/meta.h"
+
+
+
+/* Rassemblement de données d'un paquet */
+typedef struct _py_kaitai_scope_t
+{
+ PyObject_HEAD /* A laisser en premier */
+
+ kaitai_scope_t *native; /* Tampon de données lié */
+
+} py_kaitai_scope_t;
+
+
+/* Libère de la mémoire un objet Python 'py_kaitai_scope_t'. */
+static void py_kaitai_scope_dealloc(py_kaitai_scope_t *);
+
+/* Initialise un objet Python de type 'py_kaitai_scope_t'. */
+static int py_kaitai_scope_init(py_kaitai_scope_t *, PyObject *, PyObject *);
+
+/* Conserve le souvenir de la dernière correspondance effectuée. */
+static PyObject *py_kaitai_scope_remember_last_record(PyObject *, PyObject *);
+
+/* Recherche la définition d'un type nouveau pour Kaitai. */
+static PyObject *py_kaitai_scope_find_sub_type(PyObject *, PyObject *);
+
+/* Retourne le souvenir d'une correspondance racine. */
+static PyObject *py_kaitai_scope_get_root_record(PyObject *, void *);
+
+/* Retourne le souvenir de la correspondance parente effectuée. */
+static PyObject *py_kaitai_scope_get_parent_record(PyObject *, void *);
+
+/* Retourne le souvenir de la dernière correspondance effectuée. */
+static PyObject *py_kaitai_scope_get_last_record(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = tampon de données à supprimer. *
+* *
+* Description : Libère de la mémoire un objet Python 'py_kaitai_scope_t'. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_kaitai_scope_dealloc(py_kaitai_scope_t *self)
+{
+ reset_record_scope(self->native);
+
+ Py_TYPE(self)->tp_free((PyObject *)self);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = instance d'objet à initialiser. *
+* args = arguments passés pour l'appel. *
+* kwds = mots clefs éventuellement fournis en complément. *
+* *
+* Description : Initialise un objet Python de type 'py_kaitai_scope_t'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_scope_init(py_kaitai_scope_t *self, PyObject *args, PyObject *kwds)
+{
+ int result; /* Bilan à retourner */
+ GKaitaiMeta *meta; /* Informations globale */
+ int ret; /* Bilan de lecture des args. */
+
+#define KAITAI_SCOPE_DOC \
+ "The KaitaiScope object stores a local environment which freezes" \
+ " a particular state of the Kaitai parser. It allows the dynamic" \
+ " resolving of values contained in a Kaitai expression.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " KaitaiScope(meta)" \
+ "\n" \
+ "Where *meta* is a pychrysalide.plugins.kaitai.parsers.KaitaiMeta" \
+ " instance pointing to global information about the Kaitai" \
+ " definition."
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_kaitai_meta, &meta);
+ if (!ret) return -1;
+
+ self->native = malloc(sizeof(kaitai_scope_t));
+
+ init_record_scope(self->native, meta);
+
+ result = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = environnement local à manipuler. *
+* args = arguments fournis pour la conduite de l'opération. *
+* *
+* Description : Conserve le souvenir de la dernière correspondance effectuée.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_scope_remember_last_record(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à faire remonter */
+ GMatchRecord *record; /* Correspondance à utiliser */
+ int ret; /* Bilan de lecture des args. */
+ py_kaitai_scope_t *locals; /* Instance à manipuler */
+
+#define KAITAI_SCOPE_REMEMBER_LAST_RECORD_METHOD PYTHON_METHOD_DEF \
+( \
+ remember_last_record, "$self, record, /", \
+ METH_VARARGS, py_kaitai_scope, \
+ "Store a record as the last parsed record.\n" \
+ "\n" \
+ "This *record* is expected to be a" \
+ " pychrysalide.plugins.kaitai.MatchRecord instance." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_match_record, &record);
+ if (!ret) return NULL;
+
+ locals = (py_kaitai_scope_t *)self;
+
+ remember_last_record(locals->native, record);
+
+ result = Py_None;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = environnement local à manipuler. *
+* args = arguments fournis pour la conduite de l'opération. *
+* *
+* Description : Recherche la définition d'un type nouveau pour Kaitai. *
+* *
+* Retour : Type prêt à emploi ou NULL si non trouvé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_scope_find_sub_type(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à faire remonter */
+ const char *name; /* Désignation à retrouver */
+ int ret; /* Bilan de lecture des args. */
+ py_kaitai_scope_t *locals; /* Instance à manipuler */
+ GKaitaiType *type; /* Définition à identifier */
+
+#define KAITAI_SCOPE_FIND_SUB_TYPE_METHOD PYTHON_METHOD_DEF \
+( \
+ find_sub_type, "$self, name, /", \
+ METH_VARARGS, py_kaitai_scope, \
+ "Retrieve the type structure linked to a given name.\n" \
+ "\n" \
+ "This *name* has to be a string.\n" \
+ "\n" \
+ "The result is a known" \
+ " pychrysalide.plugins.kaitai.parsers.KaitaiType instance" \
+ " or *None* if the name has not been registered during" \
+ " the parsing." \
+)
+
+ ret = PyArg_ParseTuple(args, "s", &name);
+ if (!ret) return NULL;
+
+ locals = (py_kaitai_scope_t *)self;
+
+ type = find_sub_type(locals->native, name);
+
+ result = pygobject_new(G_OBJECT(type));
+ g_object_unref(G_OBJECT(type));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = environnement local à consulter. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Retourne le souvenir d'une correspondance racine. *
+* *
+* Retour : Dernière correspondance établie ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_scope_get_root_record(PyObject *self, void *closure)
+{
+ PyObject *result; /* Conversion à retourner */
+ py_kaitai_scope_t *locals; /* Instance à manipuler */
+ GMatchRecord *record; /* Correspondance à convertir */
+
+#define KAITAI_SCOPE_ROOT_RECORD_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ root_record, py_kaitai_scope, \
+ "Provide the first record for a parsed content.\n" \
+ "\n" \
+ "The result is a pychrysalide.plugins.kaitai.MatchRecord" \
+ " instance or *None*." \
+)
+
+ locals = (py_kaitai_scope_t *)self;
+
+ record = get_root_record(locals->native);
+
+ if (record != NULL)
+ {
+ result = pygobject_new(G_OBJECT(record));
+ g_object_unref(G_OBJECT(record));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = environnement local à consulter. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Retourne le souvenir de la correspondance parente effectuée. *
+* *
+* Retour : Dernière correspondance établie ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_scope_get_parent_record(PyObject *self, void *closure)
+{
+ PyObject *result; /* Conversion à retourner */
+ py_kaitai_scope_t *locals; /* Instance à manipuler */
+ GMatchRecord *record; /* Correspondance à convertir */
+
+#define KAITAI_SCOPE_PARENT_RECORD_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ parent_record, py_kaitai_scope, \
+ "Provide the current parent record for a parsed content.\n" \
+ "\n" \
+ "The result is a pychrysalide.plugins.kaitai.MatchRecord" \
+ " instance or *None*." \
+)
+
+ locals = (py_kaitai_scope_t *)self;
+
+ record = get_parent_record(locals->native);
+
+ if (record != NULL)
+ {
+ result = pygobject_new(G_OBJECT(record));
+ g_object_unref(G_OBJECT(record));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = environnement local à consulter. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Retourne le souvenir de la dernière correspondance effectuée.*
+* *
+* Retour : Dernière correspondance établie ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_scope_get_last_record(PyObject *self, void *closure)
+{
+ PyObject *result; /* Conversion à retourner */
+ py_kaitai_scope_t *locals; /* Instance à manipuler */
+ GMatchRecord *record; /* Correspondance à convertir */
+
+#define KAITAI_SCOPE_LAST_RECORD_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ last_record, py_kaitai_scope, \
+ "Provide the last createdrecord for a parsed content.\n" \
+ "\n" \
+ "The result is a pychrysalide.plugins.kaitai.MatchRecord" \
+ " instance or *None*." \
+)
+
+ locals = (py_kaitai_scope_t *)self;
+
+ record = get_last_record(locals->native);
+
+ if (record != NULL)
+ {
+ result = pygobject_new(G_OBJECT(record));
+ g_object_unref(G_OBJECT(record));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_scope_type(void)
+{
+ static PyMethodDef py_kaitai_scope_methods[] = {
+ KAITAI_SCOPE_REMEMBER_LAST_RECORD_METHOD,
+ KAITAI_SCOPE_FIND_SUB_TYPE_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_scope_getseters[] = {
+ KAITAI_SCOPE_ROOT_RECORD_ATTRIB,
+ KAITAI_SCOPE_PARENT_RECORD_ATTRIB,
+ KAITAI_SCOPE_LAST_RECORD_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_scope_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.KaitaiScope",
+ .tp_basicsize = sizeof(py_kaitai_scope_t),
+
+ .tp_dealloc = (destructor)py_kaitai_scope_dealloc,
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+
+ .tp_doc = KAITAI_SCOPE_DOC,
+
+ .tp_methods = py_kaitai_scope_methods,
+ .tp_getset = py_kaitai_scope_getseters,
+
+ .tp_init = (initproc)py_kaitai_scope_init,
+ .tp_new = PyType_GenericNew,
+
+ };
+
+ return &py_kaitai_scope_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_scope_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'PackedBuffer' */
+ PyObject *module; /* Module à recompléter */
+
+ type = get_python_kaitai_scope_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ if (PyType_Ready(type) != 0)
+ return false;
+
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai");
+
+ if (!register_python_module_object(module, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = structure interne à copier en objet Python. *
+* *
+* Description : Convertit une structure 'kaitai_scope_t' en objet Python. *
+* *
+* Retour : Object Python résultant de la conversion opérée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyObject *build_from_internal_kaitai_scope(const kaitai_scope_t *locals)
+{
+ PyObject *result; /* Instance à retourner */
+ PyTypeObject *type; /* Type à instancier */
+
+ type = get_python_kaitai_scope_type();
+
+ result = PyObject_CallObject((PyObject *)type, NULL);
+
+ copy_record_scope(((py_kaitai_scope_t *)result)->native, locals);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en environnement local pour Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_scope(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_scope_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai scope");
+ break;
+
+ case 1:
+ *((kaitai_scope_t **)dst) = ((py_kaitai_scope_t *)arg)->native;
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/scope.h b/plugins/kaitai/python/scope.h
new file mode 100644
index 0000000..9353b06
--- /dev/null
+++ b/plugins/kaitai/python/scope.h
@@ -0,0 +1,51 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scope.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/scope.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_SCOPE_H
+#define _PLUGINS_KAITAI_PYTHON_SCOPE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+#include "../scope.h"
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_scope_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. */
+bool ensure_python_kaitai_scope_is_registered(void);
+
+/* Convertit une structure 'kaitai_scope_t' en objet Python. */
+PyObject *build_from_internal_kaitai_scope(const kaitai_scope_t *);
+
+/* Tente de convertir en environnement local pour Kaitai. */
+int convert_to_kaitai_scope(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_SCOPE_H */
diff --git a/plugins/kaitai/python/stream.c b/plugins/kaitai/python/stream.c
new file mode 100644
index 0000000..985e3c3
--- /dev/null
+++ b/plugins/kaitai/python/stream.c
@@ -0,0 +1,278 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * stream.h - équivalent Python du fichier "plugins/kaitai/stream.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "stream.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/arch/vmpa.h>
+
+
+#include "../stream-int.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(kaitai_stream, G_TYPE_KAITAI_STREAM);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_kaitai_stream_init(PyObject *, PyObject *, PyObject *);
+
+/* Détermine si la fin des données a été atteinte. */
+static PyObject *py_kaitai_stream_get_eof(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_kaitai_stream_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GBinContent *content; /* Contenu binaire manipulé */
+ vmpa2t *pos; /* Tête de lecture courante */
+ int ret; /* Bilan de lecture des args. */
+ GKaitaiStream *stream; /* Création GLib à transmettre */
+
+#define KAITAI_STREAM_DOC \
+ "KaitaiStream collects all the information useful for the processing of" \
+ " binary data." \
+ "\n" \
+ "Instances can be created using following constructor:\n" \
+ "\n" \
+ " KaitaiStream(content, pos)" \
+ "\n" \
+ "Where *content* is a pychrysalide.analysis.BinContent instance providing" \
+ " the processed data and *pos* defines the current reading location, as a" \
+ " pychrysalide.arch.vmpa value."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &content, convert_any_to_vmpa, &pos);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ stream = G_KAITAI_STREAM(pygobject_get(self));
+
+ if (!g_kaitai_stream_create(stream, content, pos))
+ {
+ clean_vmpa_arg(pos);
+
+ PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream."));
+ return -1;
+
+ }
+
+ clean_vmpa_arg(pos);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Détermine si la fin des données a été atteinte. *
+* *
+* Retour : True si la tête de lecture est en position finale, ou False. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_kaitai_stream_get_eof(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GKaitaiStream *stream; /* Version native dyu flux */
+ bool status; /* Etat de la position courante*/
+
+#define KAITAI_STREAM_EOF_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ eof, py_kaitai_stream, \
+ "Boolean value stating if the end of the stream" \
+ " has been reached or not." \
+)
+
+ stream = G_KAITAI_STREAM(pygobject_get(self));
+
+ status = g_kaitai_stream_has_reached_eof(stream);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_kaitai_stream_type(void)
+{
+ static PyMethodDef py_kaitai_stream_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_kaitai_stream_getseters[] = {
+ KAITAI_STREAM_EOF_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_kaitai_stream_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.kaitai.KaitaiStream",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = KAITAI_STREAM_DOC,
+
+ .tp_methods = py_kaitai_stream_methods,
+ .tp_getset = py_kaitai_stream_getseters,
+
+ .tp_init = py_kaitai_stream_init,
+ .tp_new = py_kaitai_stream_new,
+
+ };
+
+ return &py_kaitai_stream_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiStream.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_kaitai_stream_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'KaitaiStream' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_kaitai_stream_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.kaitai");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_STREAM, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en flux de données pour Kaitai. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_kaitai_stream(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_stream_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai stream");
+ break;
+
+ case 1:
+ *((GKaitaiStream **)dst) = G_KAITAI_STREAM(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/python/stream.h b/plugins/kaitai/python/stream.h
new file mode 100644
index 0000000..4f61358
--- /dev/null
+++ b/plugins/kaitai/python/stream.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * stream.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/stream.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PYTHON_STREAM_H
+#define _PLUGINS_KAITAI_PYTHON_STREAM_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_kaitai_stream_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiStream'. */
+bool ensure_python_kaitai_stream_is_registered(void);
+
+/* Tente de convertir en flux de données pour Kaitai. */
+int convert_to_kaitai_stream(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PYTHON_STREAM_H */
diff --git a/plugins/kaitai/record-int.h b/plugins/kaitai/record-int.h
new file mode 100644
index 0000000..5ce5b2c
--- /dev/null
+++ b/plugins/kaitai/record-int.h
@@ -0,0 +1,73 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * record-int.h - prototypes internes pour la mémorisation d'une correspondance avec un attribut Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_RECORD_INT_H
+#define PLUGINS_KAITAI_RECORD_INT_H
+
+
+#include "record.h"
+
+
+#include "parser.h"
+
+
+
+/* Calcule ou fournit la zone couverte par une correspondance. */
+typedef void (* get_record_range_fc) (const GMatchRecord *, mrange_t *);
+
+/* Recherche la correspondance associée à un identifiant. */
+typedef GMatchRecord * (* find_record_by_name_fc) (GMatchRecord *, const char *, size_t, unsigned int);
+
+/* Transforme une énumération en constante entière. */
+typedef bool (* resolve_record_enum_fc) (const GMatchRecord *, const sized_string_t *, const sized_string_t *, resolved_value_t *);
+
+
+/* Correspondance entre un attribut et du binaire (instance) */
+struct _GMatchRecord
+{
+ GObject parent; /* A laisser en premier */
+
+ GKaitaiParser *creator; /* Lecteur à l'origine */
+
+ GBinContent *content; /* Contenu binaire analysé */
+
+};
+
+/* Correspondance entre un attribut et du binaire (classe) */
+struct _GMatchRecordClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ get_record_range_fc get_range; /* Fourniture de couverture */
+ find_record_by_name_fc find; /* Recherche selon identifiant */
+ resolve_record_enum_fc resolve; /* Conversion d'une énumération*/
+
+};
+
+
+/* Met en place une correspondance entre attribut et binaire. */
+bool g_match_record_create(GMatchRecord *, GKaitaiParser *, GBinContent *);
+
+
+
+#endif /* PLUGINS_KAITAI_RECORD_INT_H */
diff --git a/plugins/kaitai/record.c b/plugins/kaitai/record.c
new file mode 100644
index 0000000..de1e80d
--- /dev/null
+++ b/plugins/kaitai/record.c
@@ -0,0 +1,416 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * record.c - définition d'une correspondance avec un attribut Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "record.h"
+
+
+#include <assert.h>
+
+
+#include "expression.h"
+#include "record-int.h"
+#include "parsers/attribute.h"
+
+
+
+/* Initialise la classe des correspondances avec du binaire. */
+static void g_match_record_class_init(GMatchRecordClass *);
+
+/* Initialise une correspondance avec du binaire. */
+static void g_match_record_init(GMatchRecord *);
+
+/* Supprime toutes les références externes. */
+static void g_match_record_dispose(GMatchRecord *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_match_record_finalize(GMatchRecord *);
+
+/* Recherche la correspondance associée à un identifiant. */
+static GMatchRecord *_g_match_record_find_by_name(GMatchRecord *, const char *, size_t, unsigned int);
+
+
+
+/* Indique le type défini pour une correspondance avec du binaire. */
+G_DEFINE_TYPE(GMatchRecord, g_match_record, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des correspondances avec du binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_record_class_init(GMatchRecordClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_match_record_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_match_record_finalize;
+
+ klass->find = (find_record_by_name_fc)_g_match_record_find_by_name;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = instance à initialiser. *
+* *
+* Description : Initialise une correspondance avec du binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_record_init(GMatchRecord *record)
+{
+ record->creator = NULL;
+
+ record->content = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_record_dispose(GMatchRecord *record)
+{
+ g_clear_object(&record->creator);
+
+ g_clear_object(&record->content);
+
+ G_OBJECT_CLASS(g_match_record_parent_class)->dispose(G_OBJECT(record));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_record_finalize(GMatchRecord *record)
+{
+ G_OBJECT_CLASS(g_match_record_parent_class)->finalize(G_OBJECT(record));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à initialiser pleinement. *
+* creator = lecteur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* *
+* Description : Met en place une correspondance entre attribut et binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_match_record_create(GMatchRecord *record, GKaitaiParser *creator, GBinContent *content)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ record->creator = creator;
+ g_object_ref(G_OBJECT(creator));
+
+ record->content = content;
+
+ if (content != NULL)
+ g_object_ref(G_OBJECT(content));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à consulter. *
+* *
+* Description : Renvoie vers le lecteur à l'origine de la correspondance. *
+* *
+* Retour : Lecteur à l'origine de la création. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiParser *g_match_record_get_creator(const GMatchRecord *record)
+{
+ GKaitaiParser *result; /* Instance à retourner */
+
+ result = record->creator;
+
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à modifier. *
+* creator = lecteur à l'origine de la correspondance. *
+* *
+* Description : Modifie la référence au créateur de la correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_match_record_fix_creator(GMatchRecord *record, GKaitaiParser *creator)
+{
+ g_object_unref(G_OBJECT(record->creator));
+
+ record->creator = creator;
+ g_object_ref(G_OBJECT(creator));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à consulter. *
+* *
+* Description : Fournit le contenu lié à une correspondance établie. *
+* *
+* Retour : Contenu binaire associé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBinContent *g_match_record_get_content(const GMatchRecord *record)
+{
+ GBinContent *result; /* Instance à retourner */
+
+ result = record->content;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à consulter. *
+* range = zone de couverture déterminée. [OUT] *
+* *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_match_record_get_range(const GMatchRecord *record, mrange_t *range)
+{
+ GMatchRecordClass *class; /* Classe de l'instance */
+
+ class = G_MATCH_RECORD_GET_CLASS(record);
+
+ class->get_range(record, range);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance établie à consulter. *
+* out = tableau d'octets retournés. [OUT] *
+* len = taille de ce tableau alloué. [OUT] *
+* *
+* Description : Lit les octets bruts couverts par une correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_match_record_read_raw_bytes(const GMatchRecord *record, bin_t **out, size_t *len)
+{
+ mrange_t range; /* Zone de correspondance */
+ const bin_t *data; /* Accès aux données brutes */
+
+ g_match_record_get_range(record, &range);
+
+ *len = get_mrange_length(&range);
+
+ data = g_binary_content_get_raw_access(record->content, get_mrange_addr(&range), *len);
+ assert(data != NULL);
+
+ *out = malloc(sizeof(bin_t) * (*len + 1));
+
+ memcpy(*out, data, *len);
+ (*out)[*len] = '\0';
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à consulter. *
+* name = désignation de l'élément recherché. *
+* len = taille de cette désignation. *
+* level = profondeur maximale à atteindre (fond : 0). *
+* *
+* Description : Recherche la correspondance associée à un identifiant. *
+* *
+* Retour : Correspondance trouvée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GMatchRecord *_g_match_record_find_by_name(GMatchRecord *record, const char *name, size_t len, unsigned int level)
+{
+ GMatchRecord *result; /* Trouvaille à retourner */
+ const char *label; /* Etiquette à manipuler */
+ size_t label_len; /* Taille de cette étiquette */
+
+ result = NULL;
+
+ if (G_IS_KAITAI_ATTRIBUTE(record->creator))
+ {
+ label = g_kaitai_attribute_get_label(G_KAITAI_ATTRIBUTE(record->creator));
+
+ if (label != NULL)
+ {
+ label_len = strlen(label);
+
+ if (label_len == len && strncmp(label, name, len) == 0)
+ {
+ result = record;
+ g_object_ref(G_OBJECT(result));
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à consulter. *
+* name = désignation de l'élément recherché. *
+* len = taille de cette désignation. *
+* level = profondeur maximale à atteindre (fond : 0). *
+* *
+* Description : Recherche la correspondance associée à un identifiant. *
+* *
+* Retour : Correspondance trouvée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *g_match_record_find_by_name(GMatchRecord *record, const char *name, size_t len, unsigned int level)
+{
+ GMatchRecord *result; /* Trouvaille à retourner */
+ GMatchRecordClass *class; /* Classe de l'instance */
+
+ class = G_MATCH_RECORD_GET_CLASS(record);
+
+ result = class->find(record, name, len, level);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à consulter. *
+* name = désignation de l'élément recherché. *
+* label = étiquette de l'élément constant à traduire. *
+* value = valeur entière correspondante. [OUT] *
+* *
+* Description : Transforme une énumération en constante entière. *
+* *
+* Retour : Bilan de l'opération : true si la résolution est réalisée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_match_record_resolve_enum(const GMatchRecord *record, const sized_string_t *name, const sized_string_t *label, resolved_value_t *value)
+{
+ bool result; /* Bilan à retourner */
+ GMatchRecordClass *class; /* Classe de l'instance */
+
+ class = G_MATCH_RECORD_GET_CLASS(record);
+
+ if (class->resolve == NULL)
+ result = false;
+
+ else
+ result = class->resolve(record, name, label, value);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/record.h b/plugins/kaitai/record.h
new file mode 100644
index 0000000..7db8187
--- /dev/null
+++ b/plugins/kaitai/record.h
@@ -0,0 +1,88 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * record.h - prototypes pour la définition d'une correspondance avec un attribut Kaitai
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORD_H
+#define _PLUGINS_KAITAI_RECORD_H
+
+
+#include <glib-object.h>
+
+
+#include <analysis/content.h>
+#include <arch/vmpa.h>
+#include <common/szstr.h>
+
+
+
+/* Depuis parser.h : spécification d'un lecteur Kaitai (instance) */
+typedef struct _GKaitaiParser GKaitaiParser;
+
+/* Depuis expression.h : informations transportées par une expression */
+typedef struct _resolved_value_t resolved_value_t;
+
+
+
+#define G_TYPE_MATCH_RECORD g_match_record_get_type()
+#define G_MATCH_RECORD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_MATCH_RECORD, GMatchRecord))
+#define G_IS_MATCH_RECORD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_MATCH_RECORD))
+#define G_MATCH_RECORD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_MATCH_RECORD, GMatchRecordClass))
+#define G_IS_MATCH_RECORD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_MATCH_RECORD))
+#define G_MATCH_RECORD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_MATCH_RECORD, GMatchRecordClass))
+
+
+/* Correspondance entre un attribut et du binaire (instance) */
+typedef struct _GMatchRecord GMatchRecord;
+
+/* Correspondance entre un attribut et du binaire (classe) */
+typedef struct _GMatchRecordClass GMatchRecordClass;
+
+
+/* Indique le type défini pour une correspondance avec du binaire. */
+GType g_match_record_get_type(void);
+
+/* Renvoie vers le lecteur à l'origine de la correspondance. */
+GKaitaiParser *g_match_record_get_creator(const GMatchRecord *);
+
+/* Modifie la référence au créateur de la correspondance. */
+void g_match_record_fix_creator(GMatchRecord *, GKaitaiParser *);
+
+/* Fournit le contenu lié à une correspondance établie. */
+GBinContent *g_match_record_get_content(const GMatchRecord *);
+
+/* Calcule ou fournit la zone couverte par une correspondance. */
+void g_match_record_get_range(const GMatchRecord *, mrange_t *);
+
+/* Lit les octets bruts couverts par une correspondance. */
+void g_match_record_read_raw_bytes(const GMatchRecord *, bin_t **, size_t *);
+
+#define DIRECT_SEARCH_DEEP_LEVEL 1
+
+/* Recherche la correspondance associée à un identifiant. */
+GMatchRecord *g_match_record_find_by_name(GMatchRecord *, const char *, size_t, unsigned int);
+
+/* Transforme une énumération en constante entière. */
+bool g_match_record_resolve_enum(const GMatchRecord *, const sized_string_t *, const sized_string_t *, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORD_H */
diff --git a/plugins/kaitai/records/Makefile.am b/plugins/kaitai/records/Makefile.am
new file mode 100644
index 0000000..3884bfb
--- /dev/null
+++ b/plugins/kaitai/records/Makefile.am
@@ -0,0 +1,23 @@
+
+noinst_LTLIBRARIES = libkaitairecords.la
+
+libkaitairecords_la_SOURCES = \
+ bits-int.h \
+ bits.h bits.c \
+ delayed-int.h \
+ delayed.h delayed.c \
+ empty-int.h \
+ empty.h empty.c \
+ group-int.h \
+ group.h group.c \
+ item-int.h \
+ item.h item.c \
+ list-int.h \
+ list.h list.c
+
+libkaitairecords_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitairecords_la_SOURCES:%c=)
diff --git a/plugins/kaitai/records/bits-int.h b/plugins/kaitai/records/bits-int.h
new file mode 100644
index 0000000..7b03911
--- /dev/null
+++ b/plugins/kaitai/records/bits-int.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bits-int.h - prototypes internes pour la conservation d'un champ de bits entre attribut et binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_BITS_INT_H
+#define _PLUGINS_KAITAI_RECORDS_BITS_INT_H
+
+
+#include "bits.h"
+
+
+#include "../record-int.h"
+
+
+
+/* Correspondance de bits établie entre un attribut et du binaire (instance) */
+struct _GRecordBitField
+{
+ GMatchRecord parent; /* A laisser en premier */
+
+ ext_vmpa_t epos; /* Point de départ */
+ uint8_t size; /* Quantité de bits concernés */
+ SourceEndian endian; /* Boutisme des données imposé */
+
+};
+
+/* Correspondance de bits établie entre un attribut et du binaire (classe) */
+struct _GRecordBitFieldClass
+{
+ GMatchRecordClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une correspondance entre attribut et binaire. */
+bool g_record_bit_field_create(GRecordBitField *, GKaitaiAttribute *, GBinContent *, const ext_vmpa_t *, uint8_t, SourceEndian);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_BITS_INT_H */
diff --git a/plugins/kaitai/records/bits.c b/plugins/kaitai/records/bits.c
new file mode 100644
index 0000000..d224112
--- /dev/null
+++ b/plugins/kaitai/records/bits.c
@@ -0,0 +1,283 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bits.c - conservation d'un champ de bits entre attribut et binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "bits.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include "bits-int.h"
+
+
+
+/* -------------------- DEFINITION D'UNE CORRESPONDANCE UNITAIRE -------------------- */
+
+
+/* Initialise la classe des correspondances attribut/binaire. */
+static void g_record_bit_field_class_init(GRecordBitFieldClass *);
+
+/* Initialise une correspondance entre attribut et binaire. */
+static void g_record_bit_field_init(GRecordBitField *);
+
+/* Supprime toutes les références externes. */
+static void g_record_bit_field_dispose(GRecordBitField *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_record_bit_field_finalize(GRecordBitField *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Calcule ou fournit la zone couverte par une correspondance. */
+static void g_record_bit_field_get_range(const GRecordBitField *, mrange_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UNE CORRESPONDANCE UNITAIRE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une correspondance entre un attribut et du binaire. */
+G_DEFINE_TYPE(GRecordBitField, g_record_bit_field, G_TYPE_MATCH_RECORD);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des correspondances attribut/binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_bit_field_class_init(GRecordBitFieldClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GMatchRecordClass *record; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_record_bit_field_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_record_bit_field_finalize;
+
+ record = G_MATCH_RECORD_CLASS(klass);
+
+ record->get_range = (get_record_range_fc)g_record_bit_field_get_range;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = instance à initialiser. *
+* *
+* Description : Initialise une correspondance entre attribut et binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_bit_field_init(GRecordBitField *field)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_bit_field_dispose(GRecordBitField *field)
+{
+ G_OBJECT_CLASS(g_record_bit_field_parent_class)->dispose(G_OBJECT(field));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_bit_field_finalize(GRecordBitField *field)
+{
+ G_OBJECT_CLASS(g_record_bit_field_parent_class)->finalize(G_OBJECT(field));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* epos = tête de lecture avec granularité en bits. *
+* size = quantité de bits à prendre en compte. *
+* endian = boustime des données à respecter. *
+* *
+* Description : Crée une nouvelle correspondance entre attribut et binaire. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *g_record_bit_field_new(GKaitaiAttribute *attrib, GBinContent *content, const ext_vmpa_t *epos, uint8_t size, SourceEndian endian)
+{
+ GMatchRecord *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_RECORD_BIT_FIELD, NULL);
+
+ if (!g_record_bit_field_create(G_RECORD_BIT_FIELD(result), attrib, content, epos, size, endian))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = correspondance à initialiser pleinement. *
+* attrib = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* epos = tête de lecture avec granularité en bits. *
+* size = quantité de bits à prendre en compte. *
+* endian = boustime des données à respecter. *
+* *
+* Description : Met en place une correspondance entre attribut et binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_bit_field_create(GRecordBitField *field, GKaitaiAttribute *attrib, GBinContent *content, const ext_vmpa_t *epos, uint8_t size, SourceEndian endian)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_match_record_create(G_MATCH_RECORD(field), G_KAITAI_PARSER(attrib), content);
+
+ if (result)
+ {
+ copy_evmpa(&field->epos, epos);
+ field->size = size;
+ field->endian = endian;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = correspondance à consulter. *
+* out = valeur à sauvegarder sous une forme générique. [OUT] *
+* *
+* Description : Lit la valeur d'un élément Kaitai entier représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_bit_field_get_value(const GRecordBitField *field, resolved_value_t *out)
+{
+ bool result; /* Bilan à retourner */
+ GKaitaiParser *parser; /* Attribut associé à l'élément*/
+
+ parser = g_match_record_get_creator(G_MATCH_RECORD(field));
+ assert(G_IS_KAITAI_ATTRIBUTE(parser));
+
+ result = g_kaitai_attribute_read_bit_field_value(G_KAITAI_ATTRIBUTE(parser),
+ G_MATCH_RECORD(field)->content,
+ &field->epos, field->size,
+ field->endian, out);
+
+ g_object_unref(G_OBJECT(parser));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : record = correspondance à consulter. *
+* range = zone de couverture déterminée. [OUT] *
+* *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_bit_field_get_range(const GRecordBitField *record, mrange_t *range)
+{
+ phys_t len; /* Taille en octets */
+
+ len = record->size / 8;
+
+ if (record->size % 8 > 0)
+ len ++;
+
+ init_mrange(range, &record->epos.base, len);
+
+}
diff --git a/plugins/kaitai/records/bits.h b/plugins/kaitai/records/bits.h
new file mode 100644
index 0000000..923e8e3
--- /dev/null
+++ b/plugins/kaitai/records/bits.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bits.h - prototypes pour la conservation d'un champ de bits entre attribut et binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_BITS_H
+#define _PLUGINS_KAITAI_RECORDS_BITS_H
+
+
+#include <glib-object.h>
+
+
+#include "../record.h"
+#include "../parsers/attribute.h"
+
+
+
+#define G_TYPE_RECORD_BIT_FIELD g_record_bit_field_get_type()
+#define G_RECORD_BIT_FIELD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_BIT_FIELD, GRecordBitField))
+#define G_IS_RECORD_BIT_FIELD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_BIT_FIELD))
+#define G_RECORD_BIT_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_BIT_FIELD, GRecordBitFieldClass))
+#define G_IS_RECORD_BIT_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_BIT_FIELD))
+#define G_RECORD_BIT_FIELD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_BIT_FIELD, GRecordBitFieldClass))
+
+
+/* Correspondance de bits établie entre un attribut et du binaire (instance) */
+typedef struct _GRecordBitField GRecordBitField;
+
+/* Correspondance de bits établie entre un attribut et du binaire (classe) */
+typedef struct _GRecordBitFieldClass GRecordBitFieldClass;
+
+
+/* Indique le type défini pour une correspondance entre un attribut et du binaire. */
+GType g_record_bit_field_get_type(void);
+
+/* Crée une nouvelle correspondance entre attribut et binaire. */
+GMatchRecord *g_record_bit_field_new(GKaitaiAttribute *, GBinContent *, const ext_vmpa_t *, uint8_t, SourceEndian);
+
+/* Lit la valeur d'un élément Kaitai entier représenté. */
+bool g_record_bit_field_get_value(const GRecordBitField *, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_BITS_H */
diff --git a/plugins/kaitai/records/delayed-int.h b/plugins/kaitai/records/delayed-int.h
new file mode 100644
index 0000000..9275500
--- /dev/null
+++ b/plugins/kaitai/records/delayed-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * delayed-int.h - prototypes internes pour la conservation d'une instance virtuelle
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_DELAYED_INT_H
+#define _PLUGINS_KAITAI_RECORDS_DELAYED_INT_H
+
+
+#include "delayed.h"
+
+
+#include "../record-int.h"
+
+
+
+/* Valeur calculée selon des correspondances parallèles (instance) */
+struct _GRecordDelayed
+{
+ GMatchRecord parent; /* A laisser en premier */
+
+ kaitai_scope_t locals; /* Sauvegarde de contexte */
+
+ bool has_value; /* Port d'une valeur directe ? */
+ GMatchRecord *real_record; /* Enregistrement effectif */
+
+};
+
+/* Valeur calculée selon des correspondances parallèles (classe) */
+struct _GRecordDelayedClass
+{
+ GMatchRecordClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une valeur calculée selon des correspondances. */
+bool g_record_delayed_create(GRecordDelayed *, GKaitaiInstance *, const kaitai_scope_t *, GBinContent *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_DELAYED_INT_H */
diff --git a/plugins/kaitai/records/delayed.c b/plugins/kaitai/records/delayed.c
new file mode 100644
index 0000000..8c1395c
--- /dev/null
+++ b/plugins/kaitai/records/delayed.c
@@ -0,0 +1,352 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * delayed.c - conservation d'une correspondance entre attribut et binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "delayed.h"
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+
+#include "delayed-int.h"
+#include "item.h"
+#include "../parsers/attribute.h"
+
+
+
+/* -------------------- DEFINITION D'UNE CORRESPONDANCE UNITAIRE -------------------- */
+
+
+/* Initialise la classe des valeurs purement calculées. */
+static void g_record_delayed_class_init(GRecordDelayedClass *);
+
+/* Initialise une correspondance entre attribut et binaire. */
+static void g_record_delayed_init(GRecordDelayed *);
+
+/* Supprime toutes les références externes. */
+static void g_record_delayed_dispose(GRecordDelayed *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_record_delayed_finalize(GRecordDelayed *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Calcule ou fournit la zone couverte par une correspondance. */
+static void g_record_delayed_get_range(const GRecordDelayed *, mrange_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UNE CORRESPONDANCE UNITAIRE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une valeur calculée selon des correspondances établies. */
+G_DEFINE_TYPE(GRecordDelayed, g_record_delayed, G_TYPE_MATCH_RECORD);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des valeurs purement calculées. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_delayed_class_init(GRecordDelayedClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GMatchRecordClass *record; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_record_delayed_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_record_delayed_finalize;
+
+ record = G_MATCH_RECORD_CLASS(klass);
+
+ record->get_range = (get_record_range_fc)g_record_delayed_get_range;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : delayed = instance à initialiser. *
+* *
+* Description : Initialise une correspondance entre attribut et binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_delayed_init(GRecordDelayed *delayed)
+{
+ init_record_scope(&delayed->locals, NULL);
+
+ delayed->real_record = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : delayed = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_delayed_dispose(GRecordDelayed *delayed)
+{
+ reset_record_scope(&delayed->locals);
+
+ G_OBJECT_CLASS(g_record_delayed_parent_class)->dispose(G_OBJECT(delayed));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : delayed = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_delayed_finalize(GRecordDelayed *delayed)
+{
+ G_OBJECT_CLASS(g_record_delayed_parent_class)->finalize(G_OBJECT(delayed));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = analyseur à l'origine de la correspondance. *
+* locals = correspondances courantes pour résolutions. *
+* content = contenu binaire lié à la correspondance. *
+* *
+* Description : Crée une nouvelle valeur calculée à partir d'une instance. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRecordDelayed *g_record_delayed_new(GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content)
+{
+ GRecordDelayed *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_RECORD_DELAYED, NULL);
+
+ if (!g_record_delayed_create(result, inst, locals, content))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : delayed = correspondance à initialiser pleinement. *
+* inst = analyseur à l'origine de la correspondance. *
+* locals = correspondances courantes pour résolutions. *
+* content = contenu binaire lié à la correspondance. *
+* *
+* Description : Met en place une valeur calculée à partir d'une instance. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_delayed_create(GRecordDelayed *delayed, GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_match_record_create(G_MATCH_RECORD(delayed), G_KAITAI_PARSER(inst), content);
+
+ if (result)
+ copy_record_scope(&delayed->locals, locals);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : delayed = correspondance à consulter. *
+* out = valeur à sauvegarder sous forme générique. [OUT] *
+* *
+* Description : Détermine la valeur d'un élément Kaitai calculé. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_delayed_compute_value(GRecordDelayed *delayed, resolved_value_t *out)
+{
+ bool result; /* Bilan à retourner */
+ GKaitaiParser *parser; /* Instance liée à l'élément */
+
+ parser = g_match_record_get_creator(G_MATCH_RECORD(delayed));
+ assert(G_IS_KAITAI_ATTRIBUTE(parser));
+
+ if (G_MATCH_RECORD(delayed)->content == NULL)
+ result = g_kaitai_instance_compute_value(G_KAITAI_INSTANCE(parser),
+ &delayed->locals,
+ out);
+
+ else
+ {
+ if (delayed->real_record == NULL)
+ delayed->real_record = g_kaitai_instance_compute_real_record(G_KAITAI_INSTANCE(parser),
+ &delayed->locals,
+ G_MATCH_RECORD(delayed)->content);
+
+ if (delayed->real_record == NULL)
+ result = false;
+
+ else
+ {
+ assert(G_IS_RECORD_ITEM(delayed->real_record));
+ result = g_record_item_get_value(G_RECORD_ITEM(delayed->real_record), out);
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(parser));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : delayed = correspondance à consulter. *
+* out = valeur à sauvegarder sous forme générique. [OUT] *
+* *
+* Description : Détermine et ajuste la valeur d'un élément Kaitai calculé. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_delayed_compute_and_aggregate_value(GRecordDelayed *delayed, resolved_value_t *out)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t converted; /* Conversion finale ? */
+
+ result = g_record_delayed_compute_value(delayed, out);
+
+ if (result)
+ {
+ /**
+ * Lorsque c'est possible, les tableaux Kaitai sont transformés en série
+ * d'octets.
+ *
+ * Même si les tableaux ont une grande portée en interne des règles
+ * Kaitai (par exemple pour constituer une table de constantes de
+ * référence), il en est différemment à l'extérieur du processus de
+ * traitement : les tableaux sont le plus souvent destinés à manipuler
+ * les octets représentés directement (par exemple :
+ * "contents: [0xca, 0xfe, 0xba, 0xbe]").
+ *
+ * Pour les valeurs d'instance dont le type n'est pas explicite,
+ * le choix est fait de tenter de simplifier la vie de l'utilisateur
+ * en lui fournissant directement les octets qu'il attend probablement
+ * plutôt qu'un tableau contenant des octets à extraire.
+ */
+
+ if (out->type == GVT_ARRAY)
+ {
+ if (g_kaitai_array_convert_to_bytes(out->array, &converted))
+ {
+ EXIT_RESOLVED_VALUE(*out);
+
+ out->bytes = converted;
+ out->type = GVT_BYTES;
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : delayed = correspondance à consulter. *
+* range = zone de couverture déterminée. [OUT] *
+* *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_delayed_get_range(const GRecordDelayed *delayed, mrange_t *range)
+{
+ copy_mrange(range, UNUSED_MRANGE_PTR);
+
+}
diff --git a/plugins/kaitai/records/delayed.h b/plugins/kaitai/records/delayed.h
new file mode 100644
index 0000000..e88bb6c
--- /dev/null
+++ b/plugins/kaitai/records/delayed.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * delayed.h - prototypes pour la conservation d'une correspondance entre attribut et binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_DELAYED_H
+#define _PLUGINS_KAITAI_RECORDS_DELAYED_H
+
+
+#include <glib-object.h>
+
+
+#include "../record.h"
+#include "../parsers/instance.h"
+
+
+
+#define G_TYPE_RECORD_DELAYED g_record_delayed_get_type()
+#define G_RECORD_DELAYED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_DELAYED, GRecordDelayed))
+#define G_IS_RECORD_DELAYED(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_DELAYED))
+#define G_RECORD_DELAYED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_DELAYED, GRecordDelayedClass))
+#define G_IS_RECORD_DELAYED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_DELAYED))
+#define G_RECORD_DELAYED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_DELAYED, GRecordDelayedClass))
+
+
+/* Valeur calculée selon des correspondances parallèles (instance) */
+typedef struct _GRecordDelayed GRecordDelayed;
+
+/* Valeur calculée selon des correspondances parallèles (classe) */
+typedef struct _GRecordDelayedClass GRecordDelayedClass;
+
+
+/* Indique le type défini pour une valeur calculée selon des correspondances établies. */
+GType g_record_delayed_get_type(void);
+
+/* Crée une nouvelle valeur calculée à partir d'une instance. */
+GRecordDelayed *g_record_delayed_new(GKaitaiInstance *, const kaitai_scope_t *, GBinContent *);
+
+/* Détermine la valeur d'un élément Kaitai entier calculé. */
+bool g_record_delayed_compute_value(GRecordDelayed *, resolved_value_t *);
+
+/* Détermine et ajuste la valeur d'un élément Kaitai calculé. */
+bool g_record_delayed_compute_and_aggregate_value(GRecordDelayed *, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_DELAYED_H */
diff --git a/plugins/kaitai/records/empty-int.h b/plugins/kaitai/records/empty-int.h
new file mode 100644
index 0000000..2c6cefa
--- /dev/null
+++ b/plugins/kaitai/records/empty-int.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * empty-int.h - prototypes internes pour la notification d'une absence de correspondance attendue
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_EMPTY_INT_H
+#define _PLUGINS_KAITAI_RECORDS_EMPTY_INT_H
+
+
+#include "empty.h"
+
+
+#include "../record-int.h"
+
+
+
+/* Marque d'une zone de correspondance vide (instance) */
+struct _GRecordEmpty
+{
+ GMatchRecord parent; /* A laisser en premier */
+
+ vmpa2t pos; /* Début d'une zone vide */
+
+};
+
+/* Marque d'une zone de correspondance vide (classe) */
+struct _GRecordEmptyClass
+{
+ GMatchRecordClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une zone de correspondance vide. */
+bool g_record_empty_create(GRecordEmpty *, GKaitaiParser *, GBinContent *, const vmpa2t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_EMPTY_INT_H */
diff --git a/plugins/kaitai/records/empty.c b/plugins/kaitai/records/empty.c
new file mode 100644
index 0000000..e5121e1
--- /dev/null
+++ b/plugins/kaitai/records/empty.c
@@ -0,0 +1,236 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * empty.c - conservation d'une correspondance entre attribut et binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "empty.h"
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+
+#include "empty-int.h"
+
+
+
+/* ------------------ DEFINITION D'UNE ZONE DE CORRESPONDANCE VIDE ------------------ */
+
+
+/* Initialise la classe des zones de correspondance vides. */
+static void g_record_empty_class_init(GRecordEmptyClass *);
+
+/* Initialise une zone de correspondance vide. */
+static void g_record_empty_init(GRecordEmpty *);
+
+/* Supprime toutes les références externes. */
+static void g_record_empty_dispose(GRecordEmpty *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_record_empty_finalize(GRecordEmpty *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Calcule ou fournit la zone couverte par une correspondance. */
+static void g_record_empty_get_range(const GRecordEmpty *, mrange_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UNE ZONE DE CORRESPONDANCE VIDE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une zone de correspondance vide. */
+G_DEFINE_TYPE(GRecordEmpty, g_record_empty, G_TYPE_MATCH_RECORD);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des zones de correspondance vides. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_empty_class_init(GRecordEmptyClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GMatchRecordClass *record; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_record_empty_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_record_empty_finalize;
+
+ record = G_MATCH_RECORD_CLASS(klass);
+
+ record->get_range = (get_record_range_fc)g_record_empty_get_range;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : empty = instance à initialiser. *
+* *
+* Description : Initialise une zone de correspondance vide. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_empty_init(GRecordEmpty *empty)
+{
+ init_vmpa(&empty->pos, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : empty = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_empty_dispose(GRecordEmpty *empty)
+{
+ G_OBJECT_CLASS(g_record_empty_parent_class)->dispose(G_OBJECT(empty));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : empty = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_empty_finalize(GRecordEmpty *empty)
+{
+ G_OBJECT_CLASS(g_record_empty_parent_class)->finalize(G_OBJECT(empty));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parser = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* pos = emplacement de la zone vide à construire. *
+* *
+* Description : Crée une zone de correspondance vide à une position donnée. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRecordEmpty *g_record_empty_new(GKaitaiParser *parser, GBinContent *content, const vmpa2t *pos)
+{
+ GRecordEmpty *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_RECORD_EMPTY, NULL);
+
+ if (!g_record_empty_create(result, parser, content, pos))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : empty = correspondance à initialiser pleinement. *
+* parser = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* pos = emplacement de la zone vide à construire. *
+* *
+* Description : Met en place une zone de correspondance vide. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_empty_create(GRecordEmpty *empty, GKaitaiParser *parser, GBinContent *content, const vmpa2t *pos)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_match_record_create(G_MATCH_RECORD(empty), parser, content);
+
+ if (result)
+ copy_vmpa(&empty->pos, pos);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : empty = correspondance à consulter. *
+* range = zone de couverture déterminée. [OUT] *
+* *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_empty_get_range(const GRecordEmpty *empty, mrange_t *range)
+{
+ init_mrange(range, &empty->pos, 0);
+
+}
diff --git a/plugins/kaitai/records/empty.h b/plugins/kaitai/records/empty.h
new file mode 100644
index 0000000..4e89b62
--- /dev/null
+++ b/plugins/kaitai/records/empty.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * empty.h - prototypes pour la notification d'une absence de correspondance attendue
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_EMPTY_H
+#define _PLUGINS_KAITAI_RECORDS_EMPTY_H
+
+
+#include <glib-object.h>
+
+
+#include "../record.h"
+
+
+
+#define G_TYPE_RECORD_EMPTY g_record_empty_get_type()
+#define G_RECORD_EMPTY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_EMPTY, GRecordEmpty))
+#define G_IS_RECORD_EMPTY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_EMPTY))
+#define G_RECORD_EMPTY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_EMPTY, GRecordEmptyClass))
+#define G_IS_RECORD_EMPTY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_EMPTY))
+#define G_RECORD_EMPTY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_EMPTY, GRecordEmptyClass))
+
+
+/* Marque d'une zone de correspondance vide (instance) */
+typedef struct _GRecordEmpty GRecordEmpty;
+
+/* Marque d'une zone de correspondance vide (classe) */
+typedef struct _GRecordEmptyClass GRecordEmptyClass;
+
+
+/* Indique le type défini pour une zone de correspondance vide. */
+GType g_record_empty_get_type(void);
+
+/* Crée une zone de correspondance vide à une position donnée. */
+GRecordEmpty *g_record_empty_new(GKaitaiParser *, GBinContent *, const vmpa2t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_EMPTY_H */
diff --git a/plugins/kaitai/records/group-int.h b/plugins/kaitai/records/group-int.h
new file mode 100644
index 0000000..1fd0162
--- /dev/null
+++ b/plugins/kaitai/records/group-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * group-int.h - prototypes internes pour la conservation d'un groupe de correspondance avec du binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_GROUP_INT_H
+#define _PLUGINS_KAITAI_RECORDS_GROUP_INT_H
+
+
+#include "group.h"
+
+
+#include "../record-int.h"
+
+
+
+/* Groupe de correspondances établies entre attributs et binaire (instance) */
+struct _GRecordGroup
+{
+ GMatchRecord parent; /* A laisser en premier */
+
+ GMatchRecord **children; /* Sous-correspondances */
+ size_t count; /* Taille de cette série */
+
+};
+
+/* Groupe de correspondances établies entre attributs et binaire (classe) */
+struct _GRecordGroupClass
+{
+ GMatchRecordClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une série de correspondances attribut/binaire. */
+bool g_record_group_create(GRecordGroup *, GKaitaiStruct *, GBinContent *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_GROUP_INT_H */
diff --git a/plugins/kaitai/records/group.c b/plugins/kaitai/records/group.c
new file mode 100644
index 0000000..13327c8
--- /dev/null
+++ b/plugins/kaitai/records/group.c
@@ -0,0 +1,382 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * group.c - conservation d'un groupe de correspondance avec du binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "group.h"
+
+
+#include <malloc.h>
+
+
+#include "group-int.h"
+#include "../parsers/attribute.h"
+
+
+
+/* ------------------ DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES ------------------ */
+
+
+/* Initialise la classe des groupes de correspondances. */
+static void g_record_group_class_init(GRecordGroupClass *);
+
+/* Initialise une série de correspondances attributs/binaire. */
+static void g_record_group_init(GRecordGroup *);
+
+/* Supprime toutes les références externes. */
+static void g_record_group_dispose(GRecordGroup *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_record_group_finalize(GRecordGroup *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Calcule ou fournit la zone couverte par une correspondance. */
+static void g_record_group_get_range(const GRecordGroup *, mrange_t *);
+
+/* Recherche la correspondance associée à un identifiant. */
+static GMatchRecord *g_record_group_find_by_name(GRecordGroup *, const char *, size_t, unsigned int);
+
+/* Transforme une énumération en constante entière. */
+static bool g_record_group_resolve_enum(const GRecordGroup *, const sized_string_t *, const sized_string_t *, resolved_value_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série de correspondances entre attributes et binaire. */
+G_DEFINE_TYPE(GRecordGroup, g_record_group, G_TYPE_MATCH_RECORD);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des groupes de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_group_class_init(GRecordGroupClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GMatchRecordClass *record; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_record_group_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_record_group_finalize;
+
+ record = G_MATCH_RECORD_CLASS(klass);
+
+ record->get_range = (get_record_range_fc)g_record_group_get_range;
+ record->find = (find_record_by_name_fc)g_record_group_find_by_name;
+ record->resolve = (resolve_record_enum_fc)g_record_group_resolve_enum;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = instance à initialiser. *
+* *
+* Description : Initialise une série de correspondances attributs/binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_group_init(GRecordGroup *group)
+{
+ group->children = NULL;
+ group->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_group_dispose(GRecordGroup *group)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < group->count; i++)
+ g_clear_object(&group->children[i]);
+
+ G_OBJECT_CLASS(g_record_group_parent_class)->dispose(G_OBJECT(group));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_group_finalize(GRecordGroup *group)
+{
+ if (group->children != NULL)
+ free(group->children);
+
+ G_OBJECT_CLASS(g_record_group_parent_class)->finalize(G_OBJECT(group));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = contenu binaire lié à la correspondance. *
+* kstruct = analyseur à l'origine de la correspondance. *
+* *
+* Description : Crée une nouvelle série de correspondances attribut/binaire. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRecordGroup *g_record_group_new(GKaitaiStruct *kstruct, GBinContent *content)
+{
+ GRecordGroup *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_RECORD_GROUP, NULL);
+
+ if (!g_record_group_create(result, kstruct, content))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = correspondance à initialiser pleinement. *
+* kstruct = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* *
+* Description : Met en place une série de correspondances attribut/binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_group_create(GRecordGroup *group, GKaitaiStruct *kstruct, GBinContent *content)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_match_record_create(G_MATCH_RECORD(group), G_KAITAI_PARSER(kstruct), content);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = ensemble de correspondances attribut/binaire. *
+* record = sous-corresponde à intégrer. *
+* *
+* Description : Ajoute une correspondance supplémentaire à une série. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_record_group_add_record(GRecordGroup *group, GMatchRecord *record)
+{
+ group->children = realloc(group->children, ++group->count * sizeof(GMatchRecord));
+
+ group->children[group->count - 1] = record;
+ g_object_ref(G_OBJECT(record));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : group = correspondance à consulter. *
+* range = zone de couverture déterminée. [OUT] *
+* *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_group_get_range(const GRecordGroup *group, mrange_t *range)
+{
+ vmpa2t start; /* Position de départ */
+ mrange_t range_0; /* Première zone couverte */
+ mrange_t range_n; /* Dernière zone couverte */
+ vmpa2t end; /* Position de d'arrivée */
+ phys_t length; /* Taille de zone couverte */
+
+ if (group->count == 0)
+ {
+ init_vmpa(&start, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+ init_mrange(range, &start, VMPA_NO_PHYSICAL);
+ }
+
+ else
+ {
+ g_match_record_get_range(group->children[0], &range_0);
+ g_match_record_get_range(group->children[group->count - 1], &range_n);
+
+ copy_vmpa(&start, get_mrange_addr(&range_0));
+
+ compute_mrange_end_addr(&range_n, &end);
+ length = compute_vmpa_diff(&start, &end);
+
+ init_mrange(range, &start, length);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = ensemble de correspondances attribut/binaire. *
+* name = désignation de l'élément recherché. *
+* len = taille de cette désignation. *
+* level = profondeur maximale à atteindre (fond : 0). *
+* *
+* Description : Recherche la correspondance associée à un identifiant. *
+* *
+* Retour : Correspondance trouvée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GMatchRecord *g_record_group_find_by_name(GRecordGroup *group, const char *name, size_t len, unsigned int level)
+{
+ GMatchRecord *result; /* Correspondance à renvoyer */
+ GMatchRecordClass *class; /* Classe parente normalisée */
+ size_t i; /* Boucle de parcours */
+
+ class = G_MATCH_RECORD_CLASS(g_record_group_parent_class);
+
+ /**
+ * Le cas d'un type utilisateur peut rattacher un attribut Kaitai à un groupe...
+ */
+ result = class->find(G_MATCH_RECORD(group), name, len, level);
+
+ if (level > 0)
+ {
+ level--;
+
+ for (i = 0; i < group->count && result == NULL; i++)
+ result = g_match_record_find_by_name(group->children[i], name, len, level);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = ensemble de correspondances attribut/binaire. *
+* name = désignation de l'élément recherché. *
+* label = étiquette de l'élément constant à traduire. *
+* value = valeur entière correspondante. [OUT] *
+* *
+* Description : Transforme une énumération en constante entière. *
+* *
+* Retour : Bilan de l'opération : true si la résolution est réalisée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_record_group_resolve_enum(const GRecordGroup *group, const sized_string_t *name, const sized_string_t *label, resolved_value_t *value)
+{
+ bool result; /* Bilan à retourner */
+ GMatchRecord *base; /* Autre version du groupe */
+ size_t i; /* Boucle de parcours */
+ GKaitaiEnum *kenum; /* Enumération à consulter */
+
+ result = false;
+
+ base = G_MATCH_RECORD(group);
+
+ if (G_IS_KAITAI_STRUCT(base->creator))
+ {
+ kenum = g_kaitai_structure_get_enum(G_KAITAI_STRUCT(base->creator), name);
+
+ if (kenum != NULL)
+ {
+ result = g_kaitai_enum_find_value(kenum, label, value);
+ g_object_unref(G_OBJECT(kenum));
+ }
+
+ }
+
+ for (i = 0; i < group->count && !result; i++)
+ result = g_match_record_resolve_enum(group->children[i], name, label, value);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/records/group.h b/plugins/kaitai/records/group.h
new file mode 100644
index 0000000..454dade
--- /dev/null
+++ b/plugins/kaitai/records/group.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * group.h - prototypes pour la conservation d'un groupe de correspondance avec du binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_GROUP_H
+#define _PLUGINS_KAITAI_RECORDS_GROUP_H
+
+
+#include <glib-object.h>
+
+
+#include <analysis/content.h>
+
+
+#include "../record.h"
+#include "../parsers/struct.h"
+
+
+
+#define G_TYPE_RECORD_GROUP g_record_group_get_type()
+#define G_RECORD_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_GROUP, GRecordGroup))
+#define G_IS_RECORD_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_GROUP))
+#define G_RECORD_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_GROUP, GRecordGroupClass))
+#define G_IS_RECORD_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_GROUP))
+#define G_RECORD_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_GROUP, GRecordGroupClass))
+
+
+/* Groupe de correspondances établies entre attributs et binaire (instance) */
+typedef struct _GRecordGroup GRecordGroup;
+
+/* Groupe de correspondances établies entre attributs et binaire (classe) */
+typedef struct _GRecordGroupClass GRecordGroupClass;
+
+
+/* Indique le type défini pour une série de correspondances entre attributes et binaire. */
+GType g_record_group_get_type(void);
+
+/* Crée une nouvelle série de correspondances attribut/binaire. */
+GRecordGroup *g_record_group_new(GKaitaiStruct *, GBinContent *);
+
+/* Ajoute une correspondance supplémentaire à une série. */
+void g_record_group_add_record(GRecordGroup *, GMatchRecord *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_GROUP_H */
diff --git a/plugins/kaitai/records/item-int.h b/plugins/kaitai/records/item-int.h
new file mode 100644
index 0000000..56e0a41
--- /dev/null
+++ b/plugins/kaitai/records/item-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item-int.h - prototypes internes pour la conservation d'une correspondance entre attribut et binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_ITEM_INT_H
+#define _PLUGINS_KAITAI_RECORDS_ITEM_INT_H
+
+
+#include "item.h"
+
+
+#include "../record-int.h"
+
+
+
+/* Correspondance établie entre un attribut et du binaire (instance) */
+struct _GRecordItem
+{
+ GMatchRecord parent; /* A laisser en premier */
+
+ mrange_t range; /* Zone de binaire couverte */
+ SourceEndian endian; /* Boutisme des données imposé */
+
+};
+
+/* Correspondance établie entre un attribut et du binaire (classe) */
+struct _GRecordItemClass
+{
+ GMatchRecordClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une correspondance entre attribut et binaire. */
+bool g_record_item_create(GRecordItem *, GKaitaiAttribute *, GBinContent *, const mrange_t *, SourceEndian);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_ITEM_INT_H */
diff --git a/plugins/yaml/scalar.c b/plugins/kaitai/records/item.c
index 1dd5989..0bcf9f7 100644
--- a/plugins/yaml/scalar.c
+++ b/plugins/kaitai/records/item.c
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * scalar.c - noeud Yaml de type "scalar"
+ * item.c - conservation d'une correspondance entre attribut et binaire
*
* Copyright (C) 2019 Cyrille Bagard
*
@@ -21,61 +21,56 @@
*/
-#include "scalar.h"
+#include "item.h"
-#include <malloc.h>
+#include <assert.h>
#include <string.h>
-#include "node-int.h"
+#include "item-int.h"
-/* Noeud d'une arborescence au format Yaml (instance) */
-struct _GYamlScalar
-{
- GYamlNode parent; /* A laisser en premier */
+/* -------------------- DEFINITION D'UNE CORRESPONDANCE UNITAIRE -------------------- */
- GYamlLine *key; /* Clef principale du noeud */
- GYamlCollection *collection; /* Collection de noeuds */
-};
+/* Initialise la classe des correspondances attribut/binaire. */
+static void g_record_item_class_init(GRecordItemClass *);
-/* Noeud d'une arborescence au format Yaml (classe) */
-struct _GYamlScalarClass
-{
- GYamlNodeClass parent; /* A laisser en premier */
+/* Initialise une correspondance entre attribut et binaire. */
+static void g_record_item_init(GRecordItem *);
+
+/* Supprime toutes les références externes. */
+static void g_record_item_dispose(GRecordItem *);
-};
+/* Procède à la libération totale de la mémoire. */
+static void g_record_item_finalize(GRecordItem *);
-/* Initialise la classe des noeuds d'arborescence Yaml. */
-static void g_yaml_scalar_class_init(GYamlScalarClass *);
-/* Initialise une instance de noeud d'arborescence Yaml. */
-static void g_yaml_scalar_init(GYamlScalar *);
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-/* Supprime toutes les références externes. */
-static void g_yaml_scalar_dispose(GYamlScalar *);
-/* Procède à la libération totale de la mémoire. */
-static void g_yaml_scalar_finalize(GYamlScalar *);
+/* Calcule ou fournit la zone couverte par une correspondance. */
+static void g_record_item_get_range(const GRecordItem *, mrange_t *);
+
-/* Recherche les noeuds correspondant à un chemin. */
-static void g_yaml_scalar_find_by_path(const GYamlScalar *, const char *, bool, GYamlNode ***, size_t *);
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UNE CORRESPONDANCE UNITAIRE */
+/* ---------------------------------------------------------------------------------- */
-/* Indique le type défini pour un noeud d'arborescence Yaml. */
-G_DEFINE_TYPE(GYamlScalar, g_yaml_scalar, G_TYPE_YAML_NODE);
+/* Indique le type défini pour une correspondance entre un attribut et du binaire. */
+G_DEFINE_TYPE(GRecordItem, g_record_item, G_TYPE_MATCH_RECORD);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
-* Description : Initialise la classe des noeuds d'arborescence Yaml. *
+* Description : Initialise la classe des correspondances attribut/binaire. *
* *
* Retour : - *
* *
@@ -83,28 +78,28 @@ G_DEFINE_TYPE(GYamlScalar, g_yaml_scalar, G_TYPE_YAML_NODE);
* *
******************************************************************************/
-static void g_yaml_scalar_class_init(GYamlScalarClass *klass)
+static void g_record_item_class_init(GRecordItemClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
- GYamlNodeClass *node; /* Version parente de classe */
+ GMatchRecordClass *record; /* Version parente de la classe*/
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_scalar_dispose;
- object->finalize = (GObjectFinalizeFunc)g_yaml_scalar_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_record_item_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_record_item_finalize;
- node = G_YAML_NODE_CLASS(klass);
+ record = G_MATCH_RECORD_CLASS(klass);
- node->find = (find_yaml_node_fc)g_yaml_scalar_find_by_path;
+ record->get_range = (get_record_range_fc)g_record_item_get_range;
}
/******************************************************************************
* *
-* Paramètres : node = instance à initialiser. *
+* Paramètres : item = instance à initialiser. *
* *
-* Description : Initialise une instance de noeud d'arborescence Yaml. *
+* Description : Initialise une correspondance entre attribut et binaire. *
* *
* Retour : - *
* *
@@ -112,17 +107,16 @@ static void g_yaml_scalar_class_init(GYamlScalarClass *klass)
* *
******************************************************************************/
-static void g_yaml_scalar_init(GYamlScalar *node)
+static void g_record_item_init(GRecordItem *item)
{
- node->key = NULL;
- node->collection = NULL;
+ copy_mrange(&item->range, UNUSED_MRANGE_PTR);
}
/******************************************************************************
* *
-* Paramètres : node = instance d'objet GLib à traiter. *
+* Paramètres : item = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -132,20 +126,16 @@ static void g_yaml_scalar_init(GYamlScalar *node)
* *
******************************************************************************/
-static void g_yaml_scalar_dispose(GYamlScalar *node)
+static void g_record_item_dispose(GRecordItem *item)
{
- g_clear_object(&node->key);
-
- g_clear_object(&node->collection);
-
- G_OBJECT_CLASS(g_yaml_scalar_parent_class)->dispose(G_OBJECT(node));
+ G_OBJECT_CLASS(g_record_item_parent_class)->dispose(G_OBJECT(item));
}
/******************************************************************************
* *
-* Paramètres : node = instance d'objet GLib à traiter. *
+* Paramètres : item = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -155,18 +145,21 @@ static void g_yaml_scalar_dispose(GYamlScalar *node)
* *
******************************************************************************/
-static void g_yaml_scalar_finalize(GYamlScalar *node)
+static void g_record_item_finalize(GRecordItem *item)
{
- G_OBJECT_CLASS(g_yaml_scalar_parent_class)->finalize(G_OBJECT(node));
+ G_OBJECT_CLASS(g_record_item_parent_class)->finalize(G_OBJECT(item));
}
/******************************************************************************
* *
-* Paramètres : key = line Yaml représentant la clef du futur noeud. *
+* Paramètres : attrib = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* range = zone couverture par la correspondance. *
+* endian = boustime des données à respecter. *
* *
-* Description : Construit un noeud d'arborescence Yaml. *
+* Description : Crée une nouvelle correspondance entre attribut et binaire. *
* *
* Retour : Instance mise en place ou NULL en cas d'échec. *
* *
@@ -174,24 +167,14 @@ static void g_yaml_scalar_finalize(GYamlScalar *node)
* *
******************************************************************************/
-GYamlScalar *g_yaml_scalar_new(GYamlLine *key)
+GRecordItem *g_record_item_new(GKaitaiAttribute *attrib, GBinContent *content, const mrange_t *range, SourceEndian endian)
{
- GYamlScalar *result; /* Structure à retourner */
+ GRecordItem *result; /* Structure à retourner */
- result = g_object_new(G_TYPE_YAML_SCALAR, NULL);
+ result = g_object_new(G_TYPE_RECORD_ITEM, NULL);
- /**
- * Le paragraphe "3.2.2.1. Keys Order" des spécifications précise
- * qu'une séquence n'est qu'un noeud sans correspondance clef/valeur.
- *
- * Cette situation doit donc être prise en compte.
- */
-
- if (key != NULL)
- {
- result->key = key;
- g_object_ref(G_OBJECT(key));
- }
+ if (!g_record_item_create(result, attrib, content, range, endian))
+ g_clear_object(&result);
return result;
@@ -200,24 +183,33 @@ GYamlScalar *g_yaml_scalar_new(GYamlLine *key)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* Paramètres : item = correspondance à initialiser pleinement. *
+* attrib = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* range = zone couverte par la correspondance. *
+* endian = boustime des données à respecter. *
* *
-* Description : Fournit la ligne principale associée à un noeud. *
+* Description : Met en place une correspondance entre attribut et binaire. *
* *
-* Retour : Ligne Yaml à l'origine du noeud. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlLine *g_yaml_scalar_get_yaml_line(const GYamlScalar *node)
+bool g_record_item_create(GRecordItem *item, GKaitaiAttribute *attrib, GBinContent *content, const mrange_t *range, SourceEndian endian)
{
- GYamlLine *result; /* Ligne d'origine à renvoyer */
+ bool result; /* Bilan à retourner */
+
+ result = g_match_record_create(G_MATCH_RECORD(item), G_KAITAI_PARSER(attrib), content);
+
+ if (result)
+ {
+ copy_mrange(&item->range, range);
- result = node->key;
+ item->endian = endian;
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
+ }
return result;
@@ -226,62 +218,83 @@ GYamlLine *g_yaml_scalar_get_yaml_line(const GYamlScalar *node)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à compléter. *
-* collec = collection de noeuds Yaml. *
+* Paramètres : item = correspondance à consulter. *
+* out = tableau d'octets retournés. [OUT] *
+* len = taille de ce tableau alloué. [OUT] *
* *
-* Description : Attache une collection de noeuds Yaml à un noeud. *
+* Description : Lit la série d'octets d'un élément Kaitai entier représenté. *
* *
-* Retour : - *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_yaml_scalar_set_collection(GYamlScalar *node, GYamlCollection *collec)
+bool g_record_item_get_truncated_bytes(const GRecordItem *item, bin_t **out, size_t *len)
{
- g_clear_object(&node->collection);
+ bool result; /* Bilan à retourner */
+ GKaitaiParser *parser; /* Attribut associé à l'élément*/
+
+ parser = g_match_record_get_creator(G_MATCH_RECORD(item));
+ assert(G_IS_KAITAI_ATTRIBUTE(parser));
- g_object_ref_sink(G_OBJECT(collec));
- node->collection = collec;
+ result = g_kaitai_attribute_read_truncated_bytes(G_KAITAI_ATTRIBUTE(parser),
+ G_MATCH_RECORD(item)->content,
+ &item->range,
+ out, len);
+
+ g_object_unref(G_OBJECT(parser));
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* Paramètres : item = correspondance à consulter. *
+* out = valeur à sauvegarder sous une forme générique. [OUT] *
* *
-* Description : Fournit une éventuelle collection rattachée à un noeud. *
+* Description : Lit la valeur d'un élément Kaitai entier représenté. *
* *
-* Retour : Collection de noeuds Yaml ou NULL. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlCollection *g_yaml_scalar_get_collection(const GYamlScalar *node)
+bool g_record_item_get_value(const GRecordItem *item, resolved_value_t *out)
{
- GYamlCollection *result; /* Collection à renvoyer */
+ bool result; /* Bilan à retourner */
+ GKaitaiParser *parser; /* Attribut associé à l'élément*/
+
+ parser = g_match_record_get_creator(G_MATCH_RECORD(item));
+ assert(G_IS_KAITAI_ATTRIBUTE(parser));
- result = node->collection;
+ result = g_kaitai_attribute_read_value(G_KAITAI_ATTRIBUTE(parser),
+ G_MATCH_RECORD(item)->content,
+ &item->range,
+ item->endian, out);
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
+ g_object_unref(G_OBJECT(parser));
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* nodes = liste de noeuds avec correspondance établie. [OUT] *
-* count = quantité de ces noeuds. [OUT] *
+* Paramètres : item = correspondance à consulter. *
+* range = zone de couverture déterminée. [OUT] *
* *
-* Description : Recherche les noeuds correspondant à un chemin. *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
* *
* Retour : - *
* *
@@ -289,90 +302,8 @@ GYamlCollection *g_yaml_scalar_get_collection(const GYamlScalar *node)
* *
******************************************************************************/
-static void g_yaml_scalar_find_by_path(const GYamlScalar *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count)
+static void g_record_item_get_range(const GRecordItem *item, mrange_t *range)
{
- GYamlLine *line; /* Ligne Yaml liée au noeud */
- const char *key; /* Clef associée au noeud */
- char *next; /* Prochaine partie du chemin */
- size_t cmplen; /* Etendue de la comparaison */
- int ret; /* Bilan d'une comparaison */
- GYamlCollection *collec; /* Collection de noeuds */
-
- if (path[0] == '\0')
- goto exit;
-
- line = g_yaml_scalar_get_yaml_line(node);
-
- /* Correspondance au niveau du noeud ? */
-
- if (line != NULL)
- {
- if (path[0] == '/')
- {
- path++;
-
- if (path[0] == '\0')
- goto matched;
-
- }
-
- key = g_yaml_line_get_key(line);
-
- next = strchr(path, '/');
-
- if (next == NULL)
- ret = strcmp(path, key);
-
- else
- {
- cmplen = next - path;
-
- if (cmplen == 0)
- goto cont;
-
- ret = strncmp(path, key, cmplen);
-
- }
-
- if (ret != 0)
- goto done;
-
- else if (next != NULL)
- {
- path += cmplen;
- goto cont;
- }
-
- matched:
-
- *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **));
-
- g_object_ref(G_OBJECT(node));
- (*nodes)[*count - 1] = G_YAML_NODE(node);
-
- goto done;
-
- }
-
- cont:
-
- collec = g_yaml_scalar_get_collection(node);
-
- if (collec != NULL)
- {
- _g_yaml_node_find_by_path(G_YAML_NODE(collec), path, prepare, nodes, count);
-
- g_object_unref(G_OBJECT(collec));
-
- }
-
- done:
-
- if (line != NULL)
- g_object_unref(G_OBJECT(line));
-
- exit:
-
- ;
+ copy_mrange(range, &item->range);
}
diff --git a/plugins/kaitai/records/item.h b/plugins/kaitai/records/item.h
new file mode 100644
index 0000000..1286a89
--- /dev/null
+++ b/plugins/kaitai/records/item.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.h - prototypes pour la conservation d'une correspondance entre attribut et binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_ITEM_H
+#define _PLUGINS_KAITAI_RECORDS_ITEM_H
+
+
+#include <glib-object.h>
+
+
+#include "../record.h"
+#include "../parsers/attribute.h"
+
+
+
+#define G_TYPE_RECORD_ITEM g_record_item_get_type()
+#define G_RECORD_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_ITEM, GRecordItem))
+#define G_IS_RECORD_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_ITEM))
+#define G_RECORD_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_ITEM, GRecordItemClass))
+#define G_IS_RECORD_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_ITEM))
+#define G_RECORD_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_ITEM, GRecordItemClass))
+
+
+/* Correspondance établie entre un attribut et du binaire (instance) */
+typedef struct _GRecordItem GRecordItem;
+
+/* Correspondance établie entre un attribut et du binaire (classe) */
+typedef struct _GRecordItemClass GRecordItemClass;
+
+
+/* Indique le type défini pour une correspondance entre un attribut et du binaire. */
+GType g_record_item_get_type(void);
+
+/* Crée une nouvelle correspondance entre attribut et binaire. */
+GRecordItem *g_record_item_new(GKaitaiAttribute *, GBinContent *, const mrange_t *, SourceEndian);
+
+/* Lit la série d'octets d'un élément Kaitai entier représenté. */
+bool g_record_item_get_truncated_bytes(const GRecordItem *, bin_t **, size_t *);
+
+/* Lit la valeur d'un élément Kaitai entier représenté. */
+bool g_record_item_get_value(const GRecordItem *, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_ITEM_H */
diff --git a/plugins/kaitai/records/list-int.h b/plugins/kaitai/records/list-int.h
new file mode 100644
index 0000000..88b411d
--- /dev/null
+++ b/plugins/kaitai/records/list-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list-int.h - prototypes internes pour la conservation d'une liste de correspondance avec du binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_LIST_INT_H
+#define _PLUGINS_KAITAI_RECORDS_LIST_INT_H
+
+
+#include "list.h"
+
+
+#include "../record-int.h"
+
+
+
+/* Liste de correspondances établies entre attributs et binaire (instance) */
+struct _GRecordList
+{
+ GMatchRecord parent; /* A laisser en premier */
+
+ vmpa2t pos; /* Début de zone */
+
+ GMatchRecord **children; /* Sous-correspondances */
+ size_t count; /* Taille de cette série */
+
+};
+
+/* Liste de correspondances établies entre attributs et binaire (classe) */
+struct _GRecordListClass
+{
+ GMatchRecordClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une série de correspondances attribut/binaire. */
+bool g_record_list_create(GRecordList *, GKaitaiAttribute *, GBinContent *, const vmpa2t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_LIST_INT_H */
diff --git a/plugins/kaitai/records/list.c b/plugins/kaitai/records/list.c
new file mode 100644
index 0000000..1a36bf5
--- /dev/null
+++ b/plugins/kaitai/records/list.c
@@ -0,0 +1,424 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list.c - conservation d'une liste de correspondance avec du binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "list.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "list-int.h"
+
+
+
+/* ------------------ DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES ------------------ */
+
+
+/* Initialise la classe des listes de correspondances. */
+static void g_record_list_class_init(GRecordListClass *);
+
+/* Initialise une série de correspondances attributs/binaire. */
+static void g_record_list_init(GRecordList *);
+
+/* Supprime toutes les références externes. */
+static void g_record_list_dispose(GRecordList *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_record_list_finalize(GRecordList *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Calcule ou fournit la zone couverte par une correspondance. */
+static void g_record_list_get_range(const GRecordList *, mrange_t *);
+
+/* Recherche la correspondance associée à un identifiant. */
+static GMatchRecord *g_record_list_find_by_name(GRecordList *, const char *, size_t, unsigned int);
+
+/* Transforme une énumération en constante entière. */
+static bool g_record_list_resolve_enum(const GRecordList *, const sized_string_t *, const sized_string_t *, resolved_value_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série de correspondances entre attributes et binaire. */
+G_DEFINE_TYPE(GRecordList, g_record_list, G_TYPE_MATCH_RECORD);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des listes de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_list_class_init(GRecordListClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GMatchRecordClass *record; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_record_list_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_record_list_finalize;
+
+ record = G_MATCH_RECORD_CLASS(klass);
+
+ record->get_range = (get_record_range_fc)g_record_list_get_range;
+ record->find = (find_record_by_name_fc)g_record_list_find_by_name;
+ record->resolve = (resolve_record_enum_fc)g_record_list_resolve_enum;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = instance à initialiser. *
+* *
+* Description : Initialise une série de correspondances attributs/binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_list_init(GRecordList *list)
+{
+ list->children = NULL;
+ list->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_list_dispose(GRecordList *list)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < list->count; i++)
+ g_clear_object(&list->children[i]);
+
+ G_OBJECT_CLASS(g_record_list_parent_class)->dispose(G_OBJECT(list));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_list_finalize(GRecordList *list)
+{
+ if (list->children != NULL)
+ free(list->children);
+
+ G_OBJECT_CLASS(g_record_list_parent_class)->finalize(G_OBJECT(list));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* pos = début de la zone de couverture de la liste. *
+* *
+* Description : Crée une nouvelle série de correspondances attribut/binaire. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRecordList *g_record_list_new(GKaitaiAttribute *attrib, GBinContent *content, const vmpa2t *pos)
+{
+ GRecordList *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_RECORD_LIST, NULL);
+
+ if (!g_record_list_create(result, attrib, content, pos))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = correspondance à initialiser pleinement. *
+* attrib = analyseur à l'origine de la correspondance. *
+* content = contenu binaire lié à la correspondance. *
+* *
+* Description : Met en place une série de correspondances attribut/binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_record_list_create(GRecordList *list, GKaitaiAttribute *attrib, GBinContent *content, const vmpa2t *pos)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_match_record_create(G_MATCH_RECORD(list), G_KAITAI_PARSER(attrib), content);
+
+ if (result)
+ copy_vmpa(&list->pos, pos);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de correspondances attribut/binaire. *
+* *
+* Description : Dénombre le nombre de correspondances enregistrées. *
+* *
+* Retour : Taille de la liste représentée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_record_list_count_records(const GRecordList *list)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = list->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de correspondances attribut/binaire. *
+* record = sous-corresponde à intégrer. *
+* *
+* Description : Ajoute une correspondance supplémentaire à une série. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_record_list_add_record(GRecordList *list, GMatchRecord *record)
+{
+ list->children = realloc(list->children, ++list->count * sizeof(GMatchRecord));
+
+ list->children[list->count - 1] = record;
+ g_object_ref(G_OBJECT(record));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de correspondances attribut/binaire. *
+* index = indice de la correspondance visée. *
+* *
+* Description : Fournit un élément ciblé dans la liste de correspondances. *
+* *
+* Retour : Instance de correspondance particulière, voire NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *g_record_list_get_record(const GRecordList *list, size_t index)
+{
+ GMatchRecord *result; /* Instance à retourner */
+
+ if (index < list->count)
+ {
+ result = list->children[index];
+ g_object_ref(G_OBJECT(result));
+ }
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : list = correspondance à consulter. *
+* range = zone de couverture déterminée. [OUT] *
+* *
+* Description : Calcule ou fournit la zone couverte par une correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_record_list_get_range(const GRecordList *list, mrange_t *range)
+{
+ vmpa2t start; /* Position de départ */
+ mrange_t range_0; /* Première zone couverte */
+ mrange_t range_n; /* Dernière zone couverte */
+ vmpa2t end; /* Position de d'arrivée */
+ phys_t length; /* Taille de zone couverte */
+
+ assert(list->count > 0);
+
+ if (list->count == 0)
+ {
+ init_vmpa(&start, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+ init_mrange(range, &start, VMPA_NO_PHYSICAL);
+ }
+
+ else
+ {
+ g_match_record_get_range(list->children[0], &range_0);
+ g_match_record_get_range(list->children[list->count - 1], &range_n);
+
+ copy_vmpa(&start, get_mrange_addr(&range_0));
+
+ compute_mrange_end_addr(&range_n, &end);
+ length = compute_vmpa_diff(&start, &end);
+
+ init_mrange(range, &start, length);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de correspondances attribut/binaire. *
+* name = désignation de l'élément recherché. *
+* len = taille de cette désignation. *
+* level = profondeur maximale à atteindre (fond : 0). *
+* *
+* Description : Recherche la correspondance associée à un identifiant. *
+* *
+* Retour : Correspondance trouvée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GMatchRecord *g_record_list_find_by_name(GRecordList *list, const char *name, size_t len, unsigned int level)
+{
+ GMatchRecord *result; /* Correspondance à renvoyer */
+ GMatchRecordClass *class; /* Classe parente normalisée */
+ size_t i; /* Boucle de parcours */
+
+ class = G_MATCH_RECORD_CLASS(g_record_list_parent_class);
+
+ result = class->find(G_MATCH_RECORD(list), name, len, level);
+
+ if (level > 0)
+ {
+ for (i = 0; i < list->count && result == NULL; i++)
+ result = g_match_record_find_by_name(list->children[i], name, len, level);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de correspondances attribut/binaire. *
+* name = désignation de l'élément recherché. *
+* label = étiquette de l'élément constant à traduire. *
+* value = valeur entière correspondante. [OUT] *
+* *
+* Description : Transforme une énumération en constante entière. *
+* *
+* Retour : Bilan de l'opération : true si la résolution est réalisée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_record_list_resolve_enum(const GRecordList *list, const sized_string_t *name, const sized_string_t *label, resolved_value_t *value)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ /**
+ * Comme les types peuvent être sélectionnés dynamiquement, le parcours
+ * de l'ensemble des sous-noeuds doit être effectué.
+ */
+
+ result = false;
+
+ for (i = 0; i < list->count && !result; i++)
+ result = g_match_record_resolve_enum(list->children[i], name, label, value);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/records/list.h b/plugins/kaitai/records/list.h
new file mode 100644
index 0000000..03e593e
--- /dev/null
+++ b/plugins/kaitai/records/list.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list.h - prototypes pour la conservation d'une liste de correspondance avec du binaire
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_RECORDS_LIST_H
+#define _PLUGINS_KAITAI_RECORDS_LIST_H
+
+
+#include <glib-object.h>
+
+
+#include <analysis/content.h>
+
+
+#include "../record.h"
+#include "../parsers/attribute.h"
+
+
+
+#define G_TYPE_RECORD_LIST g_record_list_get_type()
+#define G_RECORD_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_LIST, GRecordList))
+#define G_IS_RECORD_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_LIST))
+#define G_RECORD_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_LIST, GRecordListClass))
+#define G_IS_RECORD_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_LIST))
+#define G_RECORD_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_LIST, GRecordListClass))
+
+
+/* Liste de correspondances établies entre attributs et binaire (instance) */
+typedef struct _GRecordList GRecordList;
+
+/* Liste de correspondances établies entre attributs et binaire (classe) */
+typedef struct _GRecordListClass GRecordListClass;
+
+
+/* Indique le type défini pour une série de correspondances entre attributes et binaire. */
+GType g_record_list_get_type(void);
+
+/* Crée une nouvelle série de correspondances attribut/binaire. */
+GRecordList *g_record_list_new(GKaitaiAttribute *, GBinContent *, const vmpa2t *);
+
+/* Dénombre le nombre de correspondances enregistrées. */
+size_t g_record_list_count_records(const GRecordList *);
+
+/* Ajoute une correspondance supplémentaire à une série. */
+void g_record_list_add_record(GRecordList *, GMatchRecord *);
+
+/* Fournit un élément ciblé dans la liste de correspondances. */
+GMatchRecord *g_record_list_get_record(const GRecordList *, size_t);
+
+
+
+#endif /* _PLUGINS_KAITAI_RECORDS_LIST_H */
diff --git a/plugins/kaitai/rost/Makefile.am b/plugins/kaitai/rost/Makefile.am
new file mode 100644
index 0000000..c7ea84a
--- /dev/null
+++ b/plugins/kaitai/rost/Makefile.am
@@ -0,0 +1,18 @@
+
+noinst_LTLIBRARIES = libkaitairost.la
+
+libkaitairost_la_SOURCES = \
+ browser-int.h \
+ browser.h browser.c \
+ core.h core.c \
+ space-int.h \
+ space.h space.c \
+ trigger-int.h \
+ trigger.h trigger.c
+
+libkaitairost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitairost_la_SOURCES:%c=)
diff --git a/plugins/kaitai/rost/browser-int.h b/plugins/kaitai/rost/browser-int.h
new file mode 100644
index 0000000..4b49680
--- /dev/null
+++ b/plugins/kaitai/rost/browser-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * browser-int.h - prototypes internes pour le parcours des résultats d'analyse Kaitai pour ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_ROST_BROWSER_INT_H
+#define PLUGINS_KAITAI_ROST_BROWSER_INT_H
+
+
+#include <analysis/scan/item-int.h>
+
+
+#include "browser.h"
+
+
+
+/* Parcours des résultats d'une analyse Kaitai pour ROST (instance) */
+struct _GKaitaiBrowser
+{
+ GScanRegisteredItem parent; /* A laisser en premier */
+
+ char *path; /* Chamin vers l'enregistrement*/
+ GMatchRecord *record; /* Correspondance à parcourir */
+
+};
+
+/* Parcours des résultats d'une analyse Kaitai pour ROST (classe) */
+struct _GKaitaiBrowserClass
+{
+ GScanRegisteredItemClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un nouveau parcours de correspondances Kaitai. */
+bool g_kaitai_browser_create(GKaitaiBrowser *, const char *, GMatchRecord *);
+
+
+
+#endif /* PLUGINS_KAITAI_ROST_BROWSER_INT_H */
diff --git a/plugins/kaitai/rost/browser.c b/plugins/kaitai/rost/browser.c
new file mode 100644
index 0000000..159915b
--- /dev/null
+++ b/plugins/kaitai/rost/browser.c
@@ -0,0 +1,478 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * browser.c - accès à des définitions Kaitai depuis ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "browser.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include <analysis/scan/exprs/literal.h>
+
+
+#include "browser-int.h"
+#include "../records/bits.h"
+#include "../records/delayed.h"
+#include "../records/item.h"
+#include "../records/list.h"
+
+
+
+/* ---------------------- PARCOURS DE CORRESPONDANCES ETABLIES ---------------------- */
+
+
+/* Initialise la classe des parcours de correspondances Kaitai. */
+static void g_kaitai_browser_class_init(GKaitaiBrowserClass *);
+
+/* Initialise un parcours de correspondances Kaitai. */
+static void g_kaitai_browser_init(GKaitaiBrowser *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_browser_dispose(GKaitaiBrowser *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_browser_finalize(GKaitaiBrowser *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_kaitai_browser_get_name(const GKaitaiBrowser *);
+
+/* Lance une résolution d'élément à solliciter. */
+static bool g_kaitai_browser_resolve(GKaitaiBrowser *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_kaitai_browser_reduce(GKaitaiBrowser *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Effectue une extraction d'élément à partir d'une série. */
+static GObject *g_kaitai_browser_extract_at(GKaitaiBrowser *, const GScanExpression *, GScanContext *, GScanScope *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* PARCOURS DE CORRESPONDANCES ETABLIES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un parcours de correspondances Kaitai pour ROST. */
+G_DEFINE_TYPE(GKaitaiBrowser, g_kaitai_browser, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des parcours de correspondances Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_browser_class_init(GKaitaiBrowserClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_browser_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_browser_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_kaitai_browser_get_name;
+ registered->resolve = (resolve_registered_item_fc)g_kaitai_browser_resolve;
+ registered->reduce = (reduce_registered_item_fc)g_kaitai_browser_reduce;
+ registered->extract = (extract_registered_item_at)g_kaitai_browser_extract_at;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : browser = instance à initialiser. *
+* *
+* Description : Initialise un parcours de correspondances Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_browser_init(GKaitaiBrowser *browser)
+{
+ browser->path = NULL;
+ browser->record = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : browser = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_browser_dispose(GKaitaiBrowser *browser)
+{
+ g_clear_object(&browser->record);
+
+ G_OBJECT_CLASS(g_kaitai_browser_parent_class)->dispose(G_OBJECT(browser));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : browser = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_browser_finalize(GKaitaiBrowser *browser)
+{
+ if (browser->path != NULL)
+ free(browser->path);
+
+ G_OBJECT_CLASS(g_kaitai_browser_parent_class)->finalize(G_OBJECT(browser));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin vers l'enregistrement fourni. *
+* record = correspondance racine à considérer. *
+* *
+* Description : Crée un nouveau parcours de correspondances Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiBrowser *g_kaitai_browser_new(const char *path, GMatchRecord *record)
+{
+ GKaitaiBrowser *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_BROWSER, NULL);
+
+ if (!g_kaitai_browser_create(result, path, record))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : browser = encadrement d'un parcours de correspondances. *
+* path = chemin vers l'enregistrement fourni. *
+* record = correspondance racine à considérer. *
+* *
+* Description : Met en place un nouveau parcours de correspondances Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_browser_create(GKaitaiBrowser *browser, const char *path, GMatchRecord *record)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (path != NULL)
+ browser->path = strdup(path);
+
+ browser->record = record;
+ g_object_ref(G_OBJECT(browser->record));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_kaitai_browser_get_name(const GKaitaiBrowser *item)
+{
+ char *result; /* Désignation à retourner */
+ int ret; /* Statut de construction */
+
+ if (item->path == NULL)
+ result = strdup("kaitai://");
+
+ else
+ {
+ ret = asprintf(&result, "kaitai://%s", item->path);
+ assert(ret > 0);
+
+ if (ret <= 0)
+ result = strdup("kaitai://???");
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* target = désignation de l'objet d'appel à identifier. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT]*
+* *
+* Description : Lance une résolution d'élément à solliciter. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_browser_resolve(GKaitaiBrowser *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out)
+{
+ bool result; /* Bilan à retourner */
+ GMatchRecord *found; /* Correspondance trouvée */
+ char *path;
+ int ret; /* Statut de construction */
+
+ found = g_match_record_find_by_name(item->record, target, strlen(target), 1);
+ result = (found != NULL);
+
+ if (result)
+ {
+ ret = asprintf(&path, "%s.%s", item->path, target);
+ assert(ret > 0);
+
+ if (ret <= 0)
+ path = strdup("!?");
+
+ *out = G_SCAN_REGISTERED_ITEM(g_kaitai_browser_new(path, found));
+
+ free(path);
+ g_object_unref(G_OBJECT(found));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_browser_reduce(GKaitaiBrowser *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t count; /* Décompte total à considérer */
+ resolved_value_t value; /* Valeur brute à transformer */
+
+ if (G_IS_RECORD_LIST(item->record))
+ {
+ count = g_record_list_count_records(G_RECORD_LIST(item->record));
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ count > 0 });
+
+ result = true;
+
+ }
+
+ else
+ {
+ if (G_IS_RECORD_BIT_FIELD(item->record))
+ result = g_record_bit_field_get_value(G_RECORD_BIT_FIELD(item->record), &value);
+
+ else if (G_IS_RECORD_DELAYED(item->record))
+ result = g_record_delayed_compute_and_aggregate_value(G_RECORD_DELAYED(item->record), &value);
+
+ else if (G_IS_RECORD_ITEM(item->record))
+ result = g_record_item_get_value(G_RECORD_ITEM(item->record), &value);
+
+ else
+ result = false;
+
+ if (result)
+ {
+ switch (value.type)
+ {
+ case GVT_UNSIGNED_INTEGER:
+ *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &value.unsigned_integer);
+ break;
+
+ case GVT_SIGNED_INTEGER:
+ *out = g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &value.signed_integer);
+ break;
+
+ case GVT_FLOAT:
+ /* TODO */
+ break;
+
+ case GVT_BOOLEAN:
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, &value.status);
+ break;
+
+ case GVT_BYTES:
+ *out = g_scan_literal_expression_new(LVT_STRING, &value.bytes);
+ break;
+
+ default:
+ break;
+
+ }
+
+ EXIT_RESOLVED_VALUE(value);
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* index = indice de l'élément à cibler. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* *
+* Description : Effectue une extraction d'élément à partir d'une série. *
+* *
+* Retour : Elément de série obtenu ou NULL si erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GObject *g_kaitai_browser_extract_at(GKaitaiBrowser *item, const GScanExpression *index, GScanContext *ctx, GScanScope *scope)
+{
+ GObject *result; /* Elément récupéré à renvoyer */
+ GScanLiteralExpression *literal; /* Accès direct à l'indice */
+ LiteralValueType vtype; /* Type de valeur portée */
+ unsigned long long at; /* Valeur concrète du point */
+ bool status; /* Bilan d'obtention d'indice */
+ GRecordList *list; /* Accès direct à la liste */
+ size_t count; /* Décompte total à considérer */
+ GMatchRecord *found; /* Correspondance trouvée */
+ char *path;
+ int ret; /* Statut de construction */
+
+ result = NULL;
+
+ /* Validations préliminaires */
+
+ if (!G_IS_RECORD_LIST(item->record)) goto exit;
+ if (!G_IS_SCAN_LITERAL_EXPRESSION(index)) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(index);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+ if (vtype != LVT_UNSIGNED_INTEGER) goto exit;
+
+ status = g_scan_literal_expression_get_unsigned_integer_value(literal, &at);
+ if (!status) goto exit;
+
+ list = G_RECORD_LIST(item->record);
+
+ count = g_record_list_count_records(list);
+ if (at >= count) goto exit;
+
+ /* Récupération de l'élément visé */
+
+ found = g_record_list_get_record(list, at);
+ if (found == NULL) goto exit;
+
+ ret = asprintf(&path, "%s[%llu]", item->path, at);
+ assert(ret > 0);
+
+ if (ret <= 0)
+ path = strdup("!?");
+
+ result = G_OBJECT(g_kaitai_browser_new(path, found));
+
+ free(path);
+ g_object_unref(G_OBJECT(found));
+
+ exit:
+
+ return result;
+
+}
diff --git a/plugins/kaitai/rost/browser.h b/plugins/kaitai/rost/browser.h
new file mode 100644
index 0000000..89b9f6f
--- /dev/null
+++ b/plugins/kaitai/rost/browser.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * browser.h - prototypes pour le parcours des résultats d'analyse Kaitai pour ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_ROST_BROWSER_H
+#define PLUGINS_KAITAI_ROST_BROWSER_H
+
+
+#include <glib-object.h>
+
+
+#include "../record.h"
+
+
+
+#define G_TYPE_KAITAI_BROWSER g_kaitai_browser_get_type()
+#define G_KAITAI_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_BROWSER, GKaitaiBrowser))
+#define G_IS_KAITAI_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_BROWSER))
+#define G_KAITAI_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_BROWSER, GKaitaiBrowserClass))
+#define G_IS_KAITAI_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_BROWSER))
+#define G_KAITAI_BROWSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_BROWSER, GKaitaiBrowserClass))
+
+
+/* Parcours des résultats d'une analyse Kaitai pour ROST (instance) */
+typedef struct _GKaitaiBrowser GKaitaiBrowser;
+
+/* Parcours des résultats d'une analyse Kaitai pour ROST (classe) */
+typedef struct _GKaitaiBrowserClass GKaitaiBrowserClass;
+
+
+/* Indique le type défini pour un parcours de correspondances Kaitai pour ROST. */
+GType g_kaitai_browser_get_type(void);
+
+/* Crée un nouveau parcours de correspondances Kaitai. */
+GKaitaiBrowser *g_kaitai_browser_new(const char *, GMatchRecord *);
+
+
+
+#endif /* PLUGINS_KAITAI_ROST_BROWSER_H */
diff --git a/plugins/kaitai/rost/core.c b/plugins/kaitai/rost/core.c
new file mode 100644
index 0000000..8271389
--- /dev/null
+++ b/plugins/kaitai/rost/core.c
@@ -0,0 +1,66 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - mise à disposition d'un support Kaitai pour ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <core/global.h>
+
+
+#include "space.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre un support de Kaitai pour ROST. *
+* *
+* Retour : Bilan du chargement mené. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_kaitai_support_to_rost(void)
+{
+ bool result; /* Bilan à retourner */
+ GScanNamespace *root_ns; /* Espace de noms ROST racine */
+ GScanNamespace *kaitai_ns; /* Espace de noms pour Kaitai */
+
+ result = true;
+
+ root_ns = get_rost_root_namespace();
+
+ kaitai_ns = g_kaitai_namespace_new();
+
+ result = g_scan_namespace_register_item(root_ns, G_SCAN_REGISTERED_ITEM(kaitai_ns));
+
+ g_object_unref(G_OBJECT(kaitai_ns));
+
+ g_object_unref(G_OBJECT(root_ns));
+
+ return result;
+
+}
diff --git a/plugins/kaitai/rost/core.h b/plugins/kaitai/rost/core.h
new file mode 100644
index 0000000..6f810eb
--- /dev/null
+++ b/plugins/kaitai/rost/core.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour la mise à disposition d'un support Kaitai pour ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_ROST_CORE_H
+#define _PLUGINS_KAITAI_ROST_CORE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Intègre un support de Kaitai pour ROST. */
+bool add_kaitai_support_to_rost(void);
+
+
+
+#endif /* _PLUGINS_KAITAI_ROST_CORE_H */
diff --git a/plugins/kaitai/rost/space-int.h b/plugins/kaitai/rost/space-int.h
new file mode 100644
index 0000000..47ec707
--- /dev/null
+++ b/plugins/kaitai/rost/space-int.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space-int.h - prototypes internes pour la définition d'un espace de noms pour les fonctions de scan
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_ROST_SPACE_INT_H
+#define _PLUGINS_KAITAI_ROST_SPACE_INT_H
+
+
+#include "space.h"
+
+
+#include <analysis/scan/space-int.h>
+
+
+
+/* Espace de noms avec chargement dynamique de définitions Kaitai (instance) */
+struct _GKaitaiNamespace
+{
+ GScanNamespace parent; /* A laisser en premier */
+
+};
+
+/* Espace de noms avec chargement dynamique de définitions Kaitai (classe) */
+struct _GKaitaiNamespaceClass
+{
+ GScanNamespaceClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un nouvel espace de noms pour scan. */
+bool g_kaitai_namespace_create(GKaitaiNamespace *);
+
+
+
+#endif /* _PLUGINS_KAITAI_ROST_SPACE_INT_H */
diff --git a/plugins/kaitai/rost/space.c b/plugins/kaitai/rost/space.c
new file mode 100644
index 0000000..ee922d2
--- /dev/null
+++ b/plugins/kaitai/rost/space.c
@@ -0,0 +1,254 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space.c - définition d'un espace de noms pour les fonctions de scan
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "space.h"
+
+
+#include <string.h>
+
+
+#include "trigger.h"
+#include "space-int.h"
+#include "../import.h"
+
+
+
+/* ------------------------- SOCLE POUR LES ESPACES DE NOMS ------------------------- */
+
+
+/* Initialise la classe des espaces de noms dynamiques Kaitai. */
+static void g_kaitai_namespace_class_init(GKaitaiNamespaceClass *);
+
+/* Initialise une instance d'espace de noms dynamiques Kaitai. */
+static void g_kaitai_namespace_init(GKaitaiNamespace *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_namespace_dispose(GKaitaiNamespace *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_namespace_finalize(GKaitaiNamespace *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Lance une résolution d'élément à solliciter. */
+static bool g_kaitai_namespace_resolve(GKaitaiNamespace *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* SOCLE POUR LES ESPACES DE NOMS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une définition d'espace de noms dynamique Kaitai. */
+G_DEFINE_TYPE(GKaitaiNamespace, g_kaitai_namespace, G_TYPE_SCAN_NAMESPACE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des espaces de noms dynamiques Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_namespace_class_init(GKaitaiNamespaceClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_namespace_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_namespace_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->resolve = (resolve_registered_item_fc)g_kaitai_namespace_resolve;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance à initialiser. *
+* *
+* Description : Initialise une instance d'espace de noms dynamiques Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_namespace_init(GKaitaiNamespace *space)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_namespace_dispose(GKaitaiNamespace *space)
+{
+ G_OBJECT_CLASS(g_kaitai_namespace_parent_class)->dispose(G_OBJECT(space));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_namespace_finalize(GKaitaiNamespace *space)
+{
+ G_OBJECT_CLASS(g_kaitai_namespace_parent_class)->finalize(G_OBJECT(space));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un nouvel espace de noms dynamique pour Kaitai. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanNamespace *g_kaitai_namespace_new(void)
+{
+ GScanNamespace *result; /* Instance à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_NAMESPACE, NULL);
+
+ if (!g_kaitai_namespace_create(G_KAITAI_NAMESPACE(result)))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance d'espace de noms à initialiser. *
+* name = désignation du futur espace de noms. *
+* *
+* Description : Met en place un nouvel espace de noms pour scan. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_namespace_create(GKaitaiNamespace *space)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_namespace_create(G_SCAN_NAMESPACE(space), "kaitai");
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* target = désignation de l'objet d'appel à identifier. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT]*
+* *
+* Description : Lance une résolution d'élément à solliciter. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_namespace_resolve(GKaitaiNamespace *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanRegisteredItemClass *parent; /* Version de classe parente */
+ GKaitaiStruct *kstruct; /* Lecteur de définition */
+
+ parent = G_SCAN_REGISTERED_ITEM_CLASS(g_kaitai_namespace_parent_class);
+
+ result = parent->resolve(G_SCAN_REGISTERED_ITEM(item), target, ctx, scope, out);
+
+ if (!result)
+ {
+ kstruct = load_kaitai_definition(target, NULL);
+
+ if (kstruct != NULL)
+ {
+ *out = g_kaitai_trigger_new(kstruct);
+ result = true;
+
+ g_object_unref(G_OBJECT(kstruct));
+
+ }
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/rost/space.h b/plugins/kaitai/rost/space.h
new file mode 100644
index 0000000..5dcea5e
--- /dev/null
+++ b/plugins/kaitai/rost/space.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space.h - prototypes pour la définition d'un espace de noms pour les fonctions de scan
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_ROST_SPACE_H
+#define _PLUGINS_KAITAI_ROST_SPACE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <analysis/scan/space.h>
+
+
+
+#define G_TYPE_KAITAI_NAMESPACE g_kaitai_namespace_get_type()
+#define G_KAITAI_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_NAMESPACE, GKaitaiNamespace))
+#define G_IS_KAITAI_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_NAMESPACE))
+#define G_KAITAI_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_NAMESPACE, GKaitaiNamespaceClass))
+#define G_IS_KAITAI_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_NAMESPACE))
+#define G_KAITAI_NAMESPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_NAMESPACE, GKaitaiNamespaceClass))
+
+
+/* Espace de noms avec chargement dynamique de définitions Kaitai (instance) */
+typedef struct _GKaitaiNamespace GKaitaiNamespace;
+
+/* Espace de noms avec chargement dynamique de définitions Kaitai (classe) */
+typedef struct _GKaitaiNamespaceClass GKaitaiNamespaceClass;
+
+
+/* Indique le type défini pour une définition d'espace de noms dynamique Kaitai. */
+GType g_kaitai_namespace_get_type(void);
+
+/* Construit un nouvel espace de noms dynamique pour Kaitai. */
+GScanNamespace *g_kaitai_namespace_new(void);
+
+
+
+#endif /* _PLUGINS_KAITAI_ROST_SPACE_H */
diff --git a/plugins/kaitai/rost/trigger-int.h b/plugins/kaitai/rost/trigger-int.h
new file mode 100644
index 0000000..6830cd7
--- /dev/null
+++ b/plugins/kaitai/rost/trigger-int.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * trigger-int.h - prototypes internes pour l'accès à des définitions Kaitai depuis ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_ROST_TRIGGER_INT_H
+#define _PLUGINS_KAITAI_ROST_TRIGGER_INT_H
+
+
+#include <analysis/scan/item-int.h>
+
+
+#include "trigger.h"
+
+
+
+/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (instance) */
+struct _GKaitaiTrigger
+{
+ GScanRegisteredItem parent; /* A laisser en premier */
+
+ char *name; /* Désignation arbitraire */
+
+ GKaitaiStruct *kstruct; /* Définition à décliner */
+
+};
+
+/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (classe) */
+struct _GKaitaiTriggerClass
+{
+ GScanRegisteredItemClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un accès à une définition Kaitai pour ROST. */
+bool g_kaitai_trigger_create(GKaitaiTrigger *, GKaitaiStruct *);
+
+
+
+#endif /* _PLUGINS_KAITAI_ROST_TRIGGER_INT_H */
diff --git a/plugins/kaitai/rost/trigger.c b/plugins/kaitai/rost/trigger.c
new file mode 100644
index 0000000..6bb6e5d
--- /dev/null
+++ b/plugins/kaitai/rost/trigger.c
@@ -0,0 +1,320 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * trigger.c - accès à des définitions Kaitai depuis ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "trigger.h"
+
+
+#include <string.h>
+
+
+#include "browser.h"
+#include "trigger-int.h"
+
+
+
+/* ---------------------- ACCES ET DECLENCHEMENT D'UNE ANALYSE ---------------------- */
+
+
+/* Initialise la classe des accès aux définitions Kaitai. */
+static void g_kaitai_trigger_class_init(GKaitaiTriggerClass *);
+
+/* Initialise un accès à une définition Kaitai. */
+static void g_kaitai_trigger_init(GKaitaiTrigger *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_trigger_dispose(GKaitaiTrigger *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_trigger_finalize(GKaitaiTrigger *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_kaitai_trigger_get_name(const GKaitaiTrigger *);
+
+/* Lance une résolution d'élément à solliciter. */
+static bool g_kaitai_trigger_resolve(GKaitaiTrigger *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ACCES ET DECLENCHEMENT D'UNE ANALYSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un accès à une définition Kaitai pour ROST. */
+G_DEFINE_TYPE(GKaitaiTrigger, g_kaitai_trigger, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des accès aux définitions Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_trigger_class_init(GKaitaiTriggerClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_trigger_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_trigger_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_kaitai_trigger_get_name;
+ registered->resolve = (resolve_registered_item_fc)g_kaitai_trigger_resolve;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : trigger = instance à initialiser. *
+* *
+* Description : Initialise un accès à une définition Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_trigger_init(GKaitaiTrigger *trigger)
+{
+ trigger->name = NULL;
+
+ trigger->kstruct = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : trigger = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_trigger_dispose(GKaitaiTrigger *trigger)
+{
+ g_clear_object(&trigger->kstruct);
+
+ G_OBJECT_CLASS(g_kaitai_trigger_parent_class)->dispose(G_OBJECT(trigger));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : trigger = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_trigger_finalize(GKaitaiTrigger *trigger)
+{
+ if (trigger->name != NULL)
+ free(trigger->name);
+
+ G_OBJECT_CLASS(g_kaitai_trigger_parent_class)->finalize(G_OBJECT(trigger));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = définition Kaitai à manipuler avec du contenu. *
+* *
+* Description : Crée un nouvel accès à une définition Kaitai à instancier. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_kaitai_trigger_new(GKaitaiStruct *kstruct)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_TRIGGER, NULL);
+
+ if (!g_kaitai_trigger_create(G_KAITAI_TRIGGER(result), kstruct))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : trigger = lien vers une définition Kaitai à instancier. *
+* kstruct = définition Kaitai à manipuler avec du contenu. *
+* *
+* Description : Met en place un accès à une définition Kaitai pour ROST. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_trigger_create(GKaitaiTrigger *trigger, GKaitaiStruct *kstruct)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ trigger->kstruct = kstruct;
+ g_object_ref(G_OBJECT(trigger->kstruct));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : trigger = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_kaitai_trigger_get_name(const GKaitaiTrigger *trigger)
+{
+ char *result; /* Désignation à retourner */
+ GKaitaiMeta *meta; /* Eventuelles métadonnées */
+ const char *id; /* Identifiant de définition */
+
+ if (trigger->name != NULL)
+ result = strdup(trigger->name);
+
+ else
+ {
+ result = NULL;
+
+ meta = g_kaitai_structure_get_meta(trigger->kstruct);
+ if (meta == NULL) goto done;
+
+ id = g_kaitai_meta_get_id(meta);
+ if (id == NULL) goto done;
+
+ result = strdup(id);
+
+ g_object_unref(G_OBJECT(meta));
+
+ done:
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* target = désignation de l'objet d'appel à identifier. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT]*
+* *
+* Description : Lance une résolution d'élément à solliciter. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_trigger_resolve(GKaitaiTrigger *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out)
+{
+ bool result; /* Bilan à retourner */
+ GKaitaiBrowser *browser; /* Navigateur pour résultats */
+ GBinContent *content; /* Contenu binaire à analyser */
+ GMatchRecord *record; /* Premier niveau de résultats */
+
+ browser = g_object_get_data(G_OBJECT(item), "kaitai_browser");
+
+ if (browser == NULL)
+ {
+ content = g_scan_context_get_content(ctx);
+
+ record = g_kaitai_structure_parse(item->kstruct, content);
+
+ g_object_unref(G_OBJECT(content));
+
+ if (record != NULL)
+ {
+ browser = g_kaitai_browser_new(NULL, record);
+
+ g_object_set_data_full(G_OBJECT(item), "kaitai_browser", browser, g_object_unref);
+
+ }
+
+ }
+
+ if (browser == NULL)
+ result = false;
+
+ else
+ result = g_scan_registered_item_resolve(G_SCAN_REGISTERED_ITEM(browser), target, ctx, scope, out);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/rost/trigger.h b/plugins/kaitai/rost/trigger.h
new file mode 100644
index 0000000..f55e998
--- /dev/null
+++ b/plugins/kaitai/rost/trigger.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * trigger.h - prototypes pour l'accès à des définitions Kaitai depuis ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_ROST_TRIGGER_H
+#define PLUGINS_KAITAI_ROST_TRIGGER_H
+
+
+#include <glib-object.h>
+
+
+#include <analysis/scan/item.h>
+
+
+#include "../parsers/struct.h"
+
+
+
+#define G_TYPE_KAITAI_TRIGGER g_kaitai_trigger_get_type()
+#define G_KAITAI_TRIGGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_TRIGGER, GKaitaiTrigger))
+#define G_IS_KAITAI_TRIGGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_TRIGGER))
+#define G_KAITAI_TRIGGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_TRIGGER, GKaitaiTriggerClass))
+#define G_IS_KAITAI_TRIGGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_TRIGGER))
+#define G_KAITAI_TRIGGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_TRIGGER, GKaitaiTriggerClass))
+
+
+/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (instance) */
+typedef struct _GKaitaiTrigger GKaitaiTrigger;
+
+/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (classe) */
+typedef struct _GKaitaiTriggerClass GKaitaiTriggerClass;
+
+
+/* Indique le type défini pour un accès à une définition Kaitai pour ROST. */
+GType g_kaitai_trigger_get_type(void);
+
+/* Crée un nouvel accès à une définition Kaitai à instancier. */
+GScanRegisteredItem *g_kaitai_trigger_new(GKaitaiStruct *);
+
+
+
+#endif /* PLUGINS_KAITAI_ROST_TRIGGER_H */
diff --git a/plugins/kaitai/scope.c b/plugins/kaitai/scope.c
new file mode 100644
index 0000000..fad8890
--- /dev/null
+++ b/plugins/kaitai/scope.c
@@ -0,0 +1,257 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scope.c - recherches d'éléments de lecture
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "scope.h"
+
+
+#include "parsers/struct.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = contexte de variables locales à initialiser. *
+* meta = informations générales à disposition. *
+* *
+* Description : Initialise un contexte pour correspondances Kaitai établies. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void init_record_scope(kaitai_scope_t *locals, GKaitaiMeta *meta)
+{
+ locals->meta = meta;
+
+ if (meta != NULL)
+ g_object_ref(G_OBJECT(meta));
+
+ locals->root = NULL;
+ locals->parent = NULL;
+ locals->last = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = contexte de variables locales à réinitialiser. *
+* *
+* Description : Vide un contexte de correspondances Kaitai établies. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void reset_record_scope(kaitai_scope_t *locals)
+{
+ g_clear_object(&locals->meta);
+
+ g_clear_object(&locals->root);
+ g_clear_object(&locals->parent);
+ g_clear_object(&locals->last);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = contexte de variables locales à initialiser. *
+* src = contexte de variables locales à copier. *
+* *
+* Description : Copie un contexte de correspondances Kaitai établies. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void copy_record_scope(kaitai_scope_t *dest, const kaitai_scope_t *src)
+{
+ reset_record_scope(dest);
+
+#define COPY_SCOPE_ITEM(itm) \
+ dest->itm = src->itm; \
+ if (dest->itm != NULL) \
+ g_object_ref(G_OBJECT(dest->itm));
+
+ COPY_SCOPE_ITEM(meta);
+
+ COPY_SCOPE_ITEM(root);
+ COPY_SCOPE_ITEM(parent);
+ COPY_SCOPE_ITEM(last);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* *
+* Description : Retourne le souvenir d'une correspondance racine. *
+* *
+* Retour : Dernière correspondance établie ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *get_root_record(const kaitai_scope_t *locals)
+{
+ GMatchRecord *result; /* Instance à retourner */
+
+ result = locals->root;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* *
+* Description : Retourne le souvenir de la correspondance parente effectuée. *
+* *
+* Retour : Dernière correspondance établie ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *get_parent_record(const kaitai_scope_t *locals)
+{
+ GMatchRecord *result; /* Instance à retourner */
+
+ result = locals->parent;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* record = dernière correspondance établie. *
+* *
+* Description : Conserve le souvenir de la dernière correspondance effectuée.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void remember_last_record(kaitai_scope_t *locals, GMatchRecord *record)
+{
+ g_clear_object(&locals->last);
+
+ locals->last = record;
+
+ if (record != NULL)
+ g_object_ref(G_OBJECT(record));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* *
+* Description : Retourne le souvenir de la dernière correspondance effectuée.*
+* *
+* Retour : Dernière correspondance établie ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *get_last_record(const kaitai_scope_t *locals)
+{
+ GMatchRecord *result; /* Instance à retourner */
+
+ result = locals->last;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* name = désignation du type particulier ciblé. *
+* *
+* Description : Recherche la définition d'un type nouveau pour Kaitai. *
+* *
+* Retour : Type prêt à emploi ou NULL si non trouvé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiType *find_sub_type(const kaitai_scope_t *locals, const char *name)
+{
+ GKaitaiType *result; /* Instance à retourner */
+ size_t i; /* Boucle de parcours */
+ GKaitaiParser *parser; /* Lecteur d'origine */
+
+ GMatchRecord *list[] = { locals->last, locals->parent, locals->root };
+
+ result = NULL;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (list[i] == NULL)
+ continue;
+
+ parser = g_match_record_get_creator(list[i]);
+
+ if (G_IS_KAITAI_STRUCT(parser))
+ result = g_kaitai_structure_find_sub_type(G_KAITAI_STRUCT(parser), name);
+
+ g_object_unref(G_OBJECT(parser));
+
+ if (result != NULL)
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/scope.h b/plugins/kaitai/scope.h
new file mode 100644
index 0000000..5dc52bf
--- /dev/null
+++ b/plugins/kaitai/scope.h
@@ -0,0 +1,72 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scope.h - prototypes pour les recherches d'éléments de lecture
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_SCOPE_H
+#define _PLUGINS_KAITAI_SCOPE_H
+
+
+#include "record.h"
+#include "parsers/meta.h"
+#include "parsers/type.h"
+
+
+
+/* Accès aux différentes variables de contexte */
+typedef struct _kaitai_scope_t
+{
+ GKaitaiMeta *meta; /* Informations globales */
+
+ GMatchRecord *root; /* Variable "_root" */
+ GMatchRecord *parent; /* Variable "_parent" */
+ GMatchRecord *last; /* Variable "_" */
+
+} kaitai_scope_t;
+
+
+/* Initialise un contexte pour correspondances Kaitai établies. */
+void init_record_scope(kaitai_scope_t *, GKaitaiMeta *);
+
+/* Vide un contexte de correspondances Kaitai établies. */
+void reset_record_scope(kaitai_scope_t *);
+
+/* Copie un contexte de correspondances Kaitai établies. */
+void copy_record_scope(kaitai_scope_t *, const kaitai_scope_t *);
+
+/* Retourne le souvenir d'une correspondance racine. */
+GMatchRecord *get_root_record(const kaitai_scope_t *);
+
+/* Retourne le souvenir de la correspondance parente effectuée. */
+GMatchRecord *get_parent_record(const kaitai_scope_t *);
+
+/* Conserve le souvenir de la dernière correspondance effectuée. */
+void remember_last_record(kaitai_scope_t *, GMatchRecord *);
+
+/* Retourne le souvenir de la dernière correspondance effectuée. */
+GMatchRecord *get_last_record(const kaitai_scope_t *);
+
+/* Recherche la définition d'un type nouveau pour Kaitai. */
+GKaitaiType *find_sub_type(const kaitai_scope_t *, const char *);
+
+
+
+#endif /* _PLUGINS_KAITAI_SCOPE_H */
diff --git a/plugins/kaitai/stream-int.h b/plugins/kaitai/stream-int.h
new file mode 100644
index 0000000..50b71df
--- /dev/null
+++ b/plugins/kaitai/stream-int.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * stream-int.h - prototypes pour les données associées à un flux de données Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_STREAM_INT_H
+#define PLUGINS_KAITAI_STREAM_INT_H
+
+
+#include "stream.h"
+
+
+
+/* Flux de données à disposition d'une analyse Kaitai (instance) */
+struct _GKaitaiStream
+{
+ GObject parent; /* A laisser en premier */
+
+ GBinContent *content; /* Contenu brut manipulé */
+ vmpa2t pos; /* Tête de lecture dans le flux*/
+
+};
+
+/* Flux de données à disposition d'une analyse Kaitai (classe) */
+struct _GKaitaiStreamClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un flux de données pour Kaitai. */
+bool g_kaitai_stream_create(GKaitaiStream *, GBinContent *, const vmpa2t *);
+
+
+
+#endif /* PLUGINS_KAITAI_STREAM_INT_H */
diff --git a/plugins/kaitai/stream.c b/plugins/kaitai/stream.c
new file mode 100644
index 0000000..66d0f8e
--- /dev/null
+++ b/plugins/kaitai/stream.c
@@ -0,0 +1,237 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * stream.c - données associées à un flux de données Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "stream.h"
+
+
+#include "stream-int.h"
+
+
+
+/* Initialise la classe des flux de données pour Kaitai. */
+static void g_kaitai_stream_class_init(GKaitaiStreamClass *);
+
+/* Initialise un flux de données accessibles à Kaitai. */
+static void g_kaitai_stream_init(GKaitaiStream *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_stream_dispose(GKaitaiStream *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_stream_finalize(GKaitaiStream *);
+
+
+
+/* Indique le type défini pour un flux de données manipulé par une lecture Kaitai. */
+G_DEFINE_TYPE(GKaitaiStream, g_kaitai_stream, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des flux de données pour Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_stream_class_init(GKaitaiStreamClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_stream_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_stream_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = instance à initialiser. *
+* *
+* Description : Initialise un flux de données accessibles à Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_stream_init(GKaitaiStream *stream)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_stream_dispose(GKaitaiStream *stream)
+{
+ G_OBJECT_CLASS(g_kaitai_stream_parent_class)->dispose(G_OBJECT(stream));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_stream_finalize(GKaitaiStream *stream)
+{
+ G_OBJECT_CLASS(g_kaitai_stream_parent_class)->finalize(G_OBJECT(stream));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = contenu binaire parcouru par une analyse Kaitai. *
+* pos = tête de lecture courante. *
+* *
+* Description : Rassemble les éléments constituant un flux de données Kaitai.*
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiStream *g_kaitai_stream_new(GBinContent *content, const vmpa2t *pos)
+{
+ GKaitaiStream *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_STREAM, NULL);
+
+ if (!g_kaitai_stream_create(result, content, pos))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à initialiser pleinement.*
+* content = contenu binaire parcouru par une analyse Kaitai. *
+* pos = tête de lecture courante. *
+* *
+* Description : Met en place un flux de données pour Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_stream_create(GKaitaiStream *stream, GBinContent *content, const vmpa2t *pos)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ stream->content = content;
+ g_object_ref(G_OBJECT(content));
+
+ copy_vmpa(&stream->pos, pos);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = flux de données Kaitai à consulter. *
+* *
+* Description : Indique le contenu de données binaires lié au flux Kaitai. *
+* *
+* Retour : Contenu binaire associé au flux de données. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBinContent *g_kaitai_stream_get_content(const GKaitaiStream *stream)
+{
+ GBinContent *result; /* Instance à renvoyer */
+
+ result = stream->content;
+
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = flux de données Kaitai à consulter. *
+* *
+* Description : Détermine si la fin des données a été atteinte. *
+* *
+* Retour : true si la tête de lecture est en position finale, ou false. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_stream_has_reached_eof(const GKaitaiStream *stream)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t end; /* Position finale du flux */
+ int ret; /* Bilan d'une comparaison */
+
+ g_binary_content_compute_end_pos(stream->content, &end);
+
+ ret = cmp_vmpa_by_phy(&stream->pos, &end);
+
+ result = (ret == 0);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/stream.h b/plugins/kaitai/stream.h
new file mode 100644
index 0000000..ee82c6d
--- /dev/null
+++ b/plugins/kaitai/stream.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * stream.h - prototypes pour les données associées à un flux de données Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_STREAM_H
+#define PLUGINS_KAITAI_STREAM_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <analysis/content.h>
+
+
+
+#define G_TYPE_KAITAI_STREAM g_kaitai_stream_get_type()
+#define G_KAITAI_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_STREAM, GKaitaiStream))
+#define G_IS_KAITAI_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_STREAM))
+#define G_KAITAI_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_STREAM, GKaitaiStreamClass))
+#define G_IS_KAITAI_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_STREAM))
+#define G_KAITAI_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_STREAM, GKaitaiStreamClass))
+
+
+/* Flux de données à disposition d'une analyse Kaitai (instance) */
+typedef struct _GKaitaiStream GKaitaiStream;
+
+/* Flux de données à disposition d'une analyse Kaitai (classe) */
+typedef struct _GKaitaiStreamClass GKaitaiStreamClass;
+
+
+/* Indique le type défini pour un flux de données manipulé par une lecture Kaitai. */
+GType g_kaitai_stream_get_type(void);
+
+/* Rassemble les éléments constituant un flux de données Kaitai. */
+GKaitaiStream *g_kaitai_stream_new(GBinContent *, const vmpa2t *);
+
+/* Indique le contenu de données binaires lié au flux Kaitai. */
+GBinContent *g_kaitai_stream_get_content(const GKaitaiStream *);
+
+/* Détermine si la fin des données a été atteinte. */
+bool g_kaitai_stream_has_reached_eof(const GKaitaiStream *);
+
+
+
+#endif /* PLUGINS_KAITAI_STREAM_H */
diff --git a/plugins/kaitai/tokens.l b/plugins/kaitai/tokens.l
new file mode 100644
index 0000000..8c93299
--- /dev/null
+++ b/plugins/kaitai/tokens.l
@@ -0,0 +1,329 @@
+
+%top {
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+#include <common/extstr.h>
+
+#include "grammar.h"
+
+}
+
+
+%{
+
+#define PUSH_STATE(s) yy_push_state(s, yyscanner)
+#define POP_STATE yy_pop_state(yyscanner)
+
+%}
+
+
+%option bison-bridge reentrant
+%option stack
+%option nounput
+ //%option noinput
+%option noyywrap
+%option noyy_top_state
+%option yylineno
+%option never-interactive
+
+
+%x encoding
+%x escaped_str
+%x plain_str
+
+
+%%
+
+
+%{
+
+ /* no init C code */
+
+%}
+
+
+"+" { return PLUS; }
+"-" { return MINUS; }
+"*" { return MUL; }
+"/" { return DIV; }
+"%" { return MOD; }
+
+"<" { return LT; }
+"<=" { return LE; }
+"==" { return EQ; }
+"!=" { return NE; }
+">" { return GT; }
+">=" { return GE; }
+
+"<<" { return SHIFT_LEFT; }
+">>" { return SHIFT_RIGHT; }
+"&" { return BIT_AND; }
+"|" { return BIT_OR; }
+"^" { return BIT_XOR; }
+
+"not" { return NOT; }
+"and" { return AND; }
+"or" { return OR; }
+
+"(" { return PAREN_O; }
+")" { return PAREN_C; }
+"[" { return HOOK_O; }
+"]" { return HOOK_C; }
+"," { return COMMA; }
+"." { return DOT; }
+
+"?" { return QMARK; }
+":" { return COLON; }
+"::" { return DOUBLE_COLON; }
+
+".size" { return METH_SIZE; }
+".length" { return METH_LENGTH; }
+".reverse" { return METH_REVERSE; }
+".substring" { return METH_SUBSTRING; }
+".to_i" { return METH_TO_I; }
+".to_i(" { return METH_TO_I_RAD; }
+".to_s" { return METH_TO_S; }
+".to_s(" { PUSH_STATE(encoding); return METH_TO_S_ENC; }
+
+"_root" { return ROOT; }
+"_parent" { return PARENT; }
+"_" { return LAST; }
+"_io" { return IO; }
+"._io" { return METH_IO; }
+".eof" { return IO_EOF; }
+
+"true" { return TRUE_CONST; }
+"false" { return FALSE_CONST; }
+
+
+%{ /* Lecteurs de valeurs entières */ %}
+
+0[bB][01]+ {
+ char *__end;
+ yylval->unsigned_integer = strtoull(yytext + 2, &__end, 2);
+ if (__end != (yytext + yyleng))
+ YY_FATAL_ERROR("failed to parse integer");
+ return UNSIGNED_INTEGER;
+ }
+
+0[bB][01]{1,4}(_[01]{4})+ {
+ char *__tmp;
+ char *__end;
+ __tmp = strdup(yytext);
+ __tmp = strrpl(__tmp, "_", "");
+ yylval->unsigned_integer = strtoull(__tmp + 2, &__end, 2);
+ if (__end != (__tmp + strlen(__tmp)))
+ {
+ free(__tmp);
+ YY_FATAL_ERROR("failed to parse integer");
+ }
+ else free(__tmp);
+ return UNSIGNED_INTEGER;
+ }
+
+(0|[1-9][0-9]*) {
+ char *__end;
+ yylval->unsigned_integer = strtoull(yytext, &__end, 10);
+ if (__end != (yytext + yyleng))
+ YY_FATAL_ERROR("failed to parse integer");
+ return UNSIGNED_INTEGER;
+ }
+
+[1-9][0-9]{0,2}(_[1-9][0-9]{2})+ {
+ char *__tmp;
+ char *__end;
+ __tmp = strdup(yytext);
+ __tmp = strrpl(__tmp, "_", "");
+ yylval->unsigned_integer = strtoull(__tmp, &__end, 10);
+ if (__end != (__tmp + strlen(__tmp)))
+ {
+ free(__tmp);
+ YY_FATAL_ERROR("failed to parse integer");
+ }
+ else free(__tmp);
+ return UNSIGNED_INTEGER;
+ }
+
+-(0|[1-9][0-9]*) {
+ char *__end;
+ yylval->signed_integer = strtoll(yytext, &__end, 10);
+ if (__end != (yytext + yyleng))
+ YY_FATAL_ERROR("failed to parse integer");
+ return SIGNED_INTEGER;
+ }
+
+-[1-9][0-9]{0,2}(_[1-9][0-9]{2})+ {
+ char *__tmp;
+ char *__end;
+ __tmp = strdup(yytext);
+ __tmp = strrpl(__tmp, "_", "");
+ yylval->signed_integer = strtoll(__tmp, &__end, 10);
+ if (__end != (__tmp + strlen(__tmp)))
+ {
+ free(__tmp);
+ YY_FATAL_ERROR("failed to parse integer");
+ }
+ else free(__tmp);
+ return SIGNED_INTEGER;
+ }
+
+0[xX][0-9a-fA-F]+ {
+ char *__end;
+ yylval->unsigned_integer = strtoull(yytext, &__end, 16);
+ if (__end != (yytext + yyleng))
+ YY_FATAL_ERROR("failed to parse integer");
+ return UNSIGNED_INTEGER;
+ }
+
+0[xX][0-9a-fA-F]{1,4}(_[0-9a-fA-F]{4})+ {
+ char *__tmp;
+ char *__end;
+ __tmp = strdup(yytext);
+ __tmp = strrpl(__tmp, "_", "");
+ yylval->unsigned_integer = strtoull(__tmp, &__end, 16);
+ if (__end != (__tmp + strlen(__tmp)))
+ {
+ free(__tmp);
+ YY_FATAL_ERROR("failed to parse integer");
+ }
+ else free(__tmp);
+ return UNSIGNED_INTEGER;
+ }
+
+
+
+-?(0|[1-9][0-9]*\.[0-9]+) {
+ char *__end;
+ yylval->floating_number = strtod(yytext, &__end);
+ if (__end != (yytext + yyleng))
+ YY_FATAL_ERROR("failed to parse float");
+ return FLOAT;
+ }
+
+
+%{ /* Paramètre d'encodage */ %}
+
+<encoding>["'][-_A-Za-z0-9 ]+["'] {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+ return ENCODING_NAME;
+ }
+
+<encoding>")" { POP_STATE; return PAREN_C; }
+
+
+[a-z][a-z0-9_]* {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return IDENTIFIER;
+ }
+
+[^\\\[\],"'()\.: ]+ {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return PLAIN_BYTES;
+ }
+
+
+%{ /* Lecteurs des tableaux de définition d'octets */ %}
+
+"\"" { PUSH_STATE(escaped_str); }
+
+
+<escaped_str>[^\\"]+ {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return RAW_BYTES;
+ }
+
+<escaped_str>"\\a" { yylval->byte = '\a'; return RAW_BYTE; }
+<escaped_str>"\\b" { yylval->byte = '\b'; return RAW_BYTE; }
+<escaped_str>"\\t" { yylval->byte = '\t'; return RAW_BYTE; }
+<escaped_str>"\\n" { yylval->byte = '\n'; return RAW_BYTE; }
+<escaped_str>"\\v" { yylval->byte = '\v'; return RAW_BYTE; }
+<escaped_str>"\\f" { yylval->byte = '\f'; return RAW_BYTE; }
+<escaped_str>"\\r" { yylval->byte = '\r'; return RAW_BYTE; }
+<escaped_str>"\\e" { yylval->byte = '\e'; return RAW_BYTE; }
+<escaped_str>"\\\"" { yylval->byte = '"'; return RAW_BYTE; }
+<escaped_str>"\\'" { yylval->byte = '\''; return RAW_BYTE; }
+<escaped_str>"\\\\" { yylval->byte = '\\'; return RAW_BYTE; }
+<escaped_str>"\\0" { yylval->byte = '\0'; return RAW_BYTE; }
+
+<escaped_str>\\[0-9]{1,3} {
+ char __tmp[4];
+ memcpy(__tmp, yytext + 1, yyleng - 1);
+ __tmp[yyleng] = '\0';
+ yylval->byte = strtoull(__tmp, NULL, 8);
+ return RAW_BYTE;
+ }
+
+<escaped_str>"\"" { POP_STATE; }
+
+
+
+
+"'" { PUSH_STATE(plain_str); }
+
+<plain_str>[^']+ {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return PLAIN_BYTES;
+ }
+
+<plain_str>['] { POP_STATE; }
+
+[.]$ {
+#ifndef NDEBUG
+ int ch;
+#endif
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+#ifndef NDEBUG
+ ch = input(yyscanner);
+ assert(ch == '\n');
+#else
+ input(yyscanner);
+#endif
+ return RAW_BYTES_WITH_ENDING_DOT;
+ }
+
+[^\\\[\],"'()\.: ]+[.]$ {
+#ifndef NDEBUG
+ int ch;
+#endif
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+#ifndef NDEBUG
+ ch = input(yyscanner);
+ assert(ch == '\n');
+#else
+ input(yyscanner);
+#endif
+ return RAW_BYTES_WITH_ENDING_DOT;
+ }
+
+
+%{ /* Actions par défaut */ %}
+
+<*>[ \t\n]+ { }
+
+<*>. {
+ char *msg;
+ int ret;
+ ret = asprintf(&msg,
+ "Unhandled token in rule definition: '%s'",
+ yytext);
+ if (ret == -1)
+ YY_FATAL_ERROR("Unhandled token in undisclosed rule definition");
+ else
+ {
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+ }
+
+
+%%
diff --git a/plugins/libcsem/Makefile.am b/plugins/libcsem/Makefile.am
index c55a2f8..a7a264f 100644
--- a/plugins/libcsem/Makefile.am
+++ b/plugins/libcsem/Makefile.am
@@ -15,10 +15,12 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN'
endif
-liblibcsem_la_SOURCES = \
- exit.h exit.c \
+liblibcsem_la_SOURCES = \
+ exit.h exit.c \
semantic.h semantic.c
+liblibcsem_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
liblibcsem_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -29,8 +31,3 @@ liblibcsem_la_LDFLAGS = \
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(liblibcsem_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/lnxsyscalls/Makefile.am b/plugins/lnxsyscalls/Makefile.am
index 9c5158f..21feaa5 100644
--- a/plugins/lnxsyscalls/Makefile.am
+++ b/plugins/lnxsyscalls/Makefile.am
@@ -14,17 +14,17 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN'
endif
-liblnxsyscalls_la_SOURCES = \
- collect.h collect.c \
- core.h core.c \
- db.h db.c \
- hops.h \
- hops_armv7.h hops_armv7.c \
- hunter.h hunter.c \
- syscall.h syscall.c \
+liblnxsyscalls_la_SOURCES = \
+ collect.h collect.c \
+ core.h core.c \
+ db.h db.c \
+ hops.h \
+ hops_armv7.h hops_armv7.c \
+ hunter.h hunter.c \
+ syscall.h syscall.c \
writer.h writer.c
-liblnxsyscalls_la_LIBADD =
+liblnxsyscalls_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
liblnxsyscalls_la_LDFLAGS = \
-avoid-version \
@@ -44,10 +44,3 @@ dbdir = $(pluginsdatadir)
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(liblnxsyscalls_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/lnxsyscalls/hunter.h b/plugins/lnxsyscalls/hunter.h
index ed191f4..c2040eb 100644
--- a/plugins/lnxsyscalls/hunter.h
+++ b/plugins/lnxsyscalls/hunter.h
@@ -26,7 +26,7 @@
#include <analysis/binary.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
#include "hops.h"
diff --git a/plugins/mobicore/Makefile.am b/plugins/mobicore/Makefile.am
index 761108e..e8616c2 100644
--- a/plugins/mobicore/Makefile.am
+++ b/plugins/mobicore/Makefile.am
@@ -11,13 +11,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs'
endif
-libmobicore_la_SOURCES = \
- core.h core.c \
- mclf-def.h \
- mclf-int.h mclf-int.c \
- mclf.h mclf.c \
+libmobicore_la_SOURCES = \
+ core.h core.c \
+ mclf-def.h \
+ mclf-int.h mclf-int.c \
+ mclf.h mclf.c \
symbols.h symbols.c
+libmobicore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libmobicore_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -27,8 +29,3 @@ libmobicore_la_LDFLAGS = \
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libmobicore_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pe/Makefile.am b/plugins/pe/Makefile.am
index 038b8c5..e9cd482 100644
--- a/plugins/pe/Makefile.am
+++ b/plugins/pe/Makefile.am
@@ -37,19 +37,21 @@ PYTHON3_SUBDIRS = python
endif
-libpe_la_SOURCES = \
- core.h core.c \
- pe-int.h pe-int.c \
- format.h format.c \
- pe_def.h \
- rich.h rich.c \
- routine.h routine.c \
- section.h section.c \
+libpe_la_SOURCES = \
+ core.h core.c \
+ pe-int.h pe-int.c \
+ format.h format.c \
+ pe_def.h \
+ rich.h rich.c \
+ routine.h routine.c \
+ section.h section.c \
symbols.h symbols.c
-libpe_la_LIBADD = \
+libpe_la_LIBADD = \
$(PYTHON3_LIBADD)
+libpe_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libpe_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -61,8 +63,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpe_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/pe/core.c b/plugins/pe/core.c
index aa51c18..ddbacf5 100644
--- a/plugins/pe/core.c
+++ b/plugins/pe/core.c
@@ -24,18 +24,17 @@
#include "core.h"
-#include <config.h>
#include <core/global.h>
#include <plugins/self.h>
#include "format.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
{
bool result; /* Bilan à retourner */
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
result = add_format_pe_module_to_python_module();
#else
result = true;
diff --git a/plugins/pe/python/Makefile.am b/plugins/pe/python/Makefile.am
index 18634a3..5949821 100644
--- a/plugins/pe/python/Makefile.am
+++ b/plugins/pe/python/Makefile.am
@@ -1,23 +1,17 @@
noinst_LTLIBRARIES = libpepython.la
-libpepython_la_SOURCES = \
- constants.h constants.c \
- format.h format.c \
- module.h module.c \
- routine.h routine.c \
+libpepython_la_SOURCES = \
+ constants.h constants.c \
+ format.h format.c \
+ module.h module.c \
+ routine.h routine.c \
translate.h translate.c
-
-libpepython_la_LDFLAGS =
+libpepython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpepython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pe/python/format.c b/plugins/pe/python/format.c
index d295da4..4bbb99a 100644
--- a/plugins/pe/python/format.c
+++ b/plugins/pe/python/format.c
@@ -115,7 +115,7 @@ static PyObject *py_pe_format_new(PyTypeObject *type, PyObject *args, PyObject *
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -539,7 +539,10 @@ bool register_python_pe_format(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_PE_FORMAT, type, get_python_executable_format_type()))
+ if (!ensure_python_executable_format_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_PE_FORMAT, type))
return false;
if (!define_python_pe_format_constants(type))
diff --git a/plugins/pe/python/routine.c b/plugins/pe/python/routine.c
index cebeb2a..fd30e6d 100644
--- a/plugins/pe/python/routine.c
+++ b/plugins/pe/python/routine.c
@@ -221,7 +221,9 @@ bool register_python_pe_exported_routine(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_PE_EXPORTED_ROUTINE, type, get_python_binary_routine_type()))
+ /* TODO : ensure get_python_binary_routine_type() */
+
+ if (!register_class_for_pygobject(dict, G_TYPE_PE_EXPORTED_ROUTINE, type))
return false;
if (!define_python_pe_exported_routine_constants(type))
@@ -461,7 +463,9 @@ bool register_python_pe_imported_routine(PyObject *module)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_PE_IMPORTED_ROUTINE, type, get_python_pe_exported_routine_type()))
+ /* TODO : ensure get_python_pe_exported_routine_type() */
+
+ if (!register_class_for_pygobject(dict, G_TYPE_PE_IMPORTED_ROUTINE, type))
return false;
return true;
diff --git a/plugins/pe/symbols.h b/plugins/pe/symbols.h
index bb260cd..5c4b796 100644
--- a/plugins/pe/symbols.h
+++ b/plugins/pe/symbols.h
@@ -29,7 +29,7 @@
#include <glibext/delayed.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am
index 6391c80..4b6e551 100644
--- a/plugins/pychrysalide/Makefile.am
+++ b/plugins/pychrysalide/Makefile.am
@@ -13,26 +13,45 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/chrysalide-libs'
endif
-pychrysalide_la_SOURCES = \
- access.h access.c \
- core.h core.c \
- helpers.h helpers.c \
- star.h star.c \
- strenum.h strenum.c \
- struct.h struct.c \
- weak.h weak.c
-
-pychrysalide_la_LIBADD = \
- analysis/libpychrysaanalysis.la \
- arch/libpychrysaarch.la \
- common/libpychrysacommon.la \
- core/libpychrysacore.la \
- debug/libpychrysadebug.la \
- format/libpychrysaformat.la \
- glibext/libpychrysaglibext.la \
- gtkext/libpychrysagtkext.la \
- gui/libpychrysagui.la \
- mangling/libpychrysamangling.la \
+if BUILD_GTK_SUPPORT
+
+GTKEXT_LIBADD = \
+ gtkext/libpychrysagtkext.la
+
+GTKEXT_SUBDIR = \
+ gtkext
+
+GUI_LIBADD = \
+ gui/libpychrysagui.la
+
+GUI_SUBDIR = \
+ gui
+
+endif
+
+
+pychrysalide_la_SOURCES = \
+ access.h access.c \
+ core.h core.c \
+ helpers.h helpers.c \
+ star.h star.c \
+ strenum.h strenum.c \
+ struct.h struct.c
+
+AM_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+pychrysalide_la_LIBADD = \
+ analysis/libpychrysaanalysis.la \
+ arch/libpychrysaarch.la \
+ common/libpychrysacommon.la \
+ core/libpychrysacore.la \
+ debug/libpychrysadebug.la \
+ format/libpychrysaformat.la \
+ glibext/libpychrysaglibext.la \
+ $(GTKEXT_LIBADD) \
+ $(GUI_LIBADD) \
+ mangling/libpychrysamangling.la \
plugins/libpychrysaplugins.la
# -ldl: dladdr(), dlerror()
@@ -49,9 +68,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(pychrysalide_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS = analysis arch common core debug format glibext gtkext gui mangling plugins
+SUBDIRS = analysis arch common core debug format glibext $(GTKEXT_SUBDIR) $(GUI_SUBDIR) mangling plugins
diff --git a/plugins/pychrysalide/analysis/Makefile.am b/plugins/pychrysalide/analysis/Makefile.am
index 66a2524..43e8ed2 100644
--- a/plugins/pychrysalide/analysis/Makefile.am
+++ b/plugins/pychrysalide/analysis/Makefile.am
@@ -1,28 +1,30 @@
noinst_LTLIBRARIES = libpychrysaanalysis.la
-libpychrysaanalysis_la_SOURCES = \
- binary.h binary.c \
- block.h block.c \
- cattribs.h cattribs.c \
- constants.h constants.c \
- content.h content.c \
- loaded.h loaded.c \
- loading.h loading.c \
- module.h module.c \
- project.h project.c \
- routine.h routine.c \
- type.h type.c \
+libpychrysaanalysis_la_SOURCES = \
+ binary.h binary.c \
+ block.h block.c \
+ cattribs.h cattribs.c \
+ constants.h constants.c \
+ content.h content.c \
+ loaded.h loaded.c \
+ loading.h loading.c \
+ module.h module.c \
+ project.h project.c \
+ routine.h routine.c \
+ type.h type.c \
variable.h variable.c
libpychrysaanalysis_la_LIBADD = \
contents/libpychrysaanalysiscontents.la \
db/libpychrysaanalysisdb.la \
disass/libpychrysaanalysisdisass.la \
+ scan/libpychrysaanalysisscan.la \
storage/libpychrysaanalysisstorage.la \
types/libpychrysaanalysistypes.la
-libpychrysaanalysis_la_LDFLAGS =
+libpychrysaanalysis_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
@@ -30,9 +32,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaanalysis_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS = contents db disass storage types
+SUBDIRS = contents db disass scan storage types
diff --git a/plugins/pychrysalide/analysis/binary.c b/plugins/pychrysalide/analysis/binary.c
index d8f01e5..6599ecc 100644
--- a/plugins/pychrysalide/analysis/binary.c
+++ b/plugins/pychrysalide/analysis/binary.c
@@ -562,7 +562,7 @@ bool ensure_python_loaded_binary_is_registered(void)
if (!ensure_python_loaded_content_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_LOADED_BINARY, type, get_python_loaded_content_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_LOADED_BINARY, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/block.c b/plugins/pychrysalide/analysis/block.c
index 0b09eb7..7f74c2f 100644
--- a/plugins/pychrysalide/analysis/block.c
+++ b/plugins/pychrysalide/analysis/block.c
@@ -353,7 +353,7 @@ bool ensure_python_code_block_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_CODE_BLOCK, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_CODE_BLOCK, type))
return false;
}
@@ -612,7 +612,7 @@ bool ensure_python_block_list_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BLOCK_LIST, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BLOCK_LIST, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/cattribs.c b/plugins/pychrysalide/analysis/cattribs.c
index 895fed8..84a5e1d 100644
--- a/plugins/pychrysalide/analysis/cattribs.c
+++ b/plugins/pychrysalide/analysis/cattribs.c
@@ -294,7 +294,7 @@ bool ensure_python_content_attributes_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_ATTRIBUTES, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_ATTRIBUTES, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/content.c b/plugins/pychrysalide/analysis/content.c
index f94e3f7..c30cdd8 100644
--- a/plugins/pychrysalide/analysis/content.c
+++ b/plugins/pychrysalide/analysis/content.c
@@ -40,6 +40,7 @@
#include "cattribs.h"
#include "constants.h"
+#include "storage/serialize.h"
#include "../access.h"
#include "../helpers.h"
#include "../arch/vmpa.h"
@@ -49,8 +50,13 @@
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Procède à l'initialisation de l'interface de génération. */
-static void py_binary_content_interface_init(GBinContentIface *, gpointer *);
+/* Initialise la classe générique des contenus de binaire. */
+static void py_binary_content_init_gclass(GBinContentClass *, gpointer);
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(binary_content, G_TYPE_BIN_CONTENT, py_binary_content_init_gclass);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_binary_content_init(PyObject *, PyObject *, PyObject *);
/* Fournit le nom associé au contenu binaire. */
static char *py_binary_content_describe_wrapper(const GBinContent *, bool);
@@ -126,10 +132,10 @@ static PyObject *py_binary_content_get_data(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
-* unused = adresse non utilisée ici. *
+* Paramètres : class = classe à initialiser. *
+* unused = données non utilisées ici. *
* *
-* Description : Procède à l'initialisation de l'interface de génération. *
+* Description : Initialise la classe générique des contenus de binaire. *
* *
* Retour : - *
* *
@@ -137,21 +143,45 @@ static PyObject *py_binary_content_get_data(PyObject *, void *);
* *
******************************************************************************/
-static void py_binary_content_interface_init(GBinContentIface *iface, gpointer *unused)
+static void py_binary_content_init_gclass(GBinContentClass *class, gpointer unused)
{
+ class->describe = py_binary_content_describe_wrapper;
+
+ class->read_raw = py_binary_content_read_raw_wrapper;
+ class->read_u8 = py_binary_content_read_u8_wrapper;
+ class->read_u16 = py_binary_content_read_u16_wrapper;
+ class->read_u32 = py_binary_content_read_u32_wrapper;
+ class->read_u64 = py_binary_content_read_u64_wrapper;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_binary_content_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
#define BINARY_CONTENT_DOC \
- "The BinContent is an interface which handles access to a given binary" \
- " content.\n" \
+ "A BinContent is an abstract object which handles access to a given" \
+ " binary content.\n" \
"\n" \
"All of its implementations are located in the" \
" pychrysalide.analysis.contents module. The main implemantation is" \
" the pychrysalide.analysis.contents.FileContent class.\n" \
"\n" \
- "A typical class declaration for a new implementation looks like:\n" \
- "\n" \
- " class NewImplem(GObject.Object, BinContent):\n" \
- " ...\n" \
- "\n" \
"The following methods have to be defined for new implementations:\n" \
"* pychrysalide.analysis.BinContent._describe();\n" \
"* pychrysalide.analysis.BinContent._read_raw();\n" \
@@ -161,13 +191,12 @@ static void py_binary_content_interface_init(GBinContentIface *iface, gpointer *
"* pychrysalide.analysis.BinContent._read_u32();\n" \
"* pychrysalide.analysis.BinContent._read_u64();\n"
- iface->describe = py_binary_content_describe_wrapper;
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- iface->read_raw = py_binary_content_read_raw_wrapper;
- iface->read_u8 = py_binary_content_read_u8_wrapper;
- iface->read_u16 = py_binary_content_read_u16_wrapper;
- iface->read_u32 = py_binary_content_read_u32_wrapper;
- iface->read_u64 = py_binary_content_read_u64_wrapper;
+ return 0;
}
@@ -1406,14 +1435,17 @@ PyTypeObject *get_python_binary_content_type(void)
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "pychrysalide.analysis.BinContent",
- .tp_basicsize = sizeof(PyObject),
+ .tp_basicsize = sizeof(PyGObject),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_doc = BINARY_CONTENT_DOC,
.tp_methods = py_binary_content_methods,
- .tp_getset = py_binary_content_getseters
+ .tp_getset = py_binary_content_getseters,
+
+ .tp_init = py_binary_content_init,
+ .tp_new = py_binary_content_new,
};
@@ -1440,23 +1472,18 @@ bool ensure_python_binary_content_is_registered(void)
PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
- static GInterfaceInfo info = { /* Paramètres d'inscription */
-
- .interface_init = (GInterfaceInitFunc)py_binary_content_interface_init,
- .interface_finalize = NULL,
- .interface_data = NULL,
-
- };
-
type = get_python_binary_content_type();
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
+ if (!ensure_python_serializable_object_is_registered())
+ return false;
+
module = get_access_to_python_module("pychrysalide.analysis");
dict = PyModule_GetDict(module);
- if (!register_interface_for_pygobject(dict, G_TYPE_BIN_CONTENT, type, &info))
+ if (!register_class_for_pygobject(dict, G_TYPE_BIN_CONTENT, type))
return false;
if (!define_analysis_content_constants(type))
diff --git a/plugins/pychrysalide/analysis/contents/Makefile.am b/plugins/pychrysalide/analysis/contents/Makefile.am
index 5014d47..9238a58 100644
--- a/plugins/pychrysalide/analysis/contents/Makefile.am
+++ b/plugins/pychrysalide/analysis/contents/Makefile.am
@@ -1,22 +1,17 @@
noinst_LTLIBRARIES = libpychrysaanalysiscontents.la
-libpychrysaanalysiscontents_la_SOURCES = \
- encapsulated.h encapsulated.c \
- file.h file.c \
- memory.h memory.c \
- module.h module.c \
+libpychrysaanalysiscontents_la_SOURCES = \
+ encapsulated.h encapsulated.c \
+ file.h file.c \
+ memory.h memory.c \
+ module.h module.c \
restricted.h restricted.c
-libpychrysaanalysiscontents_la_LDFLAGS =
+libpychrysaanalysiscontents_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaanalysiscontents_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/analysis/contents/encapsulated.c b/plugins/pychrysalide/analysis/contents/encapsulated.c
index 0e09f81..e9583e6 100644
--- a/plugins/pychrysalide/analysis/contents/encapsulated.c
+++ b/plugins/pychrysalide/analysis/contents/encapsulated.c
@@ -28,18 +28,20 @@
#include <pygobject.h>
-#include <analysis/contents/encapsulated.h>
+#include <i18n.h>
+#include <analysis/contents/encapsulated-int.h>
#include "../content.h"
-#include "../storage/serialize.h"
#include "../../access.h"
#include "../../helpers.h"
-/* Crée un nouvel objet Python de type 'BinContent'. */
-static PyObject *py_encaps_content_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(encaps_content, G_TYPE_ENCAPS_CONTENT);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_encaps_content_init(PyObject *, PyObject *, PyObject *);
/* Indique la base d'un contenu binaire encapsulé. */
static PyObject *py_encaps_content_get_base(PyObject *, void *);
@@ -54,26 +56,25 @@ static PyObject *py_encaps_content_get_endpoint(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'BinContent'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_encaps_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_encaps_content_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
GBinContent *base; /* Base de l'extraction */
const char *path; /* Chemin vers le contenu final*/
GBinContent *endpoint; /* Contenu accessible au final */
int ret; /* Bilan de lecture des args. */
- GBinContent *content; /* Version GLib du contenu */
+ GEncapsContent *content; /* Version GLib du contenu */
#define ENCAPS_CONTENT_DOC \
"EncapsulatedContent gathers items relative to a binary encapsulated" \
@@ -94,20 +95,30 @@ static PyObject *py_encaps_content_new(PyTypeObject *type, PyObject *args, PyObj
" pychrysalide.analysis.BinContent instances and the access path must" \
" be provided as a string."
+ /* Récupération des paramètres */
+
ret = PyArg_ParseTuple(args, "O&sO&",
convert_to_binary_content, &base,
&path,
convert_to_binary_content, &endpoint);
- if (!ret) return NULL;
+ if (!ret) return -1;
- content = g_encaps_content_new(base, path, endpoint);
+ /* Initialisation d'un objet GLib */
- result = pygobject_new(G_OBJECT(content));
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- if (content != NULL)
- g_object_unref(content);
+ /* Eléments de base */
- return result;
+ content = G_ENCAPS_CONTENT(pygobject_get(self));
+
+ if (!g_encaps_content_create(content, base, path, endpoint))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create encapsulated content."));
+ return -1;
+ }
+
+ return 0;
}
@@ -276,7 +287,9 @@ PyTypeObject *get_python_encaps_content_type(void)
.tp_methods = py_encaps_content_methods,
.tp_getset = py_encaps_content_getseters,
- .tp_new = py_encaps_content_new
+
+ .tp_init = py_encaps_content_init,
+ .tp_new = py_encaps_content_new,
};
@@ -311,13 +324,10 @@ bool ensure_python_encaps_content_is_registered(void)
dict = PyModule_GetDict(module);
- if (!ensure_python_serializable_object_is_registered())
- return false;
-
if (!ensure_python_binary_content_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_ENCAPS_CONTENT, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_ENCAPS_CONTENT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/contents/file.c b/plugins/pychrysalide/analysis/contents/file.c
index 4786cdb..5bef069 100644
--- a/plugins/pychrysalide/analysis/contents/file.c
+++ b/plugins/pychrysalide/analysis/contents/file.c
@@ -28,18 +28,20 @@
#include <pygobject.h>
-#include <analysis/contents/file.h>
+#include <i18n.h>
+#include <analysis/contents/file-int.h>
#include "memory.h"
-#include "../storage/serialize.h"
#include "../../access.h"
#include "../../helpers.h"
-/* Crée un nouvel objet Python de type 'BinContent'. */
-static PyObject *py_file_content_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(file_content, G_TYPE_FILE_CONTENT);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_file_content_init(PyObject *, PyObject *, PyObject *);
/* Fournit le nom de fichier associé au contenu binaire. */
static PyObject *py_file_content_get_filename(PyObject *, void *);
@@ -48,24 +50,23 @@ static PyObject *py_file_content_get_filename(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'BinContent'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_file_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_file_content_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
const char *filename; /* Nom du fichier à charger */
int ret; /* Bilan de lecture des args. */
- GBinContent *content; /* Version GLib du contenu */
+ GFileContent *content; /* Version GLib du contenu */
#define FILE_CONTENT_DOC \
"FileContent handles binary content loaded from a file.\n" \
@@ -76,17 +77,27 @@ static PyObject *py_file_content_new(PyTypeObject *type, PyObject *args, PyObjec
"\n" \
"Where filename is a path to an existing file."
+ /* Récupération des paramètres */
+
ret = PyArg_ParseTuple(args, "s", &filename);
- if (!ret) return NULL;
+ if (!ret) return -1;
- content = g_file_content_new(filename);
+ /* Initialisation d'un objet GLib */
- result = pygobject_new(G_OBJECT(content));
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- if (content != NULL)
- g_object_unref(content);
+ /* Eléments de base */
- return result;
+ content = G_FILE_CONTENT(pygobject_get(self));
+
+ if (!g_file_content_create(content, filename))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create file content."));
+ return -1;
+ }
+
+ return 0;
}
@@ -163,7 +174,9 @@ PyTypeObject *get_python_file_content_type(void)
.tp_methods = py_file_content_methods,
.tp_getset = py_file_content_getseters,
- .tp_new = py_file_content_new
+
+ .tp_init = py_file_content_init,
+ .tp_new = py_file_content_new,
};
@@ -201,10 +214,7 @@ bool ensure_python_file_content_is_registered(void)
if (!ensure_python_memory_content_is_registered())
return false;
- if (!ensure_python_serializable_object_is_registered())
- return false;
-
- if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type, get_python_memory_content_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/contents/memory.c b/plugins/pychrysalide/analysis/contents/memory.c
index 4782445..7464779 100644
--- a/plugins/pychrysalide/analysis/contents/memory.c
+++ b/plugins/pychrysalide/analysis/contents/memory.c
@@ -28,42 +28,43 @@
#include <pygobject.h>
-#include <analysis/contents/memory.h>
+#include <i18n.h>
+#include <analysis/contents/memory-int.h>
#include "../content.h"
-#include "../storage/serialize.h"
#include "../../access.h"
#include "../../helpers.h"
-/* Crée un nouvel objet Python de type 'BinContent'. */
-static PyObject *py_memory_content_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(memory_content, G_TYPE_MEMORY_CONTENT);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_memory_content_init(PyObject *, PyObject *, PyObject *);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'BinContent'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_memory_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_memory_content_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
const char *data; /* Tampon interne de Python */
- int length; /* Taille utilisé de ce tampon */
+ Py_ssize_t length; /* Taille utilisé de ce tampon */
int ret; /* Bilan de lecture des args. */
- GBinContent *content; /* Version GLib du contenu */
+ GMemoryContent *content; /* Version GLib du contenu */
#define MEMORY_CONTENT_DOC \
"MemoryContent builds a binary content from memory data only." \
@@ -76,22 +77,32 @@ static PyObject *py_memory_content_new(PyTypeObject *type, PyObject *args, PyObj
"Where data is provided as string or read-only bytes-like object." \
" The string may contain embedded null bytes."
+ /* Récupération des paramètres */
+
/**
* La taille doit être de type 'int' et non 'Py_ssize_t', sinon les 32 bits
* de poids fort ne sont pas initialisés !
*/
ret = PyArg_ParseTuple(args, "s#", &data, &length);
- if (!ret) return NULL;
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
- content = g_memory_content_new((const bin_t *)data, length);
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- result = pygobject_new(G_OBJECT(content));
+ /* Eléments de base */
- if (content != NULL)
- g_object_unref(content);
+ content = G_MEMORY_CONTENT(pygobject_get(self));
- return result;
+ if (!g_memory_content_create(content, (const bin_t *)data, length))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create memory content."));
+ return -1;
+ }
+
+ return 0;
}
@@ -131,7 +142,9 @@ PyTypeObject *get_python_memory_content_type(void)
.tp_methods = py_memory_content_methods,
.tp_getset = py_memory_content_getseters,
- .tp_new = py_memory_content_new
+
+ .tp_init = py_memory_content_init,
+ .tp_new = py_memory_content_new,
};
@@ -166,13 +179,10 @@ bool ensure_python_memory_content_is_registered(void)
dict = PyModule_GetDict(module);
- if (!ensure_python_serializable_object_is_registered())
- return false;
-
if (!ensure_python_binary_content_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_MEMORY_CONTENT, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_MEMORY_CONTENT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/contents/restricted.c b/plugins/pychrysalide/analysis/contents/restricted.c
index 47df8c5..4521578 100644
--- a/plugins/pychrysalide/analysis/contents/restricted.c
+++ b/plugins/pychrysalide/analysis/contents/restricted.c
@@ -31,19 +31,21 @@
#include <i18n.h>
-#include <analysis/contents/restricted.h>
+#include <i18n.h>
+#include <analysis/contents/restricted-int.h>
#include "../content.h"
-#include "../storage/serialize.h"
#include "../../access.h"
#include "../../helpers.h"
#include "../../arch/vmpa.h"
-/* Crée un nouvel objet Python de type 'BinContent'. */
-static PyObject *py_restricted_content_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(restricted_content, G_TYPE_RESTRICTED_CONTENT);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_restricted_content_init(PyObject *, PyObject *, PyObject *);
/* Indique l'espace de restriction appliqué à un contenu. */
static PyObject *py_restricted_content_get_range(PyObject *, void *);
@@ -52,25 +54,24 @@ static PyObject *py_restricted_content_get_range(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'BinContent'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_restricted_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_restricted_content_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
- GBinContent *content; /* Instance GLib correspondante*/
+ GBinContent *internal; /* Instance GLib correspondante*/
mrange_t range; /* Restriction à appliquer */
int ret; /* Bilan de lecture des args. */
- GBinContent *restricted; /* Création GLib à transmettre */
+ GRestrictedContent *content; /* Version GLib du contenu */
#define RESTRICTED_CONTENT_DOC \
"RestrictedContent restricts access to a given area for a binary content." \
@@ -82,14 +83,27 @@ static PyObject *py_restricted_content_new(PyTypeObject *type, PyObject *args, P
"Where content is a pychrysalide.analysis.BinContent instance and range" \
" a Python object which can be converted into pychrysalide.arch.mrange."
- ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &content, convert_any_to_mrange, &range);
- if (!ret) return NULL;
+ /* Récupération des paramètres */
- restricted = g_restricted_content_new(content, &range);
+ ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &internal, convert_any_to_mrange, &range);
+ if (!ret) return -1;
- result = pygobject_new(G_OBJECT(restricted));
+ /* Initialisation d'un objet GLib */
- return result;
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ content = G_RESTRICTED_CONTENT(pygobject_get(self));
+
+ if (!g_restricted_content_create(content, internal, &range))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create restricted content."));
+ return -1;
+ }
+
+ return 0;
}
@@ -166,7 +180,9 @@ PyTypeObject *get_python_restricted_content_type(void)
.tp_methods = py_restricted_content_methods,
.tp_getset = py_restricted_content_getseters,
- .tp_new = py_restricted_content_new
+
+ .tp_init = py_restricted_content_init,
+ .tp_new = py_restricted_content_new,
};
@@ -201,13 +217,10 @@ bool ensure_python_restricted_content_is_registered(void)
dict = PyModule_GetDict(module);
- if (!ensure_python_serializable_object_is_registered())
- return false;
-
if (!ensure_python_binary_content_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_RESTRICTED_CONTENT, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_RESTRICTED_CONTENT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/db/Makefile.am b/plugins/pychrysalide/analysis/db/Makefile.am
index 94d4c43..a0dcc0d 100644
--- a/plugins/pychrysalide/analysis/db/Makefile.am
+++ b/plugins/pychrysalide/analysis/db/Makefile.am
@@ -1,21 +1,22 @@
noinst_LTLIBRARIES = libpychrysaanalysisdb.la
-libpychrysaanalysisdb_la_SOURCES = \
- admin.h admin.c \
- analyst.h analyst.c \
- certs.h certs.c \
- client.h client.c \
- collection.h collection.c \
- constants.h constants.c \
- item.h item.c \
- module.h module.c \
+libpychrysaanalysisdb_la_SOURCES = \
+ admin.h admin.c \
+ analyst.h analyst.c \
+ certs.h certs.c \
+ client.h client.c \
+ collection.h collection.c \
+ constants.h constants.c \
+ item.h item.c \
+ module.h module.c \
server.h server.c
-libpychrysaanalysisdb_la_LIBADD = \
+libpychrysaanalysisdb_la_LIBADD = \
items/libpychrysaanalysisdbitems.la
-libpychrysaanalysisdb_la_LDFLAGS =
+libpychrysaanalysisdb_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
@@ -23,9 +24,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaanalysisdb_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = items
diff --git a/plugins/pychrysalide/analysis/db/admin.c b/plugins/pychrysalide/analysis/db/admin.c
index a4694e6..10a150e 100644
--- a/plugins/pychrysalide/analysis/db/admin.c
+++ b/plugins/pychrysalide/analysis/db/admin.c
@@ -237,7 +237,7 @@ PyTypeObject *get_python_admin_client_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide....db.AdminClient'. *
+* Description : Prend en charge l'objet 'pychrysalide....db.AdminClient'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -255,14 +255,14 @@ bool ensure_python_admin_client_is_registered(void)
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
- if (!ensure_python_hub_client_is_registered())
- return false;
-
module = get_access_to_python_module("pychrysalide.analysis.db");
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ADMIN_CLIENT, type, get_python_hub_client_type()))
+ if (!ensure_python_hub_client_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ADMIN_CLIENT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/db/analyst.c b/plugins/pychrysalide/analysis/db/analyst.c
index 3cb77d1..f2860ed 100644
--- a/plugins/pychrysalide/analysis/db/analyst.c
+++ b/plugins/pychrysalide/analysis/db/analyst.c
@@ -900,14 +900,14 @@ bool ensure_python_analyst_client_is_registered(void)
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
- if (!ensure_python_hub_client_is_registered())
- return false;
-
module = get_access_to_python_module("pychrysalide.analysis.db");
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ANALYST_CLIENT, type, get_python_hub_client_type()))
+ if (!ensure_python_hub_client_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ANALYST_CLIENT, type))
return false;
if (!define_loading_status_hint_constants(type))
diff --git a/plugins/pychrysalide/analysis/db/client.c b/plugins/pychrysalide/analysis/db/client.c
index 0cd9704..7ef658e 100644
--- a/plugins/pychrysalide/analysis/db/client.c
+++ b/plugins/pychrysalide/analysis/db/client.c
@@ -235,7 +235,7 @@ bool ensure_python_hub_client_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_HUB_CLIENT, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_HUB_CLIENT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/db/collection.c b/plugins/pychrysalide/analysis/db/collection.c
index ca4151c..5970d15 100644
--- a/plugins/pychrysalide/analysis/db/collection.c
+++ b/plugins/pychrysalide/analysis/db/collection.c
@@ -165,7 +165,7 @@ bool ensure_python_db_collection_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DB_COLLECTION, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_DB_COLLECTION, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/db/item.c b/plugins/pychrysalide/analysis/db/item.c
index 836f902..cc9bdf4 100644
--- a/plugins/pychrysalide/analysis/db/item.c
+++ b/plugins/pychrysalide/analysis/db/item.c
@@ -369,7 +369,7 @@ bool ensure_python_db_item_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DB_ITEM, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_DB_ITEM, type))
return false;
if (!define_db_protocol_constants(type))
diff --git a/plugins/pychrysalide/analysis/db/items/Makefile.am b/plugins/pychrysalide/analysis/db/items/Makefile.am
index 2bac8ba..201aed7 100644
--- a/plugins/pychrysalide/analysis/db/items/Makefile.am
+++ b/plugins/pychrysalide/analysis/db/items/Makefile.am
@@ -1,22 +1,17 @@
noinst_LTLIBRARIES = libpychrysaanalysisdbitems.la
-libpychrysaanalysisdbitems_la_SOURCES = \
- bookmark.h bookmark.c \
- comment.h comment.c \
- constants.h constants.c \
- module.h module.c \
+libpychrysaanalysisdbitems_la_SOURCES = \
+ bookmark.h bookmark.c \
+ comment.h comment.c \
+ constants.h constants.c \
+ module.h module.c \
switcher.h switcher.c
-libpychrysaanalysisdbitems_la_LDFLAGS =
+libpychrysaanalysisdbitems_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaanalysisdbitems_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/analysis/db/items/bookmark.c b/plugins/pychrysalide/analysis/db/items/bookmark.c
index af649e3..d2bc0f0 100644
--- a/plugins/pychrysalide/analysis/db/items/bookmark.c
+++ b/plugins/pychrysalide/analysis/db/items/bookmark.c
@@ -108,7 +108,7 @@ static PyObject *py_db_bookmark_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -366,7 +366,7 @@ bool ensure_python_db_bookmark_is_registered(void)
if (!ensure_python_db_item_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_DB_BOOKMARK, type, get_python_db_item_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_DB_BOOKMARK, type))
return false;
}
@@ -473,7 +473,7 @@ static PyObject *py_bookmark_collection_new(PyTypeObject *type, PyObject *args,
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -570,7 +570,7 @@ bool ensure_python_bookmark_collection_is_registered(void)
if (!ensure_python_db_collection_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_BM_COLLECTION, type, get_python_db_collection_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_BM_COLLECTION, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/db/items/comment.c b/plugins/pychrysalide/analysis/db/items/comment.c
index 78d4902..1358f1d 100644
--- a/plugins/pychrysalide/analysis/db/items/comment.c
+++ b/plugins/pychrysalide/analysis/db/items/comment.c
@@ -117,7 +117,7 @@ static PyObject *py_db_comment_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -464,7 +464,7 @@ bool ensure_python_db_comment_is_registered(void)
if (!ensure_python_db_item_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_DB_COMMENT, type, get_python_db_item_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_DB_COMMENT, type))
return false;
if (!define_db_comment_constants(type))
@@ -574,7 +574,7 @@ static PyObject *py_comment_collection_new(PyTypeObject *type, PyObject *args, P
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -671,7 +671,7 @@ bool ensure_python_comment_collection_is_registered(void)
if (!ensure_python_db_collection_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_COMMENT_COLLECTION, type, get_python_db_collection_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_COMMENT_COLLECTION, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/db/items/switcher.c b/plugins/pychrysalide/analysis/db/items/switcher.c
index 6ac5cdf..5766fe1 100644
--- a/plugins/pychrysalide/analysis/db/items/switcher.c
+++ b/plugins/pychrysalide/analysis/db/items/switcher.c
@@ -114,7 +114,7 @@ static PyObject *py_db_switcher_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -398,7 +398,7 @@ bool ensure_python_db_switcher_is_registered(void)
if (!ensure_python_db_item_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_DB_SWITCHER, type, get_python_db_item_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_DB_SWITCHER, type))
return false;
}
@@ -506,7 +506,7 @@ static PyObject *py_switcher_collection_new(PyTypeObject *type, PyObject *args,
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -603,7 +603,7 @@ bool ensure_python_switcher_collection_is_registered(void)
if (!ensure_python_db_collection_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_SWITCHER_COLLECTION, type, get_python_db_collection_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_SWITCHER_COLLECTION, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/db/server.c b/plugins/pychrysalide/analysis/db/server.c
index 9e4ee61..dae7b29 100644
--- a/plugins/pychrysalide/analysis/db/server.c
+++ b/plugins/pychrysalide/analysis/db/server.c
@@ -274,7 +274,7 @@ bool ensure_python_hub_server_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_HUB_SERVER, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_HUB_SERVER, type))
return false;
if (!define_hub_server_constants(type))
diff --git a/plugins/pychrysalide/analysis/disass/Makefile.am b/plugins/pychrysalide/analysis/disass/Makefile.am
index 1aa34ea..0daa930 100644
--- a/plugins/pychrysalide/analysis/disass/Makefile.am
+++ b/plugins/pychrysalide/analysis/disass/Makefile.am
@@ -1,21 +1,14 @@
noinst_LTLIBRARIES = libpychrysaanalysisdisass.la
-libpychrysaanalysisdisass_la_SOURCES = \
- block.h block.c \
+libpychrysaanalysisdisass_la_SOURCES = \
+ block.h block.c \
module.h module.c
-libpychrysaanalysisdisass_la_LDFLAGS =
+libpychrysaanalysisdisass_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaanalysisdisass_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/analysis/disass/block.c b/plugins/pychrysalide/analysis/disass/block.c
index 38e65a1..d82e3e2 100644
--- a/plugins/pychrysalide/analysis/disass/block.c
+++ b/plugins/pychrysalide/analysis/disass/block.c
@@ -159,7 +159,10 @@ bool ensure_python_basic_block_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BASIC_BLOCK, type, get_python_code_block_type()))
+ if (!ensure_python_code_block_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_BASIC_BLOCK, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/loaded.c b/plugins/pychrysalide/analysis/loaded.c
index c8674a5..a2bf13f 100644
--- a/plugins/pychrysalide/analysis/loaded.c
+++ b/plugins/pychrysalide/analysis/loaded.c
@@ -66,6 +66,8 @@ static bool py_loaded_content_analyze_wrapper(GLoadedContent *, bool, bool, wgro
/* Fournit le désignation associée à l'élément chargé. */
static char *py_loaded_content_describe_wrapper(const GLoadedContent *, bool);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Détermine le nombre de vues disponibles pour un contenu. */
static unsigned int py_loaded_content_count_views_wrapper(const GLoadedContent *);
@@ -81,6 +83,8 @@ static GtkWidget *py_loaded_content_build_view_wrapper(GLoadedContent *, unsigne
/* Retrouve l'indice correspondant à la vue donnée d'un contenu. */
static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *, GtkWidget *);
+#endif
+
/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
@@ -98,6 +102,8 @@ static PyObject *py_loaded_content_describe(PyObject *, PyObject *);
/* Etablit une liste d'obscurcissements présents. */
static PyObject *py_loaded_content_detect_obfuscators(PyObject *, PyObject *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Détermine le nombre de vues disponibles pour un contenu. */
static PyObject *py_loaded_content_count_views(PyObject *, PyObject *);
@@ -110,6 +116,8 @@ static PyObject *py_loaded_content_build_default_view(PyObject *, PyObject *);
/* Met en place la vue initiale pour un contenu chargé. */
static PyObject *py_loaded_content_build_view(PyObject *, PyObject *);
+#endif
+
/* Fournit le contenu représenté de l'élément chargé. */
static PyObject *py_loaded_content_get_content(PyObject *, void *);
@@ -191,7 +199,7 @@ static PyObject *py_loaded_content_new(PyTypeObject *type, PyObject *args, PyObj
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -234,11 +242,13 @@ static void py_loaded_content_init_gclass(GLoadedContentClass *class, gpointer u
class->describe = py_loaded_content_describe_wrapper;
+#ifdef INCLUDE_GTK_SUPPORT
class->count_views = py_loaded_content_count_views_wrapper;
class->get_view_name = py_loaded_content_get_view_name_wrapper;
class->build_def_view = py_loaded_content_build_default_view_wrapper;
class->build_view = py_loaded_content_build_view_wrapper;
class->get_view_index = py_loaded_content_get_view_index_wrapper;
+#endif
}
@@ -538,6 +548,9 @@ static char *py_loaded_content_describe_wrapper(const GLoadedContent *content, b
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : content = contenu chargé à consulter. *
@@ -874,6 +887,9 @@ static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *con
}
+#endif
+
+
/* ---------------------------------------------------------------------------------- */
/* CONNEXION AVEC L'API DE PYTHON */
@@ -1107,6 +1123,9 @@ static PyObject *py_loaded_content_detect_obfuscators(PyObject *self, PyObject *
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : self = contenu chargé à manipuler. *
@@ -1348,6 +1367,9 @@ static PyObject *py_loaded_content_get_view_index(PyObject *self, PyObject *args
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : self = objet Python concerné par l'appel. *
@@ -1487,20 +1509,24 @@ PyTypeObject *get_python_loaded_content_type(void)
LOADED_CONTENT_GET_CONTENT_CLASS_WRAPPER,
LOADED_CONTENT_ANALYZE_WRAPPER,
LOADED_CONTENT_DESCRIBE_WRAPPER,
+#ifdef INCLUDE_GTK_SUPPORT
LOADED_CONTENT_COUNT_VIEWS_WRAPPER,
LOADED_CONTENT_GET_VIEW_NAME_WRAPPER,
LOADED_CONTENT_BUILD_DEFAULT_VIEW_WRAPPER,
LOADED_CONTENT_BUILD_VIEW_WRAPPER,
LOADED_CONTENT_GET_VIEW_INDEX_WRAPPER,
+#endif
LOADED_CONTENT_ANALYZE_METHOD,
LOADED_CONTENT_ANALYZE_AND_WAIT_METHOD,
LOADED_CONTENT_DESCRIBE_METHOD,
LOADED_CONTENT_DETECT_OBFUSCATORS_METHOD,
+#ifdef INCLUDE_GTK_SUPPORT
LOADED_CONTENT_COUNT_VIEWS_METHOD,
LOADED_CONTENT_GET_VIEW_NAME_METHOD,
LOADED_CONTENT_BUILD_DEFAULT_VIEW_METHOD,
LOADED_CONTENT_BUILD_VIEW_METHOD,
LOADED_CONTENT_GET_VIEW_INDEX_METHOD,
+#endif
{ NULL }
};
@@ -1560,10 +1586,12 @@ bool ensure_python_loaded_content_is_registered(void)
dict = PyModule_GetDict(module);
+#ifdef INCLUDE_GTK_SUPPORT
if (!ensure_python_named_widget_is_registered())
return false;
+#endif
- if (!register_class_for_pygobject(dict, G_TYPE_LOADED_CONTENT, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_LOADED_CONTENT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/loading.c b/plugins/pychrysalide/analysis/loading.c
index dea4e31..8a60d8a 100644
--- a/plugins/pychrysalide/analysis/loading.c
+++ b/plugins/pychrysalide/analysis/loading.c
@@ -168,7 +168,7 @@ bool ensure_python_content_explorer_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_EXPLORER, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_EXPLORER, type))
return false;
}
@@ -294,7 +294,7 @@ bool ensure_python_content_resolver_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_RESOLVER, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_RESOLVER, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/module.c b/plugins/pychrysalide/analysis/module.c
index 9632956..6b8e441 100644
--- a/plugins/pychrysalide/analysis/module.c
+++ b/plugins/pychrysalide/analysis/module.c
@@ -41,6 +41,7 @@
#include "contents/module.h"
#include "db/module.h"
#include "disass/module.h"
+#include "scan/module.h"
#include "storage/module.h"
#include "types/module.h"
#include "../helpers.h"
@@ -86,6 +87,7 @@ bool add_analysis_module(PyObject *super)
if (result) result = add_analysis_contents_module(module);
if (result) result = add_analysis_db_module(module);
if (result) result = add_analysis_disass_module(module);
+ if (result) result = add_analysis_scan_module(module);
if (result) result = add_analysis_storage_module(module);
if (result) result = add_analysis_types_module(module);
@@ -131,6 +133,7 @@ bool populate_analysis_module(void)
if (result) result = populate_analysis_contents_module();
if (result) result = populate_analysis_db_module();
if (result) result = populate_analysis_disass_module();
+ if (result) result = populate_analysis_scan_module();
if (result) result = populate_analysis_storage_module();
if (result) result = populate_analysis_types_module();
diff --git a/plugins/pychrysalide/analysis/project.c b/plugins/pychrysalide/analysis/project.c
index e66119c..b00259a 100644
--- a/plugins/pychrysalide/analysis/project.c
+++ b/plugins/pychrysalide/analysis/project.c
@@ -402,7 +402,7 @@ bool ensure_python_study_project_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_STUDY_PROJECT, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_STUDY_PROJECT, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/routine.c b/plugins/pychrysalide/analysis/routine.c
index e33ca90..535ba84 100644
--- a/plugins/pychrysalide/analysis/routine.c
+++ b/plugins/pychrysalide/analysis/routine.c
@@ -757,7 +757,7 @@ bool ensure_python_binary_routine_is_registered(void)
if (!ensure_python_binary_symbol_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_BIN_ROUTINE, type, get_python_binary_symbol_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_BIN_ROUTINE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/scan/Makefile.am b/plugins/pychrysalide/analysis/scan/Makefile.am
new file mode 100644
index 0000000..8c9fb77
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/Makefile.am
@@ -0,0 +1,28 @@
+
+noinst_LTLIBRARIES = libpychrysaanalysisscan.la
+
+libpychrysaanalysisscan_la_SOURCES = \
+ constants.h constants.c \
+ context.h context.c \
+ core.h core.c \
+ expr.h expr.c \
+ item.h item.c \
+ module.h module.c \
+ options.h options.c \
+ scanner.h scanner.c \
+ space.h space.c
+
+libpychrysaanalysisscan_la_LIBADD = \
+ exprs/libpychrysaanalysisscanexprs.la \
+ patterns/libpychrysaanalysisscanpatterns.la
+
+libpychrysaanalysisscan_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libpychrysaanalysisscan_la_SOURCES:%c=)
+
+
+SUBDIRS = exprs patterns
diff --git a/plugins/pychrysalide/analysis/scan/constants.c b/plugins/pychrysalide/analysis/scan/constants.c
new file mode 100644
index 0000000..d030df2
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/constants.c
@@ -0,0 +1,128 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.c - ajout des constantes de base pour les types
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "constants.h"
+
+
+#include <analysis/scan/expr.h>
+
+
+#include "../../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type dont le dictionnaire est à compléter. *
+* *
+* Description : Définit les constantes relatives aux expressions de scan. *
+* *
+* Retour : true en cas de succès de l'opération, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_expression_value_type_constants(PyTypeObject *type)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *values; /* Groupe de valeurs à établir */
+
+ values = PyDict_New();
+
+ result = add_const_to_group(values, "PENDING", SRS_PENDING);
+ if (result) result = add_const_to_group(values, "REDUCED", SRS_REDUCED);
+ if (result) result = add_const_to_group(values, "WAIT_FOR_SCAN", SRS_WAIT_FOR_SCAN);
+ if (result) result = add_const_to_group(values, "UNRESOLVABLE", SRS_UNRESOLVABLE);
+
+ if (!result)
+ {
+ Py_DECREF(values);
+ goto exit;
+ }
+
+ result = attach_constants_group_to_type(type, false, "ScanReductionState", values,
+ "State of a scanexpression during the reduction process.");
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en constante ScanReductionState. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_reduction_state(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ unsigned long value; /* Valeur transcrite */
+
+ result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type);
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ScanReductionState");
+ break;
+
+ case 1:
+ value = PyLong_AsUnsignedLong(arg);
+
+ if (value > SRS_UNRESOLVABLE)
+ {
+ PyErr_SetString(PyExc_TypeError, "invalid value for ScanReductionState");
+ result = 0;
+ }
+
+ else
+ *((ScanReductionState *)dst) = value;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/constants.h b/plugins/pychrysalide/analysis/scan/constants.h
new file mode 100644
index 0000000..aa6c571
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/constants.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.h - prototypes pour l'ajout des constantes de base pour les types
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit les constantes relatives aux expressions de scan. */
+bool define_expression_value_type_constants(PyTypeObject *);
+
+/* Tente de convertir en constante ScanReductionState. */
+int convert_to_scan_reduction_state(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H */
diff --git a/plugins/pychrysalide/analysis/scan/context.c b/plugins/pychrysalide/analysis/scan/context.c
new file mode 100644
index 0000000..9becaf7
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/context.c
@@ -0,0 +1,432 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * context.c - équivalent Python du fichier "analysis/scan/context.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "context.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/content.h>
+#include <analysis/scan/context-int.h>
+#include <analysis/scan/expr.h>
+
+#include "expr.h"
+#include "../content.h"
+#include "../../access.h"
+#include "../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_context, G_TYPE_SCAN_CONTEXT);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_context_init(PyObject *, PyObject *, PyObject *);
+
+/* Note que la phase d'analyse de contenu est terminée. */
+static PyObject *py_scan_context_mark_scan_as_done(PyObject *, PyObject *);
+
+/* Indique si une correspondance globale a pu être établie. */
+static PyObject *py_scan_context_has_match_for_rule(PyObject *, PyObject *);
+
+/* Fournit une référence au contenu principal analysé. */
+static PyObject *py_scan_context_get_content(PyObject *, void *);
+
+/* Définit le contenu principal à analyser. */
+static int py_scan_context_set_content(PyObject *, PyObject *, void *);
+
+/* Indique si la phase d'analyse de contenu est terminée. */
+static PyObject *py_scan_context_is_scan_done(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_context_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_CONTEXT_DOC \
+ "A ScanContext object tracks results of a run analysis process" \
+ " against binary contents.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " ScanContext()"
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "");
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Note que la phase d'analyse de contenu est terminée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_context_mark_scan_as_done(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Contexte de suivi à renvoyer*/
+ GScanContext *context; /* Contexte de suivi d'analyse */
+
+#define SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD PYTHON_METHOD_DEF \
+( \
+ mark_scan_as_done, "$self", \
+ METH_NOARGS, py_scan_context, \
+ "Note that the analysis operations are finished." \
+)
+
+ context = G_SCAN_CONTEXT(pygobject_get(self));
+
+ g_scan_context_mark_scan_as_done(context);
+
+ result = Py_None;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Indique si une correspondance globale a pu être établie. *
+* *
+* Retour : Bilan final d'une analyse (False par défaut). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_context_has_match_for_rule(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Contexte de suivi à renvoyer*/
+ const char *name; /* Désignation de règle */
+ int ret; /* Bilan de lecture des args. */
+ GScanContext *context; /* Contexte de suivi d'analyse */
+ bool matched; /* Bilan d'analyse à renvoyer */
+
+#define SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD PYTHON_METHOD_DEF \
+( \
+ has_match_for_rule, "$self, name, /", \
+ METH_VARARGS, py_scan_context, \
+ "Provide the match status for a given scan rule.\n" \
+ "\n" \
+ "The *name* argument points to the registered rule to query.\n" \
+ "\n" \
+ "The method returns the scan final status as a boolean: *True*" \
+ " in case of match, *False* otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "s", &name);
+ if (!ret) return NULL;
+
+ context = G_SCAN_CONTEXT(pygobject_get(self));
+
+ matched = g_scan_context_has_match_for_rule(context, name);
+
+ result = matched ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant une routine binaire. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Fournit une référence au contenu principal analysé. *
+* *
+* Retour : Content binaire associé au context. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_context_get_content(PyObject *self, void *closure)
+{
+ PyObject *result; /* Eléments à retourner */
+ GScanContext *context; /* Version native */
+ GBinContent *content; /* Contenu binaire à référencer*/
+
+#define SCAN_CONTEXT_CONTENT_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ content, py_scan_context, \
+ "Link to the scanned binary content.\n" \
+ "\n" \
+ "The result is a pychrysalide.analysis.BinContent for" \
+ " fully initialized context." \
+)
+
+ context = G_SCAN_CONTEXT(pygobject_get(self));
+ content = g_scan_context_get_content(context);
+
+ result = pygobject_new(G_OBJECT(content));
+
+ g_object_unref(G_OBJECT(content));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* value = valeur fournie à intégrer ou prendre en compte. *
+* closure = non utilisé ici. *
+* *
+* Description : Définit le contenu principal à analyser. *
+* *
+* Retour : Content binaire associé au context. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_context_set_content(PyObject *self, PyObject *value, void *closure)
+{
+ GScanContext *context; /* Elément à consulter */
+ int ret; /* Bilan de lecture des args. */
+ GBinContent *content; /* Contenu binaire à référencer*/
+
+ ret = PyObject_IsInstance(value, (PyObject *)get_python_binary_content_type());
+ if (!ret) return -1;
+
+ context = G_SCAN_CONTEXT(pygobject_get(self));
+ content = G_BIN_CONTENT(pygobject_get(value));
+
+ // FIXME g_scan_context_set_content(context, content);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique si la phase d'analyse de contenu est terminée. *
+* *
+* Retour : True si la phase de scan est terminée, False sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_context_is_scan_done(PyObject *self, void *closure)
+{
+ PyObject *result; /* Instance Python à retourner */
+ GScanContext *context; /* Contexte de suivi d'analyse */
+ bool status; /* Bilan de consultation */
+
+#define SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB PYTHON_IS_DEF_FULL \
+( \
+ scan_done, py_scan_context, \
+ "Tell if the analysis operations are finished.\n" \
+ "\n" \
+ "The result is a boolean: *True* if the scan is marked as" \
+ " done, *False* otherwise." \
+)
+
+ context = G_SCAN_CONTEXT(pygobject_get(self));
+
+ status = g_scan_context_is_scan_done(context);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_context_type(void)
+{
+ static PyMethodDef py_scan_context_methods[] = {
+ SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD,
+ SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_context_getseters[] = {
+ SCAN_CONTEXT_CONTENT_ATTRIB,
+ SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_context_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.ScanContext",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_CONTEXT_DOC,
+
+ .tp_methods = py_scan_context_methods,
+ .tp_getset = py_scan_context_getseters,
+
+ .tp_init = py_scan_context_init,
+ .tp_new = py_scan_context_new,
+
+ };
+
+ return &py_scan_context_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.....scan.ScanContext. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_context_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ScanContext' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_context_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_CONTEXT, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en contexte de suivi d'analyse. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_context(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_context_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan context");
+ break;
+
+ case 1:
+ *((GScanContext **)dst) = G_SCAN_CONTEXT(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/context.h b/plugins/pychrysalide/analysis/scan/context.h
new file mode 100644
index 0000000..477205b
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/context.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * context.h - prototypes pour l'équivalent Python du fichier "analysis/scan/context.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_context_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanContext'. */
+bool ensure_python_scan_context_is_registered(void);
+
+/* Tente de convertir en contexte de suivi d'analyse. */
+int convert_to_scan_context(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H */
diff --git a/plugins/pychrysalide/analysis/scan/core.c b/plugins/pychrysalide/analysis/scan/core.c
new file mode 100644
index 0000000..16df9a9
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/core.c
@@ -0,0 +1,179 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - équivalent Python du fichier "analysis/scan/core.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "core.h"
+
+
+#include <pygobject.h>
+
+
+#include <analysis/scan/core.h>
+
+
+#include "patterns/modifier.h"
+#include "../../access.h"
+#include "../../helpers.h"
+
+
+
+/* Inscrit un modificateur dans la liste des disponibles. */
+static PyObject *py_scan_register_token_modifier(PyObject *, PyObject *);
+
+/* Fournit le modificateur correspondant à un nom. */
+static PyObject *py_scan_find_token_modifiers_for_name(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Inscrit un modificateur dans la liste des disponibles. *
+* *
+* Retour : Bilan des enregistrements effectués : True si nouveauté. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_register_token_modifier(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ PyObject *instance; /* Instance Python fournie */
+ GScanTokenModifier *modifier; /* Version native */
+ int ret; /* Bilan de lecture des args. */
+ bool status; /* Bilan d'un enregistrement */
+
+#define SCAN_REGISTER_TOKEN_MODIFIER_METHOD PYTHON_METHOD_DEF \
+( \
+ register_token_modifier, "inst, /", \
+ METH_VARARGS, py_scan, \
+ "Register a token modifier for byte patterns to scan.\n" \
+ "\n" \
+ "This instance will be used as singleton and has to be a" \
+ " subclass of pychrysalide.analysis.scan.patterns.TokenModifier." \
+)
+
+ ret = PyArg_ParseTuple(args, "O!", get_python_scan_token_modifier_type(), &instance);
+ if (!ret) return NULL;
+
+ modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(instance));
+
+ status = register_scan_token_modifier(modifier);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Fournit le modificateur correspondant à un nom. *
+* *
+* Retour : Instance du modificateur identifié ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_find_token_modifiers_for_name(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ sized_string_t name; /* Nom d'appel à rechercher */
+ Py_ssize_t len; /* Taille de ce nom */
+ int ret; /* Bilan de lecture des args. */
+ GScanTokenModifier *modifier; /* Instance mise en place */
+
+#define SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD PYTHON_METHOD_DEF \
+( \
+ find_token_modifiers_for_name, "name, /", \
+ METH_VARARGS, py_scan, \
+ "Provide the registered instance of a pattern modifier linked" \
+ " to a given *name* provided as a key string.\n" \
+ "\n" \
+ "The returned instance is an object inherited from" \
+ " pychrysalide.analysis.scan.patterns.TokenModifier or *None*" \
+ " if no instance was found for the provided name." \
+)
+
+ ret = PyArg_ParseTuple(args, "s#", &name.static_data, &len);
+ if (!ret) return NULL;
+
+ name.len = len;
+
+ modifier = find_scan_token_modifiers_for_name(&name);
+
+ if (modifier != NULL)
+ {
+ result = pygobject_new(G_OBJECT(modifier));
+ g_object_unref(G_OBJECT(modifier));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Définit une extension du module 'scan' à compléter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_scan_module_with_core_methods(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Module à recompléter */
+
+ static PyMethodDef py_core_methods[] = {
+ SCAN_REGISTER_TOKEN_MODIFIER_METHOD,
+ SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD,
+ { NULL }
+ };
+
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ result = register_python_module_methods(module, py_core_methods);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/core.h b/plugins/pychrysalide/analysis/scan/core.h
new file mode 100644
index 0000000..e283f91
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/core.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour l'équivalent Python du fichier "analysis/scan/core.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_CORE_CORE_H
+#define _PLUGINS_PYCHRYSALIDE_CORE_CORE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit une extension du module 'scan' à compléter. */
+bool populate_scan_module_with_core_methods(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_CORE_CORE_H */
diff --git a/plugins/pychrysalide/analysis/scan/expr.c b/plugins/pychrysalide/analysis/scan/expr.c
new file mode 100644
index 0000000..2d8245a
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/expr.c
@@ -0,0 +1,393 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * expr.c - équivalent Python du fichier "analysis/scan/expr.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "expr.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/content.h>
+#include <analysis/scan/expr-int.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+#include <plugins/pychrysalide/glibext/comparison.h>
+
+
+#include "constants.h"
+
+
+
+/* Initialise la classe générique des expressions d'évaluation. */
+static void py_scan_expression_init_gclass(GScanExpressionClass *, gpointer);
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_expression, G_TYPE_SCAN_EXPRESSION, py_scan_expression_init_gclass);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_expression_init(PyObject *, PyObject *, PyObject *);
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *);
+
+/* Indique l'état de réduction d'une expression. */
+static PyObject *py_scan_expression_get_state(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à initialiser. *
+* unused = données non utilisées ici. *
+* *
+* Description : Initialise la classe générique des expressions d'évaluation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_scan_expression_init_gclass(GScanExpressionClass *class, gpointer unused)
+{
+ class->cmp_rich = py_scan_expression_compare_rich_wrapper;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_expression_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ ScanReductionState state; /* Etat de réduction initial */
+ int ret; /* Bilan de lecture des args. */
+ GScanExpression *expr; /* Création GLib à transmettre */
+
+ static char *kwlist[] = { "state", NULL };
+
+#define SCAN_EXPRESSION_DOC \
+ "A ScanExpression is an abstract object which defines an expression"\
+ " involved in data matching when running a scan.\n" \
+ "\n" \
+ "Calls to the *__init__* constructor of this abstract object expect"\
+ " the following arguments as keyword parameters:\n" \
+ "* *state*: initial state of reduction for the expression, as a" \
+ " pychrysalide.analysis.scan.ScanExpression.ScanReductionState" \
+ " value." \
+ "\n" \
+ "The following methods have to be defined for new classes:\n" \
+ "* pychrysalide.analysis.scan.ScanExpression._cmp_rich().\n"
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, convert_to_scan_reduction_state, &state);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ expr = G_SCAN_EXPRESSION(pygobject_get(self));
+
+ if (!g_scan_expression_create(expr, state))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create scan expression."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = premier objet à cnsulter pour une comparaison. *
+* other = second objet à cnsulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *item, const GScanExpression *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
+ PyObject *pyret; /* Bilan de consultation */
+ int ret; /* Bilan d'une conversion */
+
+#define SCAN_EXPRESSION_CMP_RICH_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _cmp_rich, "$self, other, op, /", \
+ METH_VARARGS, \
+ "Abstract method used to compare the expression against another" \
+ " one.\n" \
+ "\n" \
+ "The second *other* instance is built from the same type as *self*."\
+ " The *op* argument points to a" \
+ " pychrysalide.glibext.ComparableItem.RichCmpOperation mode" \
+ " describing the expected comparison.\n" \
+ "\n" \
+ "The result is a boolean status or *None* if the comparison" \
+ " process is undefined." \
+)
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(item));
+
+ if (has_python_method(pyobj, "_cmp_rich"))
+ {
+ args = PyTuple_New(2);
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other)));
+ PyTuple_SetItem(args, 1, cast_with_constants_group_from_type(get_python_comparable_item_type(),
+ "RichCmpOperation", op));
+
+ pyret = run_python_method(pyobj, "_cmp_rich", args);
+
+ if (pyret != NULL)
+ {
+ ret = PyBool_Check(pyret);
+
+ if (ret)
+ {
+ *status = (pyret == Py_True);
+ result = true;
+ }
+
+ Py_DECREF(pyret);
+
+ }
+
+ Py_DECREF(args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique l'état de réduction d'une expression. *
+* *
+* Retour : Etat courant associé à l'expression. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_expression_get_state(PyObject *self, void *closure)
+{
+ PyObject *result; /* Instance Python à retourner */
+ GScanExpression *expr; /* Version GLib de l'opérande */
+ ScanReductionState state; /* Etat courant de l'expression*/
+
+#define SCAN_EXPRESSION_STATE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ state, py_scan_expression, \
+ "Current state of the expression, relative to the reduction" \
+ " process, as a" \
+ " pychrysalide.analysis.scan.ScanExpression.ScanReductionState" \
+ " value." \
+)
+
+ expr = G_SCAN_EXPRESSION(pygobject_get(self));
+
+ state = g_scan_expression_get_state(expr);
+
+ result = cast_with_constants_group_from_type(get_python_scan_expression_type(), "ScanReductionState", state);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_expression_type(void)
+{
+ static PyMethodDef py_scan_expression_methods[] = {
+ SCAN_EXPRESSION_CMP_RICH_WRAPPER,
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_expression_getseters[] = {
+ SCAN_EXPRESSION_STATE_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_expression_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.ScanExpression",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_EXPRESSION_DOC,
+
+ .tp_methods = py_scan_expression_methods,
+ .tp_getset = py_scan_expression_getseters,
+
+ .tp_init = py_scan_expression_init,
+ .tp_new = py_scan_expression_new,
+
+ };
+
+ return &py_scan_expression_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide...scan.ScanExpression'.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_expression_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ScanExpression'*/
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_expression_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_comparable_item_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_EXPRESSION, type))
+ return false;
+
+ if (!define_expression_value_type_constants(type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en expression d'évaluation généraliste. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_expression(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_expression_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to match expression");
+ break;
+
+ case 1:
+ *((GScanExpression **)dst) = G_SCAN_EXPRESSION(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/expr.h b/plugins/pychrysalide/analysis/scan/expr.h
new file mode 100644
index 0000000..00ab28d
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/expr.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * expr.h - prototypes pour l'équivalent Python du fichier "analysis/scan/expr.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_expression_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanExpression'. */
+bool ensure_python_scan_expression_is_registered(void);
+
+/* Tente de convertir en fonction d'analyse pour scan. */
+int convert_to_scan_expression(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H */
diff --git a/plugins/pychrysalide/analysis/scan/exprs/Makefile.am b/plugins/pychrysalide/analysis/scan/exprs/Makefile.am
new file mode 100644
index 0000000..e40d4de
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/exprs/Makefile.am
@@ -0,0 +1,15 @@
+
+noinst_LTLIBRARIES = libpychrysaanalysisscanexprs.la
+
+libpychrysaanalysisscanexprs_la_SOURCES = \
+ constants.h constants.c \
+ literal.h literal.c \
+ module.h module.c
+
+libpychrysaanalysisscanexprs_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ $(TOOLKIT_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libpychrysaanalysisscanexprs_la_SOURCES:%c=)
diff --git a/plugins/pychrysalide/analysis/scan/exprs/constants.c b/plugins/pychrysalide/analysis/scan/exprs/constants.c
new file mode 100644
index 0000000..b11ac4c
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/exprs/constants.c
@@ -0,0 +1,128 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.c - ajout des constantes de base pour les expressions
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "constants.h"
+
+
+#include <analysis/scan/exprs/literal.h>
+
+
+#include "../../../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type dont le dictionnaire est à compléter. *
+* *
+* Description : Définit les constantes relatives aux expressions de scan. *
+* *
+* Retour : true en cas de succès de l'opération, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_literal_expression_value_type_constants(PyTypeObject *type)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *values; /* Groupe de valeurs à établir */
+
+ values = PyDict_New();
+
+ result = add_const_to_group(values, "LVT_BOOLEAN", LVT_BOOLEAN);
+ if (result) result = add_const_to_group(values, "SIGNED_INTEGER", LVT_SIGNED_INTEGER);
+ if (result) result = add_const_to_group(values, "UNSIGNED_INTEGER", LVT_UNSIGNED_INTEGER);
+ if (result) result = add_const_to_group(values, "STRING", LVT_STRING);
+
+ if (!result)
+ {
+ Py_DECREF(values);
+ goto exit;
+ }
+
+ result = attach_constants_group_to_type(type, false, "LiteralValueType", values,
+ "Type of value carried by a literal scan expression.");
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en constante LiteralValueType. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_literal_expression_value_type(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ unsigned long value; /* Valeur transcrite */
+
+ result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type);
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to LiteralValueType");
+ break;
+
+ case 1:
+ value = PyLong_AsUnsignedLong(arg);
+
+ if (value > LVT_REG_EXPR)
+ {
+ PyErr_SetString(PyExc_TypeError, "invalid value for LiteralValueType");
+ result = 0;
+ }
+
+ else
+ *((LiteralValueType *)dst) = value;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/exprs/constants.h b/plugins/pychrysalide/analysis/scan/exprs/constants.h
new file mode 100644
index 0000000..e5b8e8c
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/exprs/constants.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.h - prototypes pour l'ajout des constantes de base pour les expressions
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit les constantes relatives aux expressions litérales. */
+bool define_literal_expression_value_type_constants(PyTypeObject *);
+
+/* Tente de convertir en constante LiteralValueType. */
+int convert_to_literal_expression_value_type(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H */
diff --git a/plugins/pychrysalide/analysis/scan/exprs/literal.c b/plugins/pychrysalide/analysis/scan/exprs/literal.c
new file mode 100644
index 0000000..d7ae002
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/exprs/literal.c
@@ -0,0 +1,281 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * literal.c - équivalent Python du fichier "analysis/scan/exprs/literal.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "literal.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/exprs/literal-int.h>
+
+
+#include "constants.h"
+#include "../expr.h"
+#include "../../../access.h"
+#include "../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_literal_expression, G_TYPE_SCAN_LITERAL_EXPRESSION);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_literal_expression_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_literal_expression_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *py_value; /* Valeur en version Python */
+ int ret; /* Bilan de lecture des args. */
+ LiteralValueType vtype; /* Valeur à porter */
+ bool arg_boolean; /* Argument natif booléen */
+ unsigned long long arg_uinteger; /* Argument natif entier */
+ sized_string_t arg_string; /* Argument natif textuel */
+ Py_ssize_t arg_str_length; /* Taille de ce texte */
+ void *arg_ptr; /* Pointeur vers un argument */
+ GScanLiteralExpression *expr; /* Création GLib à transmettre */
+
+#define SCAN_LITERAL_EXPRESSION_DOC \
+ "A ScanLiteralExpression object defines expression carrying" \
+ " literal values available for scan match conditions.\n" \
+ "\n" \
+ "Instances can be created using one of the following" \
+ " constructors:\n" \
+ "\n" \
+ " ScanLiteralExpression(value)" \
+ "\n" \
+ "\n" \
+ "Where *value* is either a boolean, an integer or bytes."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O", &py_value);
+ if (!ret) return -1;
+
+ if (PyBool_Check(py_value))
+ {
+ vtype = LVT_BOOLEAN;
+
+ arg_boolean = (py_value == Py_True);
+ arg_ptr = &arg_boolean;
+
+ }
+
+ else if (PyLong_Check(py_value))
+ {
+ if (1 /* sign - TODO */)
+ ;
+
+ vtype = LVT_UNSIGNED_INTEGER;
+
+ arg_uinteger = PyLong_AsUnsignedLongLong(py_value);
+ arg_ptr = &arg_uinteger;
+
+ }
+
+ else if (PyBytes_Check(py_value))
+ {
+ vtype = LVT_STRING;
+
+ ret = PyBytes_AsStringAndSize(py_value, &arg_string.data, &arg_str_length);
+ if (ret == -1) return -1;
+
+ arg_string.len = arg_str_length;
+ arg_ptr = &arg_string;
+
+ }
+
+ else
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unsupported Python value for a literal scan expression."));
+ return -1;
+ }
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ expr = G_SCAN_LITERAL_EXPRESSION(pygobject_get(self));
+
+ if (!g_scan_literal_expression_create(expr, vtype, arg_ptr))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create literal expression."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_literal_expression_type(void)
+{
+ static PyMethodDef py_scan_literal_expression_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_literal_expression_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_literal_expression_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.exprs.ScanLiteralExpression",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_LITERAL_EXPRESSION_DOC,
+
+ .tp_methods = py_scan_literal_expression_methods,
+ .tp_getset = py_scan_literal_expression_getseters,
+
+ .tp_init = py_scan_literal_expression_init,
+ .tp_new = py_scan_literal_expression_new,
+
+ };
+
+ return &py_scan_literal_expression_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....PlainModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_literal_expression_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'PlainModifier' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_literal_expression_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.exprs");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_expression_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_LITERAL_EXPRESSION, type))
+ return false;
+
+ if (!define_literal_expression_value_type_constants(type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transmission d'octets à l'identique. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_literal_expression(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_literal_expression_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan literal expression");
+ break;
+
+ case 1:
+ *((GScanLiteralExpression **)dst) = G_SCAN_LITERAL_EXPRESSION(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/exprs/literal.h b/plugins/pychrysalide/analysis/scan/exprs/literal.h
new file mode 100644
index 0000000..8e7ea70
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/exprs/literal.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * literal.h - équivalent Python du fichier "analysis/scan/exprs/literal.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_literal_expression_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.exprs.ScanLiteralExpression'. */
+bool ensure_python_scan_literal_expression_is_registered(void);
+
+/* Tente de convertir en transmission d'octets à l'identique. */
+int convert_to_scan_literal_expression(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H */
diff --git a/plugins/pychrysalide/analysis/scan/exprs/module.c b/plugins/pychrysalide/analysis/scan/exprs/module.c
new file mode 100644
index 0000000..4f38430
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/exprs/module.c
@@ -0,0 +1,103 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire exprs en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+
+
+#include "literal.h"
+#include "../../../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Ajoute le module 'analysis....modifiers' à un module Python. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_analysis_scan_exprs_module(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_DOC \
+ "This module provide expressions used to build a match condition."
+
+ static PyModuleDef py_chrysalide_analysis_scan_exprs_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.analysis.scan.exprs",
+ .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_DOC,
+
+ .m_size = -1,
+
+ };
+
+ module = build_python_module(super, &py_chrysalide_analysis_scan_exprs_module);
+
+ result = (module != NULL);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'analysis...patterns.modifiers'.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_analysis_scan_exprs_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_scan_literal_expression_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/exprs/module.h b/plugins/pychrysalide/analysis/scan/exprs/module.h
new file mode 100644
index 0000000..ee4b8ab
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/exprs/module.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire exprs en tant que module
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'analysis.scan.exprs' à un module Python. */
+bool add_analysis_scan_exprs_module(PyObject *);
+
+/* Intègre les objets du module 'analysis.scan.exprs'. */
+bool populate_analysis_scan_exprs_module(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H */
diff --git a/plugins/pychrysalide/analysis/scan/item.c b/plugins/pychrysalide/analysis/scan/item.c
new file mode 100644
index 0000000..014ae24
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/item.c
@@ -0,0 +1,740 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.c - équivalent Python du fichier "analysis/scan/item.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "item.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/item-int.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "context.h"
+
+
+
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Initialise la classe des éléments appelables enregistrés. */
+static void py_scan_registered_item_init_gclass(GScanRegisteredItemClass *, gpointer);
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_registered_item, G_TYPE_SCAN_REGISTERED_ITEM, py_scan_registered_item_init_gclass);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_registered_item_init(PyObject *, PyObject *, PyObject *);
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *py_scan_registered_item_get_name_wrapper(const GScanRegisteredItem *);
+
+/* Lance une résolution d'élément à solliciter. */
+static bool py_scan_registered_item_resolve_wrapper(GScanRegisteredItem *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **);
+
+/* Réduit une expression à une forme plus simple. */
+static bool py_scan_registered_item_reduce_wrapper(GScanRegisteredItem *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Effectue un appel à une fonction enregistrée. */
+static bool py_scan_registered_item_run_call_wrapper(GScanRegisteredItem *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+
+
+/* Lance une résolution d'élément à appeler. */
+static PyObject *py_scan_registered_item_resolve(PyObject *, PyObject *);
+
+/* Fournit le désignation associée à un composant nommé. */
+static PyObject *py_scan_registered_item_get_name(PyObject *, void *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à initialiser. *
+* unused = données non utilisées ici. *
+* *
+* Description : Initialise la classe des éléments appelables enregistrés. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_scan_registered_item_init_gclass(GScanRegisteredItemClass *class, gpointer unused)
+{
+ class->get_name = py_scan_registered_item_get_name_wrapper;
+ class->resolve = py_scan_registered_item_resolve_wrapper;
+ class->reduce = py_scan_registered_item_reduce_wrapper;
+ class->run_call = py_scan_registered_item_run_call_wrapper;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_registered_item_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_REGISTERED_ITEM_DOC \
+ "The *RegisteredItem* class is an abstract definition which is" \
+ " the base for all keywords involved in a match condition" \
+ " expression.\n" \
+ "\n" \
+ "Calls to the *__init__* constructor of this abstract object" \
+ " expect no particular argument.\n" \
+ "\n" \
+ "The following methods have to be defined for new classes:\n" \
+ "* pychrysalide.analysis.scan.RegisteredItem._resolve();\n" \
+ "* pychrysalide.analysis.scan.RegisteredItem._reduce();\n" \
+ "* pychrysalide.analysis.scan.RegisteredItem._call().\n" \
+ "\n" \
+ "One item has to be defined as class attributes in the final" \
+ " class:\n" \
+ "* pychrysalide.analysis.scan.RegisteredItem._name.\n"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *py_scan_registered_item_get_name_wrapper(const GScanRegisteredItem *item)
+{
+ char *result; /* Désignation à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyname; /* Nom en objet Python */
+ int ret; /* Bilan d'une conversion */
+
+#define SCAN_REGISTERED_ITEM_NAME_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \
+( \
+ _name, \
+ "Provide the keyword of the expression item to be evaluated.\n" \
+ "\n" \
+ "The result has to be a string." \
+)
+
+ result = NULL;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(item));
+
+ if (PyObject_HasAttrString(pyobj, "_name"))
+ {
+ pyname = PyObject_GetAttrString(pyobj, "_name");
+
+ if (pyname != NULL)
+ {
+ ret = PyUnicode_Check(pyname);
+
+ if (ret)
+ result = strdup(PyUnicode_AsUTF8(pyname));
+
+ Py_DECREF(pyname);
+
+ }
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* target = désignation de l'objet d'appel à identifier. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT]*
+* *
+* Description : Lance une résolution d'élément à solliciter. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_scan_registered_item_resolve_wrapper(GScanRegisteredItem *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out)
+{
+ bool result; /* Bilan à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
+ PyObject *pyret; /* Bilan de consultation */
+ GObject *gobj_ret; /* Bilan natif de consultation */
+
+#define SCAN_REGISTERED_ITEM_RESOLVE_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _cmp_rich, "$self, target, ctx, scope, /", \
+ METH_VARARGS, \
+ "Abstract method used to resolve an item by name.\n" \
+ "\n" \
+ "The *target* argument provide the name of the searched item;" \
+ " *ctx* is a pychrysalide.analysis.scan.ScanContext instance" \
+ " providing information about the current state; *scope* is a" \
+ " pychrysalide.analysis.scan.ScanScope offering a view on the" \
+ " current namespace for variables.\n" \
+ "\n" \
+ "The result has to be a pychrysalide.analysis.scan.RegisteredItem" \
+ " instance on success, or *None* in case of failure." \
+)
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(item));
+
+ if (has_python_method(pyobj, "_resolve"))
+ {
+ args = PyTuple_New(3);
+ PyTuple_SetItem(args, 0, PyUnicode_FromString(target));
+ PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(ctx)));
+ PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(scope)));
+
+ pyret = run_python_method(pyobj, "_resolve", args);
+
+ if (pyret != NULL)
+ {
+ gobj_ret = pygobject_get(pyret);
+
+ if (G_IS_SCAN_REGISTERED_ITEM(gobj_ret))
+ {
+ *out = G_SCAN_REGISTERED_ITEM(gobj_ret);
+
+ g_object_ref(G_OBJECT(*out));
+ result = true;
+
+ }
+
+ Py_DECREF(pyret);
+
+ }
+
+ Py_DECREF(args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_scan_registered_item_reduce_wrapper(GScanRegisteredItem *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
+ PyObject *pyret; /* Bilan de consultation */
+ GObject *gobj_ret; /* Bilan natif de consultation */
+
+#define SCAN_REGISTERED_ITEM_REDUCE_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _cmp_rich, "$self, ctx, scope, /", \
+ METH_VARARGS, \
+ "Abstract method used to replace the item by an equivalent reduced" \
+ " value.\n" \
+ "\n" \
+ "The *ctx* argument is a pychrysalide.analysis.scan.ScanContext" \
+ " instance providing information about the current state; *scope*" \
+ " is a pychrysalide.analysis.scan.ScanScope offering a view on the" \
+ " current namespace for variables.\n" \
+ "\n" \
+ "The result has to be a pychrysalide.analysis.scan.ScanExpression" \
+ " instance on success, or *None* in case of failure." \
+)
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(item));
+
+ if (has_python_method(pyobj, "_reduce"))
+ {
+ args = PyTuple_New(2);
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(ctx)));
+ PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(scope)));
+
+ pyret = run_python_method(pyobj, "_reduce", args);
+
+ if (pyret != NULL)
+ {
+ gobj_ret = pygobject_get(pyret);
+
+ if (G_IS_SCAN_EXPRESSION(gobj_ret))
+ {
+ *out = G_SCAN_EXPRESSION(gobj_ret);
+
+ g_object_ref(G_OBJECT(*out));
+ result = true;
+
+ }
+
+ Py_DECREF(pyret);
+
+ }
+
+ Py_DECREF(args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Effectue un appel à une fonction enregistrée. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_scan_registered_item_run_call_wrapper(GScanRegisteredItem *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *sub_args; /* Sous-arguments pour l'appel */
+ size_t i; /* Boucle de parcours */
+ PyObject *py_args; /* Arguments pour l'appel */
+ PyObject *pyret; /* Bilan de consultation */
+ GObject *gobj_ret; /* Bilan natif de consultation */
+
+#define SCAN_REGISTERED_ITEM_CALL_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _cmp_rich, "$self, args, ctx, scope, /", \
+ METH_VARARGS, \
+ "Abstract method used to replace the item and its arguments by an" \
+ " equivalent reduced value.\n" \
+ "\n" \
+ "The *args* argument is a tuple of already reduced" \
+ " pychrysalide.analysis.scan.ScanExpression objects; ctx* argument" \
+ " is a pychrysalide.analysis.scan.ScanContext instance providing" \
+ " information about the current state; *scope* is a" \
+ " pychrysalide.analysis.scan.ScanScope offering a view on the" \
+ " current namespace for variables.\n" \
+ "\n" \
+ "The result has to be a pychrysalide.analysis.scan.ScanExpression" \
+ " instance on success, or *None* in case of failure." \
+)
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(item));
+
+ if (has_python_method(pyobj, "_call"))
+ {
+ sub_args = PyTuple_New(count);
+
+ for (i = 0; i < count; i++)
+ PyTuple_SetItem(sub_args, 1, pygobject_new(G_OBJECT(args[i])));
+
+ py_args = PyTuple_New(3);
+ PyTuple_SetItem(py_args, 0, sub_args);
+ PyTuple_SetItem(py_args, 1, pygobject_new(G_OBJECT(ctx)));
+ PyTuple_SetItem(py_args, 2, pygobject_new(G_OBJECT(scope)));
+
+ pyret = run_python_method(pyobj, "_call", py_args);
+
+ if (pyret != NULL)
+ {
+ gobj_ret = pygobject_get(pyret);
+
+ if (G_IS_OBJECT(gobj_ret))
+ {
+ *out = gobj_ret;
+
+ g_object_ref(G_OBJECT(*out));
+ result = true;
+
+ }
+
+ Py_DECREF(pyret);
+
+ }
+
+ Py_DECREF(py_args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONNEXION AVEC L'API DE PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : self = élément d'appel à consulter. *
+* args = arguments fournis pour l'opération. *
+* *
+* Description : Lance une résolution d'élément à appeler. *
+* *
+* Retour : Nouvel élément d'appel identifié ou None. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_registered_item_resolve(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ const char *target; /* Désignation de la cible */
+ GScanContext *ctx; /* Contexte d'analyse */
+ GScanScope *scope; /* Portée de variables locales */
+ int ret; /* Bilan de lecture des args. */
+ GScanRegisteredItem *item; /* Version native */
+ bool status; /* Bilan d'exécution */
+ GScanRegisteredItem *resolved; /* Elément trouvé */
+
+#define SCAN_REGISTERED_ITEM_RESOLVE_METHOD PYTHON_METHOD_DEF \
+( \
+ resolve, "$self, target, /, ctx=None, scope=None", \
+ METH_VARARGS, py_scan_registered_item, \
+ "Resolve a name into a scan item." \
+ "\n" \
+ "The *target* name is the only mandatory parameter and has to point"\
+ " to only one item. The *ctx* argument points to an optional useful"\
+ " storage for resolution lookup, as a" \
+ " pychrysalide.analysis.scan.ScanContext instance. The *args* list" \
+ " defines an optional list of arguments, as" \
+ " pychrysalide.analysis.scan.ScanExpression instances, to use for" \
+ " building the resolved item. The *final* flag states if the" \
+ " scanning process is about to conclude or not." \
+ "\n" \
+ "The result is an object inheriting from" \
+ " pychrysalide.analysis.scan.RegisteredItem or *None* if the" \
+ " resolution operation failed." \
+)
+
+ ctx = NULL;
+ scope = NULL;
+
+ ret = PyArg_ParseTuple(args, "s|O&", &target,
+ convert_to_scan_context, &ctx);
+ if (!ret) return NULL;
+
+ item = G_SCAN_REGISTERED_ITEM(pygobject_get(self));
+
+ status = g_scan_registered_item_resolve(item, target, ctx, scope, &resolved);
+
+ if (!status)
+ {
+ result = NULL;
+ PyErr_Format(PyExc_RuntimeError, _("Unable to resolve any target from the item"));
+ }
+ else
+ {
+ if (resolved != NULL)
+ {
+ result = pygobject_new(G_OBJECT(resolved));
+ g_object_unref(G_OBJECT(resolved));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un composant nommé à manipuler.*
+* closure = non utilisé ici. *
+* *
+* Description : Fournit le désignation associée à un composant nommé. *
+* *
+* Retour : Description courante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_registered_item_get_name(PyObject *self, void *closure)
+{
+ PyObject *result; /* Décompte à retourner */
+ GScanRegisteredItem *item; /* Version native */
+ char *name; /* Désignation à convertir */
+
+#define SCAN_REGISTERED_ITEM_NAME_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ name, py_scan_registered_item, \
+ "Name linked to the registered item.\n" \
+ "\n" \
+ "The result should be a string, or *None* for the root namespace." \
+)
+
+ item = G_SCAN_REGISTERED_ITEM(pygobject_get(self));
+
+ name = g_scan_registered_item_get_name(item);
+
+ if (name == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else
+ {
+ result = PyUnicode_FromString(name);
+ free(name);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_registered_item_type(void)
+{
+ static PyMethodDef py_scan_registered_item_methods[] = {
+ SCAN_REGISTERED_ITEM_RESOLVE_WRAPPER,
+ SCAN_REGISTERED_ITEM_REDUCE_WRAPPER,
+ SCAN_REGISTERED_ITEM_CALL_WRAPPER,
+ SCAN_REGISTERED_ITEM_RESOLVE_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_registered_item_getseters[] = {
+ SCAN_REGISTERED_ITEM_NAME_ATTRIB_WRAPPER,
+ SCAN_REGISTERED_ITEM_NAME_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_registered_item_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.ScanRegisteredItem",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_REGISTERED_ITEM_DOC,
+
+ .tp_methods = py_scan_registered_item_methods,
+ .tp_getset = py_scan_registered_item_getseters,
+
+ .tp_init = py_scan_registered_item_init,
+ .tp_new = py_scan_registered_item_new,
+
+ };
+
+ return &py_scan_registered_item_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide...ScanRegisteredItem'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_registered_item_is_registered(void)
+{
+ PyTypeObject *type; /* Type 'ScanRegisteredItem' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_registered_item_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_REGISTERED_ITEM, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en expression d'évaluation généraliste. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_registered_item(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_registered_item_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to generic scan expression");
+ break;
+
+ case 1:
+ *((GScanRegisteredItem **)dst) = G_SCAN_REGISTERED_ITEM(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/item.h b/plugins/pychrysalide/analysis/scan/item.h
new file mode 100644
index 0000000..773908c
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/item.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.h - prototypes pour l'équivalent Python du fichier "analysis/scan/item.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_registered_item_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanRegisteredItem'. */
+bool ensure_python_scan_registered_item_is_registered(void);
+
+/* Tente de convertir en expression d'évaluation généraliste. */
+int convert_to_scan_registered_item(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H */
diff --git a/plugins/pychrysalide/analysis/scan/module.c b/plugins/pychrysalide/analysis/scan/module.c
new file mode 100644
index 0000000..9ae0e52
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/module.c
@@ -0,0 +1,125 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire scan en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+
+
+#include "context.h"
+#include "core.h"
+#include "expr.h"
+#include "item.h"
+#include "options.h"
+#include "scanner.h"
+#include "space.h"
+#include "exprs/module.h"
+#include "patterns/module.h"
+#include "../../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Ajoute le module 'analysis.scan' à un module Python. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_analysis_scan_module(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC \
+ "This module provide all the features useful for scanning" \
+ " binary contents."
+
+ static PyModuleDef py_chrysalide_analysis_scan_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.analysis.scan",
+ .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC,
+
+ .m_size = -1,
+
+ };
+
+ module = build_python_module(super, &py_chrysalide_analysis_scan_module);
+
+ result = (module != NULL);
+
+ if (result) result = add_analysis_scan_exprs_module(module);
+ if (result) result = add_analysis_scan_patterns_module(module);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'analysis.scan'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_analysis_scan_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_content_scanner_is_registered();
+ if (result) result = ensure_python_scan_context_is_registered();
+ if (result) result = ensure_python_scan_expression_is_registered();
+ if (result) result = ensure_python_scan_registered_item_is_registered();
+ if (result) result = ensure_python_scan_options_is_registered();
+ if (result) result = ensure_python_scan_namespace_is_registered();
+
+ if (result) result = populate_scan_module_with_core_methods();
+
+ if (result) result = populate_analysis_scan_exprs_module();
+ if (result) result = populate_analysis_scan_patterns_module();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/module.h b/plugins/pychrysalide/analysis/scan/module.h
new file mode 100644
index 0000000..a5e84b5
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/module.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire scan en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'analysis.scan' à un module Python. */
+bool add_analysis_scan_module(PyObject *);
+
+/* Intègre les objets du module 'analysis.scan'. */
+bool populate_analysis_scan_module(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H */
diff --git a/plugins/pychrysalide/analysis/scan/options.c b/plugins/pychrysalide/analysis/scan/options.c
new file mode 100644
index 0000000..84c1784
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/options.c
@@ -0,0 +1,511 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * options.c - équivalent Python du fichier "analysis/scan/options.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "options.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/options-int.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_options, G_TYPE_SCAN_OPTIONS);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_options_init(PyObject *, PyObject *, PyObject *);
+
+/* Indique le type d'un moteur d'analyse de données sélectionné. */
+static PyObject *py_scan_options_get_backend_for_data(PyObject *, void *);
+
+/* Sélectionne un type de moteur d'analyse pour données brutes. */
+static int py_scan_options_set_backend_for_data(PyObject *, PyObject *, void *);
+
+/* Impose le format JSON comme type de sortie. */
+static PyObject *py_scan_options_get_print_json(PyObject *, void *);
+
+/* Mémorise le format JSON comme type de sortie. */
+static int py_scan_options_set_print_json(PyObject *, PyObject *, void *);
+
+/* Indique un besoin d'affichage des correspondances finales. */
+static PyObject *py_scan_options_get_print_strings(PyObject *, void *);
+
+/* Mémorise un besoin d'affichage des correspondances finales. */
+static int py_scan_options_set_print_strings(PyObject *, PyObject *, void *);
+
+/* Indique un besoin de statistiques en fin de compilation. */
+static PyObject *py_scan_options_get_print_stats(PyObject *, void *);
+
+/* Mémorise un besoin de statistiques en fin de compilation. */
+static int py_scan_options_set_print_stats(PyObject *, PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_options_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_OPTIONS_DOC \
+ "The *ScanOptions* class stores all parameters used to tune" \
+ " a scanning process.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " ScanOptions()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format Axml. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Indique le type d'un moteur d'analyse de données sélectionné.*
+* *
+* Retour : Type d'objet, idéalement valide. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_options_get_backend_for_data(PyObject *self, void *closure)
+{
+ PyObject *result; /* Liste éventuelle à renvoyer */
+ GScanOptions *options; /* Version native */
+ GType type; /* Type à transcrire */
+
+#define SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ backend_for_data, py_scan_options, \
+ "Type of the selected scan algorithm." \
+)
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ type = g_scan_options_get_backend_for_data(options);
+
+ result = pyg_type_wrapper_new(type);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* value = valeur fournie à intégrer ou prendre en compte. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Sélectionne un type de moteur d'analyse pour données brutes. *
+* *
+* Retour : Bilan de l'opération pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_options_set_backend_for_data(PyObject *self, PyObject *value, void *closure)
+{
+ GType type; /* Type à transcrit */
+ GScanOptions *options; /* Version native */
+
+ type = pyg_type_from_object(value);
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ g_scan_options_set_backend_for_data(options, type);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format Axml. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Impose le format JSON comme type de sortie. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_options_get_print_json(PyObject *self, void *closure)
+{
+ PyObject *result; /* Liste éventuelle à renvoyer */
+ GScanOptions *options; /* Version native */
+ bool state; /* Etat courant à consulter */
+
+#define SCAN_OPTIONS_PRINT_JSON_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ print_json, py_scan_options, \
+ "Define if the process summary is output into a JSON" \
+ " format at the end of the scan or not." \
+)
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ state = g_scan_options_get_print_json(options);
+
+ result = state ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* value = valeur fournie à intégrer ou prendre en compte. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Mémorise le format JSON comme type de sortie. *
+* *
+* Retour : Bilan de l'opération pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_options_set_print_json(PyObject *self, PyObject *value, void *closure)
+{
+ bool state; /* Nouvel état à définir */
+ GScanOptions *options; /* Version native */
+
+ if (value != Py_True && value != Py_False)
+ return -1;
+
+ state = (value == Py_True);
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ g_scan_options_set_print_json(options, state);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format Axml. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Indique un besoin d'affichage des correspondances finales. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_options_get_print_strings(PyObject *self, void *closure)
+{
+ PyObject *result; /* Liste éventuelle à renvoyer */
+ GScanOptions *options; /* Version native */
+ bool state; /* Etat courant à consulter */
+
+#define SCAN_OPTIONS_PRINT_STRINGS_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ print_strings, py_scan_options, \
+ "Define if the matching patterns are printed with found" \
+ " offset at the end of the scan or not." \
+)
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ state = g_scan_options_get_print_strings(options);
+
+ result = state ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* value = valeur fournie à intégrer ou prendre en compte. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Mémorise un besoin d'affichage des correspondances finales. *
+* *
+* Retour : Bilan de l'opération pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_options_set_print_strings(PyObject *self, PyObject *value, void *closure)
+{
+ bool state; /* Nouvel état à définir */
+ GScanOptions *options; /* Version native */
+
+ if (value != Py_True && value != Py_False)
+ return -1;
+
+ state = (value == Py_True);
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ g_scan_options_set_print_strings(options, state);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format Axml. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Indique un besoin de statistiques en fin de compilation. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_options_get_print_stats(PyObject *self, void *closure)
+{
+ PyObject *result; /* Liste éventuelle à renvoyer */
+ GScanOptions *options; /* Version native */
+ bool state; /* Etat courant à consulter */
+
+#define SCAN_OPTIONS_PRINT_STATS_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ print_stats, py_scan_options, \
+ "Control the output of final statistics afer a scan." \
+)
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ state = g_scan_options_get_print_stats(options);
+
+ result = state ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* value = valeur fournie à intégrer ou prendre en compte. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Mémorise un besoin de statistiques en fin de compilation. *
+* *
+* Retour : Bilan de l'opération pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_options_set_print_stats(PyObject *self, PyObject *value, void *closure)
+{
+ bool state; /* Nouvel état à définir */
+ GScanOptions *options; /* Version native */
+
+ if (value != Py_True && value != Py_False)
+ return -1;
+
+ state = (value == Py_True);
+
+ options = G_SCAN_OPTIONS(pygobject_get(self));
+
+ g_scan_options_set_print_stats(options, state);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_options_type(void)
+{
+ static PyMethodDef py_scan_options_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_options_getseters[] = {
+ SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB,
+ SCAN_OPTIONS_PRINT_JSON_ATTRIB,
+ SCAN_OPTIONS_PRINT_STRINGS_ATTRIB,
+ SCAN_OPTIONS_PRINT_STATS_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_options_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.ScanOptions",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+
+ .tp_doc = SCAN_OPTIONS_DOC,
+
+ .tp_methods = py_scan_options_methods,
+ .tp_getset = py_scan_options_getseters,
+
+ .tp_init = py_scan_options_init,
+ .tp_new = py_scan_options_new,
+
+ };
+
+ return &py_scan_options_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide...scan.ScanOptions'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_options_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ScanOptions' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_options_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_OPTIONS, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en ensemble d'options d'analyses. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_options(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_options_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan options");
+ break;
+
+ case 1:
+ *((GScanOptions **)dst) = G_SCAN_OPTIONS(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/options.h b/plugins/pychrysalide/analysis/scan/options.h
new file mode 100644
index 0000000..3e83880
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/options.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * options.h - prototypes pour l'équivalent Python du fichier "analysis/scan/options.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_options_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanOptions'. */
+bool ensure_python_scan_options_is_registered(void);
+
+/* Tente de convertir en ensemble d'options d'analyses. */
+int convert_to_scan_options(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am
new file mode 100644
index 0000000..dd26fa5
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am
@@ -0,0 +1,22 @@
+
+noinst_LTLIBRARIES = libpychrysaanalysisscanpatterns.la
+
+libpychrysaanalysisscanpatterns_la_SOURCES = \
+ backend.h backend.c \
+ modifier.h modifier.c \
+ module.h module.c
+
+libpychrysaanalysisscanpatterns_la_LIBADD = \
+ backends/libpychrysaanalysisscanpatternsbackends.la \
+ modifiers/libpychrysaanalysisscanpatternsmodifiers.la
+
+libpychrysaanalysisscanpatterns_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ $(TOOLKIT_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libpychrysaanalysisscanpatterns_la_SOURCES:%c=)
+
+
+SUBDIRS = backends modifiers
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.c b/plugins/pychrysalide/analysis/scan/patterns/backend.c
new file mode 100644
index 0000000..03db143
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backend.c
@@ -0,0 +1,202 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend.c - équivalent Python du fichier "analysis/scan/backend.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "backend.h"
+
+
+#include <pygobject.h>
+
+
+#include <analysis/scan/patterns/backend-int.h>
+
+
+#include "../../../access.h"
+#include "../../../helpers.h"
+
+
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(engine_backend, G_TYPE_ENGINE_BACKEND, NULL);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_engine_backend_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_engine_backend_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define ENGINE_BACKEND_DOC \
+ "An *EngineBackend* object is the root class of all scan algorithm" \
+ " looking for data patterns."
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_engine_backend_type(void)
+{
+ static PyMethodDef py_engine_backend_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_engine_backend_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_engine_backend_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.EngineBackend",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+
+ .tp_doc = ENGINE_BACKEND_DOC,
+
+ .tp_methods = py_engine_backend_methods,
+ .tp_getset = py_engine_backend_getseters,
+
+ .tp_init = py_engine_backend_init,
+ .tp_new = py_engine_backend_new,
+
+ };
+
+ return &py_engine_backend_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....EngineBackend'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_engine_backend_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ScanNamespace' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_engine_backend_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ENGINE_BACKEND, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en méthode de recherches. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_engine_backend(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_engine_backend_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to engine backend");
+ break;
+
+ case 1:
+ *((GEngineBackend **)dst) = G_ENGINE_BACKEND(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.h b/plugins/pychrysalide/analysis/scan/patterns/backend.h
new file mode 100644
index 0000000..6b1f4cd
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backend.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend.h - prototypes pour l'équivalent Python du fichier "analysis/scan/backend.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_engine_backend_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.EngineBackend'. */
+bool ensure_python_engine_backend_is_registered(void);
+
+/* Tente de convertir en méthode de recherches. */
+int convert_to_engine_backend(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am
new file mode 100644
index 0000000..cccfc2d
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am
@@ -0,0 +1,15 @@
+
+noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsbackends.la
+
+libpychrysaanalysisscanpatternsbackends_la_SOURCES = \
+ acism.h acism.c \
+ bitap.h bitap.c \
+ module.h module.c
+
+libpychrysaanalysisscanpatternsbackends_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libpychrysaanalysisscanpatternsbackends_la_SOURCES:%c=)
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c
new file mode 100644
index 0000000..56d0b55
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c
@@ -0,0 +1,214 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * acism.c - équivalent Python du fichier "analysis/scan/patterns/backends/acism.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acism.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/backends/acism-int.h>
+
+
+#include "../backend.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(acism_backend, G_TYPE_ACISM_BACKEND);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_acism_backend_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_acism_backend_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define ACISM_BACKEND_DOC \
+ "A *AcismBackend* class provide an implementation of the Aho-Corasick" \
+ " search algorithm with Interleaved State-transition Matrix (ACISM)." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " AcismBackend()" \
+ "\n" \
+ "See the relative white paper for more information:" \
+ " https://docs.google.com/document/d/1e9Qbn22__togYgQ7PNyCz3YzIIVPKvrf8PCrFa74IFM"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_acism_backend_type(void)
+{
+ static PyMethodDef py_acism_backend_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_acism_backend_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_acism_backend_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.backends.AcismBackend",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = ACISM_BACKEND_DOC,
+
+ .tp_methods = py_acism_backend_methods,
+ .tp_getset = py_acism_backend_getseters,
+
+ .tp_init = py_acism_backend_init,
+ .tp_new = py_acism_backend_new,
+
+ };
+
+ return &py_acism_backend_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....AcismBackend'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_acism_backend_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'AcismBackend'*/
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_acism_backend_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_engine_backend_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_ACISM_BACKEND, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en méthode de recherche ACISM. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_acism_backend(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_acism_backend_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ACISM backend");
+ break;
+
+ case 1:
+ *((GAcismBackend **)dst) = G_ACISM_BACKEND(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h
new file mode 100644
index 0000000..9ed61fa
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * acism.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/acism.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_acism_backend_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.AcismBackend'. */
+bool ensure_python_acism_backend_is_registered(void);
+
+/* Tente de convertir en méthode de recherche ACISM. */
+int convert_to_acism_backend(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c
new file mode 100644
index 0000000..c910f26
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c
@@ -0,0 +1,214 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bitap.c - équivalent Python du fichier "analysis/scan/patterns/backends/bitap.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "bitap.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/backends/bitap-int.h>
+
+
+#include "../backend.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(bitap_backend, G_TYPE_BITAP_BACKEND);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_bitap_backend_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_bitap_backend_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define BITAP_BACKEND_DOC \
+ "A *BitapBackend* class provide an implementation of the Bitap" \
+ " search algorithm." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " BitapBackend()" \
+ "\n" \
+ "See the relative white paper for more information:" \
+ " https://en.wikipedia.org/wiki/Bitap_algorithm"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_bitap_backend_type(void)
+{
+ static PyMethodDef py_bitap_backend_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_bitap_backend_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_bitap_backend_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.backends.BitapBackend",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = BITAP_BACKEND_DOC,
+
+ .tp_methods = py_bitap_backend_methods,
+ .tp_getset = py_bitap_backend_getseters,
+
+ .tp_init = py_bitap_backend_init,
+ .tp_new = py_bitap_backend_new,
+
+ };
+
+ return &py_bitap_backend_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....BitapBackend'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_bitap_backend_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'BitapBackend'*/
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_bitap_backend_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_engine_backend_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_BITAP_BACKEND, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en méthode de recherche BITAP. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_bitap_backend(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_bitap_backend_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Bitap backend");
+ break;
+
+ case 1:
+ *((GBitapBackend **)dst) = G_BITAP_BACKEND(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h
new file mode 100644
index 0000000..f7853d4
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bitap.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/bitap.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_bitap_backend_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.BitapBackend'. */
+bool ensure_python_bitap_backend_is_registered(void);
+
+/* Tente de convertir en méthode de recherche Bitap. */
+int convert_to_bitap_backend(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.c b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c
new file mode 100644
index 0000000..f4a0293
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c
@@ -0,0 +1,106 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire backends en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+
+
+#include "acism.h"
+#include "bitap.h"
+#include "../../../../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Ajoute le module 'analysis.....backends' à un module Python. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_analysis_scan_patterns_backends_module(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC \
+ "This module provide all the features useful for scanning" \
+ " binary contents."
+
+ static PyModuleDef py_chrysalide_analysis_scan_patterns_backends_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.analysis.scan.patterns.backends",
+ .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC,
+
+ .m_size = -1,
+
+ };
+
+ module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_backends_module);
+
+ result = (module != NULL);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'analysis....patterns.backends'.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_analysis_scan_patterns_backends_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_acism_backend_is_registered();
+ if (result) result = ensure_python_bitap_backend_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.h b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h
new file mode 100644
index 0000000..ab1aad5
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire backends en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'analysis.scan.patterns.backends' à un module Python. */
+bool add_analysis_scan_patterns_backends_module(PyObject *);
+
+/* Intègre les objets du module 'analysis.scan.patterns.backends'. */
+bool populate_analysis_scan_patterns_backends_module(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.c b/plugins/pychrysalide/analysis/scan/patterns/modifier.c
new file mode 100644
index 0000000..6547d91
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.c
@@ -0,0 +1,416 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modifier.c - équivalent Python du fichier "analysis/scan/modifier.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "modifier.h"
+
+
+#include <pygobject.h>
+
+
+#include <analysis/scan/patterns/modifier-int.h>
+
+
+#include "../../../access.h"
+#include "../../../helpers.h"
+
+
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_token_modifier, G_TYPE_SCAN_TOKEN_MODIFIER, NULL);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_token_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_token_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_TOKEN_MODIFIER_DOC \
+ "An *TokenModifier* object is the root class of all modifiers" \
+ " for byte patterns."
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = tampon de données à consulter. *
+* args = arguments fournis pour la conduite de l'opération. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Liste des nouvelle(s) séquence(s) d'octets obtenue(s). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_token_modifier_transform(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à faire remonter */
+ PyObject *py_src; /* Motifs Python en entrée */
+ PyObject *py_arg; /* Eventuel paramètre de config*/
+ sized_binary_t src; /* Entrée au format adapté */
+ Py_ssize_t len; /* Quantité de ces données */
+ int ret; /* Bilan de lecture des args. */
+ sized_binary_t *src_list; /* Entrées au format adapté */
+ size_t scount; /* Taille de cette liste */
+ bool dyn_src; /* Allocation dynamique ? */
+ Py_ssize_t size; /* Taille d'une séquence */
+ Py_ssize_t k; /* Boucle de parcours #1 */
+ PyObject *item; /* Elément de liste de motifs */
+ modifier_arg_t arg; /* Eventuelle précision */
+ GScanTokenModifier *modifier; /* Version native de l'instance*/
+ sized_binary_t *dest; /* Liste des nouvelles chaînes */
+ size_t dcount; /* Taille de cette liste */
+ bool status; /* Bilan de l'opération */
+ size_t i; /* Boucle de parcours #2 */
+
+#define SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD PYTHON_METHOD_DEF \
+( \
+ transform, "$self, data, /, arg", \
+ METH_VARARGS, py_scan_token_modifier, \
+ "Transform data from a byte pattern for an incoming scan.\n" \
+ "\n" \
+ "The data has to be provided as bytes.\n" \
+ "\n" \
+ "The method returns a tuple of transformed data as bytes, or" \
+ " *None* in case of error." \
+)
+
+ py_arg = NULL;
+
+ ret = PyArg_ParseTuple(args, "O|O", &py_src, &py_arg);
+ if (!ret) return NULL;
+
+ /* Constitution des motifs d'entrée */
+
+ if (PyBytes_Check(py_src))
+ {
+ ret = PyBytes_AsStringAndSize(py_src, &src.data, &len);
+ if (ret == -1) return NULL;
+
+ src.len = len;
+
+ src_list = &src;
+ scount = 1;
+
+ dyn_src = false;
+
+ }
+
+ else if (PySequence_Check(py_src))
+ {
+ size = PySequence_Size(py_src);
+
+ src_list = malloc(size * sizeof(sized_binary_t));
+ scount = size;
+
+ dyn_src = true;
+
+ for (k = 0; k < size; k++)
+ {
+ item = PySequence_ITEM(py_src, k);
+
+ if (PyBytes_Check(item))
+ {
+ ret = PyBytes_AsStringAndSize(item, &src_list[k].data, &len);
+ if (ret == -1) return NULL;
+
+ src_list[k].len = len;
+
+ }
+ else
+ {
+ free(src_list);
+
+ PyErr_SetString(PyExc_TypeError, "lists of items other than bytes are not supported");
+ return NULL;
+ }
+
+ }
+
+ }
+
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "only bytes and lists of bytes are expected as input for modifiers");
+ return NULL;
+ }
+
+ /* Récupération d'une éventuelle précision opérationnelle */
+
+ if (py_arg != NULL)
+ {
+ if (PyLong_Check(py_arg))
+ {
+ arg.type = MAT_UNSIGNED_INTEGER;
+ arg.value.u_integer = PyLong_AsUnsignedLongLong(py_arg);
+ }
+
+ else
+ {
+ if (dyn_src)
+ free(src_list);
+
+ PyErr_SetString(PyExc_TypeError, "unable to handle the argument type for calling a modifier");
+ return NULL;
+
+ }
+
+ }
+
+ /* Création des nouveaux motifs */
+
+ modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self));
+
+ if (py_arg == NULL)
+ status = g_scan_token_modifier_transform(modifier, src_list, scount, &dest, &dcount);
+ else
+ status = g_scan_token_modifier_transform_with_arg(modifier, src_list, scount, &arg, &dest, &dcount);
+
+ if (dyn_src)
+ free(src_list);
+
+ if (status)
+ {
+ result = PyTuple_New(dcount);
+
+ for (i = 0; i < dcount; i++)
+ {
+ PyTuple_SetItem(result, i, PyBytes_FromStringAndSize(dest[i].data, dest[i].len));
+ exit_szstr(&dest[i]);
+ }
+
+ free(dest);
+
+ }
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un composant nommé à manipuler.*
+* closure = non utilisé ici. *
+* *
+* Description : Fournit le désignation associée à un composant nommé. *
+* *
+* Retour : Description courante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_token_modifier_get_name(PyObject *self, void *closure)
+{
+ PyObject *result; /* Décompte à retourner */
+ GScanTokenModifier *modifier; /* Version native */
+ char *name; /* Désignation à convertir */
+
+#define SCAN_TOKEN_MODIFIER_NAME_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ name, py_scan_token_modifier, \
+ "Call name for the modifier.\n" \
+ "\n" \
+ "The result is a string." \
+)
+
+ modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self));
+
+ name = g_scan_token_modifier_get_name(modifier);
+
+ if (name == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else
+ {
+ result = PyUnicode_FromString(name);
+ free(name);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_token_modifier_type(void)
+{
+ static PyMethodDef py_scan_token_modifier_methods[] = {
+ SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_token_modifier_getseters[] = {
+ SCAN_TOKEN_MODIFIER_NAME_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_token_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.TokenModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_TOKEN_MODIFIER_DOC,
+
+ .tp_methods = py_scan_token_modifier_methods,
+ .tp_getset = py_scan_token_modifier_getseters,
+
+ .tp_init = py_scan_token_modifier_init,
+ .tp_new = py_scan_token_modifier_new,
+
+ };
+
+ return &py_scan_token_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....TokenModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_token_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'TokenModifier' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_token_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_TOKEN_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation de séquence d'octets. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_token_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_token_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to token modifier");
+ break;
+
+ case 1:
+ *((GScanTokenModifier **)dst) = G_SCAN_TOKEN_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.h b/plugins/pychrysalide/analysis/scan/patterns/modifier.h
new file mode 100644
index 0000000..770b2c1
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modifier.h - prototypes pour l'équivalent Python du fichier "analysis/scan/modifier.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_token_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.TokenModifier'. */
+bool ensure_python_scan_token_modifier_is_registered(void);
+
+/* Tente de convertir en transformation de séquence d'octets. */
+int convert_to_scan_token_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am
new file mode 100644
index 0000000..ae53e45
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am
@@ -0,0 +1,18 @@
+
+noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsmodifiers.la
+
+libpychrysaanalysisscanpatternsmodifiers_la_SOURCES = \
+ hex.h hex.c \
+ list.h list.c \
+ module.h module.c \
+ plain.h plain.c \
+ rev.h rev.c \
+ xor.h xor.c
+
+libpychrysaanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libpychrysaanalysisscanpatternsmodifiers_la_SOURCES:%c=)
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c
new file mode 100644
index 0000000..503580d
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "hex.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/modifiers/hex.h>
+
+
+#include "../modifier.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_hex_modifier, G_TYPE_SCAN_HEX_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_hex_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_hex_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_HEX_MODIFIER_DOC \
+ "The *HexModifier* class transforms a byte pattern into its" \
+ " corresponding byte sequence in lower case." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " HexModifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_hex_modifier_type(void)
+{
+ static PyMethodDef py_scan_hex_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_hex_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_hex_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.HexModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_HEX_MODIFIER_DOC,
+
+ .tp_methods = py_scan_hex_modifier_methods,
+ .tp_getset = py_scan_hex_modifier_getseters,
+
+ .tp_init = py_scan_hex_modifier_init,
+ .tp_new = py_scan_hex_modifier_new,
+
+ };
+
+ return &py_scan_hex_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....HexModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_hex_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'HexModifier' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_hex_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_token_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_HEX_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transmission d'octets à l'identique. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_hex_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_hex_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to hex modifier");
+ break;
+
+ case 1:
+ *((GScanHexModifier **)dst) = G_SCAN_HEX_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h
new file mode 100644
index 0000000..5d70a01
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_hex_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.HexModifier'. */
+bool ensure_python_scan_hex_modifier_is_registered(void);
+
+/* Tente de convertir en transmission d'octets à l'identique. */
+int convert_to_scan_hex_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c
new file mode 100644
index 0000000..7c77d63
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c
@@ -0,0 +1,320 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "list.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/modifiers/list.h>
+
+
+#include "../modifier.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_modifier_list, G_TYPE_SCAN_MODIFIER_LIST);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_modifier_list_init(PyObject *, PyObject *, PyObject *);
+
+/* Intègre un nouveau transformateur dans une liste. */
+static PyObject *py_scan_modifier_list_add(PyObject *, PyObject *);
+
+/* Fournit les transformateurs associés à la liste. */
+static PyObject *py_scan_modifier_list_get_modifiers(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_modifier_list_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_MODIFIER_LIST_DOC \
+ "The *ModifierList* class is a special modifier which groups a list of" \
+ " modifiers for byte patterns." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " ModifierList()" \
+ "\n" \
+ "The keyword for such a modifier is *(list)*."
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = projet d'étude à manipuler. *
+* args = arguments accompagnant l'appel. *
+* *
+* Description : Intègre un nouveau transformateur dans une liste. *
+* *
+* Retour : Bilan de l'ajout : False si un élément similaire est déjà là.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_modifier_list_add(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Absence de retour Python */
+ GScanTokenModifier *modifier; /* Modificateur à intégrer */
+ int ret; /* Bilan de lecture des args. */
+ GScanModifierList *list; /* Version GLib du type */
+ bool status; /* Bilan de l'opération */
+
+#define SCAN_MODIFIER_LIST_ADD_METHOD PYTHON_METHOD_DEF \
+( \
+ add, "$self, modifier, /", \
+ METH_VARARGS, py_scan_modifier_list, \
+ "Add an extra modifier to the list.\n" \
+ "\n" \
+ "This *modifier* parameter has to be a" \
+ " pychrysalide.analysis.scan.patterns.TokenModifier instance." \
+ "\n" \
+ "The function returns *True* if the provided modifier did not already" \
+ " exist in the list, *False* otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_scan_token_modifier, &modifier);
+ if (!ret) return NULL;
+
+ list = G_SCAN_MODIFIER_LIST(pygobject_get(self));
+
+ status = g_scan_modifier_list_add(list, modifier);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit les transformateurs associés à la liste. *
+* *
+* Retour : Liste de modificateurs de séquence d'octets. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_modifier_list_get_modifiers(PyObject *self, void *closure)
+{
+ PyObject *result; /* Résultat à retourner */
+ GScanModifierList *list; /* Version GLib du type */
+ size_t count; /* Nombre de transformateurs */
+ size_t i; /* Boucle de parcours */
+ GScanTokenModifier *modifier; /* Modificateur de la liste */
+
+#define SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ modifiers, py_scan_modifier_list, \
+ "List of all modifiers contained in a list.\n" \
+ "\n" \
+ "The returned value is a tuple of pychrysalide.analysis.scan.patterns.TokenModifier" \
+ " instances." \
+)
+
+ list = G_SCAN_MODIFIER_LIST(pygobject_get(self));
+
+ count = g_scan_modifier_list_count(list);
+
+ result = PyTuple_New(count);
+
+ for (i = 0; i < count; i++)
+ {
+ modifier = g_scan_modifier_list_get(list, i);
+
+ PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(modifier)));
+
+ g_object_unref(modifier);
+
+ }
+
+ return result;
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_modifier_list_type(void)
+{
+ static PyMethodDef py_scan_modifier_list_methods[] = {
+ SCAN_MODIFIER_LIST_ADD_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_modifier_list_getseters[] = {
+ SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_modifier_list_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ModifierList",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_MODIFIER_LIST_DOC,
+
+ .tp_methods = py_scan_modifier_list_methods,
+ .tp_getset = py_scan_modifier_list_getseters,
+
+ .tp_init = py_scan_modifier_list_init,
+ .tp_new = py_scan_modifier_list_new,
+
+ };
+
+ return &py_scan_modifier_list_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....ModifierList'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_modifier_list_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ModifierList' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_modifier_list_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_token_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_MODIFIER_LIST, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en liste de transormations d'octets. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_modifier_list(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_modifier_list_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to modifier list");
+ break;
+
+ case 1:
+ *((GScanModifierList **)dst) = G_SCAN_MODIFIER_LIST(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h
new file mode 100644
index 0000000..133de8d
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_modifier_list_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ModifierList'. */
+bool ensure_python_scan_modifier_list_is_registered(void);
+
+/* Tente de convertir en liste de transormations d'octets. */
+int convert_to_scan_modifier_list(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c
new file mode 100644
index 0000000..ae450dc
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c
@@ -0,0 +1,112 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire modifiers en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+
+
+#include "hex.h"
+#include "list.h"
+#include "plain.h"
+#include "rev.h"
+#include "xor.h"
+#include "../../../../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Ajoute le module 'analysis....modifiers' à un module Python. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_analysis_scan_patterns_modifiers_module(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC \
+ "This module provide all the features useful for scanning" \
+ " binary contents."
+
+ static PyModuleDef py_chrysalide_analysis_scan_patterns_modifiers_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.analysis.scan.patterns.modifiers",
+ .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC,
+
+ .m_size = -1,
+
+ };
+
+ module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_modifiers_module);
+
+ result = (module != NULL);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'analysis...patterns.modifiers'.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_analysis_scan_patterns_modifiers_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_scan_hex_modifier_is_registered();
+ if (result) result = ensure_python_scan_modifier_list_is_registered();
+ if (result) result = ensure_python_scan_plain_modifier_is_registered();
+ if (result) result = ensure_python_scan_reverse_modifier_is_registered();
+ if (result) result = ensure_python_scan_xor_modifier_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h
new file mode 100644
index 0000000..8094efc
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire modifiers en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'analysis.scan.patterns.modifiers' à un module Python. */
+bool add_analysis_scan_patterns_modifiers_module(PyObject *);
+
+/* Intègre les objets du module 'analysis.scan.patterns.modifiers'. */
+bool populate_analysis_scan_patterns_modifiers_module(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c
new file mode 100644
index 0000000..7a260c1
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "plain.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/modifiers/plain.h>
+
+
+#include "../modifier.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_plain_modifier, G_TYPE_SCAN_PLAIN_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_plain_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_plain_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_PLAIN_MODIFIER_DOC \
+ "The *PlainModifier* class provide an transmision of a byte pattern" \
+ " without any modification." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " PlainModifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_plain_modifier_type(void)
+{
+ static PyMethodDef py_scan_plain_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_plain_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_plain_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.PlainModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_PLAIN_MODIFIER_DOC,
+
+ .tp_methods = py_scan_plain_modifier_methods,
+ .tp_getset = py_scan_plain_modifier_getseters,
+
+ .tp_init = py_scan_plain_modifier_init,
+ .tp_new = py_scan_plain_modifier_new,
+
+ };
+
+ return &py_scan_plain_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....PlainModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_plain_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'PlainModifier' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_plain_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_token_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_PLAIN_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transmission d'octets à l'identique. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_plain_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_plain_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to plain modifier");
+ break;
+
+ case 1:
+ *((GScanPlainModifier **)dst) = G_SCAN_PLAIN_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h
new file mode 100644
index 0000000..03949d8
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_plain_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.PlainModifier'. */
+bool ensure_python_scan_plain_modifier_is_registered(void);
+
+/* Tente de convertir en transmission d'octets à l'identique. */
+int convert_to_scan_plain_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c
new file mode 100644
index 0000000..841e929
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "rev.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/modifiers/rev.h>
+
+
+#include "../modifier.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_reverse_modifier, G_TYPE_SCAN_REVERSE_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_reverse_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_reverse_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_HEX_MODIFIER_DOC \
+ "The *ReverseModifier* class transforms a byte pattern by reversing" \
+ " the order of each bytes." \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " ReverseModifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_reverse_modifier_type(void)
+{
+ static PyMethodDef py_scan_reverse_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_reverse_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_reverse_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_HEX_MODIFIER_DOC,
+
+ .tp_methods = py_scan_reverse_modifier_methods,
+ .tp_getset = py_scan_reverse_modifier_getseters,
+
+ .tp_init = py_scan_reverse_modifier_init,
+ .tp_new = py_scan_reverse_modifier_new,
+
+ };
+
+ return &py_scan_reverse_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....ReverseModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_reverse_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python ReverseModifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_reverse_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_token_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_REVERSE_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation d'octets par inverse. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_reverse_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_reverse_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to reverse modifier");
+ break;
+
+ case 1:
+ *((GScanReverseModifier **)dst) = G_SCAN_REVERSE_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h
new file mode 100644
index 0000000..fe10e1e
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rev.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/rev.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_reverse_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier'. */
+bool ensure_python_scan_reverse_modifier_is_registered(void);
+
+/* Tente de convertir en transformation d'octets par inverse. */
+int convert_to_scan_reverse_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c
new file mode 100644
index 0000000..17a32f4
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c
@@ -0,0 +1,210 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * xor.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/xor.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "xor.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/modifiers/xor.h>
+
+
+#include "../modifier.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_xor_modifier, G_TYPE_SCAN_XOR_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_xor_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_xor_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SCAN_XOR_MODIFIER_DOC \
+ "The *XorModifier* class transforms a byte pattern by XORing bytes.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " XorModifier()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_xor_modifier_type(void)
+{
+ static PyMethodDef py_scan_xor_modifier_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_xor_modifier_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_xor_modifier_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.XorModifier",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_XOR_MODIFIER_DOC,
+
+ .tp_methods = py_scan_xor_modifier_methods,
+ .tp_getset = py_scan_xor_modifier_getseters,
+
+ .tp_init = py_scan_xor_modifier_init,
+ .tp_new = py_scan_xor_modifier_new,
+
+ };
+
+ return &py_scan_xor_modifier_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....XorModifier'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_xor_modifier_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python XorModifier */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_xor_modifier_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_python_scan_token_modifier_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_XOR_MODIFIER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en transformation d'octets par inverse. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_xor_modifier(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_xor_modifier_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to XOR modifier");
+ break;
+
+ case 1:
+ *((GScanXorModifier **)dst) = G_SCAN_XOR_MODIFIER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h
new file mode 100644
index 0000000..7b9bb69
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * xor.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/xor.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_xor_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.XorModifier'. */
+bool ensure_python_scan_xor_modifier_is_registered(void);
+
+/* Tente de convertir en transformation d'octets par inverse. */
+int convert_to_scan_xor_modifier(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H */
diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.c b/plugins/pychrysalide/analysis/scan/patterns/module.c
new file mode 100644
index 0000000..123b23a
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/module.c
@@ -0,0 +1,114 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire patterns en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "module.h"
+
+
+#include <assert.h>
+
+
+#include "backend.h"
+#include "modifier.h"
+#include "backends/module.h"
+#include "modifiers/module.h"
+#include "../../../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Ajoute le module 'analysis.scan.patterns' à un module Python.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_analysis_scan_patterns_module(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC \
+ "This module provide all the features useful for scanning" \
+ " binary contents."
+
+ static PyModuleDef py_chrysalide_analysis_scan_patterns_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.analysis.scan.patterns",
+ .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC,
+
+ .m_size = -1,
+
+ };
+
+ module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_module);
+
+ result = (module != NULL);
+
+ if (result) result = add_analysis_scan_patterns_backends_module(module);
+ if (result) result = add_analysis_scan_patterns_modifiers_module(module);
+
+ if (!result)
+ Py_XDECREF(module);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'analysis.scan.patterns'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_analysis_scan_patterns_module(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_engine_backend_is_registered();
+ if (result) result = ensure_python_scan_token_modifier_is_registered();
+
+ if (result) result = populate_analysis_scan_patterns_backends_module();
+ if (result) result = populate_analysis_scan_patterns_modifiers_module();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.h b/plugins/pychrysalide/analysis/scan/patterns/module.h
new file mode 100644
index 0000000..bc25129
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/module.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire patterns en tant que module
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'analysis.scan.patterns' à un module Python. */
+bool add_analysis_scan_patterns_module(PyObject *);
+
+/* Intègre les objets du module 'analysis.scan.patterns'. */
+bool populate_analysis_scan_patterns_module(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H */
diff --git a/plugins/pychrysalide/analysis/scan/scanner.c b/plugins/pychrysalide/analysis/scan/scanner.c
new file mode 100644
index 0000000..bc58c9a
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/scanner.c
@@ -0,0 +1,487 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scanner.c - équivalent Python du fichier "analysis/scan/scanner.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "scanner.h"
+
+
+#include <malloc.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/content.h>
+#include <analysis/scan/context.h>
+#include <analysis/scan/scanner-int.h>
+
+
+#include "context.h"
+#include "options.h"
+#include "../content.h"
+#include "../../access.h"
+#include "../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(content_scanner, G_TYPE_CONTENT_SCANNER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_content_scanner_init(PyObject *, PyObject *, PyObject *);
+
+/* Lance une analyse d'un contenu binaire. */
+static PyObject *py_content_scanner_analyze(PyObject *, PyObject *);
+
+/* Convertit un gestionnaire de recherches en JSON. */
+static PyObject *py_content_scanner_convert_to_json(PyObject *, PyObject *);
+
+/* Indique le chemin d'un éventuel fichier de source. */
+static PyObject *py_content_scanner_get_filename(PyObject *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_content_scanner_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ const char *text; /* Contenu de règles à traiter */
+ Py_ssize_t len; /* Taille de ce nom */
+ const char *filename; /* Fichier de définitions */
+ int ret; /* Bilan de lecture des args. */
+ GContentScanner *scanner; /* Création GLib à transmettre */
+
+ static char *kwlist[] = { "text", "filename", NULL };
+
+#define CONTENT_SCANNER_DOC \
+ "A ContentScanner object provides support for rules processing" \
+ " against binary contents.\n" \
+ "\n" \
+ "Instances can be created using one of the following" \
+ " constructors:\n" \
+ "\n" \
+ " ContentScanner(text=str)" \
+ "\n" \
+ " ContentScanner(filename=str)" \
+ "\n" \
+ "Where *text* is a string for the rules definitions and" \
+ " *filename* an alternative string for a path pointing to a" \
+ " definition file."
+
+ /* Récupération des paramètres */
+
+ text = NULL;
+ len = 0;
+ filename = NULL;
+
+ ret = PyArg_ParseTupleAndKeywords(args, kwds, "|s#s", kwlist, &text, &len, &filename);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ scanner = G_CONTENT_SCANNER(pygobject_get(self));
+
+ if (text != NULL)
+ {
+ if (!g_content_scanner_create_from_text(scanner, text, len))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner."));
+ return -1;
+ }
+
+ }
+
+ else if (filename != NULL)
+ {
+ if (!g_content_scanner_create_from_file(scanner, filename))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner."));
+ return -1;
+ }
+
+ }
+
+ else
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create empty content scanner."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Lance une analyse d'un contenu binaire. *
+* *
+* Retour : Contexte de suivi pour l'analyse menée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_content_scanner_analyze(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Contexte de suivi à renvoyer*/
+ GScanOptions *options; /* Paramètres d'analyse */
+ GBinContent *content; /* Contenu binaire à traiter */
+ int ret; /* Bilan de lecture des args. */
+ GContentScanner *scanner; /* Encadrement de recherche */
+ GScanContext *context; /* Contexte de suivi */
+
+#define CONTENT_SCANNER_ANALYZE_METHOD PYTHON_METHOD_DEF \
+( \
+ analyze, "$self, options, content, /", \
+ METH_VARARGS, py_content_scanner, \
+ "Run a scan against a binary content.\n" \
+ "\n" \
+ "The *content* argument is a pychrysalide.analysis.BinContent" \
+ " object pointing to data to analyze.\n" \
+ "\n" \
+ "The method returns a pychrysalide.analysis.scan.ScanContext" \
+ " object tracking all the scan results." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&O&", convert_to_scan_options, &options, convert_to_binary_content, &content);
+ if (!ret) return NULL;
+
+ scanner = G_CONTENT_SCANNER(pygobject_get(self));
+
+ context = g_content_scanner_analyze(scanner, options, content);
+
+ result = pygobject_new(G_OBJECT(context));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Convertit un gestionnaire de recherches en texte. *
+* *
+* Retour : Données textuelles ou None en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_content_scanner_convert_to_text(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Contexte de suivi à renvoyer*/
+ GScanContext *context; /* Contexte d'analyse */
+ int ret; /* Bilan de lecture des args. */
+ GContentScanner *scanner; /* Encadrement de recherche */
+ char *out; /* Données en sortie */
+
+#define CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD PYTHON_METHOD_DEF \
+( \
+ convert_to_text, "$self, context, /", \
+ METH_VARARGS, py_content_scanner, \
+ "Output a scan results as text.\n" \
+ "\n" \
+ "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \
+ " instance provided by a previous call to *self.analyze()*. This" \
+ " context stores all the scan results.\n" \
+ "\n" \
+ "The method returns a string value, or *None* in case of failure." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context);
+ if (!ret) return NULL;
+
+ scanner = G_CONTENT_SCANNER(pygobject_get(self));
+
+ out = g_content_scanner_convert_to_text(scanner, context);
+
+ if (out != NULL)
+ {
+ result = PyUnicode_FromString(out);
+ free(out);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Convertit un gestionnaire de recherches en JSON. *
+* *
+* Retour : Données textuelles au format JSON ou None en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_content_scanner_convert_to_json(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Contexte de suivi à renvoyer*/
+ GScanContext *context; /* Contexte d'analyse */
+ int ret; /* Bilan de lecture des args. */
+ GContentScanner *scanner; /* Encadrement de recherche */
+ char *out; /* Données en sortie */
+
+#define CONTENT_SCANNER_CONVERT_TO_JSON_METHOD PYTHON_METHOD_DEF \
+( \
+ convert_to_json, "$self, context, /", \
+ METH_VARARGS, py_content_scanner, \
+ "Output a scan results as JSON data.\n" \
+ "\n" \
+ "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \
+ " instance provided by a previous call to *self.analyze()*. This" \
+ " context stores all the scan results.\n" \
+ "\n" \
+ "The method returns JSON data as a string value, or *None* in case" \
+ " of failure." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context);
+ if (!ret) return NULL;
+
+ scanner = G_CONTENT_SCANNER(pygobject_get(self));
+
+ out = g_content_scanner_convert_to_json(scanner, context);
+
+ if (out != NULL)
+ {
+ result = PyUnicode_FromString(out);
+ free(out);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique le chemin d'un éventuel fichier de source. *
+* *
+* Retour : Chemin d'un éventuel fichier de définitions ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_content_scanner_get_filename(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GContentScanner *scanner; /* Analyseur à consulter */
+ const char *filename; /* Chemin d'accès à transmettre*/
+
+#define CONTENT_SCANNER_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ filename, py_content_scanner, \
+ "Provide the access path to the source file of the rules'" \
+ " definition, or *None* if these rules have not been loaded"\
+ " from memory." \
+)
+
+ scanner = G_CONTENT_SCANNER(pygobject_get(self));
+
+ filename = g_content_scanner_get_filename(scanner);
+
+ if (filename != NULL)
+ result = PyUnicode_FromString(filename);
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_content_scanner_type(void)
+{
+ static PyMethodDef py_content_scanner_methods[] = {
+ CONTENT_SCANNER_ANALYZE_METHOD,
+ CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD,
+ CONTENT_SCANNER_CONVERT_TO_JSON_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_content_scanner_getseters[] = {
+ CONTENT_SCANNER_FILENAME_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_content_scanner_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.ContentScanner",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = CONTENT_SCANNER_DOC,
+
+ .tp_methods = py_content_scanner_methods,
+ .tp_getset = py_content_scanner_getseters,
+
+ .tp_init = py_content_scanner_init,
+ .tp_new = py_content_scanner_new,
+
+ };
+
+ return &py_content_scanner_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide...scan.ContentScanner. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_content_scanner_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ContentScanner'*/
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_content_scanner_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_SCANNER, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en scanner de contenus binaires. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_content_scanner(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_content_scanner_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to content scanner");
+ break;
+
+ case 1:
+ *((GContentScanner **)dst) = G_CONTENT_SCANNER(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/scanner.h b/plugins/pychrysalide/analysis/scan/scanner.h
new file mode 100644
index 0000000..b3b1baf
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/scanner.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scanner.h - prototypes pour l'équivalent Python du fichier "analysis/scan/scanner.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_content_scanner_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.ContentScanner'. */
+bool ensure_python_content_scanner_is_registered(void);
+
+/* Tente de convertir en scanner de contenus binaires. */
+int convert_to_content_scanner(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H */
diff --git a/plugins/pychrysalide/analysis/scan/space.c b/plugins/pychrysalide/analysis/scan/space.c
new file mode 100644
index 0000000..6ea87b8
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/space.c
@@ -0,0 +1,283 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space.c - équivalent Python du fichier "analysis/scan/space.c"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "space.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/content.h>
+#include <analysis/scan/item.h>
+#include <analysis/scan/space-int.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+
+
+#include "item.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_namespace, G_TYPE_SCAN_NAMESPACE);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_namespace_init(PyObject *, PyObject *, PyObject *);
+
+/* Intègre un nouvel élément dans l'esapce de noms. */
+static PyObject *py_scan_namespace_register_item(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_scan_namespace_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ const char *name; /* Désignation de l'espace */
+ int ret; /* Bilan de lecture des args. */
+ GScanNamespace *space; /* Création GLib à transmettre */
+
+#define SCAN_NAMESPACE_DOC \
+ "ScanNamespace defines a group of properties and functions for a" \
+ " given scan theme.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " ScanNamespace(name)" \
+ "\n" \
+ "Where *name* is a string providing the name of the new namespace."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "s", &name);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Elément de base */
+
+ space = G_SCAN_NAMESPACE(pygobject_get(self));
+
+ if (!g_scan_namespace_create(space, name))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create scan namespace."));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet représentant une table de chaînes. *
+* args = arguments fournis pour l'opération. *
+* *
+* Description : Intègre un nouvel élément dans l'esapce de noms. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_scan_namespace_register_item(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ GScanRegisteredItem *item; /* Elément d'évaluation à lier */
+ int ret; /* Bilan de lecture des args. */
+ GScanNamespace *space; /* Version native */
+ bool status; /* Bilan de l'opération */
+
+#define SCAN_NAMESPACE_REGISTER_ITEM_METHOD PYTHON_METHOD_DEF \
+( \
+ register_item, "$self, item, /", \
+ METH_VARARGS, py_scan_namespace, \
+ "Include an item into a namespace.\n" \
+ "\n" \
+ "The *item* argument has to be a pychrysalide.analysis.scan.RegisteredItem" \
+ " instance.\n" \
+ "\n" \
+ "The function returns a boolean value translating the operation status:" \
+ " *True* in case of success, *False* for a failure.\n" \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_scan_registered_item, &item);
+ if (!ret) return NULL;
+
+ space = G_SCAN_NAMESPACE(pygobject_get(self));
+
+ status = g_scan_namespace_register_item(space, item);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_namespace_type(void)
+{
+ static PyMethodDef py_scan_namespace_methods[] = {
+ SCAN_NAMESPACE_REGISTER_ITEM_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_scan_namespace_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_scan_namespace_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.analysis.scan.ScanNamespace",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SCAN_NAMESPACE_DOC,
+
+ .tp_methods = py_scan_namespace_methods,
+ .tp_getset = py_scan_namespace_getseters,
+
+ .tp_init = py_scan_namespace_init,
+ .tp_new = py_scan_namespace_new,
+
+ };
+
+ return &py_scan_namespace_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide...scan.ScanNamespace'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_scan_namespace_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ScanNamespace' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_scan_namespace_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.analysis.scan");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SCAN_NAMESPACE, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en espace de noms pour scan. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_scan_namespace(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_namespace_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan namespace");
+ break;
+
+ case 1:
+ *((GScanNamespace **)dst) = G_SCAN_NAMESPACE(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/space.h b/plugins/pychrysalide/analysis/scan/space.h
new file mode 100644
index 0000000..0166c04
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/space.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space.h - prototypes pour l'équivalent Python du fichier "analysis/scan/space.h"
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_namespace_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanNamespace'. */
+bool ensure_python_scan_namespace_is_registered(void);
+
+/* Tente de convertir en espace de noms pour scan. */
+int convert_to_scan_namespace(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H */
diff --git a/plugins/pychrysalide/analysis/storage/Makefile.am b/plugins/pychrysalide/analysis/storage/Makefile.am
index fdf2666..d0a4df4 100644
--- a/plugins/pychrysalide/analysis/storage/Makefile.am
+++ b/plugins/pychrysalide/analysis/storage/Makefile.am
@@ -9,19 +9,10 @@ libpychrysaanalysisstorage_la_SOURCES = \
storage.h storage.c \
tpmem.h tpmem.c
-libpychrysaanalysisstorage_la_LIBADD =
-
-libpychrysaanalysisstorage_la_LDFLAGS =
+libpychrysaanalysisstorage_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaanalysisstorage_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/analysis/storage/cache.c b/plugins/pychrysalide/analysis/storage/cache.c
index 9859623..8cd5bac 100644
--- a/plugins/pychrysalide/analysis/storage/cache.c
+++ b/plugins/pychrysalide/analysis/storage/cache.c
@@ -100,7 +100,7 @@ static PyObject *py_object_cache_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -304,7 +304,7 @@ bool ensure_python_object_cache_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_CACHE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_CACHE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/storage/storage.c b/plugins/pychrysalide/analysis/storage/storage.c
index 7c03be0..c54fe0f 100644
--- a/plugins/pychrysalide/analysis/storage/storage.c
+++ b/plugins/pychrysalide/analysis/storage/storage.c
@@ -115,7 +115,7 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -601,7 +601,7 @@ bool ensure_python_object_storage_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_STORAGE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_STORAGE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/storage/tpmem.c b/plugins/pychrysalide/analysis/storage/tpmem.c
index 491ee68..ae07008 100644
--- a/plugins/pychrysalide/analysis/storage/tpmem.c
+++ b/plugins/pychrysalide/analysis/storage/tpmem.c
@@ -108,7 +108,7 @@ static PyObject *py_type_memory_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -453,7 +453,7 @@ bool ensure_python_type_memory_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_TYPE_MEMORY, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_TYPE_MEMORY, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/type.c b/plugins/pychrysalide/analysis/type.c
index 357d381..ea8affd 100644
--- a/plugins/pychrysalide/analysis/type.c
+++ b/plugins/pychrysalide/analysis/type.c
@@ -158,7 +158,7 @@ static PyObject *py_data_type_new(PyTypeObject *type, PyObject *args, PyObject *
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -1125,7 +1125,7 @@ bool ensure_python_data_type_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_DATA_TYPE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_DATA_TYPE, type))
return false;
if (!define_analysis_data_type_constants(type))
diff --git a/plugins/pychrysalide/analysis/types/Makefile.am b/plugins/pychrysalide/analysis/types/Makefile.am
index d13fe0c..697c998 100644
--- a/plugins/pychrysalide/analysis/types/Makefile.am
+++ b/plugins/pychrysalide/analysis/types/Makefile.am
@@ -1,30 +1,23 @@
noinst_LTLIBRARIES = libpychrysaanalysistypes.la
-libpychrysaanalysistypes_la_SOURCES = \
- array.h array.c \
- basic.h basic.c \
- constants.h constants.c \
- cse.h cse.c \
- encaps.h encaps.c \
- expr.h expr.c \
- literal.h literal.c \
- module.h module.c \
- override.h override.c \
- proto.h proto.c \
+libpychrysaanalysistypes_la_SOURCES = \
+ array.h array.c \
+ basic.h basic.c \
+ constants.h constants.c \
+ cse.h cse.c \
+ encaps.h encaps.c \
+ expr.h expr.c \
+ literal.h literal.c \
+ module.h module.c \
+ override.h override.c \
+ proto.h proto.c \
template.h template.c
-libpychrysaanalysistypes_la_LDFLAGS =
+libpychrysaanalysistypes_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaanalysistypes_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/analysis/types/array.c b/plugins/pychrysalide/analysis/types/array.c
index 8055316..88b773e 100644
--- a/plugins/pychrysalide/analysis/types/array.c
+++ b/plugins/pychrysalide/analysis/types/array.c
@@ -423,7 +423,7 @@ bool ensure_python_array_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_ARRAY_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_ARRAY_TYPE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/types/basic.c b/plugins/pychrysalide/analysis/types/basic.c
index 9ae4f8f..19fb9d1 100644
--- a/plugins/pychrysalide/analysis/types/basic.c
+++ b/plugins/pychrysalide/analysis/types/basic.c
@@ -210,7 +210,7 @@ bool ensure_python_basic_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_BASIC_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_BASIC_TYPE, type))
return false;
if (!define_basic_type_constants(type))
diff --git a/plugins/pychrysalide/analysis/types/cse.c b/plugins/pychrysalide/analysis/types/cse.c
index 7701d48..0aab4d9 100644
--- a/plugins/pychrysalide/analysis/types/cse.c
+++ b/plugins/pychrysalide/analysis/types/cse.c
@@ -262,7 +262,7 @@ bool ensure_python_class_enum_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_CLASS_ENUM_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_CLASS_ENUM_TYPE, type))
return false;
if (!define_class_enum_type_constants(type))
diff --git a/plugins/pychrysalide/analysis/types/encaps.c b/plugins/pychrysalide/analysis/types/encaps.c
index 3a5acb5..bc9f4db 100644
--- a/plugins/pychrysalide/analysis/types/encaps.c
+++ b/plugins/pychrysalide/analysis/types/encaps.c
@@ -223,7 +223,7 @@ bool ensure_python_encapsulated_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_ENCAPSULATED_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_ENCAPSULATED_TYPE, type))
return false;
if (!define_encapsulated_type_constants(type))
diff --git a/plugins/pychrysalide/analysis/types/expr.c b/plugins/pychrysalide/analysis/types/expr.c
index 02cb02f..e3b2b0a 100644
--- a/plugins/pychrysalide/analysis/types/expr.c
+++ b/plugins/pychrysalide/analysis/types/expr.c
@@ -201,7 +201,7 @@ bool ensure_python_expr_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_EXPR_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_EXPR_TYPE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/types/literal.c b/plugins/pychrysalide/analysis/types/literal.c
index e00104f..3d9d5e3 100644
--- a/plugins/pychrysalide/analysis/types/literal.c
+++ b/plugins/pychrysalide/analysis/types/literal.c
@@ -136,7 +136,7 @@ bool ensure_python_literal_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_LITERAL_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_LITERAL_TYPE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/types/override.c b/plugins/pychrysalide/analysis/types/override.c
index 896163f..236a34c 100644
--- a/plugins/pychrysalide/analysis/types/override.c
+++ b/plugins/pychrysalide/analysis/types/override.c
@@ -247,7 +247,7 @@ bool ensure_python_override_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_OVERRIDE_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_OVERRIDE_TYPE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/types/proto.c b/plugins/pychrysalide/analysis/types/proto.c
index 7c3ebed..1da3119 100644
--- a/plugins/pychrysalide/analysis/types/proto.c
+++ b/plugins/pychrysalide/analysis/types/proto.c
@@ -349,7 +349,7 @@ bool ensure_python_proto_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_PROTO_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_PROTO_TYPE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/types/template.c b/plugins/pychrysalide/analysis/types/template.c
index 6fc50e4..68f390a 100644
--- a/plugins/pychrysalide/analysis/types/template.c
+++ b/plugins/pychrysalide/analysis/types/template.c
@@ -345,7 +345,7 @@ bool ensure_python_template_type_is_registered(void)
if (!ensure_python_data_type_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_TEMPLATE_TYPE, type, get_python_data_type_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_TEMPLATE_TYPE, type))
return false;
}
diff --git a/plugins/pychrysalide/analysis/variable.c b/plugins/pychrysalide/analysis/variable.c
index 3aeddf4..5f8d490 100644
--- a/plugins/pychrysalide/analysis/variable.c
+++ b/plugins/pychrysalide/analysis/variable.c
@@ -266,7 +266,7 @@ bool ensure_python_binary_variable_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BIN_VARIABLE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BIN_VARIABLE, type))
return false;
}
diff --git a/plugins/pychrysalide/arch/Makefile.am b/plugins/pychrysalide/arch/Makefile.am
index b934412..c113f6e 100644
--- a/plugins/pychrysalide/arch/Makefile.am
+++ b/plugins/pychrysalide/arch/Makefile.am
@@ -1,22 +1,23 @@
noinst_LTLIBRARIES = libpychrysaarch.la
-libpychrysaarch_la_SOURCES = \
- constants.h constants.c \
- context.h context.c \
- instriter.h instriter.c \
- instruction.h instruction.c \
- module.h module.c \
- operand.h operand.c \
- processor.h processor.c \
- register.h register.c \
+libpychrysaarch_la_SOURCES = \
+ constants.h constants.c \
+ context.h context.c \
+ instriter.h instriter.c \
+ instruction.h instruction.c \
+ module.h module.c \
+ operand.h operand.c \
+ processor.h processor.c \
+ register.h register.c \
vmpa.h vmpa.c
-libpychrysaarch_la_LIBADD = \
+libpychrysaarch_la_LIBADD = \
instructions/libpychrysaarchinstructions.la \
operands/libpychrysaarchoperands.la
-libpychrysaarch_la_LDFLAGS =
+libpychrysaarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
@@ -24,9 +25,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaarch_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = instructions operands
diff --git a/plugins/pychrysalide/arch/context.c b/plugins/pychrysalide/arch/context.c
index ce1ef01..79c782f 100644
--- a/plugins/pychrysalide/arch/context.c
+++ b/plugins/pychrysalide/arch/context.c
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * context.c - équivalent Python du fichier "arch/context.h"
+ * context.c - équivalent Python du fichier "arch/context.c"
*
* Copyright (C) 2018 Cyrille Bagard
*
@@ -39,6 +39,7 @@
#include "../helpers.h"
#include "../analysis/db/item.h"
#include "../arch/vmpa.h"
+#include "../format/preload.h"
@@ -120,7 +121,7 @@ static PyObject *py_proc_context_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -518,7 +519,10 @@ bool ensure_python_proc_context_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_PROC_CONTEXT, type, &PyGObject_Type))
+ if (!ensure_python_preload_info_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_PROC_CONTEXT, type))
return false;
if (!define_proc_context_constants(type))
diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c
index 3606cfe..0a9ba16 100644
--- a/plugins/pychrysalide/arch/instruction.c
+++ b/plugins/pychrysalide/arch/instruction.c
@@ -45,52 +45,7 @@
-/* -------------------- INTERFACE INTERNE POUR EXTENSIONS PYTHON -------------------- */
-
-
-/* Définition générique d'une instruction d'architecture (instance) */
-typedef struct _GPyArchInstruction
-{
- GArchInstruction parent; /* A laisser en premier */
-
- char *cached_keyword; /* Conservation de constante */
-
-} GPyArchInstruction;
-
-
-/* Définition générique d'une instruction d'architecture (classe) */
-typedef struct _GPyArchInstructionClass
-{
- GArchInstructionClass parent; /* A laisser en premier */
-
-} GPyArchInstructionClass;
-
-
-#define G_TYPE_PYARCH_INSTRUCTION g_pyarch_instruction_get_type()
-#define G_PYARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstruction))
-#define G_IS_PYTHON_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYARCH_INSTRUCTION))
-#define G_PYARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass))
-#define G_IS_PYTHON_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYARCH_INSTRUCTION))
-#define G_PYARCH_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass))
-
-
-/* Indique le type défini pour une instruction d'architecture en Python. */
-GType g_pyarch_instruction_get_type(void);
-
-/* Initialise la classe générique des instructions en Python. */
-static void g_pyarch_instruction_class_init(GPyArchInstructionClass *);
-
-/* Initialise une instance d'opérande d'architecture. */
-static void g_pyarch_instruction_init(GPyArchInstruction *);
-
-/* Supprime toutes les références externes. */
-static void g_pyarch_instruction_dispose(GPyArchInstruction *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_pyarch_instruction_finalize(GPyArchInstruction *);
-
-/* Fournit le nom humain de l'instruction manipulée. */
-static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *);
+static G_DEFINE_QUARK(cached_keyword, get_cached_keyword);
@@ -101,11 +56,16 @@ static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *);
static PyObject *py_arch_instruction_new(PyTypeObject *, PyObject *, PyObject *);
/* Initialise la classe générique des instructions. */
-static void py_arch_instruction_init_gclass(GPyArchInstructionClass *, gpointer);
+static void py_arch_instruction_init_gclass(GArchInstructionClass *, gpointer);
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_instruction, G_TYPE_ARCH_INSTRUCTION, py_arch_instruction_init_gclass);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_arch_instruction_init(PyObject *, PyObject *, PyObject *);
+/* Fournit le nom humain de l'instruction manipulée. */
+static const char *py_arch_instruction_get_class_keyword(GArchInstruction *);
+
/* --------------------------- MANIPULATION DES OPERANDES --------------------------- */
@@ -160,19 +120,16 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *, void *);
/* ---------------------------------------------------------------------------------- */
-/* INTERFACE INTERNE POUR EXTENSIONS PYTHON */
+/* GLUE POUR CREATION DEPUIS PYTHON */
/* ---------------------------------------------------------------------------------- */
-/* Indique le type défini pour une instruction d'architecture en Python. */
-G_DEFINE_TYPE(GPyArchInstruction, g_pyarch_instruction, G_TYPE_ARCH_INSTRUCTION);
-
-
/******************************************************************************
* *
-* Paramètres : klass = classe à initialiser. *
+* Paramètres : class = classe à initialiser. *
+* unused = données non utilisées ici. *
* *
-* Description : Initialise la classe générique des instructions en Python. *
+* Description : Initialise la classe générique des instructions. *
* *
* Retour : - *
* *
@@ -180,78 +137,62 @@ G_DEFINE_TYPE(GPyArchInstruction, g_pyarch_instruction, G_TYPE_ARCH_INSTRUCTION)
* *
******************************************************************************/
-static void g_pyarch_instruction_class_init(GPyArchInstructionClass *klass)
+static void py_arch_instruction_init_gclass(GArchInstructionClass *class, gpointer unused)
{
- GObjectClass *object; /* Autre version de la classe */
GArchInstructionClass *instr; /* Encore une autre vision... */
- object = G_OBJECT_CLASS(klass);
+ instr = G_ARCH_INSTRUCTION_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_pyarch_instruction_dispose;
- object->finalize = (GObjectFinalizeFunc)g_pyarch_instruction_finalize;
-
- instr = G_ARCH_INSTRUCTION_CLASS(klass);
-
- instr->get_keyword = (get_instruction_keyword_fc)g_pyarch_instruction_get_keyword;
+ instr->get_keyword = (get_instruction_keyword_fc)py_arch_instruction_get_class_keyword;
}
/******************************************************************************
* *
-* Paramètres : instr = instance à initialiser. *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
* *
-* Description : Initialise une instance d'instruction d'architecture. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : - *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_pyarch_instruction_init(GPyArchInstruction *instr)
+static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kwds)
{
+ unsigned short int uid; /* Indentifiant unique de type */
+ const char *keyword; /* Désignation d'instruction */
+ int ret; /* Bilan de lecture des args. */
+ GArchInstruction *instr; /* Instruction à manipuler */
+ GQuark cache_key; /* Emplacement local */
-}
+ static char *kwlist[] = { "uid", "keyword", NULL };
+ /* Récupération des paramètres */
-/******************************************************************************
-* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword);
+ if (!ret) return -1;
-static void g_pyarch_instruction_dispose(GPyArchInstruction *instr)
-{
- G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->dispose(G_OBJECT(instr));
+ /* Initialisation d'un objet GLib */
-}
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+ /* Eléments de base */
-/******************************************************************************
-* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ instr = G_ARCH_INSTRUCTION(pygobject_get(self));
-static void g_pyarch_instruction_finalize(GPyArchInstruction *instr)
-{
- if (instr->cached_keyword)
- free(instr->cached_keyword);
+ cache_key = get_cached_keyword_quark();
- G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->finalize(G_OBJECT(instr));
+ g_object_set_qdata_full(G_OBJECT(instr), cache_key, strdup(keyword), g_free);
+
+ g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(instr), uid);
+
+ return 0;
}
@@ -268,151 +209,21 @@ static void g_pyarch_instruction_finalize(GPyArchInstruction *instr)
* *
******************************************************************************/
-static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *instr)
+static const char *py_arch_instruction_get_class_keyword(GArchInstruction *instr)
{
const char *result; /* Désignation à retourner */
+ GQuark cache_key; /* Emplacement local */
- result = instr->cached_keyword;
+ cache_key = get_cached_keyword_quark();
- return result;
-
-}
-
-
-/* ---------------------------------------------------------------------------------- */
-/* GLUE POUR CREATION DEPUIS PYTHON */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : type = type du nouvel objet à mettre en place. *
-* args = éventuelle liste d'arguments. *
-* kwds = éventuel dictionnaire de valeurs mises à disposition. *
-* *
-* Description : Accompagne la création d'une instance dérivée en Python. *
-* *
-* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_arch_instruction_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *result; /* Objet à retourner */
- PyTypeObject *base; /* Type de base à dériver */
- bool first_time; /* Evite les multiples passages*/
- GType gtype; /* Nouveau type de processeur */
- bool status; /* Bilan d'un enregistrement */
-
- /* Validations diverses */
-
- base = get_python_arch_instruction_type();
-
- if (type == base)
- {
- result = NULL;
- PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
- goto exit;
- }
-
- /* Mise en place d'un type dédié */
-
- first_time = (g_type_from_name(type->tp_name) == 0);
-
- gtype = build_dynamic_type(G_TYPE_PYARCH_INSTRUCTION, type->tp_name,
- (GClassInitFunc)py_arch_instruction_init_gclass, NULL, NULL);
-
- if (first_time)
- {
- status = register_class_for_dynamic_pygobject(gtype, type, base);
-
- if (!status)
- {
- result = NULL;
- goto exit;
- }
-
- }
-
- /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
-
- result = PyType_GenericNew(type, args, kwds);
-
- exit:
+ result = g_object_get_qdata(G_OBJECT(instr), cache_key);
+ assert(result != NULL);
return result;
}
-/******************************************************************************
-* *
-* Paramètres : class = classe à initialiser. *
-* unused = données non utilisées ici. *
-* *
-* Description : Initialise la classe générique des instructions. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void py_arch_instruction_init_gclass(GPyArchInstructionClass *class, gpointer unused)
-{
- /// ....
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = objet à initialiser (théoriquement). *
-* args = arguments fournis à l'appel. *
-* kwds = arguments de type key=val fournis. *
-* *
-* Description : Initialise une instance sur la base du dérivé de GObject. *
-* *
-* Retour : 0. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
- unsigned short int uid; /* Indentifiant unique de type */
- const char *keyword; /* Désignation d'instruction */
- int ret; /* Bilan de lecture des args. */
- GPyArchInstruction *instr; /* Instruction à manipuler */
-
- static char *kwlist[] = { "uid", "keyword", NULL };
-
- /* Récupération des paramètres */
-
- ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword);
- if (!ret) return -1;
-
- /* Initialisation d'un objet GLib */
-
- ret = forward_pygobjet_init(self);
- if (ret == -1) return -1;
-
- /* Eléments de base */
-
- instr = G_PYARCH_INSTRUCTION(pygobject_get(self));
-
- instr->cached_keyword = strdup(keyword);
-
- g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(instr), uid);
-
- return 0;
-
-}
-
-
/* ---------------------------------------------------------------------------------- */
/* MANIPULATION DES OPERANDES */
@@ -1085,8 +896,7 @@ bool ensure_python_arch_instruction_is_registered(void)
if (!ensure_python_line_generator_is_registered())
return false;
- if (!_register_class_for_pygobject(dict, G_TYPE_PYARCH_INSTRUCTION, type,
- &PyGObject_Type, get_python_line_generator_type(), NULL))
+ if (!register_class_for_pygobject(dict, G_TYPE_ARCH_INSTRUCTION, type))
return false;
if (!define_arch_instruction_constants(type))
diff --git a/plugins/pychrysalide/arch/instructions/Makefile.am b/plugins/pychrysalide/arch/instructions/Makefile.am
index 01c22c4..65efe42 100644
--- a/plugins/pychrysalide/arch/instructions/Makefile.am
+++ b/plugins/pychrysalide/arch/instructions/Makefile.am
@@ -2,24 +2,15 @@
noinst_LTLIBRARIES = libpychrysaarchinstructions.la
libpychrysaarchinstructions_la_SOURCES = \
- constants.h constants.c \
- module.h module.c \
- raw.h raw.c \
+ constants.h constants.c \
+ module.h module.c \
+ raw.h raw.c \
undefined.h undefined.c
-libpychrysaarchinstructions_la_LIBADD =
-
-libpychrysaarchinstructions_la_LDFLAGS =
+libpychrysaarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaarchinstructions_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/arch/instructions/raw.c b/plugins/pychrysalide/arch/instructions/raw.c
index c1366c6..7e58b96 100644
--- a/plugins/pychrysalide/arch/instructions/raw.c
+++ b/plugins/pychrysalide/arch/instructions/raw.c
@@ -99,7 +99,7 @@ static PyObject *py_raw_instruction_new(PyTypeObject *type, PyObject *args, PyOb
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -458,7 +458,7 @@ bool ensure_python_raw_instruction_is_registered(void)
if (!ensure_python_arch_instruction_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, type, get_python_arch_instruction_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, type))
return false;
if (!define_raw_instruction_constants(type))
diff --git a/plugins/pychrysalide/arch/instructions/undefined.c b/plugins/pychrysalide/arch/instructions/undefined.c
index 99fd2ff..1246daa 100644
--- a/plugins/pychrysalide/arch/instructions/undefined.c
+++ b/plugins/pychrysalide/arch/instructions/undefined.c
@@ -88,7 +88,7 @@ static PyObject *py_undef_instruction_new(PyTypeObject *type, PyObject *args, Py
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -285,7 +285,7 @@ bool ensure_python_undefined_instruction_is_registered(void)
if (!ensure_python_arch_instruction_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_UNDEF_INSTRUCTION, type, get_python_arch_instruction_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_UNDEF_INSTRUCTION, type))
return false;
if (!define_undefined_instruction_constants(type))
diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c
index 71e7cdc..0aee4f7 100644
--- a/plugins/pychrysalide/arch/operand.c
+++ b/plugins/pychrysalide/arch/operand.c
@@ -60,9 +60,13 @@ static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const G
/* Traduit un opérande en version humainement lisible. */
static void py_arch_operand_print_wrapper(const GArchOperand *, GBufferLine *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Construit un petit résumé concis de l'opérande. */
static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *, const GLoadedBinary *);
+#endif
+
/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
@@ -145,7 +149,7 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -186,7 +190,9 @@ static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unuse
class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper;
class->print = py_arch_operand_print_wrapper;
+#ifdef INCLUDE_GTK_SUPPORT
class->build_tooltip = py_arch_operand_build_tooltip_wrapper;
+#endif
}
@@ -456,6 +462,9 @@ static void py_arch_operand_print_wrapper(const GArchOperand *operand, GBufferLi
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : operand = opérande à consulter. *
@@ -522,6 +531,9 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand,
}
+#endif
+
+
/* ---------------------------------------------------------------------------------- */
/* DEFINITION D'OPERANDE QUELCONQUE */
@@ -709,7 +721,9 @@ PyTypeObject *get_python_arch_operand_type(void)
ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER,
ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER,
ARCH_OPERAND_PRINT_WRAPPER,
+#ifdef INCLUDE_GTK_SUPPORT
ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER,
+#endif
ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD,
ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD,
{ NULL }
@@ -773,7 +787,7 @@ bool ensure_python_arch_operand_is_registered(void)
if (!ensure_python_singleton_candidate_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type))
return false;
}
diff --git a/plugins/pychrysalide/arch/operands/Makefile.am b/plugins/pychrysalide/arch/operands/Makefile.am
index 1dd54a5..a41cbbb 100644
--- a/plugins/pychrysalide/arch/operands/Makefile.am
+++ b/plugins/pychrysalide/arch/operands/Makefile.am
@@ -1,31 +1,22 @@
noinst_LTLIBRARIES = libpychrysaarchoperands.la
-libpychrysaarchoperands_la_SOURCES = \
- constants.h constants.c \
- feeder.h feeder.c \
- immediate.h immediate.c \
- known.h known.c \
- module.h module.c \
- proxy.h proxy.c \
- register.h register.c \
- rename.h rename.c \
- target.h target.c \
+libpychrysaarchoperands_la_SOURCES = \
+ constants.h constants.c \
+ feeder.h feeder.c \
+ immediate.h immediate.c \
+ known.h known.c \
+ module.h module.c \
+ proxy.h proxy.c \
+ register.h register.c \
+ rename.h rename.c \
+ target.h target.c \
targetable.h targetable.c
-libpychrysaarchoperands_la_LIBADD =
-
-libpychrysaarchoperands_la_LDFLAGS =
+libpychrysaarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaarchoperands_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/arch/operands/immediate.c b/plugins/pychrysalide/arch/operands/immediate.c
index 62f6328..2239eb2 100644
--- a/plugins/pychrysalide/arch/operands/immediate.c
+++ b/plugins/pychrysalide/arch/operands/immediate.c
@@ -603,7 +603,7 @@ bool ensure_python_imm_operand_is_registered(void)
if (!ensure_python_renameable_operand_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type, get_python_arch_operand_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type))
return false;
if (!define_imm_operand_constants(type))
diff --git a/plugins/pychrysalide/arch/operands/known.c b/plugins/pychrysalide/arch/operands/known.c
index 435ea0f..fab426e 100644
--- a/plugins/pychrysalide/arch/operands/known.c
+++ b/plugins/pychrysalide/arch/operands/known.c
@@ -169,7 +169,7 @@ bool ensure_python_known_imm_operand_is_registered(void)
if (!ensure_python_renamed_operand_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type, get_python_imm_operand_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type))
return false;
}
diff --git a/plugins/pychrysalide/arch/operands/proxy.c b/plugins/pychrysalide/arch/operands/proxy.c
index 1cfd4a4..5009d29 100644
--- a/plugins/pychrysalide/arch/operands/proxy.c
+++ b/plugins/pychrysalide/arch/operands/proxy.c
@@ -105,7 +105,7 @@ static PyObject *py_proxy_operand_new(PyTypeObject *type, PyObject *args, PyObje
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -319,7 +319,10 @@ bool ensure_python_proxy_operand_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_PROXY_OPERAND, type, get_python_arch_operand_type()))
+ if (!ensure_python_arch_operand_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_PROXY_OPERAND, type))
return false;
}
diff --git a/plugins/pychrysalide/arch/operands/register.c b/plugins/pychrysalide/arch/operands/register.c
index d032e04..2a48a0f 100644
--- a/plugins/pychrysalide/arch/operands/register.c
+++ b/plugins/pychrysalide/arch/operands/register.c
@@ -112,7 +112,7 @@ static PyObject *py_register_operand_new(PyTypeObject *type, PyObject *args, PyO
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -427,7 +427,10 @@ bool ensure_python_register_operand_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_REGISTER_OPERAND, type, get_python_arch_operand_type()))
+ if (!ensure_python_arch_operand_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_REGISTER_OPERAND, type))
return false;
}
diff --git a/plugins/pychrysalide/arch/operands/target.c b/plugins/pychrysalide/arch/operands/target.c
index 76c8269..b8cd536 100644
--- a/plugins/pychrysalide/arch/operands/target.c
+++ b/plugins/pychrysalide/arch/operands/target.c
@@ -115,7 +115,7 @@ static PyObject *py_target_operand_new(PyTypeObject *type, PyObject *args, PyObj
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -429,10 +429,13 @@ bool ensure_python_target_operand_is_registered(void)
dict = PyModule_GetDict(module);
+ if (!ensure_python_arch_operand_is_registered())
+ return false;
+
if (!ensure_python_targetable_operand_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_TARGET_OPERAND, type, get_python_arch_operand_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_TARGET_OPERAND, type))
return false;
}
diff --git a/plugins/pychrysalide/arch/processor.c b/plugins/pychrysalide/arch/processor.c
index 80b55d3..00b472f 100644
--- a/plugins/pychrysalide/arch/processor.c
+++ b/plugins/pychrysalide/arch/processor.c
@@ -186,7 +186,7 @@ static PyObject *py_arch_processor_new(PyTypeObject *type, PyObject *args, PyObj
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -1452,7 +1452,7 @@ bool ensure_python_arch_processor_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, type))
return false;
if (!define_arch_processor_constants(type))
diff --git a/plugins/pychrysalide/arch/register.c b/plugins/pychrysalide/arch/register.c
index 5d9e90b..615a5b7 100644
--- a/plugins/pychrysalide/arch/register.c
+++ b/plugins/pychrysalide/arch/register.c
@@ -144,7 +144,7 @@ static PyObject *py_arch_register_new(PyTypeObject *type, PyObject *args, PyObje
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -686,7 +686,7 @@ bool ensure_python_arch_register_is_registered(void)
if (!ensure_python_serializable_object_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type))
return false;
}
diff --git a/plugins/pychrysalide/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am
index 3f1b0b6..b5249b9 100644
--- a/plugins/pychrysalide/common/Makefile.am
+++ b/plugins/pychrysalide/common/Makefile.am
@@ -1,25 +1,21 @@
noinst_LTLIBRARIES = libpychrysacommon.la
-libpychrysacommon_la_SOURCES = \
- bits.h bits.c \
- fnv1a.h fnv1a.c \
- hex.h hex.c \
- leb128.h leb128.c \
- module.h module.c \
- packed.h packed.c \
- pathname.h pathname.c \
+libpychrysacommon_la_SOURCES = \
+ bits.h bits.c \
+ fnv1a.h fnv1a.c \
+ hex.h hex.c \
+ itoa.h itoa.c \
+ leb128.h leb128.c \
+ module.h module.c \
+ packed.h packed.c \
+ pathname.h pathname.c \
pearson.h pearson.c
-libpychrysacommon_la_LDFLAGS =
+libpychrysacommon_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysacommon_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/common/bits.c b/plugins/pychrysalide/common/bits.c
index 73fd55b..9275996 100644
--- a/plugins/pychrysalide/common/bits.c
+++ b/plugins/pychrysalide/common/bits.c
@@ -65,6 +65,9 @@ static PyObject *py_bitfield_richcompare(PyObject *, PyObject *, int);
/* Crée une copie d'un champ de bits classique. */
static PyObject *py_bitfield_dup(PyObject *, PyObject *);
+/* Redimensionne un champ de bits. */
+static PyObject *py_bitfield_resize(PyObject *, PyObject *);
+
/* Bascule à 0 un champ de bits dans son intégralité. */
static PyObject *py_bitfield_reset_all(PyObject *, PyObject *);
@@ -77,6 +80,9 @@ static PyObject *py_bitfield_reset(PyObject *, PyObject *);
/* Bascule à 1 une partie d'un champ de bits. */
static PyObject *py_bitfield_set(PyObject *, PyObject *);
+/* Réalise une opération OU logique entre deux champs de bits. */
+static PyObject *py_bitfield_or_at(PyObject *, PyObject *);
+
/* Détermine si un bit est à 1 dans un champ de bits. */
static PyObject *py_bitfield_test(PyObject *, PyObject *);
@@ -86,6 +92,12 @@ static PyObject *py_bitfield_test_none(PyObject *, PyObject *);
/* Détermine si un ensemble de bits est à 1 dans un champ. */
static PyObject *py_bitfield_test_all(PyObject *, PyObject *);
+/* Teste l'état à 0 de bits selon un masque de bits. */
+static PyObject *py_bitfield_test_zeros_with(PyObject *, PyObject *);
+
+/* Teste l'état à 1 de bits selon un masque de bits. */
+static PyObject *py_bitfield_test_ones_with(PyObject *, PyObject *);
+
/* Indique la taille d'un champ de bits donné. */
static PyObject *py_bitfield_get_size(PyObject *, void *);
@@ -399,6 +411,47 @@ static PyObject *py_bitfield_dup(PyObject *self, PyObject *args)
/******************************************************************************
* *
+* Paramètres : self = champ de bits à dupliquer. *
+* args = non utilisé ici. *
+* *
+* Description : Redimensionne un champ de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bitfield_resize(PyObject *self, PyObject *args)
+{
+ unsigned long length; /* Nouvelle taille à respecter */
+ int ret; /* Bilan de lecture des args. */
+ py_bitfield_t *bf; /* Instance à manipuler */
+
+#define BITFIELD_RESIZE_METHOD PYTHON_METHOD_DEF \
+( \
+ resize, "$self, length, /", \
+ METH_VARARGS, py_bitfield, \
+ "Resize a bitfield and fix its new size to *length*.\n" \
+ "\n" \
+ "The new bits get initialized to the same state used at the" \
+ " bitfield creation." \
+)
+
+ ret = PyArg_ParseTuple(args, "k", &length);
+ if (!ret) return NULL;
+
+ bf = (py_bitfield_t *)self;
+
+ resize_bit_field(&bf->native, length);
+
+ Py_RETURN_NONE;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : self = champ de bits à modifier. *
* args = non utilisé ici. *
* *
@@ -552,6 +605,49 @@ static PyObject *py_bitfield_set(PyObject *self, PyObject *args)
* Paramètres : self = champ de bits à consulter. *
* args = arguments fournis pour la conduite de l'opération. *
* *
+* Description : Réalise une opération OU logique entre deux champs de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bitfield_or_at(PyObject *self, PyObject *args)
+{
+ bitfield_t *src; /* Seconde champ de bits */
+ unsigned long first; /* Indice du premier bit testé */
+ int ret; /* Bilan de lecture des args. */
+ py_bitfield_t *bf; /* Instance à manipuler */
+
+#define BITFIELD_OR_AT_METHOD PYTHON_METHOD_DEF \
+( \
+ or_at, "$self, src, first, /", \
+ METH_VARARGS, py_bitfield, \
+ "Perform an OR operation with another bitfield.\n" \
+ "\n" \
+ "The *src* argument is expected to be another" \
+ " pychrysalide.common.BitField instance. The area to" \
+ " process starts at bit *first* from *src*." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&k", convert_to_bitfield, &src, &first);
+ if (!ret) return NULL;
+
+ bf = (py_bitfield_t *)self;
+
+ or_bit_field_at(bf->native, src, first);
+
+ Py_RETURN_NONE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = champ de bits à consulter. *
+* args = arguments fournis pour la conduite de l'opération. *
+* *
* Description : Détermine si un bit est à 1 dans un champ de bits. *
* *
* Retour : true si le bit correspondant est à l'état haut. *
@@ -695,6 +791,106 @@ static PyObject *py_bitfield_test_all(PyObject *self, PyObject *args)
/******************************************************************************
* *
+* Paramètres : self = champ de bits à consulter. *
+* args = arguments fournis pour la conduite de l'opération. *
+* *
+* Description : Teste l'état à 0 de bits selon un masque de bits. *
+* *
+* Retour : true si les bits visés sont à l'état bas. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bitfield_test_zeros_with(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à faire remonter */
+ unsigned long first; /* Indice du premier bit testé */
+ bitfield_t *mask; /* Champ de bits natif */
+ int ret; /* Bilan de lecture des args. */
+ py_bitfield_t *bf; /* Instance à manipuler */
+ bool status; /* Bilan d'analyse */
+
+#define BITFIELD_TEST_ZEROS_WITH_METHOD PYTHON_METHOD_DEF \
+( \
+ test_zeros_with, "$self, first, mask, /", \
+ METH_VARARGS, py_bitfield, \
+ "Test a range of bits against another bit field.\n" \
+ "\n" \
+ "The area to process starts at bit *first* and the" \
+ " test relies on bits set within the *mask* object.\n" \
+ "\n" \
+ "The result is a boolean value: True if all tested" \
+ " bits are unset, False otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask);
+ if (!ret) return NULL;
+
+ bf = (py_bitfield_t *)self;
+
+ status = test_zeros_within_bit_field(bf->native, first, mask);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = champ de bits à consulter. *
+* args = arguments fournis pour la conduite de l'opération. *
+* *
+* Description : Teste l'état à 1 de bits selon un masque de bits. *
+* *
+* Retour : true si les bits visés sont à l'état haut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bitfield_test_ones_with(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à faire remonter */
+ unsigned long first; /* Indice du premier bit testé */
+ bitfield_t *mask; /* Champ de bits natif */
+ int ret; /* Bilan de lecture des args. */
+ py_bitfield_t *bf; /* Instance à manipuler */
+ bool status; /* Bilan d'analyse */
+
+#define BITFIELD_TEST_ONES_WITH_METHOD PYTHON_METHOD_DEF \
+( \
+ test_ones_with, "$self, first, mask, /", \
+ METH_VARARGS, py_bitfield, \
+ "Test a range of bits against another bit field.\n" \
+ "\n" \
+ "The area to process starts at bit *first* and the" \
+ " test relies on bits set within the *mask* object.\n" \
+ "\n" \
+ "The result is a boolean value: True if all tested" \
+ " bits are set, False otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask);
+ if (!ret) return NULL;
+
+ bf = (py_bitfield_t *)self;
+
+ status = test_ones_within_bit_field(bf->native, first, mask);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : self = classe représentant une instruction. *
* closure = adresse non utilisée ici. *
* *
@@ -791,13 +987,17 @@ PyTypeObject *get_python_bitfield_type(void)
static PyMethodDef py_bitfield_methods[] = {
BITFIELD_DUP_METHOD,
+ BITFIELD_RESIZE_METHOD,
BITFIELD_RESET_ALL_METHOD,
BITFIELD_SET_ALL_METHOD,
BITFIELD_RESET_METHOD,
BITFIELD_SET_METHOD,
+ BITFIELD_OR_AT_METHOD,
BITFIELD_TEST_METHOD,
BITFIELD_TEST_NONE_METHOD,
BITFIELD_TEST_ALL_METHOD,
+ BITFIELD_TEST_ZEROS_WITH_METHOD,
+ BITFIELD_TEST_ONES_WITH_METHOD,
{ NULL }
};
@@ -876,6 +1076,51 @@ bool ensure_python_bitfield_is_registered(void)
/******************************************************************************
* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en champ de bits. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_bitfield(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_bitfield_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to bit field");
+ break;
+
+ case 1:
+ *((bitfield_t **)dst) = ((py_bitfield_t *)arg)->native;
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : field = structure interne à copier en objet Python. *
* *
* Description : Convertit une structure de type 'bitfield_t' en objet Python.*
diff --git a/plugins/pychrysalide/common/bits.h b/plugins/pychrysalide/common/bits.h
index 6ddaaa5..804c3b5 100644
--- a/plugins/pychrysalide/common/bits.h
+++ b/plugins/pychrysalide/common/bits.h
@@ -40,6 +40,9 @@ PyTypeObject *get_python_bitfield_type(void);
/* Prend en charge l'objet 'pychrysalide.common.BitField'. */
bool ensure_python_bitfield_is_registered(void);
+/* Tente de convertir en champ de bits. */
+int convert_to_bitfield(PyObject *, void *);
+
/* Convertit une structure de type 'bitfield_t' en objet Python. */
PyObject *build_from_internal_bitfield(const bitfield_t *);
diff --git a/plugins/pychrysalide/common/itoa.c b/plugins/pychrysalide/common/itoa.c
new file mode 100644
index 0000000..107b047
--- /dev/null
+++ b/plugins/pychrysalide/common/itoa.c
@@ -0,0 +1,124 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * itoa.c - équivalent Python du fichier "common/itoa.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "itoa.h"
+
+
+#include <common/itoa.h>
+
+
+#include "../access.h"
+#include "../helpers.h"
+
+
+
+/* Détermine l'empreinte Itoa d'une chaîne de caractères. */
+static PyObject *py_itoa(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = NULL car méthode statique. *
+* args = arguments fournis lors de l'appel à la fonction. *
+* *
+* Description : Convertit une valeur en une forme textuelle. *
+* *
+* Retour : Chaîne de caractères mises en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_itoa(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ long long n; /* Valeur à transformer */
+ unsigned char base; /* Base de travail */
+ int ret; /* Bilan de lecture des args. */
+ char *strval; /* Valeur sous forme de chaîne */
+
+#define ITOA_METHOD PYTHON_METHOD_DEF \
+( \
+ itoa, "n, /, base=10", \
+ METH_VARARGS, py, \
+ "Construct a string representation of an integer *n* according" \
+ " to a given *base*.\n" \
+ "\n" \
+ "Both arguments are expected to be integer values; the result" \
+ " is a string or None in case of failure." \
+)
+
+ base = 10;
+
+ ret = PyArg_ParseTuple(args, "L|b", &n, &base);
+ if (!ret) return NULL;
+
+ strval = itoa(n, base);
+
+ if (strval != NULL)
+ {
+ result = PyUnicode_FromString(strval);
+ free(strval);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Définit une extension du module 'common' à compléter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_common_module_with_itoa(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Module à recompléter */
+
+ static PyMethodDef py_itoa_methods[] = {
+ ITOA_METHOD,
+ { NULL }
+ };
+
+ module = get_access_to_python_module("pychrysalide.common");
+
+ result = register_python_module_methods(module, py_itoa_methods);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/common/itoa.h b/plugins/pychrysalide/common/itoa.h
new file mode 100644
index 0000000..a66e767
--- /dev/null
+++ b/plugins/pychrysalide/common/itoa.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * itoa.h - prototypes pour l'équivalent Python du fichier "common/itoa.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H
+#define _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit une extension du module 'common' à compléter. */
+bool populate_common_module_with_itoa(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H */
diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c
index 6ced1b7..a0042ee 100644
--- a/plugins/pychrysalide/common/module.c
+++ b/plugins/pychrysalide/common/module.c
@@ -28,6 +28,7 @@
#include "bits.h"
#include "fnv1a.h"
#include "hex.h"
+#include "itoa.h"
#include "leb128.h"
#include "packed.h"
#include "pathname.h"
@@ -99,6 +100,7 @@ bool populate_common_module(void)
if (result) result = populate_common_module_with_fnv1a();
if (result) result = populate_common_module_with_hex();
+ if (result) result = populate_common_module_with_itoa();
if (result) result = populate_common_module_with_leb128();
if (result) result = populate_common_module_with_pathname();
if (result) result = populate_common_module_with_pearson();
diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index c062d15..08f570f 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -40,7 +40,6 @@
#include <unistd.h>
-#include <config.h>
#include <i18n.h>
#include <gleak.h>
#include <common/cpp.h>
@@ -65,8 +64,10 @@
#include "debug/module.h"
#include "format/module.h"
#include "glibext/module.h"
-#include "gtkext/module.h"
-#include "gui/module.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "gtkext/module.h"
+# include "gui/module.h"
+#endif
#include "mangling/module.h"
#include "plugins/module.h"
#include "plugins/plugin.h"
@@ -98,8 +99,13 @@ static PyObject *py_chrysalide_mod_version(PyObject *, PyObject *);
/* Détermine si l'interpréteur lancé est celui pris en compte. */
static bool is_current_abi_suitable(void);
+/* Assure une pleine initialisation des objets de Python-GI. */
+static bool install_metaclass_for_python_gobjects(void);
+
/* Définit la version attendue de GTK à charger dans Python. */
+#ifdef INCLUDE_GTK_SUPPORT
static bool set_version_for_gtk_namespace(const char *);
+#endif
/* Point de sortie pour l'initialisation de Python. */
static void PyExit_pychrysalide(void);
@@ -292,6 +298,126 @@ static bool is_current_abi_suitable(void)
/******************************************************************************
* *
+* Paramètres : - *
+* *
+* Description : Assure une pleine initialisation des objets de Python-GI. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool install_metaclass_for_python_gobjects(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *gi_types_mod; /* Module Python-GObject */
+
+ /**
+ * Les extensions Python sont chargées à partir de la fonction load_python_plugins(),
+ * qui fait appel à create_python_plugin(). Une instance y est construite via un
+ * appel à PyObject_CallFunction() avec la classe spécifiée par l'alias AutoLoad
+ * dans le fichier __init__.py présent dans chaque module d'extension.
+ *
+ * Le constructeur py_plugin_module_new() renvoie in fine à la fonction générique
+ * python_abstract_constructor_with_dynamic_gtype(), laquelle conduit à la fonction
+ * pygobject_register_class() définie dans <python3-gi>/gi/pygobject-object.c.
+ * Le code de cette dernière comprend notamment la portion suivante :
+ *
+ * [...]
+ * Py_SET_TYPE(type, PyGObject_MetaType);
+ * [...]
+ * if (PyType_Ready(type) < 0) {
+ * g_warning ("couldn't make the type `%s' ready", type->tp_name);
+ * return;
+ * }
+ * [...]
+ *
+ * La fonction PyType_Ready() est définie dans <python3>/Objects/typeobject.c
+ * et commence par :
+ *
+ * int PyType_Ready(PyTypeObject *type)
+ * {
+ * if (type->tp_flags & Py_TPFLAGS_READY) {
+ * assert(_PyType_CheckConsistency(type));
+ * return 0;
+ * }
+ * [...]
+ * }
+ *
+ * La vérification de cohérencce commence par analyser le type et son propre
+ * type :
+ *
+ * - cf. _PyType_CheckConsistency() dans <python3>/Objects/typeobject.c :
+ *
+ * int _PyType_CheckConsistency(PyTypeObject *type)
+ * {
+ * [...]
+ * CHECK(!_PyObject_IsFreed((PyObject *)type));
+ * [...]
+ * }
+ *
+ * - cf. _PyObject_IsFreed() dans <python3>/Objects/object.c :
+ *
+ * int _PyObject_IsFreed(PyObject *op)
+ * {
+ * if (_PyMem_IsPtrFreed(op) || _PyMem_IsPtrFreed(Py_TYPE(op))) {
+ * return 1;
+ * }
+ *
+ * La fonction _PyMem_IsPtrFreed() recherche entre autres la valeur NULL.
+ *
+ * Or le type du type est écrasé dans la fonction pygobject_register_class()
+ * avec la valeur de la variable PyGObject_MetaType. Cette variable n'est
+ * définie qu'à un seul endroit, dans <python3-gi>/gi/gimodule.c :
+ *
+ * static PyObject *
+ * pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass)
+ * {
+ * Py_INCREF(metaclass);
+ * PyGObject_MetaType = metaclass;
+ * Py_INCREF(metaclass);
+ *
+ * Py_SET_TYPE(&PyGObject_Type, metaclass);
+ *
+ * Py_INCREF(Py_None);
+ * return Py_None;
+ * }
+ *
+ * Afin de valider la vérification de _PyType_CheckConsistency() pour les
+ * modules externes qui entraînent un enregistrement tout en portant le drapeau
+ * Py_TPFLAGS_READY (typiquement ceux du répertoire "plugins/python/", il faut
+ * initialiser au besoin la variable PyGObject_MetaType.
+ *
+ * Une ligne suffit donc à enregistrer le type intermédiaire :
+ *
+ * from _gi import types
+ *
+ * On simule ici une déclaration similaire si nécessaire
+ */
+
+ result = false;
+
+ if (PyType_CheckExact(&PyGObject_Type))
+ {
+ gi_types_mod = PyImport_ImportModule("gi.types");
+
+ result = (PyErr_Occurred() == NULL);
+
+ if (result)
+ result = (PyType_CheckExact(&PyGObject_Type) == 0);
+
+ Py_XDECREF(gi_types_mod);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : version = idenfiant de la version de GTK à stipuler. *
* *
* Description : Définit la version attendue de GTK à charger dans Python. *
@@ -301,7 +427,7 @@ static bool is_current_abi_suitable(void)
* Remarques : - *
* *
******************************************************************************/
-
+#ifdef INCLUDE_GTK_SUPPORT
static bool set_version_for_gtk_namespace(const char *version)
{
bool result; /* Bilan à retourner */
@@ -337,6 +463,7 @@ static bool set_version_for_gtk_namespace(const char *version)
return result;
}
+#endif
/******************************************************************************
@@ -459,8 +586,13 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
goto exit;
}
+ if (!install_metaclass_for_python_gobjects())
+ goto exit;
+
+#ifdef INCLUDE_GTK_SUPPORT
if (!set_version_for_gtk_namespace("3.0"))
goto exit;
+#endif
if (!load_all_core_components(true))
{
@@ -485,8 +617,10 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
if (status) status = add_debug_module(result);
if (status) status = add_format_module(result);
if (status) status = add_glibext_module(result);
+#ifdef INCLUDE_GTK_SUPPORT
if (status) status = add_gtkext_module(result);
if (status) status = add_gui_module(result);
+#endif
if (status) status = add_mangling_module(result);
if (status) status = add_plugins_module(result);
@@ -500,8 +634,10 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
if (status) status = populate_debug_module();
if (status) status = populate_format_module();
if (status) status = populate_glibext_module();
+#ifdef INCLUDE_GTK_SUPPORT
if (status) status = populate_gtkext_module();
if (status) status = populate_gui_module();
+#endif
if (status) status = populate_mangling_module();
if (status) status = populate_plugins_module();
@@ -671,11 +807,11 @@ static void load_python_plugins(GPluginModule *plugin)
if (dir != NULL)
{
- closedir(dir);
+ closedir(dir);
- edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python");
- extend_python_path(edir);
- free(edir);
+ edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python");
+ extend_python_path(edir);
+ free(edir);
}
@@ -692,7 +828,7 @@ static void load_python_plugins(GPluginModule *plugin)
save = NULL; /* gcc... */
for (path = strtok_r(paths, ":", &save);
- path != NULL;
+ path != NULL;
path = strtok_r(NULL, ":", &save))
{
dir = opendir(path);
@@ -732,7 +868,7 @@ static void load_python_plugins(GPluginModule *plugin)
filename = stradd(filename, G_DIR_SEPARATOR_S);
filename = stradd(filename, entry->d_name);
- pyplugin = g_python_plugin_new(modname, filename);
+ pyplugin = create_python_plugin(modname, filename);
if (pyplugin == NULL)
{
@@ -771,7 +907,7 @@ static void load_python_plugins(GPluginModule *plugin)
}
- closedir(dir);
+ closedir(dir);
}
@@ -815,8 +951,6 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
gstate = PyGILState_Ensure();
- PySys_SetArgv(0, (wchar_t *[]) { NULL });
-
_chrysalide_module = PyImport_ImportModule("pychrysalide");
/**
@@ -907,7 +1041,6 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin,
{
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
size_t count; /* Quantité de greffons chargés*/
- PyTypeObject *parent; /* Type Python pour greffon */
PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
GPluginModule **list; /* Ensemble de ces greffons */
@@ -925,8 +1058,6 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin,
if (ensure_python_plugin_module_is_registered())
{
- parent = get_python_plugin_module_type();
-
module = get_access_to_python_module("pychrysalide.plugins");
assert(module != NULL);
@@ -959,7 +1090,7 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin,
type->tp_flags = Py_TPFLAGS_DEFAULT;
type->tp_new = no_python_constructor_allowed;
- if (register_class_for_pygobject(dict, G_OBJECT_TYPE(list[i]), type, parent))
+ if (register_class_for_pygobject(dict, G_OBJECT_TYPE(list[i]), type))
g_object_set_data_full(G_OBJECT(list[i]), "python_type", type,
(GDestroyNotify)free_native_plugin_type);
@@ -1097,7 +1228,7 @@ void log_pychrysalide_exception(const char *prefix, ...)
*
* C'est par exemple le cas quand un greffon Python ne peut se lancer
* correctement ; l'exception est alors levée à partir de la fonction
- * g_python_plugin_new() et le plantage intervient en sortie d'exécution,
+ * create_python_plugin() et le plantage intervient en sortie d'exécution,
* au moment de la libération de l'extension Python :
*
* ==14939== Jump to the invalid address stated on the next line
diff --git a/plugins/pychrysalide/core/Makefile.am b/plugins/pychrysalide/core/Makefile.am
index 3433856..880823d 100644
--- a/plugins/pychrysalide/core/Makefile.am
+++ b/plugins/pychrysalide/core/Makefile.am
@@ -1,25 +1,20 @@
noinst_LTLIBRARIES = libpychrysacore.la
-libpychrysacore_la_SOURCES = \
- constants.h constants.c \
- demanglers.h demanglers.c \
- global.h global.c \
- logs.h logs.c \
- module.h module.c \
- params.h params.c \
- processors.h processors.c \
+libpychrysacore_la_SOURCES = \
+ constants.h constants.c \
+ demanglers.h demanglers.c \
+ global.h global.c \
+ logs.h logs.c \
+ module.h module.c \
+ params.h params.c \
+ processors.h processors.c \
queue.h queue.c
-libpychrysacore_la_LDFLAGS =
+libpychrysacore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysacore_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/core/global.c b/plugins/pychrysalide/core/global.c
index ecaf2c6..9632e75 100644
--- a/plugins/pychrysalide/core/global.c
+++ b/plugins/pychrysalide/core/global.c
@@ -187,6 +187,52 @@ static PyObject *py_global_get_content_resolver(PyObject *self, PyObject *args)
* Paramètres : self = objet Python concerné par l'appel. *
* args = non utilisé ici. *
* *
+* Description : Fournit l'adresse de l'espace de noms principal pour ROST. *
+* *
+* Retour : Espace de noms racine de ROST ou NULL si aucun (!). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_global_get_rost_root_namespace(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance Python à retourner */
+ GScanNamespace *root_ns; /* Espace de noms ROST racine */
+
+#define GLOBAL_GET_ROST_ROOT_NAMESPACE_METHOD PYTHON_METHOD_DEF \
+( \
+ get_rost_root_namespace, "", \
+ METH_NOARGS, py_global, \
+ "Get the root namespace for ROST." \
+ "\n" \
+ "The returned object is a pychrysalide.analysis.scan.ScanNamespace" \
+ " instance used as singleton; it should not be *None*." \
+)
+
+ root_ns = get_rost_root_namespace();
+
+ if (root_ns != NULL)
+ {
+ result = pygobject_new(G_OBJECT(root_ns));
+ g_object_unref(G_OBJECT(root_ns));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = non utilisé ici. *
+* *
* Description : Fournit l'adresse du projet courant. *
* *
* Retour : Adresse du résolveur global ou None si aucun. *
@@ -289,6 +335,7 @@ bool populate_core_module_with_global(void)
GLOBAL_IS_BATCH_MODE_METHOD,
GLOBAL_GET_CONTENT_EXPLORER_METHOD,
GLOBAL_GET_CONTENT_RESOLVER_METHOD,
+ GLOBAL_GET_ROST_ROOT_NAMESPACE_METHOD,
GLOBAL_GET_CURRENT_PROJECT_METHOD,
GLOBAL_SET_CURRENT_PROJECT_METHOD,
{ NULL }
diff --git a/plugins/pychrysalide/debug/Makefile.am b/plugins/pychrysalide/debug/Makefile.am
index 24af93d..c653a6d 100644
--- a/plugins/pychrysalide/debug/Makefile.am
+++ b/plugins/pychrysalide/debug/Makefile.am
@@ -1,23 +1,14 @@
noinst_LTLIBRARIES = libpychrysadebug.la
-libpychrysadebug_la_SOURCES = \
- debugger.h debugger.c \
+libpychrysadebug_la_SOURCES = \
+ debugger.h debugger.c \
module.h module.c
-libpychrysadebug_la_LIBADD =
-
-libpychrysadebug_la_LDFLAGS =
+libpychrysadebug_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysadebug_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/debug/debugger.c b/plugins/pychrysalide/debug/debugger.c
index e65e295..b21087d 100644
--- a/plugins/pychrysalide/debug/debugger.c
+++ b/plugins/pychrysalide/debug/debugger.c
@@ -1195,7 +1195,7 @@ bool ensure_python_binary_debugger_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BINARY_DEBUGGER, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BINARY_DEBUGGER, type))
return false;
}
diff --git a/plugins/pychrysalide/format/Makefile.am b/plugins/pychrysalide/format/Makefile.am
index d9858e8..337265d 100644
--- a/plugins/pychrysalide/format/Makefile.am
+++ b/plugins/pychrysalide/format/Makefile.am
@@ -1,30 +1,22 @@
noinst_LTLIBRARIES = libpychrysaformat.la
-libpychrysaformat_la_SOURCES = \
- constants.h constants.c \
- executable.h executable.c \
- flat.h flat.c \
- format.h format.c \
- known.h known.c \
- module.h module.c \
- strsym.h strsym.c \
- symbol.h symbol.c \
+libpychrysaformat_la_SOURCES = \
+ constants.h constants.c \
+ executable.h executable.c \
+ flat.h flat.c \
+ format.h format.c \
+ known.h known.c \
+ module.h module.c \
+ preload.h preload.c \
+ strsym.h strsym.c \
+ symbol.h symbol.c \
symiter.h symiter.c
-libpychrysaformat_la_LIBADD =
-
-libpychrysaformat_la_LDFLAGS =
+libpychrysaformat_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaformat_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/format/executable.c b/plugins/pychrysalide/format/executable.c
index ac0125d..ff2d14a 100644
--- a/plugins/pychrysalide/format/executable.c
+++ b/plugins/pychrysalide/format/executable.c
@@ -268,7 +268,7 @@ bool ensure_python_executable_format_is_registered(void)
if (!ensure_python_binary_format_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_EXE_FORMAT, type, get_python_binary_format_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_EXE_FORMAT, type))
return false;
}
diff --git a/plugins/pychrysalide/format/flat.c b/plugins/pychrysalide/format/flat.c
index 2c8e9fd..4df3646 100644
--- a/plugins/pychrysalide/format/flat.c
+++ b/plugins/pychrysalide/format/flat.c
@@ -173,7 +173,7 @@ bool ensure_python_flat_format_is_registered(void)
if (!ensure_python_executable_format_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_FLAT_FORMAT, type, get_python_executable_format_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_FLAT_FORMAT, type))
return false;
}
diff --git a/plugins/pychrysalide/format/format.c b/plugins/pychrysalide/format/format.c
index 66d346c..82c6c33 100644
--- a/plugins/pychrysalide/format/format.c
+++ b/plugins/pychrysalide/format/format.c
@@ -166,7 +166,7 @@ static PyObject *py_binary_format_new(PyTypeObject *type, PyObject *args, PyObje
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -1150,7 +1150,7 @@ bool ensure_python_binary_format_is_registered(void)
if (!ensure_python_known_format_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type, get_python_known_format_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type))
return false;
if (!define_binary_format_constants(type))
diff --git a/plugins/pychrysalide/format/known.c b/plugins/pychrysalide/format/known.c
index a2fc18c..3167ba2 100644
--- a/plugins/pychrysalide/format/known.c
+++ b/plugins/pychrysalide/format/known.c
@@ -132,7 +132,7 @@ static PyObject *py_known_format_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -789,7 +789,7 @@ bool ensure_python_known_format_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_FORMAT, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_FORMAT, type))
return false;
}
diff --git a/plugins/pychrysalide/format/module.c b/plugins/pychrysalide/format/module.c
index 52dc58b..62c15ed 100644
--- a/plugins/pychrysalide/format/module.c
+++ b/plugins/pychrysalide/format/module.c
@@ -32,6 +32,7 @@
#include "flat.h"
#include "format.h"
#include "known.h"
+#include "preload.h"
#include "strsym.h"
#include "symbol.h"
#include "symiter.h"
@@ -105,6 +106,7 @@ bool populate_format_module(void)
if (result) result = ensure_python_flat_format_is_registered();
if (result) result = ensure_python_known_format_is_registered();
if (result) result = ensure_python_binary_format_is_registered();
+ if (result) result = ensure_python_preload_info_is_registered();
if (result) result = ensure_python_string_symbol_is_registered();
if (result) result = ensure_python_binary_symbol_is_registered();
if (result) result = ensure_python_sym_iterator_is_registered();
diff --git a/plugins/pychrysalide/format/preload.c b/plugins/pychrysalide/format/preload.c
new file mode 100644
index 0000000..e4f2a9c
--- /dev/null
+++ b/plugins/pychrysalide/format/preload.c
@@ -0,0 +1,207 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * preload.c - équivalent Python du fichier "format/preload.c"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "preload.h"
+
+
+#include <pygobject.h>
+
+
+#include <format/preload-int.h>
+
+
+#include "../access.h"
+#include "../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(preload_info, G_TYPE_PRELOAD_INFO);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_preload_info_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_preload_info_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan d'initialisation */
+
+#define PRELOAD_INFO_DOC \
+ "The PreloadInfo object stores all kinds of disassembling" \
+ " information available from the analysis of a file format" \
+ " itsself.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " PreloadInfo()"
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_preload_info_type(void)
+{
+ static PyMethodDef py_preload_info_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_preload_info_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_preload_info_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.format.PreloadInfo",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = PRELOAD_INFO_DOC,
+
+ .tp_methods = py_preload_info_methods,
+ .tp_getset = py_preload_info_getseters,
+
+ .tp_init = py_preload_info_init,
+ .tp_new = py_preload_info_new,
+
+ };
+
+ return &py_preload_info_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.format.PreloadInfo'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_preload_info_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ArchContext' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_preload_info_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.format");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_PRELOAD_INFO, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en espace de préchargement. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_preload_info(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_preload_info_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to disassembly context");
+ break;
+
+ case 1:
+ *((GPreloadInfo **)dst) = G_PRELOAD_INFO(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/format/preload.h b/plugins/pychrysalide/format/preload.h
new file mode 100644
index 0000000..bf33e82
--- /dev/null
+++ b/plugins/pychrysalide/format/preload.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * preload.h - prototypes pour l'équivalent Python du fichier "format/preload.h"
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H
+#define _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_preload_info_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.format.PreloadInfo'. */
+bool ensure_python_preload_info_is_registered(void);
+
+/* Tente de convertir en espace de préchargement. */
+int convert_to_preload_info(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H */
diff --git a/plugins/pychrysalide/format/strsym.c b/plugins/pychrysalide/format/strsym.c
index c85d61f..adc0e48 100644
--- a/plugins/pychrysalide/format/strsym.c
+++ b/plugins/pychrysalide/format/strsym.c
@@ -119,7 +119,7 @@ static PyObject *py_string_symbol_new(PyTypeObject *type, PyObject *args, PyObje
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -501,7 +501,7 @@ bool ensure_python_string_symbol_is_registered(void)
if (!ensure_python_binary_symbol_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_STR_SYMBOL, type, get_python_binary_symbol_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_STR_SYMBOL, type))
return false;
if (!define_string_symbol_constants(type))
diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c
index 1559b9a..d3a9c1e 100644
--- a/plugins/pychrysalide/format/symbol.c
+++ b/plugins/pychrysalide/format/symbol.c
@@ -157,7 +157,7 @@ static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObje
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -982,7 +982,7 @@ bool ensure_python_binary_symbol_is_registered(void)
if (!ensure_python_serializable_object_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_BIN_SYMBOL, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BIN_SYMBOL, type))
return false;
if (!define_binary_symbol_constants(type))
diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am
index 5a9a539..2ed2aa5 100644
--- a/plugins/pychrysalide/glibext/Makefile.am
+++ b/plugins/pychrysalide/glibext/Makefile.am
@@ -1,30 +1,32 @@
noinst_LTLIBRARIES = libpychrysaglibext.la
-libpychrysaglibext_la_SOURCES = \
- constants.h constants.c \
- binarycursor.h binarycursor.c \
- binportion.h binportion.c \
- buffercache.h buffercache.c \
- bufferline.h bufferline.c \
- bufferview.h bufferview.c \
- configuration.h configuration.c \
- linecursor.h linecursor.c \
- linegen.h linegen.c \
- loadedpanel.h loadedpanel.c \
- module.h module.c \
- named.h named.c \
+libpychrysaglibext_la_SOURCES = \
+ constants.h constants.c \
+ binarycursor.h binarycursor.c \
+ binportion.h binportion.c \
+ buffercache.h buffercache.c \
+ bufferline.h bufferline.c \
+ comparison.h comparison.c \
+ configuration.h configuration.c \
+ linecursor.h linecursor.c \
+ linegen.h linegen.c \
+ module.h module.c \
singleton.h singleton.c
-libpychrysaglibext_la_LDFLAGS =
+if BUILD_GTK_SUPPORT
+libpychrysaglibext_la_SOURCES += \
+ bufferview.h bufferview.c \
+ loadedpanel.h loadedpanel.c \
+ named.h named.c
-devdir = $(includedir)/chrysalide/$(subdir)
+endif
-dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=)
+libpychrysaglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+devdir = $(includedir)/chrysalide/$(subdir)
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=)
diff --git a/plugins/pychrysalide/glibext/binarycursor.c b/plugins/pychrysalide/glibext/binarycursor.c
index 4da040a..91dce3e 100644
--- a/plugins/pychrysalide/glibext/binarycursor.c
+++ b/plugins/pychrysalide/glibext/binarycursor.c
@@ -321,7 +321,7 @@ bool ensure_python_binary_cursor_is_registered(void)
if (!ensure_python_line_cursor_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type, get_python_line_cursor_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c
index 060f001..70eb314 100644
--- a/plugins/pychrysalide/glibext/binportion.c
+++ b/plugins/pychrysalide/glibext/binportion.c
@@ -112,7 +112,7 @@ static PyObject *py_bin_portion_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -674,7 +674,7 @@ bool ensure_python_binary_portion_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type))
return false;
if (!define_binary_portion_constants(type))
diff --git a/plugins/pychrysalide/glibext/buffercache.c b/plugins/pychrysalide/glibext/buffercache.c
index 0cf3342..03301d6 100644
--- a/plugins/pychrysalide/glibext/buffercache.c
+++ b/plugins/pychrysalide/glibext/buffercache.c
@@ -88,9 +88,13 @@ static PyObject *py_buffer_cache_get_line_flags(PyObject *, PyObject *);
/* Retire une propriété particulière attachée à une ligne. */
static PyObject *py_buffer_cache_remove_line_flag(PyObject *, PyObject *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve une ligne au sein d'un tampon avec un indice. */
static PyObject *py_buffer_cache_find_line_by_index(PyObject *, PyObject *);
+#endif
+
/* Avance autant que possible vers une ligne idéale. */
static PyObject *py_buffer_cache_look_for_flag(PyObject *, PyObject *);
@@ -153,7 +157,7 @@ static PyObject *py_buffer_cache_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -825,6 +829,9 @@ static PyObject *py_buffer_cache_remove_line_flag(PyObject *self, PyObject *args
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : self = classe représentant un tampon de code. *
@@ -883,6 +890,9 @@ static PyObject *py_buffer_cache_find_line_by_index(PyObject *self, PyObject *ar
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : self = classe représentant un tampon de code. *
@@ -1157,7 +1167,9 @@ PyTypeObject *get_python_buffer_cache_type(void)
BUFFER_CACHE_ADD_LINE_FLAG_METHOD,
BUFFER_CACHE_GET_LINE_FLAGS_METHOD,
BUFFER_CACHE_REMOVE_LINE_FLAG_METHOD,
+#ifdef INCLUDE_GTK_SUPPORT
BUFFER_CACHE_FIND_LINE_BY_INDEX_METHOD,
+#endif
BUFFER_CACHE_LOOK_FOR_FLAG_METHOD,
{ NULL }
};
@@ -1221,7 +1233,7 @@ bool ensure_python_buffer_cache_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c
index c88fe7f..09404bc 100644
--- a/plugins/pychrysalide/glibext/bufferline.c
+++ b/plugins/pychrysalide/glibext/bufferline.c
@@ -106,7 +106,7 @@ static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -339,7 +339,7 @@ bool ensure_python_buffer_line_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type))
return false;
if (!define_line_segment_constants(type))
diff --git a/plugins/pychrysalide/glibext/bufferview.c b/plugins/pychrysalide/glibext/bufferview.c
index 98cc10a..d4cbdc2 100644
--- a/plugins/pychrysalide/glibext/bufferview.c
+++ b/plugins/pychrysalide/glibext/bufferview.c
@@ -146,7 +146,7 @@ bool ensure_python_buffer_view_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/comparison.c b/plugins/pychrysalide/glibext/comparison.c
new file mode 100644
index 0000000..548f700
--- /dev/null
+++ b/plugins/pychrysalide/glibext/comparison.c
@@ -0,0 +1,341 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparison.c - équivalent Python du fichier "glibext/comparison.h"
+ *
+ * Copyright (C) 2018-2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "comparison.h"
+
+
+#include <pygobject.h>
+
+
+#include <glibext/comparison-int.h>
+
+
+#include "constants.h"
+#include "../access.h"
+#include "../helpers.h"
+#include "../analysis/content.h"
+
+
+
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void py_comparable_item_interface_init(GComparableItemIface *, gpointer *);
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+static bool py_comparable_item_compare_rich(const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *);
+
+
+
+/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+
+
+/* Effectue une comparaison avec un objet 'ComparableItem'. */
+static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* unused = adresse non utilisée ici. *
+* *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_comparable_item_interface_init(GComparableItemIface *iface, gpointer *unused)
+{
+
+#define COMPARABLE_ITEM_DOC \
+ "ComparableItem provides an interface to compare objects.\n" \
+ "\n" \
+ "A typical class declaration for a new implementation looks like:\n" \
+ "\n" \
+ " class NewImplem(GObject.Object, ComparableItem):\n" \
+ " ...\n" \
+ "\n"
+
+ iface->cmp_rich = py_comparable_item_compare_rich;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = premier objet à cnsulter pour une comparaison. *
+* other = second objet à cnsulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyitem; /* Objet Python concerné #1 */
+ PyObject *pyother; /* Objet Python concerné #2 */
+ PyObject *pyret; /* Bilan de consultation */
+ int ret; /* Bilan d'une conversion */
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pyitem = pygobject_new(G_OBJECT(item));
+ pyother = pygobject_new(G_OBJECT(other));
+
+ pyret = PyObject_RichCompare(pyitem, pyother, op);
+
+ if (pyret != NULL)
+ {
+ ret = PyBool_Check(pyret);
+
+ if (ret)
+ {
+ *status = (pyret == Py_True);
+ result = true;
+ }
+
+ Py_DECREF(pyret);
+
+ }
+
+ Py_DECREF(pyother);
+ Py_DECREF(pyitem);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONNEXION AVEC L'API DE PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier object Python à consulter. *
+* b = second object Python à consulter. *
+* op = type de comparaison menée. *
+* *
+* Description : Effectue une comparaison avec un objet 'ComparableItem'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_comparable_item_richcompare(PyObject *a, PyObject *b, int op)
+{
+ PyObject *result; /* Bilan à retourner */
+ int ret; /* Bilan de lecture des args. */
+ GComparableItem *item_a; /* Instance à manipuler #1 */
+ GComparableItem *item_b; /* Instance à manipuler #2 */
+ bool valid; /* Indication de validité */
+ bool status; /* Résultat d'une comparaison */
+
+ ret = PyObject_IsInstance(b, (PyObject *)get_python_comparable_item_type());
+ if (!ret)
+ {
+ result = Py_NotImplemented;
+ goto cmp_done;
+ }
+
+ item_a = G_COMPARABLE_ITEM(pygobject_get(a));
+ item_b = G_COMPARABLE_ITEM(pygobject_get(b));
+
+ valid = g_comparable_item_compare_rich(item_a, item_b, op, &status);
+
+ if (valid)
+ result = status ? Py_True : Py_False;
+ else
+ result = Py_NotImplemented;
+
+ cmp_done:
+
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_comparable_item_type(void)
+{
+ static PyMethodDef py_comparable_item_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_comparable_item_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_comparable_item_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.glibext.ComparableItem",
+ .tp_basicsize = sizeof(PyObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = COMPARABLE_ITEM_DOC,
+
+ .tp_richcompare = py_comparable_item_richcompare,
+
+ .tp_methods = py_comparable_item_methods,
+ .tp_getset = py_comparable_item_getseters,
+
+ };
+
+ return &py_comparable_item_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.....ComparableItem'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_comparable_item_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ComparableItem' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ static GInterfaceInfo info = { /* Paramètres d'inscription */
+
+ .interface_init = (GInterfaceInitFunc)py_comparable_item_interface_init,
+ .interface_finalize = NULL,
+ .interface_data = NULL,
+
+ };
+
+ type = get_python_comparable_item_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.glibext");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_interface_for_pygobject(dict, G_TYPE_COMPARABLE_ITEM, type, &info))
+ return false;
+
+ if (!define_comparable_item_constants(type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en élément comparable. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_comparable_item(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_item_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to comparable item");
+ break;
+
+ case 1:
+ *((GComparableItem **)dst) = G_COMPARABLE_ITEM(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/comparison.h b/plugins/pychrysalide/glibext/comparison.h
new file mode 100644
index 0000000..79f7092
--- /dev/null
+++ b/plugins/pychrysalide/glibext/comparison.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparison.h - prototypes pour l'équivalent Python du fichier "glibext/comparison.h"
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_comparable_item_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.glibext.ComparableItem'. */
+bool ensure_python_comparable_item_is_registered(void);
+
+/* Tente de convertir en élément comparable. */
+int convert_to_comparable_item(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H */
diff --git a/plugins/pychrysalide/glibext/configuration.c b/plugins/pychrysalide/glibext/configuration.c
index b0586af..c630331 100644
--- a/plugins/pychrysalide/glibext/configuration.c
+++ b/plugins/pychrysalide/glibext/configuration.c
@@ -174,7 +174,7 @@ static PyObject *py_config_param_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -733,7 +733,7 @@ bool ensure_python_config_param_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type))
return false;
if (!define_config_param_constants(type))
@@ -1036,7 +1036,7 @@ static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObj
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -1580,7 +1580,7 @@ bool ensure_python_generic_config_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c
index 373d1bf..169ffa2 100644
--- a/plugins/pychrysalide/glibext/constants.c
+++ b/plugins/pychrysalide/glibext/constants.c
@@ -27,10 +27,13 @@
#include <i18n.h>
#include <glibext/bufferline.h>
+#include <glibext/comparison.h>
#include <glibext/configuration.h>
#include <glibext/linesegment.h>
#include <glibext/gbinportion.h>
-#include <glibext/gloadedpanel.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <glibext/gloadedpanel.h>
+#endif
#include "../helpers.h"
@@ -250,6 +253,48 @@ int convert_to_buffer_line_flags(PyObject *arg, void *dst)
* *
* Paramètres : type = type dont le dictionnaire est à compléter. *
* *
+* Description : Définit les constantes relatives aux modes de comparaison. *
+* *
+* Retour : true en cas de succès de l'opération, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_comparable_item_constants(PyTypeObject *type)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *values; /* Groupe de valeurs à établir */
+
+ values = PyDict_New();
+
+ result = add_const_to_group(values, "LT", RCO_LT);
+ if (result) result = add_const_to_group(values, "LE", RCO_LE);
+ if (result) result = add_const_to_group(values, "EQ", RCO_EQ);
+ if (result) result = add_const_to_group(values, "NE", RCO_NE);
+ if (result) result = add_const_to_group(values, "GT", RCO_GT);
+ if (result) result = add_const_to_group(values, "GE", RCO_GE);
+
+ if (!result)
+ {
+ Py_DECREF(values);
+ goto exit;
+ }
+
+ result = attach_constants_group_to_type(type, true, "RichCmpOperation", values,
+ "Modes for objects comparison.");
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type dont le dictionnaire est à compléter. *
+* *
* Description : Définit les constantes relatives aux paramètres de config. *
* *
* Retour : true en cas de succès de l'opération, false sinon. *
@@ -471,6 +516,9 @@ int convert_to_rendering_tag_type(PyObject *arg, void *dst)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : type = type dont le dictionnaire est à compléter. *
@@ -566,3 +614,6 @@ int convert_to_scroll_position_tweak(PyObject *arg, void *dst)
return result;
}
+
+
+#endif
diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h
index 342b7ad..4a4f6da 100644
--- a/plugins/pychrysalide/glibext/constants.h
+++ b/plugins/pychrysalide/glibext/constants.h
@@ -43,6 +43,9 @@ bool define_buffer_line_constants(PyTypeObject *);
/* Tente de convertir en constante BufferLineFlags. */
int convert_to_buffer_line_flags(PyObject *, void *);
+/* Définit les constantes relatives aux modes de comparaison. */
+bool define_comparable_item_constants(PyTypeObject *);
+
/* Définit les constantes relatives aux paramètres de configuration. */
bool define_config_param_constants(PyTypeObject *);
@@ -55,12 +58,16 @@ bool define_line_segment_constants(PyTypeObject *);
/* Tente de convertir en constante RenderingTagType. */
int convert_to_rendering_tag_type(PyObject *, void *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Définit les constantes relatives aux panneaux de chargement. */
bool define_loaded_panel_constants(PyTypeObject *);
/* Tente de convertir en constante ScrollPositionTweak. */
int convert_to_scroll_position_tweak(PyObject *, void *);
+#endif
+
#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_H */
diff --git a/plugins/pychrysalide/glibext/linecursor.c b/plugins/pychrysalide/glibext/linecursor.c
index 217234a..4ac7f85 100644
--- a/plugins/pychrysalide/glibext/linecursor.c
+++ b/plugins/pychrysalide/glibext/linecursor.c
@@ -184,7 +184,7 @@ bool ensure_python_line_cursor_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c
index 634cf5c..3e4307a 100644
--- a/plugins/pychrysalide/glibext/module.c
+++ b/plugins/pychrysalide/glibext/module.c
@@ -33,6 +33,7 @@
#include "buffercache.h"
#include "bufferline.h"
#include "bufferview.h"
+#include "comparison.h"
#include "configuration.h"
#include "linecursor.h"
#include "linegen.h"
@@ -111,14 +112,19 @@ bool populate_glibext_module(void)
if (result) result = ensure_python_binary_portion_is_registered();
if (result) result = ensure_python_buffer_cache_is_registered();
if (result) result = ensure_python_buffer_line_is_registered();
+#ifdef INCLUDE_GTK_SUPPORT
if (result) result = ensure_python_buffer_view_is_registered();
+#endif
+ if (result) result = ensure_python_comparable_item_is_registered();
if (result) result = ensure_python_config_param_is_registered();
if (result) result = ensure_python_config_param_iterator_is_registered();
if (result) result = ensure_python_generic_config_is_registered();
if (result) result = ensure_python_line_cursor_is_registered();
if (result) result = ensure_python_line_generator_is_registered();
+#ifdef INCLUDE_GTK_SUPPORT
if (result) result = ensure_python_loaded_panel_is_registered();
if (result) result = ensure_python_named_widget_is_registered();
+#endif
if (result) result = ensure_python_singleton_factory_is_registered();
assert(result);
diff --git a/plugins/pychrysalide/glibext/singleton.c b/plugins/pychrysalide/glibext/singleton.c
index d00648c..8491473 100644
--- a/plugins/pychrysalide/glibext/singleton.c
+++ b/plugins/pychrysalide/glibext/singleton.c
@@ -922,7 +922,7 @@ static PyObject *py_singleton_factory_new(PyTypeObject *type, PyObject *args, Py
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -1110,7 +1110,7 @@ bool ensure_python_singleton_factory_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_SINGLETON_FACTORY, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_SINGLETON_FACTORY, type))
return false;
}
diff --git a/plugins/pychrysalide/gtkext/Makefile.am b/plugins/pychrysalide/gtkext/Makefile.am
index 3d15cb8..2e1260f 100644
--- a/plugins/pychrysalide/gtkext/Makefile.am
+++ b/plugins/pychrysalide/gtkext/Makefile.am
@@ -1,19 +1,20 @@
noinst_LTLIBRARIES = libpychrysagtkext.la
-libpychrysagtkext_la_SOURCES = \
- blockdisplay.h blockdisplay.c \
- bufferdisplay.h bufferdisplay.c \
- displaypanel.h displaypanel.c \
- dockable.h dockable.c \
- easygtk.h easygtk.c \
- module.h module.c \
+libpychrysagtkext_la_SOURCES = \
+ blockdisplay.h blockdisplay.c \
+ bufferdisplay.h bufferdisplay.c \
+ displaypanel.h displaypanel.c \
+ dockable.h dockable.c \
+ easygtk.h easygtk.c \
+ module.h module.c \
named.h named.c
-libpychrysagtkext_la_LIBADD = \
+libpychrysagtkext_la_LIBADD = \
graph/libpychrysagtkextgraph.la
-libpychrysagtkext_la_LDFLAGS =
+libpychrysagtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
@@ -21,10 +22,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysagtkext_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
SUBDIRS = graph
diff --git a/plugins/pychrysalide/gtkext/blockdisplay.c b/plugins/pychrysalide/gtkext/blockdisplay.c
index 6741553..b4b8515 100644
--- a/plugins/pychrysalide/gtkext/blockdisplay.c
+++ b/plugins/pychrysalide/gtkext/blockdisplay.c
@@ -115,7 +115,7 @@ bool ensure_python_block_display_is_registered(void)
if (!ensure_python_buffer_display_is_registered())
return false;
- if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, type, get_python_buffer_display_type()))
+ if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, type))
return false;
}
diff --git a/plugins/pychrysalide/gtkext/bufferdisplay.c b/plugins/pychrysalide/gtkext/bufferdisplay.c
index 310e60a..4babcc8 100644
--- a/plugins/pychrysalide/gtkext/bufferdisplay.c
+++ b/plugins/pychrysalide/gtkext/bufferdisplay.c
@@ -115,7 +115,7 @@ bool ensure_python_buffer_display_is_registered(void)
if (!ensure_python_display_panel_is_registered())
return false;
- if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, type, get_python_display_panel_type()))
+ if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, type))
return false;
}
diff --git a/plugins/pychrysalide/gtkext/displaypanel.c b/plugins/pychrysalide/gtkext/displaypanel.c
index dc7b8e5..a871af9 100644
--- a/plugins/pychrysalide/gtkext/displaypanel.c
+++ b/plugins/pychrysalide/gtkext/displaypanel.c
@@ -98,42 +98,23 @@ PyTypeObject *get_python_display_panel_type(void)
bool ensure_python_display_panel_is_registered(void)
{
- bool result; /* Bilan à retourner */
PyTypeObject *type; /* Type Python 'DisplayPanel' */
- PyObject *parent_mod; /* Module Python Fixed */
- PyObject *fixed; /* Module "GtkFixed" */
PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
- result = false;
-
type = get_python_display_panel_type();
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
module = get_access_to_python_module("pychrysalide.gtkext");
- parent_mod = PyImport_ImportModule("gi.repository.Gtk");
-
- if (parent_mod == NULL)
- goto rpdp_exit;
-
- fixed = PyObject_GetAttrString(parent_mod, "Fixed");
-
- Py_DECREF(parent_mod);
-
dict = PyModule_GetDict(module);
- result = register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL, type, (PyTypeObject *)fixed);
- Py_DECREF(fixed);
+ if (!register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL, type))
+ return false;
}
- else
- result = true;
-
- rpdp_exit:
-
- return result;
+ return true;
}
diff --git a/plugins/pychrysalide/gtkext/graph/Makefile.am b/plugins/pychrysalide/gtkext/graph/Makefile.am
index abcdb88..25e3088 100644
--- a/plugins/pychrysalide/gtkext/graph/Makefile.am
+++ b/plugins/pychrysalide/gtkext/graph/Makefile.am
@@ -1,21 +1,16 @@
noinst_LTLIBRARIES = libpychrysagtkextgraph.la
-libpychrysagtkextgraph_la_SOURCES = \
- constants.h constants.c \
- cluster.h cluster.c \
- edge.h edge.c \
+libpychrysagtkextgraph_la_SOURCES = \
+ constants.h constants.c \
+ cluster.h cluster.c \
+ edge.h edge.c \
module.h module.c
-libpychrysagtkextgraph_la_LDFLAGS =
+libpychrysagtkextgraph_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysagtkextgraph_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/gtkext/graph/cluster.c b/plugins/pychrysalide/gtkext/graph/cluster.c
index fc73276..11cb8fa 100644
--- a/plugins/pychrysalide/gtkext/graph/cluster.c
+++ b/plugins/pychrysalide/gtkext/graph/cluster.c
@@ -656,7 +656,7 @@ bool ensure_python_graph_cluster_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_CLUSTER, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_CLUSTER, type))
return false;
}
diff --git a/plugins/pychrysalide/gtkext/graph/edge.c b/plugins/pychrysalide/gtkext/graph/edge.c
index ce20ce9..d016e30 100644
--- a/plugins/pychrysalide/gtkext/graph/edge.c
+++ b/plugins/pychrysalide/gtkext/graph/edge.c
@@ -267,7 +267,7 @@ bool ensure_python_graph_edge_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_EDGE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_EDGE, type))
return false;
if (!define_graph_edge_constants(type))
diff --git a/plugins/pychrysalide/gtkext/named.c b/plugins/pychrysalide/gtkext/named.c
index 1d336f1..ee963de 100644
--- a/plugins/pychrysalide/gtkext/named.c
+++ b/plugins/pychrysalide/gtkext/named.c
@@ -99,7 +99,7 @@ static PyObject *py_built_named_widget_new(PyTypeObject *type, PyObject *args, P
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -312,7 +312,7 @@ bool ensure_python_built_named_widget_is_registered(void)
if (!ensure_python_named_widget_is_registered())
return false;
- if (!register_class_for_pygobject(dict, GTK_TYPE_BUILT_NAMED_WIDGET, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, GTK_TYPE_BUILT_NAMED_WIDGET, type))
return false;
}
diff --git a/plugins/pychrysalide/gui/Makefile.am b/plugins/pychrysalide/gui/Makefile.am
index 969701b..de2e888 100644
--- a/plugins/pychrysalide/gui/Makefile.am
+++ b/plugins/pychrysalide/gui/Makefile.am
@@ -1,18 +1,19 @@
noinst_LTLIBRARIES = libpychrysagui.la
-libpychrysagui_la_SOURCES = \
- constants.h constants.c \
- item.h item.c \
- menubar.h menubar.c \
- module.h module.c \
+libpychrysagui_la_SOURCES = \
+ constants.h constants.c \
+ item.h item.c \
+ menubar.h menubar.c \
+ module.h module.c \
panel.h panel.c
-libpychrysagui_la_LIBADD = \
- core/libpychrysaguicore.la \
+libpychrysagui_la_LIBADD = \
+ core/libpychrysaguicore.la \
panels/libpychrysaguipanels.la
-libpychrysagui_la_LDFLAGS =
+libpychrysagui_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
@@ -20,9 +21,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysagui_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = core panels
diff --git a/plugins/pychrysalide/gui/core/Makefile.am b/plugins/pychrysalide/gui/core/Makefile.am
index 7b3c796..8f49176 100644
--- a/plugins/pychrysalide/gui/core/Makefile.am
+++ b/plugins/pychrysalide/gui/core/Makefile.am
@@ -1,21 +1,16 @@
noinst_LTLIBRARIES = libpychrysaguicore.la
-libpychrysaguicore_la_SOURCES = \
- global.h global.c \
- items.h items.c \
- module.h module.c \
+libpychrysaguicore_la_SOURCES = \
+ global.h global.c \
+ items.h items.c \
+ module.h module.c \
panels.h panels.c
-libpychrysaguicore_la_LDFLAGS =
+libpychrysaguicore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaguicore_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/gui/item.c b/plugins/pychrysalide/gui/item.c
index eb140fb..0c604b5 100644
--- a/plugins/pychrysalide/gui/item.c
+++ b/plugins/pychrysalide/gui/item.c
@@ -691,7 +691,7 @@ bool ensure_python_editor_item_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, type))
return false;
}
diff --git a/plugins/pychrysalide/gui/menubar.c b/plugins/pychrysalide/gui/menubar.c
index 5c6270e..29b76ac 100644
--- a/plugins/pychrysalide/gui/menubar.c
+++ b/plugins/pychrysalide/gui/menubar.c
@@ -160,7 +160,10 @@ bool ensure_python_menu_bar_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_MENU_BAR, type, get_python_editor_item_type()))
+ if (!ensure_python_editor_item_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, G_TYPE_MENU_BAR, type))
return false;
}
diff --git a/plugins/pychrysalide/gui/panel.c b/plugins/pychrysalide/gui/panel.c
index 2afb2a1..949243c 100644
--- a/plugins/pychrysalide/gui/panel.c
+++ b/plugins/pychrysalide/gui/panel.c
@@ -164,7 +164,7 @@ static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -1188,8 +1188,7 @@ bool ensure_python_panel_item_is_registered(void)
if (!ensure_python_dockable_is_registered())
return false;
- if (!_register_class_for_pygobject(dict, G_TYPE_PANEL_ITEM, type,
- get_python_editor_item_type(), get_python_dockable_type(), NULL))
+ if (!register_class_for_pygobject(dict, G_TYPE_PANEL_ITEM, type))
return false;
if (!define_panel_item_constants(type))
diff --git a/plugins/pychrysalide/gui/panels/Makefile.am b/plugins/pychrysalide/gui/panels/Makefile.am
index 351e34f..067c798 100644
--- a/plugins/pychrysalide/gui/panels/Makefile.am
+++ b/plugins/pychrysalide/gui/panels/Makefile.am
@@ -1,19 +1,14 @@
noinst_LTLIBRARIES = libpychrysaguipanels.la
-libpychrysaguipanels_la_SOURCES = \
- module.h module.c \
+libpychrysaguipanels_la_SOURCES = \
+ module.h module.c \
updating.h updating.c
-libpychrysaguipanels_la_LDFLAGS =
+libpychrysaguipanels_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaguipanels_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index e0a3340..c2b1868 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -32,7 +32,9 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include <gtk/gtk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gtk/gtk.h>
+#endif
#include <i18n.h>
@@ -508,9 +510,10 @@ bool register_python_module_object(PyObject *module, PyTypeObject *type)
/******************************************************************************
* *
-* Paramètres : type = type du nouvel objet à mettre en place. *
-* args = éventuelle liste d'arguments. *
-* kwds = éventuel dictionnaire de valeurs mises à disposition. *
+* Paramètres : type = type du nouvel objet à mettre en place. *
+* gbase = type de base natif. *
+* args = éventuelle liste d'arguments. *
+* kwds = éventuel dictionnaire de valeurs mises à disposition.*
* *
* Description : Accompagne la création d'une instance dérivée en Python. *
* *
@@ -520,15 +523,18 @@ bool register_python_module_object(PyObject *module, PyTypeObject *type)
* *
******************************************************************************/
-PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *type, PyObject *args, PyObject *kwds, PyTypeObject *base, GType base_gtype)
+PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *type, GType gbase, PyObject *args, PyObject *kwds)
{
PyObject *result; /* Objet à retourner */
+ PyTypeObject *base; /* Type parent version Python */
bool first_time; /* Evite les multiples passages*/
GType gtype; /* Nouveau type de processeur */
bool status; /* Bilan d'un enregistrement */
/* Validations diverses */
+ base = pygobject_lookup_class(gbase);
+
if (type == base)
goto simple_way;
@@ -536,11 +542,11 @@ PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *type, PyObject *ar
first_time = (g_type_from_name(type->tp_name) == 0);
- gtype = build_dynamic_type(base_gtype, type->tp_name, NULL, NULL, NULL);
+ gtype = build_dynamic_type(gbase, type->tp_name, NULL, NULL, NULL);
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -565,6 +571,70 @@ PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *type, PyObject *ar
/******************************************************************************
* *
+* Paramètres : type = type du nouvel objet à mettre en place. *
+* gbase = type de base natif. *
+* cinit = procédure d'initialisation de la classe associée. *
+* args = éventuelle liste d'arguments. *
+* kwds = éventuel dictionnaire de valeurs mises à disposition.*
+* *
+* Description : Accompagne la création d'une instance dérivée en Python. *
+* *
+* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyObject *python_abstract_constructor_with_dynamic_gtype(PyTypeObject *type, GType gbase, GClassInitFunc cinit, PyObject *args, PyObject *kwds)
+{
+ PyObject *result; /* Objet à retourner */
+ PyTypeObject *base; /* Type parent version Python */
+ bool first_time; /* Evite les multiples passages*/
+ GType gtype; /* Nouveau type de processeur */
+ bool status; /* Bilan d'un enregistrement */
+
+ /* Validations diverses */
+
+ base = pygobject_lookup_class(gbase);
+
+ if (type == base)
+ {
+ result = NULL;
+ PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
+ goto exit;
+ }
+
+ /* Mise en place d'un type dédié */
+
+ first_time = (g_type_from_name(type->tp_name) == 0);
+
+ gtype = build_dynamic_type(gbase, type->tp_name, cinit, NULL, NULL);
+
+ if (first_time)
+ {
+ status = register_class_for_dynamic_pygobject(gtype, type);
+
+ if (!status)
+ {
+ result = NULL;
+ goto exit;
+ }
+
+ }
+
+ /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
+
+ result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : type = type du nouvel objet à mettre en place. *
* args = éventuelle liste d'arguments. *
* kwds = éventuel dictionnaire de valeurs mises à disposition. *
@@ -821,7 +891,6 @@ static void define_auto_documentation(PyTypeObject *type)
* Paramètres : dict = dictionnaire où conserver une référence au type créé.*
* gtype = type dans sa version GLib. *
* type = type dans sa version Python. *
-* base = type de base de l'objet. *
* *
* Description : Enregistre correctement une surcouche de conversion GObject. *
* *
@@ -831,13 +900,11 @@ static void define_auto_documentation(PyTypeObject *type)
* *
******************************************************************************/
-bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type, PyTypeObject *base, ...)
+bool register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type)
{
bool result; /* Bilan à retourner */
- Py_ssize_t size; /* Taille de liste actuelle */
- PyObject *static_bases; /* Base(s) de l'objet */
- va_list ap; /* Parcours des arguments */
- PyTypeObject *static_base; /* Base à rajouter à la liste */
+ GType parent_type; /* Type parent version GObject */
+ PyTypeObject *base; /* Type parent version Python */
assert(gtype != G_TYPE_INVALID);
@@ -862,45 +929,17 @@ bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *ty
* Et quelqu'un doit se coller à la tâche. PyGObject ne fait rien, donc...
*/
+ parent_type = g_type_parent(gtype);
+
+ base = pygobject_lookup_class(parent_type);
+
if (type->tp_basicsize < base->tp_basicsize)
{
assert(type->tp_basicsize == 0);
type->tp_basicsize = base->tp_basicsize;
}
- size = 1;
- static_bases = PyTuple_New(size);
-
- Py_INCREF(base);
- PyTuple_SetItem(static_bases, 0, (PyObject *)base);
-
- va_start(ap, base);
-
- while (1)
- {
- static_base = va_arg(ap, PyTypeObject *);
-
- if (static_base == NULL) break;
-
- _PyTuple_Resize(&static_bases, ++size);
-
- Py_INCREF(static_base);
- PyTuple_SetItem(static_bases, size - 1, (PyObject *)static_base);
-
- }
-
- va_end(ap);
-
- /**
- * les renseignements suivants ne semblent pas nécessaires...
- */
-
- /*
- type->tp_weaklistoffset = offsetof(PyGObject, weakreflist);
- type->tp_dictoffset = offsetof(PyGObject, inst_dict);
- */
-
- pygobject_register_class(dict, NULL, gtype, type, static_bases);
+ pygobject_register_class(dict, NULL, gtype, type, NULL);
if (PyErr_Occurred() == NULL)
result = true;
@@ -977,10 +1016,8 @@ bool register_interface_for_pygobject(PyObject *dict, GType gtype, PyTypeObject
/******************************************************************************
* *
-* Paramètres : dict = dictionnaire où conserver une référence au type créé.*
-* gtype = type dans sa version GLib. *
+* Paramètres : gtype = type dans sa version GLib. *
* type = type dans sa version Python. *
-* base = type de base de l'objet. *
* *
* Description : Enregistre un type Python dérivant d'un type GLib dynamique. *
* *
@@ -990,7 +1027,7 @@ bool register_interface_for_pygobject(PyObject *dict, GType gtype, PyTypeObject
* *
******************************************************************************/
-bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTypeObject *base)
+bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type)
{
bool result; /* Bilan à retourner */
PyTypeObject *legacy_parent; /* Type parent d'origine */
@@ -1045,9 +1082,9 @@ bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTyp
dict = PyModule_GetDict(module);
- result = _register_class_for_pygobject(dict, gtype, type, &PyGObject_Type, base, NULL);
+ result = register_class_for_pygobject(dict, gtype, type);
- Py_TYPE(type) = legacy_parent;
+ Py_SET_TYPE(type, legacy_parent);
/**
* Comme la mise en place dynamique de nouveau GType court-circuite les
@@ -1210,6 +1247,9 @@ int convert_to_gobject(PyObject *arg, void *dst)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : arg = argument quelconque à tenter de convertir. *
@@ -1320,6 +1360,9 @@ int convert_to_gtk_container(PyObject *arg, void *dst)
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : color = couleur dans sa définition native à copier. *
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index 52a9370..57cf96d 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -29,7 +29,9 @@
#include <assert.h>
#include <glib-object.h>
#include <stdbool.h>
-#include <gdk/gdk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gdk/gdk.h>
+#endif
@@ -85,26 +87,21 @@ bool register_python_module_object(PyObject *, PyTypeObject *);
#name "(" args ")\n--\n\n" doc \
}
-#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \
- { \
- #name, (PyCFunction)py_return_none, \
- flags, \
- #name "(" args ")\n--\n\n" doc \
+#define PYTHON_WRAPPER_DEF_WITH(name, args, flags, defcb, doc) \
+ { \
+ #name, (PyCFunction)defcb, \
+ flags, \
+ #name "(" args ")\n--\n\n" doc \
}
-#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc)\
- { \
- #name, (PyCFunction)py_return_false, \
- flags, \
- #name "(" args ")\n--\n\n" doc \
- }
+#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \
+ PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_none, doc)
-#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc)\
- { \
- #name, (PyCFunction)py_return_true, \
- flags, \
- #name "(" args ")\n--\n\n" doc \
- }
+#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc) \
+ PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_false, doc)
+
+#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc) \
+ PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_true, doc)
/**
* Il ne semble pas exister de moyen de déterminer
@@ -159,18 +156,30 @@ bool register_python_module_object(PyObject *, PyTypeObject *);
/* Accompagne la création d'une instance dérivée en Python. */
-PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *, PyObject *, PyObject *, PyTypeObject *, GType);
-
-
-#define CREATE_DYN_CONSTRUCTOR(pyname, gbase) \
-static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \
-static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \
-{ \
- PyObject *result; /* Objet à retourner */ \
- PyTypeObject *base; /* Type de base à dériver */ \
- base = get_python_ ## pyname ## _type(); \
- result = python_constructor_with_dynamic_gtype(type, args, kwds, base, gbase); \
- return result; \
+PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *, GType, PyObject *, PyObject *);
+
+/* Accompagne la création d'une instance dérivée en Python. */
+PyObject *python_abstract_constructor_with_dynamic_gtype(PyTypeObject *, GType, GClassInitFunc, PyObject *, PyObject *);
+
+
+#define CREATE_DYN_CONSTRUCTOR(pyname, gbase) \
+static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \
+static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \
+{ \
+ PyObject *result; /* Objet à retourner */ \
+ result = python_constructor_with_dynamic_gtype(type, gbase, args, kwds); \
+ return result; \
+}
+
+
+#define CREATE_DYN_ABSTRACT_CONSTRUCTOR(pyname, gbase, cinit) \
+static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \
+static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \
+{ \
+ PyObject *result; /* Objet à retourner */ \
+ result = python_abstract_constructor_with_dynamic_gtype(type, gbase, (GClassInitFunc)cinit, \
+ args, kwds); \
+ return result; \
}
@@ -216,16 +225,13 @@ PyTypeObject *define_python_dynamic_type(const PyTypeObject *);
/* Enregistre correctement une surcouche de conversion GObject. */
-bool _register_class_for_pygobject(PyObject *, GType, PyTypeObject *, PyTypeObject *, ...);
-
-#define register_class_for_pygobject(dict, gtype, type, base) \
- _register_class_for_pygobject(dict, gtype, type, base, NULL)
+bool register_class_for_pygobject(PyObject *, GType, PyTypeObject *);
/* Enregistre correctement une interface GObject pour Python. */
bool register_interface_for_pygobject(PyObject *, GType, PyTypeObject *, const GInterfaceInfo *);
/* Enregistre un type Python dérivant d'un type GLib dynamique. */
-bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *);
+bool register_class_for_dynamic_pygobject(GType, PyTypeObject *);
/* Fait suivre à la partie GObject une initialisation nouvelle. */
int forward_pygobjet_init(PyObject *);
@@ -236,12 +242,36 @@ int convert_to_gtype(PyObject *, void *);
/* Tente de convertir en instance GObject. */
int convert_to_gobject(PyObject *, void *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Tente de convertir en instance de composant GTK. */
int convert_to_gtk_widget(PyObject *, void *);
/* Tente de convertir en instance de conteneur GTK. */
int convert_to_gtk_container(PyObject *, void *);
+#endif
+
+
+#if !defined(INCLUDE_GTK_SUPPORT) && !defined(HOMEMADE_RGBA)
+
+# define HOMEMADE_RGBA
+
+/**
+ * Copie depuis /usr/include/gtk-3.0/gdk/gdkrgba.h
+ */
+typedef struct _GdkRGBA
+{
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+ gdouble alpha;
+
+} GdkRGBA;
+
+#endif
+
+
/* Construit un objet Python pour une couleur RGBA. */
PyObject *create_gdk_rgba(const GdkRGBA *);
diff --git a/plugins/pychrysalide/mangling/Makefile.am b/plugins/pychrysalide/mangling/Makefile.am
index c3294e0..640e420 100644
--- a/plugins/pychrysalide/mangling/Makefile.am
+++ b/plugins/pychrysalide/mangling/Makefile.am
@@ -1,23 +1,14 @@
noinst_LTLIBRARIES = libpychrysamangling.la
-libpychrysamangling_la_SOURCES = \
- demangler.h demangler.c \
+libpychrysamangling_la_SOURCES = \
+ demangler.h demangler.c \
module.h module.c
-libpychrysamangling_la_LIBADD =
-
-libpychrysamangling_la_LDFLAGS =
+libpychrysamangling_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysamangling_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/mangling/demangler.c b/plugins/pychrysalide/mangling/demangler.c
index 5779693..fb90dca 100644
--- a/plugins/pychrysalide/mangling/demangler.c
+++ b/plugins/pychrysalide/mangling/demangler.c
@@ -264,7 +264,7 @@ PyTypeObject *get_python_compiler_demangler_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide.mangling.DexDemangler'.*
+* Description : Prend en charge l'objet 'pychrysalide....CompDemangler'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -286,7 +286,7 @@ bool ensure_python_compiler_demangler_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_COMP_DEMANGLER, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_COMP_DEMANGLER, type))
return false;
}
diff --git a/plugins/pychrysalide/mangling/demangler.h b/plugins/pychrysalide/mangling/demangler.h
index 0c31f7c..496aa21 100644
--- a/plugins/pychrysalide/mangling/demangler.h
+++ b/plugins/pychrysalide/mangling/demangler.h
@@ -34,7 +34,7 @@
/* Fournit un accès à une définition de type à diffuser. */
PyTypeObject *get_python_compiler_demangler_type(void);
-/* Prend en charge l'objet 'pychrysalide.format.elf.ElfFormat'. */
+/* Prend en charge l'objet 'pychrysalide.mangling.CompDemangler'. */
bool ensure_python_compiler_demangler_is_registered(void);
diff --git a/plugins/pychrysalide/plugins/Makefile.am b/plugins/pychrysalide/plugins/Makefile.am
index 51d1e35..bb9ed5d 100644
--- a/plugins/pychrysalide/plugins/Makefile.am
+++ b/plugins/pychrysalide/plugins/Makefile.am
@@ -1,25 +1,16 @@
noinst_LTLIBRARIES = libpychrysaplugins.la
-libpychrysaplugins_la_SOURCES = \
- constants.h constants.c \
- plugin.h plugin.c \
- module.h module.c \
+libpychrysaplugins_la_SOURCES = \
+ constants.h constants.c \
+ plugin.h plugin.c \
+ module.h module.c \
translate.h translate.c
-libpychrysaplugins_la_LIBADD =
-
-libpychrysaplugins_la_LDFLAGS =
+libpychrysaplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaplugins_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/plugins/pychrysalide/plugins/plugin.c b/plugins/pychrysalide/plugins/plugin.c
index bd9cdfe..b013345 100644
--- a/plugins/pychrysalide/plugins/plugin.c
+++ b/plugins/pychrysalide/plugins/plugin.c
@@ -51,21 +51,31 @@
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *);
-
/* Initialise la classe des greffons d'extension. */
static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer);
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(plugin_module, G_TYPE_PLUGIN_MODULE, py_plugin_module_init_gclass);
+
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds);
/* Encadre une étape de la vie d'un greffon. */
static bool py_plugin_module_manage_wrapper(GPluginModule *);
+/* Assiste la désactivation d'un greffon. */
+static bool py_plugin_module_exit(GPluginModule *);
+
/* Accompagne la fin du chargement des modules natifs. */
static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction);
+/* Fournit le nom brut associé au greffon par défaut. */
+static PyObject *py_plugin_module_get_modname_by_default(PyObject *, PyObject *);
+
+/* Fournit le nom brut associé au greffon. */
+static char *py_plugin_module_get_modname_wrapper(const GPluginModule *);
+
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Complète une liste de resources pour thème. */
static void py_plugin_module_include_theme_wrapper(const GPluginModule *, PluginAction, gboolean, char ***, size_t *);
@@ -75,6 +85,8 @@ static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *
/* Rend compte d'un affichage ou d'un retrait de panneau. */
static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *, PluginAction, GPanelItem *, bool);
+#endif
+
/* Procède à une opération liée à un contenu binaire. */
static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *);
@@ -98,42 +110,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *
-/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
-
-
-/* Ligne de représentation de code binaire (instance) */
-struct _GPythonPlugin
-{
- GPluginModule parent; /* Instance parente */
-
-};
-
-
-/* Ligne de représentation de code binaire (classe) */
-struct _GPythonPluginClass
-{
- GPluginModuleClass parent; /* Classe parente */
-
-};
-
-
-/* Initialise la classe des greffons Python. */
-static void g_python_plugin_class_init(GPythonPluginClass *);
-
-/* Initialise l'instance d'un greffon Python. */
-static void g_python_plugin_init(GPythonPlugin *);
-
-/* Supprime toutes les références externes. */
-static void g_python_plugin_dispose(GPythonPlugin *);
-
-/* Description : Procède à la libération totale de la mémoire. */
-static void g_python_plugin_finalize(GPythonPlugin *);
-
-/* Fournit le nom brut associé au greffon. */
-static char *g_python_plugin_get_modname(const GPythonPlugin *);
-
-
-
/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
@@ -161,69 +137,6 @@ static PyObject *py_plugin_module_get_interface(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : type = type du nouvel objet à mettre en place. *
-* args = éventuelle liste d'arguments. *
-* kwds = éventuel dictionnaire de valeurs mises à disposition. *
-* *
-* Description : Accompagne la création d'une instance dérivée en Python. *
-* *
-* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *result; /* Objet à retourner */
- PyTypeObject *base; /* Type de base à dériver */
- bool first_time; /* Evite les multiples passages*/
- GType gtype; /* Nouveau type de processeur */
- bool status; /* Bilan d'un enregistrement */
-
- /* Validations diverses */
-
- base = get_python_plugin_module_type();
-
- if (type == base)
- {
- result = NULL;
- PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
- goto exit;
- }
-
- /* Mise en place d'un type dédié */
-
- first_time = (g_type_from_name(type->tp_name) == 0);
-
- gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name,
- (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL);
-
- if (first_time)
- {
- status = register_class_for_dynamic_pygobject(gtype, type, base);
-
- if (!status)
- {
- result = NULL;
- goto exit;
- }
-
- }
-
- /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
-
- result = PyType_GenericNew(type, args, kwds);
-
- exit:
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : class = classe à initialiser. *
* unused = données non utilisées ici. *
* *
@@ -239,13 +152,17 @@ static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unu
{
class->init = NULL;
class->manage = py_plugin_module_manage_wrapper;
- class->exit = NULL;
+ class->exit = py_plugin_module_exit;
class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper;
+ class->get_modname = py_plugin_module_get_modname_wrapper;
+
+#ifdef INCLUDE_GTK_SUPPORT
class->include_theme = py_plugin_module_include_theme_wrapper;
class->notify_panel = py_plugin_module_notify_panel_creation_wrapper;
class->notify_docking = py_plugin_module_notify_panel_docking_wrapper;
+#endif
class->handle_content = py_plugin_module_handle_binary_content_wrapper;
class->handle_loaded = py_plugin_module_handle_loaded_content_wrapper;
@@ -498,6 +415,51 @@ static bool py_plugin_module_manage_wrapper(GPluginModule *plugin)
/******************************************************************************
* *
* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Assiste la désactivation d'un greffon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_plugin_module_exit(GPluginModule *plugin)
+{
+ bool result; /* Bilan à faire remonter */
+ plugin_interface *final; /* Interface finale conservée */
+
+ result = true;
+
+ final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
+
+ if (final != NULL)
+ {
+ if (final->name != NULL) free(final->name);
+ if (final->desc != NULL) free(final->desc);
+ if (final->version != NULL) free(final->version);
+ if (final->url != NULL) free(final->url);
+
+ assert(final->required_count == 1);
+
+ if (final->required != NULL)
+ free(final->required);
+
+ if (final->actions != NULL)
+ free(final->actions);
+
+ free(final);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
* action = type d'action attendue. *
* *
* Description : Accompagne la fin du chargement des modules natifs. *
@@ -555,6 +517,103 @@ static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin
/******************************************************************************
* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Fournit le nom brut associé au greffon par défaut. *
+* *
+* Retour : Désignation brute du greffon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_plugin_module_get_modname_by_default(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ GPluginModule *plugin; /* Version native du greffon */
+ char *path; /* Chemin à traiter */
+
+ plugin = G_PLUGIN_MODULE(pygobject_get(self));
+
+ path = strdup(g_plugin_module_get_filename(plugin));
+
+ result = PyUnicode_FromString(basename(path));
+
+ free(path);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à valider. *
+* *
+* Description : Fournit le nom brut associé au greffon. *
+* *
+* Retour : Désignation brute du greffon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *py_plugin_module_get_modname_wrapper(const GPluginModule *plugin)
+{
+ char *result; /* Désignation brute à renvoyer*/
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyret; /* Bilan d'exécution */
+
+#define PLUGIN_MODULE_GET_MODNAME_WRAPPER PYTHON_WRAPPER_DEF_WITH \
+( \
+ _get_modname, "$self, /", \
+ METH_VARARGS, py_plugin_module_get_modname_by_default, \
+ "(Abstract) method providing the raw module name of the plugin.\n" \
+ " loaded.\n" \
+ "\n" \
+ "The result should be a short string value.\n" \
+ "\n" \
+ "A default implementation builds the module name from the Python" \
+ " script filename." \
+)
+
+ result = NULL;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(plugin));
+
+ if (has_python_method(pyobj, "_get_modname"))
+ {
+ pyret = run_python_method(pyobj, "_get_modname", NULL);
+
+ if (!PyUnicode_Check(pyret))
+ g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+ _("The returned raw name must be a string"));
+
+ else
+ result = strdup(PyUnicode_DATA(pyret));
+
+ Py_XDECREF(pyret);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+#ifdef INCLUDE_GTK_SUPPORT
+
+
+/******************************************************************************
+* *
* Paramètres : plugin = greffon à manipuler. *
* action = type d'action attendue. *
* dark = indique une préférence pour la variante foncée. *
@@ -783,6 +842,9 @@ static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *p
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : plugin = greffon à manipuler. *
@@ -1300,262 +1362,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *
/* ---------------------------------------------------------------------------------- */
-/* INTERFACE INTERNE POUR GREFFONS PYTHON */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini par la GLib pour le greffon Python. */
-G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE);
-
-
-/******************************************************************************
-* *
-* Paramètres : klass = classe à initialiser. *
-* *
-* Description : Initialise la classe des greffons Python. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_python_plugin_class_init(GPythonPluginClass *klass)
-{
- GObjectClass *object; /* Autre version de la classe */
- GPluginModuleClass *plugin; /* Version parente de la classe*/
-
- object = G_OBJECT_CLASS(klass);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose;
- object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize;
-
- plugin = G_PLUGIN_MODULE_CLASS(klass);
-
- plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : plugin = instance à initialiser. *
-* *
-* Description : Initialise l'instance d'un greffon Python. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_python_plugin_init(GPythonPlugin *plugin)
-{
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : plugin = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_python_plugin_dispose(GPythonPlugin *plugin)
-{
-#if 0
- PyThreadState *tstate; /* Contexte d'environnement */
-
- /**
- * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock
- *
- * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur,
- * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante :
- *
- * Fatal Python error: drop_gil: GIL is not locked
- *
- * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée
- * comme dépréciée depuis Python 3.2.
- *
- * Donc on choisit les alternatives officielles.
- *
- * Cependant, PyThreadState_Get() renvoit l'erreur suivante :
- *
- * Fatal Python error: PyThreadState_Get: no current thread
- *
- * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur
- * est intégré dans l'éditeur.
- */
-
- tstate = get_pychrysalide_main_tstate();
-
- if (tstate != NULL)
- PyEval_RestoreThread(tstate);
-
- if (tstate != NULL)
- PyEval_SaveThread();
-#endif
-
- G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : plugin = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_python_plugin_finalize(GPythonPlugin *plugin)
-{
- plugin_interface *final; /* Interface finale conservée */
-
- final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
-
- if (final != NULL)
- {
- if (final->name != NULL) free(final->name);
- if (final->desc != NULL) free(final->desc);
- if (final->version != NULL) free(final->version);
- if (final->url != NULL) free(final->url);
-
- assert(final->required_count == 1);
-
- if (final->required != NULL)
- free(final->required);
-
- if (final->actions != NULL)
- free(final->actions);
-
- free(final);
-
- }
-
- G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : plugin = greffon à valider. *
-* *
-* Description : Fournit le nom brut associé au greffon. *
-* *
-* Retour : Désignation brute du greffon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *g_python_plugin_get_modname(const GPythonPlugin *plugin)
-{
- char *result; /* Désignation brute à renvoyer*/
- char *path; /* Chemin à traiter */
-
- path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin)));
-
- result = strdup(basename(path));
-
- free(path);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : modname = nom du module à charger. *
-* filename = chemin d'accès au code Python à charger. *
-* *
-* Description : Crée un greffon à partir de code Python. *
-* *
-* Retour : Adresse de la structure mise en place ou NULL si erreur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GPluginModule *g_python_plugin_new(const char *modname, const char *filename)
-{
- GPythonPlugin *result; /* Structure à retourner */
- PyObject *name; /* Chemin d'accès pour Python */
- PyObject *module; /* Script Python chargé */
- PyObject *dict; /* Dictionnaire associé */
- PyObject *class; /* Classe à instancier */
- PyObject *instance; /* Instance Python du greffon */
-
- name = PyUnicode_FromString(modname);
- if (name == NULL) goto bad_exit;
-
- module = PyImport_Import(name);
- Py_DECREF(name);
-
- if (module == NULL) goto no_import;
-
- dict = PyModule_GetDict(module);
- class = PyDict_GetItemString(dict, "AutoLoad");
-
- if (class == NULL) goto no_class;
- if (!PyType_Check(class->ob_type)) goto no_class;
-
- instance = PyObject_CallFunction(class, NULL);
- if (instance == NULL) goto no_instance;
-
- result = G_PYTHON_PLUGIN(pygobject_get(instance));
-
- G_PLUGIN_MODULE(result)->filename = strdup(filename);
-
- /**
- * L'instance Python et l'objet GLib résultante sont un même PyGObject.
- *
- * Donc pas besoin de toucher au comptage des références ici, la libération
- * se réalisera à la fin, quand l'objet GLib sera libéré.
- */
-
- Py_DECREF(module);
-
- return G_PLUGIN_MODULE(result);
-
- no_instance:
-
- log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance"));
-
- no_class:
-
- if (class == NULL)
- log_plugin_simple_message(LMT_ERROR,
- _("An error occured when looking for the 'AutoLoad': item not found!"));
-
- no_import:
-
- Py_XDECREF(module);
-
- log_pychrysalide_exception(_("An error occured when importing '%s'"), modname);
-
- bad_exit:
-
- return NULL;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
/* MODULE PYTHON POUR LES SCRIPTS */
/* ---------------------------------------------------------------------------------- */
@@ -1865,9 +1671,12 @@ PyTypeObject *get_python_plugin_module_type(void)
static PyMethodDef py_plugin_module_methods[] = {
PLUGIN_MODULE_MANAGE_WRAPPER,
PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER,
+ PLUGIN_MODULE_GET_MODNAME_WRAPPER,
+#ifdef INCLUDE_GTK_SUPPORT
PLUGIN_MODULE_INCLUDE_THEME_WRAPPER,
PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER,
PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER,
+#endif
PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER,
PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER,
PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER,
@@ -1938,7 +1747,7 @@ bool ensure_python_plugin_module_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_PLUGIN_MODULE, type))
return false;
if (!define_plugin_module_constants(type))
@@ -1949,3 +1758,80 @@ bool ensure_python_plugin_module_is_registered(void)
return true;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : modname = nom du module à charger. *
+* filename = chemin d'accès au code Python à charger. *
+* *
+* Description : Crée un greffon à partir de code Python. *
+* *
+* Retour : Adresse de la structure mise en place ou NULL si erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GPluginModule *create_python_plugin(const char *modname, const char *filename)
+{
+ GPluginModule *result; /* Structure à retourner */
+ PyObject *name; /* Chemin d'accès pour Python */
+ PyObject *module; /* Script Python chargé */
+ PyObject *dict; /* Dictionnaire associé */
+ PyObject *class; /* Classe à instancier */
+ PyObject *instance; /* Instance Python du greffon */
+
+ name = PyUnicode_FromString(modname);
+ if (name == NULL) goto bad_exit;
+
+ module = PyImport_Import(name);
+ Py_DECREF(name);
+
+ if (module == NULL) goto no_import;
+
+ dict = PyModule_GetDict(module);
+ class = PyDict_GetItemString(dict, "AutoLoad");
+
+ if (class == NULL) goto no_class;
+ if (!PyType_Check(class->ob_type)) goto no_class;
+
+ instance = PyObject_CallFunction(class, NULL);
+ if (instance == NULL) goto no_instance;
+
+ result = G_PLUGIN_MODULE(pygobject_get(instance));
+
+ result->filename = strdup(filename);
+
+ /**
+ * L'instance Python et l'objet GLib résultante sont un même PyGObject.
+ *
+ * Donc pas besoin de toucher au comptage des références ici, la libération
+ * se réalisera à la fin, quand l'objet GLib sera libéré.
+ */
+
+ Py_DECREF(module);
+
+ return result;
+
+ no_instance:
+
+ log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance"));
+
+ no_class:
+
+ if (class == NULL)
+ log_plugin_simple_message(LMT_ERROR,
+ _("An error occured when looking for the 'AutoLoad': item not found!"));
+
+ no_import:
+
+ Py_XDECREF(module);
+
+ log_pychrysalide_exception(_("An error occured when importing '%s'"), modname);
+
+ bad_exit:
+
+ return NULL;
+
+}
diff --git a/plugins/pychrysalide/plugins/plugin.h b/plugins/pychrysalide/plugins/plugin.h
index ff805f4..ad54b8e 100644
--- a/plugins/pychrysalide/plugins/plugin.h
+++ b/plugins/pychrysalide/plugins/plugin.h
@@ -35,41 +35,15 @@
-/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
-
-
-#define G_TYPE_PYTHON_PLUGIN (g_python_plugin_get_type())
-#define G_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin))
-#define G_IS_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN))
-#define G_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
-#define G_IS_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYTHON_PLUGIN))
-#define G_PYTHON_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
-
-
-/* Ligne de représentation de code binaire (instance) */
-typedef struct _GPythonPlugin GPythonPlugin;
-
-/* Ligne de représentation de code binaire (classe) */
-typedef struct _GPythonPluginClass GPythonPluginClass;
-
-
-/* Indique le type défini par la GLib pour le greffon Python. */
-GType g_python_plugin_get_type(void);
-
-/* Crée un greffon à partir de code Python. */
-GPluginModule *g_python_plugin_new(const char *, const char *);
-
-
-
-/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
-
-
/* Fournit un accès à une définition de type à diffuser. */
PyTypeObject *get_python_plugin_module_type(void);
/* Prend en charge l'objet 'pychrysalide.plugins.PluginModule'. */
bool ensure_python_plugin_module_is_registered(void);
+/* Crée un greffon à partir de code Python. */
+GPluginModule *create_python_plugin(const char *, const char *);
+
#endif /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H */
diff --git a/plugins/pychrysalide/weak.h b/plugins/pychrysalide/weak.h
index 01885b0..767873f 100644
--- a/plugins/pychrysalide/weak.h
+++ b/plugins/pychrysalide/weak.h
@@ -26,10 +26,10 @@
#define _PLUGINS_PYCHRYSALIDE_WEAK_H
-#include <gtkext/gtkstatusstack.h>
-
+#include <glibext/notifier.h>
+#if 0
/* Démarre le suivi d'une nouvelle activité. */
activity_id_t gtk_status_stack_add_activity(GtkStatusStack *, const char *, unsigned long) __attribute__((weak));
@@ -44,7 +44,7 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *, activity_id_t, uns
/* Met fin au suivi d'une activité donnée. */
void gtk_status_stack_remove_activity(GtkStatusStack *, activity_id_t) __attribute__((weak));
-
+#endif
#endif /* _PLUGINS_PYCHRYSALIDE_WEAK_H */
diff --git a/plugins/python/scripting/core.py b/plugins/python/scripting/core.py
index ff912ed..135edb4 100644
--- a/plugins/python/scripting/core.py
+++ b/plugins/python/scripting/core.py
@@ -1,4 +1,7 @@
+import gi
+gi.require_version('Gtk', '3.0')
+
from gi.repository import GLib, Gtk
import os
diff --git a/plugins/readdex/Makefile.am b/plugins/readdex/Makefile.am
index b21f855..b2099fb 100644
--- a/plugins/readdex/Makefile.am
+++ b/plugins/readdex/Makefile.am
@@ -15,13 +15,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN'
endif
-libreaddex_la_SOURCES = \
- class.h class.c \
- code.h code.c \
- header.h header.c \
- ids.h ids.c \
+libreaddex_la_SOURCES = \
+ class.h class.c \
+ code.h code.c \
+ header.h header.c \
+ ids.h ids.c \
reader.h reader.c
+libreaddex_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libreaddex_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -33,8 +35,3 @@ libreaddex_la_LDFLAGS = \
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libreaddex_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/readdex/class.h b/plugins/readdex/class.h
index c7c34b0..a2c2bee 100644
--- a/plugins/readdex/class.h
+++ b/plugins/readdex/class.h
@@ -26,7 +26,7 @@
#include <format/preload.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
#include <plugins/dex/format.h>
diff --git a/plugins/readdex/ids.h b/plugins/readdex/ids.h
index 3a902cd..85495d1 100644
--- a/plugins/readdex/ids.h
+++ b/plugins/readdex/ids.h
@@ -26,7 +26,7 @@
#include <format/preload.h>
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
#include <plugins/dex/format.h>
diff --git a/plugins/readelf/Makefile.am b/plugins/readelf/Makefile.am
index 0ca002b..7e662ee 100644
--- a/plugins/readelf/Makefile.am
+++ b/plugins/readelf/Makefile.am
@@ -15,13 +15,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN'
endif
-libreadelf_la_SOURCES = \
- header.h header.c \
- program.h program.c \
- reader.h reader.c \
- section.h section.c \
+libreadelf_la_SOURCES = \
+ header.h header.c \
+ program.h program.c \
+ reader.h reader.c \
+ section.h section.c \
strtab.h strtab.c
+libreadelf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libreadelf_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -29,11 +31,7 @@ libreadelf_la_LDFLAGS = \
-L$(top_srcdir)/plugins/fmtp/.libs -lfmtp \
$(RUN_PATH)
+
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libreadelf_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/readmc/Makefile.am b/plugins/readmc/Makefile.am
index fa13fb2..51a8552 100644
--- a/plugins/readmc/Makefile.am
+++ b/plugins/readmc/Makefile.am
@@ -15,14 +15,16 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN'
endif
-libreadmc_la_SOURCES = \
- header.h header.c \
- reader.h reader.c \
- text.h text.c \
- v21.h v21.c \
- v23.h v23.c \
+libreadmc_la_SOURCES = \
+ header.h header.c \
+ reader.h reader.c \
+ text.h text.c \
+ v21.h v21.c \
+ v23.h v23.c \
v24.h v24.c
+libreadmc_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libreadmc_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -34,8 +36,3 @@ libreadmc_la_LDFLAGS = \
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libreadmc_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/ropgadgets/Makefile.am b/plugins/ropgadgets/Makefile.am
index f23e054..bec050e 100644
--- a/plugins/ropgadgets/Makefile.am
+++ b/plugins/ropgadgets/Makefile.am
@@ -22,6 +22,8 @@ libropgadgets_la_SOURCES = \
plugin.h plugin.c \
select.h select.c
+libropgadgets_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libropgadgets_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -32,8 +34,3 @@ libropgadgets_la_LDFLAGS = \
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libropgadgets_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/ropgadgets/plugin.c b/plugins/ropgadgets/plugin.c
index 836717c..938a04c 100644
--- a/plugins/ropgadgets/plugin.c
+++ b/plugins/ropgadgets/plugin.c
@@ -24,7 +24,6 @@
#include "plugin.h"
-#include <config.h>
#include <i18n.h>
@@ -36,7 +35,7 @@
#include "select.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
diff --git a/plugins/ropgadgets/select.c b/plugins/ropgadgets/select.c
index a45f043..c0cf08d 100644
--- a/plugins/ropgadgets/select.c
+++ b/plugins/ropgadgets/select.c
@@ -35,10 +35,12 @@
#include <i18n.h>
+#include <analysis/binary.h>
#include <analysis/contents/file.h>
#include <core/global.h>
#include <common/cpp.h>
#include <common/extstr.h>
+#include <core/columns.h>
#include <core/processors.h>
#include <format/known.h>
#include <gui/core/global.h>
diff --git a/plugins/winordinals/Makefile.am b/plugins/winordinals/Makefile.am
index f9ff14f..592d38a 100644
--- a/plugins/winordinals/Makefile.am
+++ b/plugins/winordinals/Makefile.am
@@ -50,6 +50,8 @@ libwinordinals_la_SOURCES = \
libwinordinals_la_LIBADD = \
$(PYTHON3_LIBADD)
+libwinordinals_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
libwinordinals_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
@@ -62,8 +64,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libwinordinals_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/winordinals/assign.h b/plugins/winordinals/assign.h
index 20310d2..e88ee28 100644
--- a/plugins/winordinals/assign.h
+++ b/plugins/winordinals/assign.h
@@ -25,7 +25,7 @@
#define _PLUGINS_WINORDINALS_ASSIGN_H
-#include <gtkext/gtkstatusstack.h>
+#include <glibext/notifier.h>
#include <plugins/pe/format.h>
diff --git a/plugins/winordinals/core.c b/plugins/winordinals/core.c
index a16c400..bae2d6d 100644
--- a/plugins/winordinals/core.c
+++ b/plugins/winordinals/core.c
@@ -31,12 +31,12 @@
#include "assign.h"
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -67,7 +67,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
result = true;
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
if (result)
result = add_winordinals_module_to_python_module();
diff --git a/plugins/winordinals/python/Makefile.am b/plugins/winordinals/python/Makefile.am
index a5f17a4..201650d 100644
--- a/plugins/winordinals/python/Makefile.am
+++ b/plugins/winordinals/python/Makefile.am
@@ -4,15 +4,10 @@ noinst_LTLIBRARIES = libwinordinalspython.la
libwinordinalspython_la_SOURCES = \
module.h module.c
-libwinordinalspython_la_LDFLAGS =
+libwinordinalspython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libwinordinalspython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/yaml/Makefile.am b/plugins/yaml/Makefile.am
index 9eee4ab..1165d7a 100644
--- a/plugins/yaml/Makefile.am
+++ b/plugins/yaml/Makefile.am
@@ -36,23 +36,24 @@ endif
libyaml_la_SOURCES = \
+ collection-int.h \
collection.h collection.c \
core.h core.c \
- line.h line.c \
node-int.h \
node.h node.c \
+ pair-int.h \
pair.h pair.c \
- reader.h reader.c \
- scalar.h scalar.c \
- tree.h tree.c
+ parser.h parser.c
libyaml_la_LIBADD = \
$(PYTHON3_LIBADD)
+libyaml_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBYAML_CFLAGS) -I$(top_srcdir)/src
+
libyaml_la_LDFLAGS = \
-avoid-version \
-L$(top_srcdir)/src/.libs -lchrysacore \
- $(RUN_PATH) $(PYTHON3_LDFLAGS)
+ $(RUN_PATH) $(LIBYAML_LIBS) $(PYTHON3_LDFLAGS)
devdir = $(includedir)/chrysalide/$(subdir)
@@ -60,8 +61,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libyaml_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/yaml/collection-int.h b/plugins/yaml/collection-int.h
new file mode 100644
index 0000000..453976d
--- /dev/null
+++ b/plugins/yaml/collection-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection-int.h - prototypes internes pour la définition d'un noeud YAML
+ *
+ * Copyright (C) 2019-2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_YAML_COLLECTION_INT_H
+#define PLUGINS_YAML_COLLECTION_INT_H
+
+
+#include "collection.h"
+
+
+#include "node-int.h"
+
+
+
+/* Collection de noeuds au format YAML (instance) */
+struct _GYamlCollection
+{
+ GYamlNode parent; /* A laisser en premier */
+
+ bool is_seq; /* Nature de la collection */
+
+ GYamlNode **nodes; /* Sous-noeuds intégrés */
+ size_t count; /* Nombre de ces enfants */
+
+};
+
+/* Collection de noeuds au format YAML (classe) */
+struct _GYamlCollectionClass
+{
+ GYamlNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une collection de noeuds YAML. */
+bool g_yaml_collection_create(GYamlCollection *, bool);
+
+
+
+#endif /* PLUGINS_YAML_COLLECTION_INT_H */
diff --git a/plugins/yaml/collection.c b/plugins/yaml/collection.c
index 376e894..cdc63d9 100644
--- a/plugins/yaml/collection.c
+++ b/plugins/yaml/collection.c
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * collection.h - collection de noeuds Yaml de type "sequence" ou "mapping"
+ * collection.h - collection de noeuds YAML de type "sequence" ou "mapping"
*
* Copyright (C) 2019 Cyrille Bagard
*
@@ -27,34 +27,17 @@
#include <malloc.h>
-#include "node-int.h"
+#include "collection-int.h"
-/* Collection de noeuds au format Yaml (instance) */
-struct _GYamlCollection
-{
- GYamlNode parent; /* A laisser en premier */
-
- bool is_seq; /* Nature de la collection */
-
- GYamlNode **nodes; /* Sous-noeuds intégrés */
- size_t count; /* Nombre de ces enfants */
-
-};
-
-/* Collection de noeuds au format Yaml (classe) */
-struct _GYamlCollectionClass
-{
- GYamlNodeClass parent; /* A laisser en premier */
-
-};
+/* -------------------- DEFINITIONS PROPRES POUR LE SUPPORT YAML -------------------- */
-/* Initialise la classe des collections de noeuds Yaml. */
+/* Initialise la classe des collections de noeuds YAML. */
static void g_yaml_collection_class_init(GYamlCollectionClass *);
-/* Initialise une instance de collection de noeuds Yaml. */
+/* Initialise une instance de collection de noeuds YAML. */
static void g_yaml_collection_init(GYamlCollection *);
/* Supprime toutes les références externes. */
@@ -63,12 +46,22 @@ static void g_yaml_collection_dispose(GYamlCollection *);
/* Procède à la libération totale de la mémoire. */
static void g_yaml_collection_finalize(GYamlCollection *);
-/* Recherche les noeuds correspondant à un chemin. */
-static void g_yaml_collection_find_by_path(const GYamlCollection *, const char *, bool, GYamlNode ***, size_t *);
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Recherche le premier noeud correspondant à un chemin. */
+static GYamlNode *g_yaml_collection_find_first_by_path(GYamlCollection *, const char *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITIONS PROPRES POUR LE SUPPORT YAML */
+/* ---------------------------------------------------------------------------------- */
+
-/* Indique le type défini pour une collection de noeuds Yaml. */
+/* Indique le type défini pour une collection de noeuds YAML. */
G_DEFINE_TYPE(GYamlCollection, g_yaml_collection, G_TYPE_YAML_NODE);
@@ -76,7 +69,7 @@ G_DEFINE_TYPE(GYamlCollection, g_yaml_collection, G_TYPE_YAML_NODE);
* *
* Paramètres : klass = classe à initialiser. *
* *
-* Description : Initialise la classe des collections de noeuds Yaml. *
+* Description : Initialise la classe des collections de noeuds YAML. *
* *
* Retour : - *
* *
@@ -96,7 +89,7 @@ static void g_yaml_collection_class_init(GYamlCollectionClass *klass)
node = G_YAML_NODE_CLASS(klass);
- node->find = (find_yaml_node_fc)g_yaml_collection_find_by_path;
+ node->find = (find_first_yaml_node_fc)g_yaml_collection_find_first_by_path;
}
@@ -105,7 +98,7 @@ static void g_yaml_collection_class_init(GYamlCollectionClass *klass)
* *
* Paramètres : collec = instance à initialiser. *
* *
-* Description : Initialise une instance de collection de noeuds Yaml. *
+* Description : Initialise une instance de collection de noeuds YAML. *
* *
* Retour : - *
* *
@@ -173,7 +166,7 @@ static void g_yaml_collection_finalize(GYamlCollection *collec)
* *
* Paramètres : seq = indique la nature de la future collection. *
* *
-* Description : Construit une collection de noeuds Yaml. *
+* Description : Construit une collection de noeuds YAML. *
* *
* Retour : Instance mise en place ou NULL en cas d'échec. *
* *
@@ -187,7 +180,34 @@ GYamlCollection *g_yaml_collection_new(bool seq)
result = g_object_new(G_TYPE_YAML_COLLEC, NULL);
- result->is_seq = seq;
+ if (!g_yaml_collection_create(result, seq))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = noeud d'arborescence YAML à initialiser pleinement. *
+* seq = indique la nature de la future collection. *
+* *
+* Description : Met en place une collection de noeuds YAML. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_yaml_collection_create(GYamlCollection *collec, bool seq)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ collec->is_seq = seq;
return result;
@@ -196,9 +216,9 @@ GYamlCollection *g_yaml_collection_new(bool seq)
/******************************************************************************
* *
-* Paramètres : collec = noeud d'arborescence Yaml à consulter. *
+* Paramètres : collec = noeud d'arborescence YAML à consulter. *
* *
-* Description : Indique la nature d'une collection Yaml. *
+* Description : Indique la nature d'une collection YAML. *
* *
* Retour : Nature de la collection. *
* *
@@ -219,10 +239,10 @@ bool g_yaml_collection_is_sequence(const GYamlCollection *collec)
/******************************************************************************
* *
-* Paramètres : collec = collection de noeuds Yaml à compléter. *
+* Paramètres : collec = collection de noeuds YAML à compléter. *
* node = noeud à rattacher. *
* *
-* Description : Ajoute un noeud à une collection de noeuds Yaml. *
+* Description : Ajoute un noeud à une collection de noeuds YAML. *
* *
* Retour : - *
* *
@@ -242,12 +262,12 @@ void g_yaml_collection_add_node(GYamlCollection *collec, GYamlNode *node)
/******************************************************************************
* *
-* Paramètres : collec = noeud d'arborescence Yaml à consulter. *
+* Paramètres : collec = noeud d'arborescence YAML à consulter. *
* count = taille de la liste constituée. [OUT] *
* *
* Description : Fournit la liste des noeuds intégrés dans une collection. *
* *
-* Retour : Enfants d'un noeud issu d'une collection Yaml. *
+* Retour : Enfants d'un noeud issu d'une collection YAML. *
* *
* Remarques : - *
* *
@@ -275,59 +295,63 @@ GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *collec, size_t *c
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* nodes = liste de noeuds avec correspondance établie. [OUT] *
-* count = quantité de ces noeuds. [OUT] *
+* Paramètres : collec = noeud d'arborescence YAML à consulter. *
* *
-* Description : Recherche les noeuds correspondant à un chemin. *
+* Description : Fournit le premier noeud intégré dans une collection. *
* *
-* Retour : - *
+* Retour : Noeud issu d'une collection YAML. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_yaml_collection_find_by_path(const GYamlCollection *collec, const char *path, bool prepare, GYamlNode ***nodes, size_t *count)
+GYamlNode *g_yaml_collection_get_first_node(const GYamlCollection *collec)
{
- size_t i; /* Boucle de parcours */
+ GYamlNode *result; /* Elément à retourner */
- if (path[0] != '/')
- goto wrong_path;
+ if (collec->count == 0)
+ result = NULL;
- if (path[1] == '\0')
+ else
{
- if (prepare)
- {
- *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **));
+ result = collec->nodes[0];
+ g_object_ref(G_OBJECT(result));
+ }
- g_object_ref(G_OBJECT(collec));
- (*nodes)[*count - 1] = G_YAML_NODE(collec);
+ return result;
- }
- else
- {
- *nodes = realloc(*nodes, (*count + collec->count) * sizeof(GYamlNode **));
+}
- for (i = 0; i < collec->count; i++)
- {
- g_object_ref(G_OBJECT(collec->nodes[i]));
- (*nodes)[*count + i] = collec->nodes[i];
- }
- *count += collec->count;
- }
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
- }
- else
- for (i = 0; i < collec->count; i++)
- _g_yaml_node_find_by_path(collec->nodes[i], path, prepare, nodes, count);
+/******************************************************************************
+* *
+* Paramètres : collec = noeud d'arborescence YAML à consulter. *
+* path = chemin d'accès à parcourir. *
+* *
+* Description : Recherche le premier noeud correspondant à un chemin. *
+* *
+* Retour : Noeud avec la correspondance établie ou NULL si non trouvé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GYamlNode *g_yaml_collection_find_first_by_path(GYamlCollection *collec, const char *path)
+{
+ GYamlNode *result; /* Trouvaille à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
- wrong_path:
+ for (i = 0; i < collec->count && result == NULL; i++)
+ result = g_yaml_node_find_first_by_path(collec->nodes[i], path);
- ;
+ return result;
}
diff --git a/plugins/yaml/collection.h b/plugins/yaml/collection.h
index 4d74d29..8a026ae 100644
--- a/plugins/yaml/collection.h
+++ b/plugins/yaml/collection.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * collection.h - prototypes pour une collection de noeuds Yaml de type "sequence" ou "mapping"
+ * collection.h - prototypes pour une collection de noeuds YAML de type "sequence" ou "mapping"
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -41,28 +41,31 @@
#define G_YAML_COLLEC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_COLLEC, GYamlCollectionClass))
-/* Collection de noeuds au format Yaml (instance) */
+/* Collection de noeuds au format YAML (instance) */
typedef struct _GYamlCollection GYamlCollection;
-/* Collection de noeuds au format Yaml (classe) */
+/* Collection de noeuds au format YAML (classe) */
typedef struct _GYamlCollectionClass GYamlCollectionClass;
-/* Indique le type défini pour une collection de noeuds Yaml. */
+/* Indique le type défini pour une collection de noeuds YAML. */
GType g_yaml_collection_get_type(void);
-/* Construit une collection de noeuds Yaml. */
+/* Construit une collection de noeuds YAML. */
GYamlCollection *g_yaml_collection_new(bool);
-/* Indique la nature d'une collection Yaml. */
+/* Indique la nature d'une collection YAML. */
bool g_yaml_collection_is_sequence(const GYamlCollection *);
-/* Ajoute un noeud à une collection de noeuds Yaml. */
+/* Ajoute un noeud à une collection de noeuds YAML. */
void g_yaml_collection_add_node(GYamlCollection *, GYamlNode *);
/* Fournit la liste des noeuds intégrés dans une collection. */
GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *, size_t *);
+/* Fournit le premier noeud intégré dans une collection. */
+GYamlNode *g_yaml_collection_get_first_node(const GYamlCollection *);
+
#endif /* PLUGINS_YAML_COLLECTION_H */
diff --git a/plugins/yaml/core.c b/plugins/yaml/core.c
index ffc7edd..7dc0570 100644
--- a/plugins/yaml/core.c
+++ b/plugins/yaml/core.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* core.c - lecture de contenus au format Yaml
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -27,12 +27,12 @@
#include <plugins/self.h>
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# include "python/module.h"
#endif
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
# define PG_REQ RL("PyChrysalide")
#else
# define PG_REQ NO_REQ
@@ -63,7 +63,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
result = true;
-#ifdef HAVE_PYTHON3_BINDINGS
+#ifdef INCLUDE_PYTHON3_BINDINGS
if (result)
result = add_yaml_module_to_python_module();
diff --git a/plugins/yaml/core.h b/plugins/yaml/core.h
index a46dbe7..b846e24 100644
--- a/plugins/yaml/core.h
+++ b/plugins/yaml/core.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* core.h - prototypes pour la lecture de contenus au format Yaml
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
diff --git a/plugins/yaml/line.h b/plugins/yaml/line.h
deleted file mode 100644
index 00f019e..0000000
--- a/plugins/yaml/line.h
+++ /dev/null
@@ -1,75 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * line.h - prototypes pour une ligne de contenu Yaml
- *
- * Copyright (C) 2019 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * Chrysalide is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef PLUGINS_YAML_LINE_H
-#define PLUGINS_YAML_LINE_H
-
-
-#include <glib-object.h>
-#include <stdbool.h>
-
-
-
-#define G_TYPE_YAML_LINE g_yaml_line_get_type()
-#define G_YAML_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_LINE, GYamlLine))
-#define G_IS_YAML_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_LINE))
-#define G_YAML_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_LINE, GYamlLineClass))
-#define G_IS_YAML_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_LINE))
-#define G_YAML_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_LINE, GYamlLineClass))
-
-
-/* Ligne de données au format Yaml (instance) */
-typedef struct _GYamlLine GYamlLine;
-
-/* Ligne de données au format Yaml (classe) */
-typedef struct _GYamlLineClass GYamlLineClass;
-
-
-/* Indique le type défini pour une ligne de données au format Yaml. */
-GType g_yaml_line_get_type(void);
-
-/* Met en place un gestionnaire pour ligne au format Yaml. */
-GYamlLine *g_yaml_line_new(const char *, size_t);
-
-/* Fournit la taille de l'indentation d'une ligne Yaml. */
-size_t g_yaml_line_count_indent(const GYamlLine *);
-
-/* Indique si la ligne représente un élément de liste. */
-bool g_yaml_line_is_list_item(const GYamlLine *);
-
-/* Fournit la charge utile associée à une ligne Yaml. */
-const char *g_yaml_line_get_payload(const GYamlLine *);
-
-/* Fournit la clef associée à une ligne Yaml si elle existe. */
-const char *g_yaml_line_get_key(const GYamlLine *);
-
-/* Fournit la valeur associée à une ligne Yaml si elle existe. */
-const char *g_yaml_line_get_value(const GYamlLine *);
-
-
-
-#define g_yaml_line_get_number(l) 0
-
-
-
-#endif /* PLUGINS_YAML_LINE_H */
diff --git a/plugins/yaml/node-int.h b/plugins/yaml/node-int.h
index a389f61..cd87950 100644
--- a/plugins/yaml/node-int.h
+++ b/plugins/yaml/node-int.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * node-int.h - prototypes internes pour la définition d'un noeud Yaml
+ * node-int.h - prototypes internes pour la définition d'un noeud YAML
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -29,32 +29,26 @@
-/* Recherche les noeuds correspondant à un chemin. */
-typedef void (* find_yaml_node_fc) (const GYamlNode *, const char *, bool, GYamlNode ***, size_t *);
+/* Recherche le premier noeud correspondant à un chemin. */
+typedef GYamlNode * (* find_first_yaml_node_fc) (GYamlNode *, const char *);
-/* Noeud d'une arborescence au format Yaml (instance) */
+/* Noeud d'une arborescence au format YAML (instance) */
struct _GYamlNode
{
GObject parent; /* A laisser en premier */
- GYamlLine *line; /* Line Yaml d'origine */
-
};
-/* Noeud d'une arborescence au format Yaml (classe) */
+/* Noeud d'une arborescence au format YAML (classe) */
struct _GYamlNodeClass
{
GObjectClass parent; /* A laisser en premier */
- find_yaml_node_fc find; /* Recherche par chemin */
+ find_first_yaml_node_fc find; /* Recherche par chemin */
};
-/* Recherche les noeuds correspondant à un chemin. */
-void _g_yaml_node_find_by_path(const GYamlNode *, const char *, bool, GYamlNode ***, size_t *);
-
-
#endif /* PLUGINS_YAML_NODE_INT_H */
diff --git a/plugins/yaml/node.c b/plugins/yaml/node.c
index 7b3413d..ff6fa7e 100644
--- a/plugins/yaml/node.c
+++ b/plugins/yaml/node.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * node.c - définition de noeud Yaml
+ * node.c - définition de noeud YAML
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -24,17 +24,14 @@
#include "node.h"
-#include <string.h>
-
-
#include "node-int.h"
-/* Initialise la classe des noeuds d'arborescence Yaml. */
+/* Initialise la classe des noeuds d'arborescence YAML. */
static void g_yaml_node_class_init(GYamlNodeClass *);
-/* Initialise une instance de noeud d'arborescence Yaml. */
+/* Initialise une instance de noeud d'arborescence YAML. */
static void g_yaml_node_init(GYamlNode *);
/* Supprime toutes les références externes. */
@@ -45,7 +42,7 @@ static void g_yaml_node_finalize(GYamlNode *);
-/* Indique le type défini pour un noeud d'arborescence Yaml. */
+/* Indique le type défini pour un noeud d'arborescence YAML. */
G_DEFINE_TYPE(GYamlNode, g_yaml_node, G_TYPE_OBJECT);
@@ -53,7 +50,7 @@ G_DEFINE_TYPE(GYamlNode, g_yaml_node, G_TYPE_OBJECT);
* *
* Paramètres : klass = classe à initialiser. *
* *
-* Description : Initialise la classe des noeuds d'arborescence Yaml. *
+* Description : Initialise la classe des noeuds d'arborescence YAML. *
* *
* Retour : - *
* *
@@ -77,7 +74,7 @@ static void g_yaml_node_class_init(GYamlNodeClass *klass)
* *
* Paramètres : node = instance à initialiser. *
* *
-* Description : Initialise une instance de noeud d'arborescence Yaml. *
+* Description : Initialise une instance de noeud d'arborescence YAML. *
* *
* Retour : - *
* *
@@ -87,7 +84,6 @@ static void g_yaml_node_class_init(GYamlNodeClass *klass)
static void g_yaml_node_init(GYamlNode *node)
{
- node->line = NULL;
}
@@ -106,8 +102,6 @@ static void g_yaml_node_init(GYamlNode *node)
static void g_yaml_node_dispose(GYamlNode *node)
{
- g_clear_object(&node->line);
-
G_OBJECT_CLASS(g_yaml_node_parent_class)->dispose(G_OBJECT(node));
}
@@ -134,119 +128,37 @@ static void g_yaml_node_finalize(GYamlNode *node)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* Paramètres : node = noeud d'arborescence YAML à consulter. *
+* path = chemin d'accès à parcourir. *
* *
-* Description : Fournit la ligne d'origine associée à un noeud. *
+* Description : Recherche le premier noeud correspondant à un chemin. *
* *
-* Retour : Ligne Yaml à l'origine du noeud. *
+* Retour : Noeud avec la correspondance établie ou NULL si non trouvé. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node)
-{
- GYamlLine *result; /* Ligne d'origine à renvoyer */
-
- result = node->line;
-
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* nodes = liste de noeuds avec correspondance établie. [OUT] *
-* count = quantité de ces noeuds. [OUT] *
-* *
-* Description : Recherche les noeuds correspondant à un chemin. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void _g_yaml_node_find_by_path(const GYamlNode *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count)
+GYamlNode *g_yaml_node_find_first_by_path(GYamlNode *node, const char *path)
{
+ GYamlNode *result; /* Trouvaille à retourner */
GYamlNodeClass *class; /* Classe de l'instance */
- class = G_YAML_NODE_GET_CLASS(node);
-
- class->find(node, path, prepare, nodes, count);
-
-}
+ while (path[0] == '/')
+ path++;
-
-/******************************************************************************
-* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* nodes = liste de noeuds avec correspondance établie. [OUT] *
-* count = quantité de ces noeuds. [OUT] *
-* *
-* Description : Recherche les noeuds correspondant à un chemin. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_yaml_node_find_by_path(const GYamlNode *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count)
-{
- *nodes = NULL;
- *count = 0;
-
- _g_yaml_node_find_by_path(node, path, prepare, nodes, count);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* *
-* Description : Recherche l'unique noeud correspondant à un chemin. *
-* *
-* Retour : Noeud avec correspondance établie ou NULL. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GYamlNode *g_yaml_node_find_one_by_path(const GYamlNode *node, const char *path, bool prepare)
-{
- GYamlNode *result; /* Trouvaille unique à renvoyer*/
- GYamlNode **nodes; /* Liste de noeuds trouvés */
- size_t count; /* Taille de cette liste */
- size_t i; /* Boucle de parcours */
-
- g_yaml_node_find_by_path(node, path, prepare, &nodes, &count);
-
- if (count == 1)
+ if (path[0] == '\0')
{
- result = nodes[0];
+ result = node;
g_object_ref(G_OBJECT(result));
}
else
- result = NULL;
+ {
+ class = G_YAML_NODE_GET_CLASS(node);
- for (i = 0; i < count; i++)
- g_object_unref(G_OBJECT(nodes[i]));
+ result = class->find(node, path);
- if (nodes != NULL)
- free(nodes);
+ }
return result;
diff --git a/plugins/yaml/node.h b/plugins/yaml/node.h
index 8197ef5..36c8e7b 100644
--- a/plugins/yaml/node.h
+++ b/plugins/yaml/node.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* node.h - prototypes pour une définition de noeud Yaml
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,15 +26,8 @@
#include <glib-object.h>
-#include <stdbool.h>
-#include "line.h"
-
-
-/* Depuis collection.h : collection de noeuds au format Yaml (instance) */
-typedef struct _GYamlCollection GYamlCollection;
-
#define G_TYPE_YAML_NODE g_yaml_node_get_type()
#define G_YAML_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_NODE, GYamlNode))
@@ -44,24 +37,18 @@ typedef struct _GYamlCollection GYamlCollection;
#define G_YAML_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_NODE, GYamlNodeClass))
-/* Noeud d'une arborescence au format Yaml (instance) */
+/* Noeud d'une arborescence au format YAML (instance) */
typedef struct _GYamlNode GYamlNode;
-/* Noeud d'une arborescence au format Yaml (classe) */
+/* Noeud d'une arborescence au format YAML (classe) */
typedef struct _GYamlNodeClass GYamlNodeClass;
/* Indique le type défini pour un noeud d'arborescence Yaml. */
GType g_yaml_node_get_type(void);
-/* Fournit la ligne d'origine associée à un noeud. */
-GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *);
-
-/* Recherche les noeuds correspondant à un chemin. */
-void g_yaml_node_find_by_path(const GYamlNode *, const char *, bool, GYamlNode ***, size_t *);
-
-/* Recherche l'unique noeud correspondant à un chemin. */
-GYamlNode *g_yaml_node_find_one_by_path(const GYamlNode *, const char *, bool);
+/* Recherche le premier noeud correspondant à un chemin. */
+GYamlNode *g_yaml_node_find_first_by_path(GYamlNode *, const char *);
diff --git a/plugins/yaml/pair-int.h b/plugins/yaml/pair-int.h
new file mode 100644
index 0000000..88b968d
--- /dev/null
+++ b/plugins/yaml/pair-int.h
@@ -0,0 +1,66 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pair-int.h - prototypes internes pour la définition d'un noeud YAML
+ *
+ * Copyright (C) 2020-2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_YAML_PAIR_INT_H
+#define PLUGINS_YAML_PAIR_INT_H
+
+
+#include "pair.h"
+
+
+#include <stdbool.h>
+
+
+#include "node-int.h"
+
+
+
+/* Noeud d'une arborescence au format YAML (instance) */
+struct _GYamlPair
+{
+ GYamlNode parent; /* A laisser en premier */
+
+ char *key; /* Clef présente dans le noeud */
+ YamlOriginalStyle key_style; /* Forme d'origine associé */
+
+ char *value; /* Valeur associée */
+ YamlOriginalStyle value_style; /* Forme d'origine associé */
+
+ GYamlCollection *children; /* Collection de noeuds */
+
+};
+
+/* Noeud d'une arborescence au format YAML (classe) */
+struct _GYamlPairClass
+{
+ GYamlNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une pair clef/valeur YAML. */
+bool g_yaml_pair_create(GYamlPair *, const char *, YamlOriginalStyle, const char *, YamlOriginalStyle);
+
+
+
+#endif /* PLUGINS_YAML_PAIR_INT_H */
diff --git a/plugins/yaml/pair.c b/plugins/yaml/pair.c
index 0e96937..4faba88 100644
--- a/plugins/yaml/pair.c
+++ b/plugins/yaml/pair.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * pair.c - noeud Yaml de paire clef/valeur
+ * pair.c - noeud YAML de paire clef/valeur
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -24,38 +24,25 @@
#include "pair.h"
+#include <assert.h>
#include <malloc.h>
#include <string.h>
-#include "node-int.h"
+#include <common/extstr.h>
+#include "pair-int.h"
-/* Noeud d'une arborescence au format Yaml (instance) */
-struct _GYamlPair
-{
- GYamlNode parent; /* A laisser en premier */
-
- char *key; /* Clef présente dans le noeud */
- char *value; /* Valeur associée */
-
- GYamlCollection *collection; /* Collection de noeuds */
-};
-
-/* Noeud d'une arborescence au format Yaml (classe) */
-struct _GYamlPairClass
-{
- GYamlNodeClass parent; /* A laisser en premier */
-};
+/* -------------------- DEFINITIONS PROPRES POUR LE SUPPORT YAML -------------------- */
-/* Initialise la classe des noeuds d'arborescence Yaml. */
+/* Initialise la classe des noeuds d'arborescence YAML. */
static void g_yaml_pair_class_init(GYamlPairClass *);
-/* Initialise une instance de noeud d'arborescence Yaml. */
+/* Initialise une instance de noeud d'arborescence YAML. */
static void g_yaml_pair_init(GYamlPair *);
/* Supprime toutes les références externes. */
@@ -64,12 +51,22 @@ static void g_yaml_pair_dispose(GYamlPair *);
/* Procède à la libération totale de la mémoire. */
static void g_yaml_pair_finalize(GYamlPair *);
-/* Recherche les noeuds correspondant à un chemin. */
-static void g_yaml_pair_find_by_path(const GYamlPair *, const char *, bool, GYamlNode ***, size_t *);
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Recherche le premier noeud correspondant à un chemin. */
+static GYamlNode *g_yaml_pair_find_first_by_path(GYamlPair *, const char *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITIONS PROPRES POUR LE SUPPORT YAML */
+/* ---------------------------------------------------------------------------------- */
-/* Indique le type défini pour un noeud d'arborescence Yaml. */
+
+/* Indique le type défini pour un noeud d'arborescence YAML. */
G_DEFINE_TYPE(GYamlPair, g_yaml_pair, G_TYPE_YAML_NODE);
@@ -77,7 +74,7 @@ G_DEFINE_TYPE(GYamlPair, g_yaml_pair, G_TYPE_YAML_NODE);
* *
* Paramètres : klass = classe à initialiser. *
* *
-* Description : Initialise la classe des noeuds d'arborescence Yaml. *
+* Description : Initialise la classe des noeuds d'arborescence YAML. *
* *
* Retour : - *
* *
@@ -97,16 +94,16 @@ static void g_yaml_pair_class_init(GYamlPairClass *klass)
node = G_YAML_NODE_CLASS(klass);
- node->find = (find_yaml_node_fc)g_yaml_pair_find_by_path;
+ node->find = (find_first_yaml_node_fc)g_yaml_pair_find_first_by_path;
}
/******************************************************************************
* *
-* Paramètres : node = instance à initialiser. *
+* Paramètres : pair = instance à initialiser. *
* *
-* Description : Initialise une instance de noeud d'arborescence Yaml. *
+* Description : Initialise une instance de noeud d'arborescence YAML. *
* *
* Retour : - *
* *
@@ -114,19 +111,22 @@ static void g_yaml_pair_class_init(GYamlPairClass *klass)
* *
******************************************************************************/
-static void g_yaml_pair_init(GYamlPair *node)
+static void g_yaml_pair_init(GYamlPair *pair)
{
- node->key = NULL;
- node->value = NULL;
+ pair->key = NULL;
+ pair->key_style = YOS_PLAIN;
+
+ pair->value = NULL;
+ pair->value_style = YOS_PLAIN;
- node->collection = NULL;
+ pair->children = NULL;
}
/******************************************************************************
* *
-* Paramètres : node = instance d'objet GLib à traiter. *
+* Paramètres : pair = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -136,18 +136,18 @@ static void g_yaml_pair_init(GYamlPair *node)
* *
******************************************************************************/
-static void g_yaml_pair_dispose(GYamlPair *node)
+static void g_yaml_pair_dispose(GYamlPair *pair)
{
- g_clear_object(&node->collection);
+ g_clear_object(&pair->children);
- G_OBJECT_CLASS(g_yaml_pair_parent_class)->dispose(G_OBJECT(node));
+ G_OBJECT_CLASS(g_yaml_pair_parent_class)->dispose(G_OBJECT(pair));
}
/******************************************************************************
* *
-* Paramètres : node = instance d'objet GLib à traiter. *
+* Paramètres : pair = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -157,24 +157,27 @@ static void g_yaml_pair_dispose(GYamlPair *node)
* *
******************************************************************************/
-static void g_yaml_pair_finalize(GYamlPair *node)
+static void g_yaml_pair_finalize(GYamlPair *pair)
{
- if (node->key != NULL)
- free(node->key);
+ if (pair->key != NULL)
+ free(pair->key);
- if (node->value != NULL)
- free(node->value);
+ if (pair->value != NULL)
+ free(pair->value);
- G_OBJECT_CLASS(g_yaml_pair_parent_class)->finalize(G_OBJECT(node));
+ G_OBJECT_CLASS(g_yaml_pair_parent_class)->finalize(G_OBJECT(pair));
}
/******************************************************************************
* *
-* Paramètres : line = ligne Yaml à l'origine du futur noeud. *
+* Paramètres : key = désignation pour le noeud YAML. *
+* kstyle = format d'origine de la clef. *
+* value = éventuelle valeur directe portée par le noeud. *
+* vstyle = éventuel format d'origine de l'éventuelle valeur. *
* *
-* Description : Construit un noeud d'arborescence Yaml. *
+* Description : Construit un noeud d'arborescence YAML. *
* *
* Retour : Instance mise en place ou NULL en cas d'échec. *
* *
@@ -182,33 +185,14 @@ static void g_yaml_pair_finalize(GYamlPair *node)
* *
******************************************************************************/
-GYamlPair *g_yaml_pair_new(GYamlLine *line)
+GYamlPair *g_yaml_pair_new(const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle)
{
GYamlPair *result; /* Structure à retourner */
- const char *key; /* Clef associée au noeud */
- const char *value; /* Eventuelle valeur associée */
-
- key = g_yaml_line_get_key(line);
- value = g_yaml_line_get_value(line);
-
- if (key == NULL)
- result = NULL;
- else
- {
- result = g_object_new(G_TYPE_YAML_PAIR, NULL);
-
- G_YAML_NODE(result)->line = line;
- g_object_ref(G_OBJECT(line));
+ result = g_object_new(G_TYPE_YAML_PAIR, NULL);
- result->key = strdup(key);
-
- if (value == NULL)
- result->value = NULL;
- else
- result->value = strdup(value);
-
- }
+ if (!g_yaml_pair_create(result, key, kstyle, value, vstyle))
+ g_clear_object(&result);
return result;
@@ -217,105 +201,126 @@ GYamlPair *g_yaml_pair_new(GYamlLine *line)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* nodes = liste de noeuds avec correspondance établie. [OUT] *
-* count = quantité de ces noeuds. [OUT] *
+* Paramètres : pair = paire YAML à initialiser pleinement. *
+* key = désignation pour le noeud YAML. *
+* kstyle = format d'origine de la clef. *
+* value = éventuelle valeur directe portée par le noeud. *
+* vstyle = éventuel format d'origine de l'éventuelle valeur. *
* *
-* Description : Recherche les noeuds correspondant à un chemin. *
+* Description : Met en place une pair clef/valeur YAML. *
* *
-* Retour : - *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_yaml_pair_find_by_path(const GYamlPair *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count)
+bool g_yaml_pair_create(GYamlPair *pair, const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle)
{
- char *next; /* Prochaine partie du chemin */
- size_t cmplen; /* Etendue de la comparaison */
- int ret; /* Bilan d'une comparaison */
+ bool result; /* Bilan à retourner */
- if (path[0] == '\0')
- goto exit;
+ result = true;
- /* Correspondance au niveau du noeud ? */
+ pair->key = strdup(key);
+ pair->key_style = kstyle;
- if (path[0] == '/')
+ if (value != NULL)
{
- path++;
+ pair->value = strdup(value);
+ pair->value_style = vstyle;
+ }
- if (path[0] == '\0')
- goto matched;
+ return result;
- }
+}
- next = strchr(path, '/');
- if (next == NULL)
- ret = strcmp(path, node->key);
+/******************************************************************************
+* *
+* Paramètres : pair = noeud d'arborescence YAML à consulter. *
+* *
+* Description : Fournit la clef représentée dans une paire en YAML. *
+* *
+* Retour : Clef sous forme de chaîne de caractères. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- else
- {
- cmplen = next - path;
+const char *g_yaml_pair_get_key(const GYamlPair *pair)
+{
+ char *result; /* Valeur à retourner */
- if (cmplen == 0)
- goto cont;
+ result = pair->key;
- ret = strncmp(path, node->key, cmplen);
+ return result;
- }
+}
- if (ret != 0)
- goto done;
- else if (next != NULL)
- {
- path += cmplen;
- goto cont;
- }
+/******************************************************************************
+* *
+* Paramètres : pair = noeud d'arborescence YAML à consulter. *
+* *
+* Description : Indique le format d'origine YAML associé à la clef. *
+* *
+* Retour : Valeur renseignée lors du chargement du noeud. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- matched:
+YamlOriginalStyle g_yaml_pair_get_key_style(const GYamlPair *pair)
+{
+ YamlOriginalStyle result; /* Indication à retourner */
- *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **));
+ result = pair->key_style;
- g_object_ref(G_OBJECT(node));
- (*nodes)[*count - 1] = G_YAML_NODE(node);
+ return result;
- goto done;
+}
- cont:
- if (node->collection != NULL)
- _g_yaml_node_find_by_path(G_YAML_NODE(node->collection), path, prepare, nodes, count);
+/******************************************************************************
+* *
+* Paramètres : pair = noeud d'arborescence YAML à consulter. *
+* *
+* Description : Fournit l'éventuelle valeur d'une paire en YAML. *
+* *
+* Retour : Valeur sous forme de chaîne de caractères ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- done:
+const char *g_yaml_pair_get_value(const GYamlPair *pair)
+{
+ char *result; /* Valeur à retourner */
- exit:
+ result = pair->value;
- ;
+ return result;
}
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* Paramètres : pair = noeud d'arborescence YAML à consulter. *
* *
-* Description : Fournit la clef représentée dans une paire en Yaml. *
+* Description : Indique le format d'origine YAML associé à la valeur. *
* *
-* Retour : Clef sous forme de chaîne de caractères. *
+* Retour : Valeur renseignée lors du chargement du noeud. *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *g_yaml_pair_get_key(const GYamlPair *node)
+YamlOriginalStyle g_yaml_pair_get_value_style(const GYamlPair *pair)
{
- char *result; /* Valeur à retourner */
+ YamlOriginalStyle result; /* Indication à retourner */
- result = node->key;
+ result = pair->value_style;
return result;
@@ -324,9 +329,9 @@ const char *g_yaml_pair_get_key(const GYamlPair *node)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* Paramètres : pair = noeud d'arborescence YAML à consulter. *
* *
-* Description : Fournit l'éventuelle valeur d'une paire en Yaml. *
+* Description : Rassemble une éventuelle séquence de valeurs attachées. *
* *
* Retour : Valeur sous forme de chaîne de caractères ou NULL. *
* *
@@ -334,11 +339,88 @@ const char *g_yaml_pair_get_key(const GYamlPair *node)
* *
******************************************************************************/
-const char *g_yaml_pair_get_value(const GYamlPair *node)
+char *g_yaml_pair_aggregate_value(const GYamlPair *pair)
{
char *result; /* Valeur à retourner */
+ GYamlNode **nodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+ GYamlPair *child; /* Couple clef/valeur enfant */
+ bool failed; /* Détection d'un échec */
+
+ result = NULL;
+
+ if (pair->value != NULL)
+ result = strdup(pair->value);
+
+ else if (pair->children != NULL)
+ {
+ if (!g_yaml_collection_is_sequence(pair->children))
+ goto exit;
+
+ nodes = g_yaml_collection_get_nodes(pair->children, &count);
+
+ if (count == 0)
+ result = strdup("[ ]");
+
+ else
+ {
+ result = strdup("[ ");
+
+ for (i = 0; i < count; i++)
+ {
+ if (!G_IS_YAML_PAIR(nodes[i]))
+ break;
+
+ child = G_YAML_PAIR(nodes[i]);
+
+ if (child->value != NULL)
+ break;
+
+ if (i > 0)
+ result = stradd(result, ", ");
+
+ switch (child->key_style)
+ {
+ case YOS_PLAIN:
+ result = stradd(result, child->key);
+ break;
+
+ case YOS_SINGLE_QUOTED:
+ result = straddfmt(result, "'%s'", child->key);
+ break;
+
+ case YOS_DOUBLE_QUOTED:
+ result = straddfmt(result, "\"%s\"", child->key);
+ break;
+
+ }
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
- result = node->value;
+ failed = (i < count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ free(nodes);
+
+ if (failed)
+ {
+ free(result);
+ result = NULL;
+ }
+
+ else
+ result = stradd(result, " ]");
+
+ }
+
+ }
+
+ exit:
return result;
@@ -347,10 +429,10 @@ const char *g_yaml_pair_get_value(const GYamlPair *node)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à compléter. *
-* collec = collection de noeuds Yaml. *
+* Paramètres : pair = noeud d'arborescence YAML à compléter. *
+* children = collection de noeuds YAML. *
* *
-* Description : Attache une collection de noeuds Yaml à un noeud. *
+* Description : Attache une collection de noeuds YAML à un noeud. *
* *
* Retour : - *
* *
@@ -358,33 +440,33 @@ const char *g_yaml_pair_get_value(const GYamlPair *node)
* *
******************************************************************************/
-void g_yaml_pair_set_collection(GYamlPair *node, GYamlCollection *collec)
+void g_yaml_pair_set_children(GYamlPair *pair, GYamlCollection *children)
{
- g_clear_object(&node->collection);
+ g_clear_object(&pair->children);
- g_object_ref_sink(G_OBJECT(collec));
- node->collection = collec;
+ g_object_ref_sink(G_OBJECT(children));
+ pair->children = children;
}
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* Paramètres : pair = noeud d'arborescence YAML à consulter. *
* *
* Description : Fournit une éventuelle collection rattachée à un noeud. *
* *
-* Retour : Collection de noeuds Yaml ou NULL. *
+* Retour : Collection de noeuds YAML ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlCollection *g_yaml_pair_get_collection(const GYamlPair *node)
+GYamlCollection *g_yaml_pair_get_children(const GYamlPair *pair)
{
GYamlCollection *result; /* Collection à renvoyer */
- result = node->collection;
+ result = pair->children;
if (result != NULL)
g_object_ref(G_OBJECT(result));
@@ -392,3 +474,76 @@ GYamlCollection *g_yaml_pair_get_collection(const GYamlPair *node)
return result;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : pair = noeud d'arborescence YAML à consulter. *
+* path = chemin d'accès à parcourir. *
+* *
+* Description : Recherche le premier noeud correspondant à un chemin. *
+* *
+* Retour : Noeud avec la correspondance établie ou NULL si non trouvé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GYamlNode *g_yaml_pair_find_first_by_path(GYamlPair *pair, const char *path)
+{
+ GYamlNode *result; /* Trouvaille à retourner */
+ char *next; /* Prochaine partie du chemin */
+ size_t cmplen; /* Etendue de la comparaison */
+ int ret; /* Bilan d'une comparaison */
+
+ assert(path[0] != '/' && path[0] != '\0');
+
+ /* Correspondance au niveau du noeud ? */
+
+ next = strchr(path, '/');
+
+ if (next == NULL)
+ ret = strcmp(path, pair->key);
+
+ else
+ {
+ cmplen = next - path;
+ assert(cmplen > 0);
+
+ ret = strncmp(path, pair->key, cmplen);
+
+ }
+
+ /* Si correspondance il y a... */
+
+ if (ret == 0)
+ {
+ /* ... et que la recherche se trouve en bout de parcours */
+ if (next == NULL)
+ {
+ result = G_YAML_NODE(pair);
+ g_object_ref(G_OBJECT(result));
+ }
+
+ /* Recherche supplémentaire dans les sous-noeuds ? */
+
+ else if (pair->children != NULL)
+ result = g_yaml_node_find_first_by_path(G_YAML_NODE(pair->children), path + cmplen);
+
+ else
+ result = NULL;
+
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
diff --git a/plugins/yaml/pair.h b/plugins/yaml/pair.h
index 986fef7..5265392 100644
--- a/plugins/yaml/pair.h
+++ b/plugins/yaml/pair.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* pair.h - prototypes pour un noeud Yaml de paire clef/valeur
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -30,7 +30,6 @@
#include "collection.h"
-#include "line.h"
#include "node.h"
@@ -49,23 +48,42 @@ typedef struct _GYamlPair GYamlPair;
typedef struct _GYamlPairClass GYamlPairClass;
+/* Format d'origine des éléments du couple clef/valeur */
+typedef enum _YamlOriginalStyle
+{
+ YOS_PLAIN, /* Mode brut, par défaut */
+ YOS_SINGLE_QUOTED, /* Encadré simplement */
+ YOS_DOUBLE_QUOTED, /* ENcadré avec des guillemets */
+
+} YamlOriginalStyle;
+
+
/* Indique le type défini pour un noeud d'arborescence Yaml. */
GType g_yaml_pair_get_type(void);
/* Construit un noeud d'arborescence Yaml. */
-GYamlPair *g_yaml_pair_new(GYamlLine *);
+GYamlPair *g_yaml_pair_new(const char *, YamlOriginalStyle, const char *, YamlOriginalStyle);
/* Fournit la clef représentée dans une paire en Yaml. */
const char *g_yaml_pair_get_key(const GYamlPair *);
+/* Indique le format d'origine YAML associé à la clef. */
+YamlOriginalStyle g_yaml_pair_get_key_style(const GYamlPair *);
+
/* Fournit l'éventuelle valeur d'une paire en Yaml. */
const char *g_yaml_pair_get_value(const GYamlPair *);
+/* Indique le format d'origine YAML associé à la valeur. */
+YamlOriginalStyle g_yaml_pair_get_value_style(const GYamlPair *);
+
+/* Rassemble une éventuelle séquence de valeurs attachées. */
+char *g_yaml_pair_aggregate_value(const GYamlPair *);
+
/* Attache une collection de noeuds Yaml à un noeud. */
-void g_yaml_pair_set_collection(GYamlPair *, GYamlCollection *);
+void g_yaml_pair_set_children(GYamlPair *, GYamlCollection *);
/* Fournit une éventuelle collection rattachée à un noeud. */
-GYamlCollection *g_yaml_pair_get_collection(const GYamlPair *);
+GYamlCollection *g_yaml_pair_get_children(const GYamlPair *);
diff --git a/plugins/yaml/parser.c b/plugins/yaml/parser.c
new file mode 100644
index 0000000..8c06723
--- /dev/null
+++ b/plugins/yaml/parser.c
@@ -0,0 +1,299 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser.c - lecteur de contenu Yaml
+ *
+ * Copyright (C) 2019-2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "parser.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <yaml.h>
+#include <gio/gio.h>
+
+
+#include <analysis/contents/file.h>
+
+
+#include "collection.h"
+#include "pair.h"
+
+
+#define SCALAR_STYLE_TO_ORIGINAL_STYLE(v) \
+ ({ \
+ YamlOriginalStyle __result; \
+ if (v == YAML_SINGLE_QUOTED_SCALAR_STYLE) \
+ __result = YOS_SINGLE_QUOTED; \
+ else if (v == YAML_DOUBLE_QUOTED_SCALAR_STYLE) \
+ __result = YOS_DOUBLE_QUOTED; \
+ else \
+ __result = YOS_PLAIN; \
+ __result; \
+ })
+
+
+/* Construit la version GLib d'un noeud YAML brut. */
+static GYamlPair *build_pair_from_yaml(yaml_document_t *, int, int);
+
+/* Transforme un noeud YAML brut en sa version Glib. */
+static GYamlNode *translate_yaml_node(yaml_document_t *, yaml_node_t *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : document = gestionnaire de l'ensemble des noeuds bruts. *
+* key = indice de la clef du noeud à convertir. *
+* value = indice de la valeur du noeud à convertir. *
+* *
+* Description : Construit la version GLib d'un noeud YAML brut. *
+* *
+* Retour : Noeud GLib obtenu ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GYamlPair *build_pair_from_yaml(yaml_document_t *document, int key, int value)
+{
+ GYamlPair *result; /* Racine à retourner */
+ yaml_node_t *key_node; /* Noeud brut de la clef */
+ yaml_node_t *value_node; /* Noeud brut de la valeur */
+ GYamlNode *children; /* Collection de noeuds YAML */
+
+ result = NULL;
+
+ key_node = yaml_document_get_node(document, key);
+ assert(key_node != NULL);
+
+ if (key_node->type != YAML_SCALAR_NODE)
+ goto exit;
+
+ value_node = yaml_document_get_node(document, value);
+ assert(value_node != NULL);
+
+ if (value_node->type == YAML_SCALAR_NODE)
+ result = g_yaml_pair_new((char *)key_node->data.scalar.value,
+ SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style),
+ (char *)value_node->data.scalar.value,
+ SCALAR_STYLE_TO_ORIGINAL_STYLE(value_node->data.scalar.style));
+
+ else
+ {
+ children = translate_yaml_node(document, value_node);
+
+ if (children != NULL)
+ {
+ result = g_yaml_pair_new((char *)key_node->data.scalar.value,
+ SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style),
+ NULL, YOS_PLAIN);
+
+ g_yaml_pair_set_children(result, G_YAML_COLLEC(children));
+
+ }
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : document = gestionnaire de l'ensemble des noeuds bruts. *
+* node = point de départ des transformations. *
+* *
+* Description : Transforme un noeud YAML brut en sa version Glib. *
+* *
+* Retour : Noeud GLib obtenu ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GYamlNode *translate_yaml_node(yaml_document_t *document, yaml_node_t *node)
+{
+ GYamlNode *result; /* Racine à retourner */
+ yaml_node_item_t *index; /* Elément d'une série */
+ yaml_node_t *item; /* Elément d'une série */
+ GYamlNode *child; /* Version GLib de l'élément */
+ yaml_node_pair_t *pair; /* Combinaison clef/valeur */
+ GYamlPair *sub; /* Sous-noeud à intégrer */
+
+ switch (node->type)
+ {
+ case YAML_SCALAR_NODE:
+ result = G_YAML_NODE(g_yaml_pair_new((char *)node->data.scalar.value,
+ SCALAR_STYLE_TO_ORIGINAL_STYLE(node->data.scalar.style),
+ NULL, YOS_PLAIN));
+ break;
+
+ case YAML_SEQUENCE_NODE:
+
+ result = G_YAML_NODE(g_yaml_collection_new(true));
+
+ for (index = node->data.sequence.items.start; index < node->data.sequence.items.top; index++)
+ {
+ item = yaml_document_get_node(document, *index);
+ assert(item != NULL);
+
+ child = translate_yaml_node(document, item);
+
+ if (child == NULL)
+ {
+ g_clear_object(&result);
+ break;
+ }
+
+ g_yaml_collection_add_node(G_YAML_COLLEC(result), child);
+
+ }
+
+ break;
+
+ case YAML_MAPPING_NODE:
+
+ result = G_YAML_NODE(g_yaml_collection_new(false));
+
+ for (pair = node->data.mapping.pairs.start; pair < node->data.mapping.pairs.top; pair++)
+ {
+ sub = build_pair_from_yaml(document, pair->key, pair->value);
+
+ if (sub == NULL)
+ {
+ g_clear_object(&result);
+ break;
+ }
+
+ g_yaml_collection_add_node(G_YAML_COLLEC(result), G_YAML_NODE(sub));
+
+ }
+
+ break;
+
+ default:
+ assert(false);
+ result = NULL;
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : text = définitions textuelles d'un contenu brut. *
+* len = taille de ces définitions. *
+* *
+* Description : Crée une arborescence YAML pour contenu au format adapté. *
+* *
+* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GYamlNode *parse_yaml_from_text(const char *text, size_t len)
+{
+ GYamlNode *result; /* Racine à retourner */
+ yaml_parser_t parser; /* Lecteur du contenu fourni */
+ yaml_document_t document; /* Document YAML constitué */
+ int ret; /* Bilan de la constitution */
+ yaml_node_t *root; /* Elément racine brut */
+
+ result = NULL;
+
+ yaml_parser_initialize(&parser);
+
+ yaml_parser_set_input_string(&parser, (const unsigned char *)text, len);
+
+ ret = yaml_parser_load(&parser, &document);
+ if (ret != 1) goto bad_loading;
+
+ root = yaml_document_get_root_node(&document);
+
+ if (root != NULL)
+ result = translate_yaml_node(&document, root);
+
+ yaml_document_delete(&document);
+
+ bad_loading:
+
+ yaml_parser_delete(&parser);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : filename = chemin vers des définitions de règles. *
+* *
+* Description : Crée une arborescence YAML pour fichier au format adapté. *
+* *
+* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GYamlNode *parse_yaml_from_file(const char *filename)
+{
+ GYamlNode *result; /* Racine à retourner */
+ GBinContent *content; /* Fichier à parcourir */
+ phys_t size; /* Taille du contenu associé */
+ vmpa2t start; /* Tête de lecture */
+ const bin_t *data; /* Données à consulter */
+ char *dumped; /* Contenu manipulable */
+
+ result = NULL;
+
+ content = g_file_content_new(filename);
+ if (content == NULL) goto no_content;
+
+ size = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &start);
+ data = g_binary_content_get_raw_access(content, &start, size);
+
+ dumped = malloc((size + 1) * sizeof(char));
+
+ memcpy(dumped, data, size);
+ dumped[size] = '\0';
+
+ result = parse_yaml_from_text(dumped, size);
+
+ free(dumped);
+
+ g_object_unref(G_OBJECT(content));
+
+ no_content:
+
+ return result;
+
+}
diff --git a/plugins/yaml/parser.h b/plugins/yaml/parser.h
new file mode 100644
index 0000000..761e12b
--- /dev/null
+++ b/plugins/yaml/parser.h
@@ -0,0 +1,43 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser.h - prototypes pour le lecteur de contenu Yaml
+ *
+ * Copyright (C) 2019-2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_YAML_PARSER_H
+#define PLUGINS_YAML_PARSER_H
+
+
+#include <sys/types.h>
+
+
+#include "node.h"
+
+
+
+/* Crée une arborescence YAML pour contenu au format adapté. */
+GYamlNode *parse_yaml_from_text(const char *, size_t);
+
+/* Crée une arborescence YAML pour fichier au format adapté. */
+GYamlNode *parse_yaml_from_file(const char *);
+
+
+
+#endif /* PLUGINS_YAML_PARSER_H */
diff --git a/plugins/yaml/python/Makefile.am b/plugins/yaml/python/Makefile.am
index 4662a8e..f3dc989 100644
--- a/plugins/yaml/python/Makefile.am
+++ b/plugins/yaml/python/Makefile.am
@@ -3,23 +3,16 @@ noinst_LTLIBRARIES = libyamlpython.la
libyamlpython_la_SOURCES = \
collection.h collection.c \
- line.h line.c \
+ constants.h constants.c \
module.h module.c \
node.h node.c \
pair.h pair.c \
- reader.h reader.c \
- scalar.h scalar.c \
- tree.h tree.c
+ parser.h parser.c
-libyamlpython_la_LDFLAGS =
+libyamlpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libyamlpython_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/yaml/python/collection.c b/plugins/yaml/python/collection.c
index e21bb9e..fd8e08a 100644
--- a/plugins/yaml/python/collection.c
+++ b/plugins/yaml/python/collection.c
@@ -28,18 +28,22 @@
#include <pygobject.h>
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
#include <plugins/pychrysalide/helpers.h>
#include "node.h"
-#include "../collection.h"
+#include "../collection-int.h"
-/* Crée un nouvel objet Python de type 'YamlCollection'. */
-static PyObject *py_yaml_collection_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(yaml_collection, G_TYPE_YAML_COLLEC);
-/* Indique la nature d'une collection Yaml. */
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_yaml_collection_init(PyObject *, PyObject *, PyObject *);
+
+/* Indique la nature d'une collection YAML. */
static PyObject *py_yaml_collection_is_sequence(PyObject *, void *);
/* Fournit la liste des noeuds intégrés dans une collection. */
@@ -49,44 +53,56 @@ static PyObject *py_yaml_collection_get_nodes(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'YamlCollection'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_collection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_yaml_collection_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
int seq; /* Indicateur de type */
int ret; /* Bilan de lecture des args. */
GYamlCollection *collec; /* Création GLib à transmettre */
#define YAML_COLLECTION_DOC \
- "YamlCollection handles a collection of Yaml nodes.\n" \
+ "YamlCollection handles a collection of YAML nodes.\n" \
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
" YamlCollection(seq=False)\n" \
"\n" \
- "Where seq defines if the collection will be a sequence or a mapping of nodes."
+ "Where *seq* is a boolean value which defines if the collection will be a" \
+ " sequence or a mapping of nodes."
+
+ /* Récupération des paramètres */
ret = PyArg_ParseTuple(args, "p", &seq);
- if (!ret) return NULL;
+ if (!ret) return -1;
- collec = g_yaml_collection_new(seq);
+ /* Initialisation d'un objet GLib */
- g_object_ref_sink(G_OBJECT(collec));
- result = pygobject_new(G_OBJECT(collec));
- g_object_unref(collec);
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- return result;
+ /* Eléments de base */
+
+ collec = G_YAML_COLLEC(pygobject_get(self));
+
+ if (!g_yaml_collection_create(collec, seq))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create YAML collection."));
+ return -1;
+
+ }
+
+ return 0;
}
@@ -98,7 +114,7 @@ static PyObject *py_yaml_collection_new(PyTypeObject *type, PyObject *args, PyOb
* *
* Description : Fournit la liste des noeuds intégrés dans une collection. *
* *
-* Retour : Enfants d'un noeud issu d'une collection Yaml. *
+* Retour : Enfants d'un noeud issu d'une collection YAML. *
* *
* Remarques : - *
* *
@@ -152,7 +168,7 @@ static PyObject *py_yaml_collection_get_nodes(PyObject *self, void *closure)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Indique la nature d'une collection Yaml. *
+* Description : Indique la nature d'une collection YAML. *
* *
* Retour : Nature de la collection. *
* *
@@ -169,7 +185,7 @@ static PyObject *py_yaml_collection_is_sequence(PyObject *self, void *closure)
#define YAML_COLLECTION_IS_SEQUENCE_ATTRIB PYTHON_IS_DEF_FULL \
( \
sequence, py_yaml_collection, \
- "Nature of the collection: True is the collection is a sequence," \
+ "Nature of the collection: True if the collection is a sequence," \
" False if it is a mapping of \"key: value\" nodes." \
)
@@ -222,7 +238,9 @@ PyTypeObject *get_python_yaml_collection_type(void)
.tp_methods = py_yaml_collection_methods,
.tp_getset = py_yaml_collection_getseters,
- .tp_new = py_yaml_collection_new
+
+ .tp_init = py_yaml_collection_init,
+ .tp_new = py_yaml_collection_new,
};
@@ -233,7 +251,7 @@ PyTypeObject *get_python_yaml_collection_type(void)
/******************************************************************************
* *
-* Paramètres : module = module dont la définition est à compléter. *
+* Paramètres : - *
* *
* Description : Prend en charge l'objet 'pychrysalide.....YamlCollection. *
* *
@@ -243,17 +261,24 @@ PyTypeObject *get_python_yaml_collection_type(void)
* *
******************************************************************************/
-bool register_python_yaml_collection(PyObject *module)
+bool ensure_python_yaml_collection_is_registered(void)
{
PyTypeObject *type; /* Type Python 'YamlCollection'*/
+ PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
type = get_python_yaml_collection_type();
- dict = PyModule_GetDict(module);
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.yaml");
+
+ dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_YAML_COLLEC, type, get_python_yaml_node_type()))
- return false;
+ if (!register_class_for_pygobject(dict, G_TYPE_YAML_COLLEC, type))
+ return false;
+
+ }
return true;
@@ -265,7 +290,7 @@ bool register_python_yaml_collection(PyObject *module)
* Paramètres : arg = argument quelconque à tenter de convertir. *
* dst = destination des valeurs récupérées en cas de succès. *
* *
-* Description : Tente de convertir en collection de noeuds de format Yaml. *
+* Description : Tente de convertir en collection de noeuds de format YAML. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
* *
@@ -287,7 +312,7 @@ int convert_to_yaml_collection(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml collection");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YAML collection");
break;
case 1:
diff --git a/plugins/yaml/python/collection.h b/plugins/yaml/python/collection.h
index ab2caba..24875d0 100644
--- a/plugins/yaml/python/collection.h
+++ b/plugins/yaml/python/collection.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* collection.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/collection.h"
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -35,9 +35,9 @@
PyTypeObject *get_python_yaml_collection_type(void);
/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlCollection'. */
-bool register_python_yaml_collection(PyObject *);
+bool ensure_python_yaml_collection_is_registered(void);
-/* Tente de convertir en collection de noeuds de format Yaml. */
+/* Tente de convertir en collection de noeuds de format YAML. */
int convert_to_yaml_collection(PyObject *, void *);
diff --git a/plugins/yaml/python/constants.c b/plugins/yaml/python/constants.c
new file mode 100644
index 0000000..ff04584
--- /dev/null
+++ b/plugins/yaml/python/constants.c
@@ -0,0 +1,127 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.c - prise en charge des constantes liées à YAML
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "constants.h"
+
+
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../pair.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type dont le dictionnaire est à compléter. *
+* *
+* Description : Définit les constantes relatives au noeuds principaux. *
+* *
+* Retour : true en cas de succès de l'opération, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_yaml_pair_constants(PyTypeObject *type)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *values; /* Groupe de valeurs à établir */
+
+ values = PyDict_New();
+
+ result = add_const_to_group(values, "PLAIN", YOS_PLAIN);
+ if (result) result = add_const_to_group(values, "SINGLE_QUOTED", YOS_SINGLE_QUOTED);
+ if (result) result = add_const_to_group(values, "DOUBLE_QUOTED", YOS_DOUBLE_QUOTED);
+
+ if (!result)
+ {
+ Py_DECREF(values);
+ goto exit;
+ }
+
+ result = attach_constants_group_to_type(type, false, "YamlOriginalStyle", values,
+ "Original style of scalar YAML nodes.");
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en constante YamlOriginalStyle. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_yaml_pair_original_style(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ unsigned long value; /* Valeur transcrite */
+
+ result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type);
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YamlOriginalStyle");
+ break;
+
+ case 1:
+ value = PyLong_AsUnsignedLong(arg);
+
+ if (value > YOS_DOUBLE_QUOTED)
+ {
+ PyErr_SetString(PyExc_TypeError, "invalid value for YamlOriginalStyle");
+ result = 0;
+ }
+
+ else
+ *((YamlOriginalStyle *)dst) = value;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/yaml/python/constants.h b/plugins/yaml/python/constants.h
new file mode 100644
index 0000000..d31bb69
--- /dev/null
+++ b/plugins/yaml/python/constants.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.h - prototypes pour la prise en charge des constantes liées à YAML
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_YAML_PYTHON_CONSTANTS_H
+#define _PLUGINS_YAML_PYTHON_CONSTANTS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit les constantes relatives au noeuds principaux. */
+bool define_yaml_pair_constants(PyTypeObject *);
+
+/* Tente de convertir en constante YamlOriginalStyle. */
+int convert_to_yaml_pair_original_style(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_YAML_PYTHON_CONSTANTS_H */
diff --git a/plugins/yaml/python/module.c b/plugins/yaml/python/module.c
index 90823e8..3d6a4e8 100644
--- a/plugins/yaml/python/module.c
+++ b/plugins/yaml/python/module.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* module.c - intégration du répertoire yaml en tant que module
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -34,12 +34,9 @@
#include "collection.h"
-#include "line.h"
#include "node.h"
#include "pair.h"
-#include "reader.h"
-#include "scalar.h"
-#include "tree.h"
+#include "parser.h"
@@ -62,7 +59,12 @@ bool add_yaml_module_to_python_module(void)
PyObject *module; /* Sous-module mis en place */
#define PYCHRYSALIDE_PLUGINS_YAML_DOC \
- "yaml is a module providing access to Yaml content."
+ "yaml is a module providing access to YAML content.\n" \
+ "\n" \
+ "The parsing is provided by an external library: " \
+ " https://github.com/yaml/libyaml . The Python module only" \
+ " creates some glue to access YAML content from GObject" \
+ " code."
static PyModuleDef py_chrysalide_yaml_module = {
@@ -105,19 +107,12 @@ bool add_yaml_module_to_python_module(void)
bool populate_yaml_module(void)
{
bool result; /* Bilan à retourner */
- PyObject *module; /* Module à recompléter */
- result = true;
+ result = populate_yaml_module_with_parsers();
- module = get_access_to_python_module("pychrysalide.plugins.yaml");
-
- if (result) result = register_python_yaml_node(module);
- if (result) result = register_python_yaml_collection(module);
- if (result) result = register_python_yaml_line(module);
- if (result) result = register_python_yaml_pair(module);
- if (result) result = register_python_yaml_reader(module);
- if (result) result = register_python_yaml_scalar(module);
- if (result) result = register_python_yaml_tree(module);
+ if (result) result = ensure_python_yaml_node_is_registered();
+ if (result) result = ensure_python_yaml_collection_is_registered();
+ if (result) result = ensure_python_yaml_pair_is_registered();
assert(result);
diff --git a/plugins/yaml/python/node.c b/plugins/yaml/python/node.c
index 7db6e59..7d2fef0 100644
--- a/plugins/yaml/python/node.c
+++ b/plugins/yaml/python/node.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* node.c - équivalent Python du fichier "plugins/yaml/node.c"
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -28,101 +28,55 @@
#include <pygobject.h>
+#include <plugins/pychrysalide/access.h>
#include <plugins/pychrysalide/helpers.h>
-#include "collection.h"
-#include "line.h"
#include "../node.h"
-#define YAML_NODE_DOC \
- "YamlNode handles a node in a Yaml tree.\n" \
- "\n" \
- "There are three kinds of node contents defined in the Yaml specifications:\n" \
- "* scalar, implemented by the pychrysalide.plugins.yaml.YamlScalar object.\n" \
- "* sequence and mapping, implemented by the pychrysalide.plugins.yaml.YamlCollection object."
-
-
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(yaml_node, G_TYPE_YAML_NODE, NULL);
-/* Recherche les noeuds correspondant à un chemin. */
-static PyObject *py_yaml_node_find_by_path(PyObject *, PyObject *);
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_yaml_node_init(PyObject *, PyObject *, PyObject *);
-/* Recherche l'unique noeud correspondant à un chemin. */
-static PyObject *py_yaml_node_find_one_by_path(PyObject *, PyObject *);
-
-/* Fournit la ligne d'origine associée à un noeud. */
-static PyObject *py_yaml_node_get_yaml_line(PyObject *, void *);
+/* Recherche le premier noeud correspondant à un chemin. */
+static PyObject *py_yaml_node_find_first_by_path(PyObject *, PyObject *);
/******************************************************************************
* *
-* Paramètres : self = variable non utilisée ici. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
* *
-* Description : Recherche les noeuds correspondant à un chemin. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Liste de noeuds trouvés, éventuellement vide. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_node_find_by_path(PyObject *self, PyObject *args)
+static int py_yaml_node_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
- int prepare; /* Orientation des résultats */
- const char *path; /* Chemin d'accès à traiter */
int ret; /* Bilan de lecture des args. */
- GYamlNode *node; /* Version GLib du noeud */
- GYamlNode **found; /* Créations GLib à transmettre*/
- size_t count; /* Quantité de trouvailles */
- size_t i; /* Boucle de parcours */
-
-#define YAML_NODE_FIND_BY_PATH_METHOD PYTHON_METHOD_DEF \
-( \
- find_by_path, "path, /, prepare=False", \
- METH_VARARGS, py_yaml_node, \
- "Find nodes from a Yaml node using a path.\n" \
- "\n" \
- "Paths are node keys separated by '/', such as '/my/path/to/node'." \
- "\n" \
- "In case where the path ends with a trailing '/', the operation can" \
- " be used to prepare a further look by returning a node which can be" \
- " searched by a new call to this function instead of returning all its" \
- " contained nodes." \
-)
-
- prepare = 0;
- ret = PyArg_ParseTuple(args, "s|p", &path, &prepare);
- if (!ret) return NULL;
-
- node = G_YAML_NODE(pygobject_get(self));
-
- g_yaml_node_find_by_path(node, path, prepare, &found, &count);
-
- result = PyTuple_New(count);
-
- for (i = 0; i < count; i++)
- {
-#ifndef NDEBUG
- ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
- assert(ret == 0);
-#else
- PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
-#endif
-
- g_object_unref(G_OBJECT(found[i]));
+#define YAML_NODE_DOC \
+ "YamlNode handles a node in a YAML tree.\n" \
+ "\n" \
+ "There are two kinds of node contents defined in the YAML specifications:\n" \
+ "* pair, implemented by the pychrysalide.plugins.yaml.YamlPair object;\n" \
+ "* sequence and mapping, implemented by the pychrysalide.plugins.yaml.YamlCollection object."
- }
+ /* Initialisation d'un objet GLib */
- if (found != NULL)
- free(found);
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- return result;
+ return 0;
}
@@ -132,103 +86,55 @@ static PyObject *py_yaml_node_find_by_path(PyObject *self, PyObject *args)
* Paramètres : self = variable non utilisée ici. *
* args = arguments fournis à l'appel. *
* *
-* Description : Recherche l'unique noeud correspondant à un chemin. *
+* Description : Recherche le premier noeud correspondant à un chemin. *
* *
-* Retour : Noeud avec correspondance établie ou None. *
+* Retour : Noeud avec la correspondance établie ou None si non trouvé. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_node_find_one_by_path(PyObject *self, PyObject *args)
+static PyObject *py_yaml_node_find_first_by_path(PyObject *self, PyObject *args)
{
PyObject *result; /* Instance à retourner */
- int prepare; /* Orientation des résultats */
const char *path; /* Chemin d'accès à traiter */
int ret; /* Bilan de lecture des args. */
GYamlNode *node; /* Version GLib du noeud */
- GYamlNode *found; /* Création GLib à transmettre */
+ GYamlNode *found; /* Créations GLib à transmettre*/
-#define YAML_NODE_FIND_ONE_BY_PATH_METHOD PYTHON_METHOD_DEF \
+#define YAML_NODE_FIND_FIRST_BY_PATH_METHOD PYTHON_METHOD_DEF \
( \
- find_one_by_path, "path, /, prepare=False", \
+ find_first_by_path, "path", \
METH_VARARGS, py_yaml_node, \
- "Find a given node from a Yaml node using a path.\n" \
+ "Find the first node related to a path among the node YAML children.\n" \
"\n" \
"Paths are node keys separated by '/', such as '/my/path/to/node'." \
+ " In case where the path ends with a trailing '/', the operation" \
+ " matches the first next met node.\n" \
"\n" \
- "Only one node has to match the path for the function success." \
+ "The *path* argument is expected to be a string value.\n" \
"\n" \
- "In case where the path ends with a trailing '/', the operation can" \
- " be used to prepare a further look by returning a node which can be" \
- " searched by a new call to this function instead of returning all its" \
- " contained nodes." \
+ "The function returns a pychrysalide.plugins.yaml.YamlNode instance," \
+ " or *None* if none found." \
)
- prepare = 0;
-
- ret = PyArg_ParseTuple(args, "s|p", &path, &prepare);
+ ret = PyArg_ParseTuple(args, "s", &path);
if (!ret) return NULL;
node = G_YAML_NODE(pygobject_get(self));
- found = g_yaml_node_find_one_by_path(node, path, prepare);
+ found = g_yaml_node_find_first_by_path(node, path);
- if (found == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
- else
+ if (found != NULL)
{
result = pygobject_new(G_OBJECT(found));
g_object_unref(G_OBJECT(found));
}
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
-* *
-* Description : Fournit la ligne principale associée à un noeud. *
-* *
-* Retour : Ligne Yaml à l'origine du noeud. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
-{
- PyObject *result; /* Résultat à retourner */
- GYamlNode *node; /* Version GLib du noeud */
- GYamlLine *line; /* Line Yaml associée */
-
-#define YAML_NODE_YAML_LINE_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- yaml_line, py_yaml_node, \
- "Orginal Yaml line linked to the node." \
-)
-
- node = G_YAML_NODE(pygobject_get(self));
-
- line = g_yaml_node_get_yaml_line(node);
-
- if (line == NULL)
+ else
{
result = Py_None;
Py_INCREF(result);
}
- else
- {
- result = pygobject_new(G_OBJECT(line));
- g_object_unref(G_OBJECT(line));
- }
return result;
@@ -250,13 +156,11 @@ static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
PyTypeObject *get_python_yaml_node_type(void)
{
static PyMethodDef py_yaml_node_methods[] = {
- YAML_NODE_FIND_BY_PATH_METHOD,
- YAML_NODE_FIND_ONE_BY_PATH_METHOD,
+ YAML_NODE_FIND_FIRST_BY_PATH_METHOD,
{ NULL }
};
static PyGetSetDef py_yaml_node_getseters[] = {
- YAML_NODE_YAML_LINE_ATTRIB,
{ NULL }
};
@@ -273,7 +177,9 @@ PyTypeObject *get_python_yaml_node_type(void)
.tp_methods = py_yaml_node_methods,
.tp_getset = py_yaml_node_getseters,
- .tp_new = no_python_constructor_allowed
+
+ .tp_init = py_yaml_node_init,
+ .tp_new = py_yaml_node_new,
};
@@ -284,7 +190,7 @@ PyTypeObject *get_python_yaml_node_type(void)
/******************************************************************************
* *
-* Paramètres : module = module dont la définition est à compléter. *
+* Paramètres : - *
* *
* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlNode. *
* *
@@ -294,17 +200,24 @@ PyTypeObject *get_python_yaml_node_type(void)
* *
******************************************************************************/
-bool register_python_yaml_node(PyObject *module)
+bool ensure_python_yaml_node_is_registered(void)
{
PyTypeObject *type; /* Type Python 'YamlNode' */
+ PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
type = get_python_yaml_node_type();
- dict = PyModule_GetDict(module);
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.yaml");
+
+ dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_YAML_NODE, type, &PyGObject_Type))
- return false;
+ if (!register_class_for_pygobject(dict, G_TYPE_YAML_NODE, type))
+ return false;
+
+ }
return true;
@@ -316,7 +229,7 @@ bool register_python_yaml_node(PyObject *module)
* Paramètres : arg = argument quelconque à tenter de convertir. *
* dst = destination des valeurs récupérées en cas de succès. *
* *
-* Description : Tente de convertir en noeud d'arborescence de format Yaml. *
+* Description : Tente de convertir en noeud d'arborescence de format YAML. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
* *
@@ -338,7 +251,7 @@ int convert_to_yaml_node(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml node");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YAML node");
break;
case 1:
diff --git a/plugins/yaml/python/node.h b/plugins/yaml/python/node.h
index dc3686b..80d8a65 100644
--- a/plugins/yaml/python/node.h
+++ b/plugins/yaml/python/node.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* node.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/node.h"
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -35,9 +35,9 @@
PyTypeObject *get_python_yaml_node_type(void);
/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlNode'. */
-bool register_python_yaml_node(PyObject *);
+bool ensure_python_yaml_node_is_registered(void);
-/* Tente de convertir en noeud d'arborescence de format Yaml. */
+/* Tente de convertir en noeud d'arborescence de format YAML. */
int convert_to_yaml_node(PyObject *, void *);
diff --git a/plugins/yaml/python/pair.c b/plugins/yaml/python/pair.c
index db5597d..1fffbeb 100644
--- a/plugins/yaml/python/pair.c
+++ b/plugins/yaml/python/pair.c
@@ -26,74 +26,176 @@
#include <assert.h>
+#include <malloc.h>
#include <pygobject.h>
+#include <i18n.h>
+#include <plugins/pychrysalide/access.h>
#include <plugins/pychrysalide/helpers.h>
#include "collection.h"
-#include "line.h"
+#include "constants.h"
#include "node.h"
-#include "../pair.h"
+#include "../pair-int.h"
-/* Crée un nouvel objet Python de type 'YamlPair'. */
-static PyObject *py_yaml_pair_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(yaml_pair, G_TYPE_YAML_PAIR);
-/* Fournit la clef représentée dans une paire en Yaml. */
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_yaml_pair_init(PyObject *, PyObject *, PyObject *);
+
+/* Rassemble une éventuelle séquence de valeurs attachées. */
+static PyObject *py_yaml_pair_aggregate_value(PyObject *, PyObject *);
+
+/* Fournit la clef représentée dans une paire en YAML. */
static PyObject *py_yaml_pair_get_key(PyObject *, void *);
-/* Fournit l'éventuelle valeur d'une paire en Yaml. */
+/* Indique le format d'origine YAML associé à la clef. */
+static PyObject *py_yaml_pair_get_key_style(PyObject *, void *);
+
+/* Fournit l'éventuelle valeur d'une paire en YAML. */
static PyObject *py_yaml_pair_get_value(PyObject *, void *);
-/* Attache une collection de noeuds Yaml à un noeud. */
-static int py_yaml_pair_set_collection(PyObject *, PyObject *, void *);
+/* Indique le format d'origine YAML associé à la clef. */
+static PyObject *py_yaml_pair_get_value_style(PyObject *, void *);
+
+/* Attache une collection de noeuds YAML à un noeud. */
+static int py_yaml_pair_set_children(PyObject *, PyObject *, void *);
/* Fournit une éventuelle collection rattachée à un noeud. */
-static PyObject *py_yaml_pair_get_collection(PyObject *, void *);
+static PyObject *py_yaml_pair_get_children(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : type = type de l'objet à instancier. *
+* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
* *
-* Description : Crée un nouvel objet Python de type 'YamlPair'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_pair_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_yaml_pair_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
- GYamlLine *key; /* Ligne principale du noeud */
+ YamlOriginalStyle kstyle; /* Format d'origine de la clef */
+ const char *value; /* Eventuelle valeur associée */
+ YamlOriginalStyle vstyle; /* Format d'origine de la val. */
+ const char *key; /* Clef associée au noeud */
int ret; /* Bilan de lecture des args. */
- GYamlPair *node; /* Création GLib à transmettre */
+ GYamlPair *pair; /* Création GLib à transmettre */
#define YAML_PAIR_DOC \
- "YamlPair handles a key/value pair node in a Yaml tree.\n" \
+ "YamlPair handles a key/value pair node in a YAML tree.\n" \
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
- " YamlPair(line)\n" \
+ " YamlPair(key, kstyle=PLAIN, value=None, vstyle=PLAIN)\n" \
+ "\n" \
+ "Where *key* defines the name for the YAML node, and *value*" \
+ " provides an optional direct value for the node. The *kstyle* and" \
+ " *vstyle* arguements are" \
+ " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle states" \
+ " linking an original format to the provided relative strings.\n" \
+ "\n" \
+ "The two style are mainly used to aggregate children values into" \
+ " a raw array. The following declarations are indeed equivalent" \
+ " and pychrysalide.plugins.yaml.YamlPair.aggregate_value()" \
+ " build the latter version from the former one:\n" \
"\n" \
- "Where key is the original Yaml line for the pair."
+ "a: [ 1, 2, 3 ]\n" \
+ "\n" \
+ "a:\n" \
+ " - 1\n" \
+ " - 2\n" \
+ " - 3" \
+
+ /* Récupération des paramètres */
+
+ kstyle = YOS_PLAIN;
+ value = NULL;
+ vstyle = YOS_PLAIN;
+
+ ret = PyArg_ParseTuple(args, "s|O&sO&",
+ &key, convert_to_yaml_pair_original_style, &kstyle,
+ &value, convert_to_yaml_pair_original_style, &vstyle);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ pair = G_YAML_PAIR(pygobject_get(self));
+
+ if (!g_yaml_pair_create(pair, key, kstyle, value, vstyle))
+ {
+ PyErr_SetString(PyExc_ValueError, _("Unable to create YAML pair."));
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = serveur à manipuler. *
+* args = arguments d'appel non utilisés ici. *
+* *
+* Description : Rassemble une éventuelle séquence de valeurs attachées. *
+* *
+* Retour : Valeur sous forme de chaîne de caractères ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_pair_aggregate_value(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ GYamlPair *node; /* Version GLib du type */
+ char *value; /* Chaîne à transmettre */
- ret = PyArg_ParseTuple(args, "O&", &convert_to_yaml_line, &key);
- if (!ret) return NULL;
+#define YAML_PAIR_AGGREGATE_VALUE_METHOD PYTHON_METHOD_DEF \
+( \
+ aggregate_value, "$self, /", \
+ METH_NOARGS, py_yaml_pair, \
+ "Provide the value linked to the YAML node, rebuilding" \
+ " it from inner sequenced values if necessary and" \
+ " possible." \
+ "\n" \
+ "The result is a string value, or *None* if none" \
+ " available." \
+)
- node = g_yaml_pair_new(key);
+ node = G_YAML_PAIR(pygobject_get(self));
+
+ value = g_yaml_pair_aggregate_value(node);
+
+ if (value == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
- g_object_ref_sink(G_OBJECT(node));
- result = pygobject_new(G_OBJECT(node));
- g_object_unref(node);
+ else
+ {
+ result = PyUnicode_FromString(value);
+ free(value);
+ }
return result;
@@ -105,7 +207,7 @@ static PyObject *py_yaml_pair_new(PyTypeObject *type, PyObject *args, PyObject *
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit la clef représentée dans une paire en Yaml. *
+* Description : Fournit la clef représentée dans une paire en YAML. *
* *
* Retour : Clef sous forme de chaîne de caractères. *
* *
@@ -122,7 +224,8 @@ static PyObject *py_yaml_pair_get_key(PyObject *self, void *closure)
#define YAML_PAIR_KEY_ATTRIB PYTHON_GET_DEF_FULL \
( \
key, py_yaml_pair, \
- "Key linked to the Yaml key/value pair node." \
+ "Key linked to the YAML key/value pair node," \
+ " as a string value." \
)
node = G_YAML_PAIR(pygobject_get(self));
@@ -142,7 +245,45 @@ static PyObject *py_yaml_pair_get_key(PyObject *self, void *closure)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit l'éventuelle valeur d'une paire en Yaml. *
+* Description : Indique le format d'origine YAML associé à la clef. *
+* *
+* Retour : Valeur renseignée lors du chargement du noeud. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_pair_get_key_style(PyObject *self, void *closure)
+{
+ PyObject *result; /* Résultat à retourner */
+ GYamlPair *node; /* Version GLib du noeud */
+ YamlOriginalStyle style; /* Format à transmettre */
+
+#define YAML_PAIR_KEY_STYLE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ key_style, py_yaml_pair, \
+ "Original format for the YAML node Key, as a" \
+ " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle" \
+ " value." \
+)
+
+ node = G_YAML_PAIR(pygobject_get(self));
+
+ style = g_yaml_pair_get_key_style(node);
+
+ result = cast_with_constants_group_from_type(get_python_yaml_pair_type(), "YamlOriginalStyle", style);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit l'éventuelle valeur d'une paire en YAML. *
* *
* Retour : Valeur sous forme de chaîne de caractères ou None. *
* *
@@ -159,7 +300,8 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure)
#define YAML_PAIR_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
( \
value, py_yaml_pair, \
- "Value linked to the Yaml key/value pair node or None." \
+ "Value linked to the YAML key/value pair node, as a" \
+ " string value, or *None* if none defined." \
)
node = G_YAML_PAIR(pygobject_get(self));
@@ -182,11 +324,52 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure)
/******************************************************************************
* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique le format d'origine YAML associé à la clef. *
+* *
+* Retour : Valeur renseignée lors du chargement du noeud. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_pair_get_value_style(PyObject *self, void *closure)
+{
+ PyObject *result; /* Résultat à retourner */
+ GYamlPair *node; /* Version GLib du noeud */
+ YamlOriginalStyle style; /* Format à transmettre */
+
+#define YAML_PAIR_VALUE_STYLE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ value_style, py_yaml_pair, \
+ "Original format for the YAML node Value, as a" \
+ " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle" \
+ " value.\n" \
+ "\n" \
+ "Even if there is no value for the node, the default" \
+ " style is returned: *PLAIN*." \
+)
+
+ node = G_YAML_PAIR(pygobject_get(self));
+
+ style = g_yaml_pair_get_value_style(node);
+
+ result = cast_with_constants_group_from_type(get_python_yaml_pair_type(), "YamlOriginalStyle", style);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : self = contenu binaire à manipuler. *
-* value = collection de noeuds Yaml. *
+* value = collection de noeuds YAML. *
* closure = adresse non utilisée ici. *
* *
-* Description : Attache une collection de noeuds Yaml à un noeud. *
+* Description : Attache une collection de noeuds YAML à un noeud. *
* *
* Retour : Jeu d'attributs liés au contenu courant. *
* *
@@ -194,28 +377,28 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure)
* *
******************************************************************************/
-static int py_yaml_pair_set_collection(PyObject *self, PyObject *value, void *closure)
+static int py_yaml_pair_set_children(PyObject *self, PyObject *value, void *closure)
{
int result; /* Bilan à renvoyer */
GYamlPair *node; /* Version GLib du noeud */
- GYamlCollection *collec; /* Version GLib de la valeur */
+ GYamlCollection *children; /* Version GLib de la valeur */
node = G_YAML_PAIR(pygobject_get(self));
if (value == Py_None)
{
- g_yaml_pair_set_collection(node, NULL);
+ g_yaml_pair_set_children(node, NULL);
result = 0;
}
else
{
- if (!convert_to_yaml_collection(value, &collec))
+ if (!convert_to_yaml_collection(value, &children))
result = -1;
else
{
- g_yaml_pair_set_collection(node, collec);
+ g_yaml_pair_set_children(node, children);
result = 0;
}
@@ -233,29 +416,31 @@ static int py_yaml_pair_set_collection(PyObject *self, PyObject *value, void *cl
* *
* Description : Fournit une éventuelle collection rattachée à un noeud. *
* *
-* Retour : Collection de noeuds Yaml ou None. *
+* Retour : Collection de noeuds YAML ou None. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_pair_get_collection(PyObject *self, void *closure)
+static PyObject *py_yaml_pair_get_children(PyObject *self, void *closure)
{
PyObject *result; /* Instance à retourner */
GYamlPair *node; /* Version GLib du noeud */
- GYamlCollection *collec; /* Collection à transmettre */
-
-#define YAML_PAIR_COLLECTION_ATTRIB PYTHON_GETSET_DEF_FULL \
-( \
- collection, py_yaml_pair, \
- "Provide or define the collection of nodes attached to another Yaml node." \
+ GYamlCollection *children; /* Collection à transmettre */
+
+#define YAML_PAIR_CHILDREN_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ children, py_yaml_pair, \
+ "Provide or define the collection of nodes attached to another" \
+ " YAML node. The collection, if defined, is handled as a" \
+ " pychrysalide.plugins.yaml.YamlCollection instance." \
)
node = G_YAML_PAIR(pygobject_get(self));
- collec = g_yaml_pair_get_collection(node);
+ children = g_yaml_pair_get_children(node);
- if (collec == NULL)
+ if (children == NULL)
{
result = Py_None;
Py_INCREF(result);
@@ -263,8 +448,8 @@ static PyObject *py_yaml_pair_get_collection(PyObject *self, void *closure)
else
{
- result = pygobject_new(G_OBJECT(collec));
- g_object_unref(collec);
+ result = pygobject_new(G_OBJECT(children));
+ g_object_unref(children);
}
return result;
@@ -287,13 +472,16 @@ static PyObject *py_yaml_pair_get_collection(PyObject *self, void *closure)
PyTypeObject *get_python_yaml_pair_type(void)
{
static PyMethodDef py_yaml_pair_methods[] = {
+ YAML_PAIR_AGGREGATE_VALUE_METHOD,
{ NULL }
};
static PyGetSetDef py_yaml_pair_getseters[] = {
YAML_PAIR_KEY_ATTRIB,
+ YAML_PAIR_KEY_STYLE_ATTRIB,
YAML_PAIR_VALUE_ATTRIB,
- YAML_PAIR_COLLECTION_ATTRIB,
+ YAML_PAIR_VALUE_STYLE_ATTRIB,
+ YAML_PAIR_CHILDREN_ATTRIB,
{ NULL }
};
@@ -310,7 +498,9 @@ PyTypeObject *get_python_yaml_pair_type(void)
.tp_methods = py_yaml_pair_methods,
.tp_getset = py_yaml_pair_getseters,
- .tp_new = py_yaml_pair_new
+
+ .tp_init = py_yaml_pair_init,
+ .tp_new = py_yaml_pair_new,
};
@@ -321,7 +511,7 @@ PyTypeObject *get_python_yaml_pair_type(void)
/******************************************************************************
* *
-* Paramètres : module = module dont la définition est à compléter. *
+* Paramètres : - *
* *
* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlPair. *
* *
@@ -331,17 +521,27 @@ PyTypeObject *get_python_yaml_pair_type(void)
* *
******************************************************************************/
-bool register_python_yaml_pair(PyObject *module)
+bool ensure_python_yaml_pair_is_registered(void)
{
PyTypeObject *type; /* Type Python 'YamlPair' */
+ PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
type = get_python_yaml_pair_type();
- dict = PyModule_GetDict(module);
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.plugins.yaml");
+
+ dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_YAML_PAIR, type, get_python_yaml_node_type()))
- return false;
+ if (!register_class_for_pygobject(dict, G_TYPE_YAML_PAIR, type))
+ return false;
+
+ if (!define_yaml_pair_constants(type))
+ return false;
+
+ }
return true;
@@ -353,7 +553,7 @@ bool register_python_yaml_pair(PyObject *module)
* Paramètres : arg = argument quelconque à tenter de convertir. *
* dst = destination des valeurs récupérées en cas de succès. *
* *
-* Description : Tente de convertir en noeud d'arborescence de format Yaml. *
+* Description : Tente de convertir en noeud d'arborescence de format YAML. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
* *
@@ -375,7 +575,7 @@ int convert_to_yaml_pair(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml key/value pair");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YAML key/value pair");
break;
case 1:
diff --git a/plugins/yaml/python/pair.h b/plugins/yaml/python/pair.h
index 2cafab8..b03b984 100644
--- a/plugins/yaml/python/pair.h
+++ b/plugins/yaml/python/pair.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* pair.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/pair.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -35,9 +35,9 @@
PyTypeObject *get_python_yaml_pair_type(void);
/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlPair'. */
-bool register_python_yaml_pair(PyObject *);
+bool ensure_python_yaml_pair_is_registered(void);
-/* Tente de convertir en noeud d'arborescence de format Yaml. */
+/* Tente de convertir en noeud d'arborescence de format YAML. */
int convert_to_yaml_pair(PyObject *, void *);
diff --git a/plugins/yaml/python/parser.c b/plugins/yaml/python/parser.c
new file mode 100644
index 0000000..35a9090
--- /dev/null
+++ b/plugins/yaml/python/parser.c
@@ -0,0 +1,186 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser.c - équivalent Python du fichier "plugins/yaml/parser.c"
+ *
+ * Copyright (C) 2019-2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "parser.h"
+
+
+#include <pygobject.h>
+#include <string.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../parser.h"
+
+
+
+/* Crée une arborescence YAML pour contenu au format adapté. */
+static PyObject *py_yaml_parse_from_text(PyObject *, PyObject *);
+
+/* Crée une arborescence YAML pour fichier au format adapté. */
+static PyObject *py_yaml_parse_from_file(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = NULL car méthode statique. *
+* args = arguments fournis lors de l'appel à la fonction. *
+* *
+* Description : Crée une arborescence YAML pour contenu au format adapté. *
+* *
+* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_parse_from_text(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ const char *text; /* Chaîne à traiter. */
+ int ret; /* Bilan de lecture des args. */
+ GYamlNode *root; /* Noeud racine obtenu */
+
+#define YAML_PARSE_FROM_TEXT_METHOD PYTHON_METHOD_DEF \
+( \
+ parse_from_text, "text, /", \
+ METH_VARARGS, py_yaml, \
+ "Parse a YAML content in order to build the relative YAML tree.\n" \
+ "\n" \
+ "The *text* argument is a string containg a markup content to" \
+ " parse.\n" \
+ "\n" \
+ "The result is a pychrysalide.plugins.yaml.YamlNode instance" \
+ " or None in case of error." \
+)
+
+ ret = PyArg_ParseTuple(args, "s", &text);
+ if (!ret) return NULL;
+
+ root = parse_yaml_from_text(text, strlen(text));
+
+ if (root != NULL)
+ {
+ result = pygobject_new(G_OBJECT(root));
+ g_object_unref(G_OBJECT(root));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = NULL car méthode statique. *
+* args = arguments fournis lors de l'appel à la fonction. *
+* *
+* Description : Crée une arborescence YAML pour fichier au format adapté. *
+* *
+* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_parse_from_file(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ const char *filename; /* Chemin vers des définitions */
+ int ret; /* Bilan de lecture des args. */
+ GYamlNode *root; /* Noeud racine obtenu */
+
+#define YAML_PARSE_FROM_FILE_METHOD PYTHON_METHOD_DEF \
+( \
+ parse_from_file, "filename, /", \
+ METH_VARARGS, py_yaml, \
+ "Parse a YAML content in order to build the relative YAML tree.\n" \
+ "\n" \
+ "The *filename* argument is a string for a path pointing to a YAML" \
+ " content. This path can be either a real filename or a resource" \
+ " URI.\n" \
+ "\n" \
+ "The result is a pychrysalide.plugins.yaml.YamlNode instance" \
+ " or None in case of error." \
+)
+
+ ret = PyArg_ParseTuple(args, "s", &filename);
+ if (!ret) return NULL;
+
+ root = parse_yaml_from_file(filename);
+
+ if (root != NULL)
+ {
+ result = pygobject_new(G_OBJECT(root));
+ g_object_unref(G_OBJECT(root));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Définit une extension du module 'plugins.yaml' à compléter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_yaml_module_with_parsers(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *module; /* Module à recompléter */
+
+ static PyMethodDef py_yaml_methods[] = {
+ YAML_PARSE_FROM_TEXT_METHOD,
+ YAML_PARSE_FROM_FILE_METHOD,
+ { NULL }
+ };
+
+ module = get_access_to_python_module("pychrysalide.plugins.yaml");
+
+ result = register_python_module_methods(module, py_yaml_methods);
+
+ return result;
+
+}
diff --git a/plugins/yaml/python/parser.h b/plugins/yaml/python/parser.h
new file mode 100644
index 0000000..18586ab
--- /dev/null
+++ b/plugins/yaml/python/parser.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * parser.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/parser.h"
+ *
+ * Copyright (C) 2019-2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_YAML_PYTHON_PARSER_H
+#define _PLUGINS_YAML_PYTHON_PARSER_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit une extension du module 'plugins.yaml' à compléter. */
+bool populate_yaml_module_with_parsers(void);
+
+
+
+#endif /* _PLUGINS_YAML_PYTHON_PARSER_H */
diff --git a/plugins/yaml/python/reader.c b/plugins/yaml/python/reader.c
deleted file mode 100644
index f80623f..0000000
--- a/plugins/yaml/python/reader.c
+++ /dev/null
@@ -1,388 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * reader.c - équivalent Python du fichier "plugins/yaml/reader.c"
- *
- * Copyright (C) 2019 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * Chrysalide is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include "reader.h"
-
-
-#include <pygobject.h>
-
-
-#include <plugins/pychrysalide/helpers.h>
-
-
-#include "../reader.h"
-
-
-
-#define YAML_READER_DOC \
- "YamlReader is the class which aims to provide a reader interface to Yaml content.\n" \
- "\n" \
- "When no input error, the Yaml content can be retrieved line by line or thanks to a tree."
-
-
-
-/* Crée un lecteur pour contenu au format Yaml. */
-static PyObject *py_yaml_reader_new_from_content(PyObject *, PyObject *);
-
-/* Crée un lecteur pour contenu au format Yaml. */
-static PyObject *py_yaml_reader_new_from_path(PyObject *, PyObject *);
-
-/* Fournit la liste des lignes lues depuis un contenu Yaml. */
-static PyObject *py_yaml_reader_get_lines(PyObject *, void *);
-
-/* Fournit l'arborescence associée à la lecture de lignes Yaml. */
-static PyObject *py_yaml_reader_get_tree(PyObject *, void *);
-
-
-
-/******************************************************************************
-* *
-* Paramètres : self = variable non utilisée ici. *
-* args = arguments fournis à l'appel. *
-* *
-* Description : Crée un lecteur pour contenu au format Yaml. *
-* *
-* Retour : Instance mise en place ou None en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_reader_new_from_content(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Instance à retourner */
- const char *content; /* Contenu brut au format Yaml */
- int length; /* Taille de ce contenu */
- int ret; /* Bilan de lecture des args. */
- GYamlReader *reader; /* Création GLib à transmettre */
-
-#define YAML_READER_NEW_FROM_CONTENT_METHOD PYTHON_METHOD_DEF \
-( \
- new_from_content, "content", \
- METH_STATIC | METH_VARARGS, py_yaml_reader, \
- "Load a Yaml content." \
-)
-
- /**
- * La taille doit être de type 'int' et non 'Py_ssize_t', sinon les 32 bits
- * de poids fort ne sont pas initialisés !
- */
-
- ret = PyArg_ParseTuple(args, "s#", &content, &length);
- if (!ret) return NULL;
-
- reader = g_yaml_reader_new_from_content(content, length);
-
- if (reader == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
-
- else
- {
- g_object_ref_sink(G_OBJECT(reader));
- result = pygobject_new(G_OBJECT(reader));
- g_object_unref(reader);
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = variable non utilisée ici. *
-* args = arguments fournis à l'appel. *
-* *
-* Description : Crée un lecteur pour contenu au format Yaml. *
-* *
-* Retour : Instance mise en place ou None en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_reader_new_from_path(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Instance à retourner */
- const char *path; /* Chemin d'accès à un contenu */
- int ret; /* Bilan de lecture des args. */
- GYamlReader *reader; /* Création GLib à transmettre */
-
-#define YAML_READER_NEW_FROM_PATH_METHOD PYTHON_METHOD_DEF \
-( \
- new_from_path, "path", \
- METH_STATIC | METH_VARARGS, py_yaml_reader, \
- "Load a Yaml content from a path.\n" \
- "\n" \
- "The path can be a filename or a resource URI." \
-)
-
- ret = PyArg_ParseTuple(args, "s", &path);
- if (!ret) return NULL;
-
- reader = g_yaml_reader_new_from_path(path);
-
- if (reader == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
-
- else
- {
- g_object_ref_sink(G_OBJECT(reader));
- result = pygobject_new(G_OBJECT(reader));
- g_object_unref(reader);
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
-* *
-* Description : Fournit la liste des lignes lues depuis un contenu Yaml. *
-* *
-* Retour : Liste de lignes correspondant au contenu Yaml lu. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_reader_get_lines(PyObject *self, void *closure)
-{
- PyObject *result; /* Résultat à retourner */
- GYamlReader *reader; /* Version GLib du type */
- size_t count; /* Quantité de lignes à traiter*/
- GYamlLine **lines; /* Liste de lignes lues */
- size_t i; /* Boucle de parcours */
-#ifndef NDEBUG
- int ret; /* Bilan d'une insertion */
-#endif
-
-#define YAML_READER_LINES_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- lines, py_yaml_reader, \
- "List of Yaml lines processed by the reader." \
-)
-
- reader = G_YAML_READER(pygobject_get(self));
-
- lines = g_yaml_reader_get_lines(reader, &count);
-
- result = PyTuple_New(count);
-
- for (i = 0; i < count; i++)
- {
-#ifndef NDEBUG
- ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(lines[i])));
- assert(ret == 0);
-#else
- PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(lines[i])));
-#endif
-
- g_object_unref(G_OBJECT(lines[i]));
-
- }
-
- if (lines != NULL)
- free(lines);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
-* *
-* Description : Fournit l'arborescence associée à la lecture de lignes Yaml. *
-* *
-* Retour : Arborescence constituée par la lecture du contenu Yaml. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_reader_get_tree(PyObject *self, void *closure)
-{
- PyObject *result; /* Résultat à retourner */
- GYamlReader *reader; /* Version GLib du type */
- GYamlTree *tree; /* Arborescence associée */
-
-#define YAML_READER_TREE_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- tree, py_yaml_reader, \
- "Tree of all nodes built from the Yaml content." \
-)
-
- reader = G_YAML_READER(pygobject_get(self));
-
- tree = g_yaml_reader_get_tree(reader);
-
- if (tree == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
- else
- {
- result = pygobject_new(G_OBJECT(tree));
- g_object_unref(G_OBJECT(tree));
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Fournit un accès à une définition de type à diffuser. *
-* *
-* Retour : Définition d'objet pour Python. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-PyTypeObject *get_python_yaml_reader_type(void)
-{
- static PyMethodDef py_yaml_reader_methods[] = {
- YAML_READER_NEW_FROM_CONTENT_METHOD,
- YAML_READER_NEW_FROM_PATH_METHOD,
- { NULL }
- };
-
- static PyGetSetDef py_yaml_reader_getseters[] = {
- YAML_READER_LINES_ATTRIB,
- YAML_READER_TREE_ATTRIB,
- { NULL }
- };
-
- static PyTypeObject py_yaml_reader_type = {
-
- PyVarObject_HEAD_INIT(NULL, 0)
-
- .tp_name = "pychrysalide.plugins.yaml.YamlReader",
- .tp_basicsize = sizeof(PyGObject),
-
- .tp_flags = Py_TPFLAGS_DEFAULT,
-
- .tp_doc = YAML_READER_DOC,
-
- .tp_methods = py_yaml_reader_methods,
- .tp_getset = py_yaml_reader_getseters,
- .tp_new = no_python_constructor_allowed
-
- };
-
- return &py_yaml_reader_type;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : module = module dont la définition est à compléter. *
-* *
-* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlReader.*
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool register_python_yaml_reader(PyObject *module)
-{
- PyTypeObject *type; /* Type Python 'YamlReader' */
- PyObject *dict; /* Dictionnaire du module */
-
- type = get_python_yaml_reader_type();
-
- dict = PyModule_GetDict(module);
-
- if (!register_class_for_pygobject(dict, G_TYPE_YAML_READER, type, &PyGObject_Type))
- return false;
-
- return true;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : arg = argument quelconque à tenter de convertir. *
-* dst = destination des valeurs récupérées en cas de succès. *
-* *
-* Description : Tente de convertir en lecteur de données au format Yaml. *
-* *
-* Retour : Bilan de l'opération, voire indications supplémentaires. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-int convert_to_yaml_reader(PyObject *arg, void *dst)
-{
- int result; /* Bilan à retourner */
-
- result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_reader_type());
-
- switch (result)
- {
- case -1:
- /* L'exception est déjà fixée par Python */
- result = 0;
- break;
-
- case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml reader");
- break;
-
- case 1:
- *((GYamlReader **)dst) = G_YAML_READER(pygobject_get(arg));
- break;
-
- default:
- assert(false);
- break;
-
- }
-
- return result;
-
-}
diff --git a/plugins/yaml/python/tree.c b/plugins/yaml/python/tree.c
deleted file mode 100644
index 7d28254..0000000
--- a/plugins/yaml/python/tree.c
+++ /dev/null
@@ -1,427 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * tree.c - équivalent Python du fichier "plugins/yaml/tree.c"
- *
- * Copyright (C) 2019-2020 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * Chrysalide is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include "tree.h"
-
-
-#include <pygobject.h>
-
-
-#include <i18n.h>
-#include <plugins/pychrysalide/helpers.h>
-
-
-#include "line.h"
-#include "../tree.h"
-
-
-
-/* Crée un nouvel objet Python de type 'YamlTree'. */
-static PyObject *py_yaml_tree_new(PyTypeObject *, PyObject *, PyObject *);
-
-/* Recherche les noeuds correspondant à un chemin. */
-static PyObject *py_yaml_tree_find_by_path(PyObject *, PyObject *);
-
-/* Fournit le noeud constituant la racine d'arborescence Yaml. */
-static PyObject *py_yaml_tree_get_root(PyObject *, void *);
-
-
-
-/******************************************************************************
-* *
-* Paramètres : type = type de l'objet à instancier. *
-* args = arguments fournis à l'appel. *
-* kwds = arguments de type key=val fournis. *
-* *
-* Description : Crée un nouvel objet Python de type 'YamlTree'. *
-* *
-* Retour : Instance Python mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *result; /* Instance à retourner */
- PyObject *tuple; /* Liste de lignes Yaml */
- int ret; /* Bilan de lecture des args. */
- size_t count; /* Nombre d'éléments présents */
- GYamlLine **lines; /* Lignes au format Yaml */
- GYamlTree *tree; /* Création GLib à transmettre */
- size_t i; /* Boucle de parcours #1 */
- PyObject *item; /* Elément de la liste fournie */
- size_t k; /* Boucle de parcours #2 */
-
-#define YAML_TREE_DOC \
- "YamlTree offers a hierarchical access to Yaml lines as a tree.\n" \
- "\n" \
- "Instances can be created using the following constructor:\n" \
- "\n" \
- " YamlTree(lines)" \
- "\n" \
- "Where lines are a tuple of Yaml lines used to built the tree."
-
- ret = PyArg_ParseTuple(args, "O!", &PyTuple_Type, &tuple);
- if (!ret) return NULL;
-
- count = PyTuple_Size(tuple);
-
- lines = (GYamlLine **)malloc(count * sizeof(GYamlLine *));
-
- tree = NULL;
-
- for (i = 0; i < count; i++)
- {
- item = PyTuple_GetItem(tuple, i);
-
- ret = convert_to_yaml_line(item, &lines[i]);
-
- if (ret == 0)
- g_object_ref(G_OBJECT(lines[i]));
-
- else
- goto arg_error;
-
- }
-
- tree = g_yaml_tree_new(lines, count);
-
- arg_error:
-
- for (k = 0; k < i; k++)
- g_object_unref(G_OBJECT(lines[i]));
-
- free(lines);
-
- /* S'il y a eu une erreur... */
- if (i < count) return NULL;
-
- if (tree == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
-
- else
- {
- g_object_ref_sink(G_OBJECT(tree));
- result = pygobject_new(G_OBJECT(tree));
- g_object_unref(tree);
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = variable non utilisée ici. *
-* args = arguments fournis à l'appel. *
-* *
-* Description : Recherche les noeuds correspondant à un chemin. *
-* *
-* Retour : Liste de noeuds trouvés, éventuellement vide. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_tree_find_by_path(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Instance à retourner */
- int prepare; /* Orientation des résultats */
- const char *path; /* Chemin d'accès à traiter */
- int ret; /* Bilan de lecture des args. */
- GYamlTree *tree; /* Version GLib du type */
- GYamlNode **found; /* Créations GLib à transmettre*/
- size_t count; /* Quantité de trouvailles */
- size_t i; /* Boucle de parcours */
-
-#define YAML_TREE_FIND_BY_PATH_METHOD PYTHON_METHOD_DEF \
-( \
- find_by_path, "path, /, prepare=False", \
- METH_VARARGS, py_yaml_tree, \
- "Find nodes in a Yaml tree using a path.\n" \
- "\n" \
- "Paths are node keys separated by '/', such as '/my/path/to/node'." \
- "\n" \
- "In case where the path ends with a trailing '/', the operation can" \
- " be used to prepare a further look by returning a node which can be" \
- " searched by a new call to this function instead of returning all its" \
- " contained nodes." \
-)
-
- prepare = 0;
-
- ret = PyArg_ParseTuple(args, "s|p", &path, &prepare);
- if (!ret) return NULL;
-
- tree = G_YAML_TREE(pygobject_get(self));
-
- g_yaml_tree_find_by_path(tree, path, prepare, &found, &count);
-
- result = PyTuple_New(count);
-
- for (i = 0; i < count; i++)
- {
-#ifndef NDEBUG
- ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
- assert(ret == 0);
-#else
- PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
-#endif
-
- g_object_unref(G_OBJECT(found[i]));
-
- }
-
- if (found != NULL)
- free(found);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = variable non utilisée ici. *
-* args = arguments fournis à l'appel. *
-* *
-* Description : Recherche l'unique noeud correspondant à un chemin. *
-* *
-* Retour : Noeud avec correspondance établie ou None. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_tree_find_one_by_path(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Instance à retourner */
- int prepare; /* Orientation des résultats */
- const char *path; /* Chemin d'accès à traiter */
- int ret; /* Bilan de lecture des args. */
- GYamlTree *tree; /* Version GLib du type */
- GYamlNode *found; /* Création GLib à transmettre */
-
-#define YAML_TREE_FIND_ONE_BY_PATH_METHOD PYTHON_METHOD_DEF \
-( \
- find_one_by_path, "path, /, prepare=False", \
- METH_VARARGS, py_yaml_tree, \
- "Find a given node from a Yaml node using a path.\n" \
- "\n" \
- "Paths are node keys separated by '/', such as '/my/path/to/node'." \
- "\n" \
- "Only one node has to match the path for the function success." \
- "\n" \
- "In case where the path ends with a trailing '/', the operation can" \
- " be used to prepare a further look by returning a node which can be" \
- " searched by a new call to this function instead of returning all its" \
- " contained nodes." \
-)
-
- prepare = 0;
-
- ret = PyArg_ParseTuple(args, "s|p", &path, &prepare);
- if (!ret) return NULL;
-
- tree = G_YAML_TREE(pygobject_get(self));
-
- found = g_yaml_tree_find_one_by_path(tree, path, prepare);
-
- if (found == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
- else
- {
- result = pygobject_new(G_OBJECT(found));
- g_object_unref(G_OBJECT(found));
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
-* *
-* Description : Fournit le noeud constituant la racine d'arborescence Yaml. *
-* *
-* Retour : Noeud constituant la racine de l'arborescence. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_yaml_tree_get_root(PyObject *self, void *closure)
-{
- PyObject *result; /* Résultat à retourner */
- GYamlTree *tree; /* Version GLib du type */
- GYamlNode *root; /* Noeud racine d'arborescence */
-
-#define YAML_TREE_ROOT_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- root, py_yaml_tree, \
- "Yaml node which is the root of the whole tree nodes." \
-)
-
- tree = G_YAML_TREE(pygobject_get(self));
-
- root = g_yaml_tree_get_root(tree);
-
- result = pygobject_new(G_OBJECT(root));
- g_object_unref(G_OBJECT(root));
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Fournit un accès à une définition de type à diffuser. *
-* *
-* Retour : Définition d'objet pour Python. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-PyTypeObject *get_python_yaml_tree_type(void)
-{
- static PyMethodDef py_yaml_tree_methods[] = {
- YAML_TREE_FIND_BY_PATH_METHOD,
- YAML_TREE_FIND_ONE_BY_PATH_METHOD,
- { NULL }
- };
-
- static PyGetSetDef py_yaml_tree_getseters[] = {
- YAML_TREE_ROOT_ATTRIB,
- { NULL }
- };
-
- static PyTypeObject py_yaml_tree_type = {
-
- PyVarObject_HEAD_INIT(NULL, 0)
-
- .tp_name = "pychrysalide.plugins.yaml.YamlTree",
- .tp_basicsize = sizeof(PyGObject),
-
- .tp_flags = Py_TPFLAGS_DEFAULT,
-
- .tp_doc = YAML_TREE_DOC,
-
- .tp_methods = py_yaml_tree_methods,
- .tp_getset = py_yaml_tree_getseters,
- .tp_new = py_yaml_tree_new
-
- };
-
- return &py_yaml_tree_type;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : module = module dont la définition est à compléter. *
-* *
-* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlTree. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool register_python_yaml_tree(PyObject *module)
-{
- PyTypeObject *type; /* Type Python 'YamlTree' */
- PyObject *dict; /* Dictionnaire du module */
-
- type = get_python_yaml_tree_type();
-
- dict = PyModule_GetDict(module);
-
- if (!register_class_for_pygobject(dict, G_TYPE_YAML_TREE, type, &PyGObject_Type))
- return false;
-
- return true;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : arg = argument quelconque à tenter de convertir. *
-* dst = destination des valeurs récupérées en cas de succès. *
-* *
-* Description : Tente de convertir en arborescence de lignes au format Yaml. *
-* *
-* Retour : Bilan de l'opération, voire indications supplémentaires. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-int convert_to_yaml_tree(PyObject *arg, void *dst)
-{
- int result; /* Bilan à retourner */
-
- result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_tree_type());
-
- switch (result)
- {
- case -1:
- /* L'exception est déjà fixée par Python */
- result = 0;
- break;
-
- case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml tree");
- break;
-
- case 1:
- *((GYamlTree **)dst) = G_YAML_TREE(pygobject_get(arg));
- break;
-
- default:
- assert(false);
- break;
-
- }
-
- return result;
-
-}
diff --git a/plugins/yaml/reader.h b/plugins/yaml/reader.h
deleted file mode 100644
index 3e5ce48..0000000
--- a/plugins/yaml/reader.h
+++ /dev/null
@@ -1,69 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * reader.h - prototypes pour le lecteur de contenu Yaml
- *
- * Copyright (C) 2019 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * Chrysalide is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef PLUGINS_YAML_READER_H
-#define PLUGINS_YAML_READER_H
-
-
-#include <glib-object.h>
-#include <stdbool.h>
-
-
-#include "line.h"
-#include "tree.h"
-
-
-
-#define G_TYPE_YAML_READER g_yaml_reader_get_type()
-#define G_YAML_READER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_READER, GYamlReader))
-#define G_IS_YAML_READER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_READER))
-#define G_YAML_READER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_READER, GYamlReaderClass))
-#define G_IS_YAML_READER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_READER))
-#define G_YAML_READER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_READER, GYamlReaderClass))
-
-
-/* Lecteur de contenu Yaml (instance) */
-typedef struct _GYamlReader GYamlReader;
-
-/* Lecteur de contenu Yaml (classe) */
-typedef struct _GYamlReaderClass GYamlReaderClass;
-
-
-/* Indique le type défini pour un lecteur de contenu Yaml. */
-GType g_yaml_reader_get_type(void);
-
-/* Crée un lecteur pour contenu au format Yaml. */
-GYamlReader *g_yaml_reader_new_from_content(const char *, size_t);
-
-/* Crée un lecteur pour contenu au format Yaml. */
-GYamlReader *g_yaml_reader_new_from_path(const char *);
-
-/* Fournit la liste des lignes lues depuis un contenu Yaml. */
-GYamlLine **g_yaml_reader_get_lines(const GYamlReader *, size_t *);
-
-/* Fournit l'arborescence associée à la lecture de lignes Yaml. */
-GYamlTree *g_yaml_reader_get_tree(const GYamlReader *);
-
-
-
-#endif /* PLUGINS_YAML_READER_H */
diff --git a/plugins/yaml/scalar.h b/plugins/yaml/scalar.h
deleted file mode 100644
index 5403e85..0000000
--- a/plugins/yaml/scalar.h
+++ /dev/null
@@ -1,72 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * scalar.h - prototypes pour un noeud Yaml de type "scalar"
- *
- * Copyright (C) 2019 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * Chrysalide is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef PLUGINS_YAML_SCALAR_H
-#define PLUGINS_YAML_SCALAR_H
-
-
-#include <glib-object.h>
-#include <stdbool.h>
-
-
-#include "line.h"
-#include "node.h"
-
-
-/* Depuis collection.h : collection de noeuds au format Yaml (instance) */
-typedef struct _GYamlCollection GYamlCollection;
-
-
-#define G_TYPE_YAML_SCALAR g_yaml_scalar_get_type()
-#define G_YAML_SCALAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_SCALAR, GYamlScalar))
-#define G_IS_YAML_SCALAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_SCALAR))
-#define G_YAML_SCALAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_SCALAR, GYamlScalarClass))
-#define G_IS_YAML_SCALAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_SCALAR))
-#define G_YAML_SCALAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_SCALAR, GYamlScalarClass))
-
-
-/* Noeud d'une arborescence au format Yaml (instance) */
-typedef struct _GYamlScalar GYamlScalar;
-
-/* Noeud d'une arborescence au format Yaml (classe) */
-typedef struct _GYamlScalarClass GYamlScalarClass;
-
-
-/* Indique le type défini pour un noeud d'arborescence Yaml. */
-GType g_yaml_scalar_get_type(void);
-
-/* Construit un noeud d'arborescence Yaml. */
-GYamlScalar *g_yaml_scalar_new(GYamlLine *);
-
-/* Fournit la ligne principale associée à un noeud. */
-GYamlLine *g_yaml_scalar_get_yaml_line(const GYamlScalar *);
-
-/* Attache une collection de noeuds Yaml à un noeud. */
-void g_yaml_scalar_set_collection(GYamlScalar *, GYamlCollection *);
-
-/* Fournit une éventuelle collection rattachée à un noeud. */
-GYamlCollection *g_yaml_scalar_get_collection(const GYamlScalar *);
-
-
-
-#endif /* PLUGINS_YAML_SCALAR_H */
diff --git a/plugins/yaml/tree.c b/plugins/yaml/tree.c
deleted file mode 100644
index 9125302..0000000
--- a/plugins/yaml/tree.c
+++ /dev/null
@@ -1,421 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * tree.c - ligne de contenu Yaml
- *
- * Copyright (C) 2019-2020 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * Chrysalide is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "tree.h"
-
-
-#include <assert.h>
-#include <malloc.h>
-#include <string.h>
-
-
-#include <i18n.h>
-#include <core/logs.h>
-
-
-#include "pair.h"
-#include "collection.h"
-
-
-
-/* Arborescence de lignes au format Yaml (instance) */
-struct _GYamlTree
-{
- GObject parent; /* A laisser en premier */
-
- GYamlNode *root; /* Racine des noeuds */
-
-};
-
-/* Arborescence de lignes au format Yaml (classe) */
-struct _GYamlTreeClass
-{
- GObjectClass parent; /* A laisser en premier */
-
-};
-
-
-/* Initialise la classe des arborescence de lignes Yaml. */
-static void g_yaml_tree_class_init(GYamlTreeClass *);
-
-/* Initialise une instance d'arborescence de lignes Yaml. */
-static void g_yaml_tree_init(GYamlTree *);
-
-/* Supprime toutes les références externes. */
-static void g_yaml_tree_dispose(GYamlTree *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_yaml_tree_finalize(GYamlTree *);
-
-/* Construit une collection de noeuds avec une arborescence. */
-static bool g_yaml_tree_build_node(GYamlCollection *, GYamlLine **, size_t, size_t, size_t *);
-
-
-
-/* Indique le type défini pour une arborescence de lignes au format Yaml. */
-G_DEFINE_TYPE(GYamlTree, g_yaml_tree, G_TYPE_OBJECT);
-
-
-/******************************************************************************
-* *
-* Paramètres : klass = classe à initialiser. *
-* *
-* Description : Initialise la classe des arborescence de lignes Yaml. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_yaml_tree_class_init(GYamlTreeClass *klass)
-{
- GObjectClass *object; /* Autre version de la classe */
-
- object = G_OBJECT_CLASS(klass);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_tree_dispose;
- object->finalize = (GObjectFinalizeFunc)g_yaml_tree_finalize;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : tree = instance à initialiser. *
-* *
-* Description : Initialise une instance d'arborescence de lignes Yaml. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_yaml_tree_init(GYamlTree *tree)
-{
- tree->root = NULL;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : tree = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_yaml_tree_dispose(GYamlTree *tree)
-{
- g_clear_object(&tree->root);
-
- G_OBJECT_CLASS(g_yaml_tree_parent_class)->dispose(G_OBJECT(tree));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : tree = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_yaml_tree_finalize(GYamlTree *tree)
-{
- G_OBJECT_CLASS(g_yaml_tree_parent_class)->finalize(G_OBJECT(tree));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
-* count = taille de cet ensemble de lignes. *
-* *
-* Description : Construit une arborescence à partir de lignes Yaml. *
-* *
-* Retour : Instance mise en place ou NULL en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GYamlTree *g_yaml_tree_new(GYamlLine **lines, size_t count)
-{
- GYamlTree *result; /* Structure à retourner */
- GYamlCollection *collec; /* Collection de noeuds */
- size_t indent; /* Indentation initiale */
- size_t processed; /* Quantité de noeuds traités */
- bool status; /* Bilan de construction */
-
- result = g_object_new(G_TYPE_YAML_TREE, NULL);
-
- if (count > 0)
- {
- collec = g_yaml_collection_new(g_yaml_line_is_list_item(lines[0]));
-
- result->root = G_YAML_NODE(collec);
-
- indent = g_yaml_line_count_indent(lines[0]);
- processed = 0;
-
- status = g_yaml_tree_build_node(collec, lines, count, indent, &processed);
-
- if (status)
- assert(processed == count);
-
- else
- {
- g_object_unref(G_OBJECT(result));
- result = NULL;
- }
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
-* count = taille de cet ensemble de lignes. *
-* expected = niveau d'identation attendu. *
-* cur = position courante dans les lignes. [OUT] *
-* *
-* Description : Construit une collection de noeuds avec une arborescence. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool g_yaml_tree_build_node(GYamlCollection *collec, GYamlLine **lines, size_t count, size_t expected, size_t *cur)
-{
- bool result; /* Bilan à retourner */
- bool first; /* Marque d'un premier élément */
- GYamlNode *last; /* Mémorisation du dernier */
- GYamlLine *line; /* Ligne de parcours courante */
- size_t indent; /* Indentation de ligne */
- bool is_item; /* Elément d'une liste ? */
- GYamlCollection *sub; /* Nouvelle sous-collection */
-
- result = true;
-
- first = true;
- last = NULL;
-
- for (; *cur < count; )
- {
- line = lines[*cur];
-
- indent = g_yaml_line_count_indent(line);
- is_item = g_yaml_line_is_list_item(line);
-
- /**
- * Si la première ligne traitée commence par un élément de liste,
- * alors un appel parent a constitué une collection qui n'est pas une séquence.
- *
- * L'objectif est de créer une simple association de 'clefs: valeurs'.
- *
- * Si la collection n'est pas adaptée, alors le parcours n'est pas encore
- * arrivé à ce stade de construction.
- */
- if (first && is_item && !g_yaml_collection_is_sequence(collec))
- {
- indent += 2; /* 2 == strlen("- ") */
- is_item = false;
- }
-
- first = false;
-
- /* Fin de l'ensemble courant */
- if (indent < expected)
- goto done;
-
- /* Début d'un sous-ensemble */
- else if (indent > expected)
- {
- if (last == NULL)
- {
- result = false;
- goto done;
- }
-
- sub = g_yaml_collection_new(is_item);
- g_yaml_pair_set_collection(G_YAML_PAIR(last), sub);
-
- result = g_yaml_tree_build_node(sub, lines, count, indent, cur);
- if (!result) goto done;
-
- }
-
- /* Elément de même niveau */
- else
- {
- if (is_item)
- {
- /* Vérification de cohérence */
- if (!g_yaml_collection_is_sequence(collec))
- {
- log_variadic_message(LMT_BAD_BINARY, _("A list item was expected at line %zu"),
- g_yaml_line_get_number(line));
-
- result = false;
- goto done;
-
- }
-
- sub = g_yaml_collection_new(false);
- g_yaml_collection_add_node(collec, G_YAML_NODE(sub));
-
- result = g_yaml_tree_build_node(sub, lines, count, expected + 2 /* 2 == strlen("- ") */, cur);
- if (!result) goto done;
-
- }
-
- else
- {
- /* Vérification de cohérence */
- if (g_yaml_collection_is_sequence(collec))
- {
- log_variadic_message(LMT_BAD_BINARY, _("A mapping item was expected at line %zu"),
- g_yaml_line_get_number(line));
-
-
- result = false;
- goto done;
-
- }
-
- last = G_YAML_NODE(g_yaml_pair_new(line));
-
- if (last == NULL)
- {
- result = false;
- goto done;
- }
-
- g_yaml_collection_add_node(collec, last);
-
- (*cur)++;
-
- }
-
- }
-
- }
-
- done:
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : tree = ligne au format Yaml à consulter. *
-* *
-* Description : Fournit le noeud constituant la racine d'arborescence Yaml. *
-* *
-* Retour : Noeud constituant la racine de l'arborescence. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GYamlNode *g_yaml_tree_get_root(const GYamlTree *tree)
-{
- GYamlNode *result; /* Liste à retourner */
-
- result = tree->root;
-
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : tree = ligne au format Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* nodes = liste de noeuds avec correspondance établie. [OUT] *
-* count = quantité de ces noeuds. [OUT] *
-* *
-* Description : Recherche les noeuds correspondant à un chemin. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_yaml_tree_find_by_path(const GYamlTree *tree, const char *path, bool prepare, GYamlNode ***nodes, size_t *count)
-{
- g_yaml_node_find_by_path(tree->root, path, prepare, nodes, count);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : tree = ligne au format Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
-* prepare = indication sur une préparation d'un prochain appel.*
-* *
-* Description : Recherche l'unique noeud correspondant à un chemin. *
-* *
-* Retour : Noeud avec correspondance établie ou NULL. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GYamlNode *g_yaml_tree_find_one_by_path(GYamlTree *tree, const char *path, bool prepare)
-{
- GYamlNode *result; /* Trouvaille unique à renvoyer*/
-
- result = g_yaml_node_find_one_by_path(tree->root, path, prepare);
-
- return result;
-
-}
diff --git a/plugins/yaml/tree.h b/plugins/yaml/tree.h
deleted file mode 100644
index bfe034a..0000000
--- a/plugins/yaml/tree.h
+++ /dev/null
@@ -1,69 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * tree.h - prototypes pour une ligne de contenu Yaml
- *
- * Copyright (C) 2019 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * Chrysalide is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef PLUGINS_YAML_TREE_H
-#define PLUGINS_YAML_TREE_H
-
-
-#include <glib-object.h>
-#include <stdbool.h>
-
-
-#include "line.h"
-#include "node.h"
-
-
-
-#define G_TYPE_YAML_TREE g_yaml_tree_get_type()
-#define G_YAML_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_TREE, GYamlTree))
-#define G_IS_YAML_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_TREE))
-#define G_YAML_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_TREE, GYamlTreeClass))
-#define G_IS_YAML_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_TREE))
-#define G_YAML_TREE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_TREE, GYamlTreeClass))
-
-
-/* Arborescence de lignes au format Yaml (instance) */
-typedef struct _GYamlTree GYamlTree;
-
-/* Arborescence de lignes au format Yaml (classe) */
-typedef struct _GYamlTreeClass GYamlTreeClass;
-
-
-/* Indique le type défini pour une arborescence de lignes au format Yaml. */
-GType g_yaml_tree_get_type(void);
-
-/* Construit une arborescence à partir de lignes Yaml. */
-GYamlTree *g_yaml_tree_new(GYamlLine **, size_t);
-
-/* Fournit le noeud constituant la racine d'arborescence Yaml. */
-GYamlNode *g_yaml_tree_get_root(const GYamlTree *);
-
-/* Recherche les noeuds correspondant à un chemin. */
-void g_yaml_tree_find_by_path(const GYamlTree *, const char *, bool, GYamlNode ***, size_t *);
-
-/* Recherche l'unique noeud correspondant à un chemin. */
-GYamlNode *g_yaml_tree_find_one_by_path(GYamlTree *, const char *, bool);
-
-
-
-#endif /* PLUGINS_YAML_TREE_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 321b472..9dc053e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,10 @@
lib_LTLIBRARIES = libchrysacore.la
-bin_PROGRAMS = chrysalide chrysalide-hub
+bin_PROGRAMS = chrysalide chrysalide-hub rost
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/intl
@@ -17,28 +20,58 @@ GOBJECT_LEAKS_SOURCES = gleak.h gleak.c
endif
-libchrysacore_la_SOURCES = \
- $(GOBJECT_LEAKS_SOURCES)
+libchrysacore_la_SOURCES =
+
+if BUILD_GTK_SUPPORT
+
+GTKEXT_LIBADD = \
+ gtkext/libgtkext.la
+
+GTKEXT_SUBDIR = \
+ gtkext
+
+GUI_LIBADD = \
+ gui/libgui.la
+
+GUI_SUBDIR = \
+ gui
+
+endif
+
+
+libchrysacore_la_LIBADD = \
+ analysis/libanalysis.la \
+ arch/libarch.la \
+ common/libcommon.la \
+ core/libcore.la \
+ debug/libdebug.la \
+ format/libformat.la \
+ glibext/libglibext.la \
+ $(GTKEXT_LIBADD) \
+ $(GUI_LIBADD) \
+ mangling/libmangling.la \
+ plugins/libplugins.la
+
# -ldl: dladdr(), dlerror()
+# -lm : pow()
libchrysacore_la_LDFLAGS = \
- -avoid-version -ldl \
- $(LIBGTK_LIBS) $(LIBXML_LIBS) \
+ -avoid-version -ldl -lm \
+ $(TOOLKIT_LIBS) $(LIBXML_LIBS) \
$(LIBSQLITE_LIBS) $(LIBARCHIVE_LIBS) \
- $(LIBCURL_LIBS)
-
-libchrysacore_la_LIBADD = \
- analysis/libanalysis.la \
- arch/libarch.la \
- common/libcommon.la \
- core/libcore.la \
- debug/libdebug.la \
- format/libformat.la \
- glibext/libglibext.la \
- gtkext/libgtkext.la \
- gui/libgui.la \
- mangling/libmangling.la \
- plugins/libplugins.la
+ $(LIBSSL_LIBS) $(LIBHS_LIBS)
+
+if BUILD_CURL_SUPPORT
+
+libchrysacore_la_LDFLAGS += $(LIBCURL_LIBS)
+
+endif
+
+if BUILD_MAGIC_SUPPORT
+
+libchrysacore_la_LDFLAGS += $(LIBMAGIC_LIBS)
+
+endif
@@ -46,21 +79,18 @@ libchrysacore_la_LIBADD = \
# Programme principal
############################################################
-EXTRA_chrysalide_DEPENDENCIES = $(lib_LTLIBRARIES)
+EXTRA_chrysalide_DEPENDENCIES = libchrysacore.la
chrysalide_SOURCES = \
+ $(GOBJECT_LEAKS_SOURCES) \
main.c
-AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/intl $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) `pkg-config --cflags gthread-2.0` $(LIBPYTHON_CFLAGS)
+chrysalide_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS)
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
-chrysalide_LDFLAGS = $(LIBGTK_LIBS) -L/usr/X11R6/lib -ldl -lm $(LIBXML_LIBS) `pkg-config --libs gthread-2.0` $(LIBPYTHON_LIBS) $(LIBARCHIVE_LIBS) $(LIBSQLITE_LIBS) \
+chrysalide_LDFLAGS = $(TOOLKIT_LIBS) -L/usr/X11R6/lib -ldl -lm $(LIBXML_LIBS) $(LIBPYTHON_LIBS) $(LIBARCHIVE_LIBS) $(LIBSQLITE_LIBS) \
-L.libs -lchrysacore
-
chrysalide_LDADD = $(LIBINTL)
@@ -69,13 +99,31 @@ chrysalide_LDADD = $(LIBINTL)
# Gestionnaire de serveurs distants
############################################################
-EXTRA_chrysalide_hub_DEPENDENCIES = $(lib_LTLIBRARIES)
+EXTRA_chrysalide_hub_DEPENDENCIES = libchrysacore.la
chrysalide_hub_SOURCES = \
+ $(GOBJECT_LEAKS_SOURCES) \
hub.c
+chrysalide_hub_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+
+chrysalide_hub_LDFLAGS = $(TOOLKIT_LIBS) $(LIBXML_LIBS) -L.libs -lchrysacore
+
+
+
+############################################################
+# Détecteur de motifs
+############################################################
+
+EXTRA_rost_DEPENDENCIES = libchrysacore.la
+
+rost_SOURCES = \
+ $(GOBJECT_LEAKS_SOURCES) \
+ rost.c
+
+rost_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
-chrysalide_hub_LDFLAGS = $(LIBGTK_LIBS) -L.libs -lchrysacore
+rost_LDFLAGS = $(LIBGOBJ_LIBS) -L.libs -lchrysacore
@@ -85,4 +133,4 @@ chrysalide_hub_LDFLAGS = $(LIBGTK_LIBS) -L.libs -lchrysacore
# glibext doit être traité en premier, à cause des marshals GLib
-SUBDIRS = core glibext gtkext analysis arch format common debug gui mangling plugins
+SUBDIRS = core glibext $(GTKEXT_SUBDIR) analysis arch format common debug $(GUI_SUBDIR) mangling plugins
diff --git a/src/analysis/Makefile.am b/src/analysis/Makefile.am
index 1dd83cb..909ced9 100644
--- a/src/analysis/Makefile.am
+++ b/src/analysis/Makefile.am
@@ -18,24 +18,21 @@ libanalysis_la_SOURCES = \
type.h type.c \
variable.h variable.c
+libanalysis_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+
libanalysis_la_LIBADD = \
contents/libanalysiscontents.la \
db/libanalysisdb.la \
disass/libanalysisdisass.la \
human/libanalysishuman.la \
+ scan/libanalysisscan.la \
storage/libanalysisstorage.la \
types/libanalysistypes.la
-libanalysis_la_LDFLAGS =
-
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysis_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS = contents db disass human storage types
+SUBDIRS = contents db disass human scan storage types
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 41f148a..f8b17d2 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -43,17 +43,21 @@
#include "../common/cpp.h"
#include "../common/xdg.h"
#include "../core/collections.h"
+#include "../core/columns.h"
#include "../core/logs.h"
#include "../core/params.h"
#include "../core/processors.h"
#include "../format/known.h"
#include "../glibext/gbinarycursor.h"
-#include "../glibext/gloadedpanel.h"
-#include "../gtkext/easygtk.h"
-#include "../gtkext/gtkblockdisplay.h"
-#include "../gtkext/gtkdisplaypanel.h"
-#include "../gtkext/gtkgraphdisplay.h"
-#include "../gtkext/hexdisplay.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../glibext/gloadedpanel.h"
+# include "../gtkext/easygtk.h"
+# include "../gtkext/gtkblockdisplay.h"
+# include "../gtkext/gtkdisplaypanel.h"
+# include "../gtkext/gtkgraphdisplay.h"
+# include "../gtkext/gtkstatusstack.h"
+# include "../gtkext/hexdisplay.h"
+#endif
@@ -168,6 +172,8 @@ static void on_binary_processor_changed(GArchProcessor *, GArchInstruction *, gb
/* Fournit le désignation associée à l'élément chargé. */
static char *g_loaded_binary_describe(const GLoadedBinary *, bool);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Détermine le nombre de vues disponibles pour un contenu. */
static unsigned int g_loaded_binary_count_views(const GLoadedBinary *);
@@ -186,6 +192,8 @@ static unsigned int g_loaded_binary_get_view_index(GLoadedBinary *, GtkWidget *)
/* Fournit toutes les options d'affichage pour un contenu. */
static GDisplayOptions *g_loaded_binary_get_display_options(const GLoadedBinary *, unsigned int);
+#endif
+
/* ---------------------------------------------------------------------------------- */
@@ -231,6 +239,8 @@ static void g_loaded_binary_class_init(GLoadedBinaryClass *klass)
loaded->describe = (describe_loaded_fc)g_loaded_binary_describe;
+#ifdef INCLUDE_GTK_SUPPORT
+
loaded->count_views = (count_loaded_views_fc)g_loaded_binary_count_views;
loaded->get_view_name = (get_loaded_view_name_fc)g_loaded_binary_get_view_name;
loaded->build_def_view = (build_loaded_def_view_fc)g_loaded_binary_build_default_view;
@@ -239,6 +249,8 @@ static void g_loaded_binary_class_init(GLoadedBinaryClass *klass)
loaded->get_options = (get_loaded_options_fc)g_loaded_binary_get_display_options;
+#endif
+
}
@@ -1466,7 +1478,9 @@ static bool g_loaded_binary_analyze(GLoadedBinary *binary, bool connect, bool ca
char *desc; /* Description humaine associée*/
bool has_virt; /* Présence de virtuel ? */
GProcContext *context; /* Contexte de suivi dédié */
+#ifdef INCLUDE_GTK_SUPPORT
GWidthTracker *tracker; /* Gestionnaire de largeur */
+#endif
/* Interprétation du format associé */
@@ -1512,12 +1526,16 @@ static bool g_loaded_binary_analyze(GLoadedBinary *binary, bool connect, bool ca
{
output_disassembly(binary, context, status, &binary->disass_cache);
+#ifdef INCLUDE_GTK_SUPPORT
+
tracker = g_buffer_cache_get_width_tracker(binary->disass_cache);
g_width_tracker_build_initial_cache(tracker, gid, status);
g_object_unref(G_OBJECT(tracker));
+#endif
+
}
g_object_unref(G_OBJECT(context));
@@ -1661,6 +1679,9 @@ static char *g_loaded_binary_describe(const GLoadedBinary *binary, bool full)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : binary = contenu chargé à consulter. *
@@ -1872,3 +1893,6 @@ static GDisplayOptions *g_loaded_binary_get_display_options(const GLoadedBinary
return result;
}
+
+
+#endif
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h
index faa0e1f..80fa6ea 100644
--- a/src/analysis/block-int.h
+++ b/src/analysis/block-int.h
@@ -44,12 +44,16 @@ typedef int (* block_compare_links_fc) (const block_link_t *, const block_link_t
/* Fournit les détails des origines d'un bloc de code donné. */
typedef block_link_t * (* block_get_links_fc) (const GCodeBlock *, const GBlockList *, size_t *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit la représentation graphique d'un bloc de code. */
typedef GBufferView * (* block_build_view_fc) (const GCodeBlock *, segcnt_list *);
/* Construit un ensemble d'indications pour bloc. */
typedef char *(* block_build_tooltip_fc) (const GCodeBlock *);
+#endif
+
/* Description d'un bloc de code (instance) */
struct _GCodeBlock
@@ -64,7 +68,9 @@ struct _GCodeBlock
size_t index; /* Indice dans une liste */
size_t rank; /* Rang dans l'exécution */
+#ifdef INCLUDE_GTK_SUPPORT
GBufferView *view; /* Représentation construite */
+#endif
};
@@ -77,8 +83,10 @@ struct _GCodeBlockClass
block_compare_links_fc cmp_links; /* Comparaison de liens */
block_get_links_fc get_src; /* Obtention des origines */
block_get_links_fc get_dest; /* Obtention des destinations */
+#ifdef INCLUDE_GTK_SUPPORT
block_build_view_fc build; /* Construction d'une vue */
block_build_tooltip_fc build_tooltip; /* Construction d'une bulle */
+#endif
};
diff --git a/src/analysis/block.c b/src/analysis/block.c
index 119dc86..f93a772 100644
--- a/src/analysis/block.c
+++ b/src/analysis/block.c
@@ -139,7 +139,9 @@ static void g_code_block_init(GCodeBlock *block)
block->index = (size_t)-1;
block->rank = (size_t)-1;
+#ifdef INCLUDE_GTK_SUPPORT
block->view = NULL;
+#endif
}
@@ -158,7 +160,9 @@ static void g_code_block_init(GCodeBlock *block)
static void g_code_block_dispose(GCodeBlock *block)
{
+#ifdef INCLUDE_GTK_SUPPORT
g_clear_object(&block->view);
+#endif
G_OBJECT_CLASS(g_code_block_parent_class)->dispose(G_OBJECT(block));
@@ -322,6 +326,9 @@ void g_code_block_set_rank(GCodeBlock *block, size_t rank)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : block = bloc de code à manipuler. *
@@ -383,6 +390,9 @@ char *g_code_block_build_tooltip(const GCodeBlock *block)
}
+#endif
+
+
/* ---------------------------------------------------------------------------------- */
/* DEFINITION DE LIAISONS ENTRE BLOCS DE CODE */
diff --git a/src/analysis/block.h b/src/analysis/block.h
index 63f0be0..401b520 100644
--- a/src/analysis/block.h
+++ b/src/analysis/block.h
@@ -33,7 +33,9 @@
#include "../arch/instruction.h"
#include "../arch/vmpa.h"
#include "../common/bits.h"
-#include "../glibext/bufferview.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../glibext/bufferview.h"
+#endif
#include "../glibext/linesegment.h"
@@ -74,12 +76,16 @@ size_t g_code_block_get_rank(const GCodeBlock *);
/* Définit le rang du bloc de code dans le flot d'exécution. */
void g_code_block_set_rank(GCodeBlock *, size_t);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit la représentation graphique d'un bloc de code. */
GBufferView *g_code_block_get_view(GCodeBlock *, segcnt_list *);
/* Construit un ensemble d'indications pour bloc. */
char *g_code_block_build_tooltip(const GCodeBlock *);
+#endif
+
/* ------------------- DEFINITION DE LIAISONS ENTRE BLOCS DE CODE ------------------- */
diff --git a/src/analysis/content-int.h b/src/analysis/content-int.h
index 4ef64f9..3475b3f 100644
--- a/src/analysis/content-int.h
+++ b/src/analysis/content-int.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* content-int.h - définitions internes propres aux contenus binaires
*
- * Copyright (C) 2015-2019 Cyrille Bagard
+ * Copyright (C) 2015-2023 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,6 +26,7 @@
#include "content.h"
+#include "storage/serialize-int.h"
@@ -83,11 +84,24 @@ typedef bool (* read_uleb128_fc) (const GBinContent *, vmpa2t *, uleb128_t *);
/* Lit un nombre signé encodé au format LEB128. */
typedef bool (* read_leb128_fc) (const GBinContent *, vmpa2t *, leb128_t *);
+/* Charge un objet depuis une mémoire tampon. */
+typedef bool (* load_content_cb) (GBinContent *, GObjectStorage *, packed_buffer_t *);
-/* Accès à un contenu binaire quelconque (interface) */
-struct _GBinContentIface
+/* Sauvegarde un objet dans une mémoire tampon. */
+typedef bool (* store_content_cb) (const GBinContent *, GObjectStorage *, packed_buffer_t *);
+
+
+/* Accès à un contenu binaire quelconque (instance) */
+struct _GBinContent
{
- GTypeInterface base_iface; /* A laisser en premier */
+ GObject parent; /* A laisser en premier */
+
+};
+
+/* Accès à un contenu binaire quelconque (classe) */
+struct _GBinContentClass
+{
+ GObjectClass parent; /* A laisser en premier */
set_content_attributes set_attribs; /* Enregistrement d'attributs */
get_content_attributes get_attribs; /* Fourniture d'attributs */
@@ -116,11 +130,10 @@ struct _GBinContentIface
read_uleb128_fc read_uleb128; /* Lecture d'un LEB non signé */
read_leb128_fc read_leb128; /* Lecture d'un LEB signé */
-};
-
+ load_content_cb load; /* Chargement */
+ store_content_cb store; /* Enregistrement */
-/* Redéfinition */
-typedef GBinContentIface GBinContentInterface;
+};
diff --git a/src/analysis/content.c b/src/analysis/content.c
index 6d8075c..e12237f 100644
--- a/src/analysis/content.c
+++ b/src/analysis/content.c
@@ -35,20 +35,114 @@
-/* Procède à l'initialisation de l'interface de rassemblement. */
-static void g_binary_content_default_init(GBinContentInterface *);
+/* -------------------------- ENSEMBLE DE DONNEES BINAIRES -------------------------- */
+/* Initialise la classe des contenus binaires à parcourir. */
+static void g_binary_content_class_init(GBinContentClass *);
-/* Détermine le type d'une interface pour la lecture de binaire. */
-G_DEFINE_INTERFACE(GBinContent, g_binary_content, G_TYPE_OBJECT);
+/* Initialise l'instance de contenu binaire à parcourir. */
+static void g_binary_content_init(GBinContent *);
+
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_binary_content_serializable_interface_init(GSerializableObjectIface *);
+
+/* Supprime toutes les références externes. */
+static void g_binary_content_dispose(GBinContent *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_binary_content_finalize(GBinContent *);
+
+
+
+/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
+
+
+/* Charge un contenu depuis une mémoire tampon. */
+static bool g_binary_content_load(GBinContent *, GObjectStorage *, packed_buffer_t *);
+
+/* Sauvegarde un contenu dans une mémoire tampon. */
+static bool g_binary_content_store(const GBinContent *, GObjectStorage *, packed_buffer_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ENSEMBLE DE DONNEES BINAIRES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Détermine le type d'un contenu binaire à parcourir. */
+G_DEFINE_TYPE_WITH_CODE(GBinContent, g_binary_content, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_binary_content_serializable_interface_init));
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des contenus binaires à parcourir. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_binary_content_class_init(GBinContentClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_content_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_binary_content_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = instance à initialiser. *
+* *
+* Description : Initialise l'instance de contenu binaire à parcourir. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_binary_content_init(GBinContent *content)
+{
+
+}
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de rassemblement. *
+* Description : Procède à l'initialisation de l'interface de sérialisation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_binary_content_serializable_interface_init(GSerializableObjectIface *iface)
+{
+ iface->load = (load_serializable_object_cb)g_binary_content_load;
+ iface->store = (store_serializable_object_cb)g_binary_content_store;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
@@ -56,8 +150,28 @@ G_DEFINE_INTERFACE(GBinContent, g_binary_content, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_binary_content_default_init(GBinContentInterface *iface)
+static void g_binary_content_dispose(GBinContent *content)
{
+ G_OBJECT_CLASS(g_binary_content_parent_class)->dispose(G_OBJECT(content));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_binary_content_finalize(GBinContent *content)
+{
+ G_OBJECT_CLASS(g_binary_content_parent_class)->finalize(G_OBJECT(content));
}
@@ -77,11 +191,11 @@ static void g_binary_content_default_init(GBinContentInterface *iface)
void g_binary_content_set_attributes(GBinContent *content, GContentAttributes *attribs)
{
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- iface->set_attribs(content, attribs);
+ class->set_attribs(content, attribs);
}
@@ -101,11 +215,11 @@ void g_binary_content_set_attributes(GBinContent *content, GContentAttributes *a
GContentAttributes *g_binary_content_get_attributes(const GBinContent *content)
{
GContentAttributes *result; /* Instance à retourner */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->get_attribs(content);
+ result = class->get_attribs(content);
return result;
@@ -127,11 +241,11 @@ GContentAttributes *g_binary_content_get_attributes(const GBinContent *content)
GBinContent *g_binary_content_get_root(GBinContent *content)
{
GBinContent *result; /* Contenu en place à renvoyer */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->get_root(content);
+ result = class->get_root(content);
return result;
@@ -154,11 +268,11 @@ GBinContent *g_binary_content_get_root(GBinContent *content)
char *g_binary_content_describe(const GBinContent *content, bool full)
{
char *result; /* Description à retourner */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->describe(content, full);
+ result = class->describe(content, full);
return result;
@@ -181,7 +295,7 @@ const gchar *g_binary_content_get_checksum(GBinContent *content)
{
const gchar *result; /* Empreinte à retourner */
GChecksum *checksum; /* Calcul de l'empreinte */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
checksum = g_object_get_data(G_OBJECT(content), "checksum");
@@ -192,9 +306,9 @@ const gchar *g_binary_content_get_checksum(GBinContent *content)
g_checksum_reset(checksum);
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- iface->compute_checksum(content, checksum);
+ class->compute_checksum(content, checksum);
g_object_set_data_full(G_OBJECT(content), "checksum", checksum, (GDestroyNotify)g_checksum_free);
@@ -221,11 +335,11 @@ const gchar *g_binary_content_get_checksum(GBinContent *content)
phys_t g_binary_content_compute_size(const GBinContent *content)
{
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- return iface->compute_size(content);
+ return class->compute_size(content);
}
@@ -245,11 +359,11 @@ phys_t g_binary_content_compute_size(const GBinContent *content)
void g_binary_content_compute_start_pos(const GBinContent *content, vmpa2t *pos)
{
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- return iface->compute_start_pos(content, pos);
+ return class->compute_start_pos(content, pos);
}
@@ -269,11 +383,11 @@ void g_binary_content_compute_start_pos(const GBinContent *content, vmpa2t *pos)
void g_binary_content_compute_end_pos(const GBinContent *content, vmpa2t *pos)
{
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- return iface->compute_end_pos(content, pos);
+ return class->compute_end_pos(content, pos);
}
@@ -294,11 +408,11 @@ void g_binary_content_compute_end_pos(const GBinContent *content, vmpa2t *pos)
bool g_binary_content_seek(const GBinContent *content, vmpa2t *addr, phys_t length)
{
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- return iface->seek(content, addr, length);
+ return class->seek(content, addr, length);
}
@@ -319,11 +433,11 @@ bool g_binary_content_seek(const GBinContent *content, vmpa2t *addr, phys_t leng
const bin_t *g_binary_content_get_raw_access(const GBinContent *content, vmpa2t *addr, phys_t length)
{
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- return iface->get_raw_access(content, addr, length);
+ return class->get_raw_access(content, addr, length);
}
@@ -346,11 +460,99 @@ const bin_t *g_binary_content_get_raw_access(const GBinContent *content, vmpa2t
bool g_binary_content_read_raw(const GBinContent *content, vmpa2t *addr, phys_t length, bin_t *out)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_raw(content, addr, length, out);
+ result = class->read_raw(content, addr, length, out);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = contenu binaire à venir lire. *
+* addr = position de la tête de lecture complète. *
+* size = quantité de bits à lire. *
+* endian = ordre des bits dans la source. *
+* val = lieu d'enregistrement de la lecture. [OUT] *
+* *
+* Description : Lit un nombre non signé sur deux octets. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_content_read_bits(const GBinContent *content, ext_vmpa_t *addr, uint8_t size, SourceEndian endian, uint64_t *val)
+{
+ bool result; /* Bilan de lecture à renvoyer */
+ vmpa2t pos; /* Tête de lecture courante */
+ uint8_t data; /* Données à parcourir */
+ uint8_t i; /* Boucle de parcours */
+ uint8_t remaining; /* Nombre de bits disponibles */
+ uint64_t bit; /* Nouveau bit à intégrer */
+
+ assert(addr->consumed_extra_bits < 8);
+ assert(size <= 64);
+
+ if (addr->consumed_extra_bits >= 8 || size > 64)
+ return false;
+
+ copy_vmpa(&pos, &addr->base);
+
+ result = g_binary_content_read_u8(content, &pos, &data);
+ if (!result) goto exit;
+
+ remaining = 8 - addr->consumed_extra_bits;
+
+ *val = 0;
+
+ for (i = 0; i < size; i++)
+ {
+ if (remaining == 0)
+ {
+ result = g_binary_content_read_u8(content, &pos, &data);
+ if (!result) goto exit;
+
+ remaining = 8;
+
+ }
+
+ bit = (data >> (remaining - 1)) & 0x1;
+
+ remaining--;
+
+ switch (endian)
+ {
+ case SRE_LITTLE:
+ *val |= (bit << i);
+ break;
+
+ case SRE_BIG:
+ *val |= (bit << (size - i - 1));
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ break;
+
+ }
+
+ }
+
+ if (result)
+ {
+ advance_vmpa(&addr->base, get_phy_addr(&pos) - get_phy_addr(&addr->base) - 1);
+ addr->consumed_extra_bits = 8 - remaining;
+
+ }
+
+ exit:
return result;
@@ -375,11 +577,11 @@ bool g_binary_content_read_raw(const GBinContent *content, vmpa2t *addr, phys_t
bool g_binary_content_read_u4(const GBinContent *content, vmpa2t *addr, bool *low, uint8_t *val)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_u4(content, addr, low, val);
+ result = class->read_u4(content, addr, low, val);
return result;
@@ -404,11 +606,11 @@ bool g_binary_content_read_u4(const GBinContent *content, vmpa2t *addr, bool *lo
bool g_binary_content_read_u8(const GBinContent *content, vmpa2t *addr, uint8_t *val)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_u8(content, addr, val);
+ result = class->read_u8(content, addr, val);
return result;
@@ -433,11 +635,11 @@ bool g_binary_content_read_u8(const GBinContent *content, vmpa2t *addr, uint8_t
bool g_binary_content_read_u16(const GBinContent *content, vmpa2t *addr, SourceEndian endian, uint16_t *val)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_u16(content, addr, endian, val);
+ result = class->read_u16(content, addr, endian, val);
return result;
@@ -462,11 +664,11 @@ bool g_binary_content_read_u16(const GBinContent *content, vmpa2t *addr, SourceE
bool g_binary_content_read_u32(const GBinContent *content, vmpa2t *addr, SourceEndian endian, uint32_t *val)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_u32(content, addr, endian, val);
+ result = class->read_u32(content, addr, endian, val);
return result;
@@ -491,11 +693,11 @@ bool g_binary_content_read_u32(const GBinContent *content, vmpa2t *addr, SourceE
bool g_binary_content_read_u64(const GBinContent *content, vmpa2t *addr, SourceEndian endian, uint64_t *val)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_u64(content, addr, endian, val);
+ result = class->read_u64(content, addr, endian, val);
return result;
@@ -519,11 +721,11 @@ bool g_binary_content_read_u64(const GBinContent *content, vmpa2t *addr, SourceE
bool g_binary_content_read_uleb128(const GBinContent *content, vmpa2t *addr, uleb128_t *val)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_uleb128(content, addr, val);
+ result = class->read_uleb128(content, addr, val);
return result;
@@ -547,11 +749,73 @@ bool g_binary_content_read_uleb128(const GBinContent *content, vmpa2t *addr, ule
bool g_binary_content_read_leb128(const GBinContent *content, vmpa2t *addr, leb128_t *val)
{
bool result; /* Bilan à remonter */
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
+
+ class = G_BIN_CONTENT_GET_CLASS(content);
+
+ result = class->read_leb128(content, addr, val);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION ET RECHARGEMENT DES DONNEES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : content = élément GLib à constuire. *
+* storage = conservateur de données à manipuler ou NULL. *
+* pbuf = zone tampon à lire. *
+* *
+* Description : Charge un contenu depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_binary_content_load(GBinContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GBinContentClass *class; /* Classe de l'instance */
+
+ class = G_BIN_CONTENT_GET_CLASS(content);
+
+ result = class->load(content, storage, pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = élément GLib à consulter. *
+* storage = conservateur de données à manipuler ou NULL. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde un contenu dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_binary_content_store(const GBinContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- result = iface->read_leb128(content, addr, val);
+ result = class->store(content, storage, pbuf);
return result;
diff --git a/src/analysis/content.h b/src/analysis/content.h
index afb721e..ee79a9c 100644
--- a/src/analysis/content.h
+++ b/src/analysis/content.h
@@ -36,22 +36,22 @@
-#define G_TYPE_BIN_CONTENT (g_binary_content_get_type())
-#define G_BIN_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BIN_CONTENT, GBinContent))
-#define G_BIN_CONTENT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_BIN_CONTENT, GBinContentIface))
-#define G_IS_BIN_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BIN_CONTENT))
-#define G_IS_BIN_CONTENT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE((vtable), G_TYPE_BIN_CONTENT))
-#define G_BIN_CONTENT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), G_TYPE_BIN_CONTENT, GBinContentIface))
+#define G_TYPE_BIN_CONTENT g_binary_content_get_type()
+#define G_BIN_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BIN_CONTENT, GBinContent))
+#define G_IS_BIN_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BIN_CONTENT))
+#define G_BIN_CONTENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BIN_CONTENT, GBinContentClass))
+#define G_IS_BIN_CONTENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BIN_CONTENT))
+#define G_BIN_CONTENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BIN_CONTENT, GBinContentClass))
-/* Accès à un contenu binaire quelconque (coquille vide) */
+/* Accès à un contenu binaire quelconque (instance) */
typedef struct _GBinContent GBinContent;
-/* Accès à un contenu binaire quelconque (interface) */
-typedef struct _GBinContentIface GBinContentIface;
+/* Accès à un contenu binaire quelconque (classe) */
+typedef struct _GBinContentClass GBinContentClass;
-/* Détermine le type d'une interface pour la lecture de binaire. */
+/* Détermine le type d'un contenu binaire à parcourir. */
GType g_binary_content_get_type(void) G_GNUC_CONST;
/* Associe un ensemble d'attributs au contenu binaire. */
@@ -87,6 +87,9 @@ const bin_t *g_binary_content_get_raw_access(const GBinContent *, vmpa2t *, phys
/* Fournit une portion des données représentées. */
bool g_binary_content_read_raw(const GBinContent *, vmpa2t *, phys_t, bin_t *);
+/* Lit un nombre non signé sur deux octets. */
+bool g_binary_content_read_bits(const GBinContent *, ext_vmpa_t *, uint8_t, SourceEndian, uint64_t *);
+
/* Lit un nombre non signé sur quatre bits. */
bool g_binary_content_read_u4(const GBinContent *, vmpa2t *, bool *, uint8_t *);
diff --git a/src/analysis/contents/Makefile.am b/src/analysis/contents/Makefile.am
index 66e3cac..e1cf04f 100644
--- a/src/analysis/contents/Makefile.am
+++ b/src/analysis/contents/Makefile.am
@@ -2,24 +2,18 @@
noinst_LTLIBRARIES = libanalysiscontents.la
libanalysiscontents_la_SOURCES = \
+ encapsulated-int.h \
encapsulated.h encapsulated.c \
+ file-int.h \
file.h file.c \
memory-int.h \
memory.h memory.c \
+ restricted-int.h \
restricted.h restricted.c
-libanalysiscontents_la_LIBADD =
-
-libanalysiscontents_la_LDFLAGS =
+libanalysiscontents_la_CFLAGS = $(TOOLKIT_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysiscontents_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/analysis/contents/encapsulated-int.h b/src/analysis/contents/encapsulated-int.h
new file mode 100644
index 0000000..5ccd318
--- /dev/null
+++ b/src/analysis/contents/encapsulated-int.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * encapsulated-int.h - prototypes internes pour le chargement de données binaires à partir d'un contenu restreint
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_CONTENTS_ENCAPSULATED_INT_H
+#define _ANALYSIS_CONTENTS_ENCAPSULATED_INT_H
+
+
+#include "encapsulated.h"
+
+
+#include "../content-int.h"
+
+
+
+/* Contenu de données binaires issues d'un contenu restreint (instance) */
+struct _GEncapsContent
+{
+ GBinContent parent; /* A laisser en premier */
+
+ GBinContent *base; /* Base offrant une extraction */
+ char *path; /* Chemin vers le contenu ciblé*/
+ GBinContent *endpoint; /* Contenu ciblé */
+
+ char *full_desc; /* Description de l'ensemble */
+ char *desc; /* Description de l'ensemble */
+
+};
+
+/* Contenu de données binaires issues d'un contenu restreint (classe) */
+struct _GEncapsContentClass
+{
+ GBinContentClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un contenu de données brutes encapsulées. */
+bool g_encaps_content_create(GEncapsContent *, GBinContent *, const char *, GBinContent *);
+
+
+
+#endif /* _ANALYSIS_CONTENTS_ENCAPSULATED_INT_H */
diff --git a/src/analysis/contents/encapsulated.c b/src/analysis/contents/encapsulated.c
index dadc0a5..e0e6ed1 100644
--- a/src/analysis/contents/encapsulated.c
+++ b/src/analysis/contents/encapsulated.c
@@ -28,7 +28,7 @@
#include <string.h>
-#include "../content-int.h"
+#include "encapsulated-int.h"
#include "../db/misc/rlestr.h"
#include "../storage/serialize-int.h"
#include "../../common/extstr.h"
@@ -38,40 +38,12 @@
/* -------------------------- ENSEMBLE DE DONNEES BINAIRES -------------------------- */
-/* Contenu de issu d'un contenu plus global (instance) */
-struct _GEncapsContent
-{
- GObject parent; /* A laisser en premier */
-
- GBinContent *base; /* Base offrant une extraction */
- char *path; /* Chemin vers le contenu ciblé*/
- GBinContent *endpoint; /* Contenu ciblé */
-
- char *full_desc; /* Description de l'ensemble */
- char *desc; /* Description de l'ensemble */
-
-};
-
-/* Contenu de issu d'un contenu plus global (classe) */
-struct _GEncapsContentClass
-{
- GObjectClass parent; /* A laisser en premier */
-
-};
-
-
/* Initialise la classe des contenus de données encapsulés. */
static void g_encaps_content_class_init(GEncapsContentClass *);
/* Initialise une instance de contenu de données encapsulé. */
static void g_encaps_content_init(GEncapsContent *);
-/* Procède à l'initialisation de l'interface de sérialisation. */
-static void g_encaps_content_serializable_init(GSerializableObjectInterface *);
-
-/* Procède à l'initialisation de l'interface de lecture. */
-static void g_encaps_content_interface_init(GBinContentInterface *);
-
/* Supprime toutes les références externes. */
static void g_encaps_content_dispose(GEncapsContent *);
@@ -80,7 +52,7 @@ static void g_encaps_content_finalize(GEncapsContent *);
-/* ---------------------- INTERACTIONS AVEC UN CONTENU BINAIRE ---------------------- */
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
/* Associe un ensemble d'attributs au contenu binaire. */
@@ -137,11 +109,6 @@ static bool g_encaps_content_read_uleb128(const GEncapsContent *, vmpa2t *, uleb
/* Lit un nombre signé encodé au format LEB128. */
static bool g_encaps_content_read_leb128(const GEncapsContent *, vmpa2t *, leb128_t *);
-
-
-/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
-
-
/* Charge un contenu depuis une mémoire tampon. */
static bool g_encaps_content_load(GEncapsContent *, GObjectStorage *, packed_buffer_t *);
@@ -156,9 +123,7 @@ static bool g_encaps_content_store(const GEncapsContent *, GObjectStorage *, pac
/* Indique le type défini par la GLib pour les contenus encapsulés. */
-G_DEFINE_TYPE_WITH_CODE(GEncapsContent, g_encaps_content, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_encaps_content_interface_init)
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_encaps_content_serializable_init));
+G_DEFINE_TYPE(GEncapsContent, g_encaps_content, G_TYPE_BIN_CONTENT);
/******************************************************************************
@@ -176,88 +141,53 @@ G_DEFINE_TYPE_WITH_CODE(GEncapsContent, g_encaps_content, G_TYPE_OBJECT,
static void g_encaps_content_class_init(GEncapsContentClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GBinContentClass *content; /* Version parente de la classe*/
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_encaps_content_dispose;
object->finalize = (GObjectFinalizeFunc)g_encaps_content_finalize;
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : content = instance à initialiser. *
-* *
-* Description : Initialise une instance de contenu de données encapsulé. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_encaps_content_init(GEncapsContent *content)
-{
- content->base = NULL;
- content->path = NULL;
- content->endpoint = NULL;
-
- content->full_desc = NULL;
- content->desc = NULL;
+ content = G_BIN_CONTENT_CLASS(klass);
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : iface = interface GLib à initialiser. *
-* *
-* Description : Procède à l'initialisation de l'interface de lecture. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ content->set_attribs = (set_content_attributes)g_encaps_content_set_attributes;
+ content->get_attribs = (get_content_attributes)g_encaps_content_get_attributes;
-static void g_encaps_content_interface_init(GBinContentInterface *iface)
-{
- iface->set_attribs = (set_content_attributes)g_encaps_content_set_attributes;
- iface->get_attribs = (get_content_attributes)g_encaps_content_get_attributes;
+ content->get_root = (get_content_root_fc)g_encaps_content_get_root;
- iface->get_root = (get_content_root_fc)g_encaps_content_get_root;
+ content->describe = (describe_content_fc)g_encaps_content_describe;
- iface->describe = (describe_content_fc)g_encaps_content_describe;
+ content->compute_checksum = (compute_checksum_fc)g_encaps_content_compute_checksum;
- iface->compute_checksum = (compute_checksum_fc)g_encaps_content_compute_checksum;
+ content->compute_size = (compute_size_fc)g_encaps_content_compute_size;
+ content->compute_start_pos = (compute_start_pos_fc)g_encaps_content_compute_start_pos;
+ content->compute_end_pos = (compute_end_pos_fc)g_encaps_content_compute_end_pos;
- iface->compute_size = (compute_size_fc)g_encaps_content_compute_size;
- iface->compute_start_pos = (compute_start_pos_fc)g_encaps_content_compute_start_pos;
- iface->compute_end_pos = (compute_end_pos_fc)g_encaps_content_compute_end_pos;
+ content->seek = (seek_fc)g_encaps_content_seek;
- iface->seek = (seek_fc)g_encaps_content_seek;
+ content->get_raw_access = (get_raw_access_fc)g_encaps_content_get_raw_access;
- iface->get_raw_access = (get_raw_access_fc)g_encaps_content_get_raw_access;
+ content->read_raw = (read_raw_fc)g_encaps_content_read_raw;
+ content->read_u4 = (read_u4_fc)g_encaps_content_read_u4;
+ content->read_u8 = (read_u8_fc)g_encaps_content_read_u8;
+ content->read_u16 = (read_u16_fc)g_encaps_content_read_u16;
+ content->read_u32 = (read_u32_fc)g_encaps_content_read_u32;
+ content->read_u64 = (read_u64_fc)g_encaps_content_read_u64;
- iface->read_raw = (read_raw_fc)g_encaps_content_read_raw;
- iface->read_u4 = (read_u4_fc)g_encaps_content_read_u4;
- iface->read_u8 = (read_u8_fc)g_encaps_content_read_u8;
- iface->read_u16 = (read_u16_fc)g_encaps_content_read_u16;
- iface->read_u32 = (read_u32_fc)g_encaps_content_read_u32;
- iface->read_u64 = (read_u64_fc)g_encaps_content_read_u64;
+ content->read_uleb128 = (read_uleb128_fc)g_encaps_content_read_uleb128;
+ content->read_leb128 = (read_leb128_fc)g_encaps_content_read_leb128;
- iface->read_uleb128 = (read_uleb128_fc)g_encaps_content_read_uleb128;
- iface->read_leb128 = (read_leb128_fc)g_encaps_content_read_leb128;
+ content->load = (load_content_cb)g_encaps_content_load;
+ content->store = (store_content_cb)g_encaps_content_store;
}
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
+* Paramètres : content = instance à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de sérialisation. *
+* Description : Initialise une instance de contenu de données encapsulé. *
* *
* Retour : - *
* *
@@ -265,10 +195,14 @@ static void g_encaps_content_interface_init(GBinContentInterface *iface)
* *
******************************************************************************/
-static void g_encaps_content_serializable_init(GSerializableObjectInterface *iface)
+static void g_encaps_content_init(GEncapsContent *content)
{
- iface->load = (load_serializable_object_cb)g_encaps_content_load;
- iface->store = (store_serializable_object_cb)g_encaps_content_store;
+ content->base = NULL;
+ content->path = NULL;
+ content->endpoint = NULL;
+
+ content->full_desc = NULL;
+ content->desc = NULL;
}
@@ -337,30 +271,59 @@ static void g_encaps_content_finalize(GEncapsContent *content)
GBinContent *g_encaps_content_new(GBinContent *base, const char *path, GBinContent *endpoint)
{
- GEncapsContent *result; /* Structure à retourner */
+ GBinContent *result; /* Structure à retourner */
result = g_object_new(G_TYPE_ENCAPS_CONTENT, NULL);
+ if (!g_encaps_content_create(G_ENCAPS_CONTENT(result), base, path, endpoint))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = instance à initialiser pleinement. *
+* base = contenu binaire d'où réaliser une extraction. *
+* path = chemin vers le contenu finalement ciblé. *
+* endpoint = contenu final rendu accessible. *
+* *
+* Description : Met en place un contenu de données brutes encapsulées. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_encaps_content_create(GEncapsContent *content, GBinContent *base, const char *path, GBinContent *endpoint)
+{
+ bool result; /* Bilan à retourner */
+
g_object_ref(base);
g_object_ref(endpoint);
- result->base = base;
- result->path = strdup(path);
- result->endpoint = endpoint;
+ content->base = base;
+ content->path = strdup(path);
+ content->endpoint = endpoint;
/* Description complète */
- result->full_desc = g_binary_content_describe(result->base, true);
+ content->full_desc = g_binary_content_describe(content->base, true);
- result->full_desc = stradd(result->full_desc, G_DIR_SEPARATOR_S);
+ content->full_desc = stradd(content->full_desc, G_DIR_SEPARATOR_S);
- result->full_desc = stradd(result->full_desc, path);
+ content->full_desc = stradd(content->full_desc, path);
/* Description partielle */
- result->desc = strdup(path);
+ content->desc = strdup(path);
+
+ result = true;
- return G_BIN_CONTENT(result);
+ return result;
}
@@ -442,7 +405,7 @@ GBinContent *g_encaps_content_get_endpoint(const GEncapsContent *content)
/* ---------------------------------------------------------------------------------- */
-/* INTERACTIONS AVEC UN CONTENU BINAIRE */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */
@@ -554,11 +517,11 @@ static char *g_encaps_content_describe(const GEncapsContent *content, bool full)
static void g_encaps_content_compute_checksum(GEncapsContent *content, GChecksum *checksum)
{
- GBinContentIface *iface; /* Interface utilisée */
+ GBinContentClass *class; /* Classe de l'instance */
- iface = G_BIN_CONTENT_GET_IFACE(content->endpoint);
+ class = G_BIN_CONTENT_GET_CLASS(content);
- iface->compute_checksum(content->endpoint, checksum);
+ class->compute_checksum(content->endpoint, checksum);
}
@@ -882,12 +845,6 @@ static bool g_encaps_content_read_leb128(const GEncapsContent *content, vmpa2t *
}
-
-/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION ET RECHARGEMENT DES DONNEES */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
* Paramètres : content = élément GLib à constuire. *
diff --git a/src/analysis/contents/file-int.h b/src/analysis/contents/file-int.h
new file mode 100644
index 0000000..dc61bdc
--- /dev/null
+++ b/src/analysis/contents/file-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * file-int.h - prototypes internes pour le chargement de données binaires à partir d'un fichier
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_CONTENTS_FILE_INT_H
+#define _ANALYSIS_CONTENTS_FILE_INT_H
+
+
+#include "file.h"
+
+
+#include "memory-int.h"
+
+
+
+/* Contenu de données binaires issues d'un fichier (instance) */
+struct _GFileContent
+{
+ GMemoryContent parent; /* A laisser en premier */
+
+ char *filename; /* Fichier chargé en mémoire */
+ int fd; /* Flux ouvert en lectureu */
+
+};
+
+/* Contenu de données binaires issues d'un fichier (classe) */
+struct _GFileContentClass
+{
+ GMemoryContentClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un contenu d'un fichier donné. */
+bool g_file_content_create(GFileContent *, const char *);
+
+
+
+#endif /* _ANALYSIS_CONTENTS_FILE_INT_H */
diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c
index 4f102d8..545d869 100644
--- a/src/analysis/contents/file.c
+++ b/src/analysis/contents/file.c
@@ -25,6 +25,7 @@
#include <fcntl.h>
+#include <libgen.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h>
@@ -32,8 +33,7 @@
#include <sys/stat.h>
-#include "memory-int.h"
-#include "../content-int.h"
+#include "file-int.h"
#include "../db/misc/rlestr.h"
#include "../storage/serialize-int.h"
#include "../../core/logs.h"
@@ -43,32 +43,12 @@
/* -------------------------- ENSEMBLE DE DONNEES BINAIRES -------------------------- */
-/* Contenu de données binaires issues d'un fichier (instance) */
-struct _GFileContent
-{
- GMemoryContent parent; /* A laisser en premier */
-
- char *filename; /* Fichier chargé en mémoire */
-
-};
-
-/* Contenu de données binaires issues d'un fichier (classe) */
-struct _GFileContentClass
-{
- GMemoryContentClass parent; /* A laisser en premier */
-
-};
-
-
/* Initialise la classe des contenus de données binaires. */
static void g_file_content_class_init(GFileContentClass *);
/* Initialise une instance de contenu de données binaires. */
static void g_file_content_init(GFileContent *);
-/* Procède à l'initialisation de l'interface de sérialisation. */
-static void g_file_content_serializable_init(GSerializableObjectInterface *);
-
/* Supprime toutes les références externes. */
static void g_file_content_dispose(GFileContent *);
@@ -76,8 +56,12 @@ static void g_file_content_dispose(GFileContent *);
static void g_file_content_finalize(GFileContent *);
-/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom associé au contenu binaire. */
+static char *g_file_content_describe(const GFileContent *, bool);
/* Charge un contenu depuis une mémoire tampon. */
static bool g_file_content_load(GFileContent *, GObjectStorage *, packed_buffer_t *);
@@ -93,8 +77,7 @@ static bool g_file_content_store(const GFileContent *, GObjectStorage *, packed_
/* Indique le type défini par la GLib pour les contenus de données. */
-G_DEFINE_TYPE_WITH_CODE(GFileContent, g_file_content, G_TYPE_MEMORY_CONTENT,
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_file_content_serializable_init));
+G_DEFINE_TYPE(GFileContent, g_file_content, G_TYPE_MEMORY_CONTENT);
/******************************************************************************
@@ -112,12 +95,20 @@ G_DEFINE_TYPE_WITH_CODE(GFileContent, g_file_content, G_TYPE_MEMORY_CONTENT,
static void g_file_content_class_init(GFileContentClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GBinContentClass *content; /* Version parente de la classe*/
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_file_content_dispose;
object->finalize = (GObjectFinalizeFunc)g_file_content_finalize;
+ content = G_BIN_CONTENT_CLASS(klass);
+
+ content->describe = (describe_content_fc)g_file_content_describe;
+
+ content->load = (load_content_cb)g_file_content_load;
+ content->store = (store_content_cb)g_file_content_store;
+
}
@@ -136,15 +127,16 @@ static void g_file_content_class_init(GFileContentClass *klass)
static void g_file_content_init(GFileContent *content)
{
content->filename = NULL;
+ content->fd = -1;
}
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
+* Paramètres : content = instance d'objet GLib à traiter. *
* *
-* Description : Procède à l'initialisation de l'interface de sérialisation. *
+* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
@@ -152,10 +144,9 @@ static void g_file_content_init(GFileContent *content)
* *
******************************************************************************/
-static void g_file_content_serializable_init(GSerializableObjectInterface *iface)
+static void g_file_content_dispose(GFileContent *content)
{
- iface->load = (load_serializable_object_cb)g_file_content_load;
- iface->store = (store_serializable_object_cb)g_file_content_store;
+ G_OBJECT_CLASS(g_file_content_parent_class)->dispose(G_OBJECT(content));
}
@@ -164,7 +155,7 @@ static void g_file_content_serializable_init(GSerializableObjectInterface *iface
* *
* Paramètres : content = instance d'objet GLib à traiter. *
* *
-* Description : Supprime toutes les références externes. *
+* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
@@ -172,55 +163,78 @@ static void g_file_content_serializable_init(GSerializableObjectInterface *iface
* *
******************************************************************************/
-static void g_file_content_dispose(GFileContent *content)
+static void g_file_content_finalize(GFileContent *content)
{
- G_OBJECT_CLASS(g_file_content_parent_class)->dispose(G_OBJECT(content));
+ GMemoryContent *base; /* Structure parente */
+
+ free(content->filename);
+
+ if (content->fd != -1)
+ {
+ base = G_MEMORY_CONTENT(content);
+ munmap(base->data, base->length);
+
+ close(content->fd);
+
+ }
+
+ G_OBJECT_CLASS(g_file_content_parent_class)->finalize(G_OBJECT(content));
}
+
+
/******************************************************************************
* *
-* Paramètres : content = instance d'objet GLib à traiter. *
+* Paramètres : filename = chemin d'accès au fichier à charger. *
* *
-* Description : Procède à la libération totale de la mémoire. *
+* Description : Charge en mémoire le contenu d'un fichier donné. *
* *
-* Retour : - *
+* Retour : Représentation de contenu à manipuler ou NULL en cas d'échec.*
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_file_content_finalize(GFileContent *content)
+GBinContent *g_file_content_new(const char *filename)
{
- free(content->filename);
+ GBinContent *result; /* Structure à retourner */
- G_OBJECT_CLASS(g_file_content_parent_class)->finalize(G_OBJECT(content));
+ result = g_object_new(G_TYPE_FILE_CONTENT, NULL);
+
+ if (!g_file_content_create(G_FILE_CONTENT(result), filename))
+ g_clear_object(&result);
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : filename = chemin d'accès au fichier à charger. *
+* Paramètres : content = instance à initialiser pleinement. *
+* filename = chemin d'accès au fichier à charger. *
* *
-* Description : Charge en mémoire le contenu d'un fichier donné. *
+* Description : Met en place un contenu d'un fichier donné. *
* *
-* Retour : Représentation de contenu à manipuler ou NULL en cas d'échec.*
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GBinContent *g_file_content_new(const char *filename)
+bool g_file_content_create(GFileContent *content, const char *filename)
{
- GFileContent *result; /* Structure à retourner */
+ bool result; /* Bilan à retourner */
int fd; /* Descripteur du fichier */
struct stat info; /* Informations sur le fichier */
int ret; /* Bilan d'un appel */
- void *content; /* Contenu brut du fichier */
+ void *data; /* Contenu brut du fichier */
GMemoryContent *base; /* Structure parente */
+ result = false;
+
/* Récupération des données */
fd = open(filename, O_RDONLY);
@@ -238,8 +252,8 @@ GBinContent *g_file_content_new(const char *filename)
goto file_error;
}
- content = mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (content == MAP_FAILED)
+ data = mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED)
{
close(fd);
LOG_ERROR_N("mmap");
@@ -248,25 +262,18 @@ GBinContent *g_file_content_new(const char *filename)
/* Constitution du contenu officiel */
- result = g_object_new(G_TYPE_FILE_CONTENT, NULL);
-
- result->filename = strdup(filename);
-
- base = G_MEMORY_CONTENT(result);
+ content->filename = strdup(filename);
- base->data = malloc(info.st_size);
- memcpy(base->data, content, info.st_size);
+ base = G_MEMORY_CONTENT(content);
+ base->data = data;
base->length = info.st_size;
- munmap(content, info.st_size);
- close(fd);
-
- return G_BIN_CONTENT(result);
+ result = true;
file_error:
- return NULL;
+ return result;
}
@@ -296,12 +303,51 @@ const char *g_file_content_get_filename(const GFileContent *content)
/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION ET RECHARGEMENT DES DONNEES */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
+* Paramètres : content = contenu binaire à consulter. *
+* full = précise s'il s'agit d'une version longue ou non. *
+* *
+* Description : Fournit le nom associé au contenu binaire. *
+* *
+* Retour : Nom de fichier avec chemin absolu au besoin. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_file_content_describe(const GFileContent *content, bool full)
+{
+ char *result; /* Description à retourner */
+ char *tmp; /* Copie modifiable */
+ char *base; /* Description à recopier */
+
+ if (full)
+ result = strdup(content->filename);
+
+ else
+ {
+ tmp = strdup(content->filename);
+
+ base = basename(tmp);
+
+ result = strdup(base);
+
+ free(tmp);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : content = élément GLib à constuire. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à lire. *
diff --git a/src/analysis/contents/memory-int.h b/src/analysis/contents/memory-int.h
index 621e4a6..d3012c7 100644
--- a/src/analysis/contents/memory-int.h
+++ b/src/analysis/contents/memory-int.h
@@ -28,16 +28,20 @@
#include "memory.h"
+#include "../content-int.h"
+
+
/* Contenu de données binaires résidant en mémoire (instance) */
struct _GMemoryContent
{
- GObject parent; /* A laisser en premier */
+ GBinContent parent; /* A laisser en premier */
GContentAttributes *attribs; /* Attributs liés au contenu */
bin_t *data; /* Contenu binaire représenté */
phys_t length; /* Taille totale du contenu */
+ bool allocated; /* Nature de la zone de données*/
char *full_desc; /* Description de l'ensemble */
char *desc; /* Description de l'ensemble */
@@ -47,10 +51,14 @@ struct _GMemoryContent
/* Contenu de données binaires résidant en mémoire (classe) */
struct _GMemoryContentClass
{
- GObjectClass parent; /* A laisser en premier */
+ GBinContentClass parent; /* A laisser en premier */
};
+/* Met en place un contenu de données brutes depuis la mémoire. */
+bool g_memory_content_create(GMemoryContent *, const bin_t *, phys_t);
+
+
#endif /* _ANALYSIS_CONTENTS_MEMORY_INT_H */
diff --git a/src/analysis/contents/memory.c b/src/analysis/contents/memory.c
index 9ddc4fa..f8ff863 100644
--- a/src/analysis/contents/memory.c
+++ b/src/analysis/contents/memory.c
@@ -51,12 +51,6 @@ static void g_memory_content_class_init(GMemoryContentClass *);
/* Initialise une instance de contenu de données en mémoire. */
static void g_memory_content_init(GMemoryContent *);
-/* Procède à l'initialisation de l'interface de lecture. */
-static void g_memory_content_interface_init(GBinContentInterface *);
-
-/* Procède à l'initialisation de l'interface de sérialisation. */
-static void g_memory_content_serializable_init(GSerializableObjectInterface *);
-
/* Supprime toutes les références externes. */
static void g_memory_content_dispose(GMemoryContent *);
@@ -65,7 +59,7 @@ static void g_memory_content_finalize(GMemoryContent *);
-/* ---------------------- INTERACTIONS AVEC UN CONTENU BINAIRE ---------------------- */
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
/* Associe un ensemble d'attributs au contenu binaire. */
@@ -122,11 +116,6 @@ static bool g_memory_content_read_uleb128(const GMemoryContent *, vmpa2t *, uleb
/* Lit un nombre signé encodé au format LEB128. */
static bool g_memory_content_read_leb128(const GMemoryContent *, vmpa2t *, leb128_t *);
-
-
-/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
-
-
/* Charge un contenu depuis une mémoire tampon. */
static bool g_memory_content_load(GMemoryContent *, GObjectStorage *, packed_buffer_t *);
@@ -141,9 +130,7 @@ static bool g_memory_content_store(const GMemoryContent *, GObjectStorage *, pac
/* Indique le type défini par la GLib pour les contenus de données en mémoire. */
-G_DEFINE_TYPE_WITH_CODE(GMemoryContent, g_memory_content, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_memory_content_interface_init)
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_memory_content_serializable_init));
+G_DEFINE_TYPE(GMemoryContent, g_memory_content, G_TYPE_BIN_CONTENT);
/******************************************************************************
@@ -161,12 +148,45 @@ G_DEFINE_TYPE_WITH_CODE(GMemoryContent, g_memory_content, G_TYPE_OBJECT,
static void g_memory_content_class_init(GMemoryContentClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GBinContentClass *content; /* Version parente de la classe*/
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_memory_content_dispose;
object->finalize = (GObjectFinalizeFunc)g_memory_content_finalize;
+ content = G_BIN_CONTENT_CLASS(klass);
+
+ content->set_attribs = (set_content_attributes)g_memory_content_set_attributes;
+ content->get_attribs = (get_content_attributes)g_memory_content_get_attributes;
+
+ content->get_root = (get_content_root_fc)g_memory_content_get_root;
+
+ content->describe = (describe_content_fc)g_memory_content_describe;
+
+ content->compute_checksum = (compute_checksum_fc)g_memory_content_compute_checksum;
+
+ content->compute_size = (compute_size_fc)g_memory_content_compute_size;
+ content->compute_start_pos = (compute_start_pos_fc)g_memory_content_compute_start_pos;
+ content->compute_end_pos = (compute_end_pos_fc)g_memory_content_compute_end_pos;
+
+ content->seek = (seek_fc)g_memory_content_seek;
+
+ content->get_raw_access = (get_raw_access_fc)g_memory_content_get_raw_access;
+
+ content->read_raw = (read_raw_fc)g_memory_content_read_raw;
+ content->read_u4 = (read_u4_fc)g_memory_content_read_u4;
+ content->read_u8 = (read_u8_fc)g_memory_content_read_u8;
+ content->read_u16 = (read_u16_fc)g_memory_content_read_u16;
+ content->read_u32 = (read_u32_fc)g_memory_content_read_u32;
+ content->read_u64 = (read_u64_fc)g_memory_content_read_u64;
+
+ content->read_uleb128 = (read_uleb128_fc)g_memory_content_read_uleb128;
+ content->read_leb128 = (read_leb128_fc)g_memory_content_read_leb128;
+
+ content->load = (load_content_cb)g_memory_content_load;
+ content->store = (store_content_cb)g_memory_content_store;
+
}
@@ -196,6 +216,7 @@ static void g_memory_content_init(GMemoryContent *content)
content->data = NULL;
content->length = 0;
+ content->allocated = false;
content->full_desc = strdup("In-memory content");
content->desc = strdup("In-memory content");
@@ -205,70 +226,6 @@ static void g_memory_content_init(GMemoryContent *content)
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
-* *
-* Description : Procède à l'initialisation de l'interface de lecture. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_memory_content_interface_init(GBinContentInterface *iface)
-{
- iface->set_attribs = (set_content_attributes)g_memory_content_set_attributes;
- iface->get_attribs = (get_content_attributes)g_memory_content_get_attributes;
-
- iface->get_root = (get_content_root_fc)g_memory_content_get_root;
-
- iface->describe = (describe_content_fc)g_memory_content_describe;
-
- iface->compute_checksum = (compute_checksum_fc)g_memory_content_compute_checksum;
-
- iface->compute_size = (compute_size_fc)g_memory_content_compute_size;
- iface->compute_start_pos = (compute_start_pos_fc)g_memory_content_compute_start_pos;
- iface->compute_end_pos = (compute_end_pos_fc)g_memory_content_compute_end_pos;
-
- iface->seek = (seek_fc)g_memory_content_seek;
-
- iface->get_raw_access = (get_raw_access_fc)g_memory_content_get_raw_access;
-
- iface->read_raw = (read_raw_fc)g_memory_content_read_raw;
- iface->read_u4 = (read_u4_fc)g_memory_content_read_u4;
- iface->read_u8 = (read_u8_fc)g_memory_content_read_u8;
- iface->read_u16 = (read_u16_fc)g_memory_content_read_u16;
- iface->read_u32 = (read_u32_fc)g_memory_content_read_u32;
- iface->read_u64 = (read_u64_fc)g_memory_content_read_u64;
-
- iface->read_uleb128 = (read_uleb128_fc)g_memory_content_read_uleb128;
- iface->read_leb128 = (read_leb128_fc)g_memory_content_read_leb128;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : iface = interface GLib à initialiser. *
-* *
-* Description : Procède à l'initialisation de l'interface de sérialisation. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_memory_content_serializable_init(GSerializableObjectInterface *iface)
-{
- iface->load = (load_serializable_object_cb)g_memory_content_load;
- iface->store = (store_serializable_object_cb)g_memory_content_store;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : content = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
@@ -302,8 +259,11 @@ static void g_memory_content_dispose(GMemoryContent *content)
static void g_memory_content_finalize(GMemoryContent *content)
{
- if (content->data != NULL)
- free(content->data);
+ if (content->allocated)
+ {
+ if (content->data != NULL)
+ free(content->data);
+ }
if (content->desc != NULL)
free(content->desc);
@@ -331,31 +291,62 @@ static void g_memory_content_finalize(GMemoryContent *content)
GBinContent *g_memory_content_new(const bin_t *data, phys_t size)
{
- GMemoryContent *result; /* Structure à retourner */
+ GBinContent *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_MEMORY_CONTENT, NULL);
+
+ if (!g_memory_content_create(G_MEMORY_CONTENT(result), data, size))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = instance à initialiser pleinement. *
+* data = données du contenu volatile. *
+* size = quantité de ces données. *
+* *
+* Description : Met en place un contenu de données brutes depuis la mémoire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_memory_content_create(GMemoryContent *content, const bin_t *data, phys_t size)
+{
+ bool result; /* Bilan à retourner */
bin_t *allocated; /* Zone de réception */
allocated = malloc(size);
if (allocated == NULL)
{
LOG_ERROR_N("malloc");
- return NULL;
+ goto exit;
}
memcpy(allocated, data, size);
- result = g_object_new(G_TYPE_MEMORY_CONTENT, NULL);
+ content->data = allocated;
+ content->length = size;
+ content->allocated = true;
- result->data = allocated;
- result->length = size;
+ result = true;
+
+ exit:
- return G_BIN_CONTENT(result);
+ return result;
}
/* ---------------------------------------------------------------------------------- */
-/* INTERACTIONS AVEC UN CONTENU BINAIRE */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */
@@ -705,15 +696,12 @@ static bool g_memory_content_read_u8(const GMemoryContent *content, vmpa2t *addr
{
bool result; /* Bilan de lecture à renvoyer */
phys_t pos; /* Tête de lecture courante */
- phys_t length; /* Taille de la surface dispo. */
pos = get_phy_addr(addr);
if (pos == VMPA_NO_PHYSICAL)
return false;
- length = length;
-
result = read_u8(val, content->data, &pos, content->length);
if (result)
@@ -897,12 +885,6 @@ static bool g_memory_content_read_leb128(const GMemoryContent *content, vmpa2t *
}
-
-/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION ET RECHARGEMENT DES DONNEES */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
* Paramètres : content = élément GLib à constuire. *
@@ -929,6 +911,9 @@ static bool g_memory_content_load(GMemoryContent *content, GObjectStorage *stora
{
content->data = malloc(length);
result = (content->data != NULL);
+
+ content->allocated = true;
+
}
if (result)
diff --git a/src/analysis/contents/restricted-int.h b/src/analysis/contents/restricted-int.h
new file mode 100644
index 0000000..ab86359
--- /dev/null
+++ b/src/analysis/contents/restricted-int.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * restricted-int.h - prototypes internes pour le chargement de données binaires à partir d'un contenu restreint
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_CONTENTS_RESTRICTED_INT_H
+#define _ANALYSIS_CONTENTS_RESTRICTED_INT_H
+
+
+#include "restricted.h"
+
+
+#include "../content-int.h"
+
+
+
+/* Contenu de données binaires issues d'un contenu restreint (instance) */
+struct _GRestrictedContent
+{
+ GBinContent parent; /* A laisser en premier */
+
+ GBinContent *internal; /* Contenu de sous-traitance */
+
+ mrange_t range; /* Restriction de couverture */
+
+};
+
+/* Contenu de données binaires issues d'un contenu restreint (classe) */
+struct _GRestrictedContentClass
+{
+ GBinContentClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un contenu restreint de données brutes. */
+bool g_restricted_content_create(GRestrictedContent *, GBinContent *, const mrange_t *);
+
+
+
+#endif /* _ANALYSIS_CONTENTS_RESTRICTED_INT_H */
diff --git a/src/analysis/contents/restricted.c b/src/analysis/contents/restricted.c
index 55bc83f..9b4e1c8 100644
--- a/src/analysis/contents/restricted.c
+++ b/src/analysis/contents/restricted.c
@@ -28,7 +28,7 @@
#include <string.h>
-#include "../content-int.h"
+#include "restricted-int.h"
#include "../db/misc/rlestr.h"
#include "../storage/serialize-int.h"
#include "../../common/extstr.h"
@@ -39,37 +39,12 @@
/* -------------------------- ENSEMBLE DE DONNEES BINAIRES -------------------------- */
-/* Contenu de données binaires issues d'un contenu restreint (instance) */
-struct _GRestrictedContent
-{
- GObject parent; /* A laisser en premier */
-
- GBinContent *internal; /* Contenu de sous-traitance */
-
- mrange_t range; /* Restriction de couverture */
-
-};
-
-/* Contenu de données binaires issues d'un contenu restreint (classe) */
-struct _GRestrictedContentClass
-{
- GObjectClass parent; /* A laisser en premier */
-
-};
-
-
/* Initialise la classe des contenus de données binaires. */
static void g_restricted_content_class_init(GRestrictedContentClass *);
/* Initialise une instance de contenu de données binaires. */
static void g_restricted_content_init(GRestrictedContent *);
-/* Procède à l'initialisation de l'interface de lecture. */
-static void g_restricted_content_interface_init(GBinContentInterface *);
-
-/* Procède à l'initialisation de l'interface de sérialisation. */
-static void g_restricted_content_serializable_init(GSerializableObjectInterface *);
-
/* Supprime toutes les références externes. */
static void g_restricted_content_dispose(GRestrictedContent *);
@@ -78,7 +53,7 @@ static void g_restricted_content_finalize(GRestrictedContent *);
-/* ---------------------- INTERACTIONS AVEC UN CONTENU BINAIRE ---------------------- */
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
/* Associe un ensemble d'attributs au contenu binaire. */
@@ -135,11 +110,6 @@ static bool g_restricted_content_read_uleb128(const GRestrictedContent *, vmpa2t
/* Lit un nombre signé encodé au format LEB128. */
static bool g_restricted_content_read_leb128(const GRestrictedContent *, vmpa2t *, leb128_t *);
-
-
-/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
-
-
/* Charge un contenu depuis une mémoire tampon. */
static bool g_restricted_content_load(GRestrictedContent *, GObjectStorage *, packed_buffer_t *);
@@ -154,9 +124,7 @@ static bool g_restricted_content_store(const GRestrictedContent *, GObjectStorag
/* Indique le type défini par la GLib pour les contenus de données. */
-G_DEFINE_TYPE_WITH_CODE(GRestrictedContent, g_restricted_content, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_restricted_content_interface_init)
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_restricted_content_serializable_init));
+G_DEFINE_TYPE(GRestrictedContent, g_restricted_content, G_TYPE_BIN_CONTENT);
/******************************************************************************
@@ -174,88 +142,53 @@ G_DEFINE_TYPE_WITH_CODE(GRestrictedContent, g_restricted_content, G_TYPE_OBJECT,
static void g_restricted_content_class_init(GRestrictedContentClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GBinContentClass *content; /* Version parente de la classe*/
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_restricted_content_dispose;
object->finalize = (GObjectFinalizeFunc)g_restricted_content_finalize;
-}
+ content = G_BIN_CONTENT_CLASS(klass);
+ content->set_attribs = (set_content_attributes)g_restricted_content_set_attributes;
+ content->get_attribs = (get_content_attributes)g_restricted_content_get_attributes;
-/******************************************************************************
-* *
-* Paramètres : content = instance à initialiser. *
-* *
-* Description : Initialise une instance de contenu de données binaires. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ content->get_root = (get_content_root_fc)g_restricted_content_get_root;
-static void g_restricted_content_init(GRestrictedContent *content)
-{
- vmpa2t dummy; /* Localisation nulle */
+ content->describe = (describe_content_fc)g_restricted_content_describe;
- content->internal = NULL;
+ content->compute_checksum = (compute_checksum_fc)g_restricted_content_compute_checksum;
- init_vmpa(&dummy, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
- init_mrange(&content->range, &dummy, 0);
+ content->compute_size = (compute_size_fc)g_restricted_content_compute_size;
+ content->compute_start_pos = (compute_start_pos_fc)g_restricted_content_compute_start_pos;
+ content->compute_end_pos = (compute_end_pos_fc)g_restricted_content_compute_end_pos;
-}
+ content->seek = (seek_fc)g_restricted_content_seek;
+ content->get_raw_access = (get_raw_access_fc)g_restricted_content_get_raw_access;
-/******************************************************************************
-* *
-* Paramètres : iface = interface GLib à initialiser. *
-* *
-* Description : Procède à l'initialisation de l'interface de lecture. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_restricted_content_interface_init(GBinContentInterface *iface)
-{
- iface->set_attribs = (set_content_attributes)g_restricted_content_set_attributes;
- iface->get_attribs = (get_content_attributes)g_restricted_content_get_attributes;
-
- iface->get_root = (get_content_root_fc)g_restricted_content_get_root;
+ content->read_raw = (read_raw_fc)g_restricted_content_read_raw;
+ content->read_u4 = (read_u4_fc)g_restricted_content_read_u4;
+ content->read_u8 = (read_u8_fc)g_restricted_content_read_u8;
+ content->read_u16 = (read_u16_fc)g_restricted_content_read_u16;
+ content->read_u32 = (read_u32_fc)g_restricted_content_read_u32;
+ content->read_u64 = (read_u64_fc)g_restricted_content_read_u64;
- iface->describe = (describe_content_fc)g_restricted_content_describe;
+ content->read_uleb128 = (read_uleb128_fc)g_restricted_content_read_uleb128;
+ content->read_leb128 = (read_leb128_fc)g_restricted_content_read_leb128;
- iface->compute_checksum = (compute_checksum_fc)g_restricted_content_compute_checksum;
-
- iface->compute_size = (compute_size_fc)g_restricted_content_compute_size;
- iface->compute_start_pos = (compute_start_pos_fc)g_restricted_content_compute_start_pos;
- iface->compute_end_pos = (compute_end_pos_fc)g_restricted_content_compute_end_pos;
-
- iface->seek = (seek_fc)g_restricted_content_seek;
-
- iface->get_raw_access = (get_raw_access_fc)g_restricted_content_get_raw_access;
-
- iface->read_raw = (read_raw_fc)g_restricted_content_read_raw;
- iface->read_u4 = (read_u4_fc)g_restricted_content_read_u4;
- iface->read_u8 = (read_u8_fc)g_restricted_content_read_u8;
- iface->read_u16 = (read_u16_fc)g_restricted_content_read_u16;
- iface->read_u32 = (read_u32_fc)g_restricted_content_read_u32;
- iface->read_u64 = (read_u64_fc)g_restricted_content_read_u64;
-
- iface->read_uleb128 = (read_uleb128_fc)g_restricted_content_read_uleb128;
- iface->read_leb128 = (read_leb128_fc)g_restricted_content_read_leb128;
+ content->load = (load_content_cb)g_restricted_content_load;
+ content->store = (store_content_cb)g_restricted_content_store;
}
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
+* Paramètres : content = instance à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de sérialisation. *
+* Description : Initialise une instance de contenu de données binaires. *
* *
* Retour : - *
* *
@@ -263,10 +196,14 @@ static void g_restricted_content_interface_init(GBinContentInterface *iface)
* *
******************************************************************************/
-static void g_restricted_content_serializable_init(GSerializableObjectInterface *iface)
+static void g_restricted_content_init(GRestrictedContent *content)
{
- iface->load = (load_serializable_object_cb)g_restricted_content_load;
- iface->store = (store_serializable_object_cb)g_restricted_content_store;
+ vmpa2t dummy; /* Localisation nulle */
+
+ content->internal = NULL;
+
+ init_vmpa(&dummy, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+ init_mrange(&content->range, &dummy, 0);
}
@@ -313,8 +250,8 @@ static void g_restricted_content_finalize(GRestrictedContent *content)
/******************************************************************************
* *
-* Paramètres : content = contenu binaire où puiser les données à fournir. *
-* range = espace de restrictions pour les accès. *
+* Paramètres : internal = contenu binaire où puiser les données à fournir. *
+* range = espace de restrictions pour les accès. *
* *
* Description : Charge en mémoire le contenu d'un contenu restreint. *
* *
@@ -324,47 +261,47 @@ static void g_restricted_content_finalize(GRestrictedContent *content)
* *
******************************************************************************/
-GBinContent *g_restricted_content_new(GBinContent *content, const mrange_t *range)
+GBinContent *g_restricted_content_new(GBinContent *internal, const mrange_t *range)
{
- GRestrictedContent *result; /* Structure à retourner */
+ GBinContent *result; /* Structure à retourner */
result = g_object_new(G_TYPE_RESTRICTED_CONTENT, NULL);
- result->internal = content;
- g_object_ref(G_OBJECT(result->internal));
+ if (!g_restricted_content_create(G_RESTRICTED_CONTENT(result), internal, range))
+ g_clear_object(&result);
- copy_mrange(&result->range, range);
-
- return G_BIN_CONTENT(result);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : content = contenu binaire où puiser les données à fournir. *
-* range = espace de restrictions pour les accès. *
+* Paramètres : content = instance à initialiser pleinement. *
+* base = contenu binaire d'où réaliser une extraction. *
+* path = chemin vers le contenu finalement ciblé. *
+* endpoint = contenu final rendu accessible. *
* *
-* Description : Charge en mémoire le contenu d'un contenu restreint. *
+* Description : Met en place un contenu restreint de données brutes. *
* *
-* Retour : Représentation de contenu à manipuler ou NULL en cas d'échec.*
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GBinContent *g_restricted_content_new_ro(const GBinContent *content, const mrange_t *range)
+bool g_restricted_content_create(GRestrictedContent *content, GBinContent *internal, const mrange_t *range)
{
- GRestrictedContent *result; /* Structure à retourner */
+ bool result; /* Bilan à retourner */
- result = g_object_new(G_TYPE_RESTRICTED_CONTENT, NULL);
+ content->internal = internal;
+ g_object_ref(G_OBJECT(content->internal));
- result->internal = (GBinContent *)content;
- g_object_ref(G_OBJECT(result->internal));
+ copy_mrange(&content->range, range);
- copy_mrange(&result->range, range);
+ result = true;
- return G_BIN_CONTENT(result);
+ return result;
}
@@ -1027,12 +964,6 @@ static bool g_restricted_content_read_leb128(const GRestrictedContent *content,
}
-
-/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION ET RECHARGEMENT DES DONNEES */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
* Paramètres : content = élément GLib à constuire. *
diff --git a/src/analysis/contents/restricted.h b/src/analysis/contents/restricted.h
index 402282a..1cea390 100644
--- a/src/analysis/contents/restricted.h
+++ b/src/analysis/contents/restricted.h
@@ -53,9 +53,6 @@ GType g_restricted_content_get_type(void);
/* Charge en mémoire le contenu d'un contenu restreint. */
GBinContent *g_restricted_content_new(GBinContent *, const mrange_t *);
-/* Charge en mémoire le contenu d'un contenu restreint. */
-GBinContent *g_restricted_content_new_ro(const GBinContent *, const mrange_t *);
-
/* Indique l'espace de restriction appliqué à un contenu. */
void g_restricted_content_get_range(const GRestrictedContent *, mrange_t *);
diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am
index 8f8242c..b9325e0 100644
--- a/src/analysis/db/Makefile.am
+++ b/src/analysis/db/Makefile.am
@@ -21,20 +21,16 @@ libanalysisdb_la_SOURCES = \
server.h server.c \
snapshot.h snapshot.c
+libanalysisdb_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS) $(LIBSSL_CFLAGS)
+
libanalysisdb_la_LIBADD = \
items/libanalysisdbitems.la \
misc/libanalysisdbmisc.la
-libanalysisdb_la_LDFLAGS = $(LIBSSL_LIBS)
-
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisdb_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS) $(LIBSSL_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = items misc
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index b1e47bc..6d4b84d 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -38,8 +38,8 @@
#include <sys/stat.h>
-#include <i18n.h>
#include <config.h>
+#include <i18n.h>
#include "backend-int.h"
diff --git a/src/analysis/db/items/Makefile.am b/src/analysis/db/items/Makefile.am
index b9ce117..f8f70d5 100644
--- a/src/analysis/db/items/Makefile.am
+++ b/src/analysis/db/items/Makefile.am
@@ -7,18 +7,9 @@ libanalysisdbitems_la_SOURCES = \
move.h move.c \
switcher.h switcher.c
-libanalysisdbitems_la_LIBADD =
-
-libanalysisdbitems_la_LDFLAGS =
+libanalysisdbitems_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBSQLITE_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisdbitems_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index da7a4c0..fb27f60 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -39,9 +39,9 @@
#include "../../human/asm/lang.h"
#include "../../../common/array.h"
#include "../../../common/extstr.h"
+#include "../../../core/columns.h"
#include "../../../glibext/gbinarycursor.h"
#include "../../../glibext/linegen-int.h"
-#include "../../../gtkext/gtkblockdisplay.h"
diff --git a/src/analysis/db/items/move.c b/src/analysis/db/items/move.c
index af1c8c1..e4f503b 100644
--- a/src/analysis/db/items/move.c
+++ b/src/analysis/db/items/move.c
@@ -35,9 +35,13 @@
#include "../collection-int.h"
#include "../item-int.h"
-#include "../../../gui/core/global.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../../../gui/core/global.h"
+#endif
#include "../../../glibext/gbinarycursor.h"
-#include "../../../glibext/gloadedpanel.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../../../glibext/gloadedpanel.h"
+#endif
@@ -410,6 +414,8 @@ static char *g_db_move_build_label(GDbMove *move)
static bool g_db_move_run(const GDbMove *move, GLineCursor *cursor)
{
+#ifdef INCLUDE_GTK_SUPPORT
+
GLoadedPanel *panel; /* Afficheur effectif de code */
typedef struct _move_params
@@ -465,6 +471,8 @@ static bool g_db_move_run(const GDbMove *move, GLineCursor *cursor)
if (panel != NULL)
g_object_unref(G_OBJECT(panel));
+#endif
+
return true;
}
diff --git a/src/analysis/db/misc/Makefile.am b/src/analysis/db/misc/Makefile.am
index 6d4af6c..fc3cab2 100644
--- a/src/analysis/db/misc/Makefile.am
+++ b/src/analysis/db/misc/Makefile.am
@@ -6,18 +6,7 @@ libanalysisdbmisc_la_SOURCES = \
snapshot.h snapshot.c \
timestamp.h timestamp.c
-libanalysisdbmisc_la_LIBADD =
-
-libanalysisdbmisc_la_LDFLAGS =
-
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisdbmisc_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/analysis/disass/Makefile.am b/src/analysis/disass/Makefile.am
index 5631468..fe840c6 100644
--- a/src/analysis/disass/Makefile.am
+++ b/src/analysis/disass/Makefile.am
@@ -15,14 +15,9 @@ libanalysisdisass_la_SOURCES = \
rank.h rank.c \
routines.h routines.c
-libanalysisdisass_la_LDFLAGS =
+libanalysisdisass_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisdisass_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/src/analysis/disass/area.h b/src/analysis/disass/area.h
index 12c4617..0817419 100644
--- a/src/analysis/disass/area.h
+++ b/src/analysis/disass/area.h
@@ -30,7 +30,7 @@
#include "../../format/preload.h"
#include "../../format/symbol.h"
#include "../../glibext/delayed.h"
-#include "../../gtkext/gtkstatusstack.h"
+#include "../../glibext/notifier.h"
diff --git a/src/analysis/disass/block.c b/src/analysis/disass/block.c
index ea1441f..e15b4c1 100644
--- a/src/analysis/disass/block.c
+++ b/src/analysis/disass/block.c
@@ -34,9 +34,9 @@
#include "../block-int.h"
#include "../../arch/instructions/raw.h"
#include "../../common/extstr.h"
+#include "../../core/columns.h"
#include "../../core/params.h"
#include "../../glibext/gbinarycursor.h"
-#include "../../gtkext/gtkblockdisplay.h"
@@ -88,12 +88,16 @@ static block_link_t *g_basic_block_get_sources(const GBasicBlock *, const GBlock
/* Fournit les détails des destinations de bloc de code. */
static block_link_t *g_basic_block_get_destinations(const GBasicBlock *, const GBlockList *, size_t *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit la représentation graphique d'un bloc de code. */
static GBufferView *g_basic_block_build_view(const GBasicBlock *, segcnt_list *);
/* Construit un ensemble d'indications pour bloc. */
static char *g_basic_block_build_tooltip(const GBasicBlock *);
+#endif
+
/* ---------------------------------------------------------------------------------- */
@@ -133,8 +137,10 @@ static void g_basic_block_class_init(GBasicBlockClass *class)
block->cmp_links = (block_compare_links_fc)g_basic_block_compare_links;
block->get_src = (block_get_links_fc)g_basic_block_get_sources;
block->get_dest = (block_get_links_fc)g_basic_block_get_destinations;
+#ifdef INCLUDE_GTK_SUPPORT
block->build = (block_build_view_fc)g_basic_block_build_view;
block->build_tooltip = (block_build_tooltip_fc)g_basic_block_build_tooltip;
+#endif
}
@@ -466,6 +472,9 @@ static block_link_t *g_basic_block_get_destinations(const GBasicBlock *block, co
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : block = bloc de code à manipuler. *
@@ -856,6 +865,9 @@ static char *g_basic_block_build_tooltip(const GBasicBlock *block)
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : block = bloc d'instructions à consulter. *
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index 4056c59..4baa810 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -38,11 +38,11 @@
#include "routines.h"
#include "../human/asm/lang.h"
#include "../../arch/storage.h"
+#include "../../core/columns.h"
#include "../../core/global.h"
#include "../../core/params.h"
#include "../../core/nproc.h"
#include "../../glibext/generators/prologue.h"
-#include "../../gtkext/gtkblockdisplay.h"
#include "../../plugins/pglist.h"
@@ -391,7 +391,9 @@ void output_disassembly(GLoadedBinary *binary, GProcContext *context, GtkStatusS
GBinContent *content; /* Contenu bianire manipulé */
GCodingLanguage *lang; /* Langage de sortie préféré */
int offset; /* Décalage des étiquettes */
+#ifdef INCLUDE_GTK_SUPPORT
GWidthTracker *tracker; /* Gestionnaire de largeurs */
+#endif
char **text; /* Contenu brute à imprimer */
char *desc; /* Désignation du binaire */
const gchar *checksum; /* Identifiant de binaire */
@@ -409,9 +411,11 @@ void output_disassembly(GLoadedBinary *binary, GProcContext *context, GtkStatusS
g_generic_config_get_value(get_main_configuration(), MPK_LABEL_OFFSET, &offset);
+#ifdef INCLUDE_GTK_SUPPORT
tracker = g_buffer_cache_get_width_tracker(*cache);
g_width_tracker_set_column_min_width(tracker, DLC_ASSEMBLY_LABEL, offset);
g_object_unref(G_OBJECT(tracker));
+#endif
g_buffer_cache_wlock(*cache);
diff --git a/src/analysis/disass/fetch.h b/src/analysis/disass/fetch.h
index 7afabc6..44b5424 100644
--- a/src/analysis/disass/fetch.h
+++ b/src/analysis/disass/fetch.h
@@ -27,7 +27,7 @@
#include "../binary.h"
#include "../../glibext/delayed.h"
-#include "../../gtkext/gtkstatusstack.h"
+#include "../../glibext/notifier.h"
diff --git a/src/analysis/disass/instructions.h b/src/analysis/disass/instructions.h
index c0cd4ac..24fe982 100644
--- a/src/analysis/disass/instructions.h
+++ b/src/analysis/disass/instructions.h
@@ -28,7 +28,7 @@
#include "../routine.h"
#include "../../arch/processor.h"
#include "../../format/executable.h"
-#include "../../gtkext/gtkstatusstack.h"
+#include "../../glibext/notifier.h"
diff --git a/src/analysis/disass/limit.c b/src/analysis/disass/limit.c
index 1e460e0..2caefd6 100644
--- a/src/analysis/disass/limit.c
+++ b/src/analysis/disass/limit.c
@@ -76,7 +76,7 @@ void compute_routine_limit(GBinSymbol *symbol, const vmpa2t *next, GArchProcesso
/* Dans tous les cas, on va se référer à la portion contenante... */
- portion = g_binary_portion_find_at_addr(portions, &addr, (GdkRectangle []) { { 0 } });
+ portion = g_binary_portion_find_at_addr(portions, &addr);
assert(portion != NULL);
range = g_binary_portion_get_range(portion);
diff --git a/src/analysis/disass/output.h b/src/analysis/disass/output.h
index 20729d2..2213840 100644
--- a/src/analysis/disass/output.h
+++ b/src/analysis/disass/output.h
@@ -29,7 +29,7 @@
#include "../human/lang.h"
#include "../../format/preload.h"
#include "../../glibext/buffercache.h"
-#include "../../gtkext/gtkstatusstack.h"
+#include "../../glibext/notifier.h"
diff --git a/src/analysis/disass/routines.h b/src/analysis/disass/routines.h
index 9a2c308..af8e814 100644
--- a/src/analysis/disass/routines.h
+++ b/src/analysis/disass/routines.h
@@ -27,7 +27,7 @@
#include "../binary.h"
#include "../routine.h"
-#include "../../gtkext/gtkstatusstack.h"
+#include "../../glibext/notifier.h"
diff --git a/src/analysis/human/Makefile.am b/src/analysis/human/Makefile.am
index bd5fa9f..a8e98e6 100644
--- a/src/analysis/human/Makefile.am
+++ b/src/analysis/human/Makefile.am
@@ -6,19 +6,15 @@ libanalysishuman_la_SOURCES = \
lang-int.h \
lang.h lang.c
+libanalysishuman_la_CFLAGS = $(TOOLKIT_CFLAGS)
+
libanalysishuman_la_LIBADD = \
asm/libanalysishumanasm.la
-libanalysishuman_la_LDFLAGS =
-
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysishuman_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = asm
diff --git a/src/analysis/human/asm/Makefile.am b/src/analysis/human/asm/Makefile.am
index 9dbf717..a3ab6a4 100644
--- a/src/analysis/human/asm/Makefile.am
+++ b/src/analysis/human/asm/Makefile.am
@@ -5,18 +5,9 @@ noinst_LTLIBRARIES = libanalysishumanasm.la
libanalysishumanasm_la_SOURCES = \
lang.h lang.c
-libanalysishumanasm_la_LIBADD =
-
-libanalysishumanasm_la_LDFLAGS =
+libanalysishumanasm_la_CFLAGS = $(TOOLKIT_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysishumanasm_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/analysis/loaded-int.h b/src/analysis/loaded-int.h
index 62534a6..245b5ef 100644
--- a/src/analysis/loaded-int.h
+++ b/src/analysis/loaded-int.h
@@ -48,6 +48,8 @@ typedef bool (* analyze_loaded_fc) (GLoadedContent *, bool, bool, wgroup_id_t, G
/* Fournit le désignation associée à l'élément chargé. */
typedef char * (* describe_loaded_fc) (const GLoadedContent *, bool);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Détermine le nombre de vues disponibles pour un contenu. */
typedef unsigned int (* count_loaded_views_fc) (const GLoadedContent *);
@@ -66,6 +68,8 @@ typedef unsigned int (* get_loaded_view_index_fc) (GLoadedContent *, GtkWidget *
/* Fournit toutes les options d'affichage pour un contenu. */
typedef GDisplayOptions * (* get_loaded_options_fc) (const GLoadedContent *, unsigned int);
+#endif
+
/* Accès à un contenu binaire quelconque (instance) */
struct _GLoadedContent
@@ -91,6 +95,8 @@ struct _GLoadedContentClass
describe_loaded_fc describe; /* Description de contenu */
+#ifdef INCLUDE_GTK_SUPPORT
+
count_loaded_views_fc count_views; /* Compteur de vues */
get_loaded_view_name_fc get_view_name; /* Désignation d'une vue donnée*/
build_loaded_def_view_fc build_def_view;/* Mise en place initiale */
@@ -99,6 +105,8 @@ struct _GLoadedContentClass
get_loaded_options_fc get_options; /* Obtention de liste d'options*/
+#endif
+
/* Signaux */
void (* analyzed) (GLoadedContent *, gboolean);
diff --git a/src/analysis/loaded.c b/src/analysis/loaded.c
index 9ec2f74..9a7b1fd 100644
--- a/src/analysis/loaded.c
+++ b/src/analysis/loaded.c
@@ -32,8 +32,10 @@
#include "../core/global.h"
#include "../core/queue.h"
#include "../glibext/chrysamarshal.h"
-#include "../glibext/gloadedpanel.h"
-#include "../glibext/named-int.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../glibext/gloadedpanel.h"
+# include "../glibext/named-int.h"
+#endif
#include "../glibext/seq.h"
#include "../plugins/pglist.h"
@@ -60,9 +62,13 @@ static void g_loaded_content_class_init(GLoadedContentClass *);
/* Initialise un contenu chargé. */
static void g_loaded_content_init(GLoadedContent *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Procède à l'initialisation de l'interface de composant nommé. */
static void g_loaded_content_named_init(GNamedWidgetIface *);
+#endif
+
/* Supprime toutes les références externes. */
static void g_loaded_content_dispose(GLoadedContent *);
@@ -89,8 +95,12 @@ static void on_loaded_content_analysis_completed(GSeqWork *, analysis_data_t *);
/* Détermine le type d'une interface pour l'intégration de contenu chargé. */
+#ifdef INCLUDE_GTK_SUPPORT
G_DEFINE_TYPE_WITH_CODE(GLoadedContent, g_loaded_content, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_NAMED_WIDGET, g_loaded_content_named_init));
+#else
+G_DEFINE_TYPE(GLoadedContent, g_loaded_content, G_TYPE_OBJECT);
+#endif
/******************************************************************************
@@ -143,6 +153,9 @@ static void g_loaded_content_init(GLoadedContent *content)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
@@ -163,6 +176,9 @@ static void g_loaded_content_named_init(GNamedWidgetIface *iface)
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : content = instance d'objet GLib à traiter. *
@@ -577,6 +593,9 @@ char **g_loaded_content_detect_obfuscators(const GLoadedContent *content, bool v
/* ---------------------------------------------------------------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : content = contenu chargé à consulter. *
@@ -745,12 +764,18 @@ GDisplayOptions *g_loaded_content_get_display_options(const GLoadedContent *cont
}
+#endif
+
+
/* ---------------------------------------------------------------------------------- */
/* VUES ET BASCULEMENT ENTRE LES VUES */
/* ---------------------------------------------------------------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : panel = panneau affichant un contenu binaire. *
@@ -866,3 +891,6 @@ GtkWidget *get_loaded_panel_from_built_view(GtkWidget *view)
return result;
}
+
+
+#endif
diff --git a/src/analysis/loaded.h b/src/analysis/loaded.h
index 406375c..0f627b1 100644
--- a/src/analysis/loaded.h
+++ b/src/analysis/loaded.h
@@ -27,13 +27,17 @@
#include <glib-object.h>
#include <stdbool.h>
-#include <gtk/gtk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gtk/gtk.h>
+#endif
#include "content.h"
#include "../common/xml.h"
#include "../glibext/gdisplayoptions.h"
-#include "../gtkext/gtkdockstation.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../gtkext/gtkdockstation.h"
+#endif
@@ -87,6 +91,8 @@ char **g_loaded_content_detect_obfuscators(const GLoadedContent *, bool, size_t
/* --------------------------- GESTION DYNAMIQUE DES VUES --------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Détermine le nombre de vues disponibles pour un contenu. */
unsigned int g_loaded_content_count_views(const GLoadedContent *);
@@ -105,11 +111,15 @@ unsigned int g_loaded_content_get_view_index(GLoadedContent *, GtkWidget *);
/* Fournit toutes les options d'affichage pour un contenu. */
GDisplayOptions *g_loaded_content_get_display_options(const GLoadedContent *, unsigned int);
+#endif
+
/* ----------------------- VUES ET BASCULEMENT ENTRE LES VUES ----------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit la station d'accueil d'un panneau d'affichage. */
GtkDockStation *get_dock_station_for_view_panel(GtkWidget *);
@@ -119,6 +129,8 @@ GtkWidget *get_scroll_window_for_view_panel(GtkWidget *);
/* Fournit le panneau chargé inclus dans un affichage. */
GtkWidget *get_loaded_panel_from_built_view(GtkWidget *);
+#endif
+
#endif /* _ANALYSIS_LOADED_H */
diff --git a/src/analysis/project.c b/src/analysis/project.c
index 682dfb9..9a5e4e2 100644
--- a/src/analysis/project.c
+++ b/src/analysis/project.c
@@ -1365,6 +1365,9 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
/* ---------------------------------------------------------------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : - *
@@ -1437,3 +1440,6 @@ void push_project_into_recent_list(const GStudyProject *project)
g_generic_config_set_value(get_main_configuration(), MPK_LAST_PROJECT, project->filename);
}
+
+
+#endif
diff --git a/src/analysis/project.h b/src/analysis/project.h
index e8c6365..a5b1a73 100644
--- a/src/analysis/project.h
+++ b/src/analysis/project.h
@@ -25,7 +25,9 @@
#define _ANALYSIS_PROJECT_H
-#include <gtk/gtk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gtk/gtk.h>
+#endif
#include "loaded.h"
@@ -115,12 +117,16 @@ GLoadedContent **g_study_project_get_contents(GStudyProject *, size_t *);
/* ------------------------- GESTION GLOBALISEE DES PROJETS ------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit le gestionnaire des projets connus. */
GtkRecentManager *get_project_manager(void);
/* Place un projet au sommet de la pile des projets récents. */
void push_project_into_recent_list(const GStudyProject *);
+#endif
+
#endif /* _PROJECT_H */
diff --git a/src/analysis/routine.c b/src/analysis/routine.c
index 41bf451..2cb4ad3 100644
--- a/src/analysis/routine.c
+++ b/src/analysis/routine.c
@@ -37,9 +37,9 @@
#include "routine-int.h"
#include "../arch/instructions/raw.h"
#include "../common/extstr.h"
+#include "../core/columns.h"
#include "../core/params.h"
#include "../glibext/gbinarycursor.h"
-#include "../gtkext/gtkblockdisplay.h"
@@ -1047,6 +1047,8 @@ void g_binary_routine_print_code(const GBinRoutine *routine, GLangOutput *lang,
+#ifdef INCLUDE_GTK_SUPPORT
+
/******************************************************************************
* *
@@ -1334,3 +1336,6 @@ char *g_binary_routine_build_tooltip(const GBinRoutine *routine, const GLoadedBi
return result;
}
+
+
+#endif
diff --git a/src/analysis/routine.h b/src/analysis/routine.h
index f148406..ac33fbd 100644
--- a/src/analysis/routine.h
+++ b/src/analysis/routine.h
@@ -133,10 +133,13 @@ char *g_binary_routine_to_string(const GBinRoutine *, bool);
+#ifdef INCLUDE_GTK_SUPPORT
/* Construit un petit résumé concis de la routine. */
char *g_binary_routine_build_tooltip(const GBinRoutine *, const GLoadedBinary *);
+#endif
+
#endif /* _ANALYSIS_ROUTINE_H */
diff --git a/src/analysis/scan/Makefile.am b/src/analysis/scan/Makefile.am
new file mode 100644
index 0000000..f7e85ad
--- /dev/null
+++ b/src/analysis/scan/Makefile.am
@@ -0,0 +1,67 @@
+
+BUILT_SOURCES = grammar.h
+
+
+# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS
+# afin de conserver des noms de fichiers simples, ie sans le nom de la
+# bibliothèque de sortie en préfixe.
+
+AM_YFLAGS = -v -d -p rost_ -Wno-yacc -Wcounterexamples
+
+AM_LFLAGS = -b -Cf -P rost_ -o lex.yy.c --header-file=tokens.h \
+ -Dyyget_lineno=rost_get_lineno \
+ -Dyy_scan_bytes=rost__scan_bytes \
+ -Dyy_delete_buffer=rost__delete_buffer
+
+noinst_LTLIBRARIES = libanalysisscan.la
+
+
+libanalysisscan_la_SOURCES = \
+ cond-int.h \
+ cond.h cond.c \
+ context-int.h \
+ context.h context.c \
+ core.h core.c \
+ expr-int.h \
+ expr.h expr.c \
+ item-int.h \
+ item.h item.c \
+ matches-int.h \
+ matches.h matches.c \
+ options-int.h \
+ options.h options.c \
+ pattern-int.h \
+ pattern.h pattern.c \
+ rule-int.h \
+ rule.h rule.c \
+ scanner-int.h \
+ scanner.h scanner.c \
+ scope-int.h \
+ scope.h scope.c \
+ space-int.h \
+ space.h space.c \
+ tokens.l \
+ grammar.y
+
+libanalysisscan_la_LIBADD = \
+ exprs/libanalysisscanexprs.la \
+ items/libanalysisscanitems.la \
+ matches/libanalysisscanmatches.la \
+ patterns/libanalysisscanpatterns.la
+
+libanalysisscan_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscan_la_SOURCES:%c=)
+
+
+# Automake fait les choses à moitié
+CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
+
+# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions !
+EXTRA_DIST = tokens.h
+
+
+SUBDIRS = exprs items matches patterns
diff --git a/src/analysis/scan/cond-int.h b/src/analysis/scan/cond-int.h
new file mode 100644
index 0000000..aeb3fc9
--- /dev/null
+++ b/src/analysis/scan/cond-int.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cond-int.h - prototypes internes pour le parcours de contenus à la recherche de motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_COND_INT_H
+#define _ANALYSIS_SCAN_COND_INT_H
+
+
+#include "cond.h"
+
+
+
+/* Indique le statut d'une condition de validation. */
+typedef bool (* resolve_cond_fc) (const GMatchCondition *);
+
+/* Indique le statut d'une condition de validation. */
+typedef unsigned long long (* resolve_cond_as_number_fc) (const GMatchCondition *);
+
+/* Avance vers la validation d'une condition, si besoin est. */
+typedef void (* analyze_cond_fc) (const GMatchCondition *, const bin_t *, phys_t, phys_t, bool);
+
+
+
+/* Expression conditionnelle manipulant des motifs (instance) */
+struct _GMatchCondition
+{
+ GObject parent; /* A laisser en premier */
+
+};
+
+/* Expression conditionnelle manipulant des motifs (classe) */
+struct _GMatchConditionClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ resolve_cond_fc resolve; /* Réduction en booléen */
+ resolve_cond_as_number_fc resolve_as_num; /* Réduction en nombre */
+ analyze_cond_fc analyze; /* Analyse selon une position */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_COND_INT_H */
diff --git a/src/analysis/scan/cond.c b/src/analysis/scan/cond.c
new file mode 100644
index 0000000..be5b3cb
--- /dev/null
+++ b/src/analysis/scan/cond.c
@@ -0,0 +1,220 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cond.c - expression conditionnelle validant la présence de motifs donnés
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "cond.h"
+
+
+#include "cond-int.h"
+
+
+
+/* Initialise la classe des recherches dans du binaire. */
+static void g_match_condition_class_init(GMatchConditionClass *);
+
+/* Initialise une instance de recherche dans du binaire. */
+static void g_match_condition_init(GMatchCondition *);
+
+/* Supprime toutes les références externes. */
+static void g_match_condition_dispose(GMatchCondition *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_match_condition_finalize(GMatchCondition *);
+
+
+
+/* Indique le type défini pour une expression de validation. */
+G_DEFINE_TYPE(GMatchCondition, g_match_condition, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des recherches dans du binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_condition_class_init(GMatchConditionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ klass->resolve = NULL;
+ klass->resolve_as_num = NULL;
+ klass->analyze = NULL;
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_match_condition_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_match_condition_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cond = instance à initialiser. *
+* *
+* Description : Initialise une instance de recherche dans du binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_condition_init(GMatchCondition *cond)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cond = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_condition_dispose(GMatchCondition *cond)
+{
+ G_OBJECT_CLASS(g_match_condition_parent_class)->dispose(G_OBJECT(cond));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cond = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_match_condition_finalize(GMatchCondition *cond)
+{
+ G_OBJECT_CLASS(g_match_condition_parent_class)->finalize(G_OBJECT(cond));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cond = condition à consulter. *
+* *
+* Description : Indique le statut d'une condition de validation. *
+* *
+* Retour : Validation de la condition considérée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_match_condition_resolve(const GMatchCondition *cond)
+{
+ bool result; /* Bilan à retourner */
+ GMatchConditionClass *class; /* Classe à activer */
+ unsigned long long number; /* Valeur à considérer */
+
+ class = G_MATCH_CONDITION_GET_CLASS(cond);
+
+ if (class->resolve != NULL)
+ result = class->resolve(cond);
+
+ else if (class->resolve_as_num != NULL)
+ {
+ number = class->resolve_as_num(cond);
+ result = (number > 0);
+ }
+
+ else
+ result = false;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cond = condition à consulter. *
+* *
+* Description : Indique le statut d'une condition de validation. *
+* *
+* Retour : Forme numérique de la condition considérée pour validation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+unsigned long long g_match_condition_resolve_as_number(const GMatchCondition *cond)
+{
+ unsigned long long result; /* Valeur à retourner */
+ GMatchConditionClass *class; /* Classe à activer */
+
+ class = G_MATCH_CONDITION_GET_CLASS(cond);
+
+ result = class->resolve_as_num(cond);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cond = condition à considérer. *
+* data = données binaires brutes à considérer. *
+* size = quantité de ces données. *
+* pos = position du point d'étude courant. *
+* full = force une recherche pleine et entière. *
+* *
+* Description : Avance vers la validation d'une condition, si besoin est. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_match_condition_analyze(const GMatchCondition *cond, const bin_t *data, phys_t size, phys_t pos, bool full)
+{
+ GMatchConditionClass *class; /* Classe à activer */
+
+ class = G_MATCH_CONDITION_GET_CLASS(cond);
+
+ class->analyze(cond, data, size, pos, full);
+
+}
diff --git a/src/analysis/scan/cond.h b/src/analysis/scan/cond.h
new file mode 100644
index 0000000..7a5d3c4
--- /dev/null
+++ b/src/analysis/scan/cond.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cond.h - prototypes pour l'expression conditionnelle validant la présence de motifs donnés
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_COND_H
+#define _ANALYSIS_SCAN_COND_H
+
+
+#include <glib-object.h>
+
+
+#include "../../arch/archbase.h"
+#include "../../arch/vmpa.h"
+
+
+
+#define G_TYPE_MATCH_CONDITION g_match_condition_get_type()
+#define G_MATCH_CONDITION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_MATCH_CONDITION, GMatchCondition))
+#define G_IS_MATCH_CONDITION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_MATCH_CONDITION))
+#define G_MATCH_CONDITION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_MATCH_CONDITION, GMatchConditionClass))
+#define G_IS_MATCH_CONDITION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_MATCH_CONDITION))
+#define G_MATCH_CONDITION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_MATCH_CONDITION, GMatchConditionClass))
+
+
+/* Expression conditionnelle manipulant des motifs (instance) */
+typedef struct _GMatchCondition GMatchCondition;
+
+/* Expression conditionnelle manipulant des motifs (classe) */
+typedef struct _GMatchConditionClass GMatchConditionClass;
+
+
+/* Indique le type défini pour une expression de validation. */
+GType g_match_condition_get_type(void);
+
+/* Indique le statut d'une condition de validation. */
+bool g_match_condition_resolve(const GMatchCondition *);
+
+/* Indique le statut d'une condition de validation. */
+unsigned long long g_match_condition_resolve_as_number(const GMatchCondition *);
+
+/* Avance vers la validation d'une condition, si besoin est. */
+void g_match_condition_analyze(const GMatchCondition *, const bin_t *, phys_t, phys_t, bool);
+
+
+
+#endif /* _ANALYSIS_SCAN_COND_H */
diff --git a/src/analysis/scan/context-int.h b/src/analysis/scan/context-int.h
new file mode 100644
index 0000000..6135201
--- /dev/null
+++ b/src/analysis/scan/context-int.h
@@ -0,0 +1,100 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * context-int.h - prototypes internes pour un suivi d'analyses via contextes
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_CONTEXT_INT_H
+#define _ANALYSIS_SCAN_CONTEXT_INT_H
+
+
+#include "context.h"
+
+
+#include "expr.h"
+#include "../../common/fnv1a.h"
+#include "../../glibext/umemslice.h"
+
+
+//#define __USE_TABLE_FOR_MATCHES
+
+
+#ifndef __USE_TABLE_FOR_MATCHES
+
+/* Lien entre un motif et ses correspondances */
+typedef struct _matched_pattern_t
+{
+ const GSearchPattern *pattern; /* Motif recherché */
+ GScanMatches *matches; /* Correspondances associées */
+
+} matched_pattern_t;
+
+#endif
+
+/* Condition définissant une règle de correspondance */
+typedef struct _rule_condition_t
+{
+ char *name; /* Désignation de la règle */
+ fnv64_t name_hash; /* Empreinte de la désignation */
+
+ GScanExpression *expr; /* Condition de correspondance */
+ bool final_reduced; /* Réduction finale tentée ? */
+
+} rule_condition_t;
+
+/* Contexte de suivi d'une analyse en cours (instance) */
+struct _GScanContext
+{
+ GObject parent; /* A laisser en premier */
+
+ GScanOptions *options; /* Options d'analyses */
+
+ GBinContent *content; /* Contenu binaire traité */
+ bool scan_done; /* Phase d'analyse terminée ? */
+
+ GUMemSlice *match_allocator; /* Suivi de correspondances */
+ match_area_t **match_storages; /* Suivi de correspondances */
+ size_t storages_count; /* Quantité de ces suivis */
+
+#ifdef __USE_TABLE_FOR_MATCHES
+ GHashTable *full_trackers; /* Correspondances confirmées */
+#else
+ matched_pattern_t *full_trackers; /* Correspondances confirmées */
+ size_t full_allocated; /* Quantité d'éléments alloués */
+ size_t full_count; /* Quantité de correspondances */
+#endif
+
+ bool global; /* Validation globale */
+
+ rule_condition_t *conditions; /* Ensemble de règles suivies */
+ size_t cond_count; /* Quantité de ces conditions */
+
+};
+
+/* Contexte de suivi d'une analyse en cours (classe) */
+struct _GScanContextClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_CONTEXT_INT_H */
diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c
new file mode 100644
index 0000000..7929f9c
--- /dev/null
+++ b/src/analysis/scan/context.c
@@ -0,0 +1,841 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * context.c - suivi d'analyses via contextes
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "context.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "context-int.h"
+#include "exprs/literal.h"
+#include "matches/area.h"
+#include "matches/bytes.h"
+#include "../../common/sort.h"
+
+
+
+/* --------------------- MEMORISATION DE PROGRESSIONS D'ANALYSE --------------------- */
+
+
+/* Initialise la classe des contextes de suivi d'analyses. */
+static void g_scan_context_class_init(GScanContextClass *);
+
+/* Initialise une instance de contexte de suivi d'analyse. */
+static void g_scan_context_init(GScanContext *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_context_dispose(GScanContext *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_context_finalize(GScanContext *);
+
+#ifndef __USE_TABLE_FOR_MATCHES
+
+/* Compare un lien entre motif et correspondances avec un autre. */
+static int compare_matched_pattern(const matched_pattern_t *, const matched_pattern_t *);
+
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MEMORISATION DE PROGRESSIONS D'ANALYSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un contexte de suivi d'analyse. */
+G_DEFINE_TYPE(GScanContext, g_scan_context, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des contextes de suivi d'analyses. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_context_class_init(GScanContextClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_context_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_context_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à initialiser. *
+* *
+* Description : Initialise une instance de contexte de suivi d'analyse. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_context_init(GScanContext *context)
+{
+ context->options = NULL;
+
+ context->content = NULL;
+ context->scan_done = false;
+
+ context->match_allocator = g_umem_slice_new(sizeof(match_area_t));
+ context->match_storages = NULL;
+ context->storages_count = 0;
+
+#ifdef __USE_TABLE_FOR_MATCHES
+ context->full_trackers = g_hash_table_new_full(NULL, NULL, NULL/*g_object_unref*/, g_object_unref);
+#else
+ context->full_trackers = NULL;
+ context->full_allocated = 0;
+ context->full_count = 0;
+#endif
+
+ context->global = true;
+
+ context->conditions = NULL;
+ context->cond_count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_context_dispose(GScanContext *context)
+{
+#ifndef __USE_TABLE_FOR_MATCHES
+ matched_pattern_t *iter; /* Boucle de parcours #1 */
+ matched_pattern_t *max; /* Borne de fin de parcours */
+#endif
+ size_t i; /* Boucle de parcours #2 */
+
+ g_clear_object(&context->options);
+
+ g_clear_object(&context->content);
+
+ g_clear_object(&context->match_allocator);
+
+ if (context->full_trackers != NULL)
+ {
+#ifdef __USE_TABLE_FOR_MATCHES
+
+ g_hash_table_destroy(context->full_trackers);
+ context->full_trackers = NULL;
+
+#else
+
+ iter = context->full_trackers;
+ max = iter + context->full_count;
+
+ for (; iter < max; iter++)
+ g_object_unref(G_OBJECT(iter->matches));
+
+ free(context->full_trackers);
+ context->full_trackers = NULL;
+
+#endif
+
+ }
+
+ for (i = 0; i < context->cond_count; i++)
+ g_clear_object(&context->conditions[i].expr);
+
+ G_OBJECT_CLASS(g_scan_context_parent_class)->dispose(G_OBJECT(context));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_context_finalize(GScanContext *context)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (context->match_storages != NULL)
+ free(context->match_storages);
+
+ if (context->conditions != NULL)
+ {
+ for (i = 0; i < context->cond_count; i++)
+ free(context->conditions[i].name);
+
+ free(context->conditions);
+
+ }
+
+ G_OBJECT_CLASS(g_scan_context_parent_class)->finalize(G_OBJECT(context));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à respecter. *
+* *
+* Description : Définit un contexte pour suivi d'analyse. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanContext *g_scan_context_new(GScanOptions *options)
+{
+ GScanContext *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_CONTEXT, NULL);
+
+ result->options = options;
+ g_object_ref(G_OBJECT(options));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à consulter. *
+* *
+* Description : Fournit l'ensemble des options à respecter pour les analyses.*
+* *
+* Retour : Ensemble d'options en vigueur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanOptions *g_scan_context_get_options(const GScanContext *context)
+{
+ GScanOptions *result; /* Ensemble à retourner */
+
+ result = context->options;
+
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à consulter. *
+* content = contenu binaire en cours d'analyse. *
+* ids_count = nombre d'identifiants enregistrés. *
+* *
+* Description : Définit le contenu principal à analyser. *
+* *
+* Retour : Content binaire associé au context. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_context_set_content(GScanContext *context, GBinContent *content, size_t ids_count)
+{
+ g_clear_object(&context->content);
+
+ context->content = content;
+
+ g_object_ref(G_OBJECT(content));
+
+ context->match_storages = calloc(ids_count, sizeof(match_area_t *));
+ context->storages_count = ids_count;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à consulter. *
+* *
+* Description : Fournit une référence au contenu principal analysé. *
+* *
+* Retour : Content binaire associé au context. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBinContent *g_scan_context_get_content(const GScanContext *context)
+{
+ GBinContent *result; /* Instance à retourner */
+
+ result = context->content;
+
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à consulter. *
+* *
+* Description : Indique si la phase d'analyse de contenu est terminée. *
+* *
+* Retour : true si la phase de scan est terminée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_context_is_scan_done(const GScanContext *context)
+{
+ bool result; /* Statut à retourner */
+
+ result = context->scan_done;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à mettre à jour. *
+* *
+* Description : Note que la phase d'analyse de contenu est terminée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_context_mark_scan_as_done(GScanContext *context)
+{
+ context->scan_done = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à mettre à jour. *
+* id = identifiant du motif trouvé. *
+* end = position finale d'une correspondance partielle. *
+* *
+* Description : Retourne tous les correspondances partielles notées. *
+* *
+* Retour : Liste interne des localisations conservées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_context_store_atom_match_end(GScanContext *context, patid_t id, phys_t end)
+{
+ match_area_t *new; /* Nouvel enregistrement */
+
+ new = g_umem_slice_alloc(context->match_allocator);
+
+ new->end = end + 1;
+
+ add_tail_match_area(new, &context->match_storages[id]);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à mettre à jour. *
+* id = identifiant du motif trouvé. *
+* *
+* Description : Retourne tous les correspondances partielles notées. *
+* *
+* Retour : Liste interne des localisations conservées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+match_area_t *g_scan_context_get_atom_matches(const GScanContext *context, patid_t id)
+{
+ match_area_t *result; /* Liste constituée à renvoyer */
+
+ result = context->match_storages[id];
+
+ return result;
+
+}
+
+
+#ifndef __USE_TABLE_FOR_MATCHES
+
+/******************************************************************************
+* *
+* Paramètres : a = premier lien motif/correspondances à comparer. *
+* b = second lien motif/correspondances à comparer. *
+* *
+* Description : Compare un lien entre motif et correspondances avec un autre.*
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_matched_pattern(const matched_pattern_t *a, const matched_pattern_t *b)
+{
+ int result; /* Bilan à renvoyer */
+
+ assert(sizeof(unsigned long) == sizeof(void *));
+
+ result = sort_unsigned_long((unsigned long)a->pattern, (unsigned long)b->pattern);
+
+ return result;
+
+}
+
+#endif
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à mettre à jour. *
+* pattern = definition initiale d'un motif recherché. *
+* matches = mémorisation de correspondances établies. *
+* *
+* Description : Enregistre toutes les correspondances établies pour un motif.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_context_register_full_matches(GScanContext *context, GSearchPattern *pattern, GScanMatches *matches)
+{
+#ifndef NDEBUG
+ GSearchPattern *matches_pattern; /* Clef d'un suivi */
+#endif
+#ifndef __USE_TABLE_FOR_MATCHES
+ matched_pattern_t new; /* Nouvel enregistrement */
+#endif
+
+#ifndef NDEBUG
+
+ matches_pattern = g_scan_matches_get_source(matches);
+
+ assert(matches_pattern == pattern);
+
+ g_object_unref(G_OBJECT(matches_pattern));
+
+#endif
+
+#ifdef __USE_TABLE_FOR_MATCHES
+
+ assert(!g_hash_table_contains(context->full_trackers, pattern));
+
+ //g_object_ref(G_OBJECT(pattern)); /* TODO : REMME */
+ g_object_ref(G_OBJECT(matches));
+
+ g_hash_table_insert(context->full_trackers, pattern, matches);
+
+#else
+
+ new.pattern = pattern;
+ new.matches = matches;
+
+ g_object_ref(G_OBJECT(matches));
+
+ context->full_trackers = qinsert_managed(context->full_trackers, &context->full_count, &context->full_allocated,
+ sizeof(matched_pattern_t), (__compar_fn_t)compare_matched_pattern,
+ &new);
+
+#endif
+
+ g_scan_matches_attach(matches, context, pattern);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à mettre à jour. *
+* pattern = motif dont des correspondances sont à retrouver. *
+* *
+* Description : Fournit la liste de toutes les correspondances pour un motif.*
+* *
+* Retour : Liste courante de correspondances établies. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanMatches *g_scan_context_get_full_matches(const GScanContext *context, const GSearchPattern *pattern)
+{
+ GScanMatches *result; /* Correspondance à renvoyer */
+#ifndef __USE_TABLE_FOR_MATCHES
+ matched_pattern_t target; /* Lien ciblé */
+ matched_pattern_t *found; /* Lien trouvé */
+#endif
+
+#ifdef __USE_TABLE_FOR_MATCHES
+
+ result = g_hash_table_lookup(context->full_trackers, pattern);
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+#else
+
+ target.pattern = pattern;
+
+ found = bsearch(&target, context->full_trackers, context->full_count,
+ sizeof(matched_pattern_t), (__compar_fn_t)compare_matched_pattern);
+
+ if (found == NULL)
+ result = NULL;
+
+ else
+ {
+ result = found->matches;
+ g_object_ref(G_OBJECT(result));
+ }
+
+#endif
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = instance à mettre à jour. *
+* pattern = motif dont des correspondances sont à retrouver. *
+* *
+* Description : Dénombre les correspondances associées à un motif. *
+* *
+* Retour : Quantité de correspondances établies pour un motif entier. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_scan_context_count_full_matches(const GScanContext *context, const GSearchPattern *pattern)
+{
+ size_t result; /* Quantité à retourner */
+#ifdef __USE_TABLE_FOR_MATCHES
+ GScanMatches *matches; /* Ensemble de Correspondances */
+#else
+ matched_pattern_t target; /* Lien ciblé */
+ matched_pattern_t *found; /* Lien trouvé */
+#endif
+
+#ifdef __USE_TABLE_FOR_MATCHES
+
+ matches = g_hash_table_lookup(context->full_trackers, pattern);
+
+ if (matches != NULL)
+ result = g_scan_matches_count(matches);
+ else
+ result = 0;
+
+#else
+
+ target.pattern = pattern;
+
+ found = bsearch(&target, context->full_trackers, context->full_count,
+ sizeof(matched_pattern_t), (__compar_fn_t)compare_matched_pattern);
+
+ if (found == NULL)
+ result = 0;
+ else
+ result = g_scan_matches_count(found->matches);
+
+#endif
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = mémoire de résultats d'analyse à compléter. *
+* name = désignation de la règle ciblée. *
+* expr = expression de condition à réduire. *
+* *
+* Description : Intègre une condition de correspondance pour règle. *
+* *
+* Retour : Bilan final d'une intégration (false si nom déjà présent). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_context_set_rule_condition(GScanContext *context, const char *name, GScanExpression *expr)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ rule_condition_t *new; /* Nouvel élément à intégrer */
+
+ result = true;
+
+ /* Recherche d'antécédent */
+
+ for (i = 0; i < context->cond_count; i++)
+ if (strcmp(name, context->conditions[i].name) == 0)
+ {
+ result = false;
+ break;
+ }
+
+ /* Ajout d'un nouvel élément ? */
+
+ if (result)
+ {
+ context->conditions = realloc(context->conditions, ++context->cond_count * sizeof(rule_condition_t));
+
+ new = &context->conditions[context->cond_count - 1];
+
+ new->name = strdup(name);
+ new->name_hash = fnv_64a_hash(name);
+
+ new->expr = expr;
+ g_object_ref(G_OBJECT(expr));
+ new->final_reduced = false;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = mémoire de résultats d'analyse à consulter. *
+* name = désignation de la règle ciblée. *
+* *
+* Description : Indique si un nom donné correspond à une règle. *
+* *
+* Retour : Bilan de la présence d'une règle désignée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_context_has_rule_for_name(const GScanContext *context, const char *name)
+{
+ bool result; /* Bilan à retourner */
+ fnv64_t hash; /* Empreinte du nom à retrouver*/
+ size_t i; /* Boucle de parcours */
+ const rule_condition_t *cond; /* Condition connue du contexte*/
+
+ result = false;
+
+ hash = fnv_64a_hash(name);
+
+ for (i = 0; i < context->cond_count; i++)
+ {
+ cond = context->conditions + i;
+
+ if (cond->name_hash != hash)
+ continue;
+
+ if (strcmp(cond->name, name) == 0)
+ {
+ result = true;
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = mémoire de résultats d'analyse à consulter. *
+* *
+* Description : Indique le bilan des règles globales. *
+* *
+* Retour : Bilan global des analyses menées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_context_has_global_match(const GScanContext *context)
+{
+ bool result; /* Bilan global à retourner */
+
+ result = context->global;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = mémoire de résultats d'analyse à actualiser. *
+* global = bilan global des analyses menées. *
+* *
+* Description : Définit le bilan des règles globales. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_context_set_global_match(GScanContext *context, bool global)
+{
+ context->global = global;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : context = mémoire de résultats d'analyse à consulter. *
+* name = désignation de la règle ciblée. *
+* *
+* Description : Indique si une correspondance globale a pu être établie. *
+* *
+* Retour : Bilan final d'une analyse (false par défaut). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_context_has_match_for_rule(GScanContext *context, const char *name)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ rule_condition_t *cond; /* Condition à considérer */
+ GScanScope *scope; /* Définition de portées */
+ GScanExpression *new; /* Nouvelle expression réduite */
+ ScanReductionState state; /* Statut d'une réduction */
+ bool valid; /* Validité d'une récupération */
+
+ result = false;
+
+ if (!context->global)
+ goto exit;
+
+ /* Recherche de la règle visée */
+
+ cond = NULL;
+
+ for (i = 0; i < context->cond_count; i++)
+ if (strcmp(name, context->conditions[i].name) == 0)
+ {
+ cond = &context->conditions[i];
+ break;
+ }
+
+ if (cond == NULL)
+ goto exit;
+
+ /* Tentative de réduction finale */
+
+ if (!cond->final_reduced)
+ {
+ scope = g_scan_scope_new(name);
+
+ state = g_scan_expression_reduce(cond->expr, context, scope, &new);
+ if (state == SRS_UNRESOLVABLE) goto exit_reduction;
+
+ g_object_unref(G_OBJECT(cond->expr));
+ cond->expr = new;
+
+ valid = g_scan_expression_reduce_to_boolean(cond->expr, context, scope, &new);
+ if (!valid || new == NULL) goto exit_reduction;
+
+ g_object_unref(G_OBJECT(cond->expr));
+ cond->expr = new;
+
+ cond->final_reduced = true;
+
+ exit_reduction:
+
+ g_object_unref(G_OBJECT(scope));
+
+ }
+
+ /* Tentative de récupération d'un bilan final */
+
+ if (cond->final_reduced)
+ {
+ valid = g_scan_literal_expression_get_boolean_value(G_SCAN_LITERAL_EXPRESSION(cond->expr), &result);
+
+ if (!valid)
+ {
+ assert(!result);
+ result = false;
+ }
+
+ }
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/context.h b/src/analysis/scan/context.h
new file mode 100644
index 0000000..c3b979d
--- /dev/null
+++ b/src/analysis/scan/context.h
@@ -0,0 +1,111 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * context.h - prototypes pour le suivi d'analyses via contextes
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_CONTEXT_H
+#define _ANALYSIS_SCAN_CONTEXT_H
+
+
+#include <glib-object.h>
+
+
+#include "matches.h"
+#include "options.h"
+#include "matches/area.h"
+#include "patterns/patid.h"
+#include "../content.h"
+
+
+
+/* Depuis expr.h : expression d'évaluation généraliste (instance) */
+typedef struct _GScanExpression GScanExpression;
+
+
+#define G_TYPE_SCAN_CONTEXT g_scan_context_get_type()
+#define G_SCAN_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_CONTEXT, GScanContext))
+#define G_IS_SCAN_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_CONTEXT))
+#define G_SCAN_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_CONTEXT, GScanContextClass))
+#define G_IS_SCAN_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_CONTEXT))
+#define G_SCAN_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_CONTEXT, GScanContextClass))
+
+
+/* Contexte de suivi d'une analyse en cours (instance) */
+typedef struct _GScanContext GScanContext;
+
+/* Contexte de suivi d'une analyse en cours (classe) */
+typedef struct _GScanContextClass GScanContextClass;
+
+
+/* Indique le type défini pour un contexte de suivi d'analyse. */
+GType g_scan_context_get_type(void);
+
+/* Définit un contexte pour suivi d'analyse. */
+GScanContext *g_scan_context_new(GScanOptions *);
+
+/* Fournit l'ensemble des options à respecter pour les analyses. */
+GScanOptions *g_scan_context_get_options(const GScanContext *);
+
+/* Définit le contenu principal à analyser. */
+void g_scan_context_set_content(GScanContext *, GBinContent *, size_t);
+
+/* Fournit une référence au contenu principal analysé. */
+GBinContent *g_scan_context_get_content(const GScanContext *);
+
+/* Indique si la phase d'analyse de contenu est terminée. */
+bool g_scan_context_is_scan_done(const GScanContext *);
+
+/* Note que la phase d'analyse de contenu est terminée. */
+void g_scan_context_mark_scan_as_done(GScanContext *);
+
+/* Retourne tous les correspondances partielles notées. */
+void g_scan_context_store_atom_match_end(GScanContext *, patid_t, phys_t);
+
+/* Retourne tous les correspondances partielles notées. */
+match_area_t *g_scan_context_get_atom_matches(const GScanContext *, patid_t);
+
+/* Enregistre toutes les correspondances établies pour un motif. */
+void g_scan_context_register_full_matches(GScanContext *, GSearchPattern *, GScanMatches *);
+
+/* Fournit la liste de toutes les correspondances pour un motif. */
+GScanMatches *g_scan_context_get_full_matches(const GScanContext *, const GSearchPattern *);
+
+/* Dénombre les correspondances associées à un motif. */
+size_t g_scan_context_count_full_matches(const GScanContext *, const GSearchPattern *);
+
+/* Intègre une condition de correspondance pour règle. */
+bool g_scan_context_set_rule_condition(GScanContext *, const char *, GScanExpression *);
+
+/* Indique si un nom donné correspond à une règle. */
+bool g_scan_context_has_rule_for_name(const GScanContext *, const char *);
+
+/* Indique le bilan des règles globales. */
+bool g_scan_context_has_global_match(const GScanContext *);
+
+/* Définit le bilan des règles globales. */
+void g_scan_context_set_global_match(GScanContext *, bool);
+
+/* Indique si une correspondance globale a pu être établie. */
+bool g_scan_context_has_match_for_rule(GScanContext *, const char *);
+
+
+
+#endif /* _ANALYSIS_SCAN_CONTEXT_H */
diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c
new file mode 100644
index 0000000..2b4fd92
--- /dev/null
+++ b/src/analysis/scan/core.c
@@ -0,0 +1,385 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - enregistrement des fonctions principales
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "items/count.h"
+#include "items/datasize.h"
+#include "items/maxcommon.h"
+#include "items/modpath.h"
+#include "items/uint.h"
+#include "items/console/log.h"
+#ifdef INCLUDE_MAGIC_SUPPORT
+# include "items/magic/type.h"
+# include "items/magic/mime-encoding.h"
+# include "items/magic/mime-type.h"
+#endif
+#include "items/math/to_string.h"
+#include "items/string/lower.h"
+#include "items/string/to_int.h"
+#include "items/string/upper.h"
+#include "items/string/wide.h"
+#include "items/time/make.h"
+#include "items/time/now.h"
+#include "patterns/modifiers/hex.h"
+#include "patterns/modifiers/lower.h"
+#include "patterns/modifiers/plain.h"
+#include "patterns/modifiers/rev.h"
+#include "patterns/modifiers/upper.h"
+#include "patterns/modifiers/wide.h"
+#include "patterns/modifiers/xor.h"
+
+
+/* Liste des modificateurs disponibles */
+
+typedef struct _available_modifier_t
+{
+ sized_string_t name; /* Désignation humaine */
+ GScanTokenModifier *instance; /* Mécanisme correspondant */
+
+} available_modifier_t;
+
+static available_modifier_t *__modifiers = NULL;
+static size_t __modifiers_count = 0;
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à rendre disponible. *
+* *
+* Description : Inscrit un modificateur dans la liste des disponibles. *
+* *
+* Retour : Bilan des enregistrements effectués : true si nouveauté. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool register_scan_token_modifier(GScanTokenModifier *modifier)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t name; /* Nom donné au modificateur */
+ GScanTokenModifier *found; /* Alternative présente */
+ available_modifier_t *last; /* Emplacement disponible */
+
+ name.data = g_scan_token_modifier_get_name(modifier);
+ name.len = strlen(name.data);
+
+ found = find_scan_token_modifiers_for_name(&name);
+
+ result = (found == NULL);
+
+ if (!result)
+ exit_szstr(&name);
+
+ else
+ {
+ __modifiers_count++;
+ __modifiers = realloc(__modifiers, __modifiers_count * sizeof(available_modifier_t));
+
+ last = &__modifiers[__modifiers_count - 1];
+
+ last->name = name;
+ last->instance = modifier;
+
+ g_object_ref(G_OBJECT(modifier));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Charge tous les modificateurs de base. *
+* *
+* Retour : Bilan des opérations d'enregistrement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_all_known_scan_token_modifiers(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+#define REGISTER_SCAN_MODIFIER(m) \
+ ({ \
+ GScanTokenModifier *__mod; \
+ bool __status; \
+ __mod = m; \
+ __status = register_scan_token_modifier(__mod); \
+ g_object_unref(G_OBJECT(__mod)); \
+ __status; \
+ })
+
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_hex_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_lower_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_plain_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_reverse_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_upper_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_wide_modifier_new());
+ if (result) result = REGISTER_SCAN_MODIFIER(g_scan_xor_modifier_new());
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : count = nombre de motificateurs exportés. [OUT] *
+* *
+* Description : Fournit la désignation de l'ensemble des modificateurs. *
+* *
+* Retour : Liste de modificateurs enregistrés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char **list_all_scan_token_modifiers(size_t *count)
+{
+ char **result; /* Liste à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = malloc(__modifiers_count * sizeof(char *));
+
+ *count = __modifiers_count;
+
+ for (i = 0; i < __modifiers_count; i++)
+ result[i] = strndup(__modifiers[i].name.data, __modifiers[i].name.len);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Décharge tous les modificateurs inscrits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void unload_all_scan_token_modifiers(void)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < __modifiers_count; i++)
+ {
+ exit_szstr(&__modifiers[i].name);
+ g_object_unref(G_OBJECT(__modifiers[i].instance));
+ }
+
+ if (__modifiers != NULL)
+ free(__modifiers);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : name = désignation du modificateur recherché. *
+* *
+* Description : Fournit le modificateur correspondant à un nom. *
+* *
+* Retour : Instance du modificateur identifié ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *find_scan_token_modifiers_for_name(const sized_string_t *name)
+{
+ GScanTokenModifier *result; /* Instance à renvoyer */
+ size_t i; /* Boucle de parcours */
+ available_modifier_t *registered; /* Infos d'enregistrement */
+
+ result = NULL;
+
+ for (i = 0; i < __modifiers_count; i++)
+ {
+ registered = __modifiers + i;
+
+ if (registered->name.len != name->len)
+ continue;
+
+ if (strncmp(registered->name.data, name->data, name->len) == 0)
+ {
+ result = registered->instance;
+ g_object_ref(G_OBJECT(result));
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = espace de noms à composer. *
+* *
+* Description : Inscrit les principales fonctions dans l'espace racine. *
+* *
+* Retour : Bilan des enregistrements effectués. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_main_scan_namespace(GScanNamespace *space)
+{
+ bool result; /* Bilan à retourner */
+ GScanNamespace *ns; /* Nouvel espace de noms */
+
+ result = true;
+
+#define REGISTER_FUNC(s, f) \
+ ({ \
+ GScanRegisteredItem *__item; \
+ bool __result; \
+ __item = f; \
+ __result = g_scan_namespace_register_item(s, __item); \
+ g_object_unref(G_OBJECT(__item)); \
+ __result; \
+ })
+
+ if (result) result = REGISTER_FUNC(space, g_scan_count_function_new());
+ if (result) result = REGISTER_FUNC(space, g_scan_datasize_function_new());
+ if (result) result = REGISTER_FUNC(space, g_scan_maxcommon_function_new());
+ if (result) result = REGISTER_FUNC(space, g_scan_modpath_function_new());
+
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_8_BITS_SIGNED, SRE_LITTLE));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_8_BITS_UNSIGNED, SRE_LITTLE));
+
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_SIGNED, SRE_LITTLE));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_SIGNED, SRE_BIG));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_UNSIGNED, SRE_LITTLE));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_UNSIGNED, SRE_BIG));
+
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_SIGNED, SRE_LITTLE));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_SIGNED, SRE_BIG));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_UNSIGNED, SRE_LITTLE));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_UNSIGNED, SRE_BIG));
+
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_SIGNED, SRE_LITTLE));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_SIGNED, SRE_BIG));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_UNSIGNED, SRE_LITTLE));
+ if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_UNSIGNED, SRE_BIG));
+
+ /* Console */
+
+ if (result)
+ {
+ ns = g_scan_namespace_new("console");
+ result = g_scan_namespace_register_item(space, G_SCAN_REGISTERED_ITEM(ns));
+
+ if (result) result = REGISTER_FUNC(ns, g_scan_console_log_function_new());
+
+ g_object_unref(G_OBJECT(ns));
+
+ }
+
+ /* Magic */
+
+#ifdef INCLUDE_MAGIC_SUPPORT
+ if (result)
+ {
+ ns = g_scan_namespace_new("magic");
+ result = g_scan_namespace_register_item(space, G_SCAN_REGISTERED_ITEM(ns));
+
+ if (result) result = REGISTER_FUNC(ns, g_scan_magic_type_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_mime_encoding_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_mime_type_function_new());
+
+ g_object_unref(G_OBJECT(ns));
+
+ }
+#endif
+
+ /* Math */
+
+ if (result)
+ {
+ ns = g_scan_namespace_new("math");
+ result = g_scan_namespace_register_item(space, G_SCAN_REGISTERED_ITEM(ns));
+
+ if (result) result = REGISTER_FUNC(ns, g_scan_math_to_string_function_new());
+
+ g_object_unref(G_OBJECT(ns));
+
+ }
+
+ /* String */
+
+ if (result)
+ {
+ ns = g_scan_namespace_new("string");
+ result = g_scan_namespace_register_item(space, G_SCAN_REGISTERED_ITEM(ns));
+
+ if (result) result = REGISTER_FUNC(ns, g_scan_string_lower_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_string_to_int_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_string_upper_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_string_wide_function_new());
+
+ g_object_unref(G_OBJECT(ns));
+
+ }
+
+ /* Time */
+
+ if (result)
+ {
+ ns = g_scan_namespace_new("time");
+ result = g_scan_namespace_register_item(space, G_SCAN_REGISTERED_ITEM(ns));
+
+ if (result) result = REGISTER_FUNC(ns, g_scan_time_make_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_time_now_function_new());
+
+ g_object_unref(G_OBJECT(ns));
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/core.h b/src/analysis/scan/core.h
new file mode 100644
index 0000000..a56ce16
--- /dev/null
+++ b/src/analysis/scan/core.h
@@ -0,0 +1,53 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour l'enregistrement des fonctions principales
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_CORE_H
+#define _ANALYSIS_SCAN_CORE_H
+
+
+#include "space.h"
+#include "patterns/modifier.h"
+
+
+
+/* Inscrit un modificateur dans la liste des disponibles. */
+bool register_scan_token_modifier(GScanTokenModifier *);
+
+/* Charge tous les modificateurs de base. */
+bool load_all_known_scan_token_modifiers(void);
+
+/* Fournit la désignation de l'ensemble des modificateurs. */
+char **list_all_scan_token_modifiers(size_t *);
+
+/* Décharge tous les modificateurs inscrits. */
+void unload_all_scan_token_modifiers(void);
+
+/* Fournit le modificateur correspondant à un nom. */
+GScanTokenModifier *find_scan_token_modifiers_for_name(const sized_string_t *);
+
+/* Inscrit les principales fonctions dans l'espace racine. */
+bool populate_main_scan_namespace(GScanNamespace *);
+
+
+
+#endif /* _ANALYSIS_SCAN_CORE_H */
diff --git a/src/analysis/scan/decl.h b/src/analysis/scan/decl.h
new file mode 100644
index 0000000..ab70368
--- /dev/null
+++ b/src/analysis/scan/decl.h
@@ -0,0 +1,40 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * decl.h - déclarations de prototypes utiles
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_DECL_H
+#define _ANALYSIS_SCAN_DECL_H
+
+
+#include <stdbool.h>
+
+
+#include "scanner.h"
+
+
+
+/* Complète une recherche de motifs avec des règles. */
+bool process_rules_definitions(GContentScanner *, const char *, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_DECL_H */
diff --git a/src/analysis/scan/expr-int.h b/src/analysis/scan/expr-int.h
new file mode 100644
index 0000000..618ecf7
--- /dev/null
+++ b/src/analysis/scan/expr-int.h
@@ -0,0 +1,88 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * expr-int.h - prototypes internes pour la définition d'une expression servant aux conditions de correspondance
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPR_INT_H
+#define _ANALYSIS_SCAN_EXPR_INT_H
+
+
+#include "expr.h"
+
+
+#include <stdbool.h>
+
+
+#include "../../glibext/comparison-int.h"
+
+
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+typedef bool (* compare_expr_rich_fc) (const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *);
+
+/* Réduit une expression à une forme plus simple. */
+typedef ScanReductionState (* reduce_expr_fc) (GScanExpression *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Réduit une expression à une forme booléenne. */
+typedef bool (* reduce_expr_to_bool_fc) (GScanExpression *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Dénombre les éléments portés par une expression. */
+typedef bool (* count_scan_expr_fc) (const GScanExpression *, GScanContext *, size_t *);
+
+/* Fournit un élément donné issu d'un ensemble constitué. */
+typedef bool (* get_scan_expr_fc) (const GScanExpression *, size_t, GScanContext *, GScanExpression **);
+
+/* Réalise l'intersection entre deux ensembles. */
+typedef GScanExpression * (* intersect_scan_expr_fc) (GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *);
+
+
+/* Expression d'évaluation généraliste (instance) */
+struct _GScanExpression
+{
+ GObject parent; /* A laisser en premier */
+
+ ScanReductionState state; /* Etat synthétisé de l'élément*/
+
+};
+
+/* Expression d'évaluation généraliste (classe) */
+struct _GScanExpressionClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ compare_expr_rich_fc cmp_rich; /* Comparaison de façon précise*/
+
+ reduce_expr_fc reduce; /* Simplification d'expression */
+ reduce_expr_to_bool_fc reduce_to_bool; /* Conversion en booléen */
+
+ count_scan_expr_fc count; /* Décompte d'éléments */
+ get_scan_expr_fc get; /* Extraction d'un élément */
+ intersect_scan_expr_fc intersect; /* Intersection entre ensembles*/
+
+};
+
+
+/* Met en place une expression d'évaluation pour analyse. */
+bool g_scan_expression_create(GScanExpression *, ScanReductionState);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPR_INT_H */
diff --git a/src/analysis/scan/expr.c b/src/analysis/scan/expr.c
new file mode 100644
index 0000000..332619d
--- /dev/null
+++ b/src/analysis/scan/expr.c
@@ -0,0 +1,638 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * expr.c - définition d'une expression servant aux conditions de correspondance
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "expr.h"
+
+
+#include <assert.h>
+
+
+#include "expr-int.h"
+#include "exprs/literal.h"
+#include "exprs/set.h"
+
+
+
+/* ----------------------- BASES D'OBJET POUR LE SYSTEME GLIB ----------------------- */
+
+
+/* Initialise la classe des expressions de validation. */
+static void g_scan_expression_class_init(GScanExpressionClass *);
+
+/* Initialise une instance d'expression de validation. */
+static void g_scan_expression_init(GScanExpression *);
+
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_scan_expression_cmp_interface_init(GComparableItemInterface *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_expression_dispose(GScanExpression *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_expression_finalize(GScanExpression *);
+
+/* Réalise l'intersection entre deux ensembles. */
+static GScanExpression *_g_scan_expression_intersect(GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *);
+
+
+
+/* ----------------------- INTERFACE OFFRANT DES COMPARAISONS ----------------------- */
+
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+static bool g_scan_expression_compare_rich(const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* BASES D'OBJET POUR LE SYSTEME GLIB */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une expression de validation. */
+G_DEFINE_TYPE_WITH_CODE(GScanExpression, g_scan_expression, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_ITEM, g_scan_expression_cmp_interface_init));
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des expressions de validation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_expression_class_init(GScanExpressionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_expression_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_expression_finalize;
+
+ klass->intersect = _g_scan_expression_intersect;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance à initialiser. *
+* *
+* Description : Initialise une instance d'expression de validation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_expression_init(GScanExpression *expr)
+{
+ expr->state = SRS_PENDING;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_expression_cmp_interface_init(GComparableItemInterface *iface)
+{
+ iface->cmp_rich = (compare_rich_fc)g_scan_expression_compare_rich;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_expression_dispose(GScanExpression *expr)
+{
+ G_OBJECT_CLASS(g_scan_expression_parent_class)->dispose(G_OBJECT(expr));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_expression_finalize(GScanExpression *expr)
+{
+ G_OBJECT_CLASS(g_scan_expression_parent_class)->finalize(G_OBJECT(expr));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance à initialiser pleinement. *
+* state = état de réduction initial associé par l'expression. *
+* *
+* Description : Met en place une expression d'évaluation pour analyse. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_expression_create(GScanExpression *expr, ScanReductionState state)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ expr->state = state;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* *
+* Description : Indique l'état de réduction d'une expression. *
+* *
+* Retour : Etat courant associé à l'expression. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanReductionState g_scan_expression_get_state(const GScanExpression *expr)
+{
+ ScanReductionState result; /* Etat à retourner */
+
+ result = expr->state;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanReductionState g_scan_expression_reduce(GScanExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ GScanExpressionClass *class; /* Classe à activer */
+
+ if (expr->state == SRS_REDUCED)
+ {
+ *out = expr;
+ g_object_ref(G_OBJECT(expr));
+ }
+
+ else
+ {
+ *out = NULL;
+
+ class = G_SCAN_EXPRESSION_GET_CLASS(expr);
+
+ if (class->reduce != NULL)
+ {
+ expr->state = class->reduce(expr, ctx, scope, out);
+
+ if (expr->state != SRS_UNRESOLVABLE && *out == NULL)
+ {
+ *out = expr;
+ g_object_ref(G_OBJECT(expr));
+ }
+
+ }
+
+ else
+ expr->state = SRS_UNRESOLVABLE;
+
+#ifndef NDEBUG
+ if (*out != NULL)
+ assert(expr->state != SRS_UNRESOLVABLE);
+#endif
+
+ }
+
+ assert(expr->state != SRS_PENDING);
+
+
+ return expr->state;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme booléenne. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_expression_reduce_to_boolean(GScanExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanExpression *inter; /* Expression intermédiaire */
+ GScanExpressionClass *class; /* Classe à activer */
+
+ *out = NULL;
+
+ result = g_scan_expression_reduce(expr, ctx, scope, &inter);
+ if (!result) goto exit;
+
+ if (inter != NULL)
+ {
+ class = G_SCAN_EXPRESSION_GET_CLASS(inter);
+
+ if (class->reduce_to_bool != NULL)
+ result = class->reduce_to_bool(inter, ctx, scope, out);
+ else
+ result = false;
+
+ g_object_unref(G_OBJECT(inter));
+
+ /* Validation d'un type booléen */
+ if (result && *out != NULL)
+ {
+ if (!G_IS_SCAN_LITERAL_EXPRESSION(*out))
+ {
+ g_clear_object(out);
+ result = false;
+ }
+
+ if (g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(*out)) != LVT_BOOLEAN)
+ {
+ g_clear_object(out);
+ result = false;
+ }
+
+ }
+
+ }
+
+ exit:
+
+#ifndef NDEBUG
+ if (*out != NULL)
+ assert(result);
+#endif
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* *
+* Description : Détermine si l'expression peut représenter un ensemble. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_expression_handle_set_features(const GScanExpression *expr)
+{
+ bool result; /* Bilan à retourner */
+ GScanExpressionClass *class; /* Classe à activer */
+
+ class = G_SCAN_EXPRESSION_GET_CLASS(expr);
+
+ result = (class->count != NULL);
+
+ assert((result && (class->get != NULL)) || (!result && (class->get == NULL)));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* count = quantité d'éléments déterminée. [OUT] *
+* *
+* Description : Dénombre les éléments portés par une expression. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_expression_count_items(const GScanExpression *expr, GScanContext *ctx, size_t *count)
+{
+ bool result; /* Bilan à retourner */
+ GScanExpressionClass *class; /* Classe à activer */
+
+ *count = -1;
+
+ class = G_SCAN_EXPRESSION_GET_CLASS(expr);
+
+ if (class->count != NULL)
+ result = class->count(expr, ctx, count);
+ else
+ result = false;
+
+#ifndef NDEBUG
+ if (*count != -1)
+ assert(result);
+#endif
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* index = indice de l'élément à transférer. *
+* ctx = contexte de suivi de l'analyse courante. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Fournit un élément donné issu d'un ensemble constitué. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_expression_get_item(const GScanExpression *expr, size_t index, GScanContext *ctx, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanExpressionClass *class; /* Classe à activer */
+
+ *out = NULL;
+
+ class = G_SCAN_EXPRESSION_GET_CLASS(expr);
+
+ if (class->get != NULL)
+ {
+ result = class->get(expr, index, ctx, out);
+
+ if (*out != NULL)
+ g_object_ref(G_OBJECT(*out));
+
+ }
+
+ else
+ result = false;
+
+#ifndef NDEBUG
+ if (*out != NULL)
+ assert(result);
+#endif
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à filtrer. *
+* other = expression utilisée pour le filtrage. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* *
+* Description : Réalise l'intersection entre deux ensembles. *
+* *
+* Retour : Intersection entre les deux ensembles ou NULL en cas d'échec.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GScanExpression *_g_scan_expression_intersect(GScanExpression *expr, const GScanExpression *other, GScanContext *ctx, GScanScope *scope)
+{
+ GScanExpression *result; /* Instance à retourner */
+ size_t other_count; /* Taille du second ensemble */
+ bool valid; /* Bilan de validité */
+ size_t expr_count; /* Taille du premier ensemble */
+ size_t k; /* Boucle de parcours #1 */
+ GComparableItem *comparable; /* Premier élément à comparer */
+ size_t i; /* Boucle de parcours #2 */
+ GScanExpression *item; /* Elément à comparer */
+ bool status; /* Bilan d'une comparaison */
+
+ result = NULL;
+
+ valid = g_scan_expression_count_items(other, ctx, &other_count);
+ if (!valid) goto done;
+
+ /* Intersection entre deux ensembles ? */
+ if (g_scan_expression_handle_set_features(expr))
+ {
+ valid = g_scan_expression_count_items(expr, ctx, &expr_count);
+ if (!valid) goto done;
+
+ result = g_scan_generic_set_new();
+
+ for (k = 0; k < expr_count; k++)
+ {
+ valid = g_scan_expression_get_item(expr, k, ctx, &item);
+ if (!valid) break;
+
+ comparable = G_COMPARABLE_ITEM(item);
+
+ for (i = 0; i < other_count; i++)
+ {
+ valid = g_scan_expression_get_item(other, i, ctx, &item);
+ if (!valid) break;
+
+ valid = g_comparable_item_compare_rich(comparable, G_COMPARABLE_ITEM(item), RCO_EQ, &status);
+
+ if (valid && status)
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(result), item);
+
+ g_object_unref(G_OBJECT(item));
+
+ }
+
+ g_object_unref(G_OBJECT(comparable));
+
+ }
+
+ }
+
+ /* Intersection entre un élément et un ensemble */
+ else
+ {
+ comparable = G_COMPARABLE_ITEM(expr);
+
+ for (i = 0; i < other_count && result == NULL; i++)
+ {
+ valid = g_scan_expression_get_item(other, i, ctx, &item);
+ if (!valid) break;
+
+ valid = g_comparable_item_compare_rich(comparable, G_COMPARABLE_ITEM(item), RCO_EQ, &status);
+
+ if (valid && status)
+ result = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { true });
+
+ g_object_unref(G_OBJECT(item));
+
+ }
+
+ if (result && result == NULL)
+ result = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { false });
+
+ }
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à filtrer. *
+* other = expression utilisée pour le filtrage. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* *
+* Description : Réalise l'intersection entre deux ensembles. *
+* *
+* Retour : Intersection entre les deux ensembles ou NULL en cas d'échec.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_expression_intersect(GScanExpression *expr, const GScanExpression *other, GScanContext *ctx, GScanScope *scope)
+{
+ GScanExpression *result; /* Instance à retourner */
+ GScanExpressionClass *class; /* Classe à activer */
+
+ class = G_SCAN_EXPRESSION_GET_CLASS(expr);
+
+ result = class->intersect(expr, other, ctx, scope);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTERFACE OFFRANT DES COMPARAISONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = premier objet à cnsulter pour une comparaison. *
+* other = second objet à cnsulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_expression_compare_rich(const GScanExpression *item, const GScanExpression *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+ GScanExpressionClass *class; /* Classe à activer */
+
+ class = G_SCAN_EXPRESSION_GET_CLASS(item);
+
+ if (class->cmp_rich != NULL)
+ {
+ result = (G_TYPE_FROM_INSTANCE(item) == G_TYPE_FROM_INSTANCE(other)); // FIXME : subtype ? cf. literal ?
+
+ if (result)
+ result = class->cmp_rich(item, other, op, status);
+
+ }
+
+ else
+ result = false;
+
+ return result;
+
+}
diff --git a/src/analysis/scan/expr.h b/src/analysis/scan/expr.h
new file mode 100644
index 0000000..38cbac6
--- /dev/null
+++ b/src/analysis/scan/expr.h
@@ -0,0 +1,89 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * expr.h - prototypes pour la définition d'une expression servant aux conditions de correspondance
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPR_H
+#define _ANALYSIS_SCAN_EXPR_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "context.h"
+#include "scope.h"
+
+
+
+#define G_TYPE_SCAN_EXPRESSION g_scan_expression_get_type()
+#define G_SCAN_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_EXPRESSION, GScanExpression))
+#define G_IS_SCAN_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_EXPRESSION))
+#define G_SCAN_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_EXPRESSION, GScanExpressionClass))
+#define G_IS_SCAN_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_EXPRESSION))
+#define G_SCAN_EXPRESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_EXPRESSION, GScanExpressionClass))
+
+
+/* Expression d'évaluation généraliste (instance) */
+typedef struct _GScanExpression GScanExpression;
+
+/* Expression d'évaluation généraliste (classe) */
+typedef struct _GScanExpressionClass GScanExpressionClass;
+
+
+/* Etat de l'expression vis à vis des réductions */
+typedef enum _ScanReductionState
+{
+ SRS_PENDING, /* Nature à déterminer */
+ SRS_REDUCED, /* Nature compacte finale */
+ SRS_WAIT_FOR_SCAN, /* Nature vouée à évoluer */
+ SRS_UNRESOLVABLE, /* Nature indéterminable */
+
+} ScanReductionState;
+
+
+/* Indique le type défini pour une expression de validation. */
+GType g_scan_expression_get_type(void);
+
+/* Indique l'état de réduction d'une expression. */
+ScanReductionState g_scan_expression_get_state(const GScanExpression *);
+
+/* Réduit une expression à une forme plus simple. */
+ScanReductionState g_scan_expression_reduce(GScanExpression *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Réduit une expression à une forme booléenne. */
+bool g_scan_expression_reduce_to_boolean(GScanExpression *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Détermine si l'expression peut représenter un ensemble. */
+bool g_scan_expression_handle_set_features(const GScanExpression *);
+
+/* Dénombre les éléments portés par une expression. */
+bool g_scan_expression_count_items(const GScanExpression *, GScanContext *, size_t *);
+
+/* Fournit un élément donné issu d'un ensemble constitué. */
+bool g_scan_expression_get_item(const GScanExpression *, size_t, GScanContext *, GScanExpression **);
+
+/* Réalise l'intersection entre deux ensembles. */
+GScanExpression *g_scan_expression_intersect(GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPR_H */
diff --git a/src/analysis/scan/exprs/Makefile.am b/src/analysis/scan/exprs/Makefile.am
new file mode 100644
index 0000000..c97fa25
--- /dev/null
+++ b/src/analysis/scan/exprs/Makefile.am
@@ -0,0 +1,40 @@
+
+noinst_LTLIBRARIES = libanalysisscanexprs.la
+
+
+libanalysisscanexprs_la_SOURCES = \
+ access-int.h \
+ access.h access.c \
+ arithmetic-int.h \
+ arithmetic.h arithmetic.c \
+ call-int.h \
+ call.h call.c \
+ extract-int.h \
+ extract.h extract.c \
+ handler-int.h \
+ handler.h handler.c \
+ intersect-int.h \
+ intersect.h intersect.c \
+ item-int.h \
+ item.h item.c \
+ literal-int.h \
+ literal.h literal.c \
+ logical-int.h \
+ logical.h logical.c \
+ range-int.h \
+ range.h range.c \
+ relational-int.h \
+ relational.h relational.c \
+ set-int.h \
+ set.h set.c \
+ setcounter-int.h \
+ setcounter.h setcounter.c \
+ strop-int.h \
+ strop.h strop.c
+
+libanalysisscanexprs_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanexprs_la_SOURCES:%c=)
diff --git a/src/analysis/scan/exprs/access-int.h b/src/analysis/scan/exprs/access-int.h
new file mode 100644
index 0000000..be37241
--- /dev/null
+++ b/src/analysis/scan/exprs/access-int.h
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * access-int.h - prototypes internes pour l'accès à un élément d'expression sous-jacent
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H
+#define _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H
+
+
+#include "access.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Reproduit un accès en place dans une nouvelle instance. */
+typedef void (* copy_scan_access_fc) (GScanNamedAccess *, const GScanNamedAccess *);
+
+/* Accès à un élément d'expression sous-jacent (instance) */
+struct _GScanNamedAccess
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ union
+ {
+ GScanRegisteredItem *base; /* Base de recherche */
+ GScanRegisteredItem *resolved; /* Elément ciblé au final */
+ GObject *any; /* Accès indistinct */
+ };
+
+ char *target; /* Cible dans l'espace */
+
+ struct _GScanNamedAccess *next; /* Evnetuel prochain élément */
+
+};
+
+/* Accès à un élément d'expression sous-jacent (classe) */
+struct _GScanNamedAccessClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+ copy_scan_access_fc copy; /* Reproduction d'accès */
+
+};
+
+
+/* Met en place une expression d'accès. */
+bool g_scan_named_access_create(GScanNamedAccess *, const sized_string_t *);
+
+/* Prépare une réduction en menant une résolution locale. */
+GScanRegisteredItem *_g_scan_named_access_prepare_reduction(const GScanNamedAccess *, GScanContext *, GScanScope *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H */
diff --git a/src/analysis/scan/exprs/access.c b/src/analysis/scan/exprs/access.c
new file mode 100644
index 0000000..342c2d7
--- /dev/null
+++ b/src/analysis/scan/exprs/access.c
@@ -0,0 +1,508 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * access.c - accès à un élément d'expression sous-jacent
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "access.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "access-int.h"
+#include "literal.h"
+#include "../../../core/global.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des appels de fonction avec arguments. */
+static void g_scan_named_access_class_init(GScanNamedAccessClass *);
+
+/* Initialise une instance d'appel de fonction avec arguments. */
+static void g_scan_named_access_init(GScanNamedAccess *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_named_access_dispose(GScanNamedAccess *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_named_access_finalize(GScanNamedAccess *);
+
+/* Reproduit un accès en place dans une nouvelle instance. */
+static void g_scan_named_access_copy(GScanNamedAccess *, const GScanNamedAccess *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_named_access_reduce(const GScanNamedAccess *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un appel de fonction enregistrée. */
+G_DEFINE_TYPE(GScanNamedAccess, g_scan_named_access, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des appels de fonction avec arguments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_named_access_class_init(GScanNamedAccessClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_named_access_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_named_access_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)NULL;
+ expr->reduce = (reduce_expr_fc)g_scan_named_access_reduce;
+
+ klass->copy = g_scan_named_access_copy;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : access = instance à initialiser. *
+* *
+* Description : Initialise une instance d'appel de fonction avec arguments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_named_access_init(GScanNamedAccess *access)
+{
+ access->any = NULL;
+ access->target = NULL;
+
+ access->next = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : access = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_named_access_dispose(GScanNamedAccess *access)
+{
+ g_clear_object(&access->any);
+
+ g_clear_object(&access->next);
+
+ G_OBJECT_CLASS(g_scan_named_access_parent_class)->dispose(G_OBJECT(access));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : access = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_named_access_finalize(GScanNamedAccess *access)
+{
+ if (access->target != NULL)
+ free(access->target);
+
+ G_OBJECT_CLASS(g_scan_named_access_parent_class)->finalize(G_OBJECT(access));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de l'objet d'appel à identifier. *
+* *
+* Description : Organise un accès à un élément d'expression sous-jacent. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_named_access_new(const sized_string_t *target)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_NAMED_ACCESS, NULL);
+
+ if (!g_scan_named_access_create(G_SCAN_NAMED_ACCESS(result), target))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : access = instance à initialiser pleinement. *
+* target = désignation de l'objet d'appel à identifier. *
+* *
+* Description : Met en place une expression d'accès. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_named_access_create(GScanNamedAccess *access, const sized_string_t *target)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(access), SRS_PENDING);
+ if (!result) goto exit;
+
+ if (target != NULL)
+ access->target = strndup(target->data, target->len);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] *
+* src = expression source à copier. *
+* *
+* Description : Reproduit un accès en place dans une nouvelle instance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_named_access_copy(GScanNamedAccess *dest, const GScanNamedAccess *src)
+{
+ /**
+ * Les champs suivants sont voués à être remplacés ou supprimés.
+ *
+ * On évite donc une instanciation inutile.
+ */
+
+ /*
+ if (src->any != NULL)
+ {
+ dest->any = src->any;
+ g_object_ref(src->any);
+ }
+ */
+
+ if (src->target != NULL)
+ dest->target = strdup(src->target);
+
+ if (src->next != NULL)
+ {
+ dest->next = src->next;
+ g_object_ref(src->next);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : accès = expression d'accès à copier. *
+* resolved = nouvelle base à imposer. *
+* *
+* Description : Reproduit un accès en place dans une nouvelle instance. *
+* *
+* Retour : Nouvelle instance d'expression d'accès. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_named_access_duplicate(const GScanNamedAccess *access, GScanRegisteredItem *resolved)
+{
+ GScanExpression *result; /* Instance copiée à retourner */
+ GType type; /* Type d'objet à copier */
+ GScanNamedAccessClass *class; /* Classe à activer */
+
+ type = G_TYPE_FROM_INSTANCE(access);
+
+ result = g_object_new(type, NULL);
+
+ class = G_SCAN_NAMED_ACCESS_GET_CLASS(access);
+
+ class->copy(G_SCAN_NAMED_ACCESS(result), access);
+
+ g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(result), resolved);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : access = expression d'appel à actualiser. *
+* base = zone de recherche pour la résolution à venir. *
+* *
+* Description : Définit une base de recherche pour la cible d'accès. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_named_access_set_base(GScanNamedAccess *access, GScanRegisteredItem *base)
+{
+ g_clear_object(&access->base);
+
+ access->base = base;
+ g_object_ref(G_OBJECT(base));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : access = expression d'appel à compléter. *
+* next = expression d'appel suivante dans la chaîne. *
+* *
+* Description : Complète la chaine d'accès à des expressions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_named_access_attach_next(GScanNamedAccess *access, GScanNamedAccess *next)
+{
+ if (access->next != NULL)
+ g_scan_named_access_attach_next(access->next, next);
+
+ else
+ {
+ access->next = next;
+ g_object_ref(G_OBJECT(next));
+ }
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* *
+* Description : Prépare une réduction en menant une résolution locale. *
+* *
+* Retour : Elément résolu avec les moyens du bord ou NULL si échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *_g_scan_named_access_prepare_reduction(const GScanNamedAccess *expr, GScanContext *ctx, GScanScope *scope)
+{
+ GScanRegisteredItem *result; /* Etat synthétisé à retourner */
+ GScanRegisteredItem *base; /* Base de recherche courante */
+
+ result = NULL;
+
+ if (expr->target != NULL)
+ {
+ if (expr->base != NULL)
+ {
+ base = expr->base;
+ g_object_ref(G_OBJECT(base));
+ }
+ else
+ base = G_SCAN_REGISTERED_ITEM(get_rost_root_namespace());
+
+ g_scan_registered_item_resolve(base, expr->target, ctx, scope, &result);
+
+ g_object_unref(G_OBJECT(base));
+
+ }
+
+ /**
+ * Si plus aucune indication n'est diponible pour avancer dans les réductions,
+ * c'est que l'opération est déjà conclue.
+ */
+ else
+ {
+ assert(expr->resolved != NULL);
+
+ result = expr->resolved;
+ g_object_ref(G_OBJECT(result));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_named_access_reduce(const GScanNamedAccess *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanRegisteredItem *resolved; /* Cible concrète obtenue */
+ GScanExpression *new_next; /* Nouvelle version du suivant */
+ const char *current_rule; /* Nom de la règle courante */
+ bool status; /* Bilan d'une autre règle */
+
+ resolved = _g_scan_named_access_prepare_reduction(expr, ctx, scope);
+
+ if (resolved != NULL)
+ {
+ result = SRS_PENDING;
+
+ /**
+ * Si l'élément résolu se trouve en fin de chaîne, alors cet élément
+ * est sollicité pour obtenir une expression d'évaluation classique.
+ * Le produit de cette réduction finale bénéficie d'une promotion et
+ * représente à lui seul la réduction produite pour la chaîne.
+ */
+ if (expr->next == NULL)
+ {
+ status = g_scan_registered_item_reduce(resolved, ctx, scope, out);
+
+ result = (status ? SRS_REDUCED : SRS_UNRESOLVABLE);
+
+ }
+
+ /**
+ * Sinon, l'élément résolu constitue une base pour l'étage suivant de
+ * la chaîne de résolution.
+ */
+ else
+ {
+ new_next = g_scan_named_access_duplicate(expr->next, resolved);
+
+ result = g_scan_expression_reduce(new_next, ctx, scope, out);
+
+ g_object_unref(G_OBJECT(new_next));
+
+ }
+
+ g_object_unref(G_OBJECT(resolved));
+
+ }
+
+ /**
+ * Si le nom fournit le correspond à aucun élément de la grammaire,
+ * des recherches sont menées ailleurs.
+ */
+ else
+ {
+ result = SRS_UNRESOLVABLE;
+
+ if (g_scan_context_has_rule_for_name(ctx, expr->target))
+ {
+ current_rule = g_scan_scope_get_rule_name(scope);
+
+ /* Si référence circulaire il y a... */
+ if (strcmp(current_rule, expr->target) == 0)
+ result = SRS_UNRESOLVABLE;
+
+ else
+ {
+ status = g_scan_context_has_match_for_rule(ctx, expr->target);
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status);
+ result = SRS_REDUCED;
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/access.h b/src/analysis/scan/exprs/access.h
new file mode 100644
index 0000000..bf83dd0
--- /dev/null
+++ b/src/analysis/scan/exprs/access.h
@@ -0,0 +1,66 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * access.h - prototypes pour l'accès à un élément d'expression sous-jacent
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_ACCESS_H
+#define _ANALYSIS_SCAN_EXPRS_ACCESS_H
+
+
+#include "../expr.h"
+#include "../item.h"
+#include "../../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_NAMED_ACCESS g_scan_named_access_get_type()
+#define G_SCAN_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_NAMED_ACCESS, GScanNamedAccess))
+#define G_IS_SCAN_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_NAMED_ACCESS))
+#define G_SCAN_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_NAMED_ACCESS, GScanNamedAccessClass))
+#define G_IS_SCAN_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_NAMED_ACCESS))
+#define G_SCAN_NAMED_ACCESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_NAMED_ACCESS, GScanNamedAccessClass))
+
+
+/* Accès à un élément d'expression sous-jacent (instance) */
+typedef struct _GScanNamedAccess GScanNamedAccess;
+
+/* Accès à un élément d'expression sous-jacent (classe) */
+typedef struct _GScanNamedAccessClass GScanNamedAccessClass;
+
+
+/* Indique le type défini pour un appel de fonction enregistrée. */
+GType g_scan_named_access_get_type(void);
+
+/* Organise un accès à un élément d'expression sous-jacent. */
+GScanExpression *g_scan_named_access_new(const sized_string_t *);
+
+/* Reproduit un accès en place dans une nouvelle instance. */
+GScanExpression *g_scan_named_access_duplicate(const GScanNamedAccess *, GScanRegisteredItem *);
+
+/* Définit une base de recherche pour la cible d'accès. */
+void g_scan_named_access_set_base(GScanNamedAccess *, GScanRegisteredItem *);
+
+/* Complète la chaine d'accès à des expressions. */
+void g_scan_named_access_attach_next(GScanNamedAccess *, GScanNamedAccess *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_ACCESS_H */
diff --git a/src/analysis/scan/exprs/arithmetic-int.h b/src/analysis/scan/exprs/arithmetic-int.h
new file mode 100644
index 0000000..c5010b0
--- /dev/null
+++ b/src/analysis/scan/exprs/arithmetic-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * arithmetic-int.h - prototypes internes pour la gestion des opérations arithmétiques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMETIC_INT_H
+#define _ANALYSIS_SCAN_EXPRS_ARITHMETIC_INT_H
+
+
+#include "arithmetic.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Opération arithmétique impliquant deux opérandes (instance) */
+struct _GScanArithmeticOperation
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ ArithmeticExpressionOperator operator; /* Type d'opération menée */
+
+ GScanExpression *left; /* Expression impactée #1 */
+ GScanExpression *right; /* Expression impactée #2 */
+
+};
+
+/* Opération arithmétique impliquant deux opérandes (classe) */
+struct _GScanArithmeticOperationClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une opération arithmétique entre expressions. */
+bool g_scan_arithmetic_operation_create(GScanArithmeticOperation *, ArithmeticExpressionOperator, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMETIC_INT_H */
diff --git a/src/analysis/scan/exprs/arithmetic.c b/src/analysis/scan/exprs/arithmetic.c
new file mode 100644
index 0000000..06cfc48
--- /dev/null
+++ b/src/analysis/scan/exprs/arithmetic.c
@@ -0,0 +1,641 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * arithmetic.c - gestion des opérations arithmétiques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "arithmetic.h"
+
+
+#include <assert.h>
+
+
+#include "arithmetic-int.h"
+#include "literal.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des opérations arithmétiques. */
+static void g_scan_arithmetic_operation_class_init(GScanArithmeticOperationClass *);
+
+/* Initialise une instance d'opération arithmétique. */
+static void g_scan_arithmetic_operation_init(GScanArithmeticOperation *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_arithmetic_operation_dispose(GScanArithmeticOperation *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_arithmetic_operation_finalize(GScanArithmeticOperation *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+static bool g_scan_arithmetic_operation_compare_rich(const GScanArithmeticOperation *, const GScanArithmeticOperation *, RichCmpOperation, bool *);
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_arithmetic_operation_reduce(const GScanArithmeticOperation *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une opération de relation entre expressions. */
+G_DEFINE_TYPE(GScanArithmeticOperation, g_scan_arithmetic_operation, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des opérations arithmétiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_arithmetic_operation_class_init(GScanArithmeticOperationClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_arithmetic_operation_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_arithmetic_operation_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)g_scan_arithmetic_operation_compare_rich;
+ expr->reduce = (reduce_expr_fc)g_scan_arithmetic_operation_reduce;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser. *
+* *
+* Description : Initialise une instance d'opération arithmétique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_arithmetic_operation_init(GScanArithmeticOperation *op)
+{
+ op->left = NULL;
+ op->right = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_arithmetic_operation_dispose(GScanArithmeticOperation *op)
+{
+ g_clear_object(&op->left);
+ g_clear_object(&op->right);
+
+ G_OBJECT_CLASS(g_scan_arithmetic_operation_parent_class)->dispose(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_arithmetic_operation_finalize(GScanArithmeticOperation *op)
+{
+ G_OBJECT_CLASS(g_scan_arithmetic_operation_parent_class)->finalize(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operator = type d'opération arithmétique à représenter. *
+* left = premier opérande concerné. *
+* right = éventuel second opérande impliqué ou NULL. *
+* *
+* Description : Organise une opération arithmétique entre expressions. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_arithmetic_operation_new(ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_ARITHMETIC_OPERATION, NULL);
+
+ if (!g_scan_arithmetic_operation_create(G_SCAN_ARITHMETIC_OPERATION(result), operator, left, right))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser pleinement. *
+* operator = type d'opération booléenne à représenter. *
+* left = premier opérande concerné. *
+* right = éventuel second opérande impliqué ou NULL. *
+* *
+* Description : Met en place une opération arithmétique entre expressions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_arithmetic_operation_create(GScanArithmeticOperation *op, ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING);
+ if (!result) goto exit;
+
+ op->operator = operator;
+
+ op->left = left;
+ g_object_ref(G_OBJECT(op->left));
+
+ op->right = right;
+ g_object_ref(G_OBJECT(op->right));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_arithmetic_operation_compare_rich(const GScanArithmeticOperation *item, const GScanArithmeticOperation *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+
+ result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_SCAN_ARITHMETIC_OPERATION);
+ if (!result) goto done;
+
+ if (item->operator != other->operator)
+ {
+ result = compare_rich_integer_values_unsigned(item->operator, other->operator, op);
+ goto done;
+ }
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status);
+ if (!result || STATUS_NOT_EQUAL(*status, op)) goto done;
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->left),
+ G_COMPARABLE_ITEM(other->left),
+ op, status);
+ if (!result || STATUS_NOT_EQUAL(*status, op)) goto done;
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->right),
+ G_COMPARABLE_ITEM(other->right),
+ op, status);
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_arithmetic_operation_reduce(const GScanArithmeticOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanExpression *new_left; /* Expression réduite (gauche) */
+ GScanExpression *new_right; /* Expression réduite (droite) */
+ ScanReductionState state_left; /* Etat synthétisé #1 */
+ ScanReductionState state_right; /* Etat synthétisé #2 */
+ GScanLiteralExpression *op_left; /* Opérande gauche final */
+ GScanLiteralExpression *op_right; /* Opérande droite final */
+ LiteralValueType vtype_left; /* Type de valeur portée #1 */
+ LiteralValueType vtype_right; /* Type de valeur portée #2 */
+ long long val_1_s; /* Première valeur à traiter */
+ unsigned long long val_1_u; /* Première valeur à traiter */
+ long long val_2_s; /* Seconde valeur à traiter */
+ unsigned long long val_2_u; /* Seconde valeur à traiter */
+ LiteralValueType state_final; /* Nature de la valeur finale */
+ long long reduced_s; /* Valeur réduite finale */
+ unsigned long long reduced_u; /* Valeur réduite finale */
+
+ /* Réduction des éléments considérés */
+
+ new_left = NULL;
+ new_right = NULL;
+
+ state_left = g_scan_expression_reduce(expr->left, ctx, scope, &new_left);
+ if (state_left == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ state_right = g_scan_expression_reduce(expr->right, ctx, scope, &new_right);
+ if (state_right == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ /* Construction d'une réduction locale ? */
+
+ if (G_IS_SCAN_LITERAL_EXPRESSION(new_left) && G_IS_SCAN_LITERAL_EXPRESSION(new_right))
+ {
+ /* Récupération de l'opérande de gauche */
+
+ op_left = G_SCAN_LITERAL_EXPRESSION(new_left);
+ vtype_left = g_scan_literal_expression_get_value_type(op_left);
+
+ if (vtype_left == LVT_SIGNED_INTEGER)
+ {
+ if (!g_scan_literal_expression_get_signed_integer_value(op_left, &val_1_s))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+ }
+ else if (vtype_left == LVT_UNSIGNED_INTEGER)
+ {
+ if (!g_scan_literal_expression_get_unsigned_integer_value(op_left, &val_1_u))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+ }
+ else
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ /* Récupération de l'opérande de droite */
+
+ op_right = G_SCAN_LITERAL_EXPRESSION(new_right);
+ vtype_right = g_scan_literal_expression_get_value_type(op_right);
+
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ if (!g_scan_literal_expression_get_signed_integer_value(op_right, &val_2_s))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+ }
+ else if (vtype_right == LVT_UNSIGNED_INTEGER)
+ {
+ if (!g_scan_literal_expression_get_unsigned_integer_value(op_right, &val_2_u))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+ }
+ else
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ /* Partie des calculs */
+
+ result = SRS_REDUCED;
+
+ switch (expr->operator)
+ {
+ case AEO_PLUS:
+ if (vtype_left == LVT_SIGNED_INTEGER)
+ {
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = val_1_s + val_2_s;
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ if ((long long)val_2_u > val_1_s)
+ {
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_s + (long long)val_2_u;
+ }
+ else
+ {
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = val_1_s + (long long)val_2_u;
+ }
+
+ }
+ }
+ else
+ {
+ assert(vtype_left == LVT_UNSIGNED_INTEGER);
+
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ if ((long long)val_1_u > val_2_s)
+ {
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = (long long)val_1_u + val_2_s;
+ }
+ else
+ {
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = (long long)val_1_u + val_2_s;
+ }
+
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_u + val_2_u;
+
+ }
+ }
+ break;
+
+ case AEO_MINUS:
+ if (vtype_left == LVT_SIGNED_INTEGER)
+ {
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ if (val_2_s < val_1_s)
+ {
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_s - val_2_s;
+ }
+ else
+ {
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = val_1_s - val_2_s;
+ }
+
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = val_1_s - (long long)val_2_u;
+
+ }
+ }
+ else
+ {
+ assert(vtype_left == LVT_UNSIGNED_INTEGER);
+
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = (long long)val_1_u - val_2_s;
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ if (val_1_u > val_2_u)
+ {
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_u - val_2_u;
+ }
+ else
+ {
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = val_1_u - val_2_u;
+ }
+
+ }
+ }
+ break;
+
+ case AEO_MUL:
+ if (vtype_left == LVT_SIGNED_INTEGER)
+ {
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_s * val_2_s;
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = val_1_s * (long long)val_2_u;
+
+ }
+ }
+ else
+ {
+ assert(vtype_left == LVT_UNSIGNED_INTEGER);
+
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = (long long)val_1_u * val_2_s;
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_u * val_2_u;
+
+ }
+ }
+ break;
+
+ case AEO_DIV:
+ if ((vtype_right == LVT_SIGNED_INTEGER && val_2_s == 0)
+ || (vtype_right == LVT_UNSIGNED_INTEGER && val_2_u == 0))
+ {
+ result = SRS_UNRESOLVABLE;
+ break;
+ }
+
+ if (vtype_left == LVT_SIGNED_INTEGER)
+ {
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_s / val_2_s;
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = val_1_s / (long long)val_2_u;
+
+ }
+ }
+ else
+ {
+ assert(vtype_left == LVT_UNSIGNED_INTEGER);
+
+ if (vtype_right == LVT_SIGNED_INTEGER)
+ {
+ state_final = LVT_SIGNED_INTEGER;
+ reduced_s = (long long)val_1_u / val_2_s;
+ }
+ else
+ {
+ assert(vtype_right == LVT_UNSIGNED_INTEGER);
+
+ state_final = LVT_UNSIGNED_INTEGER;
+ reduced_u = val_1_u / val_2_u;
+
+ }
+ }
+ break;
+
+ case AEO_MOD:
+ result = SRS_UNRESOLVABLE;
+ /* FIXME
+ result = (val_2 != 0);
+ if (result)
+ reduced = val_1 % val_2;
+ */
+ break;
+
+ }
+
+ if (result == SRS_REDUCED)
+ {
+ if (state_final == LVT_SIGNED_INTEGER)
+ *out = g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &reduced_s);
+ else
+ {
+ assert(state_final == LVT_UNSIGNED_INTEGER);
+ *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &reduced_u);
+ }
+
+ }
+
+ }
+
+ /* Mise à jour de la progression ? */
+
+ else if (state_left == SRS_WAIT_FOR_SCAN || state_right == SRS_WAIT_FOR_SCAN)
+ {
+ if (new_left != expr->left || new_right != expr->right)
+ *out = g_scan_arithmetic_operation_new(expr->operator, new_left, new_right);
+
+ result = SRS_WAIT_FOR_SCAN;
+
+ }
+
+ /* Cas des situations où les expressions ne sont pas exploitables (!) */
+ else
+ {
+ assert(state_left == SRS_REDUCED && state_right == SRS_REDUCED);
+
+ result = SRS_UNRESOLVABLE;
+
+ }
+
+ /* Sortie propre */
+
+ exit:
+
+ g_clear_object(&new_left);
+ g_clear_object(&new_right);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/arithmetic.h b/src/analysis/scan/exprs/arithmetic.h
new file mode 100644
index 0000000..8a1e844
--- /dev/null
+++ b/src/analysis/scan/exprs/arithmetic.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * arithmetic.h - prototypes pour la gestion des opérations arithmétiques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMETIC_H
+#define _ANALYSIS_SCAN_EXPRS_ARITHMETIC_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_SCAN_ARITHMETIC_OPERATION g_scan_arithmetic_operation_get_type()
+#define G_SCAN_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ARITHMETIC_OPERATION, GScanArithmeticOperation))
+#define G_IS_SCAN_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ARITHMETIC_OPERATION))
+#define G_SCAN_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ARITHMETIC_OPERATION, GScanArithmeticOperationClass))
+#define G_IS_SCAN_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ARITHMETIC_OPERATION))
+#define G_SCAN_ARITHMETIC_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ARITHMETIC_OPERATION, GScanArithmeticOperationClass))
+
+
+/* Opération arithmétique impliquant deux opérandes (instance) */
+typedef struct _GScanArithmeticOperation GScanArithmeticOperation;
+
+/* Opération arithmétique impliquant deux opérandes (classe) */
+typedef struct _GScanArithmeticOperationClass GScanArithmeticOperationClass;
+
+
+/* Type d'opération arithmétique */
+typedef enum _ArithmeticExpressionOperator
+{
+ AEO_PLUS, /* Opération binaire "+" */
+ AEO_MINUS, /* Opération binaire "-" */
+ AEO_MUL, /* Opération binaire "*" */
+ AEO_DIV, /* Opération binaire "\" */
+ AEO_MOD, /* Opération binaire "%" */
+
+} ArithmeticExpressionOperator;
+
+
+/* Indique le type défini pour une opération arithmétique entre expressions. */
+GType g_scan_arithmetic_operation_get_type(void);
+
+/* Organise une opération arithmétique entre expressions. */
+GScanExpression *g_scan_arithmetic_operation_new(ArithmeticExpressionOperator, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMETIC_H */
diff --git a/src/analysis/scan/exprs/call-int.h b/src/analysis/scan/exprs/call-int.h
new file mode 100644
index 0000000..9646b95
--- /dev/null
+++ b/src/analysis/scan/exprs/call-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * call-int.h - prototypes internes pour l'organisation d'un appel à un élément de scan enregistré
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_CALL_INT_H
+#define _ANALYSIS_SCAN_EXPRS_CALL_INT_H
+
+
+#include "call.h"
+
+
+#include "access-int.h"
+
+
+
+/* Exécution d'une fonction auxiliaire d'analyse (instance) */
+struct _GScanPendingCall
+{
+ GScanNamedAccess parent; /* A laisser en premier */
+
+ GScanExpression **args; /* Arguments d'appel fournis */
+ size_t count; /* Quantité de ces arguments */
+
+};
+
+/* Exécution d'une fonction auxiliaire d'analyse (classe) */
+struct _GScanPendingCallClass
+{
+ GScanNamedAccessClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une expression d'appel. */
+bool g_scan_pending_call_create(GScanPendingCall *, const sized_string_t *, GScanExpression **, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_CALL_INT_H */
diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c
new file mode 100644
index 0000000..3997ff6
--- /dev/null
+++ b/src/analysis/scan/exprs/call.c
@@ -0,0 +1,467 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * call.c - organisation d'un appel à un élément de scan enregistré
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "call.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "call-int.h"
+#include "../../../core/global.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des appels de fonction avec arguments. */
+static void g_scan_pending_call_class_init(GScanPendingCallClass *);
+
+/* Initialise une instance d'appel de fonction avec arguments. */
+static void g_scan_pending_call_init(GScanPendingCall *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_pending_call_dispose(GScanPendingCall *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_pending_call_finalize(GScanPendingCall *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Reproduit un accès en place dans une nouvelle instance. */
+static void g_scan_pending_call_copy(GScanPendingCall *, const GScanPendingCall *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un appel de fonction enregistrée. */
+G_DEFINE_TYPE(GScanPendingCall, g_scan_pending_call, G_TYPE_SCAN_NAMED_ACCESS);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des appels de fonction avec arguments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_call_class_init(GScanPendingCallClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+ GScanNamedAccessClass *access; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pending_call_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_pending_call_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)NULL;
+ expr->reduce = (reduce_expr_fc)g_scan_pending_call_reduce;
+
+ access = G_SCAN_NAMED_ACCESS_CLASS(klass);
+
+ access->copy = (copy_scan_access_fc)g_scan_pending_call_copy;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : call = instance à initialiser. *
+* *
+* Description : Initialise une instance d'appel de fonction avec arguments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_call_init(GScanPendingCall *call)
+{
+ call->args = NULL;
+ call->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : call = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_call_dispose(GScanPendingCall *call)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < call->count; i++)
+ g_clear_object(&call->args[i]);
+
+ G_OBJECT_CLASS(g_scan_pending_call_parent_class)->dispose(G_OBJECT(call));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : call = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_call_finalize(GScanPendingCall *call)
+{
+ if (call->args != NULL)
+ free(call->args);
+
+ G_OBJECT_CLASS(g_scan_pending_call_parent_class)->finalize(G_OBJECT(call));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de l'objet d'appel à identifier. *
+* args = éventuelle liste d'arguments à actionner. *
+* count = quantité de ces arguments. *
+* *
+* Description : Organise un appel de fonction avec ses arguments. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_pending_call_new(const sized_string_t *target, GScanExpression **args, size_t count)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_PENDING_CALL, NULL);
+
+ if (!g_scan_pending_call_create(G_SCAN_PENDING_CALL(result), target, args, count))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : call = instance à initialiser pleinement. *
+* target = désignation de l'objet d'appel à identifier. *
+* args = éventuelle liste d'arguments à actionner. *
+* count = quantité de ces arguments. *
+* *
+* Description : Met en place une expression d'appel. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_pending_call_create(GScanPendingCall *call, const sized_string_t *target, GScanExpression **args, size_t count)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(call), target);
+ if (!result) goto exit;
+
+ call->args = malloc(count * sizeof(GScanExpression *));
+ call->count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ call->args[i] = args[i];
+ g_object_ref(G_OBJECT(args[i]));
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanNamedAccess *access; /* Autre vision de l'expression*/
+ GScanRegisteredItem *resolved; /* Cible concrète obtenue */
+ size_t i; /* Boucle de parcours #1 */
+ GScanExpression *arg; /* Argument réduit à échanger */
+ GScanExpression *new; /* Nouvelle réduction obtenue */
+ ScanReductionState state; /* Etat synthétisé d'un élément*/
+ size_t k; /* Boucle de parcours #2 */
+ GScanExpression **new_args; /* Nouvelle séquence d'args. */
+ GObject *final; /* Expression ou élément ? */
+ bool valid; /* Validité de l'élément */
+ GScanExpression *new_next; /* Nouvelle version du suivant */
+
+ access = G_SCAN_NAMED_ACCESS(expr);
+
+ resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope);
+
+ if (resolved == NULL)
+ result = SRS_UNRESOLVABLE;
+
+ else
+ {
+ result = SRS_PENDING;
+
+ /* Actualisation nécessaire des arguments ? */
+
+ new_args = NULL;
+
+ for (i = 0; i < expr->count; i++)
+ {
+ arg = expr->args[i];
+
+ state = g_scan_expression_reduce(arg, ctx, scope, &new);
+ if (state == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ break;
+ }
+
+ if (state == SRS_WAIT_FOR_SCAN)
+ result = SRS_WAIT_FOR_SCAN;
+
+ if (new != arg)
+ {
+ if (new_args == NULL)
+ {
+ new_args = calloc(expr->count, sizeof(GScanExpression *));
+
+ for (k = 0; k < i; k++)
+ {
+ new_args[k] = expr->args[k];
+ g_object_ref(G_OBJECT(new_args[k]));
+ }
+
+ }
+
+ new_args[i] = new;
+
+ }
+
+ else
+ {
+ if (new_args != NULL)
+ new_args[i] = new;
+
+ else
+ g_object_unref(G_OBJECT(new));
+
+ }
+
+ }
+
+ /* Suite des traitements */
+
+ if (result == SRS_WAIT_FOR_SCAN)
+ {
+ /**
+ * Si changement il y a eu...
+ */
+ if (new_args != NULL)
+ {
+ *out = g_scan_pending_call_new(NULL, new_args, expr->count);
+
+ /**
+ * Fonctionnement équivalent de :
+ * g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(*out), resolved);
+ */
+ G_SCAN_NAMED_ACCESS(*out)->resolved = resolved;
+ g_object_ref(G_OBJECT(resolved));
+
+ if (G_SCAN_NAMED_ACCESS(expr)->next != NULL)
+ g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS(*out), G_SCAN_NAMED_ACCESS(expr)->next);
+
+ }
+
+ }
+
+ else if (result == SRS_PENDING)
+ {
+ if (new_args == NULL)
+ valid = g_scan_registered_item_run_call(resolved,
+ expr->args,
+ expr->count,
+ ctx, scope, &final);
+ else
+ valid = g_scan_registered_item_run_call(resolved,
+ new_args,
+ expr->count,
+ ctx, scope, &final);
+
+ if (valid && final != NULL)
+ {
+ /**
+ * Si le produit de l'appel à la fonction est une expression d'évaluation
+ * classique, alors ce produit constitue la réduction finale de la chaîne.
+ *
+ * Ce cas de figure ne se rencontre normalement qu'en bout de chaîne.
+ */
+ if (!G_IS_SCAN_REGISTERED_ITEM(final))
+ {
+ if (access->next != NULL)
+ result = SRS_UNRESOLVABLE;
+
+ else
+ {
+ *out = G_SCAN_EXPRESSION(final);
+ g_object_ref(G_OBJECT(final));
+
+ result = SRS_REDUCED;
+
+ }
+
+ }
+ else
+ {
+ assert(access->next != NULL);
+
+ new_next = g_scan_named_access_duplicate(access->next, G_SCAN_REGISTERED_ITEM(final));
+
+ result = g_scan_expression_reduce(new_next, ctx, scope, out);
+
+ g_object_unref(G_OBJECT(new_next));
+
+ }
+
+ }
+
+ else
+ result = SRS_UNRESOLVABLE;
+
+ g_clear_object(&final);
+
+ }
+
+ /* Libération locale des arguments reconstruits */
+
+ if (new_args != NULL)
+ {
+ for (i = 0; i < expr->count; i++)
+ g_clear_object(&new_args[i]);
+ }
+
+ g_object_unref(G_OBJECT(resolved));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] *
+* src = expression source à copier. *
+* *
+* Description : Reproduit un accès en place dans une nouvelle instance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_call_copy(GScanPendingCall *dest, const GScanPendingCall *src)
+{
+ GScanNamedAccessClass *class; /* Classe parente à solliciter */
+ size_t i; /* Boucle de parcours */
+
+ class = G_SCAN_NAMED_ACCESS_CLASS(g_scan_pending_call_parent_class);
+
+ class->copy(G_SCAN_NAMED_ACCESS(dest), G_SCAN_NAMED_ACCESS(src));
+
+ dest->args = malloc(src->count * sizeof(GScanExpression *));
+ dest->count = src->count;
+
+ for (i = 0; i < src->count; i++)
+ {
+ dest->args[i] = src->args[i];
+ g_object_ref(G_OBJECT(src->args[i]));
+ }
+
+}
diff --git a/src/analysis/scan/exprs/call.h b/src/analysis/scan/exprs/call.h
new file mode 100644
index 0000000..c4d8964
--- /dev/null
+++ b/src/analysis/scan/exprs/call.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * call.h - prototypes pour l'organisation d'un appel à un élément de scan enregistré
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_CALL_H
+#define _ANALYSIS_SCAN_EXPRS_CALL_H
+
+
+#include "../expr.h"
+#include "../../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_PENDING_CALL g_scan_pending_call_get_type()
+#define G_SCAN_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PENDING_CALL, GScanPendingCall))
+#define G_IS_SCAN_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PENDING_CALL))
+#define G_SCAN_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PENDING_CALL, GScanPendingCallClass))
+#define G_IS_SCAN_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PENDING_CALL))
+#define G_SCAN_PENDING_CALL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PENDING_CALL, GScanPendingCallClass))
+
+
+/* Exécution d'une fonction auxiliaire d'analyse (instance) */
+typedef struct _GScanPendingCall GScanPendingCall;
+
+/* Exécution d'une fonction auxiliaire d'analyse (classe) */
+typedef struct _GScanPendingCallClass GScanPendingCallClass;
+
+
+/* Indique le type défini pour un appel de fonction enregistrée. */
+GType g_scan_pending_call_get_type(void);
+
+/* Organise un appel de fonction avec ses arguments. */
+GScanExpression *g_scan_pending_call_new(const sized_string_t *, GScanExpression **, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_CALL_H */
diff --git a/src/analysis/scan/exprs/extract-int.h b/src/analysis/scan/exprs/extract-int.h
new file mode 100644
index 0000000..562e537
--- /dev/null
+++ b/src/analysis/scan/exprs/extract-int.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * extract-int.h - prototypes internes pour l'organisation d'une extraction d'un élément d'une série interne
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_EXTRACT_INT_H
+#define _ANALYSIS_SCAN_EXPRS_EXTRACT_INT_H
+
+
+#include "extract.h"
+
+
+#include "access-int.h"
+
+
+
+/* Extraction d'un élément donné au sein d'une série interne (instance) */
+struct _GScanPendingExtraction
+{
+ GScanNamedAccess parent; /* A laisser en premier */
+
+ GScanExpression *index; /* Arguments d'appel fournis */
+
+};
+
+/* Extraction d'un élément donné au sein d'une série interne (classe) */
+struct _GScanPendingExtractionClass
+{
+ GScanNamedAccessClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une expression d'extraction d'élément interne. */
+bool g_scan_pending_extraction_create(GScanPendingExtraction *, const sized_string_t *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_EXTRACT_INT_H */
diff --git a/src/analysis/scan/exprs/extract.c b/src/analysis/scan/exprs/extract.c
new file mode 100644
index 0000000..b140ed9
--- /dev/null
+++ b/src/analysis/scan/exprs/extract.c
@@ -0,0 +1,396 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * extract.c - organisation d'une extraction d'un élément d'une série interne
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "extract.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include "extract-int.h"
+#include "../../../core/global.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des extractions d'éléments internes. */
+static void g_scan_pending_extraction_class_init(GScanPendingExtractionClass *);
+
+/* Initialise une instance d'extraction d'élément interne. */
+static void g_scan_pending_extraction_init(GScanPendingExtraction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_pending_extraction_dispose(GScanPendingExtraction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_pending_extraction_finalize(GScanPendingExtraction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_pending_extraction_reduce(const GScanPendingExtraction *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Reproduit un accès en place dans une nouvelle instance. */
+static void g_scan_pending_extraction_copy(GScanPendingExtraction *, const GScanPendingExtraction *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une extraction d'élément de série interne. */
+G_DEFINE_TYPE(GScanPendingExtraction, g_scan_pending_extraction, G_TYPE_SCAN_NAMED_ACCESS);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des extractions d'éléments internes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_extraction_class_init(GScanPendingExtractionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+ GScanNamedAccessClass *access; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pending_extraction_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_pending_extraction_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)NULL;
+ expr->reduce = (reduce_expr_fc)g_scan_pending_extraction_reduce;
+
+ access = G_SCAN_NAMED_ACCESS_CLASS(klass);
+
+ access->copy = (copy_scan_access_fc)g_scan_pending_extraction_copy;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : extract = instance à initialiser. *
+* *
+* Description : Initialise une instance d'extraction d'élément interne. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_extraction_init(GScanPendingExtraction *extract)
+{
+ extract->index = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : extract = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_extraction_dispose(GScanPendingExtraction *extract)
+{
+ g_clear_object(&extract->index);
+
+ G_OBJECT_CLASS(g_scan_pending_extraction_parent_class)->dispose(G_OBJECT(extract));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : extract = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_extraction_finalize(GScanPendingExtraction *extract)
+{
+ G_OBJECT_CLASS(g_scan_pending_extraction_parent_class)->finalize(G_OBJECT(extract));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = désignation de l'objet d'appel à identifier. *
+* index = indice de l'élément à extraire. *
+* *
+* Description : Organise l'extraction d'un élément d'une série interne. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_pending_extraction_new(const sized_string_t *target, GScanExpression *index)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_PENDING_EXTRACTION, NULL);
+
+ if (!g_scan_pending_extraction_create(G_SCAN_PENDING_EXTRACTION(result), target, index))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : extract = instance à initialiser pleinement. *
+* target = désignation de l'objet d'appel à identifier. *
+* index = indice de l'élément à extraire. *
+* *
+* Description : Met en place une expression d'extraction d'élément interne. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_pending_extraction_create(GScanPendingExtraction *extract, const sized_string_t *target, GScanExpression *index)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(extract), target);
+ if (!result) goto exit;
+
+ extract->index = index;
+ g_object_ref(G_OBJECT(index));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_pending_extraction_reduce(const GScanPendingExtraction *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanNamedAccess *access; /* Autre vision de l'expression*/
+ GScanRegisteredItem *resolved; /* Cible concrète obtenue */
+ GScanExpression *new; /* Nouvelle réduction obtenue */
+ GObject *final; /* Expression ou élément ? */
+ GScanExpression *new_next; /* Nouvelle version du suivant */
+
+ access = G_SCAN_NAMED_ACCESS(expr);
+
+ resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope);
+
+ if (resolved == NULL)
+ result = SRS_UNRESOLVABLE;
+
+ else
+ {
+ /* Actualisation nécessaire des arguments ? */
+
+ result = g_scan_expression_reduce(expr->index, ctx, scope, &new);
+
+ /* Suite des traitements */
+
+ if (result == SRS_WAIT_FOR_SCAN)
+ {
+ /**
+ * Si changement il y a eu...
+ */
+ if (new != expr->index)
+ {
+ *out = g_scan_pending_extraction_new(NULL, new);
+
+ /**
+ * Fonctionnement équivalent de :
+ * g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(*out), resolved);
+ */
+ G_SCAN_NAMED_ACCESS(*out)->resolved = resolved;
+ g_object_ref(G_OBJECT(resolved));
+
+ if (G_SCAN_NAMED_ACCESS(expr)->next != NULL)
+ g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS(*out), G_SCAN_NAMED_ACCESS(expr)->next);
+
+ }
+
+ }
+
+ else if (result == SRS_REDUCED)
+ {
+ final = g_scan_registered_item_extract_at(resolved, new, ctx, scope);
+
+ if (final != NULL)
+ {
+ /**
+ * Si le produit de l'appel à la fonction est une expression d'évaluation
+ * classique, alors ce produit constitue la réduction finale de la chaîne.
+ *
+ * Ce cas de figure ne se rencontre normalement qu'en bout de chaîne.
+ */
+ if (!G_IS_SCAN_REGISTERED_ITEM(final))
+ {
+ if (access->next != NULL)
+ result = SRS_UNRESOLVABLE;
+
+ else
+ {
+ *out = G_SCAN_EXPRESSION(final);
+ g_object_ref(G_OBJECT(final));
+
+ result = SRS_REDUCED;
+
+ }
+
+ }
+ else
+ {
+ if (access->next != NULL)
+ {
+ new_next = g_scan_named_access_duplicate(access->next, G_SCAN_REGISTERED_ITEM(final));
+
+ result = g_scan_expression_reduce(new_next, ctx, scope, out);
+
+ g_object_unref(G_OBJECT(new_next));
+
+ }
+
+ /**
+ * Le cas ci-après est typique de l'extension Kaitai : field[n]
+ * renvoie vers une instance GScanRegisteredItem (GKaitaiBrowser).
+ *
+ * Il n'y a donc pas d'expression en jeu, et l'élément est le dernier
+ * de la liste.
+ */
+ else
+ {
+ if (g_scan_registered_item_reduce(G_SCAN_REGISTERED_ITEM(final), ctx, scope, out))
+ result = SRS_REDUCED;
+ else
+ result = SRS_UNRESOLVABLE;
+
+ }
+
+ }
+
+ }
+
+ else
+ result = SRS_UNRESOLVABLE;
+
+ g_clear_object(&final);
+
+ }
+
+ /* Libération locale des arguments reconstruits */
+
+ g_clear_object(&new);
+
+ g_object_unref(G_OBJECT(resolved));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] *
+* src = expression source à copier. *
+* *
+* Description : Reproduit un accès en place dans une nouvelle instance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pending_extraction_copy(GScanPendingExtraction *dest, const GScanPendingExtraction *src)
+{
+ GScanNamedAccessClass *class; /* Classe parente à solliciter */
+
+ class = G_SCAN_NAMED_ACCESS_CLASS(g_scan_pending_extraction_parent_class);
+
+ class->copy(G_SCAN_NAMED_ACCESS(dest), G_SCAN_NAMED_ACCESS(src));
+
+ dest->index = src->index;
+ g_object_ref(G_OBJECT(src->index));
+
+}
diff --git a/src/analysis/scan/exprs/extract.h b/src/analysis/scan/exprs/extract.h
new file mode 100644
index 0000000..8ed1cfa
--- /dev/null
+++ b/src/analysis/scan/exprs/extract.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * extract.h - prototypes pour l'organisation d'une extraction d'un élément d'une série interne
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_EXTRACT_H
+#define _ANALYSIS_SCAN_EXPRS_EXTRACT_H
+
+
+#include "../expr.h"
+#include "../../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_PENDING_EXTRACTION g_scan_pending_extraction_get_type()
+#define G_SCAN_PENDING_EXTRACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PENDING_EXTRACTION, GScanPendingExtraction))
+#define G_IS_SCAN_PENDING_EXTRACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PENDING_EXTRACTION))
+#define G_SCAN_PENDING_EXTRACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PENDING_EXTRACTION, GScanPendingExtractionClass))
+#define G_IS_SCAN_PENDING_EXTRACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PENDING_EXTRACTION))
+#define G_SCAN_PENDING_EXTRACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PENDING_EXTRACTION, GScanPendingExtractionClass))
+
+
+/* Extraction d'un élément donné au sein d'une série interne (instance) */
+typedef struct _GScanPendingExtraction GScanPendingExtraction;
+
+/* Extraction d'un élément donné au sein d'une série interne (classe) */
+typedef struct _GScanPendingExtractionClass GScanPendingExtractionClass;
+
+
+/* Indique le type défini pour une extraction d'élément de série interne. */
+GType g_scan_pending_extraction_get_type(void);
+
+/* Organise l'extraction d'un élément d'une série interne. */
+GScanExpression *g_scan_pending_extraction_new(const sized_string_t *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_EXTRACT_H */
diff --git a/src/analysis/scan/exprs/handler-int.h b/src/analysis/scan/exprs/handler-int.h
new file mode 100644
index 0000000..e051b30
--- /dev/null
+++ b/src/analysis/scan/exprs/handler-int.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * handler-int.h - prototypes internes pour la manipulation des correspondances établies lors d'un scan
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H
+#define _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H
+
+
+#include "handler.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Manipulation des correspondances établies lors d'un scan de binaire (instance) */
+struct _GScanPatternHandler
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ union
+ {
+ const GSearchPattern **patterns; /* Motifs associés */
+ GSearchPattern **ref_patterns; /* Motifs associés */
+ };
+ size_t count; /* Nombre de ces motifs */
+ bool shared; /* Définition de propriété */
+
+ ScanHandlerType type; /* Manipulation attendue */
+
+};
+
+/* Manipulation des correspondances établies lors d'un scan de binaire (classe) */
+struct _GScanPatternHandlerClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une manipulation de correspondances établies. */
+bool g_scan_pattern_handler_create_shared(GScanPatternHandler *, const GSearchPattern ** const, size_t, ScanHandlerType);
+
+/* Met en place une manipulation de correspondances établies. */
+bool g_scan_pattern_handler_create_and_ref(GScanPatternHandler *, GSearchPattern ** const, size_t, ScanHandlerType);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H */
diff --git a/src/analysis/scan/exprs/handler.c b/src/analysis/scan/exprs/handler.c
new file mode 100644
index 0000000..2706dae
--- /dev/null
+++ b/src/analysis/scan/exprs/handler.c
@@ -0,0 +1,622 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * handler.c - manipulation des correspondances établies lors d'un scan
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "handler.h"
+
+
+#include <assert.h>
+
+
+#include "literal.h"
+#include "handler-int.h"
+#include "../matches/bytes.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des manipulations de correspondances. */
+static void g_scan_pattern_handler_class_init(GScanPatternHandlerClass *);
+
+/* Initialise une instance de manipulation de correspondances. */
+static void g_scan_pattern_handler_init(GScanPatternHandler *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_pattern_handler_dispose(GScanPatternHandler *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_pattern_handler_finalize(GScanPatternHandler *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_pattern_handler_reduce(const GScanPatternHandler *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Réduit une expression à une forme booléenne. */
+static bool g_scan_pattern_handler_reduce_to_boolean(const GScanPatternHandler *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Dénombre les éléments portés par une expression. */
+static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *, GScanContext *, size_t *);
+
+/* Fournit un élément donné issu d'un ensemble constitué. */
+static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *, size_t, GScanContext *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une manipulation de correspondances établies lors d'un scan. */
+G_DEFINE_TYPE(GScanPatternHandler, g_scan_pattern_handler, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des manipulations de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pattern_handler_class_init(GScanPatternHandlerClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pattern_handler_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_pattern_handler_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->reduce = (reduce_expr_fc)g_scan_pattern_handler_reduce;
+ expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_pattern_handler_reduce_to_boolean;
+ expr->count = (count_scan_expr_fc)g_scan_pattern_handler_count_items;
+ expr->get = (get_scan_expr_fc)g_scan_pattern_handler_get_item;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : handler = instance à initialiser. *
+* *
+* Description : Initialise une instance de manipulation de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pattern_handler_init(GScanPatternHandler *handler)
+{
+ handler->patterns = NULL;
+ handler->count = 0;
+ handler->shared = true;
+
+ handler->type = SHT_RAW;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : handler = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pattern_handler_dispose(GScanPatternHandler *handler)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (!handler->shared)
+ for (i = 0; i < handler->count; i++)
+ g_clear_object(&handler->ref_patterns[i]);
+
+ G_OBJECT_CLASS(g_scan_pattern_handler_parent_class)->dispose(G_OBJECT(handler));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : handler = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_pattern_handler_finalize(GScanPatternHandler *handler)
+{
+ if (handler->patterns != NULL)
+ free(handler->patterns);
+
+ G_OBJECT_CLASS(g_scan_pattern_handler_parent_class)->finalize(G_OBJECT(handler));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* type = type de manipulation attendue. *
+* *
+* Description : Met en place une manipulation de correspondances établies. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_pattern_handler_new_shared(const GSearchPattern ** const patterns, size_t count, ScanHandlerType type)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_PATTERN_HANDLER, NULL);
+
+ if (!g_scan_pattern_handler_create_shared(G_SCAN_PATTERN_HANDLER(result), patterns, count, type))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : handler = instance à initialiser pleinement. *
+* patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* type = type de manipulation attendue. *
+* *
+* Description : Met en place une manipulation de correspondances établies. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_pattern_handler_create_shared(GScanPatternHandler *handler, const GSearchPattern ** const patterns, size_t count, ScanHandlerType type)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(handler), SRS_WAIT_FOR_SCAN);
+ if (!result) goto exit;
+
+ handler->patterns = malloc(count * sizeof(GSearchPattern *));
+ handler->count = count;
+
+ memcpy(handler->patterns, patterns, count * sizeof(GSearchPattern *));
+
+ handler->shared = true;
+
+ handler->type = type;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* type = type de manipulation attendue. *
+* *
+* Description : Met en place une manipulation de correspondances établies. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_pattern_handler_new(GSearchPattern ** const patterns, size_t count, ScanHandlerType type)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_PATTERN_HANDLER, NULL);
+
+ if (!g_scan_pattern_handler_create_and_ref(G_SCAN_PATTERN_HANDLER(result), patterns, count, type))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : handler = instance à initialiser pleinement. *
+* patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* type = type de manipulation attendue. *
+* *
+* Description : Met en place une manipulation de correspondances établies. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_pattern_handler_create_and_ref(GScanPatternHandler *handler, GSearchPattern ** const patterns, size_t count, ScanHandlerType type)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(handler), SRS_WAIT_FOR_SCAN);
+ if (!result) goto exit;
+
+ handler->patterns = malloc(count * sizeof(GSearchPattern *));
+ handler->count = count;
+
+ memcpy(handler->patterns, patterns, count * sizeof(GSearchPattern *));
+
+ for (i = 0; i < count; i++)
+ g_object_ref(G_OBJECT(patterns[i]));
+
+ handler->shared = false;
+
+ handler->type = type;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : handler = instance à initialiser pleinement. *
+* *
+* Description : Indique le type de manipulation de correspondances spécifié. *
+* *
+* Retour : Type de manipulation de correspondances représentée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanHandlerType g_scan_pattern_handler_get_handler_type(const GScanPatternHandler *handler)
+{
+ ScanHandlerType result; /* Nature à retourner */
+
+ result = handler->type;
+
+ return result;
+
+}
+
+
+#if 0 /* FIXME */
+
+/******************************************************************************
+* *
+* Paramètres : handler = instance à initialiser pleinement. *
+* ctx = contexte de suivi de l'analyse courante. *
+* count = quantité de correspondances enregistrées. [OUT] *
+* *
+* Description : Fournit la liste de toutes les correspondances représentées. *
+* *
+* Retour : Liste courante de correspondances établies. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *handler, GScanContext *ctx, size_t *count)
+{
+ GScanMatch **result; /* Liste à retourner */
+ size_t used; /* Indice pour le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ size_t partial; /* Décompte partiel */
+ const GScanMatch **matches; /* Correspondances en place */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = NULL;
+
+ if (!g_scan_pattern_handler_count_items(handler, ctx, count))
+ {
+ *count = 0;
+ goto exit;
+ }
+
+ if (*count == 0)
+ goto exit;
+
+ result = malloc(*count * sizeof(GScanMatch *));
+
+ used = 0;
+
+ for (i = 0; i < handler->count; i++)
+ {
+ matches = g_scan_context_get_full_matches(ctx, handler->patterns[i], &partial);
+
+ for (k = 0; k < partial; k++)
+ {
+ result[used++] = matches[k];
+ g_object_ref(G_OBJECT(matches[k]));
+ }
+
+ }
+
+ exit:
+
+ return result;
+
+}
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_pattern_handler_reduce(const GScanPatternHandler *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ size_t count; /* Quantité de correspondances */
+
+ if (g_scan_context_is_scan_done(ctx))
+ {
+ if (expr->type == SHT_COUNTER)
+ {
+ if (!g_scan_pattern_handler_count_items(expr, ctx, &count))
+ result = SRS_UNRESOLVABLE;
+
+ else
+ {
+ result = SRS_REDUCED;
+ *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ count });
+ }
+
+ }
+
+ else
+ result = SRS_REDUCED;
+
+ }
+
+ else
+ result = SRS_WAIT_FOR_SCAN;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme booléenne. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_pattern_handler_reduce_to_boolean(const GScanPatternHandler *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t count; /* Quantité de correspondances */
+
+ result = g_scan_pattern_handler_count_items(expr, ctx, &count);
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ count > 0 });
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* count = quantité d'éléments déterminée. [OUT] *
+* *
+* Description : Dénombre les éléments portés par une expression. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *expr, GScanContext *ctx, size_t *count)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ assert(g_scan_context_is_scan_done(ctx));
+
+ *count = 0;
+
+ for (i = 0; i < expr->count; i++)
+ *count += g_scan_context_count_full_matches(ctx, expr->patterns[i]);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* index = indice de l'élément à transférer. *
+* ctx = contexte de suivi de l'analyse courante. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Fournit un élément donné issu d'un ensemble constitué. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, size_t index, GScanContext *ctx, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ size_t count; /* Quantité de correspondances */
+ GScanMatches *matches; /* Correspondances d'un motif */
+ const match_area_t *area; /* Zone de correspondance */
+ GBinContent *content; /* Contenu binaire à relire */
+ vmpa2t pos; /* Tête de lecture */
+ const bin_t *data; /* Accès aux données brutes */
+ sized_string_t binary; /* Conversion de formats */
+
+ result = false;
+
+ assert(g_scan_context_is_scan_done(ctx));
+
+ /* Identification du motif concerné */
+
+ for (i = 0; i < expr->count; i++)
+ {
+ count = g_scan_context_count_full_matches(ctx, expr->patterns[i]);
+
+ if (index < count)
+ break;
+ else
+ index -= count;
+
+ }
+
+ if (i == expr->count) goto done;
+
+ /* Identification de la correspondance concernée */
+
+ matches = g_scan_context_get_full_matches(ctx, expr->patterns[i]);
+ if (matches == NULL) goto done;
+
+ area = g_scan_bytes_matches_get(G_SCAN_BYTES_MATCHES(matches), index);
+ if (area == NULL) goto done_with_matches;
+
+ /* Traitement adapté de la requête */
+
+ switch (expr->type)
+ {
+ case SHT_RAW:
+ content = g_scan_context_get_content(ctx);
+
+ init_vmpa(&pos, area->start, VMPA_NO_VIRTUAL);
+
+ data = g_binary_content_get_raw_access(content, &pos, area->end - area->start);
+
+ binary.static_bin_data = data;
+ binary.len = area->end - area->start;
+
+ *out = g_scan_literal_expression_new(LVT_STRING, &binary);
+
+ g_object_unref(G_OBJECT(content));
+ result = true;
+ break;
+
+ case SHT_COUNTER:
+ assert(false);
+ break;
+
+ case SHT_START:
+ *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+ (unsigned long long []){ area->start });
+ result = true;
+ break;
+
+ case SHT_LENGTH:
+ *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+ (unsigned long long []){ area->end - area->start });
+ result = true;
+ break;
+
+ case SHT_END:
+ *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+ (unsigned long long []){ area->end });
+ result = true;
+ break;
+
+ }
+
+ done_with_matches:
+
+ g_object_unref(G_OBJECT(matches));
+
+ done:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/handler.h b/src/analysis/scan/exprs/handler.h
new file mode 100644
index 0000000..a1ddf98
--- /dev/null
+++ b/src/analysis/scan/exprs/handler.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * handler.h - prototypes pour la manipulation des correspondances établies lors d'un scan
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_HANDLER_H
+#define _ANALYSIS_SCAN_EXPRS_HANDLER_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_SCAN_PATTERN_HANDLER g_scan_pattern_handler_get_type()
+#define G_SCAN_PATTERN_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandler))
+#define G_IS_SCAN_PATTERN_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PATTERN_HANDLER))
+#define G_SCAN_PATTERN_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandlerClass))
+#define G_IS_SCAN_PATTERN_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PATTERN_HANDLER))
+#define G_SCAN_PATTERN_HANDLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandlerClass))
+
+
+/* Manipulation des correspondances établies lors d'un scan de binaire (instance) */
+typedef struct _GScanPatternHandler GScanPatternHandler;
+
+/* Manipulation des correspondances établies lors d'un scan de binaire (classe) */
+typedef struct _GScanPatternHandlerClass GScanPatternHandlerClass;
+
+
+/* Type de manipulation représentée */
+typedef enum _ScanHandlerType
+{
+ SHT_RAW, /* Correspondances brutes */
+ SHT_COUNTER, /* Dénombrement de résultats */
+ SHT_START, /* Départs de correspondances */
+ SHT_LENGTH, /* Taille de correspondances */
+ SHT_END, /* Fins de correspondances */
+
+} ScanHandlerType;
+
+
+/* Indique le type défini pour une manipulation de correspondances établies lors d'un scan. */
+GType g_scan_pattern_handler_get_type(void);
+
+/* Met en place une manipulation de correspondances établies. */
+GScanExpression *g_scan_pattern_handler_new_shared(const GSearchPattern ** const, size_t, ScanHandlerType);
+
+/* Met en place une manipulation de correspondances établies. */
+GScanExpression *g_scan_pattern_handler_new(GSearchPattern ** const, size_t, ScanHandlerType);
+
+/* Indique le type de manipulation de correspondances spécifié. */
+ScanHandlerType g_scan_pattern_handler_get_handler_type(const GScanPatternHandler *);
+
+#if 0 /* FIXME */
+
+/* Fournit la liste de toutes les correspondances représentées. */
+GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *, GScanContext *, size_t *);
+
+#endif
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_HANDLER_H */
diff --git a/src/analysis/scan/exprs/intersect-int.h b/src/analysis/scan/exprs/intersect-int.h
new file mode 100644
index 0000000..83e4251
--- /dev/null
+++ b/src/analysis/scan/exprs/intersect-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * intersect-int.h - prototypes internes pour l'intersection d'ensembles aux types indentiques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_INTERSECT_INT_H
+#define _ANALYSIS_SCAN_EXPRS_INTERSECT_INT_H
+
+
+#include "intersect.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Opération d'intersection entre deux ensembles (instance) */
+struct _GScanSetsIntersection
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ GScanExpression *first; /* Expression impactée #1 */
+ GScanExpression *second; /* Expression impactée #2 */
+
+};
+
+/* Opération d'intersection entre deux ensembles (classe) */
+struct _GScanSetsIntersectionClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une expression d'opération booléenne. */
+bool g_scan_sets_intersection_create(GScanSetsIntersection *, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_INTERSECT_INT_H */
diff --git a/src/analysis/scan/exprs/intersect.c b/src/analysis/scan/exprs/intersect.c
new file mode 100644
index 0000000..c56d28c
--- /dev/null
+++ b/src/analysis/scan/exprs/intersect.c
@@ -0,0 +1,290 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * intersect.c - intersection d'ensembles aux types indentiques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "intersect.h"
+
+
+#include <assert.h>
+
+
+#include "intersect-int.h"
+#include "literal.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des intersections entre deux ensembles. */
+static void g_scan_sets_intersection_class_init(GScanSetsIntersectionClass *);
+
+/* Initialise une instance d'intersection entre deux ensembles. */
+static void g_scan_sets_intersection_init(GScanSetsIntersection *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_sets_intersection_dispose(GScanSetsIntersection *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_sets_intersection_finalize(GScanSetsIntersection *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_sets_intersection_reduce(const GScanSetsIntersection *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une intersection entre deux ensembles. */
+G_DEFINE_TYPE(GScanSetsIntersection, g_scan_sets_intersection, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des intersections entre deux ensembles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sets_intersection_class_init(GScanSetsIntersectionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sets_intersection_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_sets_intersection_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->reduce = (reduce_expr_fc)g_scan_sets_intersection_reduce;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser. *
+* *
+* Description : Initialise une instance d'intersection entre deux ensembles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sets_intersection_init(GScanSetsIntersection *inter)
+{
+ inter->first = NULL;
+ inter->second = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inter = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sets_intersection_dispose(GScanSetsIntersection *inter)
+{
+ g_clear_object(&inter->first);
+ g_clear_object(&inter->second);
+
+ G_OBJECT_CLASS(g_scan_sets_intersection_parent_class)->dispose(G_OBJECT(inter));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inter = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_sets_intersection_finalize(GScanSetsIntersection *inter)
+{
+ G_OBJECT_CLASS(g_scan_sets_intersection_parent_class)->finalize(G_OBJECT(inter));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type d'opération booléenne à représenter. *
+* first = premier élément concerné. *
+* second = second élément concerné. *
+* *
+* Description : Organise une intersection entre deux ensembles. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_sets_intersection_new(GScanExpression *first, GScanExpression *second)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SETS_INTERSECTION, NULL);
+
+ if (!g_scan_sets_intersection_create(G_SCAN_SETS_INTERSECTION(result), first, second))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inter = instance à initialiser pleinement. *
+* first = premier élément concerné. *
+* second = second élément concerné. *
+* *
+* Description : Met en place une expression d'opération booléenne. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_sets_intersection_create(GScanSetsIntersection *inter, GScanExpression *first, GScanExpression *second)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ inter->first = first;
+ g_object_ref(G_OBJECT(first));
+
+ inter->second = second;
+ g_object_ref(G_OBJECT(second));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_sets_intersection_reduce(const GScanSetsIntersection *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanExpression *new_first; /* Nouvelle réduction #1 */
+ GScanExpression *new_second; /* Nouvelle réduction #2 */
+ ScanReductionState state_first; /* Etat synthétisé #1 */
+ ScanReductionState state_second; /* Etat synthétisé #2 */
+
+ new_first = NULL;
+ new_second = NULL;
+
+ state_first = g_scan_expression_reduce(expr->first, ctx, scope, &new_first);
+ if (state_first == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ state_second = g_scan_expression_reduce(expr->second, ctx, scope, &new_second);
+ if (state_second == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (state_first == SRS_WAIT_FOR_SCAN || state_second == SRS_WAIT_FOR_SCAN)
+ {
+ if (new_first != expr->first || new_second != expr->second)
+ *out = g_scan_sets_intersection_new(new_first, new_second);
+
+ result = SRS_WAIT_FOR_SCAN;
+
+ }
+
+ else
+ {
+ assert(state_first == SRS_REDUCED && state_second == SRS_REDUCED);
+
+ *out = g_scan_expression_intersect(new_first, new_second, ctx, scope);
+
+ result = (*out != NULL ? SRS_REDUCED : SRS_UNRESOLVABLE);
+
+ }
+
+ exit:
+
+ g_clear_object(&new_first);
+ g_clear_object(&new_second);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/intersect.h b/src/analysis/scan/exprs/intersect.h
new file mode 100644
index 0000000..56efdff
--- /dev/null
+++ b/src/analysis/scan/exprs/intersect.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * intersect.h - prototypes pour l'intersection d'ensembles aux types indentiques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_INTERSECT_H
+#define _ANALYSIS_SCAN_EXPRS_INTERSECT_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_SCAN_SETS_INTERSECTION g_scan_sets_intersection_get_type()
+#define G_SCAN_SETS_INTERSECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SETS_INTERSECTION, GScanSetsIntersection))
+#define G_IS_SCAN_SETS_INTERSECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SETS_INTERSECTION))
+#define G_SCAN_SETS_INTERSECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SETS_INTERSECTION, GScanSetsIntersectionClass))
+#define G_IS_SCAN_SETS_INTERSECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SETS_INTERSECTION))
+#define G_SCAN_SETS_INTERSECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SETS_INTERSECTION, GScanSetsIntersectionClass))
+
+
+/* Opération d'intersection entre deux ensembles (instance) */
+typedef struct _GScanSetsIntersection GScanSetsIntersection;
+
+/* Opération d'intersection entre deux ensembles (classe) */
+typedef struct _GScanSetsIntersectionClass GScanSetsIntersectionClass;
+
+
+/* Indique le type défini pour une intersection entre deux ensembles. */
+GType g_scan_sets_intersection_get_type(void);
+
+/* Organise une intersection entre deux ensembles. */
+GScanExpression *g_scan_sets_intersection_new(GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_INTERSECT_H */
diff --git a/src/analysis/scan/exprs/item-int.h b/src/analysis/scan/exprs/item-int.h
new file mode 100644
index 0000000..56b159a
--- /dev/null
+++ b/src/analysis/scan/exprs/item-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item-int.h - prototypes internes pour la récupération d'un élément à partir d'une série
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_ITEM_INT_H
+#define _ANALYSIS_SCAN_EXPRS_ITEM_INT_H
+
+
+#include "item.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Accès à un élément donné d'une série établie (instance) */
+struct _GScanSetItem
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ GScanExpression *set; /* Série d'éléments à consulter*/
+ GScanExpression *index; /* Indice de l'élément visé */
+
+};
+
+/* Accès à un élément donné d'une série établie (classe) */
+struct _GScanSetItemClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un accès à un élément donné d'une série. */
+bool g_scan_set_item_create(GScanSetItem *, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_ITEM_INT_H */
diff --git a/src/analysis/scan/exprs/item.c b/src/analysis/scan/exprs/item.c
new file mode 100644
index 0000000..a5a6fdf
--- /dev/null
+++ b/src/analysis/scan/exprs/item.c
@@ -0,0 +1,353 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.c - récupération d'un élément à partir d'une série
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "set.h"
+
+
+#include <assert.h>
+
+
+#include "literal.h"
+#include "item-int.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des accès à un élément de série. */
+static void g_scan_set_item_class_init(GScanSetItemClass *);
+
+/* Initialise une instance d'accès à un élément de série. */
+static void g_scan_set_item_init(GScanSetItem *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_set_item_dispose(GScanSetItem *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_set_item_finalize(GScanSetItem *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_set_item_reduce(const GScanSetItem *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour la récupération d'un élément à partir d'une série. */
+G_DEFINE_TYPE(GScanSetItem, g_scan_set_item, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des accès à un élément de série. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_item_class_init(GScanSetItemClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_set_item_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_set_item_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->reduce = (reduce_expr_fc)g_scan_set_item_reduce;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = instance à initialiser. *
+* *
+* Description : Initialise une instance d'accès à un élément de série. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_item_init(GScanSetItem *item)
+{
+ item->set = NULL;
+ item->index = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_item_dispose(GScanSetItem *item)
+{
+ g_clear_object(&item->set);
+ g_clear_object(&item->index);
+
+ G_OBJECT_CLASS(g_scan_set_item_parent_class)->dispose(G_OBJECT(item));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_item_finalize(GScanSetItem *item)
+{
+ G_OBJECT_CLASS(g_scan_set_item_parent_class)->finalize(G_OBJECT(item));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : set = ensemble d'éléments à considérer. *
+* index = indice de l'élément à viser. *
+* *
+* Description : Met en place un accès à un élément donné d'une série. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_set_item_new(GScanExpression *set, GScanExpression *index)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SET_ITEM, NULL);
+
+ if (!g_scan_set_item_create(G_SCAN_SET_ITEM(result), set, index))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = instance à initialiser pleinement. *
+* set = ensemble d'éléments à considérer. *
+* index = indice de l'élément à viser. *
+* *
+* Description : Met en place un accès à un élément donné d'une série. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_set_item_create(GScanSetItem *item, GScanExpression *set, GScanExpression *index)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(item), SRS_PENDING);
+ if (!result) goto exit;
+
+ item->set = set;
+ g_object_ref(G_OBJECT(set));
+
+ item->index = index;
+ g_object_ref(G_OBJECT(index));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_set_item_reduce(const GScanSetItem *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanExpression *new_set; /* Expression réduite (série) */
+ GScanExpression *new_index; /* Expression réduite (indice) */
+ ScanReductionState state_set; /* Etat synthétisé #1 */
+ ScanReductionState state_index; /* Etat synthétisé #2 */
+ GScanLiteralExpression *op_index; /* Indice d'accès final */
+ LiteralValueType vtype; /* Type de valeur portée */
+ long long val_s; /* Valeur de l'indice (signée) */
+ unsigned long long val_u; /* Valeur de l'indice (!signée)*/
+ bool status; /* Statut final de récupération*/
+
+ /* Réduction des éléments considérés */
+
+ new_set = NULL;
+ new_index = NULL;
+
+ state_set = g_scan_expression_reduce(expr->set, ctx, scope, &new_set);
+ if (state_set == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ state_index = g_scan_expression_reduce(expr->index, ctx, scope, &new_index);
+ if (state_index == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ /* Validation de la nature des éléments en jeu */
+
+ if (state_set == SRS_REDUCED && !g_scan_expression_handle_set_features(new_set))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (state_index == SRS_REDUCED && !G_IS_SCAN_LITERAL_EXPRESSION(new_index))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ /* Tentative d'accès à un élément de série */
+
+ if (state_set == SRS_REDUCED && state_index == SRS_REDUCED)
+ {
+ op_index = G_SCAN_LITERAL_EXPRESSION(new_index);
+ vtype = g_scan_literal_expression_get_value_type(op_index);
+
+ if (vtype == LVT_SIGNED_INTEGER)
+ {
+ if (!g_scan_literal_expression_get_signed_integer_value(op_index, &val_s))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (val_s < 0)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ status = g_scan_expression_get_item(expr->set, val_s, ctx, out);
+
+ }
+
+ else if (vtype == LVT_UNSIGNED_INTEGER)
+ {
+ if (!g_scan_literal_expression_get_unsigned_integer_value(op_index, &val_u))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ status = g_scan_expression_get_item(expr->set, val_u, ctx, out);
+
+ }
+
+ else
+ status = false;
+
+ result = (status ? SRS_REDUCED : SRS_UNRESOLVABLE);
+
+ }
+
+ /* Mise à jour de la progression ? */
+
+ else
+ {
+ assert(state_set == SRS_WAIT_FOR_SCAN || state_index == SRS_WAIT_FOR_SCAN);
+
+ if (new_set != expr->set || new_index != expr->index)
+ *out = g_scan_set_item_new(new_set, new_index);
+
+ result = SRS_WAIT_FOR_SCAN;
+
+ }
+
+ /* Sortie propre */
+
+ exit:
+
+ g_clear_object(&new_set);
+ g_clear_object(&new_index);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/item.h b/src/analysis/scan/exprs/item.h
new file mode 100644
index 0000000..9d3cdfb
--- /dev/null
+++ b/src/analysis/scan/exprs/item.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.h - prototypes pour la récupération d'un élément à partir d'une série
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_ITEM_H
+#define _ANALYSIS_SCAN_EXPRS_ITEM_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_SCAN_SET_ITEM g_scan_set_item_get_type()
+#define G_SCAN_SET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SET_ITEM, GScanSetItem))
+#define G_IS_SCAN_SET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SET_ITEM))
+#define G_SCAN_SET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SET_ITEM, GScanSetItemClass))
+#define G_IS_SCAN_SET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SET_ITEM))
+#define G_SCAN_SET_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SET_ITEM, GScanSetItemClass))
+
+
+/* Accès à un élément donné d'une série établie (instance) */
+typedef struct _GScanSetItem GScanSetItem;
+
+/* Accès à un élément donné d'une série établie (classe) */
+typedef struct _GScanSetItemClass GScanSetItemClass;
+
+
+/* Indique le type défini pour la récupération d'un élément à partir d'une série. */
+GType g_scan_set_item_get_type(void);
+
+/* Met en place un accès à un élément donné d'une série. */
+GScanExpression *g_scan_set_item_new(GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_ITEM_H */
diff --git a/src/analysis/scan/exprs/literal-int.h b/src/analysis/scan/exprs/literal-int.h
new file mode 100644
index 0000000..b0a0ec5
--- /dev/null
+++ b/src/analysis/scan/exprs/literal-int.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * literal-int.h - prototypes internes pour la représentation d'une valeur concrète
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H
+#define _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H
+
+
+#include "literal.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Expression portant une valeur concrète (instance) */
+struct _GScanLiteralExpression
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ LiteralValueType value_type; /* Type de valeur portée */
+
+ union
+ {
+ bool boolean; /* Valeur booléenne */
+ long long s_integer; /* Valeur entière 64 bits */
+ unsigned long long u_integer; /* Valeur entière 64 bits */
+ sized_string_t string; /* Chaîne de caractères */
+ struct
+ {
+ char *regex; /* Formulation d'origine */
+ regex_t preg; /* Expression rationnelle */
+ };
+
+ } value;
+
+};
+
+/* Expression portant une valeur concrète (classe) */
+struct _GScanLiteralExpressionClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une expression de valeur concrête. */
+bool g_scan_literal_expression_create(GScanLiteralExpression *, LiteralValueType, ...);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H */
diff --git a/src/analysis/scan/exprs/literal.c b/src/analysis/scan/exprs/literal.c
new file mode 100644
index 0000000..b7aed5b
--- /dev/null
+++ b/src/analysis/scan/exprs/literal.c
@@ -0,0 +1,734 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * literal.c - représentation d'une valeur concrète
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "literal.h"
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+
+#include "literal-int.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des expressions de valeur concrète. */
+static void g_scan_literal_expression_class_init(GScanLiteralExpressionClass *);
+
+/* Initialise une instance d'expression de valeur concrète. */
+static void g_scan_literal_expression_init(GScanLiteralExpression *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_literal_expression_dispose(GScanLiteralExpression *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_literal_expression_finalize(GScanLiteralExpression *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+static bool g_scan_literal_expression_compare_rich(const GScanLiteralExpression *, const GScanLiteralExpression *, RichCmpOperation, bool *);
+
+/* Réduit une expression à une forme booléenne. */
+static bool g_scan_literal_expression_reduce_to_boolean(const GScanLiteralExpression *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Dénombre les éléments portés par une expression. */
+static bool g_scan_literal_expression_count(const GScanLiteralExpression *, GScanContext *, size_t *);
+
+/* Fournit un élément donné issu d'un ensemble constitué. */
+static bool g_scan_literal_expression_get_item(const GScanLiteralExpression *, size_t, GScanContext *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un appel de fonction enregistrée. */
+G_DEFINE_TYPE(GScanLiteralExpression, g_scan_literal_expression, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des expressions de valeur concrète. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_literal_expression_class_init(GScanLiteralExpressionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_literal_expression_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_literal_expression_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)g_scan_literal_expression_compare_rich;
+ expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_literal_expression_reduce_to_boolean;
+ expr->count = (count_scan_expr_fc)g_scan_literal_expression_count;
+ expr->get = (get_scan_expr_fc)g_scan_literal_expression_get_item;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance à initialiser. *
+* *
+* Description : Initialise une instance d'expression de valeur concrète. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_literal_expression_init(GScanLiteralExpression *expr)
+{
+ G_SCAN_EXPRESSION(expr)->state = SRS_REDUCED;
+
+ memset(&expr->value, 0, sizeof(expr->value));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_literal_expression_dispose(GScanLiteralExpression *expr)
+{
+ G_OBJECT_CLASS(g_scan_literal_expression_parent_class)->dispose(G_OBJECT(expr));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_literal_expression_finalize(GScanLiteralExpression *expr)
+{
+ switch (expr->value_type)
+ {
+ case LVT_STRING:
+ exit_szstr(&expr->value.string);
+ break;
+
+ case LVT_REG_EXPR:
+ if (expr->value.regex != NULL)
+ {
+ free(expr->value.regex);
+ regfree(&expr->value.preg);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ G_OBJECT_CLASS(g_scan_literal_expression_parent_class)->finalize(G_OBJECT(expr));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : vtype = type de valeur associée par l'expression. *
+* ... = valeur concrête à intégrer. *
+* *
+* Description : Organise un appel de fonction avec ses arguments. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_literal_expression_new(LiteralValueType vtype, ...)
+{
+ GScanExpression *result; /* Structure à retourner */
+ va_list ap; /* Liste d'arguements */
+ void *ptr; /* Vision générique de valeur */
+
+ result = g_object_new(G_TYPE_SCAN_LITERAL_EXPRESSION, NULL);
+
+ va_start(ap, vtype);
+
+ ptr = va_arg(ap, void *);
+
+ if (!g_scan_literal_expression_create(G_SCAN_LITERAL_EXPRESSION(result), vtype, ptr))
+ g_clear_object(&result);
+
+ va_end(ap);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance à initialiser pleinement. *
+* vtype = type de valeur associée par l'expression. *
+* ... = valeur concrête à intégrer. *
+* *
+* Description : Met en place une expression de valeur concrête. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_literal_expression_create(GScanLiteralExpression *expr, LiteralValueType vtype, ...)
+{
+ bool result; /* Bilan à retourner */
+ va_list ap; /* Liste d'arguements */
+ const bool *boolean; /* Valeur booléenne */
+ const long long *s_integer; /* Valeur entière 64 bits #1 */
+ const unsigned long long *u_integer; /* Valeur entière 64 bits #2 */
+ const sized_string_t *string; /* Chaîne de caractères */
+ const char *raw; /* Chaîne de caractères brute */
+ size_t len; /* Taille de la chaîne */
+ int cflags; /* Détails de compilation */
+ unsigned int i; /* Boucle de parcours */
+ char *tmp; /* Zone de travail temporaire */
+ int ret; /* Bilan d'une opération */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(expr), SRS_REDUCED);
+ if (!result) goto exit;
+
+ va_start(ap, vtype);
+
+ switch (vtype)
+ {
+ case LVT_BOOLEAN:
+ boolean = va_arg(ap, const bool *);
+ expr->value.boolean = *boolean;
+ result = true;
+ break;
+
+ case LVT_SIGNED_INTEGER:
+ s_integer = va_arg(ap, const long long *);
+ expr->value.s_integer = *s_integer;
+ result = true;
+ break;
+
+ case LVT_UNSIGNED_INTEGER:
+ u_integer = va_arg(ap, const unsigned long long *);
+ expr->value.u_integer = *u_integer;
+ result = true;
+ break;
+
+ case LVT_STRING:
+ string = va_arg(ap, const sized_string_t *);
+ szstrdup(&expr->value.string, string);
+ result = true;
+ break;
+
+ case LVT_REG_EXPR:
+ raw = va_arg(ap, const char *);
+ len = strlen(raw);
+
+ result = (len > 2 && raw[0] == '/');
+
+ cflags = REG_EXTENDED | REG_NOSUB;
+
+ for (i = 0; i < 2 && result; i++)
+ {
+ result = (len > 2);
+
+ if (raw[len - 1] == 'i')
+ {
+ cflags |= REG_ICASE;
+ len -= 1;
+ }
+
+ else if (raw[len - 1] == 's')
+ {
+ cflags |= REG_NEWLINE;
+ len -= 1;
+ }
+
+ else if (raw[len - 1] == '/')
+ break;
+
+ }
+
+ if (result)
+ result = (raw[len - 1] == '/');
+
+ if (result)
+ {
+ assert(len > 2);
+
+ tmp = strndup(&raw[1], len - 2);
+ ret = regcomp(&expr->value.preg, tmp, cflags);
+ free(tmp);
+
+ result = (ret == 0);
+
+ if (result)
+ expr->value.regex = strdup(raw);
+
+ }
+
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ va_end(ap);
+
+ expr->value_type = vtype;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* *
+* Description : Indique le type de valeur portée par une expression. *
+* *
+* Retour : Type de valeur associée à l'expression. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+LiteralValueType g_scan_literal_expression_get_value_type(const GScanLiteralExpression *expr)
+{
+ LiteralValueType result; /* Type à retourner */
+
+ result = expr->value_type;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = premier objet à consulter pour une comparaison. *
+* value = valeur portée portée par l'expression. [OUT] *
+* *
+* Description : Indique la valeur portée par une expression booléenne. *
+* *
+* Retour : true si l'expression est de type booléen, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_literal_expression_get_boolean_value(const GScanLiteralExpression *expr, bool *value)
+{
+ bool result; /* Etat à retourner */
+
+ result = (expr->value_type == LVT_BOOLEAN);
+
+ if (result)
+ *value = expr->value.boolean;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = premier objet à consulter pour une comparaison. *
+* value = valeur portée portée par l'expression. [OUT] *
+* *
+* Description : Indique la valeur portée par une expression d'entier. *
+* *
+* Retour : true si l'expression est de type entier, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_literal_expression_get_signed_integer_value(const GScanLiteralExpression *expr, long long *value)
+{
+ bool result; /* Etat à retourner */
+
+ result = (expr->value_type == LVT_SIGNED_INTEGER);
+
+ if (result)
+ *value = expr->value.u_integer;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = premier objet à consulter pour une comparaison. *
+* value = valeur portée portée par l'expression. [OUT] *
+* *
+* Description : Indique la valeur portée par une expression d'entier. *
+* *
+* Retour : true si l'expression est de type entier, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_literal_expression_get_unsigned_integer_value(const GScanLiteralExpression *expr, unsigned long long *value)
+{
+ bool result; /* Etat à retourner */
+
+ result = (expr->value_type == LVT_UNSIGNED_INTEGER);
+
+ if (result)
+ *value = expr->value.u_integer;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = premier objet à consulter pour une comparaison. *
+* value = valeur portée portée par l'expression. [OUT] *
+* *
+* Description : Indique la valeur portée par une expression de chaîne. *
+* *
+* Retour : true si l'expression est de type entier, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_literal_expression_get_string_value(const GScanLiteralExpression *expr, const sized_string_t **value)
+{
+ bool result; /* Etat à retourner */
+
+ result = (expr->value_type == LVT_STRING);
+
+ if (result)
+ *value = &expr->value.string;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = premier objet à consulter pour une comparaison. *
+* value = valeur portée portée par l'expression. [OUT] *
+* *
+* Description : Indique la valeur portée par une expression rationnelle. *
+* *
+* Retour : true si l'expression est de type entier, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_literal_expression_get_regex_value(const GScanLiteralExpression *expr, const regex_t **value)
+{
+ bool result; /* Etat à retourner */
+
+ result = (expr->value_type == LVT_REG_EXPR);
+
+ if (result)
+ *value = &expr->value.preg;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_literal_expression_compare_rich(const GScanLiteralExpression *expr, const GScanLiteralExpression *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+ int cmp; /* Bilan intermédiaire */
+
+ result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_SCAN_LITERAL_EXPRESSION);
+ if (!result) goto done;
+
+ if (expr->value_type != other->value_type)
+ {
+ *status = compare_rich_integer_values_unsigned(expr->value_type, other->value_type, op);
+ goto done;
+ }
+
+ switch (expr->value_type)
+ {
+ case LVT_BOOLEAN:
+ switch (op)
+ {
+ case RCO_EQ:
+ *status = (expr->value.boolean == other->value.boolean);
+ result = true;
+ break;
+
+ case RCO_NE:
+ *status = (expr->value.boolean != other->value.boolean);
+ result = true;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ };
+ break;
+
+ case LVT_SIGNED_INTEGER:
+ *status = compare_rich_integer_values_signed(expr->value.s_integer, other->value.s_integer, op);
+ result = true;
+ break;
+
+ case LVT_UNSIGNED_INTEGER:
+ *status = compare_rich_integer_values_unsigned(expr->value.u_integer, other->value.u_integer, op);
+ result = true;
+ break;
+
+ case LVT_STRING:
+ cmp = szstrcmp(&expr->value.string, &other->value.string);
+ *status = compare_rich_integer_values_signed(cmp, 0, op);
+ result = true;
+ break;
+
+ case LVT_REG_EXPR:
+ cmp = strcmp(expr->value.regex, other->value.regex);
+ *status = compare_rich_integer_values_signed(cmp, 0, op);
+ result = true;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme booléenne. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_literal_expression_reduce_to_boolean(const GScanLiteralExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+
+ switch (expr->value_type)
+ {
+ case LVT_BOOLEAN:
+ *out = G_SCAN_EXPRESSION(expr);
+ g_object_ref(G_OBJECT(expr));
+ result = true;
+ break;
+
+ case LVT_SIGNED_INTEGER:
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.s_integer != 0 });
+ result = true;
+ break;
+
+ case LVT_UNSIGNED_INTEGER:
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.u_integer != 0 });
+ result = true;
+ break;
+
+ case LVT_STRING:
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.string.len > 0 });
+ result = true;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* count = quantité d'éléments déterminée. [OUT] *
+* *
+* Description : Dénombre les éléments portés par une expression. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_literal_expression_count(const GScanLiteralExpression *expr, GScanContext *ctx, size_t *count)
+{
+ bool result; /* Bilan à retourner */
+
+ switch (expr->value_type)
+ {
+ case LVT_STRING:
+ *count = expr->value.string.len;
+ result = true;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* index = indice de l'élément à transférer. *
+* ctx = contexte de suivi de l'analyse courante. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Fournit un élément donné issu d'un ensemble constitué. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_literal_expression_get_item(const GScanLiteralExpression *expr, size_t index, GScanContext *ctx, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t ch; /* Caractère extrait */
+
+ switch (expr->value_type)
+ {
+ case LVT_STRING:
+
+ result = (index < expr->value.string.len);
+
+ if (result)
+ {
+ ch.data = expr->value.string.data + index;
+ ch.len = 1;
+
+ *out = g_scan_literal_expression_new(LVT_STRING, &ch);
+
+ }
+
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/literal.h b/src/analysis/scan/exprs/literal.h
new file mode 100644
index 0000000..9352baf
--- /dev/null
+++ b/src/analysis/scan/exprs/literal.h
@@ -0,0 +1,90 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * literal.h - prototypes pour la représentation d'une valeur concrète
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_LITERAL_H
+#define _ANALYSIS_SCAN_EXPRS_LITERAL_H
+
+
+#include <regex.h>
+#include <stdbool.h>
+
+
+#include "../expr.h"
+#include "../../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_LITERAL_EXPRESSION g_scan_literal_expression_get_type()
+#define G_SCAN_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_LITERAL_EXPRESSION, GScanLiteralExpression))
+#define G_IS_SCAN_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_LITERAL_EXPRESSION))
+#define G_SCAN_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_LITERAL_EXPRESSION, GScanLiteralExpressionClass))
+#define G_IS_SCAN_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_LITERAL_EXPRESSION))
+#define G_SCAN_LITERAL_EXPRESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_LITERAL_EXPRESSION, GScanLiteralExpressionClass))
+
+
+/* Expression portant une valeur concrète (instance) */
+typedef struct _GScanLiteralExpression GScanLiteralExpression;
+
+/* Expression portant une valeur concrète (classe) */
+typedef struct _GScanLiteralExpressionClass GScanLiteralExpressionClass;
+
+
+/* Types naturel équivalant à l'expression */
+typedef enum _LiteralValueType
+{
+ LVT_BOOLEAN, /* Valeur booléenne */
+ LVT_SIGNED_INTEGER, /* Nombre entier 64 bits #1 */
+ LVT_UNSIGNED_INTEGER, /* Nombre entier 64 bits #2 */
+ LVT_STRING, /* Chaîne de caractères */
+ LVT_REG_EXPR, /* Expression rationnelle */
+
+} LiteralValueType;
+
+
+/* Indique le type défini pour un appel de fonction enregistrée. */
+GType g_scan_literal_expression_get_type(void);
+
+/* Organise un appel de fonction avec ses arguments. */
+GScanExpression *g_scan_literal_expression_new(LiteralValueType, ...);
+
+/* Indique le type de valeur portée par une expression. */
+LiteralValueType g_scan_literal_expression_get_value_type(const GScanLiteralExpression *);
+
+/* Indique la valeur portée par une expression booléenne. */
+bool g_scan_literal_expression_get_boolean_value(const GScanLiteralExpression *, bool *);
+
+/* Indique la valeur portée par une expression d'entier. */
+bool g_scan_literal_expression_get_signed_integer_value(const GScanLiteralExpression *, long long *);
+
+/* Indique la valeur portée par une expression d'entier. */
+bool g_scan_literal_expression_get_unsigned_integer_value(const GScanLiteralExpression *, unsigned long long *);
+
+/* Indique la valeur portée par une expression de chaîne. */
+bool g_scan_literal_expression_get_string_value(const GScanLiteralExpression *, const sized_string_t **);
+
+/* Indique la valeur portée par une expression rationnelle. */
+bool g_scan_literal_expression_get_regex_value(const GScanLiteralExpression *, const regex_t **);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_LITERAL_H */
diff --git a/src/analysis/scan/exprs/logical-int.h b/src/analysis/scan/exprs/logical-int.h
new file mode 100644
index 0000000..6df55d0
--- /dev/null
+++ b/src/analysis/scan/exprs/logical-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * logical-int.h - prototypes internes pour la gestion des opérations booléennes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_LOGICAL_INT_H
+#define _ANALYSIS_SCAN_EXPRS_LOGICAL_INT_H
+
+
+#include "logical.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Opération booléenne avec un ou deux opérandes (instance) */
+struct _GScanLogicalOperation
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ BooleanOperationType type; /* Type d'opération menée */
+
+ GScanExpression *first; /* Expression impactée #1 */
+ GScanExpression *second; /* Expression impactée #2 */
+
+};
+
+/* Opération booléenne avec un ou deux opérandes (classe) */
+struct _GScanLogicalOperationClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une expression d'opération booléenne. */
+bool g_scan_logical_operation_create(GScanLogicalOperation *, BooleanOperationType, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_LOGICAL_INT_H */
diff --git a/src/analysis/scan/exprs/logical.c b/src/analysis/scan/exprs/logical.c
new file mode 100644
index 0000000..3b07843
--- /dev/null
+++ b/src/analysis/scan/exprs/logical.c
@@ -0,0 +1,518 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * logical.c - gestion des opérations booléennes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "logical.h"
+
+
+#include <assert.h>
+
+
+#include "logical-int.h"
+#include "literal.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des opérations booléennes. */
+static void g_scan_logical_operation_class_init(GScanLogicalOperationClass *);
+
+/* Initialise une instance d'opération booléenne. */
+static void g_scan_logical_operation_init(GScanLogicalOperation *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_logical_operation_dispose(GScanLogicalOperation *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_logical_operation_finalize(GScanLogicalOperation *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+static bool g_scan_logical_operation_compare_rich(const GScanLogicalOperation *, const GScanLogicalOperation *, RichCmpOperation, bool *);
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_logical_operation_reduce(const GScanLogicalOperation *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une opération booléenne sur expression(s). */
+G_DEFINE_TYPE(GScanLogicalOperation, g_scan_logical_operation, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des opérations booléennes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_logical_operation_class_init(GScanLogicalOperationClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_logical_operation_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_logical_operation_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)g_scan_logical_operation_compare_rich;
+ expr->reduce = (reduce_expr_fc)g_scan_logical_operation_reduce;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser. *
+* *
+* Description : Initialise une instance d'opération booléenne. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_logical_operation_init(GScanLogicalOperation *op)
+{
+ op->first = NULL;
+ op->second = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_logical_operation_dispose(GScanLogicalOperation *op)
+{
+ g_clear_object(&op->first);
+ g_clear_object(&op->second);
+
+ G_OBJECT_CLASS(g_scan_logical_operation_parent_class)->dispose(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_logical_operation_finalize(GScanLogicalOperation *op)
+{
+ G_OBJECT_CLASS(g_scan_logical_operation_parent_class)->finalize(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type d'opération booléenne à représenter. *
+* first = premier opérande concerné. *
+* second = éventuel second opérande impliqué ou NULL. *
+* *
+* Description : Organise un appel de fonction avec ses arguments. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_logical_operation_new(BooleanOperationType type, GScanExpression *first, GScanExpression *second)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_BOOLEAN_OPERATION, NULL);
+
+ if (!g_scan_logical_operation_create(G_SCAN_LOGICAL_OPERATION(result), type, first, second))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = instance à initialiser pleinement. *
+* type = type d'opération booléenne à représenter. *
+* first = premier opérande concerné. *
+* second = éventuel second opérande impliqué ou NULL. *
+* *
+* Description : Met en place une expression d'opération booléenne. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_logical_operation_create(GScanLogicalOperation *op, BooleanOperationType type, GScanExpression *first, GScanExpression *second)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING);
+ if (!result) goto exit;
+
+ op->type = type;
+
+ switch (type)
+ {
+ case BOT_AND:
+ case BOT_OR:
+ op->first = first;
+ g_object_ref(G_OBJECT(op->first));
+
+ op->second = second;
+ g_object_ref(G_OBJECT(op->second));
+
+ result = true;
+ break;
+
+ case BOT_NOT:
+ op->first = first;
+ g_object_ref(G_OBJECT(op->first));
+
+ result = (second == NULL);
+ assert(second == NULL);
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_logical_operation_compare_rich(const GScanLogicalOperation *item, const GScanLogicalOperation *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+
+ result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_BOOLEAN_OPERATION);
+ if (!result) goto done;
+
+ if (item->type != other->type)
+ {
+ *status = compare_rich_integer_values_unsigned(item->type, other->type, op);
+ goto done;
+ }
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status);
+ if (!result || STATUS_NOT_EQUAL(*status, op)) goto done;
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first),
+ G_COMPARABLE_ITEM(other->first),
+ op, status);
+ if (!result || STATUS_NOT_EQUAL(*status, op)) goto done;
+
+ if (item->second == NULL)
+ {
+ assert(other->second == NULL);
+
+ switch (op)
+ {
+ case RCO_LT:
+ case RCO_NE:
+ case RCO_GT:
+ *status = false;
+ break;
+
+ case RCO_LE:
+ case RCO_EQ:
+ case RCO_GE:
+ *status = true;
+ break;
+
+ }
+
+ }
+
+ else
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second),
+ G_COMPARABLE_ITEM(other->second),
+ op, status);
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_logical_operation_reduce(const GScanLogicalOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanExpression *new_first; /* Expression réduite (gauche) */
+ ScanReductionState state[2]; /* Bilan de sous-réductons */
+ GScanExpression *new_second; /* Expression réduite (droite) */
+ GScanExpression *bool_operands[2]; /* Expressions booléennes */
+ bool values[2]; /* Valeurs des éléments portés */
+ bool valid[2]; /* Validité de ces valeurs */
+
+ /* Réduction des éléments considérés */
+
+ state[0] = g_scan_expression_reduce(expr->first, ctx, scope, &new_first);
+
+ if (expr->second != NULL)
+ state[1] = g_scan_expression_reduce(expr->second, ctx, scope, &new_second);
+ else
+ {
+ new_second = NULL;
+ state[1] = SRS_REDUCED;
+ }
+
+ /* Récupération des valeurs booléennes */
+
+ if (new_first != NULL)
+ {
+ valid[0] = g_scan_expression_reduce_to_boolean(new_first, ctx, scope, &bool_operands[0]);
+
+ if (valid[0])
+ valid[0] = g_scan_literal_expression_get_boolean_value(G_SCAN_LITERAL_EXPRESSION(bool_operands[0]),
+ &values[0]);
+ else
+ bool_operands[0] = NULL;
+
+ }
+ else
+ {
+ bool_operands[0] = NULL;
+ valid[0] = false;
+ }
+
+ if (new_second != NULL)
+ {
+ valid[1] = g_scan_expression_reduce_to_boolean(new_second, ctx, scope, &bool_operands[1]);
+
+ if (valid[1])
+ valid[1] = g_scan_literal_expression_get_boolean_value(G_SCAN_LITERAL_EXPRESSION(bool_operands[1]),
+ &values[1]);
+ else
+ bool_operands[1] = NULL;
+
+ }
+ else
+ {
+ bool_operands[1] = NULL;
+ valid[1] = false;
+ }
+
+ /* Construction d'une réduction locale ? */
+
+ switch (expr->type)
+ {
+ case BOT_AND:
+ if (valid[0] && valid[1])
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { values[0] && values[1] });
+ result = SRS_REDUCED;
+ }
+
+ else if (valid[0] && !values[0])
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { false });
+ result = SRS_REDUCED;
+ }
+
+ else if (valid[1] && !values[1])
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { false });
+ result = SRS_REDUCED;
+ }
+
+ else
+ {
+ if (state[0] == SRS_UNRESOLVABLE || state[1] == SRS_UNRESOLVABLE)
+ result = SRS_UNRESOLVABLE;
+ else
+ {
+ assert(state[0] == SRS_WAIT_FOR_SCAN || state[1] == SRS_WAIT_FOR_SCAN);
+ result = SRS_WAIT_FOR_SCAN;
+ }
+ }
+
+ break;
+
+ case BOT_OR:
+ if (valid[0] && valid[1])
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { values[0] || values[1] });
+ result = SRS_REDUCED;
+ }
+
+ else if (valid[0] && values[0])
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { true });
+ result = SRS_REDUCED;
+ }
+
+ else if (valid[1] && values[1])
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { true });
+ result = SRS_REDUCED;
+ }
+
+ else
+ {
+ if (state[0] == SRS_UNRESOLVABLE || state[1] == SRS_UNRESOLVABLE)
+ result = SRS_UNRESOLVABLE;
+ else
+ {
+ assert(state[0] == SRS_WAIT_FOR_SCAN || state[1] == SRS_WAIT_FOR_SCAN);
+ result = SRS_WAIT_FOR_SCAN;
+ }
+ }
+
+ break;
+
+ case BOT_NOT:
+ if (valid[0])
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { !values[0] });
+ result = SRS_REDUCED;
+ }
+
+ else
+ {
+ if (state[0] == SRS_UNRESOLVABLE)
+ result = SRS_UNRESOLVABLE;
+ else
+ {
+ assert(state[0] == SRS_WAIT_FOR_SCAN);
+ result = SRS_WAIT_FOR_SCAN;
+ }
+ }
+
+ break;
+
+ /* Pour GCC... */
+ default:
+ result = SRS_UNRESOLVABLE;
+ break;
+
+ }
+
+ /* Mise à jour de la progression ? */
+
+ if (result == SRS_WAIT_FOR_SCAN)
+ {
+ if (new_first != expr->first || new_second != expr->second)
+ {
+ assert(new_first != NULL);
+ assert(new_second != NULL || expr->second == NULL);
+
+ *out = g_scan_logical_operation_new(expr->type, new_first, new_second);
+
+ }
+
+ }
+
+ /* Sortie propre */
+
+ g_clear_object(&bool_operands[0]);
+ g_clear_object(&bool_operands[1]);
+
+ g_clear_object(&new_first);
+ g_clear_object(&new_second);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/logical.h b/src/analysis/scan/exprs/logical.h
new file mode 100644
index 0000000..e98bf11
--- /dev/null
+++ b/src/analysis/scan/exprs/logical.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * logical.h - prototypes pour la gestion des opérations booléennes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_LOGICAL_H
+#define _ANALYSIS_SCAN_EXPRS_LOGICAL_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_BOOLEAN_OPERATION g_scan_logical_operation_get_type()
+#define G_SCAN_LOGICAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BOOLEAN_OPERATION, GScanLogicalOperation))
+#define G_IS_BOOLEAN_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BOOLEAN_OPERATION))
+#define G_SCAN_LOGICAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BOOLEAN_OPERATION, GScanLogicalOperationClass))
+#define G_IS_BOOLEAN_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BOOLEAN_OPERATION))
+#define G_SCAN_LOGICAL_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BOOLEAN_OPERATION, GScanLogicalOperationClass))
+
+
+/* Opération booléenne avec un ou deux opérandes (instance) */
+typedef struct _GScanLogicalOperation GScanLogicalOperation;
+
+/* Opération booléenne avec un ou deux opérandes (classe) */
+typedef struct _GScanLogicalOperationClass GScanLogicalOperationClass;
+
+
+/* Types d'opérations booléennes supportées */
+typedef enum _BooleanOperationType
+{
+ BOT_AND, /* Opérateur binaire "and" */
+ BOT_OR, /* Opérateur binaire "or" */
+ BOT_NOT, /* Opérateur unaire "not" */
+
+} BooleanOperationType;
+
+
+/* Indique le type défini pour une opération booléenne sur expression(s). */
+GType g_scan_logical_operation_get_type(void);
+
+/* Organise un appel de fonction avec ses arguments. */
+GScanExpression *g_scan_logical_operation_new(BooleanOperationType, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_LOGICAL_H */
diff --git a/src/analysis/scan/exprs/range-int.h b/src/analysis/scan/exprs/range-int.h
new file mode 100644
index 0000000..6257874
--- /dev/null
+++ b/src/analysis/scan/exprs/range-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * range-int.h - prototypes internes pour la représentation compacte d'un éventail de valeurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_RANGE_INT_H
+#define _ANALYSIS_SCAN_EXPRS_RANGE_INT_H
+
+
+#include "range.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Représentation compacte d'un éventail de valeurs (instance) */
+struct _GScanCompactRange
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ GScanExpression *start; /* Point de départ */
+ GScanExpression *end; /* Point d'arrivée */
+
+};
+
+/* Représentation compacte d'un éventail de valeurs (classe) */
+struct _GScanCompactRangeClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une réprésentation d'un éventail de valeurs. */
+bool g_scan_compact_range_create(GScanCompactRange *, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_RANGE_INT_H */
diff --git a/src/analysis/scan/exprs/range.c b/src/analysis/scan/exprs/range.c
new file mode 100644
index 0000000..9716149
--- /dev/null
+++ b/src/analysis/scan/exprs/range.c
@@ -0,0 +1,355 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * range.c - représentation compacte d'un éventail de valeurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "range.h"
+
+
+#include "literal.h"
+#include "range-int.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des éventail de valeurs. */
+static void g_scan_compact_range_class_init(GScanCompactRangeClass *);
+
+/* Initialise une instance d'éventail de valeurs. */
+static void g_scan_compact_range_init(GScanCompactRange *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_compact_range_dispose(GScanCompactRange *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_compact_range_finalize(GScanCompactRange *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_compact_range_reduce(const GScanCompactRange *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Réduit une expression à une forme booléenne. */
+static bool g_scan_compact_range_reduce_to_boolean(const GScanCompactRange *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Réalise l'intersection entre deux ensembles. */
+static GScanExpression *g_scan_compact_range_intersect(const GScanCompactRange *expr, const GScanExpression *, GScanContext *, GScanScope *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une représentation compacte d'un éventail de valeurs. */
+G_DEFINE_TYPE(GScanCompactRange, g_scan_compact_range, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des éventail de valeurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_compact_range_class_init(GScanCompactRangeClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_compact_range_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_compact_range_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->reduce = (reduce_expr_fc)g_scan_compact_range_reduce;
+ expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_compact_range_reduce_to_boolean;
+ expr->intersect = (intersect_scan_expr_fc)g_scan_compact_range_intersect;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : range = instance à initialiser. *
+* *
+* Description : Initialise une instance d'éventail de valeurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_compact_range_init(GScanCompactRange *range)
+{
+ range->start = NULL;
+ range->end = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : range = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_compact_range_dispose(GScanCompactRange *range)
+{
+ g_clear_object(&range->start);
+ g_clear_object(&range->end);
+
+ G_OBJECT_CLASS(g_scan_compact_range_parent_class)->dispose(G_OBJECT(range));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : range = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_compact_range_finalize(GScanCompactRange *range)
+{
+ G_OBJECT_CLASS(g_scan_compact_range_parent_class)->finalize(G_OBJECT(range));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : start = point de départ de la plage de valeurs. *
+* end = point d'arrivée de la plage de valeurs. *
+* *
+* Description : Organise une réprésentation d'un éventail de valeurs. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_compact_range_new(GScanExpression *start, GScanExpression *end)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_COMPACT_RANGE, NULL);
+
+ if (!g_scan_compact_range_create(G_SCAN_COMPACT_RANGE(result), start, end))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : range = instance à initialiser pleinement. *
+* start = point de départ de la plage de valeurs. *
+* end = point d'arrivée de la plage de valeurs. *
+* *
+* Description : Met en place une réprésentation d'un éventail de valeurs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_compact_range_create(GScanCompactRange *range, GScanExpression *start, GScanExpression *end)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(range), SRS_PENDING);
+ if (!result) goto exit;
+
+ range->start = start;
+ g_object_ref(G_OBJECT(start));
+
+ range->end = end;
+ g_object_ref(G_OBJECT(end));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_compact_range_reduce(const GScanCompactRange *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanExpression *new_start; /* Nouvelle réduction #1 */
+ GScanExpression *new_end; /* Nouvelle réduction #2 */
+ ScanReductionState state_start; /* Etat synthétisé #1 */
+ ScanReductionState state_end; /* Etat synthétisé #2 */
+
+ new_start = NULL;
+ new_end = NULL;
+
+ state_start = g_scan_expression_reduce(expr->start, ctx, scope, &new_start);
+ if (state_start == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ state_end = g_scan_expression_reduce(expr->end, ctx, scope, &new_end);
+ if (state_end == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (state_start == SRS_WAIT_FOR_SCAN || state_end == SRS_WAIT_FOR_SCAN)
+ result = SRS_WAIT_FOR_SCAN;
+ else
+ result = SRS_REDUCED;
+
+ if (new_start != expr->start || new_end != expr->end)
+ *out = g_scan_compact_range_new(new_start, new_end);
+
+ exit:
+
+ g_clear_object(&new_start);
+ g_clear_object(&new_end);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme booléenne. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_compact_range_reduce_to_boolean(const GScanCompactRange *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ bool status; /* Bilan d'une comparaison */
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(expr->start) && G_IS_SCAN_LITERAL_EXPRESSION(expr->end);
+ if (!result) goto exit;
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(expr->start),
+ G_COMPARABLE_ITEM(expr->end),
+ RCO_LE, &status);
+ if (!result) goto exit;
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à filtrer. *
+* other = expression utilisée pour le filtrage. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* *
+* Description : Réalise l'intersection entre deux ensembles. *
+* *
+* Retour : Intersection entre les deux ensembles ou NULL en cas d'échec.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GScanExpression *g_scan_compact_range_intersect(const GScanCompactRange *expr, const GScanExpression *other, GScanContext *ctx, GScanScope *scope)
+{
+ GScanExpression *result; /* Instance à retourner */
+
+
+
+
+ result = true; // TODO
+
+
+
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/range.h b/src/analysis/scan/exprs/range.h
new file mode 100644
index 0000000..4b7ad04
--- /dev/null
+++ b/src/analysis/scan/exprs/range.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * range.h - prototypes pour la représentation compacte d'un éventail de valeurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_SET_H
+#define _ANALYSIS_SCAN_EXPRS_SET_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_SCAN_COMPACT_RANGE g_scan_compact_range_get_type()
+#define G_SCAN_COMPACT_RANGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_COMPACT_RANGE, GScanCompactRange))
+#define G_IS_SCAN_COMPACT_RANGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_COMPACT_RANGE))
+#define G_SCAN_COMPACT_RANGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_COMPACT_RANGE, GScanCompactRangeClass))
+#define G_IS_SCAN_COMPACT_RANGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_COMPACT_RANGE))
+#define G_SCAN_COMPACT_RANGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_COMPACT_RANGE, GScanCompactRangeClass))
+
+
+/* Représentation compacte d'un éventail de valeurs (instance) */
+typedef struct _GScanCompactRange GScanCompactRange;
+
+/* Représentation compacte d'un éventail de valeurs (classe) */
+typedef struct _GScanCompactRangeClass GScanCompactRangeClass;
+
+
+/* Indique le type défini pour une représentation compacte d'un éventail de valeurs. */
+GType g_scan_compact_range_get_type(void);
+
+/* Organise une réprésentation d'un éventail de valeurs. */
+GScanExpression *g_scan_compact_range_new(GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_SET_H */
diff --git a/src/analysis/scan/exprs/relational-int.h b/src/analysis/scan/exprs/relational-int.h
new file mode 100644
index 0000000..813b89d
--- /dev/null
+++ b/src/analysis/scan/exprs/relational-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * relational-int.h - prototypes internes pour la gestion des opérations relationnelles
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_RELATIONAL_INT_H
+#define _ANALYSIS_SCAN_EXPRS_RELATIONAL_INT_H
+
+
+#include "relational.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Opération relationnelle impliquant deux opérandes (instance) */
+struct _GScanRelationalOperation
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ RichCmpOperation rel_type; /* Type de relation étudiée */
+
+ GScanExpression *left; /* Expression impactée #1 */
+ GScanExpression *right; /* Expression impactée #2 */
+
+};
+
+/* Opération relationnelle impliquant deux opérandes (classe) */
+struct _GScanRelationalOperationClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une opération relationnelle entre expressions. */
+bool g_scan_relational_operation_create(GScanRelationalOperation *, RichCmpOperation, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_RELATIONAL_INT_H */
diff --git a/src/analysis/scan/exprs/relational.c b/src/analysis/scan/exprs/relational.c
new file mode 100644
index 0000000..74a972b
--- /dev/null
+++ b/src/analysis/scan/exprs/relational.c
@@ -0,0 +1,411 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * relational.c - gestion des opérations relationnelles
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "relational.h"
+
+
+#include <assert.h>
+
+
+#include "relational-int.h"
+#include "literal.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des opérations de relations. */
+static void g_scan_relational_operation_class_init(GScanRelationalOperationClass *);
+
+/* Initialise une instance d'opération de relation. */
+static void g_scan_relational_operation_init(GScanRelationalOperation *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_relational_operation_dispose(GScanRelationalOperation *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_relational_operation_finalize(GScanRelationalOperation *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+static bool g_scan_relational_operation_compare_rich(const GScanRelationalOperation *, const GScanRelationalOperation *, RichCmpOperation, bool *);
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_relational_operation_reduce(const GScanRelationalOperation *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une opération de relation entre expressions. */
+G_DEFINE_TYPE(GScanRelationalOperation, g_scan_relational_operation, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des opérations de relations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_relational_operation_class_init(GScanRelationalOperationClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_relational_operation_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_relational_operation_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)g_scan_relational_operation_compare_rich;
+ expr->reduce = (reduce_expr_fc)g_scan_relational_operation_reduce;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser. *
+* *
+* Description : Initialise une instance d'opération de relation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_relational_operation_init(GScanRelationalOperation *op)
+{
+ op->left = NULL;
+ op->right = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_relational_operation_dispose(GScanRelationalOperation *op)
+{
+ g_clear_object(&op->left);
+ g_clear_object(&op->right);
+
+ G_OBJECT_CLASS(g_scan_relational_operation_parent_class)->dispose(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_relational_operation_finalize(GScanRelationalOperation *op)
+{
+ G_OBJECT_CLASS(g_scan_relational_operation_parent_class)->finalize(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type d'opération booléenne à représenter. *
+* left = premier opérande concerné. *
+* right = éventuel second opérande impliqué ou NULL. *
+* *
+* Description : Organise une opération relationnelle entre expressions. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_relational_operation_new(RichCmpOperation type, GScanExpression *left, GScanExpression *right)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_RELATIONAL_OPERATION, NULL);
+
+ if (!g_scan_relational_operation_create(G_SCAN_RELATIONAL_OPERATION(result), type, left, right))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser pleinement. *
+* type = type d'opération booléenne à représenter. *
+* left = premier opérande concerné. *
+* right = éventuel second opérande impliqué ou NULL. *
+* *
+* Description : Met en place une opération relationnelle entre expressions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_relational_operation_create(GScanRelationalOperation *op, RichCmpOperation type, GScanExpression *left, GScanExpression *right)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING);
+ if (!result) goto exit;
+
+ op->rel_type = type;
+
+ op->left = left;
+ g_object_ref(G_OBJECT(op->left));
+
+ op->right = right;
+ g_object_ref(G_OBJECT(op->right));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_relational_operation_compare_rich(const GScanRelationalOperation *item, const GScanRelationalOperation *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+
+ result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_SCAN_RELATIONAL_OPERATION);
+ if (!result) goto done;
+
+ if (item->rel_type != other->rel_type)
+ {
+ *status = compare_rich_integer_values_unsigned(item->rel_type, other->rel_type, op);
+ goto done;
+ }
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status);
+ if (!result || STATUS_NOT_EQUAL(*status, op)) goto done;
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->left),
+ G_COMPARABLE_ITEM(other->left),
+ op, status);
+ if (!result || STATUS_NOT_EQUAL(*status, op)) goto done;
+
+ result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->right),
+ G_COMPARABLE_ITEM(other->right),
+ op, status);
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_relational_operation_reduce(const GScanRelationalOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanExpression *new_left; /* Expression réduite (gauche) */
+ GScanExpression *new_right; /* Expression réduite (droite) */
+ ScanReductionState state_left; /* Etat synthétisé #1 */
+ ScanReductionState state_right; /* Etat synthétisé #2 */
+ LiteralValueType vtype_left; /* Type de valeur portée #1 */
+ LiteralValueType vtype_right; /* Type de valeur portée #2 */
+ GScanExpression *casted; /* Nouvelle forme en booléen */
+ bool status; /* Bilan d'une comparaison */
+ bool valid; /* Validité de ce bilan obtenu */
+
+ /* Réduction des éléments considérés */
+
+ new_left = NULL;
+ new_right = NULL;
+
+ state_left = g_scan_expression_reduce(expr->left, ctx, scope, &new_left);
+ if (state_left == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ state_right = g_scan_expression_reduce(expr->right, ctx, scope, &new_right);
+ if (state_right == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ /* Transtypage vers des booléens imposé ? */
+
+ if (expr->rel_type == RCO_EQ || expr->rel_type == RCO_NE)
+ {
+ if (G_IS_SCAN_LITERAL_EXPRESSION(new_left))
+ {
+ vtype_left = g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(new_left));
+
+ if (vtype_left == LVT_BOOLEAN)
+ {
+ if (g_scan_expression_reduce_to_boolean(new_right, ctx, scope, &casted))
+ {
+ g_object_unref(G_OBJECT(new_right));
+ new_right = casted;
+ }
+ }
+
+ }
+
+ if (G_IS_SCAN_LITERAL_EXPRESSION(new_right))
+ {
+ vtype_right = g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(new_right));
+
+ if (vtype_right == LVT_BOOLEAN)
+ {
+ if (g_scan_expression_reduce_to_boolean(new_left, ctx, scope, &casted))
+ {
+ g_object_unref(G_OBJECT(new_left));
+ new_left = casted;
+ }
+ }
+
+ }
+
+ }
+
+ /* Construction d'une réduction locale ? */
+
+ if (G_IS_SCAN_LITERAL_EXPRESSION(new_left) && G_IS_SCAN_LITERAL_EXPRESSION(new_right))
+ {
+ valid = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(new_left),
+ G_COMPARABLE_ITEM(new_right),
+ expr->rel_type, &status);
+
+ if (valid)
+ {
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { status });
+ result = SRS_REDUCED;
+ }
+ else
+ result = SRS_UNRESOLVABLE;
+
+ }
+
+ /* Mise à jour de la progression ? */
+
+ else if (state_left == SRS_WAIT_FOR_SCAN || state_right == SRS_WAIT_FOR_SCAN)
+ {
+ if (new_left != expr->left || new_right != expr->right)
+ *out = g_scan_relational_operation_new(expr->rel_type, new_left, new_right);
+
+ result = SRS_WAIT_FOR_SCAN;
+
+ }
+
+ /* Cas des situations où les expressions ne sont pas exploitables (!) */
+ else
+ {
+ assert(state_left == SRS_REDUCED && state_right == SRS_REDUCED);
+
+ result = SRS_UNRESOLVABLE;
+
+ }
+
+ /* Sortie propre */
+
+ exit:
+
+ g_clear_object(&new_left);
+ g_clear_object(&new_right);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/relational.h b/src/analysis/scan/exprs/relational.h
new file mode 100644
index 0000000..10d58a6
--- /dev/null
+++ b/src/analysis/scan/exprs/relational.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * relational.h - prototypes pour la gestion des opérations relationnelles
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_RELATIONAL_H
+#define _ANALYSIS_SCAN_EXPRS_RELATIONAL_H
+
+
+#include "../expr.h"
+#include "../../../glibext/comparison.h"
+
+
+
+#define G_TYPE_SCAN_RELATIONAL_OPERATION g_scan_relational_operation_get_type()
+#define G_SCAN_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_RELATIONAL_OPERATION, GScanRelationalOperation))
+#define G_IS_SCAN_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_RELATIONAL_OPERATION))
+#define G_SCAN_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_RELATIONAL_OPERATION, GScanRelationalOperationClass))
+#define G_IS_SCAN_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_RELATIONAL_OPERATION))
+#define G_SCAN_RELATIONAL_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_RELATIONAL_OPERATION, GScanRelationalOperationClass))
+
+
+/* Opération relationnelle impliquant deux opérandes (instance) */
+typedef struct _GScanRelationalOperation GScanRelationalOperation;
+
+/* Opération relationnelle impliquant deux opérandes (classe) */
+typedef struct _GScanRelationalOperationClass GScanRelationalOperationClass;
+
+
+/* Indique le type défini pour une opération de relation entre expressions. */
+GType g_scan_relational_operation_get_type(void);
+
+/* Organise une opération relationnelle entre expressions. */
+GScanExpression *g_scan_relational_operation_new(RichCmpOperation, GScanExpression *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_RELATIONAL_H */
diff --git a/src/analysis/scan/exprs/set-int.h b/src/analysis/scan/exprs/set-int.h
new file mode 100644
index 0000000..10ca8d0
--- /dev/null
+++ b/src/analysis/scan/exprs/set-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * set-int.h - prototypes internes pour la base d'ensembles de valeurs diverses, de types hétérogènes ou homogènes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_SET_INT_H
+#define _ANALYSIS_SCAN_EXPRS_SET_INT_H
+
+
+#include "set.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Base d'un ensemble d'éléments homogènes ou hétérogènes (instance) */
+struct _GScanGenericSet
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ GScanExpression **items; /* Liste d'éléments embarqués */
+ size_t count; /* Quantité de ces éléments */
+
+};
+
+/* Base d'un ensemble d'éléments homogènes ou hétérogènes (classe) */
+struct _GScanGenericSetClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un ensemble d'éléments homogènes ou hétérogènes. */
+bool g_scan_generic_set_create(GScanGenericSet *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_SET_INT_H */
diff --git a/src/analysis/scan/exprs/set.c b/src/analysis/scan/exprs/set.c
new file mode 100644
index 0000000..438e7e3
--- /dev/null
+++ b/src/analysis/scan/exprs/set.c
@@ -0,0 +1,407 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * set.c - base d'ensembles de valeurs diverses, de types hétérogènes ou homogènes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "set.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "literal.h"
+#include "set-int.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des bases d'ensembles d'éléments. */
+static void g_scan_generic_set_class_init(GScanGenericSetClass *);
+
+/* Initialise une instance de base d'ensemble d'éléments. */
+static void g_scan_generic_set_init(GScanGenericSet *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_generic_set_dispose(GScanGenericSet *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_generic_set_finalize(GScanGenericSet *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_generic_set_reduce(const GScanGenericSet *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Réduit une expression à une forme booléenne. */
+static bool g_scan_generic_set_reduce_to_boolean(const GScanGenericSet *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Dénombre les éléments portés par une expression. */
+static bool g_scan_generic_set_count_items(const GScanGenericSet *, GScanContext *, size_t *);
+
+/* Fournit un élément donné issu d'un ensemble constitué. */
+static bool g_scan_generic_set_get_item(const GScanGenericSet *, size_t, GScanContext *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une base d'ensembles d'éléments homogènes ou hétérogènes. */
+G_DEFINE_TYPE(GScanGenericSet, g_scan_generic_set, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bases d'ensembles d'éléments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_generic_set_class_init(GScanGenericSetClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_generic_set_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_generic_set_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->reduce = (reduce_expr_fc)g_scan_generic_set_reduce;
+ expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_generic_set_reduce_to_boolean;
+ expr->count = (count_scan_expr_fc)g_scan_generic_set_count_items;
+ expr->get = (get_scan_expr_fc)g_scan_generic_set_get_item;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : set = instance à initialiser. *
+* *
+* Description : Initialise une instance de base d'ensemble d'éléments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_generic_set_init(GScanGenericSet *set)
+{
+ set->items = NULL;
+ set->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : set = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_generic_set_dispose(GScanGenericSet *set)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < set->count; i++)
+ g_clear_object(&set->items[i]);
+
+ G_OBJECT_CLASS(g_scan_generic_set_parent_class)->dispose(G_OBJECT(set));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : set = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_generic_set_finalize(GScanGenericSet *set)
+{
+ if (set->items != NULL)
+ free(set->items);
+
+ G_OBJECT_CLASS(g_scan_generic_set_parent_class)->finalize(G_OBJECT(set));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue un ensemble d'éléments homogènes ou hétérogènes. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_generic_set_new(void)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_GENERIC_SET, NULL);
+
+ if (!g_scan_generic_set_create(G_SCAN_GENERIC_SET(result)))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : set = instance à initialiser pleinement. *
+* *
+* Description : Met en place un ensemble d'éléments homogènes ou hétérogènes.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_generic_set_create(GScanGenericSet *set)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(set), SRS_PENDING);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : set = ensemble à compléter. *
+* item = nouvel élément à intégrer. *
+* *
+* Description : Ajoute un nouvel élément à un ensemble. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_generic_set_add_item(GScanGenericSet *set, GScanExpression *item)
+{
+ set->items = realloc(set->items, ++set->count * sizeof(GScanExpression *));
+
+ set->items[set->count - 1] = item;
+ g_object_ref(G_OBJECT(item));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_generic_set_reduce(const GScanGenericSet *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ GScanExpression *item; /* Elément en cours d'analyse */
+ GScanExpression *new; /* Nouvelle réduction obtenue */
+ ScanReductionState state; /* Etat synthétisé d'un élément*/
+ size_t k; /* Boucle de parcours #2 */
+
+ result = SRS_REDUCED;
+
+ for (i = 0; i < expr->count; i++)
+ {
+ item = expr->items[i];
+
+ state = g_scan_expression_reduce(item, ctx, scope, &new);
+ if (state == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ g_clear_object(out);
+ break;
+ }
+
+ if (state == SRS_WAIT_FOR_SCAN)
+ result = SRS_WAIT_FOR_SCAN;
+
+ if (new != item)
+ {
+ if (*out == NULL)
+ {
+ *out = g_scan_generic_set_new();
+
+ for (k = 0; k < i; k++)
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), expr->items[k]);
+
+ }
+
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), new);
+
+ }
+
+ else
+ {
+ if (*out != NULL)
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), item);
+ }
+
+ g_object_unref(G_OBJECT(new));
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme booléenne. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_generic_set_reduce_to_boolean(const GScanGenericSet *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->count > 0 });
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* count = quantité d'éléments déterminée. [OUT] *
+* *
+* Description : Dénombre les éléments portés par une expression. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_generic_set_count_items(const GScanGenericSet *expr, GScanContext *ctx, size_t *count)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ *count = expr->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* index = indice de l'élément à transférer. *
+* ctx = contexte de suivi de l'analyse courante. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Fournit un élément donné issu d'un ensemble constitué. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_generic_set_get_item(const GScanGenericSet *expr, size_t index, GScanContext *ctx, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (index < expr->count);
+
+ if (result)
+ *out = expr->items[index];
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/set.h b/src/analysis/scan/exprs/set.h
new file mode 100644
index 0000000..c9fb3b3
--- /dev/null
+++ b/src/analysis/scan/exprs/set.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * set.h - prototypes pour la base d'ensembles de valeurs diverses, de types hétérogènes ou homogènes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_SET_H
+#define _ANALYSIS_SCAN_EXPRS_SET_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_SCAN_GENERIC_SET g_scan_generic_set_get_type()
+#define G_SCAN_GENERIC_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_GENERIC_SET, GScanGenericSet))
+#define G_IS_SCAN_GENERIC_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_GENERIC_SET))
+#define G_SCAN_GENERIC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_GENERIC_SET, GScanGenericSetClass))
+#define G_IS_SCAN_GENERIC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_GENERIC_SET))
+#define G_SCAN_GENERIC_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_GENERIC_SET, GScanGenericSetClass))
+
+
+/* Base d'un ensemble d'éléments homogènes ou hétérogènes (instance) */
+typedef struct _GScanGenericSet GScanGenericSet;
+
+/* Base d'un ensemble d'éléments homogènes ou hétérogènes (classe) */
+typedef struct _GScanGenericSetClass GScanGenericSetClass;
+
+
+/* Indique le type défini pour une base d'ensembles d'éléments homogènes ou hétérogènes. */
+GType g_scan_generic_set_get_type(void);
+
+/* Constitue un ensemble d'éléments homogènes ou hétérogènes. */
+GScanExpression *g_scan_generic_set_new(void);
+
+/* Ajoute un nouvel élément à un ensemble. */
+void g_scan_generic_set_add_item(GScanGenericSet *, GScanExpression *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_SET_H */
diff --git a/src/analysis/scan/exprs/setcounter-int.h b/src/analysis/scan/exprs/setcounter-int.h
new file mode 100644
index 0000000..c9e3da5
--- /dev/null
+++ b/src/analysis/scan/exprs/setcounter-int.h
@@ -0,0 +1,69 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * setcounter-int.h - prototypes internes pour le décompte global de correspondances locales
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_SETCOUNTER_INT_H
+#define _ANALYSIS_SCAN_EXPRS_SETCOUNTER_INT_H
+
+
+#include "setcounter.h"
+
+
+#include "../expr-int.h"
+
+
+
+/* Décompte global de correspondances locales (instance) */
+struct _GScanSetMatchCounter
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ union
+ {
+ const GSearchPattern **patterns; /* Motifs associés */
+ GSearchPattern **ref_patterns; /* Motifs associés */
+ };
+ size_t count; /* Nombre de ces motifs */
+ bool shared; /* Définition de propriété */
+
+ ScanSetCounterType type; /* Type de décompte */
+ size_t number; /* Eventuel volume associé */
+
+};
+
+/* Décompte global de correspondances locales (classe) */
+struct _GScanSetMatchCounterClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un décompte de motifs avec correspondances. */
+bool g_scan_set_match_counter_create_shared(GScanSetMatchCounter *, const GSearchPattern ** const, size_t);
+
+/* Met en place un décompte de motifs avec correspondances. */
+bool g_scan_set_match_counter_create_and_ref(GScanSetMatchCounter *, GSearchPattern ** const, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_SETCOUNTER_INT_H */
diff --git a/src/analysis/scan/exprs/setcounter.c b/src/analysis/scan/exprs/setcounter.c
new file mode 100644
index 0000000..bed315e
--- /dev/null
+++ b/src/analysis/scan/exprs/setcounter.c
@@ -0,0 +1,477 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * setcounter.c - décompte global de correspondances locales
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "setcounter.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include "setcounter-int.h"
+#include "literal.h"
+
+
+
+/* --------------------- INSTANCIATION D'UNE FORME DE CONDITION --------------------- */
+
+
+/* Initialise la classe des opérations booléennes. */
+static void g_scan_set_match_counter_class_init(GScanSetMatchCounterClass *);
+
+/* Initialise une instance d'opération booléenne. */
+static void g_scan_set_match_counter_init(GScanSetMatchCounter *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_set_match_counter_dispose(GScanSetMatchCounter *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_set_match_counter_finalize(GScanSetMatchCounter *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_set_match_counter_reduce(const GScanSetMatchCounter *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INSTANCIATION D'UNE FORME DE CONDITION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un décompte de résultats lors d'une recherche de motifs. */
+G_DEFINE_TYPE(GScanSetMatchCounter, g_scan_set_match_counter, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des opérations booléennes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_match_counter_class_init(GScanSetMatchCounterClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_set_match_counter_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_set_match_counter_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)NULL;
+ expr->reduce = (reduce_expr_fc)g_scan_set_match_counter_reduce;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser. *
+* *
+* Description : Initialise une instance d'opération booléenne. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_match_counter_init(GScanSetMatchCounter *counter)
+{
+ counter->patterns = NULL;
+ counter->count = 0;
+ counter->shared = true;
+
+ counter->type = SSCT_NONE;
+ counter->number = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_match_counter_dispose(GScanSetMatchCounter *counter)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (!counter->shared)
+ for (i = 0; i < counter->count; i++)
+ g_clear_object(&counter->ref_patterns[i]);
+
+ G_OBJECT_CLASS(g_scan_set_match_counter_parent_class)->dispose(G_OBJECT(counter));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_set_match_counter_finalize(GScanSetMatchCounter *counter)
+{
+ if (counter->patterns != NULL)
+ free(counter->patterns);
+
+ G_OBJECT_CLASS(g_scan_set_match_counter_parent_class)->finalize(G_OBJECT(counter));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* *
+* Description : Constitue un décompte de motifs avec correspondances. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_set_match_counter_new_shared(const GSearchPattern ** const patterns, size_t count)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SET_MATCH_COUNTER, NULL);
+
+ if (!g_scan_set_match_counter_create_shared(G_SCAN_SET_MATCH_COUNTER(result), patterns, count))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : counter = instance à initialiser pleinement. *
+* patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* *
+* Description : Met en place un décompte de motifs avec correspondances. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_set_match_counter_create_shared(GScanSetMatchCounter *counter, const GSearchPattern ** const patterns, size_t count)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(counter), SRS_WAIT_FOR_SCAN);
+ if (!result) goto exit;
+
+ counter->patterns = malloc(count * sizeof(GSearchPattern *));
+ counter->count = count;
+
+ memcpy(counter->patterns, patterns, count * sizeof(GSearchPattern *));
+
+ counter->shared = true;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* *
+* Description : Constitue un décompte de motifs avec correspondances. *
+* *
+* Retour : Expression mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_set_match_counter_new(GSearchPattern ** const patterns, size_t count)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SET_MATCH_COUNTER, NULL);
+
+ if (!g_scan_set_match_counter_create_and_ref(G_SCAN_SET_MATCH_COUNTER(result), patterns, count))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : counter = instance à initialiser pleinement. *
+* patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* *
+* Description : Met en place un décompte de motifs avec correspondances. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_set_match_counter_create_and_ref(GScanSetMatchCounter *counter, GSearchPattern ** const patterns, size_t count)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(counter), SRS_WAIT_FOR_SCAN);
+ if (!result) goto exit;
+
+ counter->patterns = malloc(count * sizeof(GSearchPattern *));
+ counter->count = count;
+
+ memcpy(counter->patterns, patterns, count * sizeof(GSearchPattern *));
+
+ for (i = 0; i < count; i++)
+ g_object_ref(G_OBJECT(patterns[i]));
+
+ counter->shared = false;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : counter = décompte à compléter. *
+* patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* *
+* Description : Ajoute de nouveaux motifs à un ensemble à décompter. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_set_match_counter_add_extra_shared_patterns(GScanSetMatchCounter *counter, const GSearchPattern ** const patterns, size_t count)
+{
+ size_t first; /* Premier emplacement libre */
+
+ assert(counter->shared);
+
+ first = counter->count;
+
+ counter->count += count;
+ counter->patterns = realloc(counter->patterns, counter->count * sizeof(GSearchPattern *));
+
+ memcpy(counter->patterns + first, patterns, count * sizeof(GSearchPattern *));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : counter = décompte à compléter. *
+* patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* *
+* Description : Ajoute de nouveaux motifs à un ensemble à décompter. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_set_match_counter_add_and_ref_extra_patterns(GScanSetMatchCounter *counter, GSearchPattern ** const patterns, size_t count)
+{
+ size_t first; /* Premier emplacement libre */
+ size_t i; /* Boucle de parcours */
+
+ assert(!counter->shared);
+
+ first = counter->count;
+
+ counter->count += count;
+ counter->patterns = realloc(counter->patterns, counter->count * sizeof(GSearchPattern *));
+
+ memcpy(counter->patterns + first, patterns, count * sizeof(GSearchPattern *));
+
+ for (i = 0; i < count; i++)
+ g_object_ref(G_OBJECT(patterns[i]));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : counter = décompte à configurer. *
+* type = type de décompte à considérer. *
+* number = volume minimal de motifs avec correspondances. *
+* *
+* Description : Précise le volume de motifs avec correspondances à retrouver.*
+* *
+* Retour : Bilan de validité des arguments fournis. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_set_match_counter_define_expected_matches(GScanSetMatchCounter *counter, ScanSetCounterType type, size_t *number)
+{
+ bool result; /* Bilan à retourner */
+
+ counter->type = type;
+
+ if (type == SSCT_NUMBER)
+ {
+ counter->number = *number;
+ result = (counter->number <= counter->count);
+ }
+ else
+ result = true;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_set_match_counter_reduce(const GScanSetMatchCounter *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ size_t matched; /* Qté de motifs avec résultats*/
+ size_t i; /* Boucle de parcours */
+ GScanMatches *matches; /* Série de correspondances */
+ size_t count; /* Quantité de correspondances */
+ bool status; /* Bilan d'évaluation finale */
+
+ if (g_scan_context_is_scan_done(ctx))
+ {
+ matched = 0;
+
+ for (i = 0; i < expr->count; i++)
+ {
+ matches = g_scan_context_get_full_matches(ctx, expr->patterns[i]);
+
+ if (matches != NULL)
+ {
+ count = g_scan_matches_count(matches);
+
+ if (count > 0)
+ matched++;
+
+ g_object_unref(G_OBJECT(matches));
+
+ }
+
+ }
+
+ switch (expr->type)
+ {
+ case SSCT_NONE:
+ status = (matched == 0);
+ break;
+
+ case SSCT_ANY:
+ status = (matched >= 1);
+ break;
+
+ case SSCT_ALL:
+ status = (matched == expr->count);
+ break;
+
+ case SSCT_NUMBER:
+ status = (matched >= expr->number);
+ break;
+
+ }
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status);
+
+ result = SRS_REDUCED;
+
+ }
+ else
+ result = SRS_WAIT_FOR_SCAN;
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/setcounter.h b/src/analysis/scan/exprs/setcounter.h
new file mode 100644
index 0000000..28c92b4
--- /dev/null
+++ b/src/analysis/scan/exprs/setcounter.h
@@ -0,0 +1,81 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * setcounter.h - prototypes pour le décompte global de correspondances locales
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_SETCOUNTER_H
+#define _ANALYSIS_SCAN_EXPRS_SETCOUNTER_H
+
+
+#include <glib-object.h>
+
+
+#include "../expr.h"
+#include "../pattern.h"
+
+
+
+#define G_TYPE_SCAN_SET_MATCH_COUNTER g_scan_set_match_counter_get_type()
+#define G_SCAN_SET_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SET_MATCH_COUNTER, GScanSetMatchCounter))
+#define G_IS_SCAN_SET_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SET_MATCH_COUNTER))
+#define G_SCAN_SET_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SET_MATCH_COUNTER, GScanSetMatchCounterClass))
+#define G_IS_SCAN_SET_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SET_MATCH_COUNTER))
+#define G_SCAN_SET_MATCH_COUNTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SET_MATCH_COUNTER, GScanSetMatchCounterClass))
+
+
+/* Décompte global de correspondances locales (instance) */
+typedef struct _GScanSetMatchCounter GScanSetMatchCounter;
+
+/* Décompte global de correspondances locales (classe) */
+typedef struct _GScanSetMatchCounterClass GScanSetMatchCounterClass;
+
+
+/* Indique le type défini pour un décompte de résultats lors d'une recherche de motifs. */
+GType g_scan_set_match_counter_get_type(void);
+
+/* Met en place un décompte de correspondances obtenues. */
+GScanExpression *g_scan_set_match_counter_new_shared(const GSearchPattern ** const, size_t);
+
+/* Met en place un décompte de correspondances obtenues. */
+GScanExpression *g_scan_set_match_counter_new(GSearchPattern ** const, size_t);
+
+/* Ajoute de nouveaux motifs à un ensemble à décompter. */
+void g_scan_set_match_counter_add_extra_shared_patterns(GScanSetMatchCounter *, const GSearchPattern ** const, size_t);
+
+/* Ajoute de nouveaux motifs à un ensemble à décompter. */
+void g_scan_set_match_counter_add_and_ref_extra_patterns(GScanSetMatchCounter *, GSearchPattern ** const, size_t);
+
+/* Formes de volume de correspondances */
+typedef enum _ScanSetCounterType
+{
+ SSCT_NONE, /* Aucun motif avec résultats */
+ SSCT_ANY, /* Au moins un motif trouvé */
+ SSCT_ALL, /* Tous les motifs présents */
+ SSCT_NUMBER, /* Au moins n motifs avec rés. */
+
+} ScanSetCounterType;
+
+/* Précise le volume de motifs avec correspondances à retrouver. */
+bool g_scan_set_match_counter_define_expected_matches(GScanSetMatchCounter *, ScanSetCounterType, size_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_SETCOUNTER_H */
diff --git a/src/analysis/scan/exprs/strop-int.h b/src/analysis/scan/exprs/strop-int.h
new file mode 100644
index 0000000..c2b40cf
--- /dev/null
+++ b/src/analysis/scan/exprs/strop-int.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * strop-int.h - prototypes internes pour la gestion des opérations booléennes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_STROP_INT_H
+#define _ANALYSIS_SCAN_EXPRS_STROP_INT_H
+
+
+#include "strop.h"
+
+
+#include "../expr-int.h"
+#include "../../../common/extstr.h"
+
+
+
+/* Opération booléenne avec un ou deux opérandes (instance) */
+struct _GScanStringOperation
+{
+ GScanExpression parent; /* A laisser en premier */
+
+ StringOperationType type; /* Type d'opération menée */
+ bool case_sensitive; /* Respect de la casse ? */
+
+ GScanExpression *left; /* Expression impactée #1 */
+ GScanExpression *right; /* Expression impactée #2 */
+
+};
+
+/* Opération booléenne avec un ou deux opérandes (classe) */
+struct _GScanStringOperationClass
+{
+ GScanExpressionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une expression d'opération traite une chaîne. */
+bool g_scan_string_operation_create(GScanStringOperation *, StringOperationType, GScanExpression *, GScanExpression *, bool);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_STROP_INT_H */
diff --git a/src/analysis/scan/exprs/strop.c b/src/analysis/scan/exprs/strop.c
new file mode 100644
index 0000000..c188c36
--- /dev/null
+++ b/src/analysis/scan/exprs/strop.c
@@ -0,0 +1,455 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * strop.c - gestion des opérations booléennes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "strop.h"
+
+
+#include <assert.h>
+#include <string.h>
+#include <strings.h>
+
+
+#include "strop-int.h"
+#include "literal.h"
+
+
+
+/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
+
+
+/* Initialise la classe des opérations visant des chaînes. */
+static void g_scan_string_operation_class_init(GScanStringOperationClass *);
+
+/* Initialise une instance d'opération visant une chaîne. */
+static void g_scan_string_operation_init(GScanStringOperation *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_operation_dispose(GScanStringOperation *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_operation_finalize(GScanStringOperation *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Réduit une expression à une forme plus simple. */
+static ScanReductionState g_scan_string_operation_reduce(const GScanStringOperation *, GScanContext *, GScanScope *, GScanExpression **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une opération traitant une chaîne de caractères. */
+G_DEFINE_TYPE(GScanStringOperation, g_scan_string_operation, G_TYPE_SCAN_EXPRESSION);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des opérations visant des chaînes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_operation_class_init(GScanStringOperationClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanExpressionClass *expr; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_operation_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_operation_finalize;
+
+ expr = G_SCAN_EXPRESSION_CLASS(klass);
+
+ expr->cmp_rich = (compare_expr_rich_fc)NULL;
+ expr->reduce = (reduce_expr_fc)g_scan_string_operation_reduce;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser. *
+* *
+* Description : Initialise une instance d'opération visant une chaîne. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_operation_init(GScanStringOperation *op)
+{
+ op->left = NULL;
+ op->right = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_operation_dispose(GScanStringOperation *op)
+{
+ g_clear_object(&op->left);
+ g_clear_object(&op->right);
+
+ G_OBJECT_CLASS(g_scan_string_operation_parent_class)->dispose(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_operation_finalize(GScanStringOperation *op)
+{
+ G_OBJECT_CLASS(g_scan_string_operation_parent_class)->finalize(G_OBJECT(op));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type d'opération booléenne à représenter. *
+* first = premier opérande concerné. *
+* second = éventuel second opérande impliqué ou NULL. *
+* sensitive = détermine la prise en compte de la casse. *
+* *
+* Description : Organise un appel de fonction avec ses arguments. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanExpression *g_scan_string_operation_new(StringOperationType type, GScanExpression *first, GScanExpression *second, bool sensitive)
+{
+ GScanExpression *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_OPERATION, NULL);
+
+ if (!g_scan_string_operation_create(G_SCAN_STRING_OPERATION(result), type, first, second, sensitive))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : op = instance à initialiser pleinement. *
+* type = type d'opération booléenne à représenter. *
+* left = premier opérande concerné. *
+* right = éventuel second opérande impliqué ou NULL. *
+* sensitive = détermine la prise en compte de la casse. *
+* *
+* Description : Met en place une expression d'opération traite une chaîne. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_string_operation_create(GScanStringOperation *op, StringOperationType type, GScanExpression *left, GScanExpression *right, bool sensitive)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING);
+ if (!result) goto exit;
+
+ op->type = type;
+
+ switch (type)
+ {
+ case SOT_CONTAINS:
+ case SOT_STARTSWITH:
+ case SOT_ENDSWITH:
+ op->case_sensitive = sensitive;
+ break;
+
+ case SOT_MATCHES:
+ break;
+
+ case SOT_IEQUALS:
+ assert(!sensitive);
+ op->case_sensitive = false;
+ break;
+
+ }
+
+ op->left = left;
+ g_object_ref(G_OBJECT(op->left));
+
+ op->right = right;
+ g_object_ref(G_OBJECT(op->right));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ScanReductionState g_scan_string_operation_reduce(const GScanStringOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ ScanReductionState result; /* Etat synthétisé à retourner */
+ GScanExpression *new_left; /* Expression réduite (gauche) */
+ GScanExpression *new_right; /* Expression réduite (droite) */
+ ScanReductionState state_left; /* Etat synthétisé #1 */
+ ScanReductionState state_right; /* Etat synthétisé #2 */
+ GScanLiteralExpression *op_left; /* Opérande gauche final */
+ GScanLiteralExpression *op_right; /* Opérande droite final */
+ const sized_string_t *strings[2]; /* Chaînes en jeu */
+ const void *found; /* Présence d'une bribe ? */
+ bool status; /* Bilan de comparaison #1 */
+ int ret; /* Bilan de comparaison #2 */
+ size_t offset; /* Point de départ d'analyse */
+ const regex_t *preg; /* Expression rationnelle */
+
+ /* Réduction des éléments considérés */
+
+ new_left = NULL;
+ new_right = NULL;
+
+ state_left = g_scan_expression_reduce(expr->left, ctx, scope, &new_left);
+ if (state_left == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ state_right = g_scan_expression_reduce(expr->right, ctx, scope, &new_right);
+ if (state_right == SRS_UNRESOLVABLE)
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ /* Construction d'une réduction locale ? */
+
+ if (G_IS_SCAN_LITERAL_EXPRESSION(new_left) && G_IS_SCAN_LITERAL_EXPRESSION(new_right))
+ {
+ op_left = G_SCAN_LITERAL_EXPRESSION(new_left);
+ op_right = G_SCAN_LITERAL_EXPRESSION(new_right);
+
+ if (!g_scan_literal_expression_get_string_value(op_left, &strings[0]))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ result = SRS_REDUCED;
+
+ switch (expr->type)
+ {
+ case SOT_CONTAINS:
+
+ if (!g_scan_literal_expression_get_string_value(op_right, &strings[1]))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (expr->case_sensitive)
+ found = memmem(strings[0]->data, strings[0]->len, strings[1]->data, strings[1]->len);
+
+ else
+ found = memcasemem(strings[0]->data, strings[0]->len, strings[1]->data, strings[1]->len);
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { found != NULL });
+ break;
+
+ case SOT_STARTSWITH:
+
+ if (!g_scan_literal_expression_get_string_value(op_right, &strings[1]))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (strings[0]->len < strings[1]->len)
+ status = false;
+
+ else
+ {
+ if (expr->case_sensitive)
+ ret = memcmp(strings[0]->data, strings[1]->data, strings[1]->len);
+ else
+ ret = memcasecmp(strings[0]->data, strings[1]->data, strings[1]->len);
+
+ status = (ret == 0);
+
+ }
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status);
+ break;
+
+ case SOT_ENDSWITH:
+
+ if (!g_scan_literal_expression_get_string_value(op_right, &strings[1]))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (strings[0]->len < strings[1]->len)
+ status = false;
+
+ else
+ {
+ offset = strings[0]->len - strings[1]->len;
+
+ if (expr->case_sensitive)
+ ret = memcmp(strings[0]->data + offset, strings[1]->data, strings[1]->len);
+ else
+ ret = memcasecmp(strings[0]->data + offset, strings[1]->data, strings[1]->len);
+
+ status = (ret == 0);
+
+ }
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status);
+ break;
+
+ case SOT_MATCHES:
+
+ if (!g_scan_literal_expression_get_regex_value(op_right, &preg))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ ret = regexec(preg, strings[0]->data, 0, NULL, 0);
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { ret != REG_NOMATCH });
+ break;
+
+ case SOT_IEQUALS:
+
+ if (!g_scan_literal_expression_get_string_value(op_right, &strings[1]))
+ {
+ result = SRS_UNRESOLVABLE;
+ goto exit;
+ }
+
+ if (strings[0]->len != strings[1]->len)
+ status = false;
+
+ else
+ {
+ ret = memcasecmp(strings[0]->data, strings[1]->data, strings[1]->len);
+ status = (ret == 0);
+ }
+
+ *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status);
+ break;
+
+ }
+
+ }
+
+ /* Mise à jour de la progression ? */
+
+ else if (state_left == SRS_WAIT_FOR_SCAN || state_right == SRS_WAIT_FOR_SCAN)
+ {
+ if (new_left != expr->left || new_right != expr->right)
+ *out = g_scan_string_operation_new(expr->type, new_left, new_right, expr->case_sensitive);
+
+ result = SRS_WAIT_FOR_SCAN;
+
+ }
+
+ /* Cas des situations où les expressions ne sont pas exploitables (!) */
+ else
+ {
+ assert(state_left == SRS_REDUCED && state_right == SRS_REDUCED);
+
+ result = SRS_UNRESOLVABLE;
+
+ }
+
+ /* Sortie propre */
+
+ exit:
+
+ g_clear_object(&new_left);
+ g_clear_object(&new_right);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/exprs/strop.h b/src/analysis/scan/exprs/strop.h
new file mode 100644
index 0000000..0a32269
--- /dev/null
+++ b/src/analysis/scan/exprs/strop.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * strop.h - prototypes pour la gestion des opérations booléennes
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_EXPRS_STROP_H
+#define _ANALYSIS_SCAN_EXPRS_STROP_H
+
+
+#include "../expr.h"
+
+
+
+#define G_TYPE_SCAN_STRING_OPERATION g_scan_string_operation_get_type()
+#define G_SCAN_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_OPERATION, GScanStringOperation))
+#define G_IS_SCAN_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_OPERATION))
+#define G_SCAN_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_OPERATION, GScanStringOperationClass))
+#define G_IS_SCAN_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_OPERATION))
+#define G_SCAN_STRING_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_OPERATION, GScanStringOperationClass))
+
+
+/* Opération booléenne avec un ou deux opérandes (instance) */
+typedef struct _GScanStringOperation GScanStringOperation;
+
+/* Opération booléenne avec un ou deux opérandes (classe) */
+typedef struct _GScanStringOperationClass GScanStringOperationClass;
+
+
+/* Types d'opérations booléennes supportées */
+typedef enum _StringOperationType
+{
+ SOT_CONTAINS, /* Opérateurs "[i]contains" */
+ SOT_STARTSWITH, /* Opérateurs "[i]startswith" */
+ SOT_ENDSWITH, /* Opérateurs "[i]endswith" */
+ SOT_MATCHES, /* Opérateur "matches" */
+ SOT_IEQUALS, /* Opérateur "iequals" */
+
+} StringOperationType;
+
+
+/* Indique le type défini pour une opération traitant une chaîne de caractères. */
+GType g_scan_string_operation_get_type(void);
+
+/* Organise un appel de fonction avec ses arguments. */
+GScanExpression *g_scan_string_operation_new(StringOperationType, GScanExpression *, GScanExpression *, bool);
+
+
+
+#endif /* _ANALYSIS_SCAN_EXPRS_STROP_H */
diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y
new file mode 100644
index 0000000..2d985a7
--- /dev/null
+++ b/src/analysis/scan/grammar.y
@@ -0,0 +1,1905 @@
+
+%{
+
+#include "decl.h"
+#include "tokens.h"
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int yyerror(GContentScanner *, yyscan_t, GScanRule **, sized_string_t *, sized_string_t *, char *);
+
+#define raise_error(msg) \
+ yyerror(scanner, yyscanner, built_rule, tmp_0, tmp_1, msg)
+
+%}
+
+
+%code requires {
+
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void *yyscan_t;
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdio.h>
+
+#include <i18n.h>
+
+#include "core.h"
+#include "scanner.h"
+#include "exprs/access.h"
+#include "exprs/arithmetic.h"
+#include "exprs/call.h"
+#include "exprs/extract.h"
+#include "exprs/handler.h"
+#include "exprs/intersect.h"
+#include "exprs/item.h"
+#include "exprs/literal.h"
+#include "exprs/logical.h"
+#include "exprs/set.h"
+#include "exprs/setcounter.h"
+#include "exprs/relational.h"
+#include "exprs/strop.h"
+#include "patterns/customizer.h"
+#include "patterns/modifier.h"
+#include "patterns/modifiers/list.h"
+#include "patterns/modifiers/pipe.h"
+#include "patterns/tokens/hex.h"
+#include "patterns/tokens/plain.h"
+#include "patterns/tokens/nodes/any.h"
+#include "patterns/tokens/nodes/choice.h"
+#include "patterns/tokens/nodes/masked.h"
+#include "patterns/tokens/nodes/not.h"
+#include "patterns/tokens/nodes/plain.h"
+#include "patterns/tokens/nodes/sequence.h"
+#include "../../core/logs.h"
+
+}
+
+%union {
+
+ unsigned long long unsigned_integer; /* Valeur entière #1 */
+ signed long long signed_integer; /* Valeur entière #2 */
+ //double floating_number; /* Valeur à virgule flottante */
+ sized_string_t sized_cstring; /* Chaîne de caractères */
+ //char byte; /* Octet unique */
+
+
+
+
+ sized_string_t *tmp_cstring; /* Série d'octets reconstituée */
+
+ struct
+ {
+ sized_string_t *tmp_values; /* Série d'octets partiels */
+ sized_string_t *tmp_masks; /* Masques associés */
+ } masked;
+
+ ScanRuleFlags rule_flags; /* Fanions pour règle */
+
+ GScanTokenNode *node; /* Bribe de motif à intégrer */
+ GSearchPattern *pattern; /* Nouveau motif à considérer */
+
+ GScanTokenModifier *modifier; /* Modificateur pour texte */
+ modifier_arg_t mod_arg; /* Argument pour modificateur */
+ ScanPlainNodeFlags str_flags; /* Fanions pour texte */
+
+ GScanExpression *expr; /* Expression de condition */
+
+ struct {
+ GScanExpression **args; /* Liste d'arguments à fournir */
+ size_t count; /* Quantité de ces arguments */
+ } args_list;
+
+}
+
+
+/**
+ * Cf.
+ * http://stackoverflow.com/questions/34418381/how-to-reference-lex-or-parse-parameters-in-flex-rules/34420950
+ */
+
+%define api.pure full
+
+%parse-param { GContentScanner *scanner } { yyscan_t yyscanner } { GScanRule **built_rule } { sized_string_t *tmp_0} { sized_string_t *tmp_1}
+%lex-param { yyscan_t yyscanner } { sized_string_t *tmp_0} { sized_string_t *tmp_1}
+
+%code provides {
+
+#define YY_DECL \
+ int rost_lex(YYSTYPE *yylval_param, yyscan_t yyscanner, sized_string_t *tmp_0, sized_string_t *tmp_1)
+
+YY_DECL;
+
+}
+
+
+%token INCLUDE "include"
+
+%token RAW_RULE "rule"
+%token RULE_IDENTIFIER
+
+%token META "meta"
+%token BYTES "bytes"
+%token CONDITION "condition"
+
+%token INFO_KEY
+
+
+
+%token BYTES_ID
+%token BYTES_FUZZY_ID
+%token BYTES_ID_COUNTER
+%token BYTES_FUZZY_ID_COUNTER
+%token BYTES_ID_START
+%token BYTES_FUZZY_ID_START
+%token BYTES_ID_LENGTH
+%token BYTES_FUZZY_ID_LENGTH
+%token BYTES_ID_END
+%token BYTES_FUZZY_ID_END
+%token NAME
+
+
+%token NOCASE "nocase"
+%token FULLWORD "fullword"
+%token PRIVATE "private"
+%token GLOBAL "global"
+
+
+%token HEX_BYTES
+%token FULL_MASK
+%token SEMI_MASK
+
+
+%token REGEX_BYTES
+%token REGEX_CLASSES
+%token REGEX_RANGE
+
+
+
+%token BRACE_IN "{"
+%token BRACE_OUT "}"
+%token ASSIGN "="
+%token COLON ":"
+
+
+%token PLAIN_TEXT
+%token ESCAPED_TEXT
+
+%token TRUE_ "true"
+%token FALSE_ "false"
+%token SIGNED_INTEGER
+%token UNSIGNED_INTEGER
+
+%token KB MB GB
+
+%token AND "and"
+%token OR "or"
+%token NOT "not"
+
+%token LT "<"
+%token LE "<="
+%token EQ "=="
+%token NE "!="
+%token GT ">"
+%token GE ">="
+
+%token CONTAINS "contains"
+%token STARTSWITH "startswith"
+%token ENDSWITH "endswith"
+%token MATCHES "matches"
+%token ICONTAINS "icontains"
+%token ISTARTSWITH "istartswith"
+%token IENDSWITH "iendswith"
+%token IEQUALS "iequals"
+
+%token PLUS "+"
+%token MINUS "-"
+%token MUL "*"
+%token DIV "/"
+%token MOD "%"
+%token TILDE "~"
+
+%token HOOK_O "["
+%token HOOK_C "]"
+
+%token QUESTION "?"
+
+%token PAREN_O "("
+%token PAREN_C ")"
+%token COMMA ","
+%token DOT "."
+%token PIPE "|"
+
+%token MOD_GROUP_O "(("
+%token MOD_GROUP_C "))"
+
+%token NONE "none"
+%token ANY "any"
+%token ALL "all"
+%token OF "of"
+%token THEM "them"
+%token IN "in"
+
+
+%type <sized_cstring> RULE_IDENTIFIER
+
+%type <sized_cstring> INFO_KEY
+
+%type <sized_cstring> BYTES_ID
+%type <sized_cstring> BYTES_FUZZY_ID
+%type <sized_cstring> BYTES_ID_COUNTER
+%type <sized_cstring> BYTES_FUZZY_ID_COUNTER
+%type <sized_cstring> BYTES_ID_START
+%type <sized_cstring> BYTES_FUZZY_ID_START
+%type <sized_cstring> BYTES_ID_LENGTH
+%type <sized_cstring> BYTES_FUZZY_ID_LENGTH
+%type <sized_cstring> BYTES_ID_END
+%type <sized_cstring> BYTES_FUZZY_ID_END
+%type <sized_cstring> NAME
+
+
+%type <signed_integer> SIGNED_INTEGER
+%type <unsigned_integer> UNSIGNED_INTEGER
+
+%type <rule_flags> rule_flags
+%type <rule_flags> rule_flag
+
+%type <sized_cstring> PLAIN_TEXT
+%type <tmp_cstring> ESCAPED_TEXT
+
+%type <tmp_cstring> HEX_BYTES
+%type <unsigned_integer> FULL_MASK
+%type <masked> SEMI_MASK
+
+%type <tmp_cstring> REGEX_BYTES
+
+
+
+%type <pattern> str_pattern
+
+%type <modifier> modifiers
+%type <modifier> _modifiers
+ //%type <modifier> chained_modifiers
+%type <modifier> mod_stage
+%type <modifier> modifier
+%type <modifier> modifier_args
+%type <mod_arg> modifier_arg
+
+%type <str_flags> str_flags
+
+
+%type <pattern> hex_pattern
+%type <node> hex_tokens
+%type <node> _hex_tokens
+%type <node> hex_token
+%type <node> hex_range
+%type <node> hex_choices
+
+
+
+%type <expr> cexpression _cexpression
+
+%type <expr> literal
+%type <expr> chain_items
+%type <expr> chain_item
+%type <args_list> call_args
+%type <expr> logical_expr
+%type <expr> relational_expr
+%type <expr> string_op
+%type <expr> arithm_expr
+%type <expr> set_match_counter
+%type <expr> pattern_set
+%type <expr> pattern_set_items
+%type <expr> set
+%type <expr> set_items
+%type <expr> intersection
+%type <expr> pattern_handler
+%type <expr> _pattern_handler
+
+
+
+
+
+%left PIPE
+
+
+
+%left OR
+%left AND
+%left EQ NE
+%left CONTAINS STARTSWITH ENDSWITH MATCHES ICONTAINS ISTARTSWITH IENDSWITH IEQUALS
+%left LT LE GT GE
+%left PLUS MINUS
+%left MUL DIV MOD
+%left IN
+%right NOT
+
+
+
+%left HOOK_O HOOK_C
+
+
+ %destructor { g_object_unref(G_OBJECT($$)); } <node>
+
+ %destructor { g_object_unref(G_OBJECT($$)); } <pattern>
+
+ %destructor { g_object_unref(G_OBJECT($$)); } <modifier>
+
+ %destructor { g_object_unref(G_OBJECT($$)); } <expr>
+
+ %destructor {
+ size_t __i;
+
+ for (__i = 0; __i < $$.count; __i++)
+ g_object_unref(G_OBJECT($$.args[__i]));
+
+ if ($$.args != NULL)
+ free($$.args);
+
+ } <args_list>
+
+
+%%
+
+ rules : /* empty */
+ | external rules
+ | rule
+ {
+ g_content_scanner_add_rule(scanner, *built_rule);
+ g_clear_object(built_rule);
+ }
+ rules
+ ;
+
+
+/**
+ * Inclusion d'une règle externe.
+ */
+
+ external : "include" PLAIN_TEXT
+ {
+ bool __status;
+ __status = g_content_scanner_include_resource(scanner, $2.data);
+ if (!__status)
+ YYERROR;
+ }
+ | "include" ESCAPED_TEXT
+ {
+ bool __status;
+ __status = g_content_scanner_include_resource(scanner, $2->data);
+ if (!__status)
+ YYERROR;
+ }
+ ;
+
+
+/**
+ * Définition de règle.
+ */
+
+ rule : rule_flags "rule" RULE_IDENTIFIER
+ {
+ *built_rule = g_scan_rule_new($1, $3.data);
+ }
+ tags "{" meta bytes condition "}"
+ ;
+
+
+ rule_flags : /* empty */
+ {
+ $$ = SRF_NONE;
+ }
+ | rule_flags rule_flag
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+ rule_flag : "private"
+ {
+ $$ = SRF_PRIVATE;
+ }
+ | "global"
+ {
+ $$ = SRF_GLOBAL;
+ }
+ ;
+
+
+ tags : /* empty */
+ | ":" tag_list
+ ;
+
+ tag_list : RULE_IDENTIFIER
+ {
+ g_scan_rule_add_tag(*built_rule, $1.data);
+ }
+ | tag_list RULE_IDENTIFIER
+ {
+ g_scan_rule_add_tag(*built_rule, $2.data);
+ }
+ ;
+
+
+/**
+ * Section "meta:" d'une définition de règle.
+ */
+
+ meta : /* empty */
+ | "meta" ":"
+ | "meta" ":" meta_list
+ ;
+
+ meta_list : meta_info
+ | meta_list meta_info
+ ;
+
+ meta_info : INFO_KEY "=" "true"
+ | INFO_KEY "=" "false"
+ | INFO_KEY "=" SIGNED_INTEGER
+ | INFO_KEY "=" UNSIGNED_INTEGER
+ | INFO_KEY "=" PLAIN_TEXT
+ | INFO_KEY "=" ESCAPED_TEXT
+ ;
+
+
+/**
+ * Section "bytes:" d'une définition de règle.
+ */
+
+ bytes : /* empty */
+ | "bytes" ":"
+ | "bytes" ":" bytes_decls
+ ;
+
+ bytes_decls : str_pattern
+ {
+ if ($1 == NULL) YYERROR;
+ g_scan_rule_add_local_variable(*built_rule, $1);
+ g_object_unref(G_OBJECT($1));
+ }
+ | hex_pattern
+ {
+ if ($1 == NULL) YYERROR;
+ g_scan_rule_add_local_variable(*built_rule, $1);
+ g_object_unref(G_OBJECT($1));
+ }
+ | regex_pattern
+ {
+ // TODO
+ }
+ | bytes_decls str_pattern
+ {
+ if ($2 == NULL) YYERROR;
+ g_scan_rule_add_local_variable(*built_rule, $2);
+ g_object_unref(G_OBJECT($2));
+ }
+ | bytes_decls hex_pattern
+ {
+ if ($2 == NULL) YYERROR;
+ g_scan_rule_add_local_variable(*built_rule, $2);
+ g_object_unref(G_OBJECT($2));
+ }
+ | bytes_decls regex_pattern
+ {
+ // TODO
+ }
+ ;
+
+
+/**
+ * Définition de motif en texte brut.
+ */
+
+ str_pattern : BYTES_ID "=" PLAIN_TEXT modifiers str_flags
+ {
+ GScanTokenNode *node;
+
+ node = g_scan_token_node_plain_new(&$3, $4, $5);
+
+ $$ = g_scan_plain_bytes_new(node);
+ g_search_pattern_set_name($$, $1.data, $1.len);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+ | BYTES_ID "=" ESCAPED_TEXT modifiers str_flags
+ {
+ GScanTokenNode *node;
+
+ node = g_scan_token_node_plain_new($3, $4, $5);
+
+ $$ = g_scan_plain_bytes_new(node);
+ g_search_pattern_set_name($$, $1.data, $1.len);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+ ;
+
+
+/**
+ * Prise en charge des modificateurs.
+ */
+
+ modifiers : /* empty */
+ {
+ $$ = NULL;
+ }
+ | _modifiers
+ {
+ $$ = $1;
+
+
+ // if (...) useless
+ // ex : xxx | { yyy zzz }
+
+ }
+ ;
+
+ _modifiers : mod_stage
+ {
+ $$ = $1;
+ }
+ | _modifiers "|" mod_stage
+ {
+ bool status;
+
+ if (G_IS_SCAN_MODIFIER_PIPE($1))
+ $$ = $1;
+ else
+ {
+ $$ = g_scan_modifier_pipe_new();
+ g_scan_modifier_pipe_add(G_SCAN_MODIFIER_PIPE($$), $1);
+ g_object_unref(G_OBJECT($1));
+ }
+
+ g_scan_modifier_pipe_add(G_SCAN_MODIFIER_PIPE($$), $3);
+ g_object_unref(G_OBJECT($3));
+
+ }
+ ;
+
+/*
+ chained_modifiers : modifiers "|" modifiers
+ {
+ printf("need chains....\n");
+
+ $$ = NULL;
+
+ }
+ ;
+*/
+
+ mod_stage : modifier
+ {
+ $$ = $1;
+ }
+ | "((" _modifiers "))"
+ {
+ $$ = NULL;
+ YYERROR; /* TODO */
+ }
+ | mod_stage modifier
+ {
+ bool status;
+
+ if (G_IS_SCAN_MODIFIER_LIST($1))
+ $$ = $1;
+ else
+ {
+ $$ = g_scan_modifier_list_new();
+ g_scan_modifier_list_add(G_SCAN_MODIFIER_LIST($$), $1);
+ g_object_unref(G_OBJECT($1));
+ }
+
+ status = g_scan_modifier_list_add(G_SCAN_MODIFIER_LIST($$), $2);
+ if (!status)
+ {
+ if (1)
+ log_simple_message(LMT_WARNING, "modifier already taken into account!");
+ }
+
+ g_object_unref(G_OBJECT($2));
+
+ }
+ ;
+
+ modifier : NAME
+ {
+ $$ = find_scan_token_modifiers_for_name(&$1);
+ if ($$ == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Unknown modifier: \"%.*s\""), (int)$1.len, $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+ }
+ | NAME "(" modifier_args ")"
+ {
+ GScanTokenModifier *_mod;
+ bool _status;
+
+ $$ = $3;
+
+ _mod = find_scan_token_modifiers_for_name(&$1);
+ if (_mod == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Unknown modifier: \"%.*s\""), (int)$1.len, $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ g_object_unref(G_OBJECT($$));
+
+ YYERROR;
+ }
+
+ _status = g_scan_token_customizer_attach_modifier(G_SCAN_TOKEN_CUSTOMIZER($$), _mod);
+
+ g_object_unref(G_OBJECT(_mod));
+
+ if (!_status)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg,
+ _("Unsupported argument for modifier: \"%.*s\""),
+ (int)$1.len, $1.data);
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ g_object_unref(G_OBJECT($$));
+
+ YYERROR;
+ }
+
+ }
+ ;
+
+
+ modifier_args : modifier_arg
+ {
+ $$ = g_scan_token_customizer_new(&$1);
+ }
+ | modifier_args "," modifier_arg
+ {
+ $$ = $1;
+ g_scan_token_customizer_add_extra_arg(G_SCAN_TOKEN_CUSTOMIZER($$), &$3);
+ }
+ ;
+
+ modifier_arg : PLAIN_TEXT
+ {
+ $$.type = MAT_STRING;
+ $$.value.string = $1;
+ }
+ ;
+
+
+/**
+ * Prise en charge des fanions pour texte.
+ */
+
+ str_flags : /* empty */
+ {
+ $$ = SPNF_NONE;
+ }
+ | str_flags "nocase"
+ {
+ $$ = $1 | SPNF_CASE_INSENSITIVE;
+ }
+ | str_flags "fullword"
+ {
+ $$ = $1 | SPNF_FULLWORD;
+ }
+ | str_flags "private"
+ {
+ $$ = $1 | SPNF_PRIVATE;
+ }
+ ;
+
+
+/**
+ * Définition de motif en hexadécimal.
+ */
+
+ hex_pattern : BYTES_ID "=" hex_tokens
+ {
+ $$ = g_scan_hex_bytes_new($3, false);
+ g_search_pattern_set_name($$, $1.data, $1.len);
+ }
+ | BYTES_ID "=" hex_tokens "private"
+ {
+ $$ = g_scan_hex_bytes_new($3, true);
+ g_search_pattern_set_name($$, $1.data, $1.len);
+ }
+ ;
+
+ hex_tokens : _hex_tokens
+ {
+ $$ = $1;
+
+ if (G_IS_SCAN_TOKEN_NODE_SEQUENCE($$))
+ {
+ if (g_scan_token_node_sequence_count(G_SCAN_TOKEN_NODE_SEQUENCE($$)) == 1)
+ {
+ GScanTokenNode *node;
+
+ node = g_scan_token_node_sequence_get(G_SCAN_TOKEN_NODE_SEQUENCE($$), 0);
+
+ g_object_unref(G_OBJECT($$));
+
+ $$ = node;
+
+ }
+
+ }
+
+ }
+ ;
+
+ _hex_tokens : hex_token
+ {
+ if ($1 == NULL) YYERROR;
+
+ $$ = $1;
+
+ }
+ | _hex_tokens hex_token
+ {
+ if ($2 == NULL) YYERROR;
+
+ if (!G_IS_SCAN_TOKEN_NODE_SEQUENCE($1))
+ {
+ $$ = g_scan_token_node_sequence_new($1);
+ g_object_unref(G_OBJECT($1));
+ g_scan_token_node_sequence_add(G_SCAN_TOKEN_NODE_SEQUENCE($$), $2);
+ g_object_unref(G_OBJECT($2));
+ }
+ else
+ {
+ $$ = $1;
+ g_scan_token_node_sequence_add(G_SCAN_TOKEN_NODE_SEQUENCE($$), $2);
+ g_object_unref(G_OBJECT($2));
+ }
+
+ }
+ ;
+
+ hex_token : HEX_BYTES
+ {
+ $$ = g_scan_token_node_plain_new($1, NULL, SPNF_NONE);
+ }
+ | FULL_MASK
+ {
+ phys_t min;
+ phys_t max;
+
+ min = $1;
+ max = $1;
+
+ $$ = g_scan_token_node_any_new(&min, &max);
+
+ }
+ | SEMI_MASK
+ {
+ size_t i;
+ masked_byte_t byte;
+
+ assert($1.tmp_values->len == $1.tmp_masks->len);
+
+ byte.value = $1.tmp_values->data[0];
+ byte.mask = $1.tmp_masks->data[0];
+
+ $$ = g_scan_token_node_masked_new(&byte);
+
+ for (i = 1; i < $1.tmp_values->len; i++)
+ {
+ byte.value = $1.tmp_values->data[i];
+ byte.mask = $1.tmp_masks->data[i];
+
+ g_scan_token_node_masked_add(G_SCAN_TOKEN_NODE_MASKED($$), &byte);
+
+ }
+
+ }
+ | hex_range
+ {
+ if ($1 == NULL)
+ {
+ raise_error(_("Unable to build hexadecimal range"));
+ YYERROR;
+ }
+
+ $$ = $1;
+
+ }
+ | "~" hex_token
+ {
+ if ($2 == NULL) YYERROR;
+ $$ = g_scan_token_node_not_new($2);
+
+ }
+ | "(" hex_choices ")"
+ {
+ $$ = $2;
+ }
+ ;
+
+ hex_range : "[" "-" "]"
+ {
+ $$ = g_scan_token_node_any_new(NULL, NULL);
+ }
+ | "[" UNSIGNED_INTEGER "]"
+ {
+ phys_t min;
+ phys_t max;
+
+ min = $2;
+ max = $2;
+
+ $$ = g_scan_token_node_any_new(&min, &max);
+
+ }
+ | "[" UNSIGNED_INTEGER "-" "]"
+ {
+ phys_t min;
+
+ min = $2;
+
+ $$ = g_scan_token_node_any_new(&min, NULL);
+
+ }
+ | "[" "-" UNSIGNED_INTEGER "]"
+ {
+ phys_t max;
+
+ max = $3;
+
+ $$ = g_scan_token_node_any_new(NULL, &max);
+
+ }
+ | "[" UNSIGNED_INTEGER "-" UNSIGNED_INTEGER "]"
+ {
+ phys_t min;
+ phys_t max;
+
+ min = $2;
+ max = $4;
+
+ $$ = g_scan_token_node_any_new(&min, &max);
+
+ }
+ ;
+
+ hex_choices : hex_token "|" hex_token
+ {
+ if ($1 == NULL) YYERROR;
+ if ($3 == NULL) YYERROR;
+
+ $$ = g_scan_token_node_choice_new();
+ g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $1);
+ g_object_unref(G_OBJECT($1));
+ g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ | hex_choices "|" hex_token
+ {
+ if ($3 == NULL) YYERROR;
+
+ $$ = $1;
+ g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+
+/**
+ * Définition de motif sous forme d'expression régulière
+ */
+
+ regex_pattern : BYTES_ID "=" regex_tokens
+ {
+
+ }
+ ;
+
+ regex_tokens : regex_token
+ {
+
+ }
+ | regex_tokens regex_token
+ {
+
+ }
+ | "(" regex_tokens_list ")"
+ {
+
+ printf("regex -- OR --\n");
+
+ }
+ | regex_tokens "(" regex_tokens_list ")"
+ {
+
+ printf("regex -- OR --\n");
+
+ }
+ ;
+
+
+ regex_tokens_list : regex_tokens
+ | regex_tokens_list "|" regex_tokens
+ ;
+
+
+ regex_token : _regex_token
+ {
+
+ }
+ | _regex_token regex_repeat
+ {
+
+ }
+ ;
+
+ _regex_token : "."
+ {
+ printf("reg dot!\n");
+ }
+ | REGEX_BYTES
+ {
+ printf("reg bytes: '%s' (l=%zu)\n", $1->data, $1->len);
+ }
+ | REGEX_CLASSES
+ {
+ printf("reg class!\n");
+ }
+ | "[" REGEX_RANGE "]"
+ {
+ printf("reg range!\n");
+ }
+ ;
+
+ regex_repeat : "*"
+ {
+ printf(" .. repeat: *\n");
+ }
+ | "+"
+ {
+ printf(" .. repeat: +\n");
+ }
+ | "?"
+ {
+ printf(" .. repeat: ?\n");
+ }
+ | "{" UNSIGNED_INTEGER "}"
+ {
+
+ printf(" .. repeat {%llu}\n", $2);
+
+ }
+ | "{" UNSIGNED_INTEGER "," "}"
+ {
+
+ printf(" .. repeat {%llu,}\n", $2);
+
+ }
+ | "{" "," UNSIGNED_INTEGER "}"
+ {
+
+ printf(" .. repeat {,%llu}\n", $3);
+
+ }
+ | "{" UNSIGNED_INTEGER "," UNSIGNED_INTEGER "}"
+ {
+
+ printf(" .. repeat {%llu,%llu}\n", $2, $4);
+
+ }
+ ;
+
+
+
+/**
+ * Définition des conditions.
+ */
+
+ condition : "condition" ":" cexpression
+ {
+ g_scan_rule_set_match_condition(*built_rule, $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+ cexpression : _cexpression { $$ = $1; if ($$ == NULL) { printf("ERROR !!!\n"); YYERROR; } }
+ ;
+
+ _cexpression : literal { $$ = $1; }
+ | chain_items { $$ = $1; }
+ | logical_expr { $$ = $1; }
+ | relational_expr { $$ = $1; }
+ | string_op { $$ = $1; }
+ | arithm_expr { $$ = $1; }
+ | set_match_counter { $$ = $1; }
+ | set { $$ = $1; }
+ | intersection { $$ = $1; }
+ | pattern_handler { $$ = $1; }
+ | "(" cexpression ")" { $$ = $2; }
+ ;
+
+ literal : "true"
+ {
+ $$ = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ true });
+ }
+ | "false"
+ {
+ $$ = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ false });
+ }
+ | SIGNED_INTEGER
+ {
+ $$ = g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &$1);
+ }
+ | UNSIGNED_INTEGER
+ {
+ $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &$1);
+ }
+ | UNSIGNED_INTEGER KB
+ {
+ unsigned long long __converted;
+ __converted = $1 * 1024;
+ $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &__converted);
+ }
+ | UNSIGNED_INTEGER MB
+ {
+ unsigned long long __converted;
+ __converted = $1 * 1048576;
+ $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &__converted);
+ }
+ | UNSIGNED_INTEGER GB
+ {
+ unsigned long long __converted;
+ __converted = $1 * 1073741824;
+ $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &__converted);
+ }
+ | PLAIN_TEXT
+ {
+ $$ = g_scan_literal_expression_new(LVT_STRING, &$1);
+ }
+ | PLAIN_TEXT "[" cexpression "]"
+ {
+ GScanExpression *__src;
+ __src = g_scan_literal_expression_new(LVT_STRING, &$1);
+ $$ = g_scan_set_item_new(__src, $3);
+ g_object_unref(G_OBJECT(__src));
+ g_object_unref(G_OBJECT($3));
+ }
+ | ESCAPED_TEXT
+ {
+ $$ = g_scan_literal_expression_new(LVT_STRING, $1);
+ }
+ | ESCAPED_TEXT "[" cexpression "]"
+ {
+ GScanExpression *__src;
+ __src = g_scan_literal_expression_new(LVT_STRING, $1);
+ $$ = g_scan_set_item_new(__src, $3);
+ g_object_unref(G_OBJECT(__src));
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+
+ chain_items : chain_item
+ {
+ $$ = $1;
+ }
+ | chain_items "." chain_item
+ {
+ g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS($1), G_SCAN_NAMED_ACCESS($3));
+ g_object_unref(G_OBJECT($3));
+ $$ = $1;
+ }
+ ;
+
+ chain_item : NAME
+ {
+ $$ = g_scan_named_access_new(&$1);
+ }
+ | NAME "(" ")"
+ {
+ $$ = g_scan_pending_call_new(&$1, NULL, 0);
+ }
+ | NAME "(" call_args ")"
+ {
+ size_t __i;
+ $$ = g_scan_pending_call_new(&$1, $3.args, $3.count);
+ for (__i = 0; __i < $3.count; __i++)
+ g_object_unref(G_OBJECT($3.args[__i]));
+ free($3.args);
+ }
+ | NAME "[" cexpression "]"
+ {
+ $$ = g_scan_pending_extraction_new(&$1, $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+ call_args : cexpression
+ {
+ $$.count = 1;
+ $$.args = malloc(sizeof(GScanExpression *));
+ $$.args[0] = $1;
+ }
+ | call_args "," cexpression
+ {
+ $1.count++;
+ $1.args = realloc($1.args, $1.count * sizeof(GScanExpression *));
+ $1.args[$1.count - 1] = $3;
+ $$ = $1;
+ }
+ ;
+
+ logical_expr : cexpression "and" cexpression
+ {
+ $$ = g_scan_logical_operation_new(BOT_AND, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "or" cexpression
+ {
+ $$ = g_scan_logical_operation_new(BOT_OR, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | "not" "(" cexpression ")"
+ {
+ $$ = g_scan_logical_operation_new(BOT_NOT, $3, NULL);
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+relational_expr : cexpression "<" cexpression
+ {
+ $$ = g_scan_relational_operation_new(RCO_LT, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "<=" cexpression
+ {
+ $$ = g_scan_relational_operation_new(RCO_LE, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "==" cexpression
+ {
+ $$ = g_scan_relational_operation_new(RCO_EQ, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "!=" cexpression
+ {
+ $$ = g_scan_relational_operation_new(RCO_NE, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression ">" cexpression
+ {
+ $$ = g_scan_relational_operation_new(RCO_GT, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression ">=" cexpression
+ {
+ $$ = g_scan_relational_operation_new(RCO_GE, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+ string_op : cexpression "contains" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_CONTAINS, $1, $3, true);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "startswith" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_STARTSWITH, $1, $3, true);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "endswith" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_ENDSWITH, $1, $3, true);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "matches" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_MATCHES, $1, $3, true);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "icontains" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_CONTAINS, $1, $3, false);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "istartswith" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_STARTSWITH, $1, $3, false);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "iendswith" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_ENDSWITH, $1, $3, false);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "iequals" cexpression
+ {
+ $$ = g_scan_string_operation_new(SOT_IEQUALS, $1, $3, false);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+ arithm_expr : cexpression "+" cexpression
+ {
+ $$ = g_scan_arithmetic_operation_new(AEO_PLUS, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "-" cexpression
+ {
+ $$ = g_scan_arithmetic_operation_new(AEO_MINUS, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "*" cexpression
+ {
+ $$ = g_scan_arithmetic_operation_new(AEO_MUL, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "/" cexpression
+ {
+ $$ = g_scan_arithmetic_operation_new(AEO_DIV, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ | cexpression "%" cexpression
+ {
+ $$ = g_scan_arithmetic_operation_new(AEO_MOD, $1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+
+ set_match_counter : "none" "of" pattern_set
+ {
+ GScanSetMatchCounter *__counter;
+ __counter = G_SCAN_SET_MATCH_COUNTER($3);
+ g_scan_set_match_counter_define_expected_matches(__counter, SSCT_NONE, NULL);
+ $$ = $3;
+ }
+ | "any" "of" pattern_set
+ {
+ GScanSetMatchCounter *__counter;
+ __counter = G_SCAN_SET_MATCH_COUNTER($3);
+ g_scan_set_match_counter_define_expected_matches(__counter, SSCT_ANY, NULL);
+ $$ = $3;
+ }
+ | "all" "of" pattern_set
+ {
+ GScanSetMatchCounter *__counter;
+ __counter = G_SCAN_SET_MATCH_COUNTER($3);
+ g_scan_set_match_counter_define_expected_matches(__counter, SSCT_ALL, NULL);
+ $$ = $3;
+ }
+ | UNSIGNED_INTEGER "of" pattern_set
+ {
+ GScanSetMatchCounter *__counter;
+ size_t __number;
+ bool __status;
+
+ __counter = G_SCAN_SET_MATCH_COUNTER($3);
+ __number = $1;
+
+ __status = g_scan_set_match_counter_define_expected_matches(__counter,
+ SSCT_NUMBER, &__number);
+
+ if (!__status)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Expected matches counter too high: %zu"), __number);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = $3;
+
+ }
+ ;
+
+ pattern_set : "them"
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, NULL, &__count);
+
+ if (__patterns == NULL)
+ {
+ raise_error(_("No pattern found for \"them\""));
+ YYERROR;
+ }
+
+ $$ = g_scan_set_match_counter_new_shared(__patterns, __count);
+
+ free(__patterns);
+
+ }
+ | "(" pattern_set_items ")"
+ {
+ $$ = $2;
+ }
+ ;
+
+ pattern_set_items : BYTES_ID
+ {
+ const GSearchPattern *__pat;
+
+ __pat = g_scan_rule_get_local_variable(*built_rule, $1.data);
+
+ if (__pat == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Pattern not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_set_match_counter_new_shared((const GSearchPattern *[]) { __pat }, 1);
+
+ }
+ | BYTES_FUZZY_ID
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, $1.data, &__count);
+
+ if (__patterns == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Patterns not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_set_match_counter_new_shared(__patterns, __count);
+
+ free(__patterns);
+
+ }
+ | pattern_set_items "," BYTES_ID
+ {
+ const GSearchPattern *__pat;
+ GScanSetMatchCounter *__counter;
+
+ __pat = g_scan_rule_get_local_variable(*built_rule, $3.data);
+
+ if (__pat == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Pattern not found: \"%s\""), $3.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ __counter = G_SCAN_SET_MATCH_COUNTER($1);
+ g_scan_set_match_counter_add_extra_shared_patterns(__counter,
+ (const GSearchPattern *[]) { __pat }, 1);
+
+ $$ = $1;
+
+ }
+ | pattern_set_items "," BYTES_FUZZY_ID
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+ GScanSetMatchCounter *__counter;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, $3.data, &__count);
+
+ if (__patterns == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Patterns not found: \"%s\""), $3.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ __counter = G_SCAN_SET_MATCH_COUNTER($1);
+ g_scan_set_match_counter_add_extra_shared_patterns(__counter, __patterns, __count);
+
+ free(__patterns);
+
+ $$ = $1;
+
+ }
+ ;
+
+
+ set : "(" ")"
+ {
+ $$ = g_scan_generic_set_new();
+ }
+ | "(" cexpression "," ")"
+ {
+ $$ = g_scan_generic_set_new();
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $2);
+ g_object_unref(G_OBJECT($2));
+ }
+ | "(" set_items ")"
+ {
+ $$ = $2;
+ }
+ ;
+
+ set_items : cexpression "," cexpression
+ {
+ $$ = g_scan_generic_set_new();
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $1);
+ g_object_unref(G_OBJECT($1));
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ | set_items "," cexpression
+ {
+ $$ = $1;
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+
+ intersection : cexpression "in" cexpression
+ {
+ $$ = g_scan_sets_intersection_new($1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+
+ pattern_handler : _pattern_handler
+ {
+ $$ = $1;
+ }
+ | _pattern_handler "[" cexpression "]"
+ {
+ if (g_scan_pattern_handler_get_handler_type(G_SCAN_PATTERN_HANDLER($1)) == SHT_COUNTER)
+ {
+ raise_error("Match counts can not get indexed");
+ YYERROR;
+ }
+
+ $$ = g_scan_set_item_new($1, $3);
+ g_object_unref(G_OBJECT($1));
+ g_object_unref(G_OBJECT($3));
+
+ }
+ ;
+
+ _pattern_handler : BYTES_ID
+ {
+ const GSearchPattern *__pat;
+
+ __pat = g_scan_rule_get_local_variable(*built_rule, $1.data);
+
+ if (__pat == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Pattern not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared((const GSearchPattern *[]) { __pat }, 1, SHT_RAW);
+
+ }
+ | BYTES_FUZZY_ID
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, $1.data, &__count);
+
+ if (__patterns == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Patterns not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared(__patterns, __count, SHT_RAW);
+
+ free(__patterns);
+
+ }
+ | BYTES_ID_COUNTER
+ {
+ const GSearchPattern *__pat;
+
+ __pat = g_scan_rule_get_local_variable(*built_rule, $1.data);
+
+ if (__pat == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Pattern not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared((const GSearchPattern *[]) { __pat }, 1, SHT_COUNTER);
+
+ }
+ | BYTES_FUZZY_ID_COUNTER
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, $1.data, &__count);
+
+ if (__patterns == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Patterns not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared(__patterns, __count, SHT_COUNTER);
+
+ free(__patterns);
+
+ }
+ | BYTES_ID_START
+ {
+ const GSearchPattern *__pat;
+
+ __pat = g_scan_rule_get_local_variable(*built_rule, $1.data);
+
+ if (__pat == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Pattern not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared((const GSearchPattern *[]) { __pat }, 1, SHT_START);
+
+ }
+ | BYTES_FUZZY_ID_START
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, $1.data, &__count);
+
+ if (__patterns == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Patterns not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared(__patterns, __count, SHT_START);
+
+ free(__patterns);
+
+ }
+ | BYTES_ID_LENGTH
+ {
+ const GSearchPattern *__pat;
+
+ __pat = g_scan_rule_get_local_variable(*built_rule, $1.data);
+
+ if (__pat == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Pattern not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared((const GSearchPattern *[]) { __pat }, 1, SHT_LENGTH);
+
+ }
+ | BYTES_FUZZY_ID_LENGTH
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, $1.data, &__count);
+
+ if (__patterns == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Patterns not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared(__patterns, __count, SHT_LENGTH);
+
+ free(__patterns);
+
+ }
+ | BYTES_ID_END
+ {
+ const GSearchPattern *__pat;
+
+ __pat = g_scan_rule_get_local_variable(*built_rule, $1.data);
+
+ if (__pat == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Pattern not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared((const GSearchPattern *[]) { __pat }, 1, SHT_END);
+
+ }
+ | BYTES_FUZZY_ID_END
+ {
+ size_t __count;
+ const GSearchPattern **__patterns;
+
+ __patterns = g_scan_rule_get_local_variables(*built_rule, $1.data, &__count);
+
+ if (__patterns == NULL)
+ {
+ char *_msg;
+ int _ret;
+
+ _ret = asprintf(&_msg, _("Patterns not found: \"%s\""), $1.data);
+
+ if (_ret != -1)
+ {
+ raise_error(_msg);
+ free(_msg);
+ }
+
+ YYERROR;
+ }
+
+ $$ = g_scan_pattern_handler_new_shared(__patterns, __count, SHT_END);
+
+ free(__patterns);
+
+ }
+ ;
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = décodeur impliqué dans le processus. *
+* temp = zone de travail à destination des lectures. *
+* msg = message d'erreur. *
+* *
+* Description : Affiche un message d'erreur suite à l'analyse en échec. *
+* *
+* Retour : 0 *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int yyerror(GContentScanner *scanner, yyscan_t yyscanner, GScanRule **built_rule, sized_string_t *tmp_0, sized_string_t *tmp_1, char *msg)
+{
+ //printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = chercheur de motifs à préparer. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* *
+* Description : Complète une recherche de motifs avec des règles. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool process_rules_definitions(GContentScanner *scanner, const char *text, size_t length)
+{
+ bool result; /* Bilan à renvoyer */
+ GScanRule *built_rule; /* Règle en construction */
+ sized_string_t tmp_0; /* Zone tampon #1 */
+ sized_string_t tmp_1; /* Zone tampon #2 */
+ yyscan_t lexstate; /* Gestion d'analyse lexicale */
+ YY_BUFFER_STATE state; /* Contexte d'analyse */
+ int status; /* Bilan d'une analyse */
+
+ result = false;
+
+ built_rule = NULL;
+
+ tmp_0.data = malloc((length + 1) * sizeof(bin_t));
+ tmp_0.len = 0;
+
+ tmp_1.data = malloc((length + 1) * sizeof(bin_t));
+ tmp_1.len = 0;
+
+ rost_lex_init(&lexstate);
+
+ state = rost__scan_bytes(text, length, lexstate);
+
+ status = yyparse(scanner, lexstate, &built_rule, &tmp_0, &tmp_1);
+
+ result = (status == EXIT_SUCCESS);
+
+ yy_delete_buffer(state, lexstate);
+
+ rost_lex_destroy(lexstate);
+
+ exit_szstr(&tmp_0);
+ exit_szstr(&tmp_1);
+
+ g_clear_object(&built_rule);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/item-int.h b/src/analysis/scan/item-int.h
new file mode 100644
index 0000000..a04b861
--- /dev/null
+++ b/src/analysis/scan/item-int.h
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item-int.h - prototypes internes pour la définition d'un élément appelable lors de l'exécution d'une règle
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEM_INT_H
+#define _ANALYSIS_SCAN_ITEM_INT_H
+
+
+#include "item.h"
+
+
+#include <stdbool.h>
+
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+typedef char * (* get_registered_item_name_fc) (const GScanRegisteredItem *);
+
+/* Lance une résolution d'élément à solliciter. */
+typedef bool (* resolve_registered_item_fc) (GScanRegisteredItem *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **);
+
+/* Réduit une expression à une forme plus simple. */
+typedef bool (* reduce_registered_item_fc) (GScanRegisteredItem *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Effectue un appel à une fonction enregistrée. */
+typedef bool (* run_registered_item_call_fc) (GScanRegisteredItem *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+/* Effectue une extraction d'élément à partir d'une série. */
+typedef GObject * (* extract_registered_item_at) (GScanRegisteredItem *, GScanExpression *, GScanContext *, GScanScope *);
+
+
+/* Expression d'évaluation généraliste (instance) */
+struct _GScanRegisteredItem
+{
+ GObject parent; /* A laisser en premier */
+
+};
+
+/* Expression d'évaluation généraliste (classe) */
+struct _GScanRegisteredItemClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ get_registered_item_name_fc get_name; /* Obtention du nom associé */
+
+ resolve_registered_item_fc resolve; /* Opération de résolution */
+ reduce_registered_item_fc reduce; /* Opération de réduction */
+ run_registered_item_call_fc run_call; /* Appel à une fonction connue */
+ extract_registered_item_at extract; /* Extraction d'un élément */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEM_INT_H */
diff --git a/src/analysis/scan/item.c b/src/analysis/scan/item.c
new file mode 100644
index 0000000..509ad28
--- /dev/null
+++ b/src/analysis/scan/item.c
@@ -0,0 +1,325 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.c - définition d'un élément appelable lors de l'exécution d'une règle
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "item.h"
+
+
+#include <assert.h>
+
+
+#include "item-int.h"
+
+
+
+/* ----------------------- BASES D'OBJET POUR LE SYSTEME GLIB ----------------------- */
+
+
+/* Initialise la classe des éléments appelables enregistrés. */
+static void g_scan_registered_item_class_init(GScanRegisteredItemClass *);
+
+/* Initialise une instance d'élément appelable enregistré. */
+static void g_scan_registered_item_init(GScanRegisteredItem *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_registered_item_dispose(GScanRegisteredItem *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_registered_item_finalize(GScanRegisteredItem *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* BASES D'OBJET POUR LE SYSTEME GLIB */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un élément appelable et enregistré. */
+G_DEFINE_TYPE(GScanRegisteredItem, g_scan_registered_item, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des éléments appelables enregistrés. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_registered_item_class_init(GScanRegisteredItemClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_registered_item_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_registered_item_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = instance à initialiser. *
+* *
+* Description : Initialise une instance d'élément appelable enregistré. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_registered_item_init(GScanRegisteredItem *item)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_registered_item_dispose(GScanRegisteredItem *item)
+{
+ G_OBJECT_CLASS(g_scan_registered_item_parent_class)->dispose(G_OBJECT(item));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_registered_item_finalize(GScanRegisteredItem *item)
+{
+ G_OBJECT_CLASS(g_scan_registered_item_parent_class)->finalize(G_OBJECT(item));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_registered_item_get_name(const GScanRegisteredItem *item)
+{
+ char *result; /* Désignation à retourner */
+ GScanRegisteredItemClass *class; /* Classe à activer */
+
+ class = G_SCAN_REGISTERED_ITEM_GET_CLASS(item);
+
+ result = class->get_name(item);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* target = désignation de l'objet d'appel à identifier. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT]*
+* *
+* Description : Lance une résolution d'élément à solliciter. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_registered_item_resolve(GScanRegisteredItem *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanRegisteredItemClass *class; /* Classe à activer */
+
+ *out = NULL;
+
+ class = G_SCAN_REGISTERED_ITEM_GET_CLASS(item);
+
+ if (class->resolve == NULL)
+ result = false;
+ else
+ {
+ result = class->resolve(item, target, ctx, scope, out);
+
+#ifndef NDEBUG
+ if (*out != NULL)
+ assert(result);
+#endif
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_registered_item_reduce(GScanRegisteredItem *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanRegisteredItemClass *class; /* Classe à activer */
+
+ *out = NULL;
+
+ class = G_SCAN_REGISTERED_ITEM_GET_CLASS(item);
+
+ if (class->reduce == NULL)
+ result = false;
+ else
+ {
+ result = class->reduce(item, ctx, scope, out);
+
+#ifndef NDEBUG
+ if (*out != NULL)
+ assert(result);
+#endif
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Effectue un appel à une fonction enregistrée. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_registered_item_run_call(GScanRegisteredItem *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanRegisteredItemClass *class; /* Classe à activer */
+
+ *out = NULL;
+
+ class = G_SCAN_REGISTERED_ITEM_GET_CLASS(item);
+
+ if (class->run_call == NULL)
+ result = false;
+ else
+ {
+ result = class->run_call(item, args, count, ctx, scope, out);
+
+#ifndef NDEBUG
+ if (*out != NULL)
+ assert(result);
+#endif
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* index = indice de l'élément à cibler. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* *
+* Description : Effectue une extraction d'élément à partir d'une série. *
+* *
+* Retour : Elément de série obtenu ou NULL si erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GObject *g_scan_registered_item_extract_at(GScanRegisteredItem *item, GScanExpression *index, GScanContext *ctx, GScanScope *scope)
+{
+ GObject *result; /* Elément récupéré à renvoyer */
+ GScanRegisteredItemClass *class; /* Classe à activer */
+
+ class = G_SCAN_REGISTERED_ITEM_GET_CLASS(item);
+
+ if (class->extract == NULL)
+ result = NULL;
+
+ else
+ result = class->extract(item, index, ctx, scope);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/item.h b/src/analysis/scan/item.h
new file mode 100644
index 0000000..a6c56c3
--- /dev/null
+++ b/src/analysis/scan/item.h
@@ -0,0 +1,72 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * item.h - prototypes pour la définition d'un élément appelable lors de l'exécution d'une règle
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEM_H
+#define _ANALYSIS_SCAN_ITEM_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "context.h"
+#include "expr.h"
+
+
+
+#define G_TYPE_SCAN_REGISTERED_ITEM g_scan_registered_item_get_type()
+#define G_SCAN_REGISTERED_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_REGISTERED_ITEM, GScanRegisteredItem))
+#define G_IS_SCAN_REGISTERED_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_REGISTERED_ITEM))
+#define G_SCAN_REGISTERED_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_REGISTERED_ITEM, GScanRegisteredItemClass))
+#define G_IS_SCAN_REGISTERED_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_REGISTERED_ITEM))
+#define G_SCAN_REGISTERED_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_REGISTERED_ITEM, GScanRegisteredItemClass))
+
+
+/* Expression d'évaluation généraliste (instance) */
+typedef struct _GScanRegisteredItem GScanRegisteredItem;
+
+/* Expression d'évaluation généraliste (classe) */
+typedef struct _GScanRegisteredItemClass GScanRegisteredItemClass;
+
+
+/* Indique le type défini pour un élément appelable et enregistré. */
+GType g_scan_registered_item_get_type(void);
+
+/* Indique le nom associé à une expression d'évaluation. */
+char *g_scan_registered_item_get_name(const GScanRegisteredItem *);
+
+/* Lance une résolution d'élément à solliciter. */
+bool g_scan_registered_item_resolve(GScanRegisteredItem *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **);
+
+/* Réduit une expression à une forme plus simple. */
+bool g_scan_registered_item_reduce(GScanRegisteredItem *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Effectue un appel à une fonction enregistrée. */
+bool g_scan_registered_item_run_call(GScanRegisteredItem *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+/* Effectue une extraction d'élément à partir d'une série. */
+GObject *g_scan_registered_item_extract_at(GScanRegisteredItem *, GScanExpression *, GScanContext *, GScanScope *);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEM_H */
diff --git a/src/analysis/scan/items/Makefile.am b/src/analysis/scan/items/Makefile.am
new file mode 100644
index 0000000..9263c7b
--- /dev/null
+++ b/src/analysis/scan/items/Makefile.am
@@ -0,0 +1,37 @@
+
+noinst_LTLIBRARIES = libanalysisscanitems.la
+
+
+if BUILD_MAGIC_SUPPORT
+
+MAGIC_LIBADD = magic/libanalysisscanitemsmagic.la
+
+MAGIC_SUBDIRS = magic
+
+endif
+
+
+libanalysisscanitems_la_SOURCES = \
+ count.h count.c \
+ datasize.h datasize.c \
+ maxcommon.h maxcommon.c \
+ modpath.h modpath.c \
+ uint-int.h \
+ uint.h uint.c
+
+libanalysisscanitems_la_LIBADD = \
+ console/libanalysisscanitemsconsole.la \
+ $(MAGIC_LIBADD) \
+ math/libanalysisscanitemsmath.la \
+ string/libanalysisscanitemsstring.la \
+ time/libanalysisscanitemstime.la
+
+libanalysisscanitems_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitems_la_SOURCES:%c=)
+
+
+SUBDIRS = console $(MAGIC_SUBDIRS) math string time
diff --git a/src/analysis/scan/items/console/Makefile.am b/src/analysis/scan/items/console/Makefile.am
new file mode 100644
index 0000000..4433789
--- /dev/null
+++ b/src/analysis/scan/items/console/Makefile.am
@@ -0,0 +1,13 @@
+
+noinst_LTLIBRARIES = libanalysisscanitemsconsole.la
+
+
+libanalysisscanitemsconsole_la_SOURCES = \
+ log.h log.c
+
+libanalysisscanitemsconsole_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsconsole_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/console/log.c b/src/analysis/scan/items/console/log.c
new file mode 100644
index 0000000..90e8f03
--- /dev/null
+++ b/src/analysis/scan/items/console/log.c
@@ -0,0 +1,304 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * log.c - affichage de message à partir des conditions d'une règle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "log.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des affichages de messages. */
+static void g_scan_console_log_function_class_init(GScanConsoleLogFunctionClass *);
+
+/* Initialise une instance d'affichage de message. */
+static void g_scan_console_log_function_init(GScanConsoleLogFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_console_log_function_dispose(GScanConsoleLogFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_console_log_function_finalize(GScanConsoleLogFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_console_log_function_get_name(const GScanConsoleLogFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un afficheur de messages arbitraires. */
+G_DEFINE_TYPE(GScanConsoleLogFunction, g_scan_console_log_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des affichages de messages. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_console_log_function_class_init(GScanConsoleLogFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_console_log_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_console_log_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_console_log_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_console_log_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance d'affichage de message. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_console_log_function_init(GScanConsoleLogFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_console_log_function_dispose(GScanConsoleLogFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_console_log_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_console_log_function_finalize(GScanConsoleLogFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_console_log_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction d'affichage de messages quelconques. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanConsoleLogFunction *g_scan_console_log_function_new(void)
+{
+ GScanConsoleLogFunction *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_console_log_function_get_name(const GScanConsoleLogFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("log");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ bool boolean; /* Valeur booléenne */
+ long long sinteger; /* Valeur entière signée */
+ unsigned long long uinteger; /* Valeur entière non signée */
+ const sized_string_t *string; /* Description du chaîne */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = true;
+
+ if (count == 0)
+ goto done;
+
+ for (i = 0; i < count && result; i++)
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[i]);
+
+ if (!result)
+ goto done;
+
+ for (i = 0; i < count; i++)
+ {
+ literal = G_SCAN_LITERAL_EXPRESSION(args[i]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ switch (vtype)
+ {
+ case LVT_BOOLEAN:
+ result = g_scan_literal_expression_get_boolean_value(literal, &boolean);
+ if (result)
+ fprintf(stderr, "%s", boolean ? "true" : "false");
+ break;
+
+ case LVT_SIGNED_INTEGER:
+ result = g_scan_literal_expression_get_signed_integer_value(literal, &sinteger);
+ if (result)
+ fprintf(stderr, "0x%llx", sinteger);
+ break;
+
+ case LVT_UNSIGNED_INTEGER:
+ result = g_scan_literal_expression_get_unsigned_integer_value(literal, &uinteger);
+ if (result)
+ fprintf(stderr, "0x%llx", uinteger);
+ break;
+
+ case LVT_STRING:
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (result)
+ for (k = 0; k < string->len; k++)
+ {
+ if (isprint(string->data[k]))
+ fprintf(stderr, "%c", string->data[k]);
+ else
+ fprintf(stderr, "\\x%02hhx", string->data[k]);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ fprintf(stderr, "\n");
+
+ done:
+
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ result }));
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/console/log.h b/src/analysis/scan/items/console/log.h
new file mode 100644
index 0000000..95fc55f
--- /dev/null
+++ b/src/analysis/scan/items/console/log.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * log.h - prototypes pour l'affichage de message à partir des conditions d'une règle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_CONSOLE_LOG_H
+#define _ANALYSIS_SCAN_ITEMS_CONSOLE_LOG_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_CONSOLE_LOG_FUNCTION g_scan_console_log_function_get_type()
+#define G_SCAN_CONSOLE_LOG_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, GScanConsoleLogFunction))
+#define G_IS_SCAN_CONSOLE_LOG_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION))
+#define G_SCAN_CONSOLE_LOG_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, GScanConsoleLogFunctionClass))
+#define G_IS_SCAN_CONSOLE_LOG_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION))
+#define G_SCAN_CONSOLE_LOG_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, GScanConsoleLogFunctionClass))
+
+
+/* Mesure de la quantité de données scannées (instance) */
+typedef GScanRegisteredItem GScanConsoleLogFunction;
+
+/* Mesure de la quantité de données scannées (classe) */
+typedef GScanRegisteredItemClass GScanConsoleLogFunctionClass;
+
+
+/* Indique le type défini pour un afficheur de messages arbitraires. */
+GType g_scan_console_log_function_get_type(void);
+
+/* Constitue une fonction d'affichage de messages quelconques. */
+GScanConsoleLogFunction *g_scan_console_log_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_CONSOLE_LOG_H */
diff --git a/src/analysis/scan/items/count.c b/src/analysis/scan/items/count.c
new file mode 100644
index 0000000..1d01867
--- /dev/null
+++ b/src/analysis/scan/items/count.c
@@ -0,0 +1,251 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * count.c - récupération de la taille du contenu scanné
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "count.h"
+
+
+#include "../item-int.h"
+#include "../exprs/arithmetic.h"
+#include "../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des décomptes d'ensemble homogène. */
+static void g_scan_count_function_class_init(GScanCountFunctionClass *);
+
+/* Initialise une instance de décompte d'ensemble homogène. */
+static void g_scan_count_function_init(GScanCountFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_count_function_dispose(GScanCountFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_count_function_finalize(GScanCountFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_count_function_get_name(const GScanCountFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_count_function_run_call(GScanCountFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un décompte d'ensemble. */
+G_DEFINE_TYPE(GScanCountFunction, g_scan_count_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des décomptes d'ensemble homogène. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_count_function_class_init(GScanCountFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_count_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_count_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_count_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_count_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de décompte d'ensemble homogène. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_count_function_init(GScanCountFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_count_function_dispose(GScanCountFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_count_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_count_function_finalize(GScanCountFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_count_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de décompte d'éléments d'un ensemble. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_count_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_COUNT_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_count_function_get_name(const GScanCountFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("count");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_count_function_run_call(GScanCountFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t sum; /* Somme des décomptes */
+ size_t i; /* Boucle de parcours */
+ size_t value; /* Nouveau décompte */
+
+ result = (count > 0);
+
+ if (result)
+ {
+ sum = 0;
+
+ for (i = 0; i < count && result; i++)
+ {
+ result = g_scan_expression_count_items(args[i], ctx, &value);
+ sum += value;
+ }
+
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ sum }));
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/count.h b/src/analysis/scan/items/count.h
new file mode 100644
index 0000000..d83714e
--- /dev/null
+++ b/src/analysis/scan/items/count.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * count.h - prototypes pour la récupération de la taille du contenu scanné
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_COUNT_H
+#define _ANALYSIS_SCAN_ITEMS_COUNT_H
+
+
+#include <glib-object.h>
+
+
+#include "../item.h"
+
+
+
+#define G_TYPE_SCAN_COUNT_FUNCTION g_scan_count_function_get_type()
+#define G_SCAN_COUNT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_COUNT_FUNCTION, GScanCountFunction))
+#define G_IS_SCAN_COUNT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_COUNT_FUNCTION))
+#define G_SCAN_COUNT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_COUNT_FUNCTION, GScanCountFunctionClass))
+#define G_IS_SCAN_COUNT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_COUNT_FUNCTION))
+#define G_SCAN_COUNT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_COUNT_FUNCTION, GScanCountFunctionClass))
+
+
+/* Mesure de la quantité de données scannées (instance) */
+typedef GScanRegisteredItem GScanCountFunction;
+
+/* Mesure de la quantité de données scannées (classe) */
+typedef GScanRegisteredItemClass GScanCountFunctionClass;
+
+
+/* Indique le type défini pour un décompte d'ensemble. */
+GType g_scan_count_function_get_type(void);
+
+/* Constitue une fonction de décompte d'éléments d'un ensemble. */
+GScanRegisteredItem *g_scan_count_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_COUNT_H */
diff --git a/src/analysis/scan/items/datasize.c b/src/analysis/scan/items/datasize.c
new file mode 100644
index 0000000..11fe649
--- /dev/null
+++ b/src/analysis/scan/items/datasize.c
@@ -0,0 +1,272 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * datasize.c - récupération de la taille du contenu scanné
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "datasize.h"
+
+
+#include "../item-int.h"
+#include "../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des mesures de quantité de données. */
+static void g_scan_datasize_function_class_init(GScanDatasizeFunctionClass *);
+
+/* Initialise une instance de mesure de quantité de données. */
+static void g_scan_datasize_function_init(GScanDatasizeFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_datasize_function_dispose(GScanDatasizeFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_datasize_function_finalize(GScanDatasizeFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_datasize_function_get_name(const GScanDatasizeFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_datasize_function_reduce(GScanDatasizeFunction *, GScanContext *, GScanScope *, GScanExpression **);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_datasize_function_run_call(GScanDatasizeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une mesure de quantité de données scannées. */
+G_DEFINE_TYPE(GScanDatasizeFunction, g_scan_datasize_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des mesures de quantité de données. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_datasize_function_class_init(GScanDatasizeFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_datasize_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_datasize_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_datasize_function_get_name;
+ registered->reduce = (reduce_registered_item_fc)g_scan_datasize_function_reduce;
+ registered->run_call = (run_registered_item_call_fc)g_scan_datasize_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de mesure de quantité de données. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_datasize_function_init(GScanDatasizeFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_datasize_function_dispose(GScanDatasizeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_datasize_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_datasize_function_finalize(GScanDatasizeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_datasize_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de récupération de taille de données. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_datasize_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_DATASIZE_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_datasize_function_get_name(const GScanDatasizeFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("datasize");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_datasize_function_reduce(GScanDatasizeFunction *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ GBinContent *content; /* Contenu à manipuler */
+ phys_t size; /* Quantité de données liées */
+
+ result = true;
+
+ content = g_scan_context_get_content(ctx);
+
+ size = g_binary_content_compute_size(content);
+
+ *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ size });
+
+ g_object_unref(G_OBJECT(content));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_datasize_function_run_call(GScanDatasizeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_scan_datasize_function_reduce(item, ctx, scope, (GScanExpression **)out);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/datasize.h b/src/analysis/scan/items/datasize.h
new file mode 100644
index 0000000..daa71d1
--- /dev/null
+++ b/src/analysis/scan/items/datasize.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * datasize.h - prototypes pour la récupération de la taille du contenu scanné
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_DATASIZE_H
+#define _ANALYSIS_SCAN_ITEMS_DATASIZE_H
+
+
+#include <glib-object.h>
+
+
+#include "../item.h"
+
+
+
+#define G_TYPE_SCAN_DATASIZE_FUNCTION g_scan_datasize_function_get_type()
+#define G_SCAN_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_DATASIZE_FUNCTION, GScanDatasizeFunction))
+#define G_IS_SCAN_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_DATASIZE_FUNCTION))
+#define G_SCAN_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_DATASIZE_FUNCTION, GScanDatasizeFunctionClass))
+#define G_IS_SCAN_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_DATASIZE_FUNCTION))
+#define G_SCAN_DATASIZE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_DATASIZE_FUNCTION, GScanDatasizeFunctionClass))
+
+
+/* Mesure de la quantité de données scannées (instance) */
+typedef GScanRegisteredItem GScanDatasizeFunction;
+
+/* Mesure de la quantité de données scannées (classe) */
+typedef GScanRegisteredItemClass GScanDatasizeFunctionClass;
+
+
+/* Indique le type défini pour une mesure de quantité de données scannées. */
+GType g_scan_datasize_function_get_type(void);
+
+/* Constitue une fonction de récupération de taille de données. */
+GScanRegisteredItem *g_scan_datasize_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_DATASIZE_H */
diff --git a/src/analysis/scan/items/magic/Makefile.am b/src/analysis/scan/items/magic/Makefile.am
new file mode 100644
index 0000000..1d741ff
--- /dev/null
+++ b/src/analysis/scan/items/magic/Makefile.am
@@ -0,0 +1,16 @@
+
+noinst_LTLIBRARIES = libanalysisscanitemsmagic.la
+
+
+libanalysisscanitemsmagic_la_SOURCES = \
+ cookie.h cookie.c \
+ mime-encoding.h mime-encoding.c \
+ mime-type.h mime-type.c \
+ type.h type.c
+
+libanalysisscanitemsmagic_la_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBMAGIC_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsmagic_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/magic/cookie.c b/src/analysis/scan/items/magic/cookie.c
new file mode 100644
index 0000000..41f26a0
--- /dev/null
+++ b/src/analysis/scan/items/magic/cookie.c
@@ -0,0 +1,122 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cookie.c - chargement des motifs de reconnaissance de contenus
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "cookie.h"
+
+
+#include <assert.h>
+
+
+#include <i18n.h>
+
+
+#include "../../../../core/logs.h"
+
+
+
+/* Référence des bibliothèques de reconnaissance */
+static magic_t __magic_cookie = 0;
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Charge les motifs de reconnaissance de contenus. *
+* *
+* Retour : Bilan de l'opération de chargemement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool init_magic_cookie(void)
+{
+ bool result; /* Bilan à retourner */
+ int ret; /* Bilan d'une opération */
+
+ __magic_cookie = magic_open(0);
+
+ ret = magic_load(__magic_cookie, NULL);
+ result = (ret != -1);
+
+ if (!result)
+ log_variadic_message(LMT_EXT_ERROR, _("cannot load magic database: %s"), magic_error(__magic_cookie));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Décharge les motifs de reconnaissance de contenus. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void exit_magic_cookie(void)
+{
+ magic_close(__magic_cookie);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : flags = forme de reconnaissance à préparer. *
+* *
+* Description : Fournit la référence aux mécanismes de reconnaissance. *
+* *
+* Retour : Cookie prêt à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+magic_t get_magic_cookie(int flags)
+{
+ magic_t result; /* Référence à retourner */
+#ifndef NDEBUG
+ int ret; /* Bilan de la préparation */
+#endif
+
+ result = __magic_cookie;
+ assert(result != 0);
+
+#ifndef NDEBUG
+ ret = magic_setflags(result, flags);
+ assert(ret != -1);
+#else
+ magic_setflags(result, flags);
+#endif
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/magic/cookie.h b/src/analysis/scan/items/magic/cookie.h
new file mode 100644
index 0000000..0ee2274
--- /dev/null
+++ b/src/analysis/scan/items/magic/cookie.h
@@ -0,0 +1,44 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cookie.h - prototypes pour le chargement des motifs de reconnaissance de contenus
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_COOKIE_H
+#define _ANALYSIS_SCAN_ITEMS_MAGIC_COOKIE_H
+
+
+#include <magic.h>
+#include <stdbool.h>
+
+
+
+/* Charge les motifs de reconnaissance de contenus. */
+bool init_magic_cookie(void);
+
+/* Décharge les motifs de reconnaissance de contenus. */
+void exit_magic_cookie(void);
+
+/* Fournit la référence aux mécanismes de reconnaissance. */
+magic_t get_magic_cookie(int);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_COOKIE_H */
diff --git a/src/analysis/scan/items/magic/mime-encoding.c b/src/analysis/scan/items/magic/mime-encoding.c
new file mode 100644
index 0000000..aee23ff
--- /dev/null
+++ b/src/analysis/scan/items/magic/mime-encoding.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * mime-encoding.c - reconnaissance de l'encodage d'un contenu
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "mime-encoding.h"
+
+
+#include "cookie.h"
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des reconnaissances de contenus. */
+static void g_scan_mime_encoding_function_class_init(GScanMimeEncodingFunctionClass *);
+
+/* Initialise une instance de reconnaissance de contenus. */
+static void g_scan_mime_encoding_function_init(GScanMimeEncodingFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_mime_encoding_function_dispose(GScanMimeEncodingFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_mime_encoding_function_finalize(GScanMimeEncodingFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_mime_encoding_function_get_name(const GScanMimeEncodingFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_mime_encoding_function_run_call(GScanMimeEncodingFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une reconnaissance d'encodages de contenus. */
+G_DEFINE_TYPE(GScanMimeEncodingFunction, g_scan_mime_encoding_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des reconnaissances de contenus. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_encoding_function_class_init(GScanMimeEncodingFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_mime_encoding_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_mime_encoding_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_mime_encoding_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_mime_encoding_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de reconnaissance de contenus. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_encoding_function_init(GScanMimeEncodingFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_encoding_function_dispose(GScanMimeEncodingFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_mime_encoding_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_encoding_function_finalize(GScanMimeEncodingFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_mime_encoding_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de cernement d'encodages de contenus. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_mime_encoding_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MIME_ENCODING_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_mime_encoding_function_get_name(const GScanMimeEncodingFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("mime_encoding");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_mime_encoding_function_run_call(GScanMimeEncodingFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ magic_t cookie; /* Référence des bibliothèques */
+ GBinContent *content; /* Contenu à manipuler */
+ vmpa2t pos; /* Tête de lecture */
+ phys_t size; /* Quantité de données dispos. */
+ const bin_t *data; /* Accès à des données */
+ const char *desc; /* Description du contenu */
+ sized_string_t string; /* Description à diffuser */
+
+ result = (count == 0);
+ if (!result) goto exit;
+
+ cookie = get_magic_cookie(MAGIC_MIME_ENCODING);
+
+ content = g_scan_context_get_content(ctx);
+
+ g_binary_content_compute_start_pos(content, &pos);
+
+ size = g_binary_content_compute_size(content);
+
+ data = g_binary_content_get_raw_access(content, &pos, size);
+
+ desc = magic_buffer(cookie, data, size);
+
+ if (desc != NULL)
+ {
+ string.data = (char *)desc;
+ string.len = strlen(desc);
+ }
+ else
+ {
+ string.data = "";
+ string.len = 0;
+ }
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string));
+
+ g_object_unref(G_OBJECT(content));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/magic/mime-encoding.h b/src/analysis/scan/items/magic/mime-encoding.h
new file mode 100644
index 0000000..45ac241
--- /dev/null
+++ b/src/analysis/scan/items/magic/mime-encoding.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * mime-encoding.h - prototypes pour la reconnaissance de l'encodage d'un contenu
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_ENCODING_H
+#define _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_ENCODING_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_MIME_ENCODING_FUNCTION g_scan_mime_encoding_function_get_type()
+#define G_SCAN_MIME_ENCODING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MIME_ENCODING_FUNCTION, GScanMimeEncodingFunction))
+#define G_IS_SCAN_MIME_ENCODING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MIME_ENCODING_FUNCTION))
+#define G_SCAN_MIME_ENCODING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MIME_ENCODING_FUNCTION, GScanMimeEncodingFunctionClass))
+#define G_IS_SCAN_MIME_ENCODING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MIME_ENCODING_FUNCTION))
+#define G_SCAN_MIME_ENCODING_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MIME_ENCODING_FUNCTION, GScanMimeEncodingFunctionClass))
+
+
+/* Reconnaissance d'encodages de contenus (instance) */
+typedef GScanRegisteredItem GScanMimeEncodingFunction;
+
+/* Reconnaissance d'encodages de contenus (classe) */
+typedef GScanRegisteredItemClass GScanMimeEncodingFunctionClass;
+
+
+/* Indique le type défini pour une reconnaissance d'encodages de contenus. */
+GType g_scan_mime_encoding_function_get_type(void);
+
+/* Constitue une fonction de cernement d'encodages de contenus. */
+GScanRegisteredItem *g_scan_mime_encoding_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_ENCODING_H */
diff --git a/src/analysis/scan/items/magic/mime-type.c b/src/analysis/scan/items/magic/mime-type.c
new file mode 100644
index 0000000..0635a33
--- /dev/null
+++ b/src/analysis/scan/items/magic/mime-type.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type.c - reconnaissance du type MIME d'un contenu
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "mime-type.h"
+
+
+#include "cookie.h"
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des reconnaissances de contenus. */
+static void g_scan_mime_type_function_class_init(GScanMimeTypeFunctionClass *);
+
+/* Initialise une instance de reconnaissance de contenus. */
+static void g_scan_mime_type_function_init(GScanMimeTypeFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_mime_type_function_dispose(GScanMimeTypeFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_mime_type_function_finalize(GScanMimeTypeFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_mime_type_function_get_name(const GScanMimeTypeFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_mime_type_function_run_call(GScanMimeTypeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une reconnaissance de types de contenus. */
+G_DEFINE_TYPE(GScanMimeTypeFunction, g_scan_mime_type_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des reconnaissances de contenus. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_type_function_class_init(GScanMimeTypeFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_mime_type_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_mime_type_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_mime_type_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_mime_type_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de reconnaissance de contenus. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_type_function_init(GScanMimeTypeFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_type_function_dispose(GScanMimeTypeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_mime_type_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_mime_type_function_finalize(GScanMimeTypeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_mime_type_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction d'identification de types de contenus.*
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_mime_type_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MIME_TYPE_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_mime_type_function_get_name(const GScanMimeTypeFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("mime_type");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_mime_type_function_run_call(GScanMimeTypeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ magic_t cookie; /* Référence des bibliothèques */
+ GBinContent *content; /* Contenu à manipuler */
+ vmpa2t pos; /* Tête de lecture */
+ phys_t size; /* Quantité de données dispos. */
+ const bin_t *data; /* Accès à des données */
+ const char *desc; /* Description du contenu */
+ sized_string_t string; /* Description à diffuser */
+
+ result = (count == 0);
+ if (!result) goto exit;
+
+ cookie = get_magic_cookie(MAGIC_MIME_TYPE);
+
+ content = g_scan_context_get_content(ctx);
+
+ g_binary_content_compute_start_pos(content, &pos);
+
+ size = g_binary_content_compute_size(content);
+
+ data = g_binary_content_get_raw_access(content, &pos, size);
+
+ desc = magic_buffer(cookie, data, size);
+
+ if (desc != NULL)
+ {
+ string.data = (char *)desc;
+ string.len = strlen(desc);
+ }
+ else
+ {
+ string.data = "";
+ string.len = 0;
+ }
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string));
+
+ g_object_unref(G_OBJECT(content));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/magic/mime-type.h b/src/analysis/scan/items/magic/mime-type.h
new file mode 100644
index 0000000..f46cd15
--- /dev/null
+++ b/src/analysis/scan/items/magic/mime-type.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * mime-type.h - prototypes pour la reconnaissance du type MIME d'un contenu
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_TYPE_H
+#define _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_TYPE_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_MIME_TYPE_FUNCTION g_scan_mime_type_function_get_type()
+#define G_SCAN_MIME_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MIME_TYPE_FUNCTION, GScanMimeTypeFunction))
+#define G_IS_SCAN_MIME_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MIME_TYPE_FUNCTION))
+#define G_SCAN_MIME_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MIME_TYPE_FUNCTION, GScanMimeTypeFunctionClass))
+#define G_IS_SCAN_MIME_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MIME_TYPE_FUNCTION))
+#define G_SCAN_MIME_TYPE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MIME_TYPE_FUNCTION, GScanMimeTypeFunctionClass))
+
+
+/* Reconnaissance de types de contenus (instance) */
+typedef GScanRegisteredItem GScanMimeTypeFunction;
+
+/* Reconnaissance de types de contenus (classe) */
+typedef GScanRegisteredItemClass GScanMimeTypeFunctionClass;
+
+
+/* Indique le type défini pour une reconnaissance de types de contenus. */
+GType g_scan_mime_type_function_get_type(void);
+
+/* Constitue une fonction d'identification de types de contenus. */
+GScanRegisteredItem *g_scan_mime_type_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_TYPE_H */
diff --git a/src/analysis/scan/items/magic/type.c b/src/analysis/scan/items/magic/type.c
new file mode 100644
index 0000000..43b16ff
--- /dev/null
+++ b/src/analysis/scan/items/magic/type.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type.c - reconnaissance du type d'un contenu
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "type.h"
+
+
+#include "cookie.h"
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des reconnaissances de contenus. */
+static void g_scan_magic_type_function_class_init(GScanMagicTypeFunctionClass *);
+
+/* Initialise une instance de reconnaissance de contenus. */
+static void g_scan_magic_type_function_init(GScanMagicTypeFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_magic_type_function_dispose(GScanMagicTypeFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_magic_type_function_finalize(GScanMagicTypeFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_magic_type_function_get_name(const GScanMagicTypeFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_magic_type_function_run_call(GScanMagicTypeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une reconnaissance de types de contenus. */
+G_DEFINE_TYPE(GScanMagicTypeFunction, g_scan_magic_type_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des reconnaissances de contenus. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_magic_type_function_class_init(GScanMagicTypeFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_magic_type_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_magic_type_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_magic_type_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_magic_type_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de reconnaissance de contenus. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_magic_type_function_init(GScanMagicTypeFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_magic_type_function_dispose(GScanMagicTypeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_magic_type_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_magic_type_function_finalize(GScanMagicTypeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_magic_type_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction d'identification de types de contenus.*
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_magic_type_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_magic_type_function_get_name(const GScanMagicTypeFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("type");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_magic_type_function_run_call(GScanMagicTypeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ magic_t cookie; /* Référence des bibliothèques */
+ GBinContent *content; /* Contenu à manipuler */
+ vmpa2t pos; /* Tête de lecture */
+ phys_t size; /* Quantité de données dispos. */
+ const bin_t *data; /* Accès à des données */
+ const char *desc; /* Description du contenu */
+ sized_string_t string; /* Description à diffuser */
+
+ result = (count == 0);
+ if (!result) goto exit;
+
+ cookie = get_magic_cookie(MAGIC_NONE);
+
+ content = g_scan_context_get_content(ctx);
+
+ g_binary_content_compute_start_pos(content, &pos);
+
+ size = g_binary_content_compute_size(content);
+
+ data = g_binary_content_get_raw_access(content, &pos, size);
+
+ desc = magic_buffer(cookie, data, size);
+
+ if (desc != NULL)
+ {
+ string.data = (char *)desc;
+ string.len = strlen(desc);
+ }
+ else
+ {
+ string.data = "";
+ string.len = 0;
+ }
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string));
+
+ g_object_unref(G_OBJECT(content));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/magic/type.h b/src/analysis/scan/items/magic/type.h
new file mode 100644
index 0000000..7a26da3
--- /dev/null
+++ b/src/analysis/scan/items/magic/type.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type.h - prototypes pour la reconnaissance du type d'un contenu
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_TYPE_H
+#define _ANALYSIS_SCAN_ITEMS_MAGIC_TYPE_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_MAGIC_TYPE_FUNCTION g_scan_magic_type_function_get_type()
+#define G_SCAN_MAGIC_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, GScanMagicTypeFunction))
+#define G_IS_SCAN_MAGIC_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION))
+#define G_SCAN_MAGIC_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, GScanMagicTypeFunctionClass))
+#define G_IS_SCAN_MAGIC_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION))
+#define G_SCAN_MAGIC_TYPE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, GScanMagicTypeFunctionClass))
+
+
+/* Reconnaissance de types de contenus (instance) */
+typedef GScanRegisteredItem GScanMagicTypeFunction;
+
+/* Reconnaissance de types de contenus (classe) */
+typedef GScanRegisteredItemClass GScanMagicTypeFunctionClass;
+
+
+/* Indique le type défini pour une reconnaissance de types de contenus. */
+GType g_scan_magic_type_function_get_type(void);
+
+/* Constitue une fonction d'identification de types de contenus. */
+GScanRegisteredItem *g_scan_magic_type_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_TYPE_H */
diff --git a/src/analysis/scan/items/math/Makefile.am b/src/analysis/scan/items/math/Makefile.am
new file mode 100644
index 0000000..1f37c72
--- /dev/null
+++ b/src/analysis/scan/items/math/Makefile.am
@@ -0,0 +1,13 @@
+
+noinst_LTLIBRARIES = libanalysisscanitemsmath.la
+
+
+libanalysisscanitemsmath_la_SOURCES = \
+ to_string.h to_string.c
+
+libanalysisscanitemsmath_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsmath_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/math/to_string.c b/src/analysis/scan/items/math/to_string.c
new file mode 100644
index 0000000..5debb61
--- /dev/null
+++ b/src/analysis/scan/items/math/to_string.c
@@ -0,0 +1,381 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_string.c - conversion d'une valeur entière en chaîne
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "to_string.h"
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des conversions de texte en entier. */
+static void g_scan_math_to_string_function_class_init(GScanMathToStringFunctionClass *);
+
+/* Initialise une instance de conversion de texte en entier. */
+static void g_scan_math_to_string_function_init(GScanMathToStringFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_math_to_string_function_dispose(GScanMathToStringFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_math_to_string_function_finalize(GScanMathToStringFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_math_to_string_function_get_name(const GScanMathToStringFunction *);
+
+/* Réalise la conversion d'une valeur en texte. */
+static void convert_integer_to_string(unsigned long long, unsigned long long, char **);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_math_to_string_function_run_call(GScanMathToStringFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conversion d'entier en texte. */
+G_DEFINE_TYPE(GScanMathToStringFunction, g_scan_math_to_string_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des conversions de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_class_init(GScanMathToStringFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_math_to_string_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_math_to_string_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_math_to_string_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_math_to_string_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de conversion de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_init(GScanMathToStringFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_dispose(GScanMathToStringFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_math_to_string_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_finalize(GScanMathToStringFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_math_to_string_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une fonction de conversion de valeur entière en texte. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_math_to_string_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_math_to_string_function_get_name(const GScanMathToStringFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("to_string");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : val = valeur entière à traiter. *
+* base = base à considérer. *
+* data = tête d'écriture à faire évoluer. [OUT] *
+* *
+* Description : Réalise la conversion d'une valeur en texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void convert_integer_to_string(unsigned long long val, unsigned long long base, char **data)
+{
+ static const char digits[16] = "0123456789abcdef";
+
+ if (val < base)
+ *((*data)++) = digits[val];
+
+ else
+ {
+ convert_integer_to_string(val / base, base, data);
+
+ *((*data)++) = digits[val % base];
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_math_to_string_function_run_call(GScanMathToStringFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ long long sval; /* Valeur signée obtenue */
+ unsigned long long uval; /* Valeur non signée obtenue */
+ bool negative; /* Besoin de signe en préfixe ?*/
+ unsigned long long base; /* Base de conversion */
+ char *data; /* Chaîne "C" à constituer */
+ char *iter; /* Tête d'écriture */
+ sized_string_t string; /* Chaîne finale complète */
+
+ /* Validation des arguments */
+
+ result = (count == 1 || count == 2);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_SIGNED_INTEGER || vtype == LVT_UNSIGNED_INTEGER);
+ if (!result) goto exit;
+
+ if (vtype == LVT_SIGNED_INTEGER)
+ {
+ result = g_scan_literal_expression_get_signed_integer_value(literal, &sval);
+ if (!result) goto exit;
+
+ assert(sval < 0);
+
+ negative = (sval < 0);
+
+ if (negative)
+ uval = -sval;
+
+ }
+ else
+ {
+ result = g_scan_literal_expression_get_unsigned_integer_value(literal, &uval);
+ if (!result) goto exit;
+ }
+
+ if (count == 1)
+ base = 10;
+
+ else
+ {
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[1]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[1]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_UNSIGNED_INTEGER);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_unsigned_integer_value(literal, &base);
+ if (!result) goto exit;
+
+ result = (base == 2 || base == 8 || base == 10 || base == 16);
+ if (!result) goto exit;
+
+ }
+
+ /* Réalisation de l'opération attendue */
+
+ data = malloc((1 + 2 + 64 * 8 + 1) * sizeof(char));
+ iter = data;
+
+ if (negative)
+ *(iter++) = '-';
+
+ switch (base)
+ {
+ case 2:
+ *(iter++) = '0';
+ *(iter++) = 'b';
+ break;
+
+ case 8:
+ *(iter++) = '0';
+ break;
+
+ case 10:
+ break;
+
+ case 16:
+ *(iter++) = '0';
+ *(iter++) = 'x';
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ convert_integer_to_string(uval, base, &iter);
+
+ string.data = data;
+ string.len = iter - data;
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string));
+
+ free(data);
+
+ result = true;
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/math/to_string.h b/src/analysis/scan/items/math/to_string.h
new file mode 100644
index 0000000..b9213a9
--- /dev/null
+++ b/src/analysis/scan/items/math/to_string.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_string.h - prototypes pour la conversion d'une valeur entière en chaîne
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H
+#define _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_MATH_TO_STRING_FUNCTION g_scan_math_to_string_function_get_type()
+#define G_SCAN_MATH_TO_STRING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunction))
+#define G_IS_SCAN_MATH_TO_STRING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION))
+#define G_SCAN_MATH_TO_STRING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunctionClass))
+#define G_IS_SCAN_MATH_TO_STRING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION))
+#define G_SCAN_MATH_TO_STRING_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunctionClass))
+
+
+/* Conversion d'une valeur entière en valeur textuelle (instance) */
+typedef GScanRegisteredItem GScanMathToStringFunction;
+
+/* Conversion d'une valeur entière en valeur textuelle (classe) */
+typedef GScanRegisteredItemClass GScanMathToStringFunctionClass;
+
+
+/* Indique le type défini pour une conversion d'entier en texte. */
+GType g_scan_math_to_string_function_get_type(void);
+
+/* Crée une fonction de conversion de valeur entière en texte. */
+GScanRegisteredItem *g_scan_math_to_string_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H */
diff --git a/src/analysis/scan/items/maxcommon.c b/src/analysis/scan/items/maxcommon.c
new file mode 100644
index 0000000..e8c4db3
--- /dev/null
+++ b/src/analysis/scan/items/maxcommon.c
@@ -0,0 +1,374 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * maxcommon.c - détermination de la plus grand occurrence au sein d'un ensemble d'éléments
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "maxcommon.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "../item-int.h"
+#include "../exprs/literal.h"
+#include "../../../glibext/comparison-int.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des repérages de plus grande occurrence. */
+static void g_scan_maxcommon_function_class_init(GScanMaxcommonFunctionClass *);
+
+/* Initialise une instance de repérage d'occurrence maximake. */
+static void g_scan_maxcommon_function_init(GScanMaxcommonFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_maxcommon_function_dispose(GScanMaxcommonFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_maxcommon_function_finalize(GScanMaxcommonFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_maxcommon_function_get_name(const GScanMaxcommonFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_maxcommon_function_run_call(GScanMaxcommonFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un décompte d'élément le plus représenté dans une série. */
+G_DEFINE_TYPE(GScanMaxcommonFunction, g_scan_maxcommon_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des repérages de plus grande occurrence.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_maxcommon_function_class_init(GScanMaxcommonFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_maxcommon_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_maxcommon_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_maxcommon_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_maxcommon_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de repérage d'occurrence maximake. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_maxcommon_function_init(GScanMaxcommonFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_maxcommon_function_dispose(GScanMaxcommonFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_maxcommon_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_maxcommon_function_finalize(GScanMaxcommonFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_maxcommon_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de calcul de plus grande occurrence. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_maxcommon_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MAXCOMMON_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_maxcommon_function_get_name(const GScanMaxcommonFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("maxcommon");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_maxcommon_function_run_call(GScanMaxcommonFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t used; /* Prochain emplacement libre */
+ GScanExpression **collected; /* Représentants de groupes */
+ size_t *scores; /* Taille de ces groupes */
+ size_t i; /* Boucle de parcours #1 */
+ size_t k; /* Boucle de parcours #2 */
+ bool status; /* Bilan de la comparaison */
+ bool equal; /* Egalité établie ? */
+ size_t arg0_count; /* Taille de l'argument unique */
+ GScanExpression *arg0_item; /* Elément de cet argument */
+ size_t best; /* Meilleur score identifié */
+
+ result = (count > 0);
+ if (!result) goto exit;
+
+ used = 0;
+
+ /* Si la série à étudier est directement fournie */
+ if (count > 1)
+ {
+ collected = malloc(count * sizeof(GScanExpression *));
+ scores = malloc(count * sizeof(size_t));
+
+ for (i = 0; i < count; i++)
+ {
+ for (k = 0; k < used; k++)
+ {
+ status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(args[i]),
+ G_COMPARABLE_ITEM(collected[k]),
+ RCO_EQ, &equal);
+
+ if (status && equal)
+ break;
+
+ }
+
+ if (k < used)
+ scores[k]++;
+
+ else
+ {
+ collected[used] = args[i];
+ g_object_ref(G_OBJECT(args[i]));
+ scores[used] = 1;
+
+ used++;
+
+ }
+
+ }
+
+ }
+
+ /* Sinon on considère que l'arguement unique porte la liste (idéalement) */
+ else
+ {
+ if (G_IS_SCAN_LITERAL_EXPRESSION(args[0]) || !g_scan_expression_handle_set_features(args[0]))
+ {
+ best = 1;
+ goto quick_unique;
+ }
+
+#ifndef NDEBUG
+ g_scan_expression_count_items(args[0], ctx, &arg0_count);
+#else
+ status = g_scan_expression_count_items(args[0], ctx, &arg0_count);
+ assert(status);
+#endif
+
+ collected = malloc(arg0_count * sizeof(GScanExpression *));
+ scores = malloc(arg0_count * sizeof(size_t));
+
+ if (arg0_count == 0)
+ {
+ best = 0;
+ goto quick_empty;
+ }
+
+ for (i = 0; i < arg0_count; i++)
+ {
+#ifndef NDEBUG
+ g_scan_expression_get_item(args[0], i, ctx, &arg0_item);
+#else
+ status = g_scan_expression_get_item(args[0], i, ctx, &arg0_item);
+ assert(status);
+#endif
+
+ for (k = 0; k < used; k++)
+ {
+ status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(arg0_item),
+ G_COMPARABLE_ITEM(collected[k]),
+ RCO_EQ, &equal);
+
+ if (status && equal)
+ break;
+
+ }
+
+ if (k < used)
+ {
+ g_object_unref(G_OBJECT(arg0_item));
+ scores[k]++;
+ }
+
+ else
+ {
+ collected[used] = arg0_item;
+ scores[used] = 1;
+
+ used++;
+
+ }
+
+ }
+
+ }
+
+ /* Analyse des résultats */
+
+ best = 0;
+
+ for (i = 0; i < used; i++)
+ if (scores[i] > best)
+ best = scores[i];
+
+ for (i = 0; i < used; i++)
+ g_object_unref(G_OBJECT(collected[i]));
+
+ free(collected);
+ free(scores);
+
+ quick_unique:
+
+ assert(best > 0);
+
+ quick_empty:
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ best }));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/maxcommon.h b/src/analysis/scan/items/maxcommon.h
new file mode 100644
index 0000000..a834c00
--- /dev/null
+++ b/src/analysis/scan/items/maxcommon.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * maxcommon.h - prototypes pour la détermination de la plus grand occurrence au sein d'un ensemble d'éléments
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MAXCOMMON_H
+#define _ANALYSIS_SCAN_ITEMS_MAXCOMMON_H
+
+
+#include <glib-object.h>
+
+
+#include "../item.h"
+
+
+
+#define G_TYPE_SCAN_MAXCOMMON_FUNCTION g_scan_maxcommon_function_get_type()
+#define G_SCAN_MAXCOMMON_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MAXCOMMON_FUNCTION, GScanMaxcommonFunction))
+#define G_IS_SCAN_MAXCOMMON_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MAXCOMMON_FUNCTION))
+#define G_SCAN_MAXCOMMON_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MAXCOMMON_FUNCTION, GScanMaxcommonFunctionClass))
+#define G_IS_SCAN_MAXCOMMON_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MAXCOMMON_FUNCTION))
+#define G_SCAN_MAXCOMMON_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MAXCOMMON_FUNCTION, GScanMaxcommonFunctionClass))
+
+
+/* Détermination de la plus grand occurrence au sein d'un ensemble (instance) */
+typedef GScanRegisteredItem GScanMaxcommonFunction;
+
+/* Détermination de la plus grand occurrence au sein d'un ensemble (classe) */
+typedef GScanRegisteredItemClass GScanMaxcommonFunctionClass;
+
+
+/* Indique le type défini pour un décompte d'élément le plus représenté dans une série. */
+GType g_scan_maxcommon_function_get_type(void);
+
+/* Constitue une fonction de calcul de plus grande occurrence. */
+GScanRegisteredItem *g_scan_maxcommon_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MAXCOMMON_H */
diff --git a/src/analysis/scan/items/modpath.c b/src/analysis/scan/items/modpath.c
new file mode 100644
index 0000000..62d3387
--- /dev/null
+++ b/src/analysis/scan/items/modpath.c
@@ -0,0 +1,306 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modpath.c - récupération des combinaisons de modification de motifs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "modpath.h"
+
+
+#include "../item-int.h"
+
+
+#include "../exprs/handler.h"
+#include "../exprs/literal.h"
+#include "../exprs/set.h"
+#include "../matches/bytes.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des énumérations de formules de motifs. */
+static void g_scan_modpath_function_class_init(GScanModpathFunctionClass *);
+
+/* Initialise une instance d'énumération de formules de motifs. */
+static void g_scan_modpath_function_init(GScanModpathFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_modpath_function_dispose(GScanModpathFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_modpath_function_finalize(GScanModpathFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_modpath_function_get_name(const GScanModpathFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_modpath_function_run_call(GScanModpathFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une énumération de formules créant des motifs. */
+G_DEFINE_TYPE(GScanModpathFunction, g_scan_modpath_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des énumérations de formules de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modpath_function_class_init(GScanModpathFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_modpath_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_modpath_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_modpath_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_modpath_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance d'énumération de formules de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modpath_function_init(GScanModpathFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modpath_function_dispose(GScanModpathFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_modpath_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modpath_function_finalize(GScanModpathFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_modpath_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction d'énumération des formules de motifs. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_modpath_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MODPATH_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_modpath_function_get_name(const GScanModpathFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("modpath");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_modpath_function_run_call(GScanModpathFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+
+ return false;
+
+#if 0 /* FIXME */
+
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ size_t mcount; /* Quantité de correspondances */
+ GScanMatch **matches; /* Correspondances établies */
+ size_t k; /* Boucle de parcours #2 */
+ sized_string_t path; /* Combinaison à conserver */
+ GScanExpression *subitem; /* Nouvel élément à transmettre*/
+
+ /* Validation préalable du type des arguments */
+
+ result = true;
+
+ for (i = 0; i < count && result; i++)
+ result = G_IS_SCAN_PATTERN_HANDLER(args[i]);
+
+ if (!result)
+ goto exit;
+
+ /* Construction des chemins attendus */
+
+ *out = G_OBJECT(g_scan_generic_set_new());
+
+ for (i = 0; i < count; i++)
+ {
+ matches = g_scan_pattern_handler_get_all_matches(G_SCAN_PATTERN_HANDLER(args[i]), ctx, &mcount);
+ if (mcount == 0) continue;
+
+ /**
+ * La série est à priori constituée d'éléments de même type, donc
+ * un test unique suffit.
+ */
+ if (!G_IS_SCAN_BYTES_MATCH(matches[0]))
+ {
+ for (k = 0; k < mcount; k++)
+ g_object_unref(G_OBJECT(matches[k]));
+ }
+
+ else
+ {
+ for (k = 0; k < mcount; k++)
+ {
+ path.data = g_scan_bytes_match_get_modifier_path(G_SCAN_BYTES_MATCH(matches[k]));
+ if (path.data == NULL) continue;
+
+ path.len = strlen(path.data);
+
+ subitem = g_scan_literal_expression_new(LVT_STRING, &path);
+
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), subitem);
+
+ g_object_unref(G_OBJECT(subitem));
+
+ exit_szstr(&path);
+
+ g_object_unref(G_OBJECT(matches[k]));
+
+ }
+
+ }
+
+ free(matches);
+
+ }
+
+ exit:
+
+ return result;
+
+#endif
+
+}
diff --git a/src/analysis/scan/items/modpath.h b/src/analysis/scan/items/modpath.h
new file mode 100644
index 0000000..3a78ef7
--- /dev/null
+++ b/src/analysis/scan/items/modpath.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modpath.h - prototypes pour la récupération des combinaisons de modification de motifs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MODPATH_H
+#define _ANALYSIS_SCAN_ITEMS_MODPATH_H
+
+
+#include <glib-object.h>
+
+
+#include "../item.h"
+
+
+
+#define G_TYPE_SCAN_MODPATH_FUNCTION g_scan_modpath_function_get_type()
+#define G_SCAN_MODPATH_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MODPATH_FUNCTION, GScanModpathFunction))
+#define G_IS_SCAN_MODPATH_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MODPATH_FUNCTION))
+#define G_SCAN_MODPATH_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MODPATH_FUNCTION, GScanModpathFunctionClass))
+#define G_IS_SCAN_MODPATH_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MODPATH_FUNCTION))
+#define G_SCAN_MODPATH_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MODPATH_FUNCTION, GScanModpathFunctionClass))
+
+
+/* Récupération de formules à l'origine de la construction de motifs (instance) */
+typedef GScanRegisteredItem GScanModpathFunction;
+
+/* Récupération de formules à l'origine de la construction de motifs (classe) */
+typedef GScanRegisteredItemClass GScanModpathFunctionClass;
+
+
+/* Indique le type défini pour une énumération de formules créant des motifs. */
+GType g_scan_modpath_function_get_type(void);
+
+/* Constitue une fonction d'énumération des formules de motifs. */
+GScanRegisteredItem *g_scan_modpath_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MODPATH_H */
diff --git a/src/analysis/scan/items/string/Makefile.am b/src/analysis/scan/items/string/Makefile.am
new file mode 100644
index 0000000..6f8d6c5
--- /dev/null
+++ b/src/analysis/scan/items/string/Makefile.am
@@ -0,0 +1,16 @@
+
+noinst_LTLIBRARIES = libanalysisscanitemsstring.la
+
+
+libanalysisscanitemsstring_la_SOURCES = \
+ lower.h lower.c \
+ to_int.h to_int.c \
+ upper.h upper.c \
+ wide.h wide.c
+
+libanalysisscanitemsstring_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsstring_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/string/lower.c b/src/analysis/scan/items/string/lower.c
new file mode 100644
index 0000000..241d87a
--- /dev/null
+++ b/src/analysis/scan/items/string/lower.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.c - bascule de lettres en minuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "lower.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des bascules de lettres en minuscules. */
+static void g_scan_string_lower_function_class_init(GScanStringLowerFunctionClass *);
+
+/* Initialise une instance de bascule de lettres en minuscules. */
+static void g_scan_string_lower_function_init(GScanStringLowerFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_lower_function_dispose(GScanStringLowerFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_lower_function_finalize(GScanStringLowerFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_lower_function_get_name(const GScanStringLowerFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_lower_function_run_call(GScanStringLowerFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+G_DEFINE_TYPE(GScanStringLowerFunction, g_scan_string_lower_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bascules de lettres en minuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_class_init(GScanStringLowerFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_lower_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_lower_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_string_lower_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_string_lower_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de bascule de lettres en minuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_init(GScanStringLowerFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_dispose(GScanStringLowerFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_lower_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_finalize(GScanStringLowerFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_lower_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de bascule de lettres en minuscules. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_string_lower_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_LOWER_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_string_lower_function_get_name(const GScanStringLowerFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("lower");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_string_lower_function_run_call(GScanStringLowerFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ const sized_string_t *string; /* Description du chaîne */
+ sized_string_t new; /* Description transformée */
+ size_t i; /* Boucle de parcours */
+
+ /* Validation des arguments */
+
+ result = (count == 1);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_STRING);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (!result) goto exit;
+
+ /* Réalisation de l'opération attendue */
+
+ new.data = malloc(string->len);
+ new.len = string->len;
+
+ for (i = 0; i < string->len; i++)
+ new.data[i] = tolower(string->data[i]);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &new));
+
+ exit_szstr(&new);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/string/lower.h b/src/analysis/scan/items/string/lower.h
new file mode 100644
index 0000000..b9eb00a
--- /dev/null
+++ b/src/analysis/scan/items/string/lower.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.h - prototypes pour la bascule de lettres en minuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_LOWER_FUNCTION g_scan_string_lower_function_get_type()
+#define G_SCAN_STRING_LOWER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunction))
+#define G_IS_SCAN_STRING_LOWER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION))
+#define G_SCAN_STRING_LOWER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunctionClass))
+#define G_IS_SCAN_STRING_LOWER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_LOWER_FUNCTION))
+#define G_SCAN_STRING_LOWER_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunctionClass))
+
+
+/* Bascule d'une suite de caractères en minuscules (instance) */
+typedef GScanRegisteredItem GScanStringLowerFunction;
+
+/* Bascule d'une suite de caractères en minuscules (classe) */
+typedef GScanRegisteredItemClass GScanStringLowerFunctionClass;
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+GType g_scan_string_lower_function_get_type(void);
+
+/* Constitue une fonction de bascule de lettres en minuscules. */
+GScanRegisteredItem *g_scan_string_lower_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H */
diff --git a/src/analysis/scan/items/string/to_int.c b/src/analysis/scan/items/string/to_int.c
new file mode 100644
index 0000000..150fd06
--- /dev/null
+++ b/src/analysis/scan/items/string/to_int.c
@@ -0,0 +1,303 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_int.c - conversion d'une chaîne en valeur entière
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "to_int.h"
+
+
+#include <stdlib.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des conversions de texte en entier. */
+static void g_scan_string_to_int_function_class_init(GScanStringToIntFunctionClass *);
+
+/* Initialise une instance de conversion de texte en entier. */
+static void g_scan_string_to_int_function_init(GScanStringToIntFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_to_int_function_dispose(GScanStringToIntFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_to_int_function_finalize(GScanStringToIntFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_to_int_function_get_name(const GScanStringToIntFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_to_int_function_run_call(GScanStringToIntFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conversion de texte en entier. */
+G_DEFINE_TYPE(GScanStringToIntFunction, g_scan_string_to_int_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des conversions de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_class_init(GScanStringToIntFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_to_int_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_to_int_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_string_to_int_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_string_to_int_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de conversion de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_init(GScanStringToIntFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_dispose(GScanStringToIntFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_to_int_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_finalize(GScanStringToIntFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_to_int_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une fonction de conversion de texte en valeur entière. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_string_to_int_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_TO_INT_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_string_to_int_function_get_name(const GScanStringToIntFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("to_int");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_string_to_int_function_run_call(GScanStringToIntFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ const sized_string_t *string; /* Chaîne à convertir */
+ unsigned long long base; /* Base de conversion */
+ char *data; /* Chaîne "C" à considérer */
+ long long sval; /* Valeur signée obtenue */
+ unsigned long long uval; /* Valeur non signée obtenue */
+
+ /* Validation des arguments */
+
+ result = (count == 1 || count == 2);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_STRING);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (!result) goto exit;
+
+ if (string->len == 0) goto exit;
+
+ if (count == 1)
+ base = 0;
+
+ else
+ {
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[1]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[1]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_UNSIGNED_INTEGER);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_unsigned_integer_value(literal, &base);
+ if (!result) goto exit;
+
+ }
+
+ /* Réalisation de l'opération attendue */
+
+ data = strndup(string->data, string->len);
+
+ if (string->data[0] == '-')
+ {
+ sval = strtoll(data, NULL, base);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &sval));
+
+ }
+ else
+ {
+ uval = strtoll(data, NULL, base);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &uval));
+
+ }
+
+ free(data);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/string/to_int.h b/src/analysis/scan/items/string/to_int.h
new file mode 100644
index 0000000..ffd971b
--- /dev/null
+++ b/src/analysis/scan/items/string/to_int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_int.h - prototypes pour la conversion d'une chaîne en valeur entière
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_TO_INT_FUNCTION g_scan_string_to_int_function_get_type()
+#define G_SCAN_STRING_TO_INT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunction))
+#define G_IS_SCAN_STRING_TO_INT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION))
+#define G_SCAN_STRING_TO_INT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunctionClass))
+#define G_IS_SCAN_STRING_TO_INT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_TO_INT_FUNCTION))
+#define G_SCAN_STRING_TO_INT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunctionClass))
+
+
+/* Conversion d'une valeur textuelle en valeur entière (instance) */
+typedef GScanRegisteredItem GScanStringToIntFunction;
+
+/* Conversion d'une valeur textuelle en valeur entière (classe) */
+typedef GScanRegisteredItemClass GScanStringToIntFunctionClass;
+
+
+/* Indique le type défini pour une conversion de texte en entier. */
+GType g_scan_string_to_int_function_get_type(void);
+
+/* Crée une fonction de conversion de texte en valeur entière. */
+GScanRegisteredItem *g_scan_string_to_int_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H */
diff --git a/src/analysis/scan/items/string/upper.c b/src/analysis/scan/items/string/upper.c
new file mode 100644
index 0000000..d09ae00
--- /dev/null
+++ b/src/analysis/scan/items/string/upper.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.c - bascule de lettres en majuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "upper.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des bascules de lettres en majuscules. */
+static void g_scan_string_upper_function_class_init(GScanStringUpperFunctionClass *);
+
+/* Initialise une instance de bascule de lettres en majuscules. */
+static void g_scan_string_upper_function_init(GScanStringUpperFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_upper_function_dispose(GScanStringUpperFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_upper_function_finalize(GScanStringUpperFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_upper_function_get_name(const GScanStringUpperFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_upper_function_run_call(GScanStringUpperFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+G_DEFINE_TYPE(GScanStringUpperFunction, g_scan_string_upper_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bascules de lettres en majuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_class_init(GScanStringUpperFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_upper_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_upper_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_string_upper_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_string_upper_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de bascule de lettres en majuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_init(GScanStringUpperFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_dispose(GScanStringUpperFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_upper_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_finalize(GScanStringUpperFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_upper_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de bascule de lettres en majuscules. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_string_upper_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_UPPER_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_string_upper_function_get_name(const GScanStringUpperFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("upper");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_string_upper_function_run_call(GScanStringUpperFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ const sized_string_t *string; /* Description du chaîne */
+ sized_string_t new; /* Description transformée */
+ size_t i; /* Boucle de parcours */
+
+ /* Validation des arguments */
+
+ result = (count == 1);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_STRING);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (!result) goto exit;
+
+ /* Réalisation de l'opération attendue */
+
+ new.data = malloc(string->len);
+ new.len = string->len;
+
+ for (i = 0; i < string->len; i++)
+ new.data[i] = toupper(string->data[i]);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &new));
+
+ exit_szstr(&new);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/string/upper.h b/src/analysis/scan/items/string/upper.h
new file mode 100644
index 0000000..4fdeb09
--- /dev/null
+++ b/src/analysis/scan/items/string/upper.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.h - prototypes pour la bascule de lettres en majuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_UPPER_FUNCTION g_scan_string_upper_function_get_type()
+#define G_SCAN_STRING_UPPER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunction))
+#define G_IS_SCAN_STRING_UPPER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION))
+#define G_SCAN_STRING_UPPER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunctionClass))
+#define G_IS_SCAN_STRING_UPPER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_UPPER_FUNCTION))
+#define G_SCAN_STRING_UPPER_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunctionClass))
+
+
+/* Bascule d'une suite de caractères en majuscules (instance) */
+typedef GScanRegisteredItem GScanStringUpperFunction;
+
+/* Bascule d'une suite de caractères en majuscules (classe) */
+typedef GScanRegisteredItemClass GScanStringUpperFunctionClass;
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+GType g_scan_string_upper_function_get_type(void);
+
+/* Constitue une fonction de bascule de lettres en majuscules. */
+GScanRegisteredItem *g_scan_string_upper_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H */
diff --git a/src/analysis/scan/items/string/wide.c b/src/analysis/scan/items/string/wide.c
new file mode 100644
index 0000000..378f21c
--- /dev/null
+++ b/src/analysis/scan/items/string/wide.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * wide.c - bascule de texte ASCII en UTF-16
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "wide.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des bascules de texte ASCII en UTF-16. */
+static void g_scan_string_wide_function_class_init(GScanStringWideFunctionClass *);
+
+/* Initialise une instance de bascule de texte ASCII en UTF-16. */
+static void g_scan_string_wide_function_init(GScanStringWideFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_wide_function_dispose(GScanStringWideFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_wide_function_finalize(GScanStringWideFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_wide_function_get_name(const GScanStringWideFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_wide_function_run_call(GScanStringWideFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bascule de texte ASCII en UTF-16. */
+G_DEFINE_TYPE(GScanStringWideFunction, g_scan_string_wide_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bascules de texte ASCII en UTF-16. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_wide_function_class_init(GScanStringWideFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_wide_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_wide_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_string_wide_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_string_wide_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de bascule de texte ASCII en UTF-16. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_wide_function_init(GScanStringWideFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_wide_function_dispose(GScanStringWideFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_wide_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_wide_function_finalize(GScanStringWideFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_wide_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de bascule de texte ASCII en UTF-16. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_string_wide_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_WIDE_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_string_wide_function_get_name(const GScanStringWideFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("wide");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_string_wide_function_run_call(GScanStringWideFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ const sized_string_t *string; /* Description du chaîne */
+ sized_string_t new; /* Description transformée */
+ size_t i; /* Boucle de parcours */
+
+ /* Validation des arguments */
+
+ result = (count == 1);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_STRING);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (!result) goto exit;
+
+ /* Réalisation de l'opération attendue */
+
+ new.len = string->len * 2;
+ new.data = calloc(new.len, sizeof(bin_t));
+
+ for (i = 0; i < string->len; i++)
+ new.data[i * 2] = string->data[i];
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &new));
+
+ exit_szstr(&new);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/string/wide.h b/src/analysis/scan/items/string/wide.h
new file mode 100644
index 0000000..65195bd
--- /dev/null
+++ b/src/analysis/scan/items/string/wide.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * wide.h - prototypes pour la bascule de texte ASCII en UTF-16
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_STRING_WIDE_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_WIDE_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_WIDE_FUNCTION g_scan_string_wide_function_get_type()
+#define G_SCAN_STRING_WIDE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_WIDE_FUNCTION, GScanStringWideFunction))
+#define G_IS_SCAN_STRING_WIDE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_WIDE_FUNCTION))
+#define G_SCAN_STRING_WIDE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_WIDE_FUNCTION, GScanStringWideFunctionClass))
+#define G_IS_SCAN_STRING_WIDE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_WIDE_FUNCTION))
+#define G_SCAN_STRING_WIDE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_WIDE_FUNCTION, GScanStringWideFunctionClass))
+
+
+/* Bascule d'une suite de texte ASCII en UTF-16 (instance) */
+typedef GScanRegisteredItem GScanStringWideFunction;
+
+/* Bascule d'une suite de texte ASCII en UTF-16 (classe) */
+typedef GScanRegisteredItemClass GScanStringWideFunctionClass;
+
+
+/* Indique le type défini pour une bascule de texte ASCII en UTF-16. */
+GType g_scan_string_wide_function_get_type(void);
+
+/* Constitue une fonction de bascule de texte ASCII en UTF-16. */
+GScanRegisteredItem *g_scan_string_wide_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_STRING_WIDE_H */
diff --git a/src/analysis/scan/items/time/Makefile.am b/src/analysis/scan/items/time/Makefile.am
new file mode 100644
index 0000000..e5330be
--- /dev/null
+++ b/src/analysis/scan/items/time/Makefile.am
@@ -0,0 +1,14 @@
+
+noinst_LTLIBRARIES = libanalysisscanitemstime.la
+
+
+libanalysisscanitemstime_la_SOURCES = \
+ make.h make.c \
+ now.h now.c
+
+libanalysisscanitemstime_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemstime_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/time/make.c b/src/analysis/scan/items/time/make.c
new file mode 100644
index 0000000..e7330a3
--- /dev/null
+++ b/src/analysis/scan/items/time/make.c
@@ -0,0 +1,350 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * make.c - construction de volume de secondes à partir d'une date
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "make.h"
+
+
+#include <assert.h>
+#include <time.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des conversions de dates en secondes. */
+static void g_scan_time_make_function_class_init(GScanTimeMakeFunctionClass *);
+
+/* Initialise une instance de convertisseur de date en secondes. */
+static void g_scan_time_make_function_init(GScanTimeMakeFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_time_make_function_dispose(GScanTimeMakeFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_time_make_function_finalize(GScanTimeMakeFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_time_make_function_get_name(const GScanTimeMakeFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_time_make_function_run_call(GScanTimeMakeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conversion de date en nombre de secondes. */
+G_DEFINE_TYPE(GScanTimeMakeFunction, g_scan_time_make_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des conversions de dates en secondes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_make_function_class_init(GScanTimeMakeFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_time_make_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_time_make_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_time_make_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_time_make_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de convertisseur de date en secondes.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_make_function_init(GScanTimeMakeFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_make_function_dispose(GScanTimeMakeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_time_make_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_make_function_finalize(GScanTimeMakeFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_time_make_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de décompte du temps écoulé. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_time_make_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TIME_MAKE_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_time_make_function_get_name(const GScanTimeMakeFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("make");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_time_make_function_run_call(GScanTimeMakeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ bool status; /* Possibilité de construction */
+ size_t i; /* Boucle de parcours */
+ LiteralValueType vtype; /* Type de valeur portée */
+ struct tm date; /* Date à mettre en place */
+ unsigned long long value; /* Valeur entière à utiliser */
+ time_t computed; /* Nombre de secondes déterminé*/
+
+ /* Validation des arguments */
+
+ result = (count == 3 || count == 6);
+ if (!result) goto exit;
+
+ status = true;
+
+ for (i = 0; i < count && status; i++)
+ {
+ status = G_IS_SCAN_LITERAL_EXPRESSION(args[i]);
+ if (!status) break;
+
+ vtype = g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(args[i]));
+
+ status = (vtype == LVT_UNSIGNED_INTEGER);
+ if (!status) break;
+
+ }
+
+ if (!status) goto exit;
+
+ /* Lecture des arguments */
+
+ memset(&date, 0, sizeof(struct tm));
+
+ status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[0]), &value);
+ assert(status);
+ if (!status) goto exit;
+
+ if (value < 1900)
+ {
+ result = false;
+ goto exit;
+ }
+
+ date.tm_year = value - 1900;
+
+ status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[1]), &value);
+ assert(status);
+ if (!status) goto exit;
+
+ if (value > 12)
+ {
+ result = false;
+ goto exit;
+ }
+
+ date.tm_mon = value - 1;
+
+ status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[2]), &value);
+ assert(status);
+ if (!status) goto exit;
+
+ if (value < 1 || value > 31)
+ {
+ result = false;
+ goto exit;
+ }
+
+ date.tm_mday = value;
+
+ if (count == 6)
+ {
+ status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[3]), &value);
+ assert(status);
+ if (!status) goto exit;
+
+ if (value >= 24)
+ {
+ result = false;
+ goto exit;
+ }
+
+ date.tm_hour = value;
+
+ status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[4]), &value);
+ assert(status);
+ if (!status) goto exit;
+
+ if (value >= 60)
+ {
+ result = false;
+ goto exit;
+ }
+
+ date.tm_min = value;
+
+ status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[5]), &value);
+ assert(status);
+ if (!status) goto exit;
+
+ if (value >= 60)
+ {
+ result = false;
+ goto exit;
+ }
+
+ date.tm_sec = value;
+
+ }
+
+ /* Construction de la valeur finale */
+
+ computed = timegm(&date);
+
+ if (computed != (time_t)-1)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ computed }));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/time/make.h b/src/analysis/scan/items/time/make.h
new file mode 100644
index 0000000..f4be276
--- /dev/null
+++ b/src/analysis/scan/items/time/make.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * make.h - prototypes pour une construction de volume de secondes à partir d'une date
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_TIME_MAKE_H
+#define _ANALYSIS_SCAN_ITEMS_TIME_MAKE_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_TIME_MAKE_FUNCTION g_scan_time_make_function_get_type()
+#define G_SCAN_TIME_MAKE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TIME_MAKE_FUNCTION, GScanTimeMakeFunction))
+#define G_IS_SCAN_TIME_MAKE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TIME_MAKE_FUNCTION))
+#define G_SCAN_TIME_MAKE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TIME_MAKE_FUNCTION, GScanTimeMakeFunctionClass))
+#define G_IS_SCAN_TIME_MAKE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TIME_MAKE_FUNCTION))
+#define G_SCAN_TIME_MAKE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TIME_MAKE_FUNCTION, GScanTimeMakeFunctionClass))
+
+
+/* Convertisseur de date en nombre de secondes depuis le 01/01/1970 (instance) */
+typedef GScanRegisteredItem GScanTimeMakeFunction;
+
+/* Convertisseur de date en nombre de secondes depuis le 01/01/1970 (classe) */
+typedef GScanRegisteredItemClass GScanTimeMakeFunctionClass;
+
+
+/* Indique le type défini pour une conversion de date en nombre de secondes. */
+GType g_scan_time_make_function_get_type(void);
+
+/* Constitue une fonction de décompte du temps écoulé. */
+GScanRegisteredItem *g_scan_time_make_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_TIME_MAKE_H */
diff --git a/src/analysis/scan/items/time/now.c b/src/analysis/scan/items/time/now.c
new file mode 100644
index 0000000..7f8b627
--- /dev/null
+++ b/src/analysis/scan/items/time/now.c
@@ -0,0 +1,243 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * now.c - décompte du temps écoulé depuis Epoch
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "now.h"
+
+
+#include <time.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des décomptes de temps écoulé. */
+static void g_scan_time_now_function_class_init(GScanTimeNowFunctionClass *);
+
+/* Initialise une instance de décompte de temps écoulé. */
+static void g_scan_time_now_function_init(GScanTimeNowFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_time_now_function_dispose(GScanTimeNowFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_time_now_function_finalize(GScanTimeNowFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_time_now_function_get_name(const GScanTimeNowFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_time_now_function_run_call(GScanTimeNowFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un décompte de secondes écoulées depuis le 01/01/1970. */
+G_DEFINE_TYPE(GScanTimeNowFunction, g_scan_time_now_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des décomptes de temps écoulé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_now_function_class_init(GScanTimeNowFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_time_now_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_time_now_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_time_now_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_time_now_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de décompte de temps écoulé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_now_function_init(GScanTimeNowFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_now_function_dispose(GScanTimeNowFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_time_now_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_time_now_function_finalize(GScanTimeNowFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_time_now_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de décompte du temps écoulé. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_time_now_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TIME_NOW_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_time_now_function_get_name(const GScanTimeNowFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("now");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_time_now_function_run_call(GScanTimeNowFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ time_t now; /* Date relative courante */
+
+ result = (count == 0);
+ if (!result) goto exit;
+
+ now = time(NULL);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ now }));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/time/now.h b/src/analysis/scan/items/time/now.h
new file mode 100644
index 0000000..73ed52a
--- /dev/null
+++ b/src/analysis/scan/items/time/now.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * now.h - prototypes pour le décompte du temps écoulé depuis Epoch
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_TIME_NOW_H
+#define _ANALYSIS_SCAN_ITEMS_TIME_NOW_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_TIME_NOW_FUNCTION g_scan_time_now_function_get_type()
+#define G_SCAN_TIME_NOW_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TIME_NOW_FUNCTION, GScanTimeNowFunction))
+#define G_IS_SCAN_TIME_NOW_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TIME_NOW_FUNCTION))
+#define G_SCAN_TIME_NOW_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TIME_NOW_FUNCTION, GScanTimeNowFunctionClass))
+#define G_IS_SCAN_TIME_NOW_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TIME_NOW_FUNCTION))
+#define G_SCAN_TIME_NOW_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TIME_NOW_FUNCTION, GScanTimeNowFunctionClass))
+
+
+/* Décompte du nombre de seccondes écoulées depuis le 01/01/1970 (instance) */
+typedef GScanRegisteredItem GScanTimeNowFunction;
+
+/* Décompte du nombre de seccondes écoulées depuis le 01/01/1970 (classe) */
+typedef GScanRegisteredItemClass GScanTimeNowFunctionClass;
+
+
+/* Indique le type défini pour un décompte de secondes écoulées depuis le 01/01/1970. */
+GType g_scan_time_now_function_get_type(void);
+
+/* Constitue une fonction de décompte du temps écoulé. */
+GScanRegisteredItem *g_scan_time_now_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_TIME_NOW_H */
diff --git a/src/analysis/scan/items/uint-int.h b/src/analysis/scan/items/uint-int.h
new file mode 100644
index 0000000..49050e6
--- /dev/null
+++ b/src/analysis/scan/items/uint-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * uint-int.h - prototypes internes pour la lecture d'un mot à partir de données binaires
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_UINT_INT_H
+#define _ANALYSIS_SCAN_ITEMS_UINT_INT_H
+
+
+#include "uint.h"
+
+
+#include "../item-int.h"
+
+
+
+/* Fonction conduisant à la lecture d'un mot (instance) */
+struct _GScanUintFunction
+{
+ GScanRegisteredItem parent; /* A laisser en premier */
+
+ MemoryDataSize size; /* Taille du mot à lire */
+ SourceEndian endian; /* Boutisme à respecter */
+
+};
+
+/* Fonction conduisant à la lecture d'un mot (classe) */
+struct _GScanUintFunctionClass
+{
+ GScanRegisteredItemClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un nouvelle fonction de lecture d'entiers. */
+bool g_scan_uint_function_create(GScanUintFunction *, MemoryDataSize, SourceEndian);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_UINT_INT_H */
diff --git a/src/analysis/scan/items/uint.c b/src/analysis/scan/items/uint.c
new file mode 100644
index 0000000..8060aca
--- /dev/null
+++ b/src/analysis/scan/items/uint.c
@@ -0,0 +1,388 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * uint.c - lecture d'un mot à partir de données binaires
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "uint.h"
+
+
+#include <assert.h>
+
+
+#include "uint-int.h"
+#include "../exprs/literal.h"
+#include "../../../common/extstr.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des lectures de valeurs entières. */
+static void g_scan_uint_function_class_init(GScanUintFunctionClass *);
+
+/* Initialise une instance de lecture de valeur entière. */
+static void g_scan_uint_function_init(GScanUintFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_uint_function_dispose(GScanUintFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_uint_function_finalize(GScanUintFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_uint_function_get_name(const GScanUintFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_uint_function_run_call(GScanUintFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une lecture de mot à partir de données binaires. */
+G_DEFINE_TYPE(GScanUintFunction, g_scan_uint_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des lectures de valeurs entières. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_uint_function_class_init(GScanUintFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_uint_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_uint_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_uint_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_uint_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de lecture de valeur entière. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_uint_function_init(GScanUintFunction *func)
+{
+ func->size = MDS_UNDEFINED;
+ func->endian = SRE_LITTLE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_uint_function_dispose(GScanUintFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_uint_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_uint_function_finalize(GScanUintFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_uint_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : size = taille du mot à venir lire dans les données. *
+* *
+* Description : Constitue une fonction de lecture de valeur entière. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_uint_function_new(MemoryDataSize size, SourceEndian endian)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_UINT_FUNCTION, NULL);
+
+ if (!g_scan_uint_function_create(G_SCAN_UINT_FUNCTION(result), size, endian))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = encadrement d'un parcours de correspondances. *
+* size = taille du mot à venir lire dans les données. *
+* *
+* Description : Met en place un nouvelle fonction de lecture d'entiers. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_uint_function_create(GScanUintFunction *func, MemoryDataSize size, SourceEndian endian)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ func->size = size;
+ func->endian = endian;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_uint_function_get_name(const GScanUintFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ switch (item->size & ~MDS_SIGN)
+ {
+ case MDS_8_BITS_UNSIGNED:
+ result = strdup("int8");
+ break;
+
+ case MDS_16_BITS_UNSIGNED:
+ result = strdup("int16");
+ break;
+
+ case MDS_32_BITS_UNSIGNED:
+ result = strdup("int32");
+ break;
+
+ case MDS_64_BITS_UNSIGNED:
+ result = strdup("int64");
+ break;
+
+ default:
+ assert(false);
+ result = NULL;
+ break;
+
+ }
+
+ if (result)
+ {
+ if (!MDS_IS_SIGNED(item->size))
+ result = strprep(result, "u");
+
+ if (item->endian == SRE_BIG)
+ result = stradd(result, "be");
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_uint_function_run_call(GScanUintFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ unsigned long long offset; /* Position du mot ciblé */
+ GBinContent *content; /* Contenu à manipuler */
+ vmpa2t pos; /* Tête de lecture */
+ uint8_t val_s8; /* Valeur entière sur 8 bits */
+ uint8_t val_u8; /* Valeur entière sur 8 bits */
+ uint16_t val_s16; /* Valeur entière sur 16 bits */
+ uint16_t val_u16; /* Valeur entière sur 16 bits */
+ uint32_t val_s32; /* Valeur entière sur 32 bits */
+ uint32_t val_u32; /* Valeur entière sur 32 bits */
+ uint64_t val_s64; /* Valeur entière sur 64 bits */
+ uint64_t val_u64; /* Valeur entière sur 64 bits */
+
+ result = (count == 1 && G_IS_SCAN_LITERAL_EXPRESSION(args[0]));
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[0]), &offset);
+ if (!result) goto exit;
+
+ content = g_scan_context_get_content(ctx);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ advance_vmpa(&pos, offset);
+
+ switch (item->size)
+ {
+ case MDS_8_BITS_SIGNED:
+ result = g_binary_content_read_s8(content, &pos, &val_s8);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER,
+ (long long []){ val_s8 }));
+ break;
+
+ case MDS_8_BITS_UNSIGNED:
+ result = g_binary_content_read_u8(content, &pos, &val_u8);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+ (unsigned long long []){ val_u8 }));
+ break;
+
+ case MDS_16_BITS_SIGNED:
+ result = g_binary_content_read_s16(content, &pos, item->endian, &val_s16);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER,
+ (long long []){ val_s16 }));
+ break;
+
+ case MDS_16_BITS_UNSIGNED:
+ result = g_binary_content_read_u16(content, &pos, item->endian, &val_u16);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+ (unsigned long long []){ val_u16 }));
+ break;
+
+ case MDS_32_BITS_SIGNED:
+ result = g_binary_content_read_s32(content, &pos, item->endian, &val_s32);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER,
+ (long long []){ val_s32 }));
+ break;
+
+ case MDS_32_BITS_UNSIGNED:
+ result = g_binary_content_read_u32(content, &pos, item->endian, &val_u32);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+ (unsigned long long []){ val_u32 }));
+ break;
+
+ case MDS_64_BITS_SIGNED:
+ result = g_binary_content_read_s64(content, &pos, item->endian, &val_s64);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER,
+ (long long []){ val_s64 }));
+ break;
+
+ case MDS_64_BITS_UNSIGNED:
+ result = g_binary_content_read_u64(content, &pos, item->endian, &val_u64);
+ if (result)
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+ (unsigned long long []){ val_u64 }));
+ break;
+
+ default:
+ break;
+
+ }
+
+ g_object_unref(G_OBJECT(content));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/uint.h b/src/analysis/scan/items/uint.h
new file mode 100644
index 0000000..d3dd3cb
--- /dev/null
+++ b/src/analysis/scan/items/uint.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * uint.h - prototypes pour la lecture d'un mot à partir de données binaires
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_UINT_H
+#define _ANALYSIS_SCAN_ITEMS_UINT_H
+
+
+#include <glib-object.h>
+
+
+#include "../item.h"
+#include "../../../arch/archbase.h"
+
+
+
+#define G_TYPE_SCAN_UINT_FUNCTION g_scan_uint_function_get_type()
+#define G_SCAN_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_UINT_FUNCTION, GScanUintFunction))
+#define G_IS_SCAN_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_UINT_FUNCTION))
+#define G_SCAN_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_UINT_FUNCTION, GScanUintFunctionClass))
+#define G_IS_SCAN_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_UINT_FUNCTION))
+#define G_SCAN_UINT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_UINT_FUNCTION, GScanUintFunctionClass))
+
+
+/* Fonction conduisant à la lecture d'un mot (instance) */
+typedef struct _GScanUintFunction GScanUintFunction;
+
+/* Fonction conduisant à la lecture d'un mot (classe) */
+typedef struct _GScanUintFunctionClass GScanUintFunctionClass;
+
+
+/* Indique le type défini pour une lecture de mot à partir de données binaires. */
+GType g_scan_uint_function_get_type(void);
+
+/* Constitue une fonction de lecture de valeur entière. */
+GScanRegisteredItem *g_scan_uint_function_new(MemoryDataSize, SourceEndian);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_UINT_H */
diff --git a/src/analysis/scan/matches-int.h b/src/analysis/scan/matches-int.h
new file mode 100644
index 0000000..4e6a244
--- /dev/null
+++ b/src/analysis/scan/matches-int.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * matches-int.h - prototypes internes pour la sauvegarde de correspondances de motif identifiées
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_INT_H
+#define _ANALYSIS_SCAN_MATCHES_INT_H
+
+
+#include "matches.h"
+
+
+
+/* Dénombre les correspondances enregistrées pour un motif. */
+typedef size_t (* count_scan_matches_fc) (const GScanMatches *);
+
+/* Affiche une série de correspondances au format texte. */
+typedef void (* output_scan_matches_to_text_fc) (const GScanMatches *, int);
+
+/* Affiche une série de correspondances au format JSON. */
+typedef void (* output_scan_matches_to_json_fc) (const GScanMatches *, const sized_string_t *, unsigned int, int);
+
+
+/* Correspondances trouvées avec un motif (instance) */
+struct _GScanMatches
+{
+ GObject parent; /* A laisser en premier */
+
+ /**
+ * L'aspect constant des instances marque seulement le fait que les
+ * pointeurs sont partagés avec un contexte, qui est le réel propriétaire
+ * de ces instances.
+ */
+ const GScanContext *context; /* Contexte de rattachement */
+ const GSearchPattern *source; /* Motif d'origine recherché */
+
+};
+
+/* Correspondances trouvées avec un motif (classe) */
+struct _GScanMatchesClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ count_scan_matches_fc count; /* Décompte des correspondances*/
+
+ output_scan_matches_to_text_fc to_text; /* Impression au format texte */
+ output_scan_matches_to_json_fc to_json; /* Impression au format JSON */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_MATCHES_INT_H */
diff --git a/src/analysis/scan/matches.c b/src/analysis/scan/matches.c
new file mode 100644
index 0000000..1290c90
--- /dev/null
+++ b/src/analysis/scan/matches.c
@@ -0,0 +1,319 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * matches.c - sauvegarde de correspondances de motif identifiées
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "matches.h"
+
+
+#include "matches-int.h"
+
+
+
+/* Initialise la classe des séries de correspondances de motifs. */
+static void g_scan_matches_class_init(GScanMatchesClass *);
+
+/* Initialise une instance de série de correspondances trouvées. */
+static void g_scan_matches_init(GScanMatches *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_matches_dispose(GScanMatches *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_matches_finalize(GScanMatches *);
+
+
+
+/* Indique le type défini pour une série de correspondances identifiées. */
+G_DEFINE_TYPE(GScanMatches, g_scan_matches, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des séries de correspondances de motifs.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_matches_class_init(GScanMatchesClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_matches_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_matches_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = instance à initialiser. *
+* *
+* Description : Initialise une instance de série de correspondances trouvées.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_matches_init(GScanMatches *matches)
+{
+ matches->context = NULL;
+ matches->source = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_matches_dispose(GScanMatches *matches)
+{
+ /**
+ * Contexte et source sont des instances partagées. Leur propriété n'est
+ * donc pas à modifier avec un appel à g_clear_object() ici.
+ */
+
+ G_OBJECT_CLASS(g_scan_matches_parent_class)->dispose(G_OBJECT(matches));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_matches_finalize(GScanMatches *matches)
+{
+ G_OBJECT_CLASS(g_scan_matches_parent_class)->finalize(G_OBJECT(matches));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = instance dont l'initialisation est à compléter. *
+* context = contexte associé au scan courant. *
+* source = lien vers le motif recherché d'origine. *
+* *
+* Description : Associe des éléments de contexte à des correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : Aucun transfert de propriété n'a lieu ici ! *
+* *
+******************************************************************************/
+
+void g_scan_matches_attach(GScanMatches *matches, const GScanContext *context, const GSearchPattern *source)
+{
+ matches->context = context;
+ matches->source = source;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = informations de correspondances à consulter. *
+* *
+* Description : Fournit le contexte du scan associé aux correspondances. *
+* *
+* Retour : Contexte de scan courant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanContext *g_scan_bytes_matches_get_context(const GScanMatches *matches)
+{
+ GScanContext *result; /* Instance à retourner */
+
+ result = (GScanContext *)matches->context;
+
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondance à consulter. *
+* *
+* Description : Indique la source du motif d'origine recherché. *
+* *
+* Retour : Motif à l'origine des correspondances. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GSearchPattern *g_scan_matches_get_source(const GScanMatches *matches)
+{
+ GSearchPattern *result; /* Source à retourner */
+
+ result = (GSearchPattern *)matches->source;
+
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondances à consulter. *
+* *
+* Description : Dénombre les correspondances enregistrées pour un motif. *
+* *
+* Retour : Quantité de correspondances établies. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_scan_matches_count(const GScanMatches *matches)
+{
+ size_t result; /* Quantité à retourner */
+ GScanMatchesClass *class; /* Classe à activer */
+
+ class = G_SCAN_MATCHES_GET_CLASS(matches);
+
+ result = class->count(matches);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondance à manipuler. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche une série de correspondances au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_matches_output_to_text(const GScanMatches *matches, int fd)
+{
+ GScanMatchesClass *class; /* Classe à activer */
+
+ class = G_SCAN_MATCHES_GET_CLASS(matches);
+
+ class->to_text(matches, fd);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondance à manipuler. *
+* *
+* Description : Convertit une série de correspondances en texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_matches_convert_as_text(const GScanMatches *matches)
+{
+ /* TODO */
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondance à manipuler. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche une série de correspondances au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_matches_output_to_json(const GScanMatches *matches, const sized_string_t *padding, unsigned int level, int fd)
+{
+ GScanMatchesClass *class; /* Classe à activer */
+
+ class = G_SCAN_MATCHES_GET_CLASS(matches);
+
+ class->to_json(matches, padding, level + 1, fd);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondance à manipuler. *
+* *
+* Description : Convertit une série de correspondances en JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_matches_convert_as_json(const GScanMatches *matches)
+{
+ /* TODO */
+
+}
diff --git a/src/analysis/scan/matches.h b/src/analysis/scan/matches.h
new file mode 100644
index 0000000..26e54ed
--- /dev/null
+++ b/src/analysis/scan/matches.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * matches.h - prototypes pour la sauvegarde de correspondances de motif identifiées
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_H
+#define _ANALYSIS_SCAN_MATCHES_H
+
+
+#include <glib-object.h>
+
+
+#include "pattern.h"
+#include "../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_MATCHES g_scan_matches_get_type()
+#define G_SCAN_MATCHES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATCHES, GScanMatches))
+#define G_IS_SCAN_MATCHES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATCHES))
+#define G_SCAN_MATCHES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATCHES, GScanMatchesClass))
+#define G_IS_SCAN_MATCHES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATCHES))
+#define G_SCAN_MATCHES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATCHES, GScanMatchesClass))
+
+
+/* Correspondances trouvées avec un motif (instance) */
+typedef struct _GScanMatches GScanMatches;
+
+/* Correspondances trouvées avec un motif (classe) */
+typedef struct _GScanMatchesClass GScanMatchesClass;
+
+
+/* Indique le type défini pour une série de correspondances identifiées. */
+GType g_scan_matches_get_type(void);
+
+/* Associe des éléments de contexte à des correspondances. */
+void g_scan_matches_attach(GScanMatches *, const GScanContext *, const GSearchPattern *);
+
+/* Fournit le contexte du scan associé aux correspondances. */
+GScanContext *g_scan_bytes_matches_get_context(const GScanMatches *);
+
+/* Indique la source du motif d'origine recherché. */
+GSearchPattern *g_scan_matches_get_source(const GScanMatches *);
+
+/* Dénombre les correspondances enregistrées pour un motif. */
+size_t g_scan_matches_count(const GScanMatches *);
+
+/* Affiche une série de correspondances au format texte. */
+void g_scan_matches_output_to_text(const GScanMatches *, int);
+
+/* Convertit une série de correspondances en texte. */
+void g_scan_matches_convert_as_text(const GScanMatches *);
+
+/* Affiche une série de correspondances au format JSON. */
+void g_scan_matches_output_to_json(const GScanMatches *, const sized_string_t *, unsigned int, int);
+
+/* Convertit une série de correspondances en JSON. */
+void g_scan_matches_convert_as_json(const GScanMatches *);
+
+
+
+#endif /* _ANALYSIS_SCAN_MATCHES_H */
diff --git a/src/analysis/scan/matches/Makefile.am b/src/analysis/scan/matches/Makefile.am
new file mode 100644
index 0000000..f1a69c3
--- /dev/null
+++ b/src/analysis/scan/matches/Makefile.am
@@ -0,0 +1,15 @@
+
+noinst_LTLIBRARIES = libanalysisscanmatches.la
+
+
+libanalysisscanmatches_la_SOURCES = \
+ area.h area.c \
+ bytes-int.h \
+ bytes.h bytes.c
+
+libanalysisscanmatches_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanmatches_la_SOURCES:%c=)
diff --git a/src/analysis/scan/matches/area.c b/src/analysis/scan/matches/area.c
new file mode 100644
index 0000000..3f512b0
--- /dev/null
+++ b/src/analysis/scan/matches/area.c
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * area.c - conservation des localisations de correspondances
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "area.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : a = première zone de correspondance à comparer. *
+* b = seconde zone de correspondance à comparer. *
+* *
+* Description : Etablit une comparaison entre deux zones de correspondance. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int compare_match_area_as_dl_item(const dl_list_item *a, const dl_list_item *b)
+{
+ int result; /* Bilan à retourner */
+ match_area_t *area_a; /* Première zone à traiter */
+ match_area_t *area_b; /* Seconde zone à traiter */
+
+ area_a = match_area_from_item(a);
+ area_b = match_area_from_item(b);
+
+ result = sort_uint64_t(area_a->start, area_b->start);
+
+ if (result == 0)
+ result = sort_uint64_t(area_a->end, area_b->end);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/matches/area.h b/src/analysis/scan/matches/area.h
new file mode 100644
index 0000000..b059b35
--- /dev/null
+++ b/src/analysis/scan/matches/area.h
@@ -0,0 +1,85 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * area.h - prototypes pour la conservation des localisations de correspondances
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_AREA_H
+#define _ANALYSIS_SCAN_MATCHES_AREA_H
+
+
+#include <assert.h>
+
+
+#include "../../../arch/vmpa.h"
+#include "../../../common/dllist.h"
+
+
+
+/* Couverture d'une correspondance */
+typedef struct _match_area_t
+{
+ phys_t start; /* Point de départ */
+ phys_t end; /* Point d'arrivée (exclus) */
+
+ DL_LIST_ITEM(link); /* Lien vers les maillons */
+
+ size_t mod_path_index; /* Indice de construction */
+ bool has_mod_path; /* Validité du champ précédent */
+
+} match_area_t;
+
+
+#define match_area_from_item(item) \
+ (match_area_t *)container_of(item, match_area_t, link)
+
+#define add_tail_match_area(new, head) \
+ dl_list_add_tail(new, head, match_area_t, link)
+
+#define del_match_area(item, head) \
+ dl_list_del(item, head, match_area_t, link)
+
+#define for_each_match_area(pos, head) \
+ dl_list_for_each(pos, head, match_area_t, link)
+
+#define for_each_match_area_safe(pos, head, next) \
+ dl_list_for_each_safe(pos, head, next, match_area_t, link)
+
+#define is_last_match_area(item, head) \
+ dl_list_is_last(item, head, link)
+
+#define merge_match_areas(head1, head2) \
+ dl_list_merge(head1, head2, match_area_t, link)
+
+#define sort_match_areas_no_dup(head, len, cmp, dup) \
+ ({ \
+ assert(!dl_list_empty(*(head))); \
+ dl_list_item *hmbr = &(*head)->link; \
+ sort_dl_list_no_dup(&hmbr, len, cmp, dup); \
+ match_area_from_item(hmbr); \
+ })
+
+
+/* Etablit une comparaison entre deux zones de correspondance. */
+int compare_match_area_as_dl_item(const dl_list_item *, const dl_list_item *);
+
+
+
+#endif /* _ANALYSIS_SCAN_MATCHES_AREA_H */
diff --git a/src/analysis/scan/matches/bytes-int.h b/src/analysis/scan/matches/bytes-int.h
new file mode 100644
index 0000000..f6239e3
--- /dev/null
+++ b/src/analysis/scan/matches/bytes-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bytes-int.h - prototypes internes pour la sauvegarde de correspondances avec des suites d'octets identifiées
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_BYTES_INT_H
+#define _ANALYSIS_SCAN_MATCHES_BYTES_INT_H
+
+
+#include "bytes.h"
+
+
+#include "../matches-int.h"
+
+
+
+/* Correspondances trouvées avec des suite d'octets (instance) */
+struct _GScanBytesMatches
+{
+ GScanMatches parent; /* A laisser en premier */
+
+ match_area_t *areas; /* Zones couvertes */
+ size_t count; /* Nombre de zones */
+
+};
+
+/* Correspondances trouvées avec des suite d'octets (classe) */
+struct _GScanBytesMatchesClass
+{
+ GScanMatchesClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_MATCHES_BYTES_INT_H */
diff --git a/src/analysis/scan/matches/bytes.c b/src/analysis/scan/matches/bytes.c
new file mode 100644
index 0000000..a23188b
--- /dev/null
+++ b/src/analysis/scan/matches/bytes.c
@@ -0,0 +1,712 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bytes.h - sauvegarde d'une correspondance identifiée de suite d'octets
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "bytes.h"
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+
+
+#include "bytes-int.h"
+#include "../patterns/token.h"
+#include "../../../common/cpp.h"
+#include "../../../core/logs.h"
+
+
+
+/* -------------------- CONSERVATION DE CORRESPONDANCES ETABLIES -------------------- */
+
+
+/* Initialise la classe des séries de correspondances d'octets. */
+static void g_scan_bytes_matches_class_init(GScanBytesMatchesClass *);
+
+/* Initialise une instance de série de correspondances trouvées. */
+static void g_scan_bytes_matches_init(GScanBytesMatches *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_bytes_matches_dispose(GScanBytesMatches *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_bytes_matches_finalize(GScanBytesMatches *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Dénombre les correspondances enregistrées pour un motif. */
+static size_t g_scan_bytes_matches_count(const GScanBytesMatches *);
+
+/* Affiche une correspondance au format texte. */
+static void g_scan_bytes_matches_output_to_text(const GScanBytesMatches *, int);
+
+/* Affiche une correspondance au format JSON. */
+static void g_scan_bytes_matches_output_to_json(const GScanBytesMatches *, const sized_string_t *, unsigned int, int);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION DE CORRESPONDANCES ETABLIES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série de correspondances d'octets identifiées. */
+G_DEFINE_TYPE(GScanBytesMatches, g_scan_bytes_matches, G_TYPE_SCAN_MATCHES);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des séries de correspondances d'octets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_bytes_matches_class_init(GScanBytesMatchesClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanMatchesClass *matches; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_bytes_matches_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_bytes_matches_finalize;
+
+ matches = G_SCAN_MATCHES_CLASS(klass);
+
+ matches->count = (count_scan_matches_fc)g_scan_bytes_matches_count;
+
+ matches->to_text = (output_scan_matches_to_text_fc)g_scan_bytes_matches_output_to_text;
+ matches->to_json = (output_scan_matches_to_json_fc)g_scan_bytes_matches_output_to_json;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = instance à initialiser. *
+* *
+* Description : Initialise une instance de série de correspondances trouvées.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_bytes_matches_init(GScanBytesMatches *matches)
+{
+ matches->areas = NULL;
+ matches->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_bytes_matches_dispose(GScanBytesMatches *matches)
+{
+ G_OBJECT_CLASS(g_scan_bytes_matches_parent_class)->dispose(G_OBJECT(matches));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_bytes_matches_finalize(GScanBytesMatches *matches)
+{
+ G_OBJECT_CLASS(g_scan_bytes_matches_parent_class)->finalize(G_OBJECT(matches));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un suivi pour série de correspondances avec des octets. *
+* *
+* Retour : Correspondance mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanMatches *g_scan_bytes_matches_new(void)
+{
+ GScanMatches *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_BYTES_MATCHES, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à manipuler. *
+* list = correspondances établies à mémoriser. *
+* count = taille de cette liste. *
+* *
+* Description : Intègre une liste de correspondances vérifiées. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_bytes_matches_set_list(GScanBytesMatches *matches, match_area_t *list, size_t count)
+{
+ matches->areas = list;
+
+ matches->count = count;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à consulter. *
+* index = indice de la correspondance recherchée. *
+* *
+* Description : Fournit les informations relatives à une correspondance. *
+* *
+* Retour : Propritétés de la correspondance visée ou NULL pour un échec.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const match_area_t *g_scan_bytes_matches_get(const GScanBytesMatches *matches, size_t index)
+{
+ const match_area_t *result; /* Pointeur à retourner */
+
+ for_each_match_area(result, matches->areas)
+ {
+ if (index == 0)
+ break;
+ }
+
+ assert(index == 0);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = informations de correspondance à consulter. *
+* index = indice de la correspondance visée. *
+* start = position de départ d'un motif détecté. [OUT] *
+* end = position d'arrivée d'un motif détecté. [OUT] *
+* *
+* Description : Indique la localisation d'une correspondance établie. *
+* *
+* Retour : Taille mesurée de la correspondance. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+phys_t g_scan_bytes_matches_get_location(const GScanBytesMatches *matches, size_t index, phys_t *start, phys_t *end)
+{
+ phys_t result; /* Taille à retourner */
+
+ result = 0;
+
+ /*
+ result = match->len;
+
+ *start = match->start;
+ *end = match->start + result;
+ */
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = informations de correspondance à consulter. *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison gagnante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_bytes_matches_get_modifier_path(const GScanBytesMatches *matches)
+{
+ char *result; /* Combinaison à retourner */
+ GBytesToken *pattern; /* Autre version du motif */
+
+ result = NULL;
+
+ /*
+
+ if (match->has_mod_path)
+ {
+ pattern = G_BYTES_TOKEN(G_SCAN_MATCH(match)->source);
+ result = g_bytes_token_get_modifier_path(pattern, match->mod_path_index);
+ }
+
+ else
+ result = NULL;
+ */
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à consulter. *
+* *
+* Description : Dénombre les correspondances enregistrées pour un motif. *
+* *
+* Retour : Quantité de correspondances établies. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static size_t g_scan_bytes_matches_count(const GScanBytesMatches *matches)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = matches->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondance à manipuler. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche une correspondance au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_bytes_matches_output_to_text(const GScanBytesMatches *matches, int fd)
+{
+ GScanMatches *base; /* Lien vers les infos de base */
+ GBinContent *content; /* Contenu binaire analysé */
+ const char *name; /* Désignation du motif ciblé */
+ match_area_t *iter; /* Boucle de parcours #1 */
+ char value[2 + ULLONG_MAXLEN]; /* Impression de la position */
+ int ret; /* Bilan d'une conversion */
+ vmpa2t pos; /* Tête de lecture */
+ phys_t len; /* Taille d'une correspondance */
+ const bin_t *data; /* Accès aux données brutes */
+ phys_t k; /* Boucle de parcours #2 */
+
+ base = G_SCAN_MATCHES(matches);
+
+ content = g_scan_context_get_content(base->context);
+
+ name = g_search_pattern_get_name(base->source);
+
+ for_each_match_area(iter, matches->areas)
+ {
+ /* Position dans le binaire (hexadécimal) */
+
+ ret = snprintf(value, ULLONG_MAXLEN, "0x%llx", (unsigned long long)iter->start);
+
+ if (ret > 0)
+ write(fd, value, ret);
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!");
+ write(fd, "\"<error>\"", 9);
+ }
+
+ write(fd, ":", 1);
+
+ /* Affichage de la désignation */
+
+ write(fd, "$", 1);
+
+ /**
+ * Les fonctionnalités Yara d'origine autorisent les variables anonymes '$'.
+ *
+ * Cette absence de nom est supportée ici.
+ */
+
+ if (name != NULL)
+ write(fd, name, strlen(name));
+
+ write(fd, ": ", 2);
+
+ /* Affichage du contenu */
+
+ init_vmpa(&pos, iter->start, VMPA_NO_VIRTUAL);
+
+ len = iter->end - iter->start;
+
+ data = g_binary_content_get_raw_access(content, &pos, len);
+ assert(data != NULL);
+
+ for (k = 0; k < len; k++)
+ {
+ if (isprint(data[k]))
+ write(fd, &data[k], 1);
+
+ else
+ {
+ write(fd, "\\x", 2);
+
+ ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]);
+
+ if (ret > 0)
+ {
+ assert(ret == 2);
+ write(fd, value, ret);
+ }
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+ write(fd, "??", 2);
+ }
+
+ }
+
+ }
+
+ write(fd, "\n", 1);
+
+ }
+
+ g_object_unref(G_OBJECT(content));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = définition de correspondance à manipuler. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche une correspondance au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_bytes_matches_output_to_json(const GScanBytesMatches *matches, const sized_string_t *padding, unsigned int level, int fd)
+{
+ unsigned int i; /* Boucle de parcours #1 */
+ char value[4 + ULLONG_MAXLEN]; /* Impression de la position */
+ int ret; /* Bilan d'une conversion */
+ GScanMatches *base; /* Lien vers les infos de base */
+ GBinContent *content; /* Contenu binaire analysé */
+ match_area_t *iter; /* Boucle de parcours #1 */
+ vmpa2t pos; /* Tête de lecture */
+ phys_t len; /* Taille d'une correspondance */
+ const bin_t *data; /* Accès aux données brutes */
+ phys_t k; /* Boucle de parcours #2 */
+
+ /* Nombre de correspondances */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"match_count\": ", 15);
+
+ ret = snprintf(value, ULLONG_MAXLEN, "%zu", matches->count);
+
+ if (ret > 0)
+ write(fd, value, ret);
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting value!");
+ write(fd, "null", 4);
+ }
+
+ write(fd, ",\n", 2);
+
+ /* Détail des correspondances */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"matches\": [\n", 13);
+
+ base = G_SCAN_MATCHES(matches);
+
+ content = g_scan_context_get_content(base->context);
+
+ for_each_match_area(iter, matches->areas)
+ {
+ /* Marqueur de début */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "{\n", 2);
+
+ /* Position dans le binaire (décimal) */
+
+ for (i = 0; i < (level + 2); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"offset\": ", 10);
+
+ ret = snprintf(value, ULLONG_MAXLEN, "%llu", (unsigned long long)iter->start);
+
+ if (ret > 0)
+ write(fd, value, ret);
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting offset!");
+ write(fd, "null", 4);
+ }
+
+ write(fd, ",\n", 2);
+
+ /* Position dans le binaire (hexadécimal) */
+
+ for (i = 0; i < (level + 2); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"offset_hex\": ", 14);
+
+ ret = snprintf(value, ULLONG_MAXLEN, "\"0x%llx\"", (unsigned long long)iter->start);
+
+ if (ret > 0)
+ write(fd, value, ret);
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!");
+ write(fd, "null", 4);
+ }
+
+ write(fd, ",\n", 2);
+
+ /* Affichage du contenu brut */
+
+ for (i = 0; i < (level + 2); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"content\": \"", 12);
+
+ init_vmpa(&pos, iter->start, VMPA_NO_VIRTUAL);
+
+ len = iter->end - iter->start;
+
+ data = g_binary_content_get_raw_access(content, &pos, len);
+ assert(data != NULL);
+
+ for (k = 0; k < len; k++)
+ {
+ if (data[k] == '\\')
+ write(fd, "\\\\", 2);
+
+ else if (isprint(data[k]))
+ write(fd, &data[k], 1);
+
+ else
+ {
+ write(fd, "\\u", 2);
+
+ /**
+ * Cf. https://datatracker.ietf.org/doc/html/rfc8259#section-7
+ */
+ ret = snprintf(value, ULLONG_MAXLEN, "%04hhx", data[k]);
+
+ if (ret > 0)
+ {
+ assert(ret == 4);
+ write(fd, value, ret);
+ }
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+ write(fd, "??", 2);
+ }
+
+ }
+
+ }
+
+ write(fd, "\",\n", 3);
+
+ /* Affichage du contenu en version humainement lisible */
+
+ for (i = 0; i < (level + 2); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"content_str\": \"", 16);
+
+ init_vmpa(&pos, iter->start, VMPA_NO_VIRTUAL);
+
+ data = g_binary_content_get_raw_access(content, &pos, len);
+ assert(data != NULL);
+
+ for (k = 0; k < len; k++)
+ {
+ if (data[k] == '\\')
+ write(fd, "\\\\", 2);
+
+ else if (isprint(data[k]))
+ write(fd, &data[k], 1);
+
+ else
+ {
+ write(fd, "\\\\x", 3);
+
+ ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]);
+
+ if (ret > 0)
+ {
+ assert(ret == 2);
+ write(fd, value, ret);
+ }
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+ write(fd, "??", 2);
+ }
+
+ }
+
+ }
+
+ write(fd, "\",\n", 3);
+
+ /* Affichage du contenu brut */
+
+ for (i = 0; i < (level + 2); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"length\": ", 10);
+
+ ret = snprintf(value, ULLONG_MAXLEN, "%llu", (unsigned long long)len);
+
+ if (ret > 0)
+ write(fd, value, ret);
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+ write(fd, "-1", 2);
+ }
+
+ write(fd, ",\n", 2);
+
+ /* Affichage du contenu brut (hexadécimal) */
+
+ for (i = 0; i < (level + 2); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"length_hex\": ", 14);
+
+ ret = snprintf(value, ULLONG_MAXLEN, "\"0x%llx\"", (unsigned long long)len);
+
+ if (ret > 0)
+ write(fd, value, ret);
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+ write(fd, "\"0xffffffffffffffff\"", 20);
+ }
+
+ write(fd, "\n", 1);
+
+ /* Marqueur de fin */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ if (is_last_match_area(iter, matches->areas))
+ write(fd, "}\n", 2);
+ else
+ write(fd, "},\n", 3);
+
+ }
+
+ g_object_unref(G_OBJECT(content));
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "]\n", 2);
+
+}
diff --git a/src/analysis/scan/matches/bytes.h b/src/analysis/scan/matches/bytes.h
new file mode 100644
index 0000000..90d6062
--- /dev/null
+++ b/src/analysis/scan/matches/bytes.h
@@ -0,0 +1,75 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bytes.h - prototypes pour la sauvegarde de correspondances avec des suites d'octets identifiées
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_BYTES_H
+#define _ANALYSIS_SCAN_MATCHES_BYTES_H
+
+
+#include <glib-object.h>
+
+
+#include "area.h"
+#include "../context.h"
+#include "../matches.h"
+
+
+
+/* -------------------- CONSERVATION DE CORRESPONDANCES ETABLIES -------------------- */
+
+
+#define G_TYPE_SCAN_BYTES_MATCHES g_scan_bytes_matches_get_type()
+#define G_SCAN_BYTES_MATCHES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_BYTES_MATCHES, GScanBytesMatches))
+#define G_IS_SCAN_BYTES_MATCHES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_BYTES_MATCHES))
+#define G_SCAN_BYTES_MATCHES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_BYTES_MATCHES, GScanBytesMatchesClass))
+#define G_IS_SCAN_BYTES_MATCHES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_BYTES_MATCHES))
+#define G_SCAN_BYTES_MATCHES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_BYTES_MATCHES, GScanBytesMatchesClass))
+
+
+/* Correspondances trouvées avec des suite d'octets (instance) */
+typedef struct _GScanBytesMatches GScanBytesMatches;
+
+/* Correspondances trouvées avec des suite d'octets (classe) */
+typedef struct _GScanBytesMatchesClass GScanBytesMatchesClass;
+
+
+/* Indique le type défini pour une série de correspondances d'octets identifiées. */
+GType g_scan_bytes_matches_get_type(void);
+
+/* Crée un suivi pour série de correspondances avec des octets. */
+GScanMatches *g_scan_bytes_matches_new(void);
+
+/* Intègre une liste de correspondances vérifiées. */
+void g_scan_bytes_matches_set_list(GScanBytesMatches *, match_area_t *, size_t);
+
+/* Fournit les informations relatives à une correspondance. */
+const match_area_t *g_scan_bytes_matches_get(const GScanBytesMatches *, size_t);
+
+/* Indique la localisation d'une correspondance établie. */
+phys_t g_scan_bytes_matches_get_location(const GScanBytesMatches *, size_t, phys_t *, phys_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_scan_bytes_matches_get_modifier_path(const GScanBytesMatches *);
+
+
+
+#endif /* _ANALYSIS_SCAN_MATCHES_BYTES_H */
diff --git a/src/analysis/scan/matches/pending.c b/src/analysis/scan/matches/pending.c
new file mode 100644
index 0000000..c653257
--- /dev/null
+++ b/src/analysis/scan/matches/pending.c
@@ -0,0 +1,677 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pending.c - consolidation de correspondances partielles
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "pending.h"
+
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "../../../common/sort.h"
+
+
+
+
+
+/* ------------------------- MEMORISATION D'UNE ZONE BORNEE ------------------------- */
+
+
+/* Compare deux couvertures bornées de correspondances. */
+static int compare_match_area(const match_area_t *, const match_area_t *);
+
+
+
+/* -------------------- CONSERVATION DE CORRESPONDANCES ETABLIES -------------------- */
+
+
+#define PENDING_ALLOC_SIZE 10
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MEMORISATION D'UNE ZONE BORNEE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : allocator = allocateur dédié à l'ensemble de zones. *
+* start = point de départ d'une nouvelle correspondance. *
+* length = taille de la zone couverte. *
+* *
+* Description : Crée une nouvelle structure de suivi de correspondance. *
+* *
+* Retour : Structure initialisée mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static match_area_t *create_match_area(GUMemCache *allocator, phys_t start, phys_t length)
+{
+ match_area_t *result; /* Zone à retourner */
+
+ result = g_umem_cache_alloc(allocator);
+
+ DL_LIST_ITEM_INIT(&result->link);
+
+ result->start = start;
+ result->end = start + length;
+
+ assert(matches->content_start <= result->start);
+ assert(result->end <= matches->content_end);
+
+ result->ttl = 1;
+
+ result->has_mod_path = false;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : allocator = allocateur dédié à l'ensemble de zones. *
+* start = point de départ d'une nouvelle correspondance. *
+* length = taille de la zone couverte. *
+* index = indice de construction pour le motif concerné. *
+* *
+* Description : Crée une nouvelle structure de suivi de correspondance. *
+* *
+* Retour : Structure initialisée mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static match_area_t *create_match_area_with_path(GUMemCache *allocator, phys_t start, phys_t length, size_t index)
+{
+ match_area_t *result; /* Zone à retourner */
+
+ result = g_umem_cache_alloc(allocator);
+
+ DL_LIST_ITEM_INIT(&result->link);
+
+ result->start = start;
+ result->end = start + length;
+
+ assert(matches->content_start <= result->start);
+ assert(result->end <= matches->content_end);
+
+ result->ttl = 1;
+
+ result->mod_path_index = index;
+ result->has_mod_path = true;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : area = zone de suivi à supprimer. *
+* allocator = allocateur dédié à l'ensemble de zones. *
+* *
+* Description : Supprime une structure de suivi de correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void delete_match_area(match_area_t *area, GUMemCache *allocator)
+{
+ // TODO : assert(alone)
+
+ g_umem_cache_free(allocator, area);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = pointeur vers la première zone à analyser. *
+* b = pointeur vers la seconde zone à analyser. *
+* *
+* Description : Compare deux couvertures bornées de correspondances. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_match_area(const match_area_t *a, const match_area_t *b)
+{
+ int result; /* Bilan à renvoyer */
+
+ result = sort_unsigned_long_long(a->start, b->start);
+
+ if (result == 0)
+ result = sort_unsigned_long_long(a->end, b->end);
+
+ if (result == 0)
+ result = sort_unsigned_long_long(a->ttl, b->ttl);
+
+ if (result == 0)
+ result = sort_unsigned_long_long(a->has_mod_path, b->has_mod_path);
+
+ if (result == 0)
+ result = sort_unsigned_long_long(a->mod_path_index, b->mod_path_index);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION DE CORRESPONDANCES ETABLIES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à initialiser. *
+* start = première position du contenu (souvent 0). *
+* end = position de fin du contenu. *
+* *
+* Description : Initialise une structure de consolidation de correspondances.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void init_pending_matches(pending_matches_t *matches, const phys_t *start, const phys_t *end)
+{
+ matches->content_start = *start;
+ matches->content_end = *end;
+
+ matches->allocator = NULL;
+ matches->areas = NULL;
+ matches->allocated = 0;
+ matches->used = 0;
+
+ matches->initialized = false;
+
+ matches->abort = false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de correspondances à initialiser. [OUT] *
+* src = suivi de correspondances à copier. *
+* *
+* Description : Copie une structure de consolidation de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void copy_pending_matches(pending_matches_t *dest, const pending_matches_t *src)
+{
+ dest->content_start = src->content_start;
+ dest->content_end = src->content_end;
+
+ dest->areas = malloc(src->used * sizeof(match_area_t));
+ dest->allocated = src->used;
+ dest->used = src->used;
+
+ memcpy(dest->areas, src->areas, src->used * sizeof(match_area_t));
+
+ dest->initialized = src->initialized;
+
+ dest->abort = src->abort;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de correspondances à initialiser. [OUT] *
+* src = suivi de correspondances à copier. *
+* *
+* Description : Fusionne une structure de consolidation avec une autre. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void merge_pending_matches(pending_matches_t *dest, const pending_matches_t *src)
+{
+ if ((dest->used + src->used) > dest->allocated)
+ {
+ dest->allocated += src->used;
+
+ dest->areas = realloc(dest->areas, dest->allocated * sizeof(match_area_t));
+
+ }
+
+ memcpy(&dest->areas[dest->used], src->areas, src->used * sizeof(match_area_t));
+
+ dest->used += src->used;
+
+ dest->initialized |= src->initialized;
+
+ dest->abort |= src->abort;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à purger. *
+* *
+* Description : Libère la mémoire utilisée par une consolidation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void exit_pending_matches(pending_matches_t *matches)
+{
+ if (matches->areas != NULL)
+ free(matches->areas);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à consulter. *
+* *
+* Description : Dénombre les correspondances établies jusque là. *
+* *
+* Retour : Quantité de correspondances complètes jusqu'à présent. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t count_pending_matches(const pending_matches_t *matches)
+{
+ size_t result; /* Quantité à renvoyer */
+
+ result = matches->used;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à consulter. *
+* count = nombre de correspondances en attente. [OUT] *
+* *
+* Description : Fournit la liste des correspondances établies à présent. *
+* *
+* Retour : Liste de correspondances en lecture seule. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+match_area_t * const *get_all_pending_matches(const pending_matches_t *matches, size_t *count)
+{
+ match_area_t * const *result; /* Série à renvoyer */
+
+ result = &matches->areas;
+
+ *count = matches->used;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à compléter. *
+* start = point de départ d'une nouvelle correspondance. *
+* length = taille de la zone couverte. *
+* *
+* Description : Ajoute au suivi la définition d'une nouvelle correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
+{
+ match_area_t *area; /* Nouvelle zone à intégrer */
+
+ area = create_match_area(matches->allocator, start, length);
+
+ dl_list_add_tail(area, &matches->areas, match_area_t, link);
+ matches->used++;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à compléter. *
+* start = point de départ d'une nouvelle correspondance. *
+* length = taille de la zone couverte. *
+* index = indice de construction pour le motif concerné. *
+* *
+* Description : Ajoute au suivi la définition d'une nouvelle correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void add_pending_match_with_path(pending_matches_t *matches, phys_t start, phys_t length, size_t index)
+{
+ match_area_t *area; /* Nouvelle zone à intégrer */
+
+ area = create_match_area_with_path(matches->allocator, start, length, index);
+
+ dl_list_add_tail(area, &matches->areas, match_area_t, link);
+ matches->used++;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à compléter. *
+* target = indice de la zone de correspondance concernée. *
+* start = nouvelle position initiale de la zone couverte. *
+* *
+* Description : Etend une zone couverte dans le suivi des correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void extend_pending_match_beginning(pending_matches_t *matches, size_t target, phys_t start)
+{
+ match_area_t *area; /* Zone à actualiser */
+
+ assert(target < matches->used);
+
+ area = &matches->areas[target];
+
+ if (area->ttl == 0)
+ {
+ assert(matches->content_start <= start);
+
+ area->start = start;
+
+ area->ttl = 1;
+
+ }
+ else
+ {
+ assert(area->ttl == 1);
+
+ add_pending_match(matches, start, area->end - start);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à compléter. *
+* target = indice de la zone de correspondance concernée. *
+* length = taille de la zone couverte supplémentaire. *
+* *
+* Description : Etend une zone couverte dans le suivi des correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void extend_pending_match_ending(pending_matches_t *matches, size_t target, phys_t end)
+{
+ match_area_t *area; /* Zone à actualiser */
+
+ assert(target < matches->used);
+
+ area = &matches->areas[target];
+
+ if (area->ttl == 0)
+ {
+ assert(end <= matches->content_end);
+
+ area->end = end;
+
+ area->ttl = 1;
+
+ }
+ else
+ {
+ assert(area->ttl == 1);
+
+ add_pending_match(matches, area->start, end - area->start);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à modifier. *
+* *
+* Description : Réinitialisation à 0 tous les TTL de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void reset_pending_matches_ttl(pending_matches_t *matches)
+{
+ size_t i; /* Boucle de parcours */
+
+ assert(matches->initialized);
+
+ for (i = 0; i < matches->used; i++)
+ matches->areas[i].ttl = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à modifier. *
+* *
+* Description : Retire toutes les correspondances sans issue pour l'analyse. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void purge_pending_matches(pending_matches_t *matches)
+{
+ match_area_t *del_start; /* Départ d'une zone morte */
+ match_area_t *del_end; /* Fin d'une zone morte */
+ size_t del_remaining; /* Nombre de valides ensuite */
+ size_t del_count; /* Nombre d'éléments à effacer */
+ size_t i; /* Boucle de parcours */
+
+ assert(matches->initialized);
+
+ /**
+ * Note : le code original était le suivant :
+ *
+
+ * for (i = matches->used; i > 0; i--)
+ * if (matches->areas[i - 1].ttl == 0)
+ * {
+ * memmove(&matches->areas[i - 1], &matches->areas[i], (matches->used - i) * sizeof(match_area_t));
+ * matches->used--;
+ * }
+ *
+ * Pour éviter les appels à memmove(), un déplacement par blocs est désormais visée.
+ */
+
+ del_start = NULL;
+ del_end = NULL;
+ del_count = 0;
+ del_remaining = 0;
+
+ /* Suppression en bloc si possible */
+
+ for (i = matches->used; i > 0; i--)
+ {
+ if (matches->areas[i - 1].ttl == 0)
+ {
+ del_start = &matches->areas[i - 1];
+
+ if (del_end == NULL)
+ {
+ del_end = del_start;
+ del_remaining = matches->used - i;
+ }
+
+ del_count++;
+
+ }
+ else
+ {
+ if (del_start != NULL)
+ {
+ assert(&matches->areas[i] == del_start);
+
+ if (del_remaining > 0)
+ memmove(del_start, del_end + 1, del_remaining * sizeof(match_area_t));
+
+ assert(matches->used > del_count);
+ matches->used -= del_count;
+
+ del_start = NULL;
+ del_end = NULL;
+ del_count = 0;
+ del_remaining = 0;
+
+ }
+
+ }
+
+ }
+
+ /* Dernier traitement au besoin */
+
+ if (del_start != NULL)
+ {
+ assert(&matches->areas[0] == del_start);
+
+ if (del_remaining > 0)
+ memmove(del_start, del_end + 1, del_remaining * sizeof(match_area_t));
+
+ assert(matches->used >= del_count);
+ matches->used -= del_count;
+
+ }
+
+ /* Bilan */
+
+ matches->abort = (matches->used == 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à finaliser. *
+* *
+* Description : Trie les correspondances et retire tous les doublons. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void sort_and_filter_pending_matches(pending_matches_t *matches)
+{
+ match_area_t *last; /* Dernière zone conservée */
+ size_t i; /* Boucle de parcours */
+ match_area_t *cur; /* Zone courante dans l'analyse*/
+
+ if (matches->used > 0)
+ {
+ qsort(matches->areas, matches->used, sizeof(match_area_t), (__compar_fn_t)compare_match_area);
+
+ last = &matches->areas[0];
+
+ for (i = 1; i < matches->used; i++)
+ {
+ cur = &matches->areas[i];
+
+ if (last->start != cur->start || last->end != cur->end)
+ {
+ if ((cur - last) > 1)
+ {
+ memmove(last + 1, cur, (matches->used - i) * sizeof(match_area_t));
+ matches->used -= (cur - last + 1);
+ }
+
+ last = cur;
+
+ }
+
+ }
+
+ cur = &matches->areas[matches->used - 1];
+
+ if (last != cur)
+ matches->used = last - matches->areas + 1;
+
+ }
+
+}
diff --git a/src/analysis/scan/matches/pending.h b/src/analysis/scan/matches/pending.h
new file mode 100644
index 0000000..e430ca1
--- /dev/null
+++ b/src/analysis/scan/matches/pending.h
@@ -0,0 +1,129 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pending.h - prototypes pour la consolidation de correspondances partielles
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#if 0 //ndef _ANALYSIS_SCAN_MATCHES_PENDING_H
+#define _ANALYSIS_SCAN_MATCHES_PENDING_H
+
+
+#include <assert.h>
+#include <stdbool.h>
+
+
+#include "../../content.h"
+#include "../../../common/dllist.h"
+
+
+
+// TODO : move vers ByteMatch
+typedef int GUMemCache;
+
+
+
+/* Couverture d'une correspondance */
+typedef struct _match_area_t
+{
+ DL_LIST_ITEM(link); /* Lien vers les maillons */
+
+ phys_t start; /* Point de départ */
+ phys_t end; /* Point d'arrivée (exclus) */
+
+ unsigned long ttl; /* Durée de vie pour analyse */
+
+ size_t mod_path_index; /* Indice de construction */
+ bool has_mod_path; /* Validité du champ précédent */
+
+} match_area_t;
+
+/* Suivi de correspondances */
+typedef struct _pending_matches_t
+{
+ phys_t content_start; /* Point de début du contenu */
+ phys_t content_end; /* Point de fin du contenu */
+
+ GUMemCache *allocator; /* Allocateur pour zones */
+ match_area_t *areas; /* Zones couvertes */
+ size_t allocated; /* Nombre d'allocations */
+ size_t used; /* Nombre de zones */
+
+ bool initialized; /* Etat du suivi */
+
+ bool abort; /* Inutilité d'une poursuite */
+
+} pending_matches_t;
+
+
+/* Initialise une structure de consolidation de correspondances. */
+void init_pending_matches(pending_matches_t *, const phys_t *, const phys_t *);
+
+/* Copie une structure de consolidation de correspondances. */
+void copy_pending_matches(pending_matches_t *, const pending_matches_t *);
+
+/* Fusionner une structure de consolidation avec une autre. */
+void merge_pending_matches(pending_matches_t *, const pending_matches_t *);
+
+/* Libère la mémoire utilisée par une consolidation. */
+void exit_pending_matches(pending_matches_t *);
+
+// TODO ajouter un assert(used == 0) si !initialized */
+#define are_pending_matches_initialized(pm) pm->initialized
+
+#define set_pending_matches_initialized(pm) pm->initialized = true
+
+/* Dénombre les correspondances établies jusque là. */
+size_t count_pending_matches(const pending_matches_t *);
+
+/* Fournit la liste des correspondances établies à présent. */
+match_area_t * const *get_all_pending_matches(const pending_matches_t *, size_t *);
+
+/* Ajoute au suivi la définition d'une nouvelle correspondance. */
+void add_pending_match(pending_matches_t *, phys_t, phys_t);
+
+/* Ajoute au suivi la définition d'une nouvelle correspondance. */
+void add_pending_match_with_path(pending_matches_t *, phys_t, phys_t, size_t);
+
+/* Etend une zone couverte dans le suivi des correspondances. */
+void extend_pending_match_beginning(pending_matches_t *, size_t, phys_t);
+
+/* Etend une zone couverte dans le suivi des correspondances. */
+void extend_pending_match_ending(pending_matches_t *, size_t, phys_t);
+
+/* Réinitialisation à 0 tous les TTL de correspondances. */
+void reset_pending_matches_ttl(pending_matches_t *);
+
+#define keep_pending_match(p) \
+ do \
+ { \
+ assert(p->ttl == 0); \
+ p->ttl = 1; \
+ } \
+ while (0);
+
+/* Retire toutes les correspondances sans issue pour l'analyse. */
+void purge_pending_matches(pending_matches_t *);
+
+/* Trie les correspondances et retire tous les doublons. */
+void sort_and_filter_pending_matches(pending_matches_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_MATCHES_PENDING_H */
diff --git a/src/analysis/scan/options-int.h b/src/analysis/scan/options-int.h
new file mode 100644
index 0000000..975fb6c
--- /dev/null
+++ b/src/analysis/scan/options-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * options-int.h - prototypes internes pour le rassemblement des options d'analyse communiquées par le donneur d'ordre
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_OPTIONS_INT_H
+#define _ANALYSIS_SCAN_OPTIONS_INT_H
+
+
+#include "options.h"
+
+
+
+/* Rassemblement d'options d'analyses (instance) */
+struct _GScanOptions
+{
+ GObject parent; /* A laisser en premier */
+
+ GType data_backend; /* Choix du moteur d'analyse */
+
+ bool check_only; /* Qu'une validation syntaxique*/
+
+ bool print_json; /* Sortie au format json ? */
+ bool print_strings; /* Affichage de correspondances*/
+ bool print_stats; /* Affichage de statistiques ? */
+ bool print_tags; /* Affichage des étiquttes ? */
+
+ char **selected_tags; /* Etiquettes sélectionnées */
+ size_t selected_count; /* Nombre de ces étiquettes */
+
+};
+
+/* Rassemblement d'options d'analyses (classe) */
+struct _GScanOptionsClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_OPTIONS_INT_H */
diff --git a/src/analysis/scan/options.c b/src/analysis/scan/options.c
new file mode 100644
index 0000000..ecff9f1
--- /dev/null
+++ b/src/analysis/scan/options.c
@@ -0,0 +1,490 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * options.c - rassemblement des options d'analyse communiquées par le donneur d'ordre
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "options.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "options-int.h"
+
+
+
+/* Initialise la classe des ensembles d'options d'analyses. */
+static void g_scan_options_class_init(GScanOptionsClass *);
+
+/* Initialise une instance de groupe d'options d'analyse. */
+static void g_scan_options_init(GScanOptions *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_options_dispose(GScanOptions *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_options_finalize(GScanOptions *);
+
+
+
+/* Indique le type défini pour un ensemble d'options d'analyses. */
+G_DEFINE_TYPE(GScanOptions, g_scan_options, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des ensembles d'options d'analyses. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_options_class_init(GScanOptionsClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_options_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_options_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = instance à initialiser. *
+* *
+* Description : Initialise une instance de groupe d'options d'analyse. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_options_init(GScanOptions *options)
+{
+ options->data_backend = G_TYPE_INVALID;
+
+ options->check_only = false;
+
+ options->print_json = false;
+ options->print_strings = false;
+ options->print_stats = false;
+
+ options->selected_tags = NULL;
+ options->selected_count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_options_dispose(GScanOptions *options)
+{
+ G_OBJECT_CLASS(g_scan_options_parent_class)->dispose(G_OBJECT(options));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_options_finalize(GScanOptions *options)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < options->selected_count; i++)
+ free(options->selected_tags[i]);
+
+ if (options->selected_tags != NULL)
+ free(options->selected_tags);
+
+ G_OBJECT_CLASS(g_scan_options_parent_class)->finalize(G_OBJECT(options));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un réceptacle pour diverses options d'analyse. *
+* *
+* Retour : Point de collecte mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanOptions *g_scan_options_new(void)
+{
+ GScanOptions *result; /* Instance à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_OPTIONS, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à consulter. *
+* *
+* Description : Indique le type d'un moteur d'analyse de données sélectionné.*
+* *
+* Retour : Type d'objet, idéalement valide. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GType g_scan_options_get_backend_for_data(const GScanOptions *options)
+{
+ GType result; /* Type à retourner */
+
+ result = options->data_backend;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à modifier. *
+* backend = type du moteur sélectionné. *
+* *
+* Description : Sélectionne un type de moteur d'analyse pour données brutes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_options_set_backend_for_data(GScanOptions *options, GType backend)
+{
+ options->data_backend = backend;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à consulter. *
+* *
+* Description : Indique un besoin limité à une validation syntaxique. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_options_get_check_only(const GScanOptions *options)
+{
+ bool result; /* Statut à retourner */
+
+ result = options->check_only;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à modifier. *
+* state = état de l'option visée à conserver. *
+* *
+* Description : Mémorise un besoin de validation syntaxique uniquement. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_options_set_check_only(GScanOptions *options, bool state)
+{
+ options->check_only = state;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à consulter. *
+* *
+* Description : Impose le format JSON comme type de sortie. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_options_get_print_json(const GScanOptions *options)
+{
+ bool result; /* Statut à retourner */
+
+ result = options->print_json;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à modifier. *
+* state = état de l'option visée à conserver. *
+* *
+* Description : Mémorise le format JSON comme type de sortie. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_options_set_print_json(GScanOptions *options, bool state)
+{
+ options->print_json = state;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à consulter. *
+* *
+* Description : Indique un besoin d'affichage des correspondances finales. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_options_get_print_strings(const GScanOptions *options)
+{
+ bool result; /* Statut à retourner */
+
+ result = options->print_strings;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à modifier. *
+* state = état de l'option visée à conserver. *
+* *
+* Description : Mémorise un besoin d'affichage des correspondances finales. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_options_set_print_strings(GScanOptions *options, bool state)
+{
+ options->print_strings = state;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à consulter. *
+* *
+* Description : Indique un besoin de statistiques en fin de compilation. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_options_get_print_stats(const GScanOptions *options)
+{
+ bool result; /* Statut à retourner */
+
+ result = options->print_stats;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à modifier. *
+* state = état de l'option visée à conserver. *
+* *
+* Description : Mémorise un besoin de statistiques en fin de compilation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_options_set_print_stats(GScanOptions *options, bool state)
+{
+ options->print_stats = state;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à consulter. *
+* *
+* Description : Indique un besoin d'affichage des étiquettes avec résultats. *
+* *
+* Retour : Etat de l'option visée à conservé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_options_get_print_tags(const GScanOptions *options)
+{
+ bool result; /* Statut à retourner */
+
+ result = options->print_tags;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à modifier. *
+* state = état de l'option visée à conserver. *
+* *
+* Description : Mémorise un besoin d'affichage des étiquettes avec résultats.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_options_set_print_tags(GScanOptions *options, bool state)
+{
+ options->print_tags = state;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à compléter. *
+* tag = étiquette de règle à sélectionner. *
+* *
+* Description : Inscrit une étiquette comme sélection de règles à afficher. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_options_select_tag(GScanOptions *options, const char *tag)
+{
+ options->selected_tags = realloc(options->selected_tags, ++options->selected_count * sizeof(char *));
+
+ options->selected_tags[options->selected_count - 1] = strdup(tag);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : options = ensemble d'options d'analyses à compléter. *
+* tag = étiquette de règle à auditionner. *
+* *
+* Description : Détermine si une étiquette donnée conduit à un affichage. *
+* *
+* Retour : true si une règle portant l'étiquette doit être affichée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_options_has_tag_as_selected(const GScanOptions *options, const char *tag)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ if (tag == NULL)
+ result = (options->selected_count == 0);
+
+ else
+ {
+ result = false;
+
+ for (i = 0; i < options->selected_count; i++)
+ if (strcmp(options->selected_tags[i], tag) == 0)
+ {
+ result = true;
+ break;
+ }
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/options.h b/src/analysis/scan/options.h
new file mode 100644
index 0000000..059c57e
--- /dev/null
+++ b/src/analysis/scan/options.h
@@ -0,0 +1,98 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * options.h - prototypes pour le rassemblement des options d'analyse communiquées par le donneur d'ordre
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_OPTIONS_H
+#define _ANALYSIS_SCAN_OPTIONS_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+
+#define G_TYPE_SCAN_OPTIONS g_scan_options_get_type()
+#define G_SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_OPTIONS, GScanOptions))
+#define G_IS_SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_OPTIONS))
+#define G_SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_OPTIONS, GScanOptionsClass))
+#define G_IS_SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_OPTIONS))
+#define G_SCAN_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_OPTIONS, GScanOptionsClass))
+
+
+/* Rassemblement d'options d'analyses (instance) */
+typedef struct _GScanOptions GScanOptions;
+
+/* Rassemblement d'options d'analyses (classe) */
+typedef struct _GScanOptionsClass GScanOptionsClass;
+
+
+/* Indique le type défini pour un ensemble d'options d'analyses. */
+GType g_scan_options_get_type(void);
+
+/* Crée un réceptacle pour diverses options d'analyse. */
+GScanOptions *g_scan_options_new(void);
+
+/* Indique le type d'un moteur d'analyse de données sélectionné. */
+GType g_scan_options_get_backend_for_data(const GScanOptions *);
+
+/* Sélectionne un type de moteur d'analyse pour données brutes. */
+void g_scan_options_set_backend_for_data(GScanOptions *, GType);
+
+/* Indique un besoin limité à une validation syntaxique. */
+bool g_scan_options_get_check_only(const GScanOptions *);
+
+/* Mémorise un besoin de validation syntaxique uniquement. */
+void g_scan_options_set_check_only(GScanOptions *, bool);
+
+/* Impose le format JSON comme type de sortie. */
+bool g_scan_options_get_print_json(const GScanOptions *);
+
+/* Mémorise le format JSON comme type de sortie. */
+void g_scan_options_set_print_json(GScanOptions *, bool);
+
+/* Indique un besoin d'affichage des correspondances finales. */
+bool g_scan_options_get_print_strings(const GScanOptions *);
+
+/* Mémorise un besoin d'affichage des correspondances finales. */
+void g_scan_options_set_print_strings(GScanOptions *, bool);
+
+/* Indique un besoin de statistiques en fin de compilation. */
+bool g_scan_options_get_print_stats(const GScanOptions *);
+
+/* Mémorise un besoin de statistiques en fin de compilation. */
+void g_scan_options_set_print_stats(GScanOptions *, bool);
+
+/* Indique un besoin d'affichage des étiquettes avec résultats. */
+bool g_scan_options_get_print_tags(const GScanOptions *);
+
+/* Mémorise un besoin d'affichage des étiquettes avec résultats. */
+void g_scan_options_set_print_tags(GScanOptions *, bool);
+
+/* Inscrit une étiquette comme sélection de règles à afficher. */
+void g_scan_options_select_tag(GScanOptions *, const char *);
+
+/* Détermine si une étiquette donnée conduit à un affichage. */
+bool g_scan_options_has_tag_as_selected(const GScanOptions *, const char *);
+
+
+
+#endif /* _ANALYSIS_SCAN_OPTIONS_H */
diff --git a/src/analysis/scan/pattern-int.h b/src/analysis/scan/pattern-int.h
new file mode 100644
index 0000000..b510c75
--- /dev/null
+++ b/src/analysis/scan/pattern-int.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pattern-int.h - prototypes internes pour la définition de motif à rechercher
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERN_INT_H
+#define _ANALYSIS_SCAN_PATTERN_INT_H
+
+
+#include "pattern.h"
+
+
+#include "context.h"
+
+
+
+/* Affiche un motif de recherche au format texte. */
+typedef void (* output_pattern_to_text_fc) (const GSearchPattern *, GScanContext *, int);
+
+/* Affiche un motif de recherche au format JSON. */
+typedef void (* output_pattern_to_json_fc) (const GSearchPattern *, GScanContext *, const sized_string_t *, unsigned int, int);
+
+
+/* Motif à rechercher au sein d'un contenu (instance) */
+struct _GSearchPattern
+{
+ GObject parent; /* A laisser en premier */
+
+ char *name; /* Eventuelle désignation */
+
+};
+
+/* Motif à rechercher au sein d'un contenu (classe) */
+struct _GSearchPatternClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ output_pattern_to_text_fc to_text; /* Impression au format texte */
+ output_pattern_to_json_fc to_json; /* Impression au format JSON */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERN_INT_H */
diff --git a/src/analysis/scan/pattern.c b/src/analysis/scan/pattern.c
new file mode 100644
index 0000000..dc4418c
--- /dev/null
+++ b/src/analysis/scan/pattern.c
@@ -0,0 +1,425 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pattern.c - définition de motif à localiser dans du contenu binaire
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "pattern.h"
+
+
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+
+#include "pattern-int.h"
+#include "../../core/logs.h"
+
+
+
+/* Initialise la classe des motifs à localiser dans du binaire. */
+static void g_search_pattern_class_init(GSearchPatternClass *);
+
+/* Initialise une instance de motif à localiser dans du binaire. */
+static void g_search_pattern_init(GSearchPattern *);
+
+/* Supprime toutes les références externes. */
+static void g_search_pattern_dispose(GSearchPattern *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_search_pattern_finalize(GSearchPattern *);
+
+
+
+/* Indique le type défini pour un motif à localiser. */
+G_DEFINE_TYPE(GSearchPattern, g_search_pattern, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des motifs à localiser dans du binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_search_pattern_class_init(GSearchPatternClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_search_pattern_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_search_pattern_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = instance à initialiser. *
+* *
+* Description : Initialise une instance de motif à localiser dans du binaire.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_search_pattern_init(GSearchPattern *pattern)
+{
+ pattern->name = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_search_pattern_dispose(GSearchPattern *pattern)
+{
+ G_OBJECT_CLASS(g_search_pattern_parent_class)->dispose(G_OBJECT(pattern));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_search_pattern_finalize(GSearchPattern *pattern)
+{
+ if (pattern->name != NULL)
+ free(pattern->name);
+
+ G_OBJECT_CLASS(g_search_pattern_parent_class)->finalize(G_OBJECT(pattern));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à consulter. *
+* *
+* Description : Fournit la désignation attribuée à un motif de recherche. *
+* *
+* Retour : Eventuelle étiquette associée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_search_pattern_get_name(const GSearchPattern *pattern)
+{
+ char *result; /* Désignation à retourner */
+
+ result = pattern->name;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à consulter. *
+* name = désignation en tant que variable locale. *
+* len = taille de cette désignation. *
+* *
+* Description : Inscrit la désignation attribuée à un motif de recherche. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_search_pattern_set_name(GSearchPattern *pattern, const char *name, size_t len)
+{
+ if (pattern->name != NULL)
+ free(pattern->name);
+
+ if (name == NULL)
+ pattern->name = NULL;
+ else
+ pattern->name = strndup(name, len);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un motif de recherche au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_search_pattern_output_to_text(const GSearchPattern *pattern, GScanContext *context, int fd)
+{
+ GSearchPatternClass *class; /* Classe à activer */
+
+ class = G_SEARCH_PATTERN_GET_CLASS(pattern);
+
+ class->to_text(pattern, context, fd);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit un motif de recherche en texte. *
+* *
+* Retour : Données textuelles ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_search_pattern_convert_as_text(const GSearchPattern *pattern, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-pattern2text-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ g_search_pattern_output_to_text(pattern, context, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* tail = décline la pose d'une virgule finale ? *
+* *
+* Description : Affiche un motif de recherche au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_search_pattern_output_to_json(const GSearchPattern *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd, bool tail)
+{
+ unsigned int i; /* Boucle de parcours */
+ GSearchPatternClass *class; /* Classe à activer */
+
+ /* Introduction */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "{\n", 2);
+
+ /* Désignation du motif */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"name\": \"$", 10);
+
+ write(fd, pattern->name, strlen(pattern->name));
+
+ write(fd, "\",\n", 3);
+
+ /* Affichage du contenu */
+
+ class = G_SEARCH_PATTERN_GET_CLASS(pattern);
+
+ class->to_json(pattern, context, padding, level, fd);
+
+ /* Conclusion */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ if (tail)
+ write(fd, "}\n", 2);
+ else
+ write(fd, "},\n", 3);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit un motif de recherche en JSON. *
+* *
+* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_search_pattern_convert_as_json(const GSearchPattern *pattern, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-pattern2json-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ padding.data = " ";
+ padding.len = 3;
+
+ g_search_pattern_output_to_json(pattern, context, &padding, 0, fd, false);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/pattern.h b/src/analysis/scan/pattern.h
new file mode 100644
index 0000000..72f87e4
--- /dev/null
+++ b/src/analysis/scan/pattern.h
@@ -0,0 +1,79 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pattern.h - prototypes pour la définition de motif à localiser dans du contenu binaire
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERN_H
+#define _ANALYSIS_SCAN_PATTERN_H
+
+
+#include <glib-object.h>
+
+
+#include "../../arch/archbase.h"
+#include "../../arch/vmpa.h"
+#include "../../common/szstr.h"
+
+
+
+/* Depuis context.h: contexte de suivi d'une analyse en cours (instance) */
+typedef struct _GScanContext GScanContext;
+;
+
+#define G_TYPE_SEARCH_PATTERN g_search_pattern_get_type()
+#define G_SEARCH_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SEARCH_PATTERN, GSearchPattern))
+#define G_IS_SEARCH_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SEARCH_PATTERN))
+#define G_SEARCH_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SEARCH_PATTERN, GSearchPatternClass))
+#define G_IS_SEARCH_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SEARCH_PATTERN))
+#define G_SEARCH_PATTERN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SEARCH_PATTERN, GSearchPatternClass))
+
+
+/* Motif à rechercher au sein d'un contenu (instance) */
+typedef struct _GSearchPattern GSearchPattern;
+
+/* Motif à rechercher au sein d'un contenu (classe) */
+typedef struct _GSearchPatternClass GSearchPatternClass;
+
+
+/* Indique le type défini pour un motif à localiser. */
+GType g_search_pattern_get_type(void);
+
+/* Fournit la désignation attribuée à un motif de recherche. */
+const char *g_search_pattern_get_name(const GSearchPattern *);
+
+/* Inscrit la désignation attribuée à un motif de recherche. */
+void g_search_pattern_set_name(GSearchPattern *, const char *, size_t);
+
+/* Affiche un motif de recherche au format texte. */
+void g_search_pattern_output_to_text(const GSearchPattern *, GScanContext *, int);
+
+/* Convertit un motif de recherche en texte. */
+char *g_search_pattern_convert_as_text(const GSearchPattern *, GScanContext *);
+
+/* Affiche un motif de recherche au format JSON. */
+void g_search_pattern_output_to_json(const GSearchPattern *, GScanContext *, const sized_string_t *, unsigned int, int, bool);
+
+/* Convertit un motif de recherche en JSON. */
+char *g_search_pattern_convert_as_json(const GSearchPattern *, GScanContext *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERN_H */
diff --git a/src/analysis/scan/patterns/Makefile.am b/src/analysis/scan/patterns/Makefile.am
new file mode 100644
index 0000000..989a562
--- /dev/null
+++ b/src/analysis/scan/patterns/Makefile.am
@@ -0,0 +1,30 @@
+
+noinst_LTLIBRARIES = libanalysisscanpatterns.la
+
+
+libanalysisscanpatterns_la_SOURCES = \
+ backend-int.h \
+ backend.h backend.c \
+ customizer-int.h \
+ customizer.h customizer.c \
+ modarg.h \
+ modifier-int.h \
+ modifier.h modifier.c \
+ patid.h \
+ token-int.h \
+ token.h token.c
+
+libanalysisscanpatterns_la_LIBADD = \
+ backends/libanalysisscanpatternsbackends.la \
+ modifiers/libanalysisscanpatternsmodifiers.la \
+ tokens/libanalysisscanpatternstokens.la
+
+libanalysisscanpatterns_la_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanpatterns_la_SOURCES:%c=)
+
+
+SUBDIRS = backends modifiers tokens
diff --git a/src/analysis/scan/patterns/backend-int.h b/src/analysis/scan/patterns/backend-int.h
new file mode 100644
index 0000000..aeabe1b
--- /dev/null
+++ b/src/analysis/scan/patterns/backend-int.h
@@ -0,0 +1,78 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend-int.h - prototypes internes pour une méthode de recherches au sein d'un contenu binaire
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKEND_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKEND_INT_H
+
+
+#include "backend.h"
+
+
+
+/* Indique la taille maximale des suites d'octets recherchées. */
+typedef size_t (* get_backend_atom_max_size_fc) (const GEngineBackend *);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+typedef patid_t (* enroll_plain_into_backend_fc) (GEngineBackend *, const uint8_t *, size_t, uint32_t [2]);
+
+/* Met en ordre les derniers détails avant un premier scan. */
+typedef bool (* warm_up_backend_fc) (GEngineBackend *);
+
+/* Récupère les identifiants finaux pour un motif recherché. */
+typedef patid_t (* build_backend_plain_pattern_id_fc) (const GEngineBackend *, const uint32_t [2]);
+
+/* Détermine le nombre d'identifiants constitués. */
+typedef size_t (* count_backend_plain_pattern_ids_fc) (const GEngineBackend *);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+typedef void (* run_backend_scan_fc) (const GEngineBackend *, GScanContext *);
+
+/* Imprime quelques faits quant aux éléments mis en place. */
+typedef void (* output_backend_stats_fc) (const GEngineBackend *);
+
+
+/* Méthode de traitement d'un contenu binaire pour recherches (instance) */
+struct _GEngineBackend
+{
+ GObject parent; /* A laisser en premier */
+
+};
+
+/* Méthode de traitement d'un contenu binaire pour recherches (classe) */
+struct _GEngineBackendClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ get_backend_atom_max_size_fc get_max_size; /* Taille maximale d'atome */
+ enroll_plain_into_backend_fc enroll_plain; /* Inscription simpl e */
+ warm_up_backend_fc warm_up; /* Préchauffage avant analyse */
+ build_backend_plain_pattern_id_fc build_id; /* Définition d'identifiant*/
+ count_backend_plain_pattern_ids_fc count_ids; /* Décompte des id. */
+ run_backend_scan_fc run_scan; /* Lancement d'une analyse */
+ output_backend_stats_fc output; /* Impression de statistiques */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKEND_INT_H */
diff --git a/src/analysis/scan/patterns/backend.c b/src/analysis/scan/patterns/backend.c
new file mode 100644
index 0000000..a887600
--- /dev/null
+++ b/src/analysis/scan/patterns/backend.c
@@ -0,0 +1,311 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend.c - méthode de recherches au sein d'un contenu binaire
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "backend.h"
+
+
+#include "backend-int.h"
+
+
+
+/* Initialise la classe des méthodes de recherche pour binaire. */
+static void g_engine_backend_class_init(GEngineBackendClass *);
+
+/* Initialise une instance de méthode de recherche pour binaire. */
+static void g_engine_backend_init(GEngineBackend *);
+
+/* Supprime toutes les références externes. */
+static void g_engine_backend_dispose(GEngineBackend *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_engine_backend_finalize(GEngineBackend *);
+
+
+
+/* Indique le type défini pour une méthode de recherche dans du binaire. */
+G_DEFINE_TYPE(GEngineBackend, g_engine_backend, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des méthodes de recherche pour binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_engine_backend_class_init(GEngineBackendClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_engine_backend_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_engine_backend_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance à initialiser. *
+* *
+* Description : Initialise une instance de méthode de recherche pour binaire.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_engine_backend_init(GEngineBackend *backend)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_engine_backend_dispose(GEngineBackend *backend)
+{
+ G_OBJECT_CLASS(g_engine_backend_parent_class)->dispose(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_engine_backend_finalize(GEngineBackend *backend)
+{
+ G_OBJECT_CLASS(g_engine_backend_parent_class)->finalize(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Indique la taille maximale des suites d'octets recherchées. *
+* *
+* Retour : Valeur strictement positive. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_engine_backend_get_atom_max_size(const GEngineBackend *backend)
+{
+ size_t result; /* Taille à faire connaître */
+ GEngineBackendClass *class; /* Classe à activer */
+
+ class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+ result = class->get_max_size(backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* plain = chaîne de caractères classique à intégrer. *
+* len = taille de cette chaîne. *
+* tmp_id = identifiants temporaires vers le motif. [OUT] *
+* *
+* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_engine_backend_enroll_plain_pattern(GEngineBackend *backend, const uint8_t *plain, size_t len, uint32_t tmp_id[2])
+{
+ bool result; /* Bilan à retourner */
+ GEngineBackendClass *class; /* Classe à activer */
+
+ class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+ result = class->enroll_plain(backend, plain, len, tmp_id);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Met en ordre les derniers détails avant un premier scan. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_engine_backend_warm_up(GEngineBackend *backend)
+{
+ bool result; /* Bilan à retourner */
+ GEngineBackendClass *class; /* Classe à activer */
+
+ class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+ if (class->warm_up != NULL)
+ result = class->warm_up(backend);
+ else
+ result = true;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* tmp_id = identifiants temporaires vers le motif. [OUT] *
+* *
+* Description : Récupère les identifiants finaux pour un motif recherché. *
+* *
+* Retour : Identifiant constitué ou INVALID_PATTERN_ID en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+patid_t g_engine_backend_build_plain_pattern_id(const GEngineBackend *backend, const uint32_t tmp_id[2])
+{
+ patid_t result; /* Identifiant à retourner */
+ GEngineBackendClass *class; /* Classe à activer */
+
+ class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+ result = class->build_id(backend, tmp_id);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* *
+* Description : Détermine le nombre d'identifiants constitués. *
+* *
+* Retour : Quantité de gestionnaires de suivi à prévoir. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_engine_backend_count_plain_pattern_ids(const GEngineBackend *backend)
+{
+ size_t result; /* Quantité à retourner */
+ GEngineBackendClass *class; /* Classe à activer */
+
+ class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+ result = class->count_ids(backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_engine_backend_run_scan(const GEngineBackend *backend, GScanContext *context)
+{
+ GEngineBackendClass *class; /* Classe à activer */
+
+ class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+ class->run_scan(backend, context);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Imprime quelques faits quant aux éléments mis en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_engine_backend_output_stats(const GEngineBackend *backend)
+{
+ GEngineBackendClass *class; /* Classe à activer */
+
+ class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+ if (class->output != NULL)
+ class->output(backend);
+
+}
diff --git a/src/analysis/scan/patterns/backend.h b/src/analysis/scan/patterns/backend.h
new file mode 100644
index 0000000..3f9be03
--- /dev/null
+++ b/src/analysis/scan/patterns/backend.h
@@ -0,0 +1,79 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend.h - prototypes pour une méthode de recherches au sein d'un contenu binaire
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKEND_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKEND_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+
+#include "../context.h"
+#include "../../content.h"
+
+
+
+#define G_TYPE_ENGINE_BACKEND g_engine_backend_get_type()
+#define G_ENGINE_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ENGINE_BACKEND, GEngineBackend))
+#define G_IS_ENGINE_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ENGINE_BACKEND))
+#define G_ENGINE_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ENGINE_BACKEND, GEngineBackendClass))
+#define G_IS_ENGINE_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ENGINE_BACKEND))
+#define G_ENGINE_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ENGINE_BACKEND, GEngineBackendClass))
+
+
+/* Méthode de traitement d'un contenu binaire pour recherches (instance) */
+typedef struct _GEngineBackend GEngineBackend;
+
+/* Méthode de traitement d'un contenu binaire pour recherches (classe) */
+typedef struct _GEngineBackendClass GEngineBackendClass;
+
+
+/* Indique le type défini pour une méthode de recherche dans du binaire. */
+GType g_engine_backend_get_type(void);
+
+/* Indique la taille maximale des suites d'octets recherchées. */
+size_t g_engine_backend_get_atom_max_size(const GEngineBackend *);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+bool g_engine_backend_enroll_plain_pattern(GEngineBackend *, const uint8_t *, size_t, uint32_t [2]);
+
+/* Met en ordre les derniers détails avant un premier scan. */
+bool g_engine_backend_warm_up(GEngineBackend *);
+
+/* Récupère les identifiants finaux pour un motif recherché. */
+patid_t g_engine_backend_build_plain_pattern_id(const GEngineBackend *, const uint32_t [2]);
+
+/* Détermine le nombre d'identifiants constitués. */
+size_t g_engine_backend_count_plain_pattern_ids(const GEngineBackend *);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+void g_engine_backend_run_scan(const GEngineBackend *, GScanContext *);
+
+/* Imprime quelques faits quant aux éléments mis en place. */
+void g_engine_backend_output_stats(const GEngineBackend *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKEND_H */
diff --git a/src/analysis/scan/patterns/backends/Makefile.am b/src/analysis/scan/patterns/backends/Makefile.am
new file mode 100644
index 0000000..23b0163
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/Makefile.am
@@ -0,0 +1,29 @@
+
+noinst_LTLIBRARIES = libanalysisscanpatternsbackends.la
+
+
+libanalysisscanpatternsbackends_la_SOURCES = \
+ acism-int.h \
+ acism.h acism.c \
+ bitap-int.h \
+ bitap.h bitap.c \
+ hyperscan-int.h \
+ hyperscan.h hyperscan.c
+
+# Cf. https://www.gnu.org/software/automake/manual/html_node/Per_002dObject-Flags.html
+
+AM_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBHS_CFLAGS)
+
+
+
+#AM_CFLAGS:=$(filter-out -O2,$(AM_CFLAGS))
+
+
+#bitap.lo: AM_CFLAGS += -Ofast -march=native -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1 #-mavx512bw
+#bitap.lo: AM_CFLAGS += -O3 -march=native -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1 #-mavx512bw
+bitap.lo: AM_CFLAGS += -g -march=native -mno-vzeroupper -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanpatternsbackends_la_SOURCES:%c=)
diff --git a/src/analysis/scan/patterns/backends/acism-int.h b/src/analysis/scan/patterns/backends/acism-int.h
new file mode 100644
index 0000000..c4a72ca
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/acism-int.h
@@ -0,0 +1,206 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * acism-int.h - prototypes internes pour la méthode de recherche basée sur l'algorithme Aho-Corasick Interleaved State-transition Matrix
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_INT_H
+
+
+#include "acism.h"
+
+
+#include <stdint.h>
+
+
+#include "../backend-int.h"
+#include "../../../../common/bits.h"
+
+
+
+//#define __USE_BYTE_FREQ
+//#define __SORT_BEFORE_BITMASK
+
+
+#define ACSIM_ATOM_SIZE 7
+
+
+
+/* Définition d'une portion de cible */
+typedef struct _acism_source_t
+{
+ /**
+ * Champs renseignés dans g_acism_backend_setup_for().
+ */
+
+ const uint8_t *atoms; /* Motif remarquable */
+ size_t len; /* Nombre d'octets considérés */
+
+ /**
+ * Champs renseignés dans g_acism_backend_build_trie().
+ */
+
+ bool is_first; /* Première instance rencontrée*/
+
+ union
+ {
+ uint32_t coverage[2]; /* Départ et quantité de suivis*/
+ struct
+ {
+ size_t first_source; /* Indice de première source */
+ uint32_t index; /* Position dans la liste */
+ };
+ };
+
+} acism_source_t;
+
+#define SOURCE_COVERAGE_START 0
+#define SOURCE_COVERAGE_COUNT 1
+#define SOURCE_COVERAGE_END 1
+
+/* Etude de la fréquence des octets pour attribution des codes */
+typedef struct _acism_freq_rank_t
+{
+ unsigned int frequency; /* Occurrences d'un octet */
+ uint8_t rank; /* Valeur dudit octet */
+
+} acism_freq_rank_t;
+
+/* Identifiant unique pour une valeur 8 bits donnée (max 257) */
+typedef uint16_t acism_code_t;
+
+#define MIN_ACISM_CODE 0
+#define MAX_ACISM_CODE 0xffff
+
+#define ROOT_STATE_INDEX 0
+
+/* Noeud de l'arborescence brute */
+typedef struct _acism_trie_node_t
+{
+ struct _acism_trie_node_t *parent; /* Noeud parent pour remontée */
+ struct _acism_trie_node_t *sibling; /* Noeud de même niveau suivant*/
+ struct _acism_trie_node_t *child; /* Noeud de lecture suivant */
+ struct _acism_trie_node_t *suffix_link; /* Retour en cas d'échec */
+
+ bin_t data; /* Donnée brute représentée */
+ acism_code_t code; /* Identifiant du noeud */
+
+ acism_code_t min_child_code; /* Plus petit code suivant */
+ acism_code_t max_child_code; /* Plus grand code suivant */
+ size_t children_count; /* Nombre de codes suivants */
+
+ size_t matched_atom; /* Indice de correspondance */
+
+ size_t state_index; /* Indice de le tableau final */
+
+} acism_trie_node_t;
+
+#if __LONG_WIDTH__ < 64
+
+/* Cellule du tableau compressé final */
+typedef struct _acism_state_t
+{
+ union
+ {
+ /* Indice 0 */
+ struct
+ {
+ unsigned int match : 1; /* Correspondance ici */
+ unsigned int unused : 4; /* Espace encore disponible */
+ unsigned int atom_size : 3; /* Taille d'atome représenté */
+ unsigned int suffix : 1; /* Correspondance ailleurs */
+ };
+
+ /* Indice 1 et + */
+ unsigned int code : 9; /* Position depuis la base */
+
+ };
+
+ unsigned int index : 23; /* Indice de saut */
+
+} acism_state_t;
+
+#else
+
+/* Cellule du tableau compressé final */
+typedef union _acism_state_t
+{
+ /* Indice 0 */
+ struct
+ {
+ uint8_t match : 1; /* Correspondance ici */
+ uint8_t single_source : 1; /* Unique source à notifier */
+ uint8_t atom_size; /* Indice de saut */
+ uint8_t suffix : 1; /* Correspondance ailleurs */
+ };
+
+ /* Indice 1 et + */
+ uint32_t code; /* Position depuis la base */
+
+ /* Tous */
+ struct
+ {
+ uint32_t any; /* Saut de bits */
+ uint32_t index; /* Indice de saut */
+ };
+
+} acism_state_t;
+
+#endif
+
+/* Méthode de recherche basée sur l'algorithme Acism (instance) */
+struct _GAcismBackend
+{
+ GEngineBackend parent; /* A laisser en premier */
+
+#ifdef __USE_BYTE_FREQ
+ acism_code_t codes_for_bytes[256]; /* Traduction octets -> codes */
+ acism_code_t codes_count; /* Quantité de traductions */
+#endif
+
+ acism_source_t *sources; /* Liste de motifs remarquables*/
+ size_t sources_count; /* Quantité de ces motifs */
+
+ size_t nchars; /* Taille cumulée des motifs */
+
+#ifdef __USE_BYTE_FREQ
+ acism_freq_rank_t frequencies[256]; /* Fréquences des octets */
+#endif
+
+ acism_trie_node_t *nodes; /* Liste de noeuds */
+ size_t nodes_used; /* Nombre de noeuds utilisés */
+
+ bitfield_t *bitmap_usage; /* Localisation des usages */
+ acism_state_t *states; /* Tableau de transitions */
+ uint32_t *coverages; /* Bornes de suivi de positions*/
+
+};
+
+/* Méthode de recherche basée sur l'algorithme Acism (classe) */
+struct _GAcismBackendClass
+{
+ GEngineBackendClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_INT_H */
diff --git a/src/analysis/scan/patterns/backends/acism.c b/src/analysis/scan/patterns/backends/acism.c
new file mode 100644
index 0000000..53bad11
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/acism.c
@@ -0,0 +1,1522 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * acism.c - méthode de recherche basée sur l'algorithme Aho-Corasick Interleaved State-transition Matrix
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "acism.h"
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "acism-int.h"
+#include "../../../../common/sort.h"
+
+
+
+/* ---------------------- IMPLANTATION D'UNE NOUVELLE APPROCHE ---------------------- */
+
+
+/* Initialise la classe des méthodes basée sur ACISM. */
+static void g_acism_backend_class_init(GAcismBackendClass *);
+
+/* Initialise une instance de méthodes basée sur ACISM. */
+static void g_acism_backend_init(GAcismBackend *);
+
+/* Supprime toutes les références externes. */
+static void g_acism_backend_dispose(GAcismBackend *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_acism_backend_finalize(GAcismBackend *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique la taille maximale des suites d'octets recherchées. */
+size_t g_acism_backend_get_atom_max_size(const GAcismBackend *);
+
+/* Intègre un motif limité de contenu à rechercher. */
+static void g_acism_backend_setup_for(GAcismBackend *, const uint8_t *, size_t, uint32_t [2]);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+static bool g_acism_backend_enroll_plain_pattern(GAcismBackend *, const uint8_t *, size_t, uint32_t [2]);
+
+#ifdef __USE_BYTE_FREQ
+
+/* Compare un niveau de fréquence avec un autre. */
+static int compare_byte_frequencies(const acism_freq_rank_t *, const acism_freq_rank_t *);
+
+/* Détermine les identifiants de chaque valeur 8 bits utile. */
+static void g_acism_backend_define_codes(GAcismBackend *);
+
+#endif
+
+/* Construit l'arborescence de noeuds de lecture. */
+static void g_acism_backend_build_trie(GAcismBackend *);
+
+/* Construit l'arborescence de noeuds de lecture. */
+static void g_acism_backend_build_suffix_links(GAcismBackend *);
+
+#ifdef __SORT_BEFORE_BITMASK
+
+/* Compare des noeuds selon l'espace de codes couvert. */
+static int compare_node_according_to_code_range(const acism_trie_node_t **, const acism_trie_node_t **);
+
+#endif
+
+/* Organise la convertion de l'arborescence en tableau. */
+static void g_acism_backend_prepare_interleave_array(GAcismBackend *);
+
+/* Compresse l'arborescence dans un tableau de position. */
+static void g_acism_backend_build_interleave_array(GAcismBackend *);
+
+/* Met en ordre les derniers détails avant un premier scan. */
+static bool g_acism_backend_warm_up(GAcismBackend *);
+
+/* Récupère les identifiants finaux pour un motif recherché. */
+static patid_t g_acism_backend_build_plain_pattern_id(const GAcismBackend *, const uint32_t [2]);
+
+/* Détermine le nombre d'identifiants constitués. */
+static size_t g_acism_backend_count_plain_pattern_ids(const GAcismBackend *);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+static void g_acism_backend_run_scan(const GAcismBackend *, GScanContext *);
+
+/* Affiche les caractéristques d'un noeud et de ses enfants. */
+static void visit_and_output_node(const acism_trie_node_t *, unsigned int);
+
+/* Imprime quelques faits quant aux éléments mis en place. */
+static void g_acism_backend_output_stats(const GAcismBackend *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLANTATION D'UNE NOUVELLE APPROCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+G_DEFINE_TYPE(GAcismBackend, g_acism_backend, G_TYPE_ENGINE_BACKEND);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des méthodes basée sur ACISM. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_class_init(GAcismBackendClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GEngineBackendClass *backend; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_acism_backend_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_acism_backend_finalize;
+
+ backend = G_ENGINE_BACKEND_CLASS(klass);
+
+ backend->get_max_size = (get_backend_atom_max_size_fc)g_acism_backend_get_atom_max_size;
+ backend->enroll_plain = (enroll_plain_into_backend_fc)g_acism_backend_enroll_plain_pattern;
+ backend->warm_up = (warm_up_backend_fc)g_acism_backend_warm_up;
+ backend->build_id = (build_backend_plain_pattern_id_fc)g_acism_backend_build_plain_pattern_id;
+ backend->count_ids = (count_backend_plain_pattern_ids_fc)g_acism_backend_count_plain_pattern_ids;
+ backend->run_scan = (run_backend_scan_fc)g_acism_backend_run_scan;
+ backend->output = (output_backend_stats_fc)g_acism_backend_output_stats;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance à initialiser. *
+* *
+* Description : Initialise une instance de méthodes basée sur ACISM. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_init(GAcismBackend *backend)
+{
+#ifdef __USE_BYTE_FREQ
+ size_t i; /* Boucle de parcours #1 */
+ acism_freq_rank_t *iter; /* Boucle de parcours #2 */
+#endif
+
+#ifdef __USE_BYTE_FREQ
+ memset(backend->codes_for_bytes, 0, 256 * sizeof(acism_code_t));
+#endif
+
+ backend->nchars = 0;
+
+#ifdef __USE_BYTE_FREQ
+ for (i = 0, iter = backend->frequencies; i < 256; i++, iter++)
+ {
+ iter->frequency = 0;
+ iter->rank = i;
+ }
+#endif
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_dispose(GAcismBackend *backend)
+{
+ G_OBJECT_CLASS(g_acism_backend_parent_class)->dispose(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_finalize(GAcismBackend *backend)
+{
+ if (backend->sources != NULL)
+ free(backend->sources);
+
+ if (backend->nodes != NULL)
+ free(backend->nodes);
+
+ if (backend->bitmap_usage != NULL)
+ delete_bit_field(backend->bitmap_usage);
+
+ if (backend->states != NULL)
+ free(backend->states);
+
+ if (backend->coverages != NULL)
+ free(backend->coverages);
+
+ G_OBJECT_CLASS(g_acism_backend_parent_class)->finalize(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une méthode de recherche basée sur l'algorithme Acism. *
+* *
+* Retour : Méthode mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GEngineBackend *g_acism_backend_new(void)
+{
+ GAcismBackend *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_ACISM_BACKEND, NULL);
+
+ return G_ENGINE_BACKEND(result);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Indique la taille maximale des suites d'octets recherchées. *
+* *
+* Retour : Valeur strictement positive. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_acism_backend_get_atom_max_size(const GAcismBackend *backend)
+{
+ size_t result; /* Taille à faire connaître */
+
+ result = ACSIM_ATOM_SIZE;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* pattern = chaîne de caractères classique à intégrer. *
+* len = taille de cette chaîne. *
+* tmp_id = identifiants temporaires vers le motif. [OUT] *
+* *
+* Description : Intègre un motif limité de contenu à rechercher. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_setup_for(GAcismBackend *backend, const uint8_t *pattern, size_t len, uint32_t tmp_id[2])
+{
+ size_t current; /* Indice de source courante */
+ acism_source_t *source; /* Définition à mémoriser */
+
+ /**
+ * Les motifs '\x00\x00\x00\x00abcd1234' et '\x01\x01\x01\x01abcd1234'
+ * peuvent constituer deux cibles différentes, mais ils comportent
+ * normalement la même séquence atomique à rechercher : 'abcd1234'.
+ *
+ * Chaque motif 'abcd1234' proposé est enregistré ici, et se verra in fine
+ * attribuer un identifiant propre. Le regroupement des motifs identiques
+ * et la constitution des identifiants finaux sont réalisés au moment de la
+ * construction de l'arborescence de recherche.
+ */
+
+ /* Pré-inscription pour l'extérieur */
+
+ current = backend->sources_count;
+
+ tmp_id[0] = current;
+ tmp_id[1] = 0; /* Non utilisé */
+
+ /* Inscription en interne */
+
+ backend->sources = realloc(backend->sources, ++backend->sources_count * sizeof(acism_source_t));
+
+ source = &backend->sources[current];
+
+ source->atoms = pattern;
+ source->len = len;
+
+ backend->nchars += len;
+
+#ifdef __USE_BYTE_FREQ
+ for (i = 0; i < len; i++)
+ backend->frequencies[pattern[i]].frequency++;
+#endif
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* plain = chaîne de caractères classique à intégrer. *
+* len = taille de cette chaîne. *
+* tmp_id = identifiants temporaires vers le motif. [OUT] *
+* *
+* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_acism_backend_enroll_plain_pattern(GAcismBackend *backend, const uint8_t *plain, size_t len, uint32_t tmp_id[2])
+{
+ bool result; /* Bilan à retourner */
+
+ assert(len <= ACSIM_ATOM_SIZE);
+
+ result = true;
+
+ /**
+ * Le traitement différé des chaînes à rechercher permet deux choses :
+ * - la construction d'une table de permutation ;
+ * - le décompte des noeuds à allouer (en une seule fois).
+ *
+ * Si l'intention du premier point est louable (densifier les champs de bits
+ * pour allouer moins et tenir plus facilement dans le cache du CPU), la
+ * permetutation est extrèmement coûteuse pendant la phase de scan
+ * (une lecture supplémentaire par octet de données scannées).
+ *
+ * Le second point reste valable (à priori).
+ *
+ * L'appel à la fonction g_acism_backend_setup_for() demeure donc, et l'arbre
+ * est construit dans un second temps. La distinction de cette fonction avec
+ * la procédure d'enrôlement permet potentiellement d'étuer une bascule à
+ * moindre coût un jour.
+ */
+
+ g_acism_backend_setup_for(backend, plain, len, tmp_id);
+
+ return result;
+
+}
+
+
+#ifdef __USE_BYTE_FREQ
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à comparer. *
+* b = second élément à comparer. *
+* *
+* Description : Compare un niveau de fréquence avec un autre. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_byte_frequencies(const acism_freq_rank_t *a, const acism_freq_rank_t *b)
+{
+ int result; /* Bilan à retourner */
+
+ /**
+ * Afin d'obtenir les plus grosses fréquences en premier,
+ * l'ordre de comparaison est inversé : b < a ?
+ */
+
+ result = sort_unsigned_long(b->frequency, a->frequency);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Détermine les identifiants de chaque valeur 8 bits utile. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_define_codes(GAcismBackend *backend)
+{
+ size_t i; /* Boucle de parcours #1 */
+ acism_freq_rank_t *iter; /* Boucle de parcours #2 */
+
+ /**
+ * La redistribution des valeurs d'octet va permettre de compacter
+ * par la suite les masques de cellules utilisées pour construire
+ * le plus petit tableau des états.
+ *
+ * L'idée est de grouper le plus possible les états (représentés
+ * par un indice) autour de l'état 0.
+ */
+
+ qsort(backend->frequencies, 256, sizeof(acism_freq_rank_t), (__compar_fn_t)compare_byte_frequencies);
+
+ /* 0 == racine */
+ backend->codes_count++;
+
+ for (i = 0, iter = backend->frequencies; i < 256; i++, iter++)
+ {
+ if (iter->frequency == 0)
+ break;
+
+ backend->codes_for_bytes[iter->rank] = backend->codes_count++;
+
+ }
+
+}
+
+
+#endif
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Construit l'arborescence de noeuds de lecture. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_build_trie(GAcismBackend *backend)
+{
+ size_t i; /* Boucle de parcours #1 */
+ acism_trie_node_t *next; /* Prochain noeud disponible */
+ acism_trie_node_t *node; /* Tête de parcours */
+ acism_source_t *source; /* Définition à mémoriser */
+ size_t k; /* Boucle de parcours #2 */
+ acism_code_t code; /* Identifiant de symbole */
+ acism_trie_node_t *parent; /* Sauvegarde d'un accès */
+ uint32_t current_start; /* Indice de gestionnaire */
+
+ backend->nodes = calloc(backend->nchars + 1, sizeof(acism_trie_node_t));
+
+ for (i = 0; i < (backend->nchars + 1); i++)
+ {
+ backend->nodes[i].min_child_code = MAX_ACISM_CODE;
+ backend->nodes[i].max_child_code = MIN_ACISM_CODE;
+ }
+
+ next = backend->nodes + 1;
+
+ for (i = 0; i < backend->sources_count; i++)
+ {
+ node = backend->nodes;
+
+ source = &backend->sources[i];
+
+ /* Parcours des noeuds contenus */
+
+ for (k = 0; k < source->len && node->child != NULL; k++)
+ {
+#ifdef __USE_BYTE_FREQ
+ code = backend->codes_for_bytes[source->atoms[k]];
+#else
+ code = 1 + source->atoms[k];
+#endif
+
+ /* Insertion d'un nouveau noeud au début des enfants */
+ if (code < node->child->code)
+ {
+ next->parent = node;
+ next->suffix_link = node;
+ next->data = source->atoms[k];
+ next->code = code;
+
+ next->sibling = node->child;
+ node->child = next++;
+
+ if (code < node->min_child_code) node->min_child_code = code;
+ if (code > node->max_child_code) node->max_child_code = code;
+ node->children_count++;
+
+ node = node->child;
+
+ k++;
+ break;
+
+ }
+
+ parent = node;
+
+ /* Recherche du point d'insertion idéal */
+ for (node = node->child;
+ node->sibling != NULL && code >= node->sibling->code;
+ node = node->sibling);
+
+ /* Si le noeud idéal n'existe pas, insertion ordonnée */
+ if (code > node->code)
+ {
+ next->parent = parent;
+ next->suffix_link = parent;
+ next->data = source->atoms[k];
+ next->code = code;
+
+ next->sibling = node->sibling;
+ node->sibling = next++;
+
+ if (code < parent->min_child_code) parent->min_child_code = code;
+ if (code > parent->max_child_code) parent->max_child_code = code;
+ parent->children_count++;
+
+ node = node->sibling;
+
+ k++;
+ break;
+
+ }
+
+ }
+
+ /* Si un atome (partiellement ?) identique a déjà été inscrit */
+ if (k == source->len)
+ {
+ /**
+ * L'atome déjà inscrit est plus long, et on se trouve ici dans le
+ * parcours de l'arborescence qui mène à sa conclusion, sans
+ * inscription d'une fin de parcours au point courant.
+ */
+ if (node->matched_atom == 0)
+ goto register_leaf;
+
+ /**
+ * Rattachement au motif strictement identique.
+ */
+ else
+ {
+ assert(backend->sources[node->matched_atom - 1].is_first);
+
+ source->is_first = false;
+ source->first_source = node->matched_atom - 1;
+ source->index = backend->sources[source->first_source].coverage[SOURCE_COVERAGE_COUNT]++;
+
+ }
+
+ }
+
+ else
+ {
+ /* Creéation d'une nouvelle branche avec le reliquat */
+ for (; k < source->len; k++)
+ {
+#ifdef __USE_BYTE_FREQ
+ code = backend->codes_for_bytes[source->atoms[k]];
+#else
+ code = 1 + source->atoms[k];
+#endif
+
+ next->parent = node;
+ next->suffix_link = node;
+ next->data = source->atoms[k];
+ next->code = code;
+
+ node->child = next++;
+
+ if (code < node->min_child_code) node->min_child_code = code;
+ if (code > node->max_child_code) node->max_child_code = code;
+ node->children_count++;
+
+ node = node->child;
+
+ }
+
+ register_leaf:
+
+ node->matched_atom = i + 1;
+
+ source->is_first = true;
+ source->coverage[SOURCE_COVERAGE_COUNT] = 1;
+
+ }
+
+ }
+
+ backend->nodes_used = next - backend->nodes;
+
+ /* Construction des bases pour identifiants */
+
+ current_start = 0;
+
+ for (i = 0; i < backend->sources_count; i++)
+ {
+ source = &backend->sources[i];
+
+ if (source->is_first)
+ {
+ source->coverage[SOURCE_COVERAGE_START] = current_start;
+
+ current_start += source->coverage[SOURCE_COVERAGE_COUNT];
+
+ }
+
+ }
+
+ assert(current_start == backend->sources_count);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Construit l'arborescence de noeuds de lecture. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_build_suffix_links(GAcismBackend *backend)
+{
+ size_t max_pos; /* Tête de lecture finale */
+ acism_trie_node_t **stack; /* Pile des noeuds à traiter */
+ size_t rd_pos; /* Tête de lecture */
+ size_t wr_pos; /* Tête d'écriture */
+ acism_trie_node_t *node; /* Noeud à traiter */
+ acism_trie_node_t *parent; /* Noeud parent de la chaîne */
+ acism_trie_node_t *iter; /* Boucle de parcours */
+
+ max_pos = backend->nodes_used;
+
+ stack = calloc(max_pos, sizeof(acism_trie_node_t *));
+
+ /* Initialisation du parcours */
+
+ rd_pos = 0;
+ wr_pos = 0;
+
+ stack[wr_pos++] = &backend->nodes[0];
+
+ assert(backend->nodes->sibling == NULL);
+
+ /* Traitement manuel de démarrage pour éviter une condition en [0] */
+
+ for (iter = backend->nodes->child; iter != NULL; iter = iter->sibling)
+ stack[wr_pos++] = iter;
+
+ rd_pos++;
+
+ /* Suivi des liens déjà en place */
+
+ while (rd_pos < max_pos)
+ {
+ assert(rd_pos < wr_pos);
+
+ node = stack[rd_pos++];
+
+ /* Remontée jusqu'à la découverte d'un lien d'intérêt */
+
+ for (parent = node->suffix_link; parent != NULL; parent = parent->suffix_link)
+ {
+ for (iter = parent->child; iter != NULL; iter = iter->sibling)
+ if (iter->code == node->code && iter != node)
+ {
+ node->suffix_link = iter;
+ break;
+ }
+
+ if (iter != NULL)
+ break;
+
+ }
+
+ if (parent == NULL /* && node != &backend->nodes [0] */)
+ node->suffix_link = backend->nodes;
+
+ /* Inscription des noeuds suivants */
+
+ for (iter = node->child; iter != NULL; iter = iter->sibling)
+ stack[wr_pos++] = iter;
+
+ }
+
+ /* Sortie propre */
+
+ free(stack);
+
+}
+
+
+#ifdef __SORT_BEFORE_BITMASK
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à comparer. *
+* b = second élément à comparer. *
+* *
+* Description : Compare des noeuds selon l'espace de codes couvert. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_node_according_to_code_range(const acism_trie_node_t **a, const acism_trie_node_t **b)
+{
+ int result; /* Bilan à retourner */
+ const acism_trie_node_t *_a; /* Autre vision de l'élément #1*/
+ const acism_trie_node_t *_b; /* Autre vision de l'élément #1*/
+ acism_code_t range_a; /* Espacement des codes #1 */
+ acism_code_t range_b; /* Espacement des codes #2 */
+
+ result = 0;
+
+ _a = *a;
+ _b = *b;
+
+ if (_a->child == NULL)
+ result = (_b->child == NULL ? 0 : 1);
+
+ else if (_b->child == NULL)
+ result = (_a->child == NULL ? 0 : -1);
+
+ else
+ {
+ assert(_a->min_child_code <= _a->max_child_code);
+ range_a = _a->max_child_code - _a->min_child_code;
+
+ assert(_b->min_child_code <= _b->max_child_code);
+ range_b = _b->max_child_code - _b->min_child_code;
+
+ result = sort_unsigned_long(range_b, range_a);
+
+ if (result == 0)
+ result = sort_unsigned_long(_b->children_count, _a->children_count);
+
+ }
+
+ return result;
+
+}
+
+
+#endif
+
+
+#if 1
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Organise la convertion de l'arborescence en tableau. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend)
+{
+#ifdef __SORT_BEFORE_BITMASK
+ acism_trie_node_t **list; /* Liste de noeuds alloués */
+#endif
+ size_t i; /* Boucle de parcours #1 */
+ size_t last_free_state; /* Dernier emplacement dispo. */
+ size_t full_size; /* Cartographie entière */
+ bitfield_t *global_usage; /* Cartographie des usages */
+#ifndef NDEBUG
+ size_t pops[3]; /* Décomptes individuels */
+ size_t bsum; /* Somme de tous les bits */
+#endif
+ bitfield_t *usage; /* Cartographie locale */
+ acism_trie_node_t *node; /* Noeud en cours de traitement*/
+ size_t highest; /* Poids du bit le plus fort */
+ acism_trie_node_t *iter; /* Boucle de parcours #2 */
+ size_t first_freedom_word; /* Premier mot avec des dispos.*/
+ size_t free_state; /* Emplacement libre trouvé */
+
+ /* Préparation de la liste de noeuds à inscrire */
+
+#ifdef __SORT_BEFORE_BITMASK
+
+ list = calloc(backend->nodes_used, sizeof(acism_trie_node_t *));
+
+ for (i = 0; i < backend->nodes_used; i++)
+ list[i] = backend->nodes + i;
+
+ qsort(list + 1, backend->nodes_used - 1, sizeof(acism_trie_node_t *),
+ (__compar_fn_t)compare_node_according_to_code_range);
+
+#endif
+
+ /* Insertion des noeuds dans l'ordre prévu */
+
+ last_free_state = 257;
+ full_size = last_free_state + 257;
+ global_usage = create_bit_field(full_size, false);
+
+#ifndef NDEBUG
+
+ pops[0] = 0;
+ pops[1] = 0;
+ pops[2] = 0;
+
+ bsum = 0;
+
+#endif
+
+ usage = create_bit_field(257, false);
+
+ for (i = 0; i < backend->nodes_used; i++)
+ {
+#ifdef __SORT_BEFORE_BITMASK
+ node = list[i];
+#else
+ node = backend->nodes + i;
+#endif
+
+ /* Préparation du masque du noeud */
+
+ truncate_bit_field(&usage, 257);
+
+ reset_all_in_bit_field(usage);
+
+ set_in_bit_field(usage, 0, 1);
+
+#ifndef NDEBUG
+ pops[0]++;
+#endif
+
+ highest = 0;
+
+ for (iter = node->child; iter != NULL; iter = iter->sibling)
+ {
+ set_in_bit_field(usage, iter->code, 1);
+
+#ifndef NDEBUG
+ pops[0]++;
+#endif
+
+ if (iter->code > highest)
+ highest = iter->code;
+
+ }
+
+#ifndef NDEBUG
+ pops[1] += popcount_for_bit_field(usage);
+#endif
+
+ assert(popcount_for_bit_field(usage) == (node->children_count + 1));
+
+ truncate_bit_field(&usage, ++highest);
+
+ /* Recherche d'une position idéale */
+
+ if (i == 0)
+ {
+ first_freedom_word = 0;
+ free_state = 0;
+ }
+
+ else
+ free_state = find_interleaving_index_for_acism(global_usage, usage, &first_freedom_word);
+
+ /* Suivi global */
+
+ assert(!test_in_bit_field(global_usage, free_state));
+
+ or_bit_field_at(global_usage, usage, free_state);
+
+#ifndef NDEBUG
+ bsum += node->children_count + 1;
+ assert(popcount_for_bit_field(global_usage) == bsum);
+#endif
+
+ node->state_index = free_state;
+
+ if ((free_state + 257) > last_free_state)
+ {
+ last_free_state += 257;
+ full_size += 257;
+ resize_bit_field(&global_usage, full_size);
+ }
+
+ }
+
+ /* Sotie encadrée */
+
+#ifndef NDEBUG
+
+ pops[2] = popcount_for_bit_field(global_usage);
+
+ assert(pops[0] == pops[1]);
+ assert(pops[0] == pops[2]);
+
+#endif
+
+ backend->bitmap_usage = global_usage;
+
+ delete_bit_field(usage);
+
+#ifdef __SORT_BEFORE_BITMASK
+ free(list);
+#endif
+
+}
+
+
+#else
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Organise la convertion de l'arborescence en tableau. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend)
+{
+ size_t max_pos; /* Tête de lecture finale */
+ acism_trie_node_t **stack; /* Pile des noeuds à traiter */
+ size_t last_free_state; /* Dernier emplacement dispo. */
+ size_t full_size; /* Cartographie entière */
+ bitfield_t *global_usage; /* Cartographie des usages */
+ bitfield_t *usage; /* Cartographie locale */
+ size_t rd_pos; /* Tête de lecture */
+ size_t wr_pos; /* Tête d'écriture */
+ size_t first_freedom_word; /* Premier mot avec des dispos.*/
+ acism_trie_node_t *node; /* Noeud à traiter */
+ acism_trie_node_t *iter; /* Boucle de parcours */
+ size_t free_state; /* Emplacement libre trouvé */
+
+ max_pos = backend->nodes_used;
+
+ stack = calloc(max_pos, sizeof(acism_trie_node_t *));
+
+ last_free_state = 257;
+ full_size = last_free_state + 257;
+ global_usage = create_bit_field(full_size, false);
+
+ usage = create_bit_field(257, false);
+
+ /* Initialisation du parcours */
+
+ rd_pos = 0;
+ wr_pos = 0;
+
+ stack[wr_pos++] = &backend->nodes[0];
+
+ assert(backend->nodes->sibling == NULL);
+
+ /* Traitement manuel de démarrage pour éviter une condition en [0] */
+
+ set_in_bit_field(global_usage, 0, 1);
+
+ for (iter = backend->nodes->child; iter != NULL; iter = iter->sibling)
+ {
+ set_in_bit_field(global_usage, iter->code, 1);
+ stack[wr_pos++] = iter;
+ }
+
+ rd_pos++;
+
+ first_freedom_word = 0;
+
+ /* Suivi des liens déjà en place */
+
+ while (rd_pos < max_pos)
+ {
+ assert(rd_pos < wr_pos);
+
+ node = stack[rd_pos++];
+
+ /* Préparation du masque du noeud et inscription des noeuds suivants */
+
+ reset_all_in_bit_field(usage);
+
+ set_in_bit_field(usage, 0, 1);
+
+ for (iter = node->child; iter != NULL; iter = iter->sibling)
+ {
+ set_in_bit_field(usage, iter->code, 1);
+ stack[wr_pos++] = iter;
+ }
+
+ assert(popcount_for_bit_field(usage) == (node->children_count + 1));
+
+ /* Recherche d'une position idéale */
+
+ free_state = find_interleaving_index_for_acism(global_usage, usage, &first_freedom_word);
+
+ /* Suivi global */
+
+ assert(!test_in_bit_field(global_usage, free_state));
+
+ or_bit_field_at(global_usage, usage, free_state);
+
+ node->state_index = free_state;
+
+ if ((free_state + 257) > last_free_state)
+ {
+ last_free_state += 257;
+ full_size += 257;
+ resize_bit_field(&global_usage, full_size);
+ }
+
+ }
+
+ /* Sotie encadrée */
+
+ backend->bitmap_usage = global_usage;
+
+ delete_bit_field(usage);
+
+ free(stack);
+
+}
+
+
+#endif
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Compresse l'arborescence dans un tableau de position. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_build_interleave_array(GAcismBackend *backend)
+{
+ size_t maxsize; /* Taille maximale du tableau */
+ size_t i; /* Boucle de parcours #1 */
+ acism_trie_node_t *node; /* Noeud à transcrire */
+ acism_state_t *base; /* Base d'une série de cellules*/
+ uint32_t *coverage; /* Couverture des inscriptions */
+ acism_source_t *source; /* Définition originelle */
+ acism_trie_node_t *iter; /* Sous-noeud à inscrire #2 */
+ acism_trie_node_t *child; /* Sous-noeud à inscrire #3 */
+ uint16_t offset; /* Décalage local */
+
+ maxsize = get_bit_field_size(backend->bitmap_usage);
+
+ backend->states = calloc(maxsize, sizeof(acism_state_t));
+ backend->coverages = calloc(maxsize, 2 * sizeof(uint32_t));
+
+ for (i = 0; i < backend->nodes_used; i++)
+ {
+ node = &backend->nodes[i];
+ base = backend->states + node->state_index;
+
+ assert(base[0].code == 0);
+ assert(base[0].index == 0);
+
+ if (node->matched_atom > 0)
+ {
+ source = &backend->sources[node->matched_atom - 1];
+
+ base[0].match = 1;
+ base[0].single_source = source->coverage[SOURCE_COVERAGE_COUNT] == 1 ? 1 : 0;
+ base[0].atom_size = backend->sources[node->matched_atom - 1].len - 1;
+
+ coverage = &backend->coverages[node->state_index * 2];
+
+ coverage[SOURCE_COVERAGE_START] = source->coverage[SOURCE_COVERAGE_START];
+ coverage[SOURCE_COVERAGE_END] = coverage[SOURCE_COVERAGE_START] \
+ + source->coverage[SOURCE_COVERAGE_COUNT];
+
+ for (iter = node->parent->suffix_link; iter != NULL; iter = iter->suffix_link)
+ {
+ for (child = iter->child; child != NULL; child = child->sibling)
+ if (child->code == node->code && child->matched_atom > 0)
+ break;
+
+ if (child != NULL)
+ {
+ base[0].suffix = 1;
+ break;
+ }
+
+ }
+
+ }
+
+ base[0].index = i == 0 ? 0 : node->suffix_link->state_index;
+
+ for (child = node->child; child != NULL; child = child->sibling)
+ {
+ offset = child->code;
+
+ assert(base[offset].code == 0);
+ assert(base[offset].index == 0);
+
+ base[offset].code = child->code;
+ base[offset].index = child->state_index;
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Met en ordre les derniers détails avant un premier scan. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_acism_backend_warm_up(GAcismBackend *backend)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+#ifdef __USE_BYTE_FREQ
+
+ /**
+ * Attribue un identifiant unique pour chaque octet présent dans les
+ * motifs recherchés.
+ */
+ g_acism_backend_define_codes(backend);
+
+#endif
+
+ /**
+ * Construit une arborescence de lecture à partir des différents
+ * octets présents dans les motifs.
+ *
+ * Les couvertures des futurs tableaux de correspondances sont
+ * établies au passage, ouvrant la voie aux définitions d'identifiant
+ * pour les motifs enregistrés.
+ */
+ g_acism_backend_build_trie(backend);
+
+ /**
+ * Met en place les liens suivis en cas d'échec de correspondance
+ * lors de la lecture d'un octet supplémentaire.
+ */
+ g_acism_backend_build_suffix_links(backend);
+
+ /**
+ * Conversion de l'arborescence en tableau plat et compressé.
+ */
+
+ g_acism_backend_prepare_interleave_array(backend);
+
+ g_acism_backend_build_interleave_array(backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* tmp_id = identifiants temporaires vers le motif. [OUT] *
+* *
+* Description : Récupère les identifiants finaux pour un motif recherché. *
+* *
+* Retour : Identifiant constitué ou INVALID_PATTERN_ID en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static patid_t g_acism_backend_build_plain_pattern_id(const GAcismBackend *backend, const uint32_t tmp_id[2])
+{
+ patid_t result; /* Identifiant à retourner */
+ acism_source_t *source; /* Motif d'origine concerné */
+ acism_source_t *reference; /* Renvoi vers un même motif */
+
+ assert(tmp_id[0] < backend->sources_count);
+
+ /**
+ * L'indicateur tmp_id[1] n'est pas utilisé ici.
+ */
+
+ source = backend->sources + tmp_id[0];
+
+ if (source->is_first)
+ result = source->coverage[SOURCE_COVERAGE_START];
+
+ else
+ {
+ reference = backend->sources + source->first_source;
+
+ assert(source->index < reference->coverage[SOURCE_COVERAGE_COUNT]);
+
+ result = reference->coverage[SOURCE_COVERAGE_START] + source->index;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* *
+* Description : Détermine le nombre d'identifiants constitués. *
+* *
+* Retour : Quantité de gestionnaires de suivi à prévoir. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static size_t g_acism_backend_count_plain_pattern_ids(const GAcismBackend *backend)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = backend->sources_count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_run_scan(const GAcismBackend *backend, GScanContext *context)
+{
+ GBinContent *content; /* Contenu binaire manipulé */
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+#ifdef __USE_BYTE_FREQ
+ acism_code_t codes_for_bytes[256]; /* Copie des codes d'accès */
+#endif
+ acism_state_t *root; /* Racine de l'arborescence */
+ uint32_t *coverages; /* Bornes de suivi de positions*/
+ unsigned int state; /* Tête de lecture courante */
+ phys_t i; /* Boucle de parcours #1 */
+ acism_code_t code; /* Code du caractère courant */
+ unsigned int next; /* Prochaine tête à valider */
+ acism_state_t next_state; /* Prochaine tête à valider */
+ uint32_t k; /* Boucle de parcours #2 */
+ uint32_t final_k; /* Dernier indice à traiter */
+ unsigned int iter; /* Boucle de parcours #3 */
+ acism_state_t test_state; /* Test de validité alternative*/
+ acism_state_t sub_state; /* Test de validité alternative*/
+
+ content = g_scan_context_get_content(context);
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ /* Suivi via l'arborescence aplatie */
+
+#ifdef __USE_BYTE_FREQ
+ memcpy(&codes_for_bytes, backend->codes_for_bytes, 256 * sizeof(acism_code_t));
+#endif
+
+ root = backend->states;
+ if (root == NULL) goto done;
+
+ coverages = backend->coverages;
+
+ state = ROOT_STATE_INDEX;
+
+ for (i = 0; i < dlen; i++)
+ {
+#ifdef __USE_BYTE_FREQ
+ code = codes_for_bytes[data[i]];
+#else
+ code = 1 + data[i];
+#endif
+
+ /* Déplacement de la tête de lecture dans l'arborescence */
+
+ retry:
+
+ next = state + code;
+
+ if (root[next].code == code)
+ {
+ next = root[next].index;
+ next_state = root[next];
+ }
+
+ else if (state != ROOT_STATE_INDEX)
+ {
+ state = root[state].index;
+ goto retry;
+ }
+
+ else
+ continue;
+
+ /* Remontée d'éventuels résultats */
+
+ if (next_state.match)
+ {
+ k = coverages[next * 2 + SOURCE_COVERAGE_START];
+
+ if (next_state.single_source)
+ g_scan_context_store_atom_match_end(context, k, i);
+ //g_umem_slice_put_uint64(matches[0/*k*/], i - next_state.atom_size);
+
+ else
+ {
+ final_k = coverages[next * 2 + SOURCE_COVERAGE_END];
+
+ for (; k < final_k; k++)
+ g_scan_context_store_atom_match_end(context, k, i);
+ //g_umem_slice_put_uint64(matches[0/*k*/], i - next_state.atom_size);
+
+ }
+
+ if (next_state.suffix)
+ {
+ for (iter = root[state].index; ; iter = root[iter].index)
+ {
+ test_state = root[iter + code];
+
+ if (test_state.code == code)
+ {
+ sub_state = root[test_state.index];
+
+ if (sub_state.match)
+ {
+ assert(sub_state.atom_size < next_state.atom_size);
+
+ k = coverages[test_state.index * 2 + SOURCE_COVERAGE_START];
+
+ if (sub_state.single_source)
+ g_scan_context_store_atom_match_end(context, k, i);
+ //g_umem_slice_put_uint64(matches[0/*k*/], i - sub_state.atom_size);
+
+ else
+ {
+ final_k = coverages[test_state.index * 2 + SOURCE_COVERAGE_END];
+
+ for (; k < final_k; k++)
+ g_scan_context_store_atom_match_end(context, k, i);
+ //g_umem_slice_put_uint64(matches[0/*k*/], i - sub_state.atom_size);
+
+ }
+
+ }
+
+ }
+
+ if (iter == ROOT_STATE_INDEX)
+ break;
+
+ }
+
+ }
+
+
+ }
+
+ /* Bascule au caractère suivant */
+
+ state = next;
+
+ }
+
+ done:
+
+ g_object_unref(G_OBJECT(content));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud d'arborescence à traiter. *
+* level = profondeur courante. *
+* *
+* Description : Affiche les caractéristques d'un noeud et de ses enfants. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void visit_and_output_node(const acism_trie_node_t *node, unsigned int level)
+{
+ unsigned int i; /* Boucle de parcours #1 */
+ acism_trie_node_t *iter; /* Boucle de parcours #2 */
+
+ for (i = 0; i < level; i++)
+ printf(" ");
+
+ printf(" '%c' (code=%hhu)\n", node->data, node->code);
+
+ for (iter = node->child; iter != NULL; iter = iter->sibling)
+ visit_and_output_node(iter, level + 1);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Imprime quelques faits quant aux éléments mis en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_acism_backend_output_stats(const GAcismBackend *backend)
+{
+ printf("nodes used: %zu\n", backend->nodes_used);
+
+ printf("full_size: %zu (real: %zu)\n",
+ get_bit_field_size(backend->bitmap_usage),
+ popcount_for_bit_field(backend->bitmap_usage));
+
+ visit_and_output_node(backend->nodes, 0);
+
+}
diff --git a/src/analysis/scan/patterns/backends/acism.h b/src/analysis/scan/patterns/backends/acism.h
new file mode 100644
index 0000000..837022a
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/acism.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * acism.h - prototypes pour la méthode de recherche basée sur l'algorithme Aho-Corasick Interleaved State-transition Matrix
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "../backend.h"
+
+
+
+#define G_TYPE_ACISM_BACKEND g_acism_backend_get_type()
+#define G_ACISM_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ACISM_BACKEND, GAcismBackend))
+#define G_IS_ACISM_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ACISM_BACKEND))
+#define G_ACISM_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ACISM_BACKEND, GAcismBackendClass))
+#define G_IS_ACISM_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ACISM_BACKEND))
+#define G_ACISM_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ACISM_BACKEND, GAcismBackendClass))
+
+
+/* Méthode de recherche basée sur l'algorithme Acism (instance) */
+typedef struct _GAcismBackend GAcismBackend;
+
+/* Méthode de recherche basée sur l'algorithme Acism (classe) */
+typedef struct _GAcismBackendClass GAcismBackendClass;
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+GType g_acism_backend_get_type(void);
+
+/* Crée une méthode de recherche basée sur l'algorithme Acism. */
+GEngineBackend *g_acism_backend_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H */
diff --git a/src/analysis/scan/patterns/backends/bitap-int.h b/src/analysis/scan/patterns/backends/bitap-int.h
new file mode 100644
index 0000000..ea739b4
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/bitap-int.h
@@ -0,0 +1,132 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bitap-int.h - prototypes internes pour la méthode de recherche basée sur l'algorithme Bitap
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_INT_H
+
+
+#include "bitap.h"
+
+
+#include <immintrin.h>
+
+
+#include "../backend-int.h"
+#include "../../../../common/cpu.h"
+#include "../../../../../config.h"
+
+
+
+#define BITAP_ATOM_SIZE 7
+
+
+#ifdef HAVE_AVX2
+
+/* Suivi d'un groupe de chaînes */
+typedef struct _grouped_strings_avx2_t
+{
+ __m256i pattern_masks[256]; /* Programmation de détections */
+ __m256i found_masks; /* Masques multiples d'alerte */
+
+ __m256i R; /* Résultats courants */
+
+ size_t m[32]; /* Taille des chaînes */
+
+ patid_t found_id[32]; /* Indice des résultats */
+
+ size_t available; /* Nombre de places disponibles*/
+ size_t used; /* Quantité de places utilisées*/
+
+} grouped_strings_avx2_t;
+
+/* Suivi de l'ensemble de chaînes */
+typedef struct _group_manager_avx2_t
+{
+ grouped_strings_avx2_t **strings_8; /* Chaînes de taille 8 max */
+ size_t count_8; /* Quantité de ces chaînes */
+
+} group_manager_avx2_t;
+
+#endif
+
+#ifdef HAVE_AVX512_F
+
+/* Suivi d'un groupe de chaînes */
+typedef struct _grouped_strings_avx512_t
+{
+ __m512i pattern_masks[256]; /* Programmation de détections */
+ __m512i found_masks; /* Masques multiples d'alerte */
+
+ __m512i R; /* Résultats courants */
+
+ size_t m[64]; /* Taille des chaînes */
+
+ patid_t found_id[64]; /* Indice des résultats */
+
+ size_t used; /* Quantité de places utilisées*/
+ size_t available; /* Nombre de places disponibles*/
+
+} grouped_strings_avx512_t;
+
+/* Suivi de l'ensemble de chaînes */
+typedef struct _group_manager_avx512_t
+{
+ grouped_strings_avx512_t **strings_8; /* Chaînes de taille 8 max */
+ size_t count_8; /* Quantité de ces chaînes */
+
+} group_manager_avx512_t;
+
+#endif
+
+
+/* Méthode de recherche basée sur l'algorithme Bitap (instance) */
+struct _GBitapBackend
+{
+ GEngineBackend parent; /* A laisser en premier */
+
+ CPUSMIDFeature optimization; /* Mode de calculs */
+
+#if defined HAVE_AVX2 || defined HAVE_AVX512_F
+ union
+ {
+# ifdef HAVE_AVX2
+ group_manager_avx2_t manager_avx2; /* Gestionnaire pour AVX2 */
+# endif
+# ifdef HAVE_AVX512_F
+ group_manager_avx512_t manager_avx512;/* Gestionnaire pour AVX-512 */
+# endif
+ };
+#endif
+
+};
+
+/* Méthode de recherche basée sur l'algorithme Bitap (classe) */
+struct _GBitapBackendClass
+{
+ GEngineBackendClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_INT_H */
diff --git a/src/analysis/scan/patterns/backends/bitap.c b/src/analysis/scan/patterns/backends/bitap.c
new file mode 100644
index 0000000..af50c6d
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/bitap.c
@@ -0,0 +1,2785 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bitap.c - méthode de recherche basée sur l'algorithme Bitap
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "bitap.h"
+
+
+#include <alloca.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <sched.h>
+
+
+#include "bitap-int.h"
+#include "../../../../core/logs.h"
+//#include "../../matches/bytes.h"
+
+
+
+/* ---------------------- IMPLANTATION D'UNE NOUVELLE APPROCHE ---------------------- */
+
+
+/* Initialise la classe des méthodes basée sur Bitmap. */
+static void g_bitap_backend_class_init(GBitapBackendClass *);
+
+/* Initialise une instance de méthodes basée sur Bitmap. */
+static void g_bitap_backend_init(GBitapBackend *);
+
+/* Supprime toutes les références externes. */
+static void g_bitap_backend_dispose(GBitapBackend *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_bitap_backend_finalize(GBitapBackend *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique la taille maximale des suites d'octets recherchées. */
+size_t g_bitap_backend_get_atom_max_size(const GBitapBackend *);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+static patid_t g_bitap_backend_enroll_plain_pattern(GBitapBackend *, GScanContext *, const uint8_t *, size_t);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+static void g_bitap_backend_run_scan(const GBitapBackend *, GScanContext *);
+
+/* Imprime quelques faits quant aux éléments mis en place. */
+static void g_bitap_backend_output_stats(const GBitapBackend *);
+
+
+
+/* ---------------------- OPTIMISATIONS POUR ARCHITECTURE AVX2 ---------------------- */
+
+
+#ifdef HAVE_AVX2
+
+/* Indique la valeur portée par une expression rationnelle. */
+static void extend_grouped_strings_avx2(grouped_strings_avx2_t ***, size_t *);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+static patid_t enroll_plain_pattern_avx2(GBitapBackend *, GScanContext *, const bin_t *, size_t);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+static void run_scan_avx2(const GBitapBackend *, GScanContext *, const bin_t *, phys_t);
+
+#endif
+
+
+
+/* --------------------- OPTIMISATIONS POUR ARCHITECTURE AVX512 --------------------- */
+
+
+#ifdef HAVE_AVX512_F
+
+/* Indique la valeur portée par une expression rationnelle. */
+static void extend_grouped_strings_avx512(grouped_strings_avx512_t ***, size_t *);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+static patid_t enroll_plain_pattern_avx512(GBitapBackend *, GScanContext *, const bin_t *, size_t);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+static void run_scan_avx512(const GBitapBackend *, GScanContext *, const bin_t *, phys_t);
+
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLANTATION D'UNE NOUVELLE APPROCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+G_DEFINE_TYPE(GBitapBackend, g_bitap_backend, G_TYPE_ENGINE_BACKEND);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des méthodes basée sur Bitmap. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bitap_backend_class_init(GBitapBackendClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GEngineBackendClass *backend; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_bitap_backend_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_bitap_backend_finalize;
+
+ backend = G_ENGINE_BACKEND_CLASS(klass);
+
+ backend->get_max_size = (get_backend_atom_max_size_fc)g_bitap_backend_get_atom_max_size;
+ backend->enroll_plain = (enroll_plain_into_backend_fc)g_bitap_backend_enroll_plain_pattern;
+ backend->run_scan = (run_backend_scan_fc)g_bitap_backend_run_scan;
+ backend->output = (output_backend_stats_fc)g_bitap_backend_output_stats;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance à initialiser. *
+* *
+* Description : Initialise une instance de méthodes basée sur Bitmap. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bitap_backend_init(GBitapBackend *backend)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bitap_backend_dispose(GBitapBackend *backend)
+{
+ G_OBJECT_CLASS(g_bitap_backend_parent_class)->dispose(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bitap_backend_finalize(GBitapBackend *backend)
+{
+ G_OBJECT_CLASS(g_bitap_backend_parent_class)->finalize(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une méthode de recherche basée sur l'algorithme Bitap. *
+* *
+* Retour : Méthode mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GEngineBackend *g_bitap_backend_new(void)
+{
+ GBitapBackend *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_BITAP_BACKEND, NULL);
+
+ return G_ENGINE_BACKEND(result);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Indique la taille maximale des suites d'octets recherchées. *
+* *
+* Retour : Valeur strictement positive. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_bitap_backend_get_atom_max_size(const GBitapBackend *backend)
+{
+ size_t result; /* Taille à faire connaître */
+
+ result = BITAP_ATOM_SIZE;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = contexte de l'analyse à mener. *
+* plain = chaîne de caractères classique à intégrer. *
+* len = taille de cette chaîne. *
+* *
+* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static patid_t g_bitap_backend_enroll_plain_pattern(GBitapBackend *backend, GScanContext *context, const uint8_t *plain, size_t len)
+{
+ patid_t result; /* Identifiant à retourner */
+
+#ifdef HAVE_AVX512_F
+ if (0)
+ result = enroll_plain_pattern_avx512(backend, context, plain, len);
+ else
+#endif
+
+#ifdef HAVE_AVX2
+ if (0)
+ result = enroll_plain_pattern_avx2(backend, context, plain, len);
+ else
+#endif
+
+ result = INVALID_PATTERN_ID;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bitap_backend_run_scan(const GBitapBackend *backend, GScanContext *context)
+{
+ cpu_set_t old_mask; /* Cartographie des CPU #1 */
+ int ret; /* Bilan d'un appel */
+ unsigned int cpu; /* Processeur courant */
+ cpu_set_t new_mask; /* Cartographie des CPU #2 */
+ GBinContent *content; /* Contenu binaire manipulé */
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+
+ ret = sched_getaffinity(0, sizeof(cpu_set_t), &old_mask);
+
+ if (ret != 0)
+ {
+ LOG_ERROR_N("sched_getaffinity");
+ goto exit;
+ }
+
+ ret = getcpu(&cpu, NULL);
+
+ if (ret != 0)
+ {
+ LOG_ERROR_N("get_cpu");
+ goto exit;
+ }
+
+ CPU_ZERO(&new_mask);
+ CPU_SET(cpu, &new_mask);
+
+ ret = sched_setaffinity(0, sizeof(cpu_set_t), &new_mask);
+
+ if (ret != 0)
+ {
+ LOG_ERROR_N("sched_setaffinity");
+ goto exit;
+ }
+
+ content = g_scan_context_get_content(context);
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ assert(data != NULL);
+
+
+
+
+#ifdef HAVE_AVX512_F
+ if (0)
+ run_scan_avx512(backend, context, data, dlen);
+ else
+#endif
+
+#ifdef HAVE_AVX2
+ if (0)
+ run_scan_avx2(backend, context, data, dlen);
+ else
+#endif
+
+ ;
+
+ g_object_unref(G_OBJECT(content));
+
+ exit:
+
+ ;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Imprime quelques faits quant aux éléments mis en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bitap_backend_output_stats(const GBitapBackend *backend)
+{
+ printf("hello here!\n");
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* OPTIMISATIONS POUR ARCHITECTURE AVX2 */
+/* ---------------------------------------------------------------------------------- */
+
+
+/**
+ * Cf. https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=AVX,AVX2
+ */
+
+#ifdef HAVE_AVX2
+
+/******************************************************************************
+* *
+* Paramètres : strings = ensemble de groupes constitués. [OUT] *
+* count = nombre de groupes courant. [OUT] *
+* *
+* Description : Indique la valeur portée par une expression rationnelle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void extend_grouped_strings_avx2(grouped_strings_avx2_t ***strings, size_t *count)
+{
+ grouped_strings_avx2_t *new; /* Zone supplémentaire */
+ size_t i; /* Boucle de parcours */
+
+ /* Définition d'un nouvel élément vierge */
+
+ new = aligned_alloc(256, sizeof(grouped_strings_avx2_t));
+
+ for (i = 0; i < 256; i++)
+ new->pattern_masks[i] = _mm256_set1_epi8(~0);
+
+ new->found_masks = _mm256_set1_epi8(~0);
+
+ new->R = _mm256_set1_epi8(~1);
+
+ for (i = 0; i < 32; i++)
+ {
+ new->m[i] = 0;
+
+ new->found_id[i] = INVALID_PATTERN_ID;
+
+ }
+
+ new->available = 32;
+ new->used = 0;
+
+ /* Inscription */
+
+ *strings = realloc(*strings, ++(*count) * sizeof(grouped_strings_avx2_t *));
+
+ (*strings)[*count - 1] = new;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = contexte de l'analyse à mener. *
+* plain = chaîne de caractères classique à intégrer. *
+* plen = taille de cette chaîne. *
+* *
+* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
+* *
+* Retour : Indice de résultats pour le motif. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static patid_t enroll_plain_pattern_avx2(GBitapBackend *backend, GScanContext *context, const bin_t *plain, size_t plen)
+{
+ patid_t result; /* Identifiant à retourner */
+ grouped_strings_avx2_t ***strings; /* Groupe de chaînes visé */
+ size_t *count; /* Taille de ce groupe */
+ grouped_strings_avx2_t *last; /* Dernier groupe à remplir */
+ size_t n; /* Indice dans le groupe */
+ size_t i; /* Boucle de parcours */
+ __m256i *letter; /* Lettre à marquer */
+
+ /* Sélection du groupe de travail adéquat */
+
+ strings = &backend->manager_avx2.strings_8;
+ count = &backend->manager_avx2.count_8;
+
+ /* Préparation de la place nécessaire */
+
+ if (*count == 0)
+ {
+ extend_grouped_strings_avx2(strings, count);
+
+ last = (*strings)[0];
+
+ }
+
+ else
+ {
+ last = (*strings)[*count - 1];
+
+ if (last->used == last->available)
+ {
+ extend_grouped_strings_avx2(strings, count);
+ last = (*strings)[*count - 1];
+ }
+
+ }
+
+ /* Intégration d'une nouvelle chaîne */
+
+ n = last->used++;
+
+ last->m[n] = plen;
+
+ result = 0; // FIXME g_scan_context_get_new_pattern_id(context);
+
+ last->found_id[n] = result;
+
+ ((uint8_t *)&last->found_masks)[n] = (1 << plen);
+
+ for (i = 0; i < plen; i++)
+ {
+ letter = last->pattern_masks + plain[i];
+ ((uint8_t *)letter)[n] &= ~(1 << i);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* data = données à analyser. *
+* dlen = quantité de ces données. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, const bin_t *data, phys_t dlen)
+{
+ const group_manager_avx2_t *manager; /* Accès simplifié */
+
+ register __m256i zero asm("ymm11"); /* Constante 0 sur 256 bits */
+ size_t k; /* Boucle de parcours #1 */
+ grouped_strings_avx2_t group; /* Copie pour accès locaux */
+
+ register __m256i R asm("ymm12"); /* Résultats courants */
+ register __m256i found_masks asm("ymm10"); /* Vérifications accélérées */
+
+ //__m256i pre_shift_mask; /* Préparation de décalage */
+ //phys_t i; /* Boucle de parcours #2 */
+
+
+
+
+ const bin_t *iter;
+ const bin_t *maxiter;
+ //phys_t i; /* Boucle de parcours #2 */
+
+ volatile register __m256i xxxx; /* Test de correspondances */
+
+
+ __m256i test; /* Test de correspondances */
+ __m256i test2; /* Test de correspondances */
+ __m256i status; /* Statut d'une comparaison */
+
+ int masks[10];
+
+ int mask; /* Masque d'accès rapide */
+ size_t j; /* Boucle de parcours #3 */
+
+
+ int ret;
+
+ //return;
+
+ /* Initialisations diverses */
+
+ manager = &backend->manager_avx2;
+
+ zero = _mm256_set1_epi16(0);
+
+ asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop;nop;");
+
+ xxxx = _mm256_set1_epi8(~1);
+
+ asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop;nop;");
+
+ /* Recherches des chaînes de moins de 8 caractères */
+
+ printf(" --- manager->count_8: %zu\n", manager->count_8);
+
+ ret = 0;
+
+ for (k = 0; k < manager->count_8; k++)
+ {
+ memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx2_t));
+
+ //printf(" --- group.used: %zu\n", group.used);
+
+
+ asm volatile
+ (
+ /*
+ * R = _mm256_set1_epi8(~1);
+ *
+ */
+
+ "movabs $0xfefefefefefefefe, %%rax ; "
+ "vpbroadcastq %%rax, %[STATE] ; "
+
+ /*
+ *
+ */
+
+ "vmovdqa %[FOUND_SRC], %[FOUND_DST] ; "
+
+ : [STATE] "=v"(R),
+ [FOUND_DST] "=v"(found_masks)
+ : [FOUND_SRC] "m"(group.found_masks)
+ : "memory", "rax"
+
+ );
+
+
+
+
+ //pre_shift_mask = _mm256_set1_epi8(0xef);
+
+ maxiter = data + dlen;
+
+
+
+ for (iter = data; (iter + 10) < maxiter; iter += 10)
+ {
+
+ //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter);
+
+
+ asm volatile
+ (
+#if 0
+
+ /*
+ * R = _mm256_or_si256(R, group.pattern_masks[data[i]]);
+ *
+ * Latency : 1-9
+ * Throughput : 0.5
+ * #Uops : 1-2
+ * Port Usage : 1*p015+1*p23
+ *
+ */
+
+ "vpor %[PATTERN], %[STATE], %[STATE] ; "
+
+#else
+
+ /*
+ * %ymm = group.pattern_masks[data[i]];
+ *
+ * Latency : 5-8
+ * Throughput : 0.5
+ * #Uops : 1
+ * Port Usage : 1*p23
+ *
+ */
+
+ "vmovdqa %[PATTERN0], %%ymm0 ; "
+ "vmovdqa %[PATTERN1], %%ymm1 ; "
+ "vmovdqa %[PATTERN2], %%ymm2 ; "
+ "vmovdqa %[PATTERN3], %%ymm3 ; "
+ "vmovdqa %[PATTERN4], %%ymm4 ; "
+ "vmovdqa %[PATTERN5], %%ymm5 ; "
+ "vmovdqa %[PATTERN6], %%ymm6 ; "
+ "vmovdqa %[PATTERN7], %%ymm7 ; "
+ "vmovdqa %[PATTERN7], %%ymm8 ; "
+ "vmovdqa %[PATTERN7], %%ymm9 ; "
+
+ /*
+ * R = _mm256_or_si256(R, %ymm);
+ *
+ * Latency : 1
+ * Throughput : 0.33
+ * #Uops : 1
+ * Port Usage : 1*p015
+ *
+ */
+
+ "vpor %%ymm0, %[STATE], %[STATE] ; "
+
+#endif
+
+ /*
+ * R = _mm256_add_epi8(R, R);
+ *
+ * Latency : 1
+ * Throughput : 0.3
+ * #Uops : 1
+ * Port Usage : 1*p015
+ *
+ */
+
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ /*
+ * test = _mm256_and_si256(R, group.found_masks);
+ *
+ * Latency : 1
+ * Throughput : 0.33
+ * #Uops : 1
+ * Port Usage : 1*p015
+ *
+ */
+
+ "vpand %[FOUND], %[STATE], %%ymm0 ; "
+
+ /* Déroulemets... */
+
+ "vpor %%ymm1, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm2, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm3, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm4, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm5, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm6, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm7, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm8, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpor %%ymm9, %[STATE], %[STATE] ; "
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ "vpand %[FOUND], %[STATE], %%ymm1 ; "
+ "vpand %[FOUND], %[STATE], %%ymm2 ; "
+ "vpand %[FOUND], %[STATE], %%ymm3 ; "
+ "vpand %[FOUND], %[STATE], %%ymm4 ; "
+ "vpand %[FOUND], %[STATE], %%ymm5 ; "
+ "vpand %[FOUND], %[STATE], %%ymm6 ; "
+ "vpand %[FOUND], %[STATE], %%ymm7 ; "
+ "vpand %[FOUND], %[STATE], %%ymm8 ; "
+ "vpand %[FOUND], %[STATE], %%ymm9 ; "
+
+
+
+
+
+ /*
+ * status = _mm256_cmpeq_epi8(test, zero);
+ *
+ * Latency : 1
+ * Throughput : 0.5
+ * #Uops : 1
+ * Port Usage : 1*p01
+ *
+ */
+
+ "vpcmpeqb %%ymm0, %[NUL], %%ymm0 ; "
+
+ /*
+ * mask = _mm256_movemask_epi8(status);
+ *
+ * Latency : <5
+ * Throughput : 1
+ * #Uops : 1
+ * Port Usage : 1*p0
+ *
+ */
+
+ "vpmovmskb %%ymm0, %[MASK0] ; "
+
+
+
+
+
+ "vpcmpeqb %%ymm1, %[NUL], %%ymm1 ; "
+ "vpcmpeqb %%ymm2, %[NUL], %%ymm2 ; "
+ "vpcmpeqb %%ymm3, %[NUL], %%ymm3 ; "
+ "vpcmpeqb %%ymm4, %[NUL], %%ymm4 ; "
+ "vpcmpeqb %%ymm5, %[NUL], %%ymm5 ; "
+ "vpcmpeqb %%ymm6, %[NUL], %%ymm6 ; "
+ "vpcmpeqb %%ymm7, %[NUL], %%ymm7 ; "
+ "vpcmpeqb %%ymm8, %[NUL], %%ymm8 ; "
+ "vpcmpeqb %%ymm9, %[NUL], %%ymm9 ; "
+
+
+ "vpmovmskb %%ymm1, %[MASK1] ; "
+ "vpmovmskb %%ymm2, %[MASK2] ; "
+ "vpmovmskb %%ymm3, %[MASK3] ; "
+ "vpmovmskb %%ymm4, %[MASK4] ; "
+ "vpmovmskb %%ymm5, %[MASK5] ; "
+ "vpmovmskb %%ymm6, %[MASK6] ; "
+ "vpmovmskb %%ymm7, %[MASK7] ; "
+ "vpmovmskb %%ymm8, %[MASK8] ; "
+ "vpmovmskb %%ymm9, %[MASK9] ; "
+
+
+
+
+
+
+
+
+
+
+ //"vmovdqa %%ymm7, %[OUTPUT] ; "
+
+ //"vmovdqa %%ymm8, %[OUTPUT2] ; "
+
+ : [STATE] "+v"(R),
+ [OUTPUT] "=v"(test),
+ [OUTPUT2] "=v"(test2),
+ [MASK0] "=r"(mask),
+ [MASK1] "=r"(mask),
+ [MASK2] "=r"(mask),
+ [MASK3] "=r"(mask),
+ [MASK4] "=r"(mask),
+ [MASK5] "=r"(mask),
+ [MASK6] "=r"(mask),
+ [MASK7] "=r"(mask),
+ [MASK8] "=r"(mask),
+ [MASK9] "=r"(mask),
+ [NUL] "+v"(zero)
+ : [PATTERN0] "m"(group./*manager->strings_8[k]->*/pattern_masks[*iter]),
+ [PATTERN1] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 1)]),
+ [PATTERN2] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 2)]),
+ [PATTERN3] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 3)]),
+ [PATTERN4] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 4)]),
+ [PATTERN5] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 5)]),
+ [PATTERN6] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 6)]),
+ [PATTERN7] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 7)]),
+ [PATTERN8] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 8)]),
+ [PATTERN9] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 9)]),
+ [FOUND] "v"(found_masks)
+ : "memory", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9"
+
+ );
+
+
+ /*
+ printf(" test: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n",
+ ((uint8_t *)&test)[0],
+ ((uint8_t *)&test)[1],
+ ((uint8_t *)&test)[2],
+ ((uint8_t *)&test)[3],
+ ((uint8_t *)&test)[4],
+ ((uint8_t *)&test)[5],
+ ((uint8_t *)&test)[6],
+ ((uint8_t *)&test)[7],
+ ((uint8_t *)&test)[16],
+ ((uint8_t *)&test)[17],
+ ((uint8_t *)&test)[18],
+ ((uint8_t *)&test)[19]);
+
+ printf(" test2: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n",
+ ((uint8_t *)&test2)[0],
+ ((uint8_t *)&test2)[1],
+ ((uint8_t *)&test2)[2],
+ ((uint8_t *)&test2)[3],
+ ((uint8_t *)&test2)[4],
+ ((uint8_t *)&test2)[5],
+ ((uint8_t *)&test2)[6],
+ ((uint8_t *)&test2)[7],
+ ((uint8_t *)&test2)[16],
+ ((uint8_t *)&test2)[17],
+ ((uint8_t *)&test2)[18],
+ ((uint8_t *)&test2)[19]);
+ */
+
+#if 0
+ //printf(" > %c\n", data[i]);
+
+ R = _mm256_or_si256(R, group.pattern_masks[*iter]);
+
+ //printf("group pattern: %hhx\n", *((uint8_t *)&group.pattern_masks[data[i]]));
+
+ //printf("R: %hhx\n", *((uint8_t *)&R));
+
+ //R = _mm256_and_si256(R, pre_shift_mask);
+
+ //printf("R after and: %hhx\n", *((uint8_t *)&R));
+
+ R = _mm256_add_epi8(R, R);
+ //R = _mm256_slli_si256(R, 1);
+
+ //printf("R after shift: %hhx\n", *((uint8_t *)&R));
+
+ test = _mm256_and_si256(R, group.found_masks);
+
+#if 1
+ status = _mm256_cmpeq_epi8(test, zero);
+
+ mask = _mm256_movemask_epi8(status);
+#else
+ //mask = _mm256_movemask_epi8(test) ^ 0xffffffff;
+ mask = _mm256_movemask_epi8(test);
+#endif
+
+
+#endif
+
+
+ //printf(" mask : %x\n", mask);
+
+ if (mask != 0)
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == 1)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ /** TODO : update call
+ g_scan_context_register_atom_match(context,
+ group.found_id[j],
+ (iter - data) + 1 - group.m[j]);
+ **/
+
+ }
+
+ mask >>= 1;
+
+ }
+
+ }
+
+
+
+
+
+#if 0
+ for (; iter < maxiter; iter++)
+ {
+
+ //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter);
+
+
+ asm volatile
+ (
+ /*
+ * R = _mm256_or_si256(R, group.pattern_masks[data[i]]);
+ *
+ * Latency : 1
+ * Throughput : 0.33
+ * #Uops : 1
+ * Port Usage : 1*p015
+ *
+ */
+
+ "vpor %[PATTERN], %[STATE], %[STATE] ; "
+
+ /*
+ * R = _mm256_add_epi8(R, R);
+ *
+ * Latency : 1
+ * Throughput : 0.3
+ * #Uops : 1
+ * Port Usage : 1*p015
+ *
+ */
+
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ /*
+ * test = _mm256_and_si256(R, group.found_masks);
+ *
+ * Latency : 1
+ * Throughput : 0.33
+ * #Uops : 1
+ * Port Usage : 1*p015
+ *
+ */
+
+ "vpand %[FOUND], %[STATE], %%ymm7 ; "
+
+ /*
+ * status = _mm256_cmpeq_epi8(test, zero);
+ *
+ * Latency : 1
+ * Throughput : 0.5
+ * #Uops : 1
+ * Port Usage : 1*p01
+ *
+ */
+
+ "vpcmpeqb %%ymm7, %[NUL], %%ymm8 ; "
+
+ /*
+ * mask = _mm256_movemask_epi8(status);
+ *
+ * Latency : <5
+ * Throughput : 1
+ * #Uops : 1
+ * Port Usage : 1*p0
+ *
+ */
+
+ "vpmovmskb %%ymm8, %[MASK0] ; "
+
+
+ //"vmovdqa %%ymm7, %[OUTPUT] ; "
+
+ //"vmovdqa %%ymm8, %[OUTPUT2] ; "
+
+ : [STATE] "+v"(R),
+ [OUTPUT] "=v"(test),
+ [OUTPUT2] "=v"(test2),
+ [MASK0] "=r"(mask),
+ [NUL] "+v"(zero)
+ : [PATTERN] "m"(group./*manager->strings_8[k]->*/pattern_masks[*iter]),
+ [FOUND] "v"(found_masks)
+ : "memory", "ymm7", "ymm8"
+
+ );
+
+
+ /*
+ printf(" test: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n",
+ ((uint8_t *)&test)[0],
+ ((uint8_t *)&test)[1],
+ ((uint8_t *)&test)[2],
+ ((uint8_t *)&test)[3],
+ ((uint8_t *)&test)[4],
+ ((uint8_t *)&test)[5],
+ ((uint8_t *)&test)[6],
+ ((uint8_t *)&test)[7],
+ ((uint8_t *)&test)[16],
+ ((uint8_t *)&test)[17],
+ ((uint8_t *)&test)[18],
+ ((uint8_t *)&test)[19]);
+
+ printf(" test2: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n",
+ ((uint8_t *)&test2)[0],
+ ((uint8_t *)&test2)[1],
+ ((uint8_t *)&test2)[2],
+ ((uint8_t *)&test2)[3],
+ ((uint8_t *)&test2)[4],
+ ((uint8_t *)&test2)[5],
+ ((uint8_t *)&test2)[6],
+ ((uint8_t *)&test2)[7],
+ ((uint8_t *)&test2)[16],
+ ((uint8_t *)&test2)[17],
+ ((uint8_t *)&test2)[18],
+ ((uint8_t *)&test2)[19]);
+ */
+
+#if 0
+ //printf(" > %c\n", data[i]);
+
+ R = _mm256_or_si256(R, group.pattern_masks[*iter]);
+
+ //printf("group pattern: %hhx\n", *((uint8_t *)&group.pattern_masks[data[i]]));
+
+ //printf("R: %hhx\n", *((uint8_t *)&R));
+
+ //R = _mm256_and_si256(R, pre_shift_mask);
+
+ //printf("R after and: %hhx\n", *((uint8_t *)&R));
+
+ R = _mm256_add_epi8(R, R);
+ //R = _mm256_slli_si256(R, 1);
+
+ //printf("R after shift: %hhx\n", *((uint8_t *)&R));
+
+ test = _mm256_and_si256(R, group.found_masks);
+
+#if 1
+ status = _mm256_cmpeq_epi8(test, zero);
+
+ mask = _mm256_movemask_epi8(status);
+#else
+ //mask = _mm256_movemask_epi8(test) ^ 0xffffffff;
+ mask = _mm256_movemask_epi8(test);
+#endif
+
+
+#endif
+
+
+ //printf(" mask : %x\n", mask);
+
+ if (mask != 0)
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == 1)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ /** TODO : update call
+ g_scan_context_register_atom_match(context,
+ group.found_id[j],
+ (iter - data) + 1 - group.m[j]);
+ **/
+
+ }
+
+ mask >>= 1;
+
+ }
+
+ }
+
+#endif
+
+
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if 0
+
+
+#if 0
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* content = données binaires à analyser. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, GBinContent *content)
+{
+ const group_manager_avx2_t *manager; /* Accès simplifié */
+
+ grouped_strings_avx2_t groups[10]; /* Copie pour accès locaux */
+
+
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+ __m256i zero; /* Constante 0 sur 256 bits */
+ size_t k; /* Boucle de parcours #1 */
+
+ grouped_strings_avx2_t group; /* Copie pour accès locaux */
+ __m256i R; /* Résultats courants */
+ __m256i pre_shift_mask; /* Préparation de décalage */
+ phys_t i; /* Boucle de parcours #2 */
+ __m256i test; /* Test de correspondances */
+ __m256i status; /* Statut d'une comparaison */
+ int mask; /* Masque d'accès rapide */
+ size_t j; /* Boucle de parcours #3 */
+
+ uint32_t leaves;
+ int ret;
+
+
+ phys_t old_i;
+ phys_t p;
+
+ //return;
+
+ /* Initialisations diverses */
+
+ manager = &backend->manager_avx2;
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ zero = _mm256_set1_epi16(0);
+
+ /* Recherches des chaînes de moins de 8 caractères */
+
+ printf(" --- manager->count_8: %zu\n", manager->count_8);
+
+ ret = 0;
+
+ //for (k = 0; k < manager->count_8; k++)
+ // memcpy(&groups[k], manager->strings_8[k], sizeof(grouped_strings_avx2_t));
+
+
+ for (i = 0; i < dlen; )
+ {
+
+ //printf(" --- %llx\n", (unsigned long long)i);
+
+ p = i + 4096;
+
+ if (p > dlen)
+ p = dlen;
+
+ old_i = i;
+
+ printf("old_i: %llx\n", (unsigned long long)old_i);
+
+ for (k = 0; k < manager->count_8; k++)
+ {
+
+ group = *manager->strings_8[k];
+
+ R = group.R;
+
+ for (i = old_i ; i < p; i++)
+ {
+
+ //group = &groups[k];
+
+ //printf(" k: %zu i: %llx\n", k, (unsigned long long)i);
+
+ //R = group.R;//_mm256_set1_epi8(~1);
+
+ R = _mm256_or_si256(R, group.pattern_masks[data[i]]);
+
+ R = _mm256_add_epi8(R, R);
+
+ test = _mm256_and_si256(R, group.found_masks);
+
+#if 0
+ status = _mm256_cmpeq_epi8(test, zero);
+
+ mask = _mm256_movemask_epi8(status);
+#else
+ //mask = _mm256_movemask_epi8(test) ^ 0xffffffff;
+ mask = _mm256_movemask_epi8(test);
+#endif
+
+ if (mask != 0xffffffff)
+ {
+ leaves = group.leaves;
+
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == 0)
+ {
+ if (leaves & 0x1) //group.leaves & (1u << j))
+ ;//define_full_match_avx2(backend, context, content, &group, j, i + 1);
+
+ }
+
+ mask >>= 1;
+
+ leaves >>= 1;
+
+ }
+
+ }
+
+ group.R = R;//_mm256_set1_epi8(~1);
+
+ memcpy(manager->strings_8[k], &group, sizeof(grouped_strings_avx2_t));
+
+ }
+
+
+ }
+
+ }
+
+ printf("oh: %d\n", ret);
+
+
+}
+
+
+#else
+
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* content = données binaires à analyser. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, GBinContent *content)
+{
+ const group_manager_avx2_t *manager; /* Accès simplifié */
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+ __m256i zero; /* Constante 0 sur 256 bits */
+ size_t k; /* Boucle de parcours #1 */
+ grouped_strings_avx2_t group; /* Copie pour accès locaux */
+ __m256i R; /* Résultats courants */
+ __m256i pre_shift_mask; /* Préparation de décalage */
+ phys_t i; /* Boucle de parcours #2 */
+ __m256i test; /* Test de correspondances */
+ __m256i status; /* Statut d'une comparaison */
+ int mask; /* Masque d'accès rapide */
+ size_t j; /* Boucle de parcours #3 */
+
+ uint32_t leaves;
+ int ret;
+
+ //return;
+
+ /* Initialisations diverses */
+
+ manager = &backend->manager_avx2;
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ zero = _mm256_set1_epi16(0);
+
+ /* Recherches des chaînes de moins de 8 caractères */
+
+ printf(" --- manager->count_8: %zu\n", manager->count_8);
+
+ ret = 0;
+
+ for (k = 0; k < manager->count_8; k++)
+ {
+ memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx2_t));
+
+ //printf(" --- group.used: %zu\n", group.used);
+
+ R = _mm256_set1_epi8(~1);
+
+ //pre_shift_mask = _mm256_set1_epi8(0xef);
+
+ for (i = 0; i < dlen; ++i)
+ {
+ //printf(" > %c\n", data[i]);
+
+ R = _mm256_or_si256(R, group.pattern_masks[data[i]]);
+
+ //printf("group pattern: %hhx\n", *((uint8_t *)&group.pattern_masks[data[i]]));
+
+ //printf("R: %hhx\n", *((uint8_t *)&R));
+
+ //R = _mm256_and_si256(R, pre_shift_mask);
+
+ //printf("R after and: %hhx\n", *((uint8_t *)&R));
+
+ R = _mm256_add_epi8(R, R);
+ //R = _mm256_slli_si256(R, 1);
+
+ //printf("R after shift: %hhx\n", *((uint8_t *)&R));
+
+ test = _mm256_and_si256(R, group.found_masks);
+
+#if 0
+ status = _mm256_cmpeq_epi8(test, zero);
+
+ mask = _mm256_movemask_epi8(status);
+#else
+ //mask = _mm256_movemask_epi8(test) ^ 0xffffffff;
+ mask = _mm256_movemask_epi8(test);
+#endif
+
+ if (mask != 0xffffffff)
+ {
+ leaves = group.leaves;
+
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == 0)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ if (leaves & 0x1) //group.leaves & (1u << j))
+ define_full_match_avx2(backend, context, content, &group, j, i + 1);
+ //else
+ //{
+ // ret++;
+ //printf("%x\n", (unsigned int)i + 1);
+ //}
+ //else
+ // g_scan_context_register_sub_match(context, group.found_id[j], i + 1 - group.m[j]);
+
+ }
+
+ mask >>= 1;
+
+ leaves >>= 1;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ printf("oh: %d\n", ret);
+
+ /* Recherches des chaînes de moins de 16 caractères */
+
+ for (k = 0; k < manager->count_16; k++)
+ {
+ memcpy(&group, manager->strings_16[k], sizeof(grouped_strings_avx2_t));
+
+ R = _mm256_set1_epi16(~1);
+
+ for (i = 0; i < dlen; ++i)
+ {
+ R = _mm256_or_si256(R, group.pattern_masks[data[i]]);
+ R = _mm256_slli_epi16(R, 1);
+
+ test = _mm256_and_si256(R, group.found_masks);
+
+ status = _mm256_cmpeq_epi16(test, zero);
+
+ mask = _mm256_movemask_epi8(status);
+
+ if (mask != 0)
+ for (j = 0; j < group.used; j++)
+ {
+ if (mask & 0x3)
+ {
+ assert((i + 1) >= group.m[j]);
+
+ if (group.leaves & (1llu << j))
+ define_full_match_avx2(backend, context, content, &group, j, i + 1);
+ else
+ ;//g_scan_context_register_sub_match(context, group.found_id[j], i + 1 - group.m[j]);
+
+ }
+
+ mask >>= 2;
+
+ }
+
+ }
+
+ }
+
+}
+
+#endif
+
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* OPTIMISATIONS POUR ARCHITECTURE AVX512 */
+/* ---------------------------------------------------------------------------------- */
+
+
+/**
+ * Cf. https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=AVX_512
+ * - https://agner.org/optimize/
+ * - https://uops.info/table.html
+ */
+
+#ifdef HAVE_AVX512_F
+
+/******************************************************************************
+* *
+* Paramètres : strings = ensemble de groupes constitués. [OUT] *
+* count = nombre de groupes courant. [OUT] *
+* *
+* Description : Indique la valeur portée par une expression rationnelle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void extend_grouped_strings_avx512(grouped_strings_avx512_t ***strings, size_t *count)
+{
+ grouped_strings_avx512_t *new; /* Zone supplémentaire */
+ size_t i; /* Boucle de parcours */
+
+ /* Définition d'un nouvel élément vierge */
+
+ new = aligned_alloc(0x1000, sizeof(grouped_strings_avx512_t));
+
+ for (i = 0; i < 256; i++)
+ new->pattern_masks[i] = _mm512_set1_epi8(~0);
+
+ new->found_masks = _mm512_set1_epi8(~0);
+
+ new->R = _mm512_set1_epi8(~1);
+
+ for (i = 0; i < 64; i++)
+ {
+ new->m[i] = 0;
+
+ new->found_id[i] = INVALID_PATTERN_ID;
+
+ }
+
+ new->available = 64;
+ new->used = 0;
+
+ /* Inscription */
+
+ *strings = realloc(*strings, ++(*count) * sizeof(grouped_strings_avx512_t *));
+
+ (*strings)[*count - 1] = new;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = contexte de l'analyse à mener. *
+* plain = chaîne de caractères classique à intégrer. *
+* plen = taille de cette chaîne. *
+* *
+* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
+* *
+* Retour : Indice de résultats pour le motif. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static patid_t enroll_plain_pattern_avx512(GBitapBackend *backend, GScanContext *context, const bin_t *plain, size_t plen)
+{
+ patid_t result; /* Identifiant à retourner */
+ grouped_strings_avx512_t ***strings; /* Groupe de chaînes visé */
+ size_t *count; /* Taille de ce groupe */
+ grouped_strings_avx512_t *last; /* Dernier groupe à remplir */
+ size_t n; /* Indice dans le groupe */
+ size_t i; /* Boucle de parcours */
+ __m512i *letter; /* Lettre à marquer */
+
+ /* Sélection du groupe de travail adéquat */
+
+ strings = &backend->manager_avx512.strings_8;
+ count = &backend->manager_avx512.count_8;
+
+ /* Préparation de la place nécessaire */
+
+ if (*count == 0)
+ {
+ extend_grouped_strings_avx512(strings, count);
+
+ last = (*strings)[0];
+
+ }
+
+ else
+ {
+ last = (*strings)[*count - 1];
+
+ if (last->used == last->available)
+ {
+ extend_grouped_strings_avx512(strings, count);
+ last = (*strings)[*count - 1];
+ }
+
+ }
+
+ /* Intégration d'une nouvelle chaîne */
+
+ n = last->used++;
+
+ last->m[n] = plen;
+
+ result = 0; // FIXME g_scan_context_get_new_pattern_id(context);
+
+ last->found_id[n] = result;
+
+ ((uint8_t *)&last->found_masks)[n] = (1 << plen);
+
+ for (i = 0; i < plen; i++)
+ {
+ letter = last->pattern_masks + plain[i];
+ ((uint8_t *)letter)[n] &= ~(1 << i);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* data = données à analyser. *
+* dlen = quantité de ces données. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void run_scan_avx512(const GBitapBackend *backend, GScanContext *context, const bin_t *data, phys_t dlen)
+{
+ const group_manager_avx512_t *manager; /* Accès simplifié */
+
+ //register __m512i zero asm("zmm19"); /* Constante 0 sur 512 bits */
+
+ //__m512i shift8_mask; /* Masque pour décalage manuel */
+
+
+ size_t k; /* Boucle de parcours #1 */
+ /*__attribute__((aligned(0x1000)))*/ grouped_strings_avx512_t group; /* Copie pour accès locaux */
+ //void *grpptr;
+ //grouped_strings_avx512_t *_group; /* Copie pour accès locaux */
+
+ int ret;
+
+
+ register __m512i R asm("zmm28"); /* Résultats courants */
+ register __m512i found_masks asm("zmm21"); /* Vérifications accélérées */
+
+
+ register __mmask64 test_mask asm("k6");
+
+
+ register const bin_t *iter asm("rsi");
+ register const bin_t *maxiter/* asm("rdi")*/;
+ //phys_t i; /* Boucle de parcours #2 */
+
+
+ //__m512i test;
+
+ __mmask64 mask; /* Masque d'accès rapide */
+ size_t j; /* Boucle de parcours #3 */
+
+
+ /* Initialisations diverses */
+
+ manager = &backend->manager_avx512;
+
+
+
+
+ /* Recherches des chaînes de moins de 8 caractères */
+
+ //asm volatile ("nop; nop; nop; nop; nop; nop; nop; ");
+
+ //zero = _mm512_set1_epi8(0);
+
+ //asm volatile ("nop; nop; nop; nop; nop; nop; nop; ");
+
+ //shift8_mask = _mm512_set1_epi8(0x7f);
+
+
+
+#define WORK_ON_COPY
+
+ for (k = 0; k < manager->count_8; k++)
+ {
+#ifdef WORK_ON_COPY
+ memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t));
+
+#else
+
+ grpptr = alloca(sizeof(grouped_strings_avx512_t) + 0x1000);
+
+ _group = grpptr + 0x1000 - (((unsigned long)grpptr) % 0x1000);
+
+ //_group = manager->strings_8[k];
+
+ memcpy(_group, manager->strings_8[k], sizeof(grouped_strings_avx512_t));
+
+ ret = mlock(_group, sizeof(grouped_strings_avx512_t));
+
+ printf("ret = %d\n", ret);
+#endif
+
+
+
+ //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t));
+ //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t));
+
+
+ asm volatile
+ (
+ /*
+ * R = _mm512_set1_epi8(~1);
+ *
+ */
+
+ "movabs $0xfefefefefefefefe, %%rax ; "
+ "vpbroadcastq %%rax, %[STATE] ; "
+
+ "movabs $0xffffffffffffffff, %%rax ; "
+ "kmovq %%rax, %[KMASK] ; "
+
+ /*
+ *
+ */
+
+ "vmovdqa64 %[FOUND_SRC], %[FOUND_DST] ; "
+
+ : [STATE] "=v"(R),
+ [KMASK] "=Yk"(test_mask),
+ [FOUND_DST] "=v"(found_masks)
+#ifdef WORK_ON_COPY
+ : [FOUND_SRC] "m"(group.found_masks)
+#else
+ : [FOUND_SRC] "m"(_group->found_masks)
+#endif
+ : "memory", "rax"
+
+ );
+
+
+
+
+
+
+
+ //for (i = 0; i < dlen; i++)
+
+ maxiter = data + dlen;
+
+ for (iter = data; iter < maxiter; iter++)
+ {
+
+ //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter);
+
+
+ asm volatile goto
+ (
+ /*
+ * R = _mm512_or_si512(R, group.pattern_masks[*iter]);
+ *
+ * Latency : 1-9
+ * Throughput : 0.5
+ * #Uops : 1-2
+ * Port Usage : 1*p05+1*p23
+ *
+ */
+
+ "vpord %[PATTERN], %[STATE], %[STATE] ; "
+
+ /*
+ * R = _mm512_add_epi8(R, R);
+ *
+ * Latency : 1
+ * Throughput : 0.5
+ * #Uops : 1
+ * Port Usage : 1*p05
+ *
+ */
+
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ /*
+ * mask = _mm512_test_epi8_mask(R, group.found_masks);
+ *
+ * Latency : 3
+ * Throughput : 1
+ * #Uops : 2
+ * Port Usage : 1*p23+1*p5
+ *
+ */
+
+ /******************************
+ * Version 0
+
+ ******************/
+
+ //"vptestmb %[FOUND], %[STATE], %%k7 ; "
+
+ /******************************
+ * Version 1
+
+ "vmovdqa64 %[STATE], %%zmm12 ; "
+
+ "vptestmb %[FOUND], %%zmm12, %%k7 ; "
+
+ ******************/
+
+ /******************************
+ * Version 2
+
+ "vpandd %[STATE], %[FOUND], %%zmm12 ; "
+
+ "vpcmpneqb %[NUL], %%zmm12, %%k7 ; "
+
+ ******************/
+
+
+ "vmovdqa64 %[STATE], %%zmm12 ; "
+
+ "vptestmb %[FOUND], %%zmm12, %%k7 ; "
+
+
+ "ktestq %[KMASK], %%k7 ; "
+
+ "jc %l[next_iter] ; "
+
+
+
+
+
+ /*
+ * (suite)
+ *
+ * Latency : 3
+ * Throughput : 1
+ * #Uops : 1
+ * Port Usage : 1*p5
+ *
+ */
+
+ "kmovq %%k7, %[MASK0] ; "
+
+ //"vmovdqa64 %%zmm12, %[OUTPUT] ; "
+
+ //"nop; nop; nop; nop; nop; nop; nop; nop; "
+ //"nop; nop; nop; nop; nop; nop; nop; nop; "
+
+ : [STATE] "+v"(R),
+ //[OUTPUT] "=v"(test),
+ [MASK0] "=r"(mask)
+ //[NUL] "=v"(zero)
+#ifdef WORK_ON_COPY
+ : [PATTERN] "m"(group.pattern_masks[*iter]),
+#else
+ : [PATTERN] "m"(_group->pattern_masks[*iter]),
+#endif
+ [FOUND] "v"(found_masks),
+ [KMASK] "Yk"(test_mask)
+ : "memory", "k7", "zmm12"
+ : next_iter
+
+ );
+
+
+
+
+ /*
+ printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&group.found_masks)[0],
+ ((uint8_t *)&group.found_masks)[1],
+ ((uint8_t *)&group.found_masks)[2],
+ ((uint8_t *)&group.found_masks)[3],
+ ((uint8_t *)&group.found_masks)[4],
+ ((uint8_t *)&group.found_masks)[5],
+ ((uint8_t *)&group.found_masks)[6],
+ ((uint8_t *)&group.found_masks)[7]);
+
+
+ printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&test)[0],
+ ((uint8_t *)&test)[1],
+ ((uint8_t *)&test)[2],
+ ((uint8_t *)&test)[3],
+ ((uint8_t *)&test)[4],
+ ((uint8_t *)&test)[5],
+ ((uint8_t *)&test)[6],
+ ((uint8_t *)&test)[7]);
+
+
+ printf(" -> mask: 0x%llx\n", (unsigned long long)mask);
+ */
+
+
+#ifdef WORK_ON_COPY
+
+ //if (mask != 0xffffffffffffffffllu)
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == 0)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ /** TODO : update call
+ g_scan_context_register_atom_match(context,
+ group.found_id[j],
+ (iter - data) + 1 - group.m[j]);
+ **/
+
+ }
+
+ mask >>= 1;
+
+ }
+
+#else
+
+# error "WEFEF"
+
+ if (mask != 0xffffffffffffffffllu)
+ for (j = 0; j < _group->used; j++)
+ {
+ if ((mask & 0x1) == 0)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ /** TODO : update call
+ g_scan_context_register_atom_match(context,
+ _group->found_id[j],
+ (iter - data) + 1 - _group->m[j]);
+ **/
+
+ }
+
+ mask >>= 1;
+
+ }
+
+#endif
+
+
+ next_iter:
+
+ //;
+
+ //iter++;
+
+ }
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+#if 0
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* content = données binaires à analyser. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void run_scan_avx512____good_asm_perfs(const GBitapBackend *backend, GScanContext *context, GBinContent *content)
+{
+ const group_manager_avx512_t *manager; /* Accès simplifié */
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+
+
+ //__m512i shift8_mask; /* Masque pour décalage manuel */
+
+
+ size_t k; /* Boucle de parcours #1 */
+ grouped_strings_avx512_t group; /* Copie pour accès locaux */
+
+ register __m512i found_masks asm("zmm21"); /* Vérifications accélérées */
+
+
+ //register volatile __m512i zero/* asm("zmm19")*/; /* Constante 0 sur 512 bits */
+ register __m512i R asm("zmm28"); /* Résultats courants */
+
+ //int counter;
+
+ const bin_t *iter;
+ const bin_t *maxiter;
+ //phys_t i; /* Boucle de parcours #2 */
+
+
+ __m512i test;
+
+ __mmask64 mask; /* Masque d'accès rapide */
+ size_t j; /* Boucle de parcours #3 */
+
+
+ //register __m512i z30 asm("zmm30");
+
+
+ //return;
+
+
+ //counter = 0;
+
+ //return;
+
+ /* Initialisations diverses */
+
+ manager = &backend->manager_avx512;
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ /* Recherches des chaînes de moins de 8 caractères */
+
+ printf(" --- manager512->count_8: %zu\n", manager->count_8);
+
+ asm volatile ("nop; nop; nop; nop; nop; nop; nop; ");
+
+ //zero = _mm512_set1_epi8(0);
+
+ asm volatile ("nop; nop; nop; nop; nop; nop; nop; ");
+
+ //shift8_mask = _mm512_set1_epi8(0x7f);
+
+
+ for (k = 0; k < manager->count_8; k++)
+ {
+ memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t));
+
+
+
+
+ //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t));
+ //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t));
+
+
+ asm volatile
+ (
+ /*
+ * R = _mm512_set1_epi8(~1);
+ *
+ */
+
+ "movabs $0xfefefefefefefefe, %%rax ; "
+ "vpbroadcastq %%rax, %[STATE] ; "
+
+ /*
+ *
+ */
+
+ "vmovdqa64 %[FOUND_SRC], %[FOUND_DST] ; "
+
+ : [STATE] "=v"(R),
+ [FOUND_DST] "=v"(found_masks)
+ : [FOUND_SRC] "m"(group.found_masks)
+ : "memory", "rax"
+
+ );
+
+
+
+
+
+
+
+ //for (i = 0; i < dlen; i++)
+
+ maxiter = data + dlen;
+
+ for (iter = data; iter < maxiter; iter++)
+ {
+
+ //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter);
+
+
+ asm volatile
+ (
+
+ /*
+ * R = _mm512_or_si512(R, group.pattern_masks[*iter]);
+ *
+ * Latency : 1-9
+ * Throughput : 0.5
+ * #Uops : 1-2
+ * Port Usage : 1*p05+1*p23
+ *
+ */
+
+ "vpord %[PATTERN], %[STATE], %[STATE] ; "
+
+ /*
+ * R = _mm512_add_epi8(R, R);
+ *
+ * Latency : 1
+ * Throughput : 0.5
+ * #Uops : 1
+ * Port Usage : 1*p05
+ *
+ */
+
+ "vpaddb %[STATE], %[STATE], %[STATE] ; "
+
+ /*
+ * mask = _mm512_test_epi8_mask(R, group.found_masks);
+ *
+ * Latency : 3
+ * Throughput : 1
+ * #Uops : 2
+ * Port Usage : 1*p23+1*p5
+ *
+ */
+
+ /******************************
+ * Version 0
+
+ ******************/
+
+ "vptestmb %[FOUND], %[STATE], %%k7 ; "
+
+ /******************************
+ * Version 1
+
+ "vmovdqa64 %[STATE], %%zmm12 ; "
+
+ "vptestmb %[FOUND], %%zmm12, %%k0 ; "
+
+ ******************/
+
+ /******************************
+ * Version 2
+
+ "vpandd %[STATE], %[FOUND], %%zmm12 ; "
+
+ "vpcmpneqb %[NUL], %%zmm12, %%k7 ; "
+
+ ******************/
+
+ /*
+ * (suite)
+ *
+ * Latency : 3
+ * Throughput : 1
+ * #Uops : 1
+ * Port Usage : 1*p5
+ *
+ */
+
+ "kmovq %%k7, %[MASK0] ; "
+
+ //"vmovdqa64 %%zmm12, %[OUTPUT] ; "
+
+ //"nop; nop; nop; nop; nop; nop; nop; nop; "
+ //"nop; nop; nop; nop; nop; nop; nop; nop; "
+
+ : [STATE] "+v"(R),
+ [OUTPUT] "=v"(test),
+ [MASK0] "=r"(mask)/*,
+ [NUL] "+v"(zero)*/
+ : [PATTERN] "v"(group.pattern_masks[*iter]),
+ [FOUND] "v"(found_masks)
+ : "memory", "k0", "zmm12"
+
+ );
+
+
+
+
+ /*
+ printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&group.found_masks)[0],
+ ((uint8_t *)&group.found_masks)[1],
+ ((uint8_t *)&group.found_masks)[2],
+ ((uint8_t *)&group.found_masks)[3],
+ ((uint8_t *)&group.found_masks)[4],
+ ((uint8_t *)&group.found_masks)[5],
+ ((uint8_t *)&group.found_masks)[6],
+ ((uint8_t *)&group.found_masks)[7]);
+
+
+ printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&test)[0],
+ ((uint8_t *)&test)[1],
+ ((uint8_t *)&test)[2],
+ ((uint8_t *)&test)[3],
+ ((uint8_t *)&test)[4],
+ ((uint8_t *)&test)[5],
+ ((uint8_t *)&test)[6],
+ ((uint8_t *)&test)[7]);
+
+
+ printf(" -> mask: 0x%llx\n", (unsigned long long)mask);
+ */
+
+#if 0
+
+ /*
+ printf(" R: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&R)[0],
+ ((uint8_t *)&R)[1],
+ ((uint8_t *)&R)[2],
+ ((uint8_t *)&R)[3],
+ ((uint8_t *)&R)[4],
+ ((uint8_t *)&R)[5],
+ ((uint8_t *)&R)[6],
+ ((uint8_t *)&R)[7]);
+
+ printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&group.found_masks)[0],
+ ((uint8_t *)&group.found_masks)[1],
+ ((uint8_t *)&group.found_masks)[2],
+ ((uint8_t *)&group.found_masks)[3],
+ ((uint8_t *)&group.found_masks)[4],
+ ((uint8_t *)&group.found_masks)[5],
+ ((uint8_t *)&group.found_masks)[6],
+ ((uint8_t *)&group.found_masks)[7]);
+ */
+
+ /*
+
+ printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&test)[0],
+ ((uint8_t *)&test)[1],
+ ((uint8_t *)&test)[2],
+ ((uint8_t *)&test)[3],
+ ((uint8_t *)&test)[4],
+ ((uint8_t *)&test)[5],
+ ((uint8_t *)&test)[6],
+ ((uint8_t *)&test)[7]);
+
+ */
+
+#endif
+
+
+
+
+
+# define TEST_MASK 0xffffffffffffffffllu
+# define TEST_BIT 0
+
+
+ //printf("mask: %llx\n", (unsigned long long)mask);
+
+
+ if (mask != TEST_MASK)
+ {
+ //printf("mask: %llx\n", (unsigned long long)mask);
+
+ //counter++;
+ //printf("Ouhc: %p - %x\n", &group, *((uint8_t *)&mask));
+ //printf("Ouhc: %x\n", 1);
+ //asm("vzeroupper;");
+ //printf("Ouhc: %hhx\n", R[0]);
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == TEST_BIT)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ //printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1);
+ printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)(iter - data) + 1);
+
+
+ }
+
+ mask >>= 1;
+ //printf("> mask: %llx\n", (unsigned long long)mask);
+
+ }
+
+
+
+ }
+
+
+
+ }
+
+ //printf("%hhx\n", ((uint8_t *)&R)[0], ((uint8_t *)&mask)[0]);
+
+ }
+
+ //printf("counter=%d\n", counter);
+
+
+}
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* content = données binaires à analyser. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void run_scan_avx512_best_test(const GBitapBackend *backend, GScanContext *context, GBinContent *content)
+{
+ const group_manager_avx512_t *manager; /* Accès simplifié */
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+
+
+ //__m512i shift8_mask; /* Masque pour décalage manuel */
+
+
+ size_t k; /* Boucle de parcours #1 */
+ grouped_strings_avx512_t group; /* Copie pour accès locaux */
+
+ //register __m512i zero; /* Constante 0 sur 512 bits */
+ register __m512i R; /* Résultats courants */
+
+ //int counter;
+
+ const bin_t *iter;
+ const bin_t *maxiter;
+ //phys_t i; /* Boucle de parcours #2 */
+
+
+ //__m512i test;
+
+ __mmask64 mask; /* Masque d'accès rapide */
+ size_t j; /* Boucle de parcours #3 */
+
+ //return;
+
+
+ //counter = 0;
+
+ //return;
+
+ /* Initialisations diverses */
+
+ manager = &backend->manager_avx512;
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ /* Recherches des chaînes de moins de 8 caractères */
+
+ printf(" --- manager512->count_8: %zu\n", manager->count_8);
+
+ //zero = _mm512_set1_epi8(0);
+
+ //shift8_mask = _mm512_set1_epi8(0x7f);
+
+
+
+ for (k = 0; k < manager->count_8; k++)
+ {
+ memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t));
+
+ //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t));
+ //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t));
+
+ R = _mm512_set1_epi8(~1);
+
+
+
+ /* vpord zmm, zmm, zmm : latence 1, 1*p05 */
+ //R = _mm512_or_si512(R, group.pattern_masks[data[0]]);
+
+ //for (i = 0; i < dlen; i++)
+
+ maxiter = data + dlen;
+
+ for (iter = data; iter < maxiter; iter++)
+ {
+
+ //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter);
+
+
+ //R = _mm512_or_si512(R, group.pattern_masks[data[i]]);
+ R = _mm512_or_si512(R, group.pattern_masks[*iter]);
+
+
+#if 1
+ /* vpaddb zmm, zmm, zmm : latence 1, 1*p05 */
+ R = _mm512_add_epi8(R, R);
+#else
+ /* vpandd zmm, zmm, zmm : latence 1, 1*p5 */
+ R = _mm512_and_si512(R, shift8_mask);
+ /* vpslldq zmm, zmm, imm8 : latence 1, 1*p5 */
+ R = _mm512_bslli_epi128(R, 1);
+
+#endif
+
+ /*
+ printf(" R: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&R)[0],
+ ((uint8_t *)&R)[1],
+ ((uint8_t *)&R)[2],
+ ((uint8_t *)&R)[3],
+ ((uint8_t *)&R)[4],
+ ((uint8_t *)&R)[5],
+ ((uint8_t *)&R)[6],
+ ((uint8_t *)&R)[7]);
+
+ printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&group.found_masks)[0],
+ ((uint8_t *)&group.found_masks)[1],
+ ((uint8_t *)&group.found_masks)[2],
+ ((uint8_t *)&group.found_masks)[3],
+ ((uint8_t *)&group.found_masks)[4],
+ ((uint8_t *)&group.found_masks)[5],
+ ((uint8_t *)&group.found_masks)[6],
+ ((uint8_t *)&group.found_masks)[7]);
+ */
+
+#if 1
+ /* vptestmb k, zmm, zmm : latence 3, 1*p5 */
+ mask = _mm512_test_epi8_mask(R, group.found_masks);
+
+
+ //test = _mm512_add_epi64(R, zero);
+
+ //mask = _mm512_test_epi8_mask(test, group.found_masks);
+
+
+
+
+
+# define TEST_MASK 0xffffffffffffffffllu
+# define TEST_BIT 0
+
+ /* comparaison : != */
+
+
+#else
+ /* vpandd zmm, zmm, zmm : latence 1, 1*p05 */
+ test = _mm512_and_si512(R, group.found_masks);
+
+
+ printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&test)[0],
+ ((uint8_t *)&test)[1],
+ ((uint8_t *)&test)[2],
+ ((uint8_t *)&test)[3],
+ ((uint8_t *)&test)[4],
+ ((uint8_t *)&test)[5],
+ ((uint8_t *)&test)[6],
+ ((uint8_t *)&test)[7]);
+
+ /* vpmovb2m k, zmm : latence 3 (au lieu de 1 !?), 1*p0 */
+ //mask = _mm512_movepi8_mask(test);
+
+# define TEST_MASK 0
+# define TEST_BIT 0
+
+
+ //test = _mm512_popcnt_epi8(test);
+
+#endif
+
+
+ //printf(" final mask: %16llx\n", (unsigned long long)mask);
+
+
+
+ //R = _mm512_or_si512(R, group.pattern_masks[data[i + 1]]);
+
+#if 1
+
+
+ if (mask != TEST_MASK)
+ {
+ //counter++;
+ //printf("Ouhc: %p - %x\n", &group, *((uint8_t *)&mask));
+ printf("Ouhc: %p\n", &group);
+ //printf("Ouhc: %hhx\n", R[0]);
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == TEST_BIT)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ //printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1);
+ printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)(iter - data) + 1);
+
+
+ }
+
+ mask >>= 1;
+
+ }
+
+
+
+ }
+
+
+#else
+
+ if (_mm512_reduce_or_epi64(test) != 0)
+ {
+ for (j = 0; j < group.used; j++)
+ {
+ if (((uint8_t *)&test)[j] == 0)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1);
+
+ }
+
+
+ }
+
+ }
+
+#endif
+
+
+ }
+
+ //printf("%hhx\n", ((uint8_t *)&R)[0], ((uint8_t *)&mask)[0]);
+
+ }
+
+ //printf("counter=%d\n", counter);
+
+
+}
+
+
+
+
+
+static void run_scan_avx512__saved(const GBitapBackend *backend, GScanContext *context, GBinContent *content)
+{
+ const group_manager_avx512_t *manager; /* Accès simplifié */
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+
+
+ __m512i shift8_mask; /* Masque pour décalage manuel */
+
+
+ size_t k; /* Boucle de parcours #1 */
+ grouped_strings_avx512_t group; /* Copie pour accès locaux */
+
+
+ __m512i R; /* Résultats courants */
+
+ //int counter;
+
+ phys_t i; /* Boucle de parcours #2 */
+
+
+ __m512i test;
+
+ __mmask64 mask; /* Masque d'accès rapide */
+ size_t j; /* Boucle de parcours #3 */
+
+
+
+ //counter = 0;
+
+ //return;
+
+ /* Initialisations diverses */
+
+ manager = &backend->manager_avx512;
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ /* Recherches des chaînes de moins de 8 caractères */
+
+ printf(" --- manager512->count_8: %zu\n", manager->count_8);
+
+
+
+ shift8_mask = _mm512_set1_epi8(0x7f);
+
+
+ for (k = 0; k < manager->count_8; k++)
+ {
+ memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t));
+
+ //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t));
+ //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t));
+
+ R = _mm512_set1_epi8(~1);
+
+ /* vpord zmm, zmm, zmm : latence 1, 1*p05 */
+ R = _mm512_or_si512(R, group.pattern_masks[data[0]]);
+
+ for (i = 0; i < dlen; i++)
+ {
+
+ /*
+ printf("--- %llx <-> %c\n", (unsigned long long)i, data[i]);
+
+ printf(" R: %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&R)[0],
+ ((uint8_t *)&R)[1],
+ ((uint8_t *)&R)[2],
+ ((uint8_t *)&R)[3]);
+
+ printf(" mask: %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&group.pattern_masks[data[i]])[0],
+ ((uint8_t *)&group.pattern_masks[data[i]])[1],
+ ((uint8_t *)&group.pattern_masks[data[i]])[2],
+ ((uint8_t *)&group.pattern_masks[data[i]])[3]);
+ */
+
+ //R = _mm512_or_si512(R, group.pattern_masks[data[i]]);
+
+ /*
+ printf(" R: %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&R)[0],
+ ((uint8_t *)&R)[1],
+ ((uint8_t *)&R)[2],
+ ((uint8_t *)&R)[3]);
+ */
+
+#if 1
+ /* vpaddb zmm, zmm, zmm : latence 1, 1*p05 */
+ R = _mm512_add_epi8(R, R);
+#else
+ /* vpandd zmm, zmm, zmm : latence 1, 1*p5 */
+ R = _mm512_and_si512(R, shift8_mask);
+ /* vpslldq zmm, zmm, imm8 : latence 1, 1*p5 */
+ R = _mm512_bslli_epi128(R, 1);
+
+#endif
+
+#if 1
+ /* vptestmb k, zmm, zmm : latence 3, 1*p5 */
+ mask = _mm512_test_epi8_mask(R, group.found_masks);
+#else
+ test = _mm512_and_si512(R, group.found_masks);
+ test = _mm512_popcnt_epi8(test);
+
+#endif
+
+ /*
+ printf(" found mask: %hhx %hhx %hhx %hhx\n",
+ ((uint8_t *)&group.found_masks)[0],
+ ((uint8_t *)&group.found_masks)[1],
+ ((uint8_t *)&group.found_masks)[2],
+ ((uint8_t *)&group.found_masks)[3]);
+
+ printf(" final mask: %16llx\n", (unsigned long long)mask);
+ */
+
+
+ R = _mm512_or_si512(R, group.pattern_masks[data[i + 1]]);
+
+#if 1
+
+ if (mask != 0xffffffffffffffffllu)
+ {
+ //counter++;
+ //printf("Ouhc: %p - %x\n", &group, *((uint8_t *)&mask));
+ //printf("Ouhc: %p\n", &group);
+ for (j = 0; j < group.used; j++)
+ {
+ if ((mask & 0x1) == 0)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1);
+
+
+ }
+
+ mask >>= 1;
+
+ }
+
+
+
+ }
+
+
+#else
+
+ if (_mm512_reduce_or_epi64(test) != 0)
+ {
+ for (j = 0; j < group.used; j++)
+ {
+ if (((uint8_t *)&test)[j] == 0)
+ {
+ //assert((i + 1) >= group.m[j]);
+
+ printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1);
+
+ }
+
+
+ }
+
+ }
+
+#endif
+
+
+ }
+
+ //printf("%hhx\n", ((uint8_t *)&R)[0], ((uint8_t *)&mask)[0]);
+
+ }
+
+ //printf("counter=%d\n", counter);
+
+
+}
+#endif
+
+
+
+#endif
diff --git a/src/analysis/scan/patterns/backends/bitap.h b/src/analysis/scan/patterns/backends/bitap.h
new file mode 100644
index 0000000..1cb384c
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/bitap.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bitap.h - prototypes pour la méthode de recherche basée sur l'algorithme Bitap
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "../backend.h"
+
+
+
+#define G_TYPE_BITAP_BACKEND g_bitap_backend_get_type()
+#define G_BITAP_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BITAP_BACKEND, GBitapBackend))
+#define G_IS_BITAP_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BITAP_BACKEND))
+#define G_BITAP_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BITAP_BACKEND, GBitapBackendClass))
+#define G_IS_BITAP_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BITAP_BACKEND))
+#define G_BITAP_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BITAP_BACKEND, GBitapBackendClass))
+
+
+/* Méthode de recherche basée sur l'algorithme Bitap (instance) */
+typedef struct _GBitapBackend GBitapBackend;
+
+/* Méthode de recherche basée sur l'algorithme Bitap (classe) */
+typedef struct _GBitapBackendClass GBitapBackendClass;
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+GType g_bitap_backend_get_type(void);
+
+/* Crée une méthode de recherche basée sur l'algorithme Bitap. */
+GEngineBackend *g_bitap_backend_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H */
diff --git a/src/analysis/scan/patterns/backends/hyperscan-int.h b/src/analysis/scan/patterns/backends/hyperscan-int.h
new file mode 100644
index 0000000..31d271b
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/hyperscan-int.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hyperscan-int.h - prototypes internes pour la méthode de recherche basée sur la bibliothèque Hyperscan d'Intel
+ *
+ * Copyright (C) 2024 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_INT_H
+
+
+#include "hyperscan.h"
+
+
+#include "../backend-int.h"
+
+
+
+#define EXPR_COVERAGE_START 0
+#define EXPR_COVERAGE_COUNT 1
+#define EXPR_COVERAGE_END 1
+
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (instance) */
+struct _GHyperscanBackend
+{
+ GEngineBackend parent; /* A laisser en premier */
+
+ const uint8_t **atoms; /* Motif remarquable */
+ size_t *lengths; /* Nombre d'octets considérés */
+ uint32_t *coverages; /* Départ et quantité de suivis*/
+ size_t allocated; /* Nombre d'éléments alloués */
+ size_t used; /* Nombre d'éléments utiles */
+
+ unsigned int *lit_ids; /* Identifiants internes */
+
+ hs_database_t *database; /* Compilation d'éléments */
+ hs_scratch_t *scratch; /* Espace de travail */
+
+};
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (classe) */
+struct _GHyperscanBackendClass
+{
+ GEngineBackendClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_INT_H */
diff --git a/src/analysis/scan/patterns/backends/hyperscan.c b/src/analysis/scan/patterns/backends/hyperscan.c
new file mode 100644
index 0000000..40a7372
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/hyperscan.c
@@ -0,0 +1,1063 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hyperscan.c - méthode de recherche basée sur la bibliothèque Hyperscan d'Intel
+ *
+ * Copyright (C) 2024 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hyperscan.h"
+
+
+#include <hs.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include "hyperscan-int.h"
+#include "../../../../core/logs.h"
+#include "../../../../glibext/umemslice.h" /* REMME */
+
+
+
+/* ---------------------- IMPLANTATION D'UNE NOUVELLE APPROCHE ---------------------- */
+
+
+/* Initialise la classe des méthodes basée sur Hyperscan. */
+static void g_hyperscan_backend_class_init(GHyperscanBackendClass *);
+
+/* Initialise une instance de méthodes basée sur Hyperscan. */
+static void g_hyperscan_backend_init(GHyperscanBackend *);
+
+/* Supprime toutes les références externes. */
+static void g_hyperscan_backend_dispose(GHyperscanBackend *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_hyperscan_backend_finalize(GHyperscanBackend *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/**
+ * for i in range(int(8192 / 25) + 1):
+ * print(','.join([ '% 5u' % (i * 25 + k) for k in range(25) ]) + ',')
+ */
+static const unsigned int __cached_ids[8200] = {
+
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
+ 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+ 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
+ 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349,
+ 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
+ 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424,
+ 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449,
+ 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474,
+ 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499,
+ 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524,
+ 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549,
+ 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574,
+ 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599,
+ 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624,
+ 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649,
+ 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674,
+ 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699,
+ 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724,
+ 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749,
+ 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774,
+ 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799,
+ 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824,
+ 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849,
+ 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874,
+ 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899,
+ 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924,
+ 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949,
+ 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974,
+ 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999,
+ 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024,
+ 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049,
+ 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074,
+ 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099,
+ 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124,
+ 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149,
+ 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174,
+ 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199,
+ 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224,
+ 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249,
+ 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274,
+ 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299,
+ 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324,
+ 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349,
+ 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374,
+ 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399,
+ 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424,
+ 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449,
+ 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474,
+ 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499,
+ 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524,
+ 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549,
+ 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574,
+ 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599,
+ 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624,
+ 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649,
+ 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674,
+ 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699,
+ 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, 1722, 1723, 1724,
+ 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749,
+ 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774,
+ 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799,
+ 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824,
+ 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849,
+ 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874,
+ 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899,
+ 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924,
+ 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949,
+ 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974,
+ 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024,
+ 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049,
+ 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074,
+ 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099,
+ 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124,
+ 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149,
+ 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174,
+ 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199,
+ 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224,
+ 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249,
+ 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274,
+ 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299,
+ 2300, 2301, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324,
+ 2325, 2326, 2327, 2328, 2329, 2330, 2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345, 2346, 2347, 2348, 2349,
+ 2350, 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, 2359, 2360, 2361, 2362, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374,
+ 2375, 2376, 2377, 2378, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, 2394, 2395, 2396, 2397, 2398, 2399,
+ 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2423, 2424,
+ 2425, 2426, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449,
+ 2450, 2451, 2452, 2453, 2454, 2455, 2456, 2457, 2458, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474,
+ 2475, 2476, 2477, 2478, 2479, 2480, 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, 2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499,
+ 2500, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524,
+ 2525, 2526, 2527, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549,
+ 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574,
+ 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 2583, 2584, 2585, 2586, 2587, 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599,
+ 2600, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624,
+ 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649,
+ 2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674,
+ 2675, 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699,
+ 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, 2718, 2719, 2720, 2721, 2722, 2723, 2724,
+ 2725, 2726, 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2734, 2735, 2736, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749,
+ 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2774,
+ 2775, 2776, 2777, 2778, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799,
+ 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824,
+ 2825, 2826, 2827, 2828, 2829, 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, 2849,
+ 2850, 2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, 2859, 2860, 2861, 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874,
+ 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899,
+ 2900, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924,
+ 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938, 2939, 2940, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949,
+ 2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, 2973, 2974,
+ 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 2999,
+ 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024,
+ 3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049,
+ 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074,
+ 3075, 3076, 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, 3098, 3099,
+ 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124,
+ 3125, 3126, 3127, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149,
+ 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174,
+ 3175, 3176, 3177, 3178, 3179, 3180, 3181, 3182, 3183, 3184, 3185, 3186, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3199,
+ 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213, 3214, 3215, 3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224,
+ 3225, 3226, 3227, 3228, 3229, 3230, 3231, 3232, 3233, 3234, 3235, 3236, 3237, 3238, 3239, 3240, 3241, 3242, 3243, 3244, 3245, 3246, 3247, 3248, 3249,
+ 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3260, 3261, 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, 3270, 3271, 3272, 3273, 3274,
+ 3275, 3276, 3277, 3278, 3279, 3280, 3281, 3282, 3283, 3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293, 3294, 3295, 3296, 3297, 3298, 3299,
+ 3300, 3301, 3302, 3303, 3304, 3305, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3320, 3321, 3322, 3323, 3324,
+ 3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, 3335, 3336, 3337, 3338, 3339, 3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349,
+ 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3371, 3372, 3373, 3374,
+ 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399,
+ 3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424,
+ 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448, 3449,
+ 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473, 3474,
+ 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3493, 3494, 3495, 3496, 3497, 3498, 3499,
+ 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 3524,
+ 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549,
+ 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, 3558, 3559, 3560, 3561, 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574,
+ 3575, 3576, 3577, 3578, 3579, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 3596, 3597, 3598, 3599,
+ 3600, 3601, 3602, 3603, 3604, 3605, 3606, 3607, 3608, 3609, 3610, 3611, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, 3620, 3621, 3622, 3623, 3624,
+ 3625, 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3640, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649,
+ 3650, 3651, 3652, 3653, 3654, 3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662, 3663, 3664, 3665, 3666, 3667, 3668, 3669, 3670, 3671, 3672, 3673, 3674,
+ 3675, 3676, 3677, 3678, 3679, 3680, 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3695, 3696, 3697, 3698, 3699,
+ 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 3712, 3713, 3714, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724,
+ 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749,
+ 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772, 3773, 3774,
+ 3775, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3786, 3787, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799,
+ 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 3814, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824,
+ 3825, 3826, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, 3848, 3849,
+ 3850, 3851, 3852, 3853, 3854, 3855, 3856, 3857, 3858, 3859, 3860, 3861, 3862, 3863, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 3872, 3873, 3874,
+ 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3888, 3889, 3890, 3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899,
+ 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3907, 3908, 3909, 3910, 3911, 3912, 3913, 3914, 3915, 3916, 3917, 3918, 3919, 3920, 3921, 3922, 3923, 3924,
+ 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, 3940, 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, 3949,
+ 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974,
+ 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, 3988, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999,
+ 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024,
+ 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, 4045, 4046, 4047, 4048, 4049,
+ 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 4060, 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074,
+ 4075, 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099,
+ 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4122, 4123, 4124,
+ 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149,
+ 4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174,
+ 4175, 4176, 4177, 4178, 4179, 4180, 4181, 4182, 4183, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194, 4195, 4196, 4197, 4198, 4199,
+ 4200, 4201, 4202, 4203, 4204, 4205, 4206, 4207, 4208, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4218, 4219, 4220, 4221, 4222, 4223, 4224,
+ 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249,
+ 4250, 4251, 4252, 4253, 4254, 4255, 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274,
+ 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, 4299,
+ 4300, 4301, 4302, 4303, 4304, 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324,
+ 4325, 4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4347, 4348, 4349,
+ 4350, 4351, 4352, 4353, 4354, 4355, 4356, 4357, 4358, 4359, 4360, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4372, 4373, 4374,
+ 4375, 4376, 4377, 4378, 4379, 4380, 4381, 4382, 4383, 4384, 4385, 4386, 4387, 4388, 4389, 4390, 4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399,
+ 4400, 4401, 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, 4418, 4419, 4420, 4421, 4422, 4423, 4424,
+ 4425, 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4435, 4436, 4437, 4438, 4439, 4440, 4441, 4442, 4443, 4444, 4445, 4446, 4447, 4448, 4449,
+ 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, 4470, 4471, 4472, 4473, 4474,
+ 4475, 4476, 4477, 4478, 4479, 4480, 4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, 4489, 4490, 4491, 4492, 4493, 4494, 4495, 4496, 4497, 4498, 4499,
+ 4500, 4501, 4502, 4503, 4504, 4505, 4506, 4507, 4508, 4509, 4510, 4511, 4512, 4513, 4514, 4515, 4516, 4517, 4518, 4519, 4520, 4521, 4522, 4523, 4524,
+ 4525, 4526, 4527, 4528, 4529, 4530, 4531, 4532, 4533, 4534, 4535, 4536, 4537, 4538, 4539, 4540, 4541, 4542, 4543, 4544, 4545, 4546, 4547, 4548, 4549,
+ 4550, 4551, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4559, 4560, 4561, 4562, 4563, 4564, 4565, 4566, 4567, 4568, 4569, 4570, 4571, 4572, 4573, 4574,
+ 4575, 4576, 4577, 4578, 4579, 4580, 4581, 4582, 4583, 4584, 4585, 4586, 4587, 4588, 4589, 4590, 4591, 4592, 4593, 4594, 4595, 4596, 4597, 4598, 4599,
+ 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4609, 4610, 4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624,
+ 4625, 4626, 4627, 4628, 4629, 4630, 4631, 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, 4640, 4641, 4642, 4643, 4644, 4645, 4646, 4647, 4648, 4649,
+ 4650, 4651, 4652, 4653, 4654, 4655, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4664, 4665, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4673, 4674,
+ 4675, 4676, 4677, 4678, 4679, 4680, 4681, 4682, 4683, 4684, 4685, 4686, 4687, 4688, 4689, 4690, 4691, 4692, 4693, 4694, 4695, 4696, 4697, 4698, 4699,
+ 4700, 4701, 4702, 4703, 4704, 4705, 4706, 4707, 4708, 4709, 4710, 4711, 4712, 4713, 4714, 4715, 4716, 4717, 4718, 4719, 4720, 4721, 4722, 4723, 4724,
+ 4725, 4726, 4727, 4728, 4729, 4730, 4731, 4732, 4733, 4734, 4735, 4736, 4737, 4738, 4739, 4740, 4741, 4742, 4743, 4744, 4745, 4746, 4747, 4748, 4749,
+ 4750, 4751, 4752, 4753, 4754, 4755, 4756, 4757, 4758, 4759, 4760, 4761, 4762, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773, 4774,
+ 4775, 4776, 4777, 4778, 4779, 4780, 4781, 4782, 4783, 4784, 4785, 4786, 4787, 4788, 4789, 4790, 4791, 4792, 4793, 4794, 4795, 4796, 4797, 4798, 4799,
+ 4800, 4801, 4802, 4803, 4804, 4805, 4806, 4807, 4808, 4809, 4810, 4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, 4820, 4821, 4822, 4823, 4824,
+ 4825, 4826, 4827, 4828, 4829, 4830, 4831, 4832, 4833, 4834, 4835, 4836, 4837, 4838, 4839, 4840, 4841, 4842, 4843, 4844, 4845, 4846, 4847, 4848, 4849,
+ 4850, 4851, 4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, 4860, 4861, 4862, 4863, 4864, 4865, 4866, 4867, 4868, 4869, 4870, 4871, 4872, 4873, 4874,
+ 4875, 4876, 4877, 4878, 4879, 4880, 4881, 4882, 4883, 4884, 4885, 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, 4894, 4895, 4896, 4897, 4898, 4899,
+ 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924,
+ 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949,
+ 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974,
+ 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, 4985, 4986, 4987, 4988, 4989, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999,
+ 5000, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024,
+ 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049,
+ 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074,
+ 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099,
+ 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, 5109, 5110, 5111, 5112, 5113, 5114, 5115, 5116, 5117, 5118, 5119, 5120, 5121, 5122, 5123, 5124,
+ 5125, 5126, 5127, 5128, 5129, 5130, 5131, 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139, 5140, 5141, 5142, 5143, 5144, 5145, 5146, 5147, 5148, 5149,
+ 5150, 5151, 5152, 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5163, 5164, 5165, 5166, 5167, 5168, 5169, 5170, 5171, 5172, 5173, 5174,
+ 5175, 5176, 5177, 5178, 5179, 5180, 5181, 5182, 5183, 5184, 5185, 5186, 5187, 5188, 5189, 5190, 5191, 5192, 5193, 5194, 5195, 5196, 5197, 5198, 5199,
+ 5200, 5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209, 5210, 5211, 5212, 5213, 5214, 5215, 5216, 5217, 5218, 5219, 5220, 5221, 5222, 5223, 5224,
+ 5225, 5226, 5227, 5228, 5229, 5230, 5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242, 5243, 5244, 5245, 5246, 5247, 5248, 5249,
+ 5250, 5251, 5252, 5253, 5254, 5255, 5256, 5257, 5258, 5259, 5260, 5261, 5262, 5263, 5264, 5265, 5266, 5267, 5268, 5269, 5270, 5271, 5272, 5273, 5274,
+ 5275, 5276, 5277, 5278, 5279, 5280, 5281, 5282, 5283, 5284, 5285, 5286, 5287, 5288, 5289, 5290, 5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, 5299,
+ 5300, 5301, 5302, 5303, 5304, 5305, 5306, 5307, 5308, 5309, 5310, 5311, 5312, 5313, 5314, 5315, 5316, 5317, 5318, 5319, 5320, 5321, 5322, 5323, 5324,
+ 5325, 5326, 5327, 5328, 5329, 5330, 5331, 5332, 5333, 5334, 5335, 5336, 5337, 5338, 5339, 5340, 5341, 5342, 5343, 5344, 5345, 5346, 5347, 5348, 5349,
+ 5350, 5351, 5352, 5353, 5354, 5355, 5356, 5357, 5358, 5359, 5360, 5361, 5362, 5363, 5364, 5365, 5366, 5367, 5368, 5369, 5370, 5371, 5372, 5373, 5374,
+ 5375, 5376, 5377, 5378, 5379, 5380, 5381, 5382, 5383, 5384, 5385, 5386, 5387, 5388, 5389, 5390, 5391, 5392, 5393, 5394, 5395, 5396, 5397, 5398, 5399,
+ 5400, 5401, 5402, 5403, 5404, 5405, 5406, 5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5421, 5422, 5423, 5424,
+ 5425, 5426, 5427, 5428, 5429, 5430, 5431, 5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5442, 5443, 5444, 5445, 5446, 5447, 5448, 5449,
+ 5450, 5451, 5452, 5453, 5454, 5455, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5469, 5470, 5471, 5472, 5473, 5474,
+ 5475, 5476, 5477, 5478, 5479, 5480, 5481, 5482, 5483, 5484, 5485, 5486, 5487, 5488, 5489, 5490, 5491, 5492, 5493, 5494, 5495, 5496, 5497, 5498, 5499,
+ 5500, 5501, 5502, 5503, 5504, 5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516, 5517, 5518, 5519, 5520, 5521, 5522, 5523, 5524,
+ 5525, 5526, 5527, 5528, 5529, 5530, 5531, 5532, 5533, 5534, 5535, 5536, 5537, 5538, 5539, 5540, 5541, 5542, 5543, 5544, 5545, 5546, 5547, 5548, 5549,
+ 5550, 5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, 5559, 5560, 5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5570, 5571, 5572, 5573, 5574,
+ 5575, 5576, 5577, 5578, 5579, 5580, 5581, 5582, 5583, 5584, 5585, 5586, 5587, 5588, 5589, 5590, 5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, 5599,
+ 5600, 5601, 5602, 5603, 5604, 5605, 5606, 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, 5615, 5616, 5617, 5618, 5619, 5620, 5621, 5622, 5623, 5624,
+ 5625, 5626, 5627, 5628, 5629, 5630, 5631, 5632, 5633, 5634, 5635, 5636, 5637, 5638, 5639, 5640, 5641, 5642, 5643, 5644, 5645, 5646, 5647, 5648, 5649,
+ 5650, 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, 5660, 5661, 5662, 5663, 5664, 5665, 5666, 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674,
+ 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682, 5683, 5684, 5685, 5686, 5687, 5688, 5689, 5690, 5691, 5692, 5693, 5694, 5695, 5696, 5697, 5698, 5699,
+ 5700, 5701, 5702, 5703, 5704, 5705, 5706, 5707, 5708, 5709, 5710, 5711, 5712, 5713, 5714, 5715, 5716, 5717, 5718, 5719, 5720, 5721, 5722, 5723, 5724,
+ 5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, 5739, 5740, 5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749,
+ 5750, 5751, 5752, 5753, 5754, 5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, 5763, 5764, 5765, 5766, 5767, 5768, 5769, 5770, 5771, 5772, 5773, 5774,
+ 5775, 5776, 5777, 5778, 5779, 5780, 5781, 5782, 5783, 5784, 5785, 5786, 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, 5795, 5796, 5797, 5798, 5799,
+ 5800, 5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, 5811, 5812, 5813, 5814, 5815, 5816, 5817, 5818, 5819, 5820, 5821, 5822, 5823, 5824,
+ 5825, 5826, 5827, 5828, 5829, 5830, 5831, 5832, 5833, 5834, 5835, 5836, 5837, 5838, 5839, 5840, 5841, 5842, 5843, 5844, 5845, 5846, 5847, 5848, 5849,
+ 5850, 5851, 5852, 5853, 5854, 5855, 5856, 5857, 5858, 5859, 5860, 5861, 5862, 5863, 5864, 5865, 5866, 5867, 5868, 5869, 5870, 5871, 5872, 5873, 5874,
+ 5875, 5876, 5877, 5878, 5879, 5880, 5881, 5882, 5883, 5884, 5885, 5886, 5887, 5888, 5889, 5890, 5891, 5892, 5893, 5894, 5895, 5896, 5897, 5898, 5899,
+ 5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909, 5910, 5911, 5912, 5913, 5914, 5915, 5916, 5917, 5918, 5919, 5920, 5921, 5922, 5923, 5924,
+ 5925, 5926, 5927, 5928, 5929, 5930, 5931, 5932, 5933, 5934, 5935, 5936, 5937, 5938, 5939, 5940, 5941, 5942, 5943, 5944, 5945, 5946, 5947, 5948, 5949,
+ 5950, 5951, 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, 5960, 5961, 5962, 5963, 5964, 5965, 5966, 5967, 5968, 5969, 5970, 5971, 5972, 5973, 5974,
+ 5975, 5976, 5977, 5978, 5979, 5980, 5981, 5982, 5983, 5984, 5985, 5986, 5987, 5988, 5989, 5990, 5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999,
+ 6000, 6001, 6002, 6003, 6004, 6005, 6006, 6007, 6008, 6009, 6010, 6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6019, 6020, 6021, 6022, 6023, 6024,
+ 6025, 6026, 6027, 6028, 6029, 6030, 6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, 6039, 6040, 6041, 6042, 6043, 6044, 6045, 6046, 6047, 6048, 6049,
+ 6050, 6051, 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, 6060, 6061, 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6074,
+ 6075, 6076, 6077, 6078, 6079, 6080, 6081, 6082, 6083, 6084, 6085, 6086, 6087, 6088, 6089, 6090, 6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099,
+ 6100, 6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109, 6110, 6111, 6112, 6113, 6114, 6115, 6116, 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124,
+ 6125, 6126, 6127, 6128, 6129, 6130, 6131, 6132, 6133, 6134, 6135, 6136, 6137, 6138, 6139, 6140, 6141, 6142, 6143, 6144, 6145, 6146, 6147, 6148, 6149,
+ 6150, 6151, 6152, 6153, 6154, 6155, 6156, 6157, 6158, 6159, 6160, 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, 6170, 6171, 6172, 6173, 6174,
+ 6175, 6176, 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, 6185, 6186, 6187, 6188, 6189, 6190, 6191, 6192, 6193, 6194, 6195, 6196, 6197, 6198, 6199,
+ 6200, 6201, 6202, 6203, 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 6212, 6213, 6214, 6215, 6216, 6217, 6218, 6219, 6220, 6221, 6222, 6223, 6224,
+ 6225, 6226, 6227, 6228, 6229, 6230, 6231, 6232, 6233, 6234, 6235, 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, 6244, 6245, 6246, 6247, 6248, 6249,
+ 6250, 6251, 6252, 6253, 6254, 6255, 6256, 6257, 6258, 6259, 6260, 6261, 6262, 6263, 6264, 6265, 6266, 6267, 6268, 6269, 6270, 6271, 6272, 6273, 6274,
+ 6275, 6276, 6277, 6278, 6279, 6280, 6281, 6282, 6283, 6284, 6285, 6286, 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294, 6295, 6296, 6297, 6298, 6299,
+ 6300, 6301, 6302, 6303, 6304, 6305, 6306, 6307, 6308, 6309, 6310, 6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, 6319, 6320, 6321, 6322, 6323, 6324,
+ 6325, 6326, 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, 6335, 6336, 6337, 6338, 6339, 6340, 6341, 6342, 6343, 6344, 6345, 6346, 6347, 6348, 6349,
+ 6350, 6351, 6352, 6353, 6354, 6355, 6356, 6357, 6358, 6359, 6360, 6361, 6362, 6363, 6364, 6365, 6366, 6367, 6368, 6369, 6370, 6371, 6372, 6373, 6374,
+ 6375, 6376, 6377, 6378, 6379, 6380, 6381, 6382, 6383, 6384, 6385, 6386, 6387, 6388, 6389, 6390, 6391, 6392, 6393, 6394, 6395, 6396, 6397, 6398, 6399,
+ 6400, 6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409, 6410, 6411, 6412, 6413, 6414, 6415, 6416, 6417, 6418, 6419, 6420, 6421, 6422, 6423, 6424,
+ 6425, 6426, 6427, 6428, 6429, 6430, 6431, 6432, 6433, 6434, 6435, 6436, 6437, 6438, 6439, 6440, 6441, 6442, 6443, 6444, 6445, 6446, 6447, 6448, 6449,
+ 6450, 6451, 6452, 6453, 6454, 6455, 6456, 6457, 6458, 6459, 6460, 6461, 6462, 6463, 6464, 6465, 6466, 6467, 6468, 6469, 6470, 6471, 6472, 6473, 6474,
+ 6475, 6476, 6477, 6478, 6479, 6480, 6481, 6482, 6483, 6484, 6485, 6486, 6487, 6488, 6489, 6490, 6491, 6492, 6493, 6494, 6495, 6496, 6497, 6498, 6499,
+ 6500, 6501, 6502, 6503, 6504, 6505, 6506, 6507, 6508, 6509, 6510, 6511, 6512, 6513, 6514, 6515, 6516, 6517, 6518, 6519, 6520, 6521, 6522, 6523, 6524,
+ 6525, 6526, 6527, 6528, 6529, 6530, 6531, 6532, 6533, 6534, 6535, 6536, 6537, 6538, 6539, 6540, 6541, 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549,
+ 6550, 6551, 6552, 6553, 6554, 6555, 6556, 6557, 6558, 6559, 6560, 6561, 6562, 6563, 6564, 6565, 6566, 6567, 6568, 6569, 6570, 6571, 6572, 6573, 6574,
+ 6575, 6576, 6577, 6578, 6579, 6580, 6581, 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, 6590, 6591, 6592, 6593, 6594, 6595, 6596, 6597, 6598, 6599,
+ 6600, 6601, 6602, 6603, 6604, 6605, 6606, 6607, 6608, 6609, 6610, 6611, 6612, 6613, 6614, 6615, 6616, 6617, 6618, 6619, 6620, 6621, 6622, 6623, 6624,
+ 6625, 6626, 6627, 6628, 6629, 6630, 6631, 6632, 6633, 6634, 6635, 6636, 6637, 6638, 6639, 6640, 6641, 6642, 6643, 6644, 6645, 6646, 6647, 6648, 6649,
+ 6650, 6651, 6652, 6653, 6654, 6655, 6656, 6657, 6658, 6659, 6660, 6661, 6662, 6663, 6664, 6665, 6666, 6667, 6668, 6669, 6670, 6671, 6672, 6673, 6674,
+ 6675, 6676, 6677, 6678, 6679, 6680, 6681, 6682, 6683, 6684, 6685, 6686, 6687, 6688, 6689, 6690, 6691, 6692, 6693, 6694, 6695, 6696, 6697, 6698, 6699,
+ 6700, 6701, 6702, 6703, 6704, 6705, 6706, 6707, 6708, 6709, 6710, 6711, 6712, 6713, 6714, 6715, 6716, 6717, 6718, 6719, 6720, 6721, 6722, 6723, 6724,
+ 6725, 6726, 6727, 6728, 6729, 6730, 6731, 6732, 6733, 6734, 6735, 6736, 6737, 6738, 6739, 6740, 6741, 6742, 6743, 6744, 6745, 6746, 6747, 6748, 6749,
+ 6750, 6751, 6752, 6753, 6754, 6755, 6756, 6757, 6758, 6759, 6760, 6761, 6762, 6763, 6764, 6765, 6766, 6767, 6768, 6769, 6770, 6771, 6772, 6773, 6774,
+ 6775, 6776, 6777, 6778, 6779, 6780, 6781, 6782, 6783, 6784, 6785, 6786, 6787, 6788, 6789, 6790, 6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799,
+ 6800, 6801, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, 6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822, 6823, 6824,
+ 6825, 6826, 6827, 6828, 6829, 6830, 6831, 6832, 6833, 6834, 6835, 6836, 6837, 6838, 6839, 6840, 6841, 6842, 6843, 6844, 6845, 6846, 6847, 6848, 6849,
+ 6850, 6851, 6852, 6853, 6854, 6855, 6856, 6857, 6858, 6859, 6860, 6861, 6862, 6863, 6864, 6865, 6866, 6867, 6868, 6869, 6870, 6871, 6872, 6873, 6874,
+ 6875, 6876, 6877, 6878, 6879, 6880, 6881, 6882, 6883, 6884, 6885, 6886, 6887, 6888, 6889, 6890, 6891, 6892, 6893, 6894, 6895, 6896, 6897, 6898, 6899,
+ 6900, 6901, 6902, 6903, 6904, 6905, 6906, 6907, 6908, 6909, 6910, 6911, 6912, 6913, 6914, 6915, 6916, 6917, 6918, 6919, 6920, 6921, 6922, 6923, 6924,
+ 6925, 6926, 6927, 6928, 6929, 6930, 6931, 6932, 6933, 6934, 6935, 6936, 6937, 6938, 6939, 6940, 6941, 6942, 6943, 6944, 6945, 6946, 6947, 6948, 6949,
+ 6950, 6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, 6969, 6970, 6971, 6972, 6973, 6974,
+ 6975, 6976, 6977, 6978, 6979, 6980, 6981, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, 6999,
+ 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024,
+ 7025, 7026, 7027, 7028, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, 7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049,
+ 7050, 7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063, 7064, 7065, 7066, 7067, 7068, 7069, 7070, 7071, 7072, 7073, 7074,
+ 7075, 7076, 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089, 7090, 7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099,
+ 7100, 7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, 7115, 7116, 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124,
+ 7125, 7126, 7127, 7128, 7129, 7130, 7131, 7132, 7133, 7134, 7135, 7136, 7137, 7138, 7139, 7140, 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, 7149,
+ 7150, 7151, 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, 7160, 7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7174,
+ 7175, 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, 7190, 7191, 7192, 7193, 7194, 7195, 7196, 7197, 7198, 7199,
+ 7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, 7221, 7222, 7223, 7224,
+ 7225, 7226, 7227, 7228, 7229, 7230, 7231, 7232, 7233, 7234, 7235, 7236, 7237, 7238, 7239, 7240, 7241, 7242, 7243, 7244, 7245, 7246, 7247, 7248, 7249,
+ 7250, 7251, 7252, 7253, 7254, 7255, 7256, 7257, 7258, 7259, 7260, 7261, 7262, 7263, 7264, 7265, 7266, 7267, 7268, 7269, 7270, 7271, 7272, 7273, 7274,
+ 7275, 7276, 7277, 7278, 7279, 7280, 7281, 7282, 7283, 7284, 7285, 7286, 7287, 7288, 7289, 7290, 7291, 7292, 7293, 7294, 7295, 7296, 7297, 7298, 7299,
+ 7300, 7301, 7302, 7303, 7304, 7305, 7306, 7307, 7308, 7309, 7310, 7311, 7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324,
+ 7325, 7326, 7327, 7328, 7329, 7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349,
+ 7350, 7351, 7352, 7353, 7354, 7355, 7356, 7357, 7358, 7359, 7360, 7361, 7362, 7363, 7364, 7365, 7366, 7367, 7368, 7369, 7370, 7371, 7372, 7373, 7374,
+ 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7385, 7386, 7387, 7388, 7389, 7390, 7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, 7399,
+ 7400, 7401, 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, 7411, 7412, 7413, 7414, 7415, 7416, 7417, 7418, 7419, 7420, 7421, 7422, 7423, 7424,
+ 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446, 7447, 7448, 7449,
+ 7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474,
+ 7475, 7476, 7477, 7478, 7479, 7480, 7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, 7499,
+ 7500, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524,
+ 7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, 7539, 7540, 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549,
+ 7550, 7551, 7552, 7553, 7554, 7555, 7556, 7557, 7558, 7559, 7560, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572, 7573, 7574,
+ 7575, 7576, 7577, 7578, 7579, 7580, 7581, 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 7594, 7595, 7596, 7597, 7598, 7599,
+ 7600, 7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, 7610, 7611, 7612, 7613, 7614, 7615, 7616, 7617, 7618, 7619, 7620, 7621, 7622, 7623, 7624,
+ 7625, 7626, 7627, 7628, 7629, 7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, 7641, 7642, 7643, 7644, 7645, 7646, 7647, 7648, 7649,
+ 7650, 7651, 7652, 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7665, 7666, 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674,
+ 7675, 7676, 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, 7685, 7686, 7687, 7688, 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699,
+ 7700, 7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, 7709, 7710, 7711, 7712, 7713, 7714, 7715, 7716, 7717, 7718, 7719, 7720, 7721, 7722, 7723, 7724,
+ 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, 7745, 7746, 7747, 7748, 7749,
+ 7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, 7761, 7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, 7771, 7772, 7773, 7774,
+ 7775, 7776, 7777, 7778, 7779, 7780, 7781, 7782, 7783, 7784, 7785, 7786, 7787, 7788, 7789, 7790, 7791, 7792, 7793, 7794, 7795, 7796, 7797, 7798, 7799,
+ 7800, 7801, 7802, 7803, 7804, 7805, 7806, 7807, 7808, 7809, 7810, 7811, 7812, 7813, 7814, 7815, 7816, 7817, 7818, 7819, 7820, 7821, 7822, 7823, 7824,
+ 7825, 7826, 7827, 7828, 7829, 7830, 7831, 7832, 7833, 7834, 7835, 7836, 7837, 7838, 7839, 7840, 7841, 7842, 7843, 7844, 7845, 7846, 7847, 7848, 7849,
+ 7850, 7851, 7852, 7853, 7854, 7855, 7856, 7857, 7858, 7859, 7860, 7861, 7862, 7863, 7864, 7865, 7866, 7867, 7868, 7869, 7870, 7871, 7872, 7873, 7874,
+ 7875, 7876, 7877, 7878, 7879, 7880, 7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, 7893, 7894, 7895, 7896, 7897, 7898, 7899,
+ 7900, 7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, 7910, 7911, 7912, 7913, 7914, 7915, 7916, 7917, 7918, 7919, 7920, 7921, 7922, 7923, 7924,
+ 7925, 7926, 7927, 7928, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7944, 7945, 7946, 7947, 7948, 7949,
+ 7950, 7951, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7959, 7960, 7961, 7962, 7963, 7964, 7965, 7966, 7967, 7968, 7969, 7970, 7971, 7972, 7973, 7974,
+ 7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7984, 7985, 7986, 7987, 7988, 7989, 7990, 7991, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999,
+ 8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007, 8008, 8009, 8010, 8011, 8012, 8013, 8014, 8015, 8016, 8017, 8018, 8019, 8020, 8021, 8022, 8023, 8024,
+ 8025, 8026, 8027, 8028, 8029, 8030, 8031, 8032, 8033, 8034, 8035, 8036, 8037, 8038, 8039, 8040, 8041, 8042, 8043, 8044, 8045, 8046, 8047, 8048, 8049,
+ 8050, 8051, 8052, 8053, 8054, 8055, 8056, 8057, 8058, 8059, 8060, 8061, 8062, 8063, 8064, 8065, 8066, 8067, 8068, 8069, 8070, 8071, 8072, 8073, 8074,
+ 8075, 8076, 8077, 8078, 8079, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, 8099,
+ 8100, 8101, 8102, 8103, 8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111, 8112, 8113, 8114, 8115, 8116, 8117, 8118, 8119, 8120, 8121, 8122, 8123, 8124,
+ 8125, 8126, 8127, 8128, 8129, 8130, 8131, 8132, 8133, 8134, 8135, 8136, 8137, 8138, 8139, 8140, 8141, 8142, 8143, 8144, 8145, 8146, 8147, 8148, 8149,
+ 8150, 8151, 8152, 8153, 8154, 8155, 8156, 8157, 8158, 8159, 8160, 8161, 8162, 8163, 8164, 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8174,
+ 8175, 8176, 8177, 8178, 8179, 8180, 8181, 8182, 8183, 8184, 8185, 8186, 8187, 8188, 8189, 8190, 8191, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199,
+
+};
+
+
+
+/* Indique la taille maximale des suites d'octets recherchées. */
+size_t g_hyperscan_backend_get_atom_max_size(const GHyperscanBackend *);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+static bool g_hyperscan_backend_enroll_plain_pattern(GHyperscanBackend *, const uint8_t *, size_t, uint32_t [2]);
+
+/* Met en ordre les derniers détails avant un premier scan. */
+static bool g_hyperscan_backend_warm_up(GHyperscanBackend *);
+
+/* Récupère les identifiants finaux pour un motif recherché. */
+static patid_t g_hyperscan_backend_build_plain_pattern_id(const GHyperscanBackend *, const uint32_t [2]);
+
+/* Détermine le nombre d'identifiants constitués. */
+static size_t g_hyperscan_backend_count_plain_pattern_ids(const GHyperscanBackend *);
+
+/* Informations utiles au traitement d'un événement */
+typedef struct _hyperscan_context_t
+{
+ const size_t *lengths; /* Nombre d'octets considérés */
+ const uint32_t *coverages; /* Départ et quantité de suivis*/
+
+#ifndef NDEBUG
+ size_t used; /* Nombre d'éléments utiles */
+ const unsigned int *lit_ids; /* Identifiants internes */
+#endif
+
+ GUMemSlice **matches; /* Zones d'enregistrements */
+
+} hyperscan_context_t;
+
+/* Prend note d'une correspondance trouvée par Hyperscan. */
+static int handle_hyperscan_match_event(unsigned int, unsigned long long, unsigned long long, unsigned int, GScanContext *context/*const hyperscan_context_t *context*/);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+static void g_hyperscan_backend_run_scan(const GHyperscanBackend *, GScanContext *);
+
+/* Imprime quelques faits quant aux éléments mis en place. */
+static void g_hyperscan_backend_output_stats(const GHyperscanBackend *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLANTATION D'UNE NOUVELLE APPROCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+G_DEFINE_TYPE(GHyperscanBackend, g_hyperscan_backend, G_TYPE_ENGINE_BACKEND);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des méthodes basée sur Hyperscan. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hyperscan_backend_class_init(GHyperscanBackendClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GEngineBackendClass *backend; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_hyperscan_backend_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_hyperscan_backend_finalize;
+
+ backend = G_ENGINE_BACKEND_CLASS(klass);
+
+ backend->get_max_size = (get_backend_atom_max_size_fc)g_hyperscan_backend_get_atom_max_size;
+ backend->enroll_plain = (enroll_plain_into_backend_fc)g_hyperscan_backend_enroll_plain_pattern;
+ backend->warm_up = (warm_up_backend_fc)g_hyperscan_backend_warm_up;
+ backend->build_id = (build_backend_plain_pattern_id_fc)g_hyperscan_backend_build_plain_pattern_id;
+ backend->count_ids = (count_backend_plain_pattern_ids_fc)g_hyperscan_backend_count_plain_pattern_ids;
+ backend->run_scan = (run_backend_scan_fc)g_hyperscan_backend_run_scan;
+ backend->output = (output_backend_stats_fc)g_hyperscan_backend_output_stats;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance à initialiser. *
+* *
+* Description : Initialise une instance de méthodes basée sur Hyperscan. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hyperscan_backend_init(GHyperscanBackend *backend)
+{
+ backend->atoms = NULL;
+ backend->lengths = NULL;
+ backend->coverages = NULL;
+ backend->allocated = 0;
+ backend->used = 0;
+
+ backend->database = NULL;
+ backend->scratch = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hyperscan_backend_dispose(GHyperscanBackend *backend)
+{
+ G_OBJECT_CLASS(g_hyperscan_backend_parent_class)->dispose(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hyperscan_backend_finalize(GHyperscanBackend *backend)
+{
+ if (backend->atoms != NULL)
+ free(backend->atoms);
+
+ if (backend->lengths != NULL)
+ free(backend->lengths);
+
+ if (backend->coverages != NULL)
+ free(backend->coverages);
+
+ if (backend->scratch != NULL)
+ hs_free_scratch(backend->scratch);
+
+ if (backend->database != NULL)
+ hs_free_database(backend->database);
+
+ G_OBJECT_CLASS(g_hyperscan_backend_parent_class)->finalize(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une méthode de recherche avec la bibliothèque Hyperscan.*
+* *
+* Retour : Méthode mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GEngineBackend *g_hyperscan_backend_new(void)
+{
+ GHyperscanBackend *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_HYPERSCAN_BACKEND, NULL);
+
+ return G_ENGINE_BACKEND(result);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Indique la taille maximale des suites d'octets recherchées. *
+* *
+* Retour : Valeur strictement positive. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_hyperscan_backend_get_atom_max_size(const GHyperscanBackend *backend)
+{
+ size_t result; /* Taille à faire connaître */
+
+ result = ~0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* plain = chaîne de caractères classique à intégrer. *
+* len = taille de cette chaîne. *
+* tmp_id = identifiants temporaires vers le motif. [OUT] *
+* *
+* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_hyperscan_backend_enroll_plain_pattern(GHyperscanBackend *backend, const uint8_t *plain, size_t len, uint32_t tmp_id[2])
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ int ret; /* Bilan d'une comparaison */
+
+ result = true;
+
+ /*Recherche d'un motif déjà sollicité */
+
+ i = backend->used;
+
+ /*
+ for (i = 0; i < backend->used; i++)
+ {
+ if (backend->lengths[i] != len)
+ continue;
+
+ ret = memcmp(backend->atoms[i], plain, backend->lengths[i]);
+
+ if (ret == 0)
+ {
+ tmp_id[0] = i;
+ tmp_id[1] = backend->coverages[i * 2 + EXPR_COVERAGE_COUNT];
+
+ backend->coverages[i * 2 + EXPR_COVERAGE_COUNT]++;
+ break;
+
+ }
+
+ }
+ */
+
+ /* Introduction d'un nouveau motif au besoin */
+
+ if (i == backend->used)
+ {
+ if (backend->used == backend->allocated)
+ {
+ if (backend->allocated == 0)
+ backend->allocated = 6400;
+ else
+ backend->allocated *= 2;
+
+ backend->atoms = realloc(backend->atoms, backend->allocated * sizeof(const uint8_t *));
+ backend->lengths = realloc(backend->lengths, backend->allocated * sizeof(size_t));
+ backend->coverages = realloc(backend->coverages, backend->allocated * 2 * sizeof(uint32_t));
+
+ }
+
+ backend->atoms[i] = plain;
+ backend->lengths[i] = len;
+ backend->coverages[i * 2 + EXPR_COVERAGE_COUNT] = 1;
+
+ backend->used++;
+
+ tmp_id[0] = i;
+ tmp_id[1] = 0;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à préparer. *
+* *
+* Description : Met en ordre les derniers détails avant un premier scan. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+#include <fcntl.h>
+#include "../../../../common/io.h"
+
+static bool g_hyperscan_backend_warm_up(GHyperscanBackend *backend)
+{
+ bool result; /* Bilan à retourner */
+ uint32_t current_start; /* Indice de gestionnaire */
+ size_t i; /* Boucle de parcours */
+ hs_compile_error_t *error; /* Compléments d'information */
+ hs_error_t ret; /* Code de retour */
+
+ hs_platform_info_t platform;
+
+ result = false;
+
+ /* Mise à jour de la couverture des gestionnaires de suivi */
+
+ current_start = 0;
+
+ for (i = 0; i < backend->used; i++)
+ {
+ backend->coverages[i * 2 + EXPR_COVERAGE_START] = current_start;
+ backend->coverages[i * 2 + EXPR_COVERAGE_END] += current_start;
+
+ current_start = backend->coverages[i * 2 + EXPR_COVERAGE_END];
+
+ }
+
+ /* Enregistrement des expressions à prendre en compte */
+
+#if 0
+ backend->lit_ids = malloc(backend->used * sizeof(unsigned));
+
+ for (i = 0; i < backend->used; i++)
+ backend->lit_ids[i] = i;
+
+#else
+
+ backend->lit_ids = __cached_ids;
+
+#endif
+
+
+ //hs_populate_platform(&platform);
+
+ //platform.tune = 1;
+
+ //platform.cpu_features = HS_CPU_FEATURES_AVX512;
+
+#if 0
+
+ ret = hs_compile_lit_multi((const char *const *)backend->atoms, NULL, backend->lit_ids, backend->lengths,
+ backend->used, HS_MODE_BLOCK, NULL, &backend->database, &error);
+
+
+ //printf("ret: %d -vs- %d\n", ret, HS_SUCCESS);
+
+ if (ret != HS_SUCCESS)
+ {
+ log_variadic_message(LMT_EXT_ERROR, _("Unable to compile %zu patterns: \"%s\""),
+ backend->used, error->message);
+ printf("FAILED: %s\n", error->message);
+ hs_free_compile_error(error);
+ goto exit;
+ }
+
+ do
+ {
+ char *bytes;
+ size_t length;
+ int fd;
+
+ ret = hs_serialize_database(backend->database, &bytes, &length);
+ printf("ret: %d -vs- %d\n", ret, HS_SUCCESS);
+
+ fd = open("/tmp/compiled.bin", O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ safe_write(fd, bytes, length);
+
+ close(fd);
+
+ }
+ while (0);
+
+
+#else
+
+ char *bytes;
+ size_t length;
+ bool status;
+ int fd;
+
+ length = 674216;
+ bytes = malloc(length);
+
+ fd = open("/tmp/compiled.bin", O_RDONLY);
+
+ status = safe_read(fd, bytes, length);
+
+ close(fd);
+
+ //printf("status: %d\n", status);
+
+ ret = hs_deserialize_database(bytes, length, &backend->database);
+ //printf("ret: %d -vs- %d\n", ret, HS_SUCCESS);
+
+
+
+#endif
+
+
+
+#if 0
+ do
+ {
+ //hs_platform_info_t platform;
+ char *__info;
+
+ //hs_populate_platform(&platform);
+
+ printf("TUNE: %u\n", platform.tune);
+
+ printf("CPU: %llx - AVX2? %d - AVX512? %d\n", platform.cpu_features,
+ platform.cpu_features & HS_CPU_FEATURES_AVX2,
+ platform.cpu_features & HS_CPU_FEATURES_AVX512);
+
+ hs_database_info(backend->database, &__info);
+
+ printf("INFO: %s\n", __info);
+
+ }
+ while (0);
+#endif
+
+ /* Création d'un espace de travail */
+
+ ret = hs_alloc_scratch(backend->database, &backend->scratch);
+
+ //printf("ret: %d -vs- %d\n", ret, HS_SUCCESS);
+
+ if (ret != HS_SUCCESS)
+ {
+ log_variadic_message(LMT_EXT_ERROR, _("Unable to allocate scratch space"));
+ goto exit;
+ }
+
+ result = true;
+
+ exit:
+
+ //printf("result: %d\n", result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* tmp_id = identifiants temporaires vers le motif. [OUT] *
+* *
+* Description : Récupère les identifiants finaux pour un motif recherché. *
+* *
+* Retour : Identifiant constitué ou INVALID_PATTERN_ID en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static patid_t g_hyperscan_backend_build_plain_pattern_id(const GHyperscanBackend *backend, const uint32_t tmp_id[2])
+{
+ patid_t result; /* Identifiant à retourner */
+ size_t index; /* Indice reconstitué */
+
+ assert(tmp_id[0] < backend->used);
+
+ index = tmp_id[0] * 2;
+
+ result = backend->coverages[index + EXPR_COVERAGE_START] + tmp_id[1];
+
+ assert(result < backend->coverages[index + EXPR_COVERAGE_END]);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* *
+* Description : Détermine le nombre d'identifiants constitués. *
+* *
+* Retour : Quantité de gestionnaires de suivi à prévoir. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static size_t g_hyperscan_backend_count_plain_pattern_ids(const GHyperscanBackend *backend)
+{
+ size_t result; /* Quantité à retourner */
+
+ if (backend->used == 0)
+ result = 0;
+ else
+ result = backend->coverages[(backend->used - 1) * 2 + EXPR_COVERAGE_END];
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* *
+* Description : Prend note d'une correspondance trouvée par Hyperscan. *
+* *
+* Retour : 0 afin de poursuivre les recherches. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int handle_hyperscan_match_event(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, GScanContext *context/*const hyperscan_context_t *context*/)
+{
+
+ g_scan_context_store_atom_match_end(context, id, to);
+
+ return 0;
+
+#if 0
+
+ phys_t offset; /* Point de départ établi */
+ const uint32_t *coverage_base; /* Base des suivis */
+ uint32_t k; /* Boucle de parcours */
+ uint32_t final_k; /* Dernier indice à traiter */
+
+ //return 0;
+
+#ifndef NDEBUG
+ assert(id < context->used);
+ assert(id == context->lit_ids[id]);
+#endif
+
+ offset = to - context->lengths[id];
+
+ coverage_base = context->coverages + id * 2;
+
+ k = coverage_base[EXPR_COVERAGE_START];
+ final_k = coverage_base[EXPR_COVERAGE_END];
+
+ for (; k < final_k; k++)
+ g_umem_slice_put_uint64(context->matches[0/*k*/], offset);
+
+ return 0;
+
+#endif
+
+}
+
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à manipuler. *
+* context = lieu d'enregistrement des résultats. *
+* *
+* Description : Parcours un contenu binaire à la recherche de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hyperscan_backend_run_scan(const GHyperscanBackend *backend, GScanContext *context)
+{
+ GBinContent *content; /* Contenu binaire manipulé */
+ phys_t dlen; /* Quantité de données */
+ vmpa2t pos; /* Point de départ ciblé */
+ const bin_t *data; /* Données à analyser */
+#ifndef NDEBUG
+ size_t count; /* Nombre de zones prévues */
+#endif
+ hyperscan_context_t hcontext; /* Rassemblement d'informations*/
+ GUMemSlice **matches; /* Zones d'enregistrements */
+ hs_error_t ret; /* Code de retour */
+
+ /* Récupération d'un accès aux données */
+
+ content = g_scan_context_get_content(context);
+
+ dlen = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &pos);
+ data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+ /* Préparation de l'accès aux éléments utiles */
+
+ hcontext.lengths = backend->lengths;
+ hcontext.coverages = backend->coverages;
+
+#ifndef NDEBUG
+ hcontext.used = backend->used;
+ hcontext.lit_ids = backend->lit_ids;
+#endif
+
+ /*
+#ifndef NDEBUG
+ matches = g_scan_context_get_match_storages(context, &count);
+ assert(count == backend->used);
+#else
+ matches = g_scan_context_get_match_storages(context, (size_t []){ 0 });
+#endif
+ */
+ matches = NULL; /* REMME */
+
+ hcontext.matches = matches;
+
+ /* Lancement de l'analyse */
+
+ ret = hs_scan(backend->database, (const char *)data, dlen,
+ 0 /* Arg. inutilisé */, backend->scratch,
+ (match_event_handler)handle_hyperscan_match_event, /*&h*/context);
+
+
+ //printf("ret ok? %d\n", ret == HS_SUCCESS);
+
+
+
+ g_object_unref(G_OBJECT(content));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = moteur de recherche à consulter. *
+* *
+* Description : Imprime quelques faits quant aux éléments mis en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hyperscan_backend_output_stats(const GHyperscanBackend *backend)
+{
+ printf("TODO: %s\n", __FUNCTION__);
+
+}
diff --git a/src/analysis/scan/patterns/backends/hyperscan.h b/src/analysis/scan/patterns/backends/hyperscan.h
new file mode 100644
index 0000000..d8c0f92
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/hyperscan.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hyperscan.h - prototypes pour la méthode de recherche basée sur la bibliothèque Hyperscan d'Intel
+ *
+ * Copyright (C) 2024 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "../backend.h"
+
+
+
+#define G_TYPE_HYPERSCAN_BACKEND g_hyperscan_backend_get_type()
+#define G_HYPERSCAN_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_HYPERSCAN_BACKEND, GHyperscanBackend))
+#define G_IS_HYPERSCAN_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_HYPERSCAN_BACKEND))
+#define G_HYPERSCAN_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_HYPERSCAN_BACKEND, GHyperscanBackendClass))
+#define G_IS_HYPERSCAN_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_HYPERSCAN_BACKEND))
+#define G_HYPERSCAN_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_HYPERSCAN_BACKEND, GHyperscanBackendClass))
+
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (instance) */
+typedef struct _GHyperscanBackend GHyperscanBackend;
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (classe) */
+typedef struct _GHyperscanBackendClass GHyperscanBackendClass;
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+GType g_hyperscan_backend_get_type(void);
+
+/* Crée une méthode de recherche avec la bibliothèque Hyperscan. */
+GEngineBackend *g_hyperscan_backend_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_H */
diff --git a/src/analysis/scan/patterns/customizer-int.h b/src/analysis/scan/patterns/customizer-int.h
new file mode 100644
index 0000000..9d49ab6
--- /dev/null
+++ b/src/analysis/scan/patterns/customizer-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * customizer-int.h - prototypes internes pour la modification paramétrée d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_CUSTOMIZER_INT_H
+#define _ANALYSIS_SCAN_CUSTOMIZER_INT_H
+
+
+#include "customizer.h"
+#include "modifier-int.h"
+
+
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (instance) */
+struct _GScanTokenCustomizer
+{
+ GScanTokenModifier parent; /* A laisser en premier */
+
+ GScanTokenModifier *effective; /* Modificateur effectif */
+
+ modifier_arg_t *args; /* Paramètres de transformation*/
+ size_t count; /* Quantité de ces paramètres */
+
+};
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (classe) */
+struct _GScanTokenCustomizerClass
+{
+ GScanTokenModifierClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un encadrement de transformation de motifs. */
+bool g_scan_token_customizer_create(GScanTokenCustomizer *, const modifier_arg_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_CUSTOMIZER_INT_H */
diff --git a/src/analysis/scan/patterns/customizer.c b/src/analysis/scan/patterns/customizer.c
new file mode 100644
index 0000000..9659957
--- /dev/null
+++ b/src/analysis/scan/patterns/customizer.c
@@ -0,0 +1,377 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * customizer.c - modification paramétrée d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "customizer.h"
+
+
+#include <malloc.h>
+
+
+#include "customizer-int.h"
+
+
+
+/* --------------------- TRANSFORMATION PERSONNALISEE DE MOTIFS --------------------- */
+
+
+/* Initialise la classe des transformations paramétrée. */
+static void g_scan_token_customizer_class_init(GScanTokenCustomizerClass *);
+
+/* Initialise une instance de transformation paramétrée. */
+static void g_scan_token_customizer_init(GScanTokenCustomizer *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_customizer_dispose(GScanTokenCustomizer *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_customizer_finalize(GScanTokenCustomizer *);
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_token_customizer_get_name(const GScanTokenCustomizer *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_token_customizer_transform(const GScanTokenCustomizer *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* TRANSFORMATION PERSONNALISEE DE MOTIFS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transformation personnalisée d'une séquence d'octets. */
+G_DEFINE_TYPE(GScanTokenCustomizer, g_scan_token_customizer, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transformations paramétrée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_customizer_class_init(GScanTokenCustomizerClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_customizer_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_customizer_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_token_customizer_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_token_customizer_transform;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : customizer = instance à initialiser. *
+* *
+* Description : Initialise une instance de transformation paramétrée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_customizer_init(GScanTokenCustomizer *customizer)
+{
+ customizer->effective = NULL;
+
+ customizer->args = NULL;
+ customizer->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : customizer = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_customizer_dispose(GScanTokenCustomizer *customizer)
+{
+ g_clear_object(&customizer->effective);
+
+ G_OBJECT_CLASS(g_scan_token_customizer_parent_class)->dispose(G_OBJECT(customizer));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : customizer = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_customizer_finalize(GScanTokenCustomizer *customizer)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < customizer->count; i++)
+ exit_mod_arg(&customizer->args[i]);
+
+ if (customizer->args != NULL)
+ free(customizer->args);
+
+ G_OBJECT_CLASS(g_scan_token_customizer_parent_class)->finalize(G_OBJECT(customizer));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = premier argument pour personnaliser l'opération. *
+* *
+* Description : Construit un encadrement de transformation de motifs. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_token_customizer_new(const modifier_arg_t *arg)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_CUSTOMIZER, NULL);
+
+ if (!g_scan_token_customizer_create(G_SCAN_TOKEN_CUSTOMIZER(result), arg))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : customizer = encadrement de motif à initialiser pleinement. *
+* arg = premier argument pour personnaliser l'opération.*
+* *
+* Description : Met en place un encadrement de transformation de motifs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_customizer_create(GScanTokenCustomizer *customizer, const modifier_arg_t *arg)
+{
+ g_scan_token_customizer_add_extra_arg(customizer, arg);
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : customizer = encadrement de motif à compléter. *
+* arg = nouvel argument pour personnaliser l'opération. *
+* *
+* Description : Ajoute un argument à l'encadrement de transformation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_customizer_add_extra_arg(GScanTokenCustomizer *customizer, const modifier_arg_t *arg)
+{
+ customizer->args = realloc(customizer->args, ++customizer->count * sizeof(modifier_arg_t));
+
+ copy_mod_arg(&customizer->args[customizer->count - 1], arg);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : customizer = encadrement de motif à compléter. *
+* modifier = modificateur de motifs à employer en sous-main. *
+* *
+* Description : Définit le transformateur effectif pour les motifs. *
+* *
+* Retour : true si le motificateur accepte les arguments courants. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_customizer_attach_modifier(GScanTokenCustomizer *customizer, GScanTokenModifier *modifier)
+{
+ bool result; /* Validation à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ for (i = 0; i < customizer->count && result; i++)
+ result = g_scan_token_modifier_can_handle_arg(modifier, &customizer->args[i]);
+
+ if (!result) goto exit;
+
+ customizer->effective = modifier;
+ g_object_ref(G_OBJECT(modifier));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_token_customizer_get_name(const GScanTokenCustomizer *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ if (modifier->effective == NULL)
+ result = NULL;
+
+ else
+ result = g_scan_token_modifier_get_name(modifier->effective);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_customizer_transform(const GScanTokenCustomizer *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ size_t i; /* Boucle de parcours #1 */
+ sized_binary_t *extra; /* Motifs supplémentaires */
+ size_t extra_count; /* Quantité de ces motifs */
+ size_t old_dcount; /* Mémorisation avant avancées */
+ sized_binary_t *new; /* Nouvel emplacement libre */
+ size_t k; /* Boucle de parcours #2 */
+
+ *dest = NULL;
+ *dcount = 0;
+
+ for (i = 0; i < modifier->count; i++)
+ {
+ result = g_scan_token_modifier_transform_with_arg(modifier->effective,
+ src, scount,
+ &modifier->args[i],
+ &extra, &extra_count);
+ if (!result) goto exit;
+
+ old_dcount = *dcount;
+
+ *dcount += extra_count;
+ *dest = realloc(*dest, *dcount * sizeof(sized_binary_t));
+
+ new = (*dest) + old_dcount;
+
+ for (k = 0; k < extra_count; k++, new++)
+ copy_szstr(*new, extra[k]);
+
+ free(extra);
+
+ }
+
+ exit:
+
+ if (!result)
+ {
+ for (i = 0; i < *dcount; i++)
+ exit_szstr(dest[i]);
+
+ if (*dest != NULL)
+ free(*dest);
+
+ *dest = NULL;
+ *dcount = 0;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/customizer.h b/src/analysis/scan/patterns/customizer.h
new file mode 100644
index 0000000..845d9ff
--- /dev/null
+++ b/src/analysis/scan/patterns/customizer.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * customizer.h - prototypes pour la modification paramétrée d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_CUSTOMIZER_H
+#define _ANALYSIS_SCAN_CUSTOMIZER_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "modifier.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_CUSTOMIZER g_scan_token_customizer_get_type()
+#define G_SCAN_TOKEN_CUSTOMIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_CUSTOMIZER, GScanTokenCustomizer))
+#define G_IS_SCAN_TOKEN_CUSTOMIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_CUSTOMIZER))
+#define G_SCAN_TOKEN_CUSTOMIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_CUSTOMIZER, GScanTokenCustomizerClass))
+#define G_IS_SCAN_TOKEN_CUSTOMIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_CUSTOMIZER))
+#define G_SCAN_TOKEN_CUSTOMIZER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_CUSTOMIZER, GScanTokenCustomizerClass))
+
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (instance) */
+typedef struct _GScanTokenCustomizer GScanTokenCustomizer;
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (classe) */
+typedef struct _GScanTokenCustomizerClass GScanTokenCustomizerClass;
+
+
+/* Indique le type défini pour une transformation personnalisée d'une séquence d'octets. */
+GType g_scan_token_customizer_get_type(void);
+
+/* Construit un encadrement de transformation de motifs. */
+GScanTokenModifier *g_scan_token_customizer_new(const modifier_arg_t *);
+
+/* Ajoute un argument à l'encadrement de transformation. */
+void g_scan_token_customizer_add_extra_arg(GScanTokenCustomizer *, const modifier_arg_t *);
+
+/* Définit le transformateur effectif pour les motifs. */
+bool g_scan_token_customizer_attach_modifier(GScanTokenCustomizer *, GScanTokenModifier *);
+
+
+
+#endif /* _ANALYSIS_SCAN_CUSTOMIZER_H */
diff --git a/src/analysis/scan/patterns/modarg.h b/src/analysis/scan/patterns/modarg.h
new file mode 100644
index 0000000..d96e137
--- /dev/null
+++ b/src/analysis/scan/patterns/modarg.h
@@ -0,0 +1,91 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modarg.h - prototypes pour la conservation d'arguments pour modificateurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MODARG_H
+#define _ANALYSIS_SCAN_MODARG_H
+
+
+#include <stdbool.h>
+
+
+#include "../../../common/szstr.h"
+
+
+
+/* Types d'arguments pris en charge */
+typedef enum _ModifierArgType
+{
+ MAT_BOOLEAN, /* Valeur booléenne */
+ MAT_SIGNED_INTEGER, /* Nombre entier 64 bits #1 */
+ MAT_UNSIGNED_INTEGER, /* Nombre entier 64 bits #2 */
+ MAT_STRING, /* Chaîne de caractères */
+ MAT_RANGE, /* Séquence d'entiers */
+
+} ModifierArgType;
+
+/* Argument pour modificateur de motif */
+typedef struct _modifier_arg_t
+{
+ ModifierArgType type; /* Type de valeur portée */
+
+ union
+ {
+ bool boolean; /* Valeur booléenne */
+ long long s_integer; /* Valeur entière 64 bits */
+ unsigned long long u_integer; /* Valeur entière 64 bits */
+ sized_string_t string; /* Chaîne de caractères */
+
+ struct
+ {
+ long long start; /* Point de départ */
+ long long end; /* Point d'arrivée */
+
+ } range;
+
+ } value;
+
+} modifier_arg_t;
+
+
+#define exit_mod_arg(a) \
+ do \
+ { \
+ if ((a)->type == MAT_STRING) \
+ exit_szstr(&(a)->value.string); \
+ } \
+ while (0)
+
+#define copy_mod_arg(d, s) \
+ do \
+ { \
+ (d)->type = (s)->type; \
+ if ((s)->type == MAT_STRING) \
+ szstrdup(&(d)->value.string, &(s)->value.string); \
+ else \
+ *(d) = *(s); \
+ } \
+ while (0)
+
+
+
+#endif /* _ANALYSIS_SCAN_MODARG_H */
diff --git a/src/analysis/scan/patterns/modifier-int.h b/src/analysis/scan/patterns/modifier-int.h
new file mode 100644
index 0000000..c9b3a36
--- /dev/null
+++ b/src/analysis/scan/patterns/modifier-int.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modifier-int.h - prototypes internes pour la modification d'une séquence d'octets pour un motif recherché
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MODIFIER_INT_H
+#define _ANALYSIS_SCAN_MODIFIER_INT_H
+
+
+#include "modifier.h"
+
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+typedef char * (* get_scan_modifier_name_fc) (const GScanTokenModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+typedef bool (* transform_scan_token_fc) (const GScanTokenModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Détermine si un argument est bien toléré par un modificateur. */
+typedef bool (* can_token_modifier_handle_arg) (const GScanTokenModifier *, const modifier_arg_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+typedef bool (* transform_scan_token_with_fc) (const GScanTokenModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+typedef char * (* get_modifier_path) (const GScanTokenModifier *, size_t *);
+
+
+/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (instance) */
+struct _GScanTokenModifier
+{
+ GObject parent; /* A laisser en premier */
+
+};
+
+/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (classe) */
+struct _GScanTokenModifierClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ get_scan_modifier_name_fc get_name; /* Fourniture du nom d'appel */
+
+ transform_scan_token_fc transform; /* Opération de transformation */
+ can_token_modifier_handle_arg can_handle; /* Support d'argument donné */
+ transform_scan_token_with_fc transform_with; /* Opération encadrée */
+ get_modifier_path get_path; /* Rappel d'une combinaison */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_MODIFIER_INT_H */
diff --git a/src/analysis/scan/patterns/modifier.c b/src/analysis/scan/patterns/modifier.c
new file mode 100644
index 0000000..9efd404
--- /dev/null
+++ b/src/analysis/scan/patterns/modifier.c
@@ -0,0 +1,278 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modifier.c - modification d'une séquence d'octets pour un motif recherché
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "modifier.h"
+
+
+#include "modifier-int.h"
+
+
+
+/* Initialise la classe des transformations d'octets. */
+static void g_scan_token_modifier_class_init(GScanTokenModifierClass *);
+
+/* Initialise une instance de transformation d'octets. */
+static void g_scan_token_modifier_init(GScanTokenModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_modifier_dispose(GScanTokenModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_modifier_finalize(GScanTokenModifier *);
+
+
+
+/* Indique le type défini pour une transformation d'une séquence d'octets. */
+G_DEFINE_TYPE(GScanTokenModifier, g_scan_token_modifier, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transformations d'octets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_modifier_class_init(GScanTokenModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_modifier_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transformation d'octets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_modifier_init(GScanTokenModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_modifier_dispose(GScanTokenModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_token_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_modifier_finalize(GScanTokenModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_token_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_token_modifier_get_name(const GScanTokenModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+ GScanTokenModifierClass *class; /* Classe à activer */
+
+ class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+ result = class->get_name(modifier);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_modifier_transform(const GScanTokenModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ GScanTokenModifierClass *class; /* Classe à activer */
+
+ class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+ result = class->transform(modifier, src, scount, dest, dcount);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* arg = argument de personnalisation. *
+* *
+* Description : Détermine si un argument est bien toléré par un modificateur.*
+* *
+* Retour : Bilan de la consultation : support ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_modifier_can_handle_arg(const GScanTokenModifier *modifier, const modifier_arg_t *arg)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ GScanTokenModifierClass *class; /* Classe à activer */
+
+ class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+ if (class->can_handle == NULL)
+ result = false;
+ else
+ result = class->can_handle(modifier, arg);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* arg = argument de personnalisation. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_modifier_transform_with_arg(const GScanTokenModifier *modifier, const sized_binary_t *src, size_t scount, const modifier_arg_t *arg, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ GScanTokenModifierClass *class; /* Classe à activer */
+
+ result = false;
+
+ if (!g_scan_token_modifier_can_handle_arg(modifier, arg))
+ goto exit;
+
+ class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+ if (class->transform_with != NULL)
+ result = class->transform_with(modifier, src, scount, arg, dest, dcount);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_token_modifier_get_path(const GScanTokenModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+ GScanTokenModifierClass *class; /* Classe à activer */
+
+ class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+ result = class->get_path(modifier, index);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifier.h b/src/analysis/scan/patterns/modifier.h
new file mode 100644
index 0000000..9030a72
--- /dev/null
+++ b/src/analysis/scan/patterns/modifier.h
@@ -0,0 +1,73 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modifier.h - prototypes pour la modification d'une séquence d'octets pour un motif recherché
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MODIFIER_H
+#define _ANALYSIS_SCAN_MODIFIER_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+
+#include "modarg.h"
+#include "../../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_MODIFIER g_scan_token_modifier_get_type()
+#define G_SCAN_TOKEN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_MODIFIER, GScanTokenModifier))
+#define G_IS_SCAN_TOKEN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_MODIFIER))
+#define G_SCAN_TOKEN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_MODIFIER, GScanTokenModifierClass))
+#define G_IS_SCAN_TOKEN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_MODIFIER))
+#define G_SCAN_TOKEN_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_MODIFIER, GScanTokenModifierClass))
+
+
+/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (instance) */
+typedef struct _GScanTokenModifier GScanTokenModifier;
+
+/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (classe) */
+typedef struct _GScanTokenModifierClass GScanTokenModifierClass;
+
+
+/* Indique le type défini pour une transformation d'une séquence d'octets. */
+GType g_scan_token_modifier_get_type(void);
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+char *g_scan_token_modifier_get_name(const GScanTokenModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+bool g_scan_token_modifier_transform(const GScanTokenModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Détermine si un argument est bien toléré par un modificateur. */
+bool g_scan_token_modifier_can_handle_arg(const GScanTokenModifier *, const modifier_arg_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+bool g_scan_token_modifier_transform_with_arg(const GScanTokenModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_scan_token_modifier_get_path(const GScanTokenModifier *, size_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_MODIFIER_H */
diff --git a/src/analysis/scan/patterns/modifiers/Makefile.am b/src/analysis/scan/patterns/modifiers/Makefile.am
new file mode 100644
index 0000000..da046b9
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/Makefile.am
@@ -0,0 +1,23 @@
+
+noinst_LTLIBRARIES = libanalysisscanpatternsmodifiers.la
+
+
+libanalysisscanpatternsmodifiers_la_SOURCES = \
+ hex.h hex.c \
+ list-int.h \
+ list.h list.c \
+ lower.h lower.c \
+ pipe-int.h \
+ pipe.h pipe.c \
+ plain.h plain.c \
+ rev.h rev.c \
+ upper.h upper.c \
+ wide.h wide.c \
+ xor.h xor.c
+
+libanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanpatternsmodifiers_la_SOURCES:%c=)
diff --git a/src/analysis/scan/patterns/modifiers/hex.c b/src/analysis/scan/patterns/modifiers/hex.c
new file mode 100644
index 0000000..4a41c7d
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/hex.c
@@ -0,0 +1,296 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.c - transformation en version hexadécimale d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hex.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transformations en hexadécimal. */
+static void g_scan_hex_modifier_class_init(GScanHexModifierClass *klass);
+
+/* Initialise une instance de transformation en hexadécimal. */
+static void g_scan_hex_modifier_init(GScanHexModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_hex_modifier_dispose(GScanHexModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_hex_modifier_finalize(GScanHexModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_hex_modifier_get_name(const GScanHexModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_hex_modifier_transform(const GScanHexModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_hex_modifier_get_path(const GScanHexModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transformation d'une séquence d'octets dans sa version hexadécimale. */
+G_DEFINE_TYPE(GScanHexModifier, g_scan_hex_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transformations en hexadécimal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_modifier_class_init(GScanHexModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_hex_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_hex_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_hex_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_hex_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_hex_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transformation en hexadécimal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_modifier_init(GScanHexModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_modifier_dispose(GScanHexModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_hex_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_modifier_finalize(GScanHexModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_hex_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur fournistant une vue hexadécimale. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_hex_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_HEX_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_hex_modifier_get_name(const GScanHexModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("hex");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_hex_modifier_transform(const GScanHexModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ size_t k; /* Boucle de parcours #2 */
+
+ static char *alphabet = "0123456789abcdef";
+
+ result = true;
+
+ *dcount = scount;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len * 2;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ {
+ binary->data[k * 2 + 0] = alphabet[_src->data[k] >> 4];
+ binary->data[k * 2 + 1] = alphabet[_src->data[k] & 0xf];
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_hex_modifier_get_path(const GScanHexModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("hex");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/hex.h b/src/analysis/scan/patterns/modifiers/hex.h
new file mode 100644
index 0000000..1a9b410
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/hex.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.h - prototypes pour la transformation en version hexadécimale d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_HEX_MODIFIER g_scan_hex_modifier_get_type()
+#define G_SCAN_HEX_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_HEX_MODIFIER, GScanHexModifier))
+#define G_IS_SCAN_HEX_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_HEX_MODIFIER))
+#define G_SCAN_HEX_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_HEX_MODIFIER, GScanHexModifierClass))
+#define G_IS_SCAN_HEX_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_HEX_MODIFIER))
+#define G_SCAN_HEX_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_HEX_MODIFIER, GScanHexModifierClass))
+
+
+/* Transformation d'une séquence d'octets dans sa version hexadécimale (instance) */
+typedef GScanTokenModifier GScanHexModifier;
+
+/* Transformation d'une séquence d'octets dans sa version hexadécimale (classe) */
+typedef GScanTokenModifierClass GScanHexModifierClass;
+
+
+/* Indique le type défini pour une transformation d'une séquence d'octets dans sa version hexadécimale. */
+GType g_scan_hex_modifier_get_type(void);
+
+/* Construit un modificateur fournistant une vue hexadécimale. */
+GScanTokenModifier *g_scan_hex_modifier_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H */
diff --git a/src/analysis/scan/patterns/modifiers/list-int.h b/src/analysis/scan/patterns/modifiers/list-int.h
new file mode 100644
index 0000000..3ba253e
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/list-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list-int.h - prototypes internes pour la gestion d'une liste de transformateurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MODIFIERS_LIST_INT_H
+#define _ANALYSIS_SCAN_MODIFIERS_LIST_INT_H
+
+
+#include "list.h"
+
+
+#include "../modifier-int.h"
+
+
+
+/* Liste de transformations d'une séquence d'octets (instance) */
+struct _GScanModifierList
+{
+ GScanTokenModifier parent; /* A laisser en premier */
+
+ GScanTokenModifier **modifiers; /* Liste de transformateurs */
+ size_t count; /* Taille de cette liste */
+
+};
+
+/* Liste de transformations d'une séquence d'octets (classe) */
+struct _GScanModifierListClass
+{
+ GScanTokenModifierClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_MODIFIERS_LIST_INT_H */
diff --git a/src/analysis/scan/patterns/modifiers/list.c b/src/analysis/scan/patterns/modifiers/list.c
new file mode 100644
index 0000000..86fd19f
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/list.c
@@ -0,0 +1,438 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list.c - gestion d'une liste de transformateurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "list.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "list-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des liste de transformations d'octets. */
+static void g_scan_modifier_list_class_init(GScanModifierListClass *);
+
+/* Initialise une instance de liste de transformations d'octets. */
+static void g_scan_modifier_list_init(GScanModifierList *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_modifier_list_dispose(GScanModifierList *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_modifier_list_finalize(GScanModifierList *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_modifier_list_get_name(const GScanModifierList *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_modifier_list_transform(const GScanModifierList *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_modifier_list_get_path(const GScanModifierList *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série de transformations d'octets. */
+G_DEFINE_TYPE(GScanModifierList, g_scan_modifier_list, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des liste de transformations d'octets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_list_class_init(GScanModifierListClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_modifier_list_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_modifier_list_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_modifier_list_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_modifier_list_transform;
+ modifier->get_path = (get_modifier_path)g_scan_modifier_list_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = instance à initialiser. *
+* *
+* Description : Initialise une instance de liste de transformations d'octets.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_list_init(GScanModifierList *list)
+{
+ list->modifiers = NULL;
+ list->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_list_dispose(GScanModifierList *list)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < list->count; i++)
+ g_clear_object(&list->modifiers[i]);
+
+ G_OBJECT_CLASS(g_scan_modifier_list_parent_class)->dispose(G_OBJECT(list));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_list_finalize(GScanModifierList *list)
+{
+ if (list->modifiers != NULL)
+ free(list->modifiers);
+
+ G_OBJECT_CLASS(g_scan_modifier_list_parent_class)->finalize(G_OBJECT(list));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit une liste de modificateurs d'octets. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_modifier_list_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MODIFIER_LIST, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = liste de modificateurs à étendre. *
+* modifier = modificateur à intégrer. *
+* *
+* Description : Intègre un nouveau transformateur dans une liste. *
+* *
+* Retour : Bilan de l'ajout : false si un élément similaire est déjà là.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_modifier_list_add(GScanModifierList *list, GScanTokenModifier *modifier)
+{
+ bool result; /* Bilan à retourner */
+ char *name; /* Désignation du modificateur */
+ size_t i; /* Boucle de parcours */
+ char *other; /* Désignation de ses collègues*/
+
+ /* Recherche d'une redondance */
+
+ /**
+ * Note : deux listes identiques passent sans soucis.
+ * TODO : comparer les transformateurs ?
+ */
+
+ result = true;
+
+ if (!G_IS_SCAN_MODIFIER_LIST(modifier))
+ {
+ name = g_scan_token_modifier_get_name(modifier);
+
+ for (i = 0; i < list->count && result; i++)
+ {
+ if (G_IS_SCAN_MODIFIER_LIST(list->modifiers[i]))
+ continue;
+
+ other = g_scan_token_modifier_get_name(list->modifiers[i]);
+
+ result = (strcmp(name, other) != 0);
+
+ free(other);
+
+ }
+
+ free(name);
+
+ }
+
+ if (!result)
+ goto done;
+
+ /* Inclusion dans la liste */
+
+ list->modifiers = realloc(list->modifiers, ++list->count * sizeof(GScanTokenModifier *));
+
+ list->modifiers[list->count - 1] = modifier;
+ g_object_ref(G_OBJECT(modifier));
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = série à consulter. *
+* *
+* Description : Indique le nombre de transformateurs intégrés dans la liste. *
+* *
+* Retour : Nombre de modificateurs représentés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_scan_modifier_list_count(const GScanModifierList *list)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = list->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = série à consulter. *
+* index = indice du paramètre à retourner. *
+* *
+* Description : Fournit un transformateur donné de la liste. *
+* *
+* Retour : Modificateur inclus dans la liste ou NULL si mauvais indice. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_modifier_list_get(const GScanModifierList *list, size_t index)
+{
+ GScanTokenModifier *result; /* Instance à retourner */
+
+ assert(index < list->count);
+
+ if (index < list->count)
+ {
+ result = list->modifiers[index];
+ g_object_ref(G_OBJECT(result));
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_modifier_list_get_name(const GScanModifierList *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("(list)");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_modifier_list_transform(const GScanModifierList *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ size_t i; /* Boucle de parcours #1 */
+ sized_binary_t *extra; /* Motifs supplémentaires */
+ size_t extra_count; /* Quantité de ces motifs */
+ sized_binary_t *new; /* Nouvel emplacement libre */
+ size_t k; /* Boucle de parcours #2 */
+
+ *dest = NULL;
+ *dcount = 0;
+
+ for (i = 0; i < modifier->count; i++)
+ {
+ result = g_scan_token_modifier_transform(modifier->modifiers[i], src, scount, &extra, &extra_count);
+ if (!result) goto exit;
+
+ *dcount += extra_count;
+ *dest = realloc(*dest, *dcount * sizeof(sized_binary_t));
+
+ new = (*dest) + *dcount - extra_count;
+
+ for (k = 0; k < extra_count; k++, new++)
+ copy_szstr(*new, extra[k]);
+
+ free(extra);
+
+ }
+
+ exit:
+
+ if (!result)
+ {
+ for (i = 0; i < *dcount; i++)
+ exit_szstr(dest[i]);
+
+ if (*dest != NULL)
+ free(*dest);
+
+ *dest = NULL;
+ *dcount = 0;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_modifier_list_get_path(const GScanModifierList *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ result = NULL;
+
+ for (i = 0; i < modifier->count && result == NULL; i++)
+ result = g_scan_token_modifier_get_path(modifier->modifiers[i], index);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/list.h b/src/analysis/scan/patterns/modifiers/list.h
new file mode 100644
index 0000000..abd1eae
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/list.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * list.h - prototypes pour la gestion d'une liste de transformateurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MODIFIERS_LIST_H
+#define _ANALYSIS_SCAN_MODIFIERS_LIST_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_MODIFIER_LIST g_scan_modifier_list_get_type()
+#define G_SCAN_MODIFIER_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MODIFIER_LIST, GScanModifierList))
+#define G_IS_SCAN_MODIFIER_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MODIFIER_LIST))
+#define G_SCAN_MODIFIER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MODIFIER_LIST, GScanModifierListClass))
+#define G_IS_SCAN_MODIFIER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MODIFIER_LIST))
+#define G_SCAN_MODIFIER_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MODIFIER_LIST, GScanModifierListClass))
+
+
+/* Liste de transformations d'une séquence d'octets (instance) */
+typedef struct _GScanModifierList GScanModifierList;
+
+/* Liste de transformations d'une séquence d'octets (classe) */
+typedef struct _GScanModifierListClass GScanModifierListClass;
+
+
+/* Indique le type défini pour une série de transformations d'octets. */
+GType g_scan_modifier_list_get_type(void);
+
+/* Construit une liste de modificateurs d'octets. */
+GScanTokenModifier *g_scan_modifier_list_new(void);
+
+/* Intègre un nouveau transformateur dans une liste. */
+bool g_scan_modifier_list_add(GScanModifierList *, GScanTokenModifier *);
+
+/* Indique le nombre de transformateurs intégrés dans la liste. */
+size_t g_scan_modifier_list_count(const GScanModifierList *);
+
+/* Fournit un transformateur donné de la liste. */
+GScanTokenModifier *g_scan_modifier_list_get(const GScanModifierList *, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_MODIFIERS_LIST_H */
diff --git a/src/analysis/scan/patterns/modifiers/lower.c b/src/analysis/scan/patterns/modifiers/lower.c
new file mode 100644
index 0000000..3904c52
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/lower.c
@@ -0,0 +1,301 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.c - transformation d'une séquence d'octets par passage en minuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "lower.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en minuscules. */
+static void g_scan_lower_modifier_class_init(GScanLowerModifierClass *klass);
+
+/* Initialise une instance de transmission en minuscules. */
+static void g_scan_lower_modifier_init(GScanLowerModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_lower_modifier_dispose(GScanLowerModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_lower_modifier_finalize(GScanLowerModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_lower_modifier_get_name(const GScanLowerModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_lower_modifier_transform(const GScanLowerModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_lower_modifier_get_path(const GScanLowerModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transformation par bascule en minuscules. */
+G_DEFINE_TYPE(GScanLowerModifier, g_scan_lower_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en minuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_lower_modifier_class_init(GScanLowerModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_lower_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_lower_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_lower_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_lower_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_lower_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en minuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_lower_modifier_init(GScanLowerModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_lower_modifier_dispose(GScanLowerModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_lower_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_lower_modifier_finalize(GScanLowerModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_lower_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des octets en minuscules. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_lower_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_LOWER_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_lower_modifier_get_name(const GScanLowerModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("lower");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_lower_modifier_transform(const GScanLowerModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ switch (_src->data[k])
+ {
+ case 'A' ... 'Z':
+ binary->data[k] = _src->data[k] + 0x20;
+ break;
+
+ default:
+ binary->data[k] = _src->data[k];
+ break;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_lower_modifier_get_path(const GScanLowerModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("lower");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/lower.h b/src/analysis/scan/patterns/modifiers/lower.h
new file mode 100644
index 0000000..d361340
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/lower.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.h - prototypes pour la transformation d'une séquence d'octets par passage en minuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_LOWER_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_LOWER_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_LOWER_MODIFIER g_scan_lower_modifier_get_type()
+#define G_SCAN_LOWER_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_LOWER_MODIFIER, GScanLowerModifier))
+#define G_IS_SCAN_LOWER_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_LOWER_MODIFIER))
+#define G_SCAN_LOWER_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_LOWER_MODIFIER, GScanLowerModifierClass))
+#define G_IS_SCAN_LOWER_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_LOWER_MODIFIER))
+#define G_SCAN_LOWER_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_LOWER_MODIFIER, GScanLowerModifierClass))
+
+
+/* Transformation d'une séquence d'octets par passage en minuscules (instance) */
+typedef GScanTokenModifier GScanLowerModifier;
+
+/* Transformation d'une séquence d'octets par passage en minuscules (classe) */
+typedef GScanTokenModifierClass GScanLowerModifierClass;
+
+
+/* Indique le type défini pour une transformation par bascule en minuscules. */
+GType g_scan_lower_modifier_get_type(void);
+
+/* Construit un modificateur livrant des octets en minuscules. */
+GScanTokenModifier *g_scan_lower_modifier_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_LOWER_H */
diff --git a/src/analysis/scan/patterns/modifiers/pipe-int.h b/src/analysis/scan/patterns/modifiers/pipe-int.h
new file mode 100644
index 0000000..63c4d97
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/pipe-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pipe-int.h - prototypes internes pour la gestion de combinaisons de transformateurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MODIFIERS_PIPE_INT_H
+#define _ANALYSIS_SCAN_MODIFIERS_PIPE_INT_H
+
+
+#include "pipe.h"
+
+
+#include "../modifier-int.h"
+
+
+
+/* Enchainement combinatoire de transformations d'octets (instance) */
+struct _GScanModifierPipe
+{
+ GScanTokenModifier parent; /* A laisser en premier */
+
+ GScanTokenModifier **modifiers; /* Pipee de transformateurs */
+ size_t count; /* Taille de cette pipee */
+
+};
+
+/* Enchainement combinatoire de transformations d'octets (classe) */
+struct _GScanModifierPipeClass
+{
+ GScanTokenModifierClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_MODIFIERS_PIPE_INT_H */
diff --git a/src/analysis/scan/patterns/modifiers/pipe.c b/src/analysis/scan/patterns/modifiers/pipe.c
new file mode 100644
index 0000000..7c659ea
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/pipe.c
@@ -0,0 +1,405 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pipe.c - gestion de combinaisons de transformateurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "pipe.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "pipe-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des pipee de transformations d'octets. */
+static void g_scan_modifier_pipe_class_init(GScanModifierPipeClass *);
+
+/* Initialise une instance de pipee de transformations d'octets. */
+static void g_scan_modifier_pipe_init(GScanModifierPipe *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_modifier_pipe_dispose(GScanModifierPipe *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_modifier_pipe_finalize(GScanModifierPipe *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_modifier_pipe_get_name(const GScanModifierPipe *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_modifier_pipe_transform(const GScanModifierPipe *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_modifier_pipe_get_path(const GScanModifierPipe *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série de transformations d'octets. */
+G_DEFINE_TYPE(GScanModifierPipe, g_scan_modifier_pipe, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des pipee de transformations d'octets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_class_init(GScanModifierPipeClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_modifier_pipe_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_modifier_pipe_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_modifier_pipe_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_modifier_pipe_transform;
+ modifier->get_path = (get_modifier_path)g_scan_modifier_pipe_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pipe = instance à initialiser. *
+* *
+* Description : Initialise une instance de pipee de transformations d'octets.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_init(GScanModifierPipe *pipe)
+{
+ pipe->modifiers = NULL;
+ pipe->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pipe = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_dispose(GScanModifierPipe *pipe)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < pipe->count; i++)
+ g_clear_object(&pipe->modifiers[i]);
+
+ G_OBJECT_CLASS(g_scan_modifier_pipe_parent_class)->dispose(G_OBJECT(pipe));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pipe = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_finalize(GScanModifierPipe *pipe)
+{
+ if (pipe->modifiers != NULL)
+ free(pipe->modifiers);
+
+ G_OBJECT_CLASS(g_scan_modifier_pipe_parent_class)->finalize(G_OBJECT(pipe));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit une pipee de modificateurs d'octets. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_modifier_pipe_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MODIFIER_PIPE, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pipe = pipee de modificateurs à étendre. *
+* modifier = modificateur à intégrer. *
+* *
+* Description : Intègre un nouveau transformateur à enchaîner. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_modifier_pipe_add(GScanModifierPipe *pipe, GScanTokenModifier *modifier)
+{
+ pipe->modifiers = realloc(pipe->modifiers, ++pipe->count * sizeof(GScanTokenModifier *));
+
+ pipe->modifiers[pipe->count - 1] = modifier;
+ g_object_ref(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pipe = série à consulter. *
+* *
+* Description : Indique le nombre de transformateurs intégrés dans la série. *
+* *
+* Retour : Nombre de modificateurs représentés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_scan_modifier_pipe_count(const GScanModifierPipe *pipe)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = pipe->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pipe = série à consulter. *
+* index = indice du paramètre à retourner. *
+* *
+* Description : Fournit un transformateur donné de la série. *
+* *
+* Retour : Modificateur inclus dans la pipee ou NULL si mauvais indice. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_modifier_pipe_get(const GScanModifierPipe *pipe, size_t index)
+{
+ GScanTokenModifier *result; /* Instance à retourner */
+
+ assert(index < pipe->count);
+
+ if (index < pipe->count)
+ {
+ result = pipe->modifiers[index];
+ g_object_ref(G_OBJECT(result));
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_modifier_pipe_get_name(const GScanModifierPipe *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("(pipe)");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_modifier_pipe_transform(const GScanModifierPipe *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ size_t i; /* Boucle de parcours #1 */
+ sized_binary_t *tmp_in; /* Motifs supplémentaires */
+ size_t tmp_in_count; /* Quantité de ces motifs */
+ sized_binary_t *tmp_out; /* Motifs supplémentaires */
+ size_t tmp_out_count; /* Quantité de ces motifs */
+ size_t k; /* Boucle de parcours #2 */
+
+ for (i = 0; i < modifier->count; i++)
+ {
+ if (i == 0)
+ result = g_scan_token_modifier_transform(modifier->modifiers[i],
+ src, scount, &tmp_out, &tmp_out_count);
+
+ else
+ {
+ tmp_in = tmp_out;
+ tmp_in_count = tmp_out_count;
+
+ result = g_scan_token_modifier_transform(modifier->modifiers[i],
+ tmp_in, tmp_in_count, &tmp_out, &tmp_out_count);
+
+ for (k = 0; k < tmp_in_count; k++)
+ exit_szstr(&tmp_in[k]);
+
+ if (tmp_in != NULL)
+ free(tmp_in);
+
+ }
+
+ if (!result)
+ break;
+
+ }
+
+ if (!result)
+ {
+ for (k = 0; k < tmp_out_count; k++)
+ exit_szstr(&tmp_out[k]);
+
+ if (tmp_out != NULL)
+ free(tmp_out);
+
+ *dest = NULL;
+ *dcount = 0;
+
+ }
+ else
+ {
+ *dcount += tmp_out_count;
+ *dest = tmp_out;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_modifier_pipe_get_path(const GScanModifierPipe *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ result = NULL;
+
+ for (i = 0; i < modifier->count && result == NULL; i++)
+ result = g_scan_token_modifier_get_path(modifier->modifiers[i], index);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/pipe.h b/src/analysis/scan/patterns/modifiers/pipe.h
new file mode 100644
index 0000000..8f9ca48
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/pipe.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pipe.h - prototypes pour la gestion de combinaisons de transformateurs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MODIFIERS_PIPE_H
+#define _ANALYSIS_SCAN_MODIFIERS_PIPE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_MODIFIER_PIPE g_scan_modifier_pipe_get_type()
+#define G_SCAN_MODIFIER_PIPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MODIFIER_PIPE, GScanModifierPipe))
+#define G_IS_SCAN_MODIFIER_PIPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MODIFIER_PIPE))
+#define G_SCAN_MODIFIER_PIPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MODIFIER_PIPE, GScanModifierPipeClass))
+#define G_IS_SCAN_MODIFIER_PIPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MODIFIER_PIPE))
+#define G_SCAN_MODIFIER_PIPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MODIFIER_PIPE, GScanModifierPipeClass))
+
+
+/* Enchainement combinatoire de transformations d'octets (instance) */
+typedef struct _GScanModifierPipe GScanModifierPipe;
+
+/* Enchainement combinatoire de transformations d'octets (classe) */
+typedef struct _GScanModifierPipeClass GScanModifierPipeClass;
+
+
+/* Indique le type défini pour une série de transformations d'octets. */
+GType g_scan_modifier_pipe_get_type(void);
+
+/* Construit une pipee de modificateurs d'octets. */
+GScanTokenModifier *g_scan_modifier_pipe_new(void);
+
+/* Intègre un nouveau transformateur à enchaîner. */
+void g_scan_modifier_pipe_add(GScanModifierPipe *, GScanTokenModifier *);
+
+/* Indique le nombre de transformateurs intégrés dans la série. */
+size_t g_scan_modifier_pipe_count(const GScanModifierPipe *);
+
+/* Fournit un transformateur donné de la pipee. */
+GScanTokenModifier *g_scan_modifier_pipe_get(const GScanModifierPipe *, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_MODIFIERS_PIPE_H */
diff --git a/src/analysis/scan/patterns/modifiers/plain.c b/src/analysis/scan/patterns/modifiers/plain.c
new file mode 100644
index 0000000..ad09129
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/plain.c
@@ -0,0 +1,289 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.c - transmission à l'identique d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "plain.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions à l'identique. */
+static void g_scan_plain_modifier_class_init(GScanPlainModifierClass *klass);
+
+/* Initialise une instance de transmission à l'identique. */
+static void g_scan_plain_modifier_init(GScanPlainModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_plain_modifier_dispose(GScanPlainModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_plain_modifier_finalize(GScanPlainModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_plain_modifier_get_name(const GScanPlainModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_plain_modifier_transform(const GScanPlainModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_plain_modifier_get_path(const GScanPlainModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transmission à l'identique d'une séquence d'octets. */
+G_DEFINE_TYPE(GScanPlainModifier, g_scan_plain_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions à l'identique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_modifier_class_init(GScanPlainModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_plain_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_plain_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_plain_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_plain_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_plain_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission à l'identique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_modifier_init(GScanPlainModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_modifier_dispose(GScanPlainModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_plain_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_modifier_finalize(GScanPlainModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_plain_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des octets à l'identique. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_plain_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_PLAIN_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_plain_modifier_get_name(const GScanPlainModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("plain");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_plain_modifier_transform(const GScanPlainModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours */
+ const sized_binary_t *_src; /* Source courante */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ memcpy(binary->data, _src->data, _src->len);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_plain_modifier_get_path(const GScanPlainModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("plain");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/plain.h b/src/analysis/scan/patterns/modifiers/plain.h
new file mode 100644
index 0000000..ecabefd
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/plain.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.h - prototypes pour la transmission à l'identique d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_PLAIN_MODIFIER g_scan_plain_modifier_get_type()
+#define G_SCAN_PLAIN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PLAIN_MODIFIER, GScanPlainModifier))
+#define G_IS_SCAN_PLAIN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PLAIN_MODIFIER))
+#define G_SCAN_PLAIN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PLAIN_MODIFIER, GScanPlainModifierClass))
+#define G_IS_SCAN_PLAIN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PLAIN_MODIFIER))
+#define G_SCAN_PLAIN_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PLAIN_MODIFIER, GScanPlainModifierClass))
+
+
+/* Transmission à l'identique d'une séquence d'octets (instance) */
+typedef GScanTokenModifier GScanPlainModifier;
+
+/* Transmission à l'identique d'une séquence d'octets (classe) */
+typedef GScanTokenModifierClass GScanPlainModifierClass;
+
+
+/* Indique le type défini pour une transmission à l'identique d'une séquence d'octets. */
+GType g_scan_plain_modifier_get_type(void);
+
+/* Construit un modificateur livrant des octets à l'identique. */
+GScanTokenModifier *g_scan_plain_modifier_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H */
diff --git a/src/analysis/scan/patterns/modifiers/rev.c b/src/analysis/scan/patterns/modifiers/rev.c
new file mode 100644
index 0000000..ef4d5fa
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/rev.c
@@ -0,0 +1,291 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rev.c - transormation via inversement d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "rev.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions via inversement. */
+static void g_scan_reverse_modifier_class_init(GScanReverseModifierClass *klass);
+
+/* Initialise une instance de transmission via inversement. */
+static void g_scan_reverse_modifier_init(GScanReverseModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_reverse_modifier_dispose(GScanReverseModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_reverse_modifier_finalize(GScanReverseModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_reverse_modifier_get_name(const GScanReverseModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_reverse_modifier_get_path(const GScanReverseModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation via inversement d'une séquence d'octets. */
+G_DEFINE_TYPE(GScanReverseModifier, g_scan_reverse_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions via inversement. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_reverse_modifier_class_init(GScanReverseModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_reverse_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_reverse_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_reverse_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_reverse_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_reverse_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission via inversement. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_reverse_modifier_init(GScanReverseModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_reverse_modifier_dispose(GScanReverseModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_reverse_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_reverse_modifier_finalize(GScanReverseModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_reverse_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des octets inversés. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_reverse_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_REVERSE_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_reverse_modifier_get_name(const GScanReverseModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("rev");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ binary->data[_src->len - k - 1] = _src->data[k];
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_reverse_modifier_get_path(const GScanReverseModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("rev");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/rev.h b/src/analysis/scan/patterns/modifiers/rev.h
new file mode 100644
index 0000000..5b4e398
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/rev.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rev.h - prototypes pour la transormation via inversement d'une séquence d'octets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_REVERSE_MODIFIER g_scan_reverse_modifier_get_type()
+#define G_SCAN_REVERSE_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_REVERSE_MODIFIER, GScanReverseModifier))
+#define G_IS_SCAN_REVERSE_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_REVERSE_MODIFIER))
+#define G_SCAN_REVERSE_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_REVERSE_MODIFIER, GScanReverseModifierClass))
+#define G_IS_SCAN_REVERSE_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_REVERSE_MODIFIER))
+#define G_SCAN_REVERSE_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_REVERSE_MODIFIER, GScanReverseModifierClass))
+
+
+/* Transormation via inversement d'une séquence d'octets (instance) */
+typedef GScanTokenModifier GScanReverseModifier;
+
+/* Transormation via inversement d'une séquence d'octets (classe) */
+typedef GScanTokenModifierClass GScanReverseModifierClass;
+
+
+/* Indique le type défini pour une transormation via inversement d'une séquence d'octets. */
+GType g_scan_reverse_modifier_get_type(void);
+
+/* Construit un modificateur livrant des octets inversés. */
+GScanTokenModifier *g_scan_reverse_modifier_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H */
diff --git a/src/analysis/scan/patterns/modifiers/upper.c b/src/analysis/scan/patterns/modifiers/upper.c
new file mode 100644
index 0000000..9d1086b
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/upper.c
@@ -0,0 +1,301 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.c - transformation d'une séquence d'octets par passage en majuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "upper.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions en majuscules. */
+static void g_scan_upper_modifier_class_init(GScanUpperModifierClass *klass);
+
+/* Initialise une instance de transmission en majuscules. */
+static void g_scan_upper_modifier_init(GScanUpperModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_upper_modifier_dispose(GScanUpperModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_upper_modifier_finalize(GScanUpperModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_upper_modifier_get_name(const GScanUpperModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_upper_modifier_transform(const GScanUpperModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_upper_modifier_get_path(const GScanUpperModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transformation par bascule en majuscules. */
+G_DEFINE_TYPE(GScanUpperModifier, g_scan_upper_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions en majuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_upper_modifier_class_init(GScanUpperModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_upper_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_upper_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_upper_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_upper_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_upper_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission en majuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_upper_modifier_init(GScanUpperModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_upper_modifier_dispose(GScanUpperModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_upper_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_upper_modifier_finalize(GScanUpperModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_upper_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des octets en majuscules. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_upper_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_UPPER_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_upper_modifier_get_name(const GScanUpperModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("upper");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_upper_modifier_transform(const GScanUpperModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ switch (_src->data[k])
+ {
+ case 'a' ... 'z':
+ binary->data[k] = _src->data[k] - 0x20;
+ break;
+
+ default:
+ binary->data[k] = _src->data[k];
+ break;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_upper_modifier_get_path(const GScanUpperModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("upper");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/upper.h b/src/analysis/scan/patterns/modifiers/upper.h
new file mode 100644
index 0000000..4666312
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/upper.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.h - prototypes pour la transformation d'une séquence d'octets par passage en majuscules
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_UPPER_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_UPPER_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_UPPER_MODIFIER g_scan_upper_modifier_get_type()
+#define G_SCAN_UPPER_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_UPPER_MODIFIER, GScanUpperModifier))
+#define G_IS_SCAN_UPPER_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_UPPER_MODIFIER))
+#define G_SCAN_UPPER_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_UPPER_MODIFIER, GScanUpperModifierClass))
+#define G_IS_SCAN_UPPER_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_UPPER_MODIFIER))
+#define G_SCAN_UPPER_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_UPPER_MODIFIER, GScanUpperModifierClass))
+
+
+/* Transformation d'une séquence d'octets par passage en majuscules (instance) */
+typedef GScanTokenModifier GScanUpperModifier;
+
+/* Transformation d'une séquence d'octets par passage en majuscules (classe) */
+typedef GScanTokenModifierClass GScanUpperModifierClass;
+
+
+/* Indique le type défini pour une transformation par bascule en majuscules. */
+GType g_scan_upper_modifier_get_type(void);
+
+/* Construit un modificateur livrant des octets en majuscules. */
+GScanTokenModifier *g_scan_upper_modifier_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_UPPER_H */
diff --git a/src/analysis/scan/patterns/modifiers/wide.c b/src/analysis/scan/patterns/modifiers/wide.c
new file mode 100644
index 0000000..ef252d9
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/wide.c
@@ -0,0 +1,291 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * wide.c - transcription d'une séquence d'octets en UTF-16
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "wide.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transcriptions en UTF-16. */
+static void g_scan_wide_modifier_class_init(GScanWideModifierClass *klass);
+
+/* Initialise une instance de transcription en UTF-16. */
+static void g_scan_wide_modifier_init(GScanWideModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_wide_modifier_dispose(GScanWideModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_wide_modifier_finalize(GScanWideModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_wide_modifier_get_name(const GScanWideModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_wide_modifier_transform(const GScanWideModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_wide_modifier_get_path(const GScanWideModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transcription d'une séquence d'octets en UTF-16. */
+G_DEFINE_TYPE(GScanWideModifier, g_scan_wide_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transcriptions en UTF-16. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_wide_modifier_class_init(GScanWideModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_wide_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_wide_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_wide_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_wide_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_wide_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transcription en UTF-16. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_wide_modifier_init(GScanWideModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_wide_modifier_dispose(GScanWideModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_wide_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_wide_modifier_finalize(GScanWideModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_wide_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des octets en UTF-16. *
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_wide_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_WIDE_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_wide_modifier_get_name(const GScanWideModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("wide");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_wide_modifier_transform(const GScanWideModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = true;
+
+ *dcount = scount;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++, binary++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len * 2;
+ binary->data = calloc(binary->len * 2, sizeof(bin_t));
+
+ for (k = 0; k < _src->len; k++)
+ binary->data[k * 2] = _src->data[k];
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_wide_modifier_get_path(const GScanWideModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("wide");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/wide.h b/src/analysis/scan/patterns/modifiers/wide.h
new file mode 100644
index 0000000..deb92a4
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/wide.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * wide.h - prototypes pour la transcription d'une séquence d'octets en UTF-16
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_WIDE_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_WIDE_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_WIDE_MODIFIER g_scan_wide_modifier_get_type()
+#define G_SCAN_WIDE_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_WIDE_MODIFIER, GScanWideModifier))
+#define G_IS_SCAN_WIDE_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_WIDE_MODIFIER))
+#define G_SCAN_WIDE_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_WIDE_MODIFIER, GScanWideModifierClass))
+#define G_IS_SCAN_WIDE_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_WIDE_MODIFIER))
+#define G_SCAN_WIDE_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_WIDE_MODIFIER, GScanWideModifierClass))
+
+
+/* Transcription d'une séquence d'octets en UTF-16 (instance) */
+typedef GScanTokenModifier GScanWideModifier;
+
+/* Transcription d'une séquence d'octets en UTF-16 (classe) */
+typedef GScanTokenModifierClass GScanWideModifierClass;
+
+
+/* Indique le type défini pour une transcription d'une séquence d'octets en UTF-16. */
+GType g_scan_wide_modifier_get_type(void);
+
+/* Construit un modificateur livrant des octets en UTF-16. */
+GScanTokenModifier *g_scan_wide_modifier_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_WIDE_H */
diff --git a/src/analysis/scan/patterns/modifiers/xor.c b/src/analysis/scan/patterns/modifiers/xor.c
new file mode 100644
index 0000000..d932c82
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/xor.c
@@ -0,0 +1,438 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * xor.c - transormation via opération XOR
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "xor.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions via opération XOR. */
+static void g_scan_xor_modifier_class_init(GScanXorModifierClass *klass);
+
+/* Initialise une instance de transmission via opération XOR. */
+static void g_scan_xor_modifier_init(GScanXorModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_xor_modifier_dispose(GScanXorModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_xor_modifier_finalize(GScanXorModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_xor_modifier_get_name(const GScanXorModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_xor_modifier_transform(const GScanXorModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Détermine si un argument est bien toléré par un modificateur. */
+static bool g_scan_xor_modifier_can_handle_arg(const GScanXorModifier *, const modifier_arg_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_xor_modifier_transform_with_arg(const GScanXorModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_xor_modifier_get_path(const GScanXorModifier *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation via une opération XOR. */
+G_DEFINE_TYPE(GScanXorModifier, g_scan_xor_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des transmissions via opération XOR. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_xor_modifier_class_init(GScanXorModifierClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenModifierClass *modifier; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_xor_modifier_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_xor_modifier_finalize;
+
+ modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+ modifier->get_name = (get_scan_modifier_name_fc)g_scan_xor_modifier_get_name;
+
+ modifier->transform = (transform_scan_token_fc)g_scan_xor_modifier_transform;
+ modifier->can_handle = (can_token_modifier_handle_arg)g_scan_xor_modifier_can_handle_arg;
+ modifier->transform_with = (transform_scan_token_with_fc)g_scan_xor_modifier_transform_with_arg;
+ modifier->get_path = (get_modifier_path)g_scan_xor_modifier_get_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance à initialiser. *
+* *
+* Description : Initialise une instance de transmission via opération XOR. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_xor_modifier_init(GScanXorModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_xor_modifier_dispose(GScanXorModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_xor_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_xor_modifier_finalize(GScanXorModifier *modifier)
+{
+ G_OBJECT_CLASS(g_scan_xor_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit un modificateur livrant des octets traités par XOR.*
+* *
+* Retour : Mécanisme mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_xor_modifier_new(void)
+{
+ GScanTokenModifier *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_XOR_MODIFIER, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* *
+* Description : Fournit le nom d'appel d'un modificateur pour motif. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_xor_modifier_get_name(const GScanXorModifier *modifier)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("xor");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_xor_modifier_transform(const GScanXorModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ long long x; /* Boucle de parcours #2 */
+ size_t k; /* Boucle de parcours #3 */
+
+ result = true;
+
+ *dcount = scount * 256;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++)
+ {
+ _src = src + i;
+
+ for (x = 0; x <= 0xff; x++, binary++)
+ {
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ binary->data[k] = _src->data[k] ^ x;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* arg = argument de personnalisation. *
+* *
+* Description : Détermine si un argument est bien toléré par un modificateur.*
+* *
+* Retour : Bilan de la consultation : support ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_xor_modifier_can_handle_arg(const GScanXorModifier *modifier, const modifier_arg_t *arg)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+
+ switch (arg->type)
+ {
+ case MAT_UNSIGNED_INTEGER:
+ result = (arg->value.u_integer <= UINT8_MAX);
+ break;
+
+ case MAT_RANGE:
+ result = (INT8_MIN <= arg->value.range.start && arg->value.range.end <= INT8_MAX);
+ break;
+
+ default:
+ result = false;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à solliciter. *
+* src = séquences d'octets à traiter. *
+* scount = quantité de ces séquences. *
+* arg = argument de personnalisation. *
+* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+* dcount = quantité de ces séquences. *
+* *
+* Description : Transforme une séquence d'octets pour motif de recherche. *
+* *
+* Retour : Bilan de l'opération : succès ou échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_xor_modifier_transform_with_arg(const GScanXorModifier *modifier, const sized_binary_t *src, size_t scount, const modifier_arg_t *arg, sized_binary_t **dest, size_t *dcount)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ sized_binary_t *binary; /* Raccourci vers le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ const sized_binary_t *_src; /* Source courante */
+ long long x; /* Boucle de parcours #2 */
+ size_t k; /* Boucle de parcours #3 */
+
+ result = true;
+
+ switch (arg->type)
+ {
+ case MAT_UNSIGNED_INTEGER:
+
+ *dcount = scount;
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++)
+ {
+ _src = src + i;
+
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ binary->data[k] = _src->data[k] ^ arg->value.u_integer;
+
+ }
+
+ break;
+
+ case MAT_RANGE:
+
+ *dcount = scount * (arg->value.range.end - arg->value.range.start + 1);
+ *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+ binary = &(*dest)[0];
+
+ for (i = 0; i < scount; i++)
+ {
+ _src = src + i;
+
+ for (x = arg->value.range.start; x <= arg->value.range.end; x++, binary++)
+ {
+ binary->len = _src->len;
+ binary->data = malloc(binary->len);
+
+ for (k = 0; k < _src->len; k++)
+ binary->data[k] = _src->data[k] ^ x;
+
+ }
+
+ }
+
+ break;
+
+ default:
+ assert(false);
+ result = false;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_xor_modifier_get_path(const GScanXorModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+ int ret; /* Bilan intermédiaire */
+
+ if (*index > 255)
+ {
+ result = NULL;
+ (*index) -= 256;
+ }
+
+ else
+ {
+ ret = asprintf(&result, "xor(0x%02hhx)", (unsigned char)*index);
+
+ if (ret == -1)
+ result = strdup("xor(0x?)");
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/xor.h b/src/analysis/scan/patterns/modifiers/xor.h
new file mode 100644
index 0000000..1a3e7e6
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/xor.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * xor.h - prototypes pour la transormation via opération XOR
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_XOR_MODIFIER g_scan_xor_modifier_get_type()
+#define G_SCAN_XOR_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_XOR_MODIFIER, GScanXorModifier))
+#define G_IS_SCAN_XOR_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_XOR_MODIFIER))
+#define G_SCAN_XOR_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_XOR_MODIFIER, GScanXorModifierClass))
+#define G_IS_SCAN_XOR_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_XOR_MODIFIER))
+#define G_SCAN_XOR_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_XOR_MODIFIER, GScanXorModifierClass))
+
+
+/* Transormation via inversement d'une séquence d'octets (instance) */
+typedef GScanTokenModifier GScanXorModifier;
+
+/* Transormation via inversement d'une séquence d'octets (classe) */
+typedef GScanTokenModifierClass GScanXorModifierClass;
+
+
+/* Indique le type défini pour une transormation via une opération XOR. */
+GType g_scan_xor_modifier_get_type(void);
+
+/* Construit un modificateur livrant des octets traités par XOR. */
+GScanTokenModifier *g_scan_xor_modifier_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H */
diff --git a/src/analysis/scan/patterns/patid.h b/src/analysis/scan/patterns/patid.h
new file mode 100644
index 0000000..e8b7eee
--- /dev/null
+++ b/src/analysis/scan/patterns/patid.h
@@ -0,0 +1,36 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * patid.h - prototypes pour la définition d'un identifiant de motif partiel
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_PATID_H
+#define _ANALYSIS_SCAN_PATTERNS_PATID_H
+
+
+
+/* Identifiant de motif intégré */
+typedef uint32_t patid_t;
+
+#define INVALID_PATTERN_ID 0xffffffff
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_PATID_H */
diff --git a/src/analysis/scan/patterns/token-int.h b/src/analysis/scan/patterns/token-int.h
new file mode 100644
index 0000000..7ba0aa4
--- /dev/null
+++ b/src/analysis/scan/patterns/token-int.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * token-int.h - prototypes internes pour les bribes de recherche textuelle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKEN_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKEN_INT_H
+
+
+#include "token.h"
+
+
+#include "../pattern-int.h"
+
+
+
+/* Encadrement d'une bribe de recherche textuelle (instance) */
+struct _GBytesToken
+{
+ GSearchPattern parent; /* A laisser en premier */
+
+ GScanTokenNode *root; /* Motif à rechercher */
+ size_t slow; /* Surcoût du motif */
+ bool need_backward; /* Besoin d'une seconde passe */
+
+ bool fullword; /* Cible de mots entiers ? */
+ bool private; /* Vocation privée ? */
+
+};
+
+/* Encadrement d'une bribe de recherche textuelle (classe) */
+struct _GBytesTokenClass
+{
+ GSearchPatternClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un gestionnaire de recherche de binaire. */
+bool g_bytes_token_create(GBytesToken *, GScanTokenNode *, bool, bool);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKEN_INT_H */
diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c
new file mode 100644
index 0000000..b3c6d53
--- /dev/null
+++ b/src/analysis/scan/patterns/token.c
@@ -0,0 +1,491 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * token.c - bribes de recherche textuelle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "token.h"
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+
+
+#include "token-int.h"
+#include "tokens/nodes/plain.h"
+#include "../../../common/cpp.h"
+#include "../../../core/logs.h"
+
+
+
+/* ------------------------- CIBLAGE DES SEQUENCES D'OCTETS ------------------------- */
+
+
+/* Initialise la classe des bribes de recherche textuelle. */
+static void g_bytes_token_class_init(GBytesTokenClass *);
+
+/* Initialise une instance de bribe de recherche textuelle. */
+static void g_bytes_token_init(GBytesToken *);
+
+/* Supprime toutes les références externes. */
+static void g_bytes_token_dispose(GBytesToken *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_bytes_token_finalize(GBytesToken *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Affiche un motif de recherche au format texte. */
+static void g_bytes_token_output_to_text(const GBytesToken *, GScanContext *, int);
+
+/* Affiche un motif de recherche au format JSON. */
+static void g_bytes_token_output_to_json(const GBytesToken *, GScanContext *, const sized_string_t *, unsigned int, int);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CIBLAGE DES SEQUENCES D'OCTETS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bribe de recherche textuelle. */
+G_DEFINE_TYPE(GBytesToken, g_bytes_token, G_TYPE_SEARCH_PATTERN);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bribes de recherche textuelle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bytes_token_class_init(GBytesTokenClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GSearchPatternClass *pattern; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_bytes_token_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_bytes_token_finalize;
+
+ pattern = G_SEARCH_PATTERN_CLASS(klass);
+
+ pattern->to_text = (output_pattern_to_text_fc)g_bytes_token_output_to_text;
+ pattern->to_json = (output_pattern_to_json_fc)g_bytes_token_output_to_json;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = instance à initialiser. *
+* *
+* Description : Initialise une instance de bribe de recherche textuelle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bytes_token_init(GBytesToken *token)
+{
+ token->root = NULL;
+ token->slow = 0;
+ token->need_backward = false;
+
+ token->fullword = false;
+ token->private = false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bytes_token_dispose(GBytesToken *token)
+{
+ g_clear_object(&token->root);
+
+ G_OBJECT_CLASS(g_bytes_token_parent_class)->dispose(G_OBJECT(token));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bytes_token_finalize(GBytesToken *token)
+{
+ G_OBJECT_CLASS(g_bytes_token_parent_class)->finalize(G_OBJECT(token));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = encadrement de motif à initialiser pleinement. *
+* root = représentation du motif à recherche. *
+* fullword = limite les correspondances à des mots entiers. *
+* private = donne une vocation privée au motif de recherche. *
+* *
+* Description : Met en place un gestionnaire de recherche de binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_bytes_token_create(GBytesToken *token, GScanTokenNode *root, bool fullword, bool private)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ token->root = root;
+ g_object_ref(G_OBJECT(root));
+
+ token->fullword = fullword;
+ token->private = private;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = encadrement de motif à consulter. *
+* *
+* Description : Indique si seuls des mots entiers sont retenus des analyses. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_bytes_token_target_fullword(const GBytesToken *token)
+{
+ bool result; /* Statut à renvoyer */
+
+ result = token->fullword;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = encadrement de motif à consulter. *
+* *
+* Description : Détermine si le gestionnaire est à vocation privée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_bytes_token_is_private(const GBytesToken *token)
+{
+ bool result; /* Statut à renvoyer */
+
+ result = token->private;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_bytes_token_enroll(GBytesToken *token, GEngineBackend *backend, size_t maxsize)
+{
+ bool result; /* Statut à retourner */
+
+ token->need_backward = g_scan_token_node_setup_tree(token->root);
+
+ result = g_scan_token_node_enroll(token->root, backend, maxsize, &token->slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = définition de la bribe à peaufiner. *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère les identifiants finaux pour un motif recherché. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_bytes_token_build_id(GBytesToken *token, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+
+ result = g_scan_token_node_build_id(token->root, backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = définition de la bribe à manipuler. *
+* matches = suivi des correspondances à consolider. *
+* params = paramètres des opérations de validation. *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_bytes_token_check(const GBytesToken *token, GScanBytesMatches *matches, scan_node_check_params_t *params)
+{
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ vmpa2t pos; /* Tête de lecture */
+ const bin_t *byte; /* Octet à valider */
+
+ /* Réinitialisation */
+
+ // TODO: offset
+
+ params->initialized = false;
+
+ params->main_areas = NULL;
+ params->main_count = 0;
+
+ params->created_areas = NULL;
+ params->created_count = 0;
+
+ params->kept_areas = NULL;
+ params->kept_count = 0;
+
+ /* Lancement des analyses */
+
+ g_scan_token_node_check_forward(token->root, params);
+
+ if (token->need_backward)
+ g_scan_token_node_check_backward(token->root, params);
+
+ // REMME ? sort_and_filter_pending_matches(matches);
+
+ if (token->fullword)
+ {
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ /* Validation de l'octet précédent, s'il existe */
+ if (area->start > params->content_start)
+ {
+ init_vmpa(&pos, area->start - 1, VMPA_NO_VIRTUAL);
+
+ byte = g_binary_content_get_raw_access(params->content, &pos, 1);
+
+ if (isalnum(*byte))
+ {
+ del_match_area(area, &params->main_areas);
+ assert(&params->main_count > 0);
+ params->main_count--;
+ continue;
+ }
+
+ }
+
+ /* Validation de l'octet suivant, s'il existe */
+ if (area->end < params->content_end)
+ {
+ init_vmpa(&pos, area->end, VMPA_NO_VIRTUAL);
+
+ byte = g_binary_content_get_raw_access(params->content, &pos, 1);
+
+ if (isalnum(*byte))
+ {
+ del_match_area(area, &params->main_areas);
+ assert(&params->main_count > 0);
+ params->main_count--;
+ continue;
+ }
+
+ }
+
+ }
+
+ }
+
+ g_scan_bytes_matches_set_list(matches, params->main_areas, params->main_count);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : token = définition de la bribe à consulter. *
+* index = indice de la combinaison de modificateurs ciblée. *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison gagnante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_bytes_token_get_modifier_path(const GBytesToken *token, size_t index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (G_IS_SCAN_TOKEN_NODE_PLAIN(token->root))
+ result = g_scan_token_node_plain_get_modifier_path(G_SCAN_TOKEN_NODE_PLAIN(token->root), index);
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un motif de recherche au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bytes_token_output_to_text(const GBytesToken *pattern, GScanContext *context, int fd)
+{
+ GScanMatches *matches; /* Correspondances établies */
+
+ if (g_bytes_token_is_private(pattern))
+ return;
+
+ matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern));
+
+ if (matches != NULL)
+ {
+ g_scan_matches_output_to_text(matches, fd);
+
+ g_object_unref(G_OBJECT(matches));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un motif de recherche au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_bytes_token_output_to_json(const GBytesToken *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd)
+{
+ GScanMatches *matches; /* Correspondances établies */
+
+ if (g_bytes_token_is_private(pattern))
+ return;
+
+ matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern));
+
+ if (matches != NULL)
+ {
+ g_scan_matches_output_to_json(matches, padding, level, fd);
+
+ g_object_unref(G_OBJECT(matches));
+
+ }
+
+}
diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h
new file mode 100644
index 0000000..f5b78f6
--- /dev/null
+++ b/src/analysis/scan/patterns/token.h
@@ -0,0 +1,75 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * token.h - prototypes pour les bribes de recherche textuelle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKEN_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKEN_H
+
+
+#include <glib-object.h>
+
+
+#include "backend.h"
+#include "tokens/node.h"
+#include "../matches/bytes.h"
+
+
+
+#define G_TYPE_BYTES_TOKEN g_bytes_token_get_type()
+#define G_BYTES_TOKEN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BYTES_TOKEN, GBytesToken))
+#define G_IS_BYTES_TOKEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BYTES_TOKEN))
+#define G_BYTES_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BYTES_TOKEN, GBytesTokenClass))
+#define G_IS_BYTES_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BYTES_TOKEN))
+#define G_BYTES_TOKEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BYTES_TOKEN, GBytesTokenClass))
+
+
+/* Encadrement d'une bribe de recherche textuelle (instance) */
+typedef struct _GBytesToken GBytesToken;
+
+/* Encadrement d'une bribe de recherche textuelle (classe) */
+typedef struct _GBytesTokenClass GBytesTokenClass;
+
+
+/* Indique le type défini pour une bribe de recherche textuelle. */
+GType g_bytes_token_get_type(void);
+
+/* Indique si seuls des mots entiers sont retenus des analyses. */
+bool g_bytes_token_target_fullword(const GBytesToken *);
+
+/* Détermine si le gestionnaire est à vocation privée. */
+bool g_bytes_token_is_private(const GBytesToken *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+bool g_bytes_token_enroll(GBytesToken *, GEngineBackend *, size_t);
+
+/* Récupère les identifiants finaux pour un motif recherché. */
+bool g_bytes_token_build_id(GBytesToken *, GEngineBackend *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void g_bytes_token_check(const GBytesToken *, GScanBytesMatches *, scan_node_check_params_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_bytes_token_get_modifier_path(const GBytesToken *, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKEN_H */
diff --git a/src/analysis/scan/patterns/tokens/Makefile.am b/src/analysis/scan/patterns/tokens/Makefile.am
new file mode 100644
index 0000000..f0ab3d5
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/Makefile.am
@@ -0,0 +1,26 @@
+
+noinst_LTLIBRARIES = libanalysisscanpatternstokens.la
+
+
+libanalysisscanpatternstokens_la_SOURCES = \
+ atom.h atom.c \
+ hex-int.h \
+ hex.h hex.c \
+ node-int.h \
+ node.h node.c \
+ offset.h offset.c \
+ plain-int.h \
+ plain.h plain.c
+
+libanalysisscanpatternstokens_la_LIBADD = \
+ nodes/libanalysisscanpatternstokensnodes.la
+
+libanalysisscanpatternstokens_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanpatternstokens_la_SOURCES:%c=)
+
+
+SUBDIRS = nodes
diff --git a/src/analysis/scan/patterns/tokens/atom.c b/src/analysis/scan/patterns/tokens/atom.c
new file mode 100644
index 0000000..4f2ad67
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/atom.c
@@ -0,0 +1,543 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * atom.c - détermination d'atomes à partir de motifs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "atom.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <math.h>
+
+
+
+/**
+ * Remplacement des fonctions de <ctypes.h> dans support des locales.
+ */
+
+#define IS_CH_LETTER(ch) (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z'))
+
+#define MAKE_CH_UPPER(ch) (ch & 0xdf)
+#define MAKE_CH_LOWER(ch) (ch | 0x20)
+
+
+
+/******************************************************************************
+* *
+* Paramètres : ch = octet dont la valeur est à analyser. *
+* seen = suivi des octets déjà rencontrés. [OUT] *
+* uniq = volume d'octets originaux à actualiser. [OUT] *
+* letters = nombre de lettres rencontrées. [OUT] *
+* *
+* Description : Note l'intêret de rechercher un octet particulier. *
+* *
+* Retour : Note positive ou négative. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int rate_byte_quality(bin_t ch, uint8_t *seen, size_t *uniq, size_t *letters)
+{
+ int result; /* Note à retourner */
+
+ switch (ch)
+ {
+ case 0x00:
+ case 0x20:
+ case 0x90:
+ case 0xcc:
+ case 0xff:
+ result = 12;
+ break;
+
+ case 'A' ... 'Z':
+ case 'a' ... 'z':
+ if (letters == NULL)
+ result = 20;
+ else
+ {
+ result = 18;
+ (*letters)++;
+ }
+ break;
+
+ default:
+ result = 20;
+ break;
+
+ }
+
+ if (seen[ch]++ == 0)
+ (*uniq)++;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : ch = octet dont la valeur est à analyser. *
+* seen = suivi des octets déjà rencontrés. [OUT] *
+* uniq = volume d'octets originaux à actualiser. [OUT] *
+* letters = nombre de lettres rencontrées. [OUT] *
+* *
+* Description : Annihile l'intêret de rechercher un octet particulier. *
+* *
+* Retour : Note positive ou négative. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int unrate_byte_quality(bin_t ch, uint8_t *seen, size_t *uniq, size_t *letters)
+{
+ int result; /* Note à retourner */
+
+ switch (ch)
+ {
+ case 0x00:
+ case 0x20:
+ case 0x90:
+ case 0xcc:
+ case 0xff:
+ result = 12;
+ break;
+
+ case 'A' ... 'Z':
+ case 'a' ... 'z':
+ if (letters == NULL)
+ result = 20;
+ else
+ {
+ result = 18;
+ assert(*letters > 0);
+ (*letters)--;
+ }
+ break;
+
+ default:
+ result = 20;
+ break;
+
+ }
+
+ if (--seen[ch] == 0)
+ {
+ assert(*uniq > 0);
+ (*uniq)--;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rating = note d'évaluation courante. *
+* uniq = volume d'octets originaux relevés. *
+* max = nombre d'octets considérés à la base. *
+* *
+* Description : Termine la notation d'un ensemble d'octets. *
+* *
+* Retour : Note positive ou négative. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int finish_quality_rating(int rating, size_t uniq, size_t max)
+{
+ int result; /* Note à retourner */
+ bool bad; /* Indice de mauvaise qualité */
+
+ if (uniq == 1)
+ {
+ bad = (rating % 12) == 0;
+
+ result = (bad ? -10 * max : 2);
+
+ }
+
+ else
+ result = uniq * 2;
+
+ result += rating;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : raw = définition de la bribe à enregistrer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* atom = informations de suivi constituées. [OUT] *
+* letters = nombre de lettres rencontrées. [OUT] *
+* *
+* Description : Détermine la portion idéale de recherche. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom_t *atom, size_t *letters)
+{
+ size_t i; /* Boucle de parcours #1 */
+ bin_t ch; /* Octets à étudier */
+ size_t best_letters; /* Mémorisation de décompte */
+ size_t *ptr_letters; /* Pointeur vers le décompte */
+ int raw_rating; /* Notation brute de séquence */
+ uint8_t seen[256]; /* Mémorisation des passages */
+ size_t uniq; /* Nombre d'octets originaux */
+ const bin_t *last; /* Dernier caractère étudié */
+ int best_rating; /* Meilleur notation obtenue */
+ size_t max_loop; /* Limitation des itérations */
+ size_t k; /* Boucle de parcours #2 */
+ size_t local_letters; /* Décompte courant des lettres*/
+ int local_rating; /* Notation courante */
+ const bin_t *first; /* Premier caractère étudié */
+
+ /* Si la chaîne fournie est plus petite que la taille d'un atome... */
+ if (raw->len <= maxsize)
+ {
+ atom->pos = 0;
+ atom->len = raw->len;
+ atom->rem = 0;
+
+ atom->fast_check = true;
+
+ if (letters != NULL)
+ {
+ *letters = 0;
+
+ for (i = 0; i < raw->len; i++)
+ {
+ ch = raw->data[i];
+
+ if (IS_CH_LETTER(ch))
+ (*letters)++;
+
+ }
+
+ }
+
+ }
+
+ /* ... ou si une sélection doit s'opérer */
+ else
+ {
+ /* Etablissement d'une mesure de référence à la position 0 */
+
+ atom->pos = 0;
+ atom->len = maxsize;
+
+ ptr_letters = (letters != NULL ? &best_letters : NULL);
+
+ best_letters = 0;
+ raw_rating = 0;
+
+ memset(seen, 0, sizeof(seen));
+ uniq = 0;
+
+ last = raw->static_bin_data;
+
+ for (k = 0; k < maxsize; k++)
+ raw_rating += rate_byte_quality(*last++, seen, &uniq, ptr_letters);
+
+ best_rating = finish_quality_rating(raw_rating, uniq, maxsize);
+
+ /* Parcours du reste du contenu */
+
+ max_loop = (raw->len - maxsize);
+
+ ptr_letters = (letters != NULL ? &local_letters : NULL);
+
+ local_letters = best_letters;
+ local_rating = best_rating;
+
+ first = raw->static_bin_data;
+
+ for (i = 0; i < max_loop; i++)
+ {
+ raw_rating += rate_byte_quality(*last++, seen, &uniq, ptr_letters);
+ raw_rating -= unrate_byte_quality(*first++, seen, &uniq, ptr_letters);
+
+ local_rating = finish_quality_rating(raw_rating , uniq, maxsize);
+
+ if (local_rating > best_rating)
+ {
+ atom->pos = i + 1;
+
+ best_letters = local_letters;
+ best_rating = local_rating;
+
+ }
+
+ }
+
+ /* Conclusion */
+
+ atom->rem = raw->len - atom->pos - maxsize;
+
+ atom->fast_check = false;
+
+ if (letters != NULL)
+ *letters = best_letters;
+
+ }
+
+ assert((atom->fast_check && atom->pos == 0 && atom->rem == 0)
+ || (!atom->fast_check && (atom->pos != 0 || atom->rem != 0)));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = chaîne ed référence à dupliquer. *
+* atom = préselection opérée en amont. *
+* count = nombre de lettres présentes. *
+* *
+* Description : Etablit la liste des cas de figures ignorant la casse. *
+* *
+* Retour : Liste de toutes les combinaisons possibles. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, const tracked_scan_atom_t *atom, size_t count)
+{
+ sized_binary_t *result; /* Liste à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ size_t replaced; /* 2^(alternatives créées) */
+#ifndef NDEBUG
+ size_t check; /* Validation du compte max. */
+#endif
+ bin_t ch; /* Octet à recopier */
+ size_t k; /* Boucle de parcours #2 */
+ size_t divisor; /* Taille de la découpe */
+ size_t quotient; /* Reste de la position */
+
+ /* Création du réceptacle */
+
+ result = malloc(count * sizeof(tracked_scan_atom_t));
+
+ assert(src->len == (atom->pos + atom->len + atom->rem));
+
+ for (i = 0; i < count; i++)
+ {
+ result[i].data = malloc(src->len);
+ result[i].len = src->len;
+
+ memcpy(result[i].data, src->data, atom->pos);
+ memcpy(&result[i].data[atom->pos + atom->len], &src->data[atom->pos + atom->len], atom->rem);
+
+ }
+
+ /* Remplissage */
+
+ replaced = 2;
+
+#ifndef NDEBUG
+ check = 1;
+#endif
+
+ for (i = atom->pos; i < (atom->pos + atom->len); i++)
+ {
+ ch = src->data[i];
+
+ if (IS_CH_LETTER(ch))
+ {
+ for (k = 0; k < count; k++)
+ {
+ divisor = count / replaced;
+ quotient = k / divisor;
+
+ if ((quotient % 2) == 0)
+ result[k].data[i] = MAKE_CH_UPPER(ch);
+ else
+ result[k].data[i] = MAKE_CH_LOWER(ch);
+
+ }
+
+ replaced *= 2;
+
+#ifndef NDEBUG
+ check *= 2;
+ assert(check <= count);
+#endif
+
+ }
+ else
+ for (k = 0; k < count; k++)
+ result[k].data[i] = ch;
+
+ }
+
+ assert(check == count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = octets partiels avec leur masque à interpréter. *
+* len = quantité d'octets à interpréter. *
+* produced = nombre de contenus générés. [OUT] *
+* *
+* Description : Etablit la liste des cas de figures avec des octets partiels.*
+* *
+* Retour : Liste de toutes les combinaisons possibles. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+sized_binary_t *make_atoms_from_masked_bytes(const masked_byte_t *bytes, size_t len, size_t *produced)
+{
+ sized_binary_t *result; /* Liste à retourner */
+ size_t seq_len; /* Taille de séquence retenue */
+ size_t repeat_times; /* Répétitions pour remplissage*/
+ sized_binary_t *maxiter; /* Borne de fin de parcours */
+ size_t i; /* Boucle de parcours #1 */
+ sized_binary_t *iter; /* Boucle de parcours #2 */
+ size_t j; /* Boucle de parcours #3 */
+ size_t k; /* Boucle de parcours #4 */
+
+ seq_len = (len > MASK_MAX_LEN_FOR_ATOMS ? MASK_MAX_LEN_FOR_ATOMS : len);
+
+ /**
+ * Si l'usage de la fonction pow() disparaît, la bibliothèque m
+ * peut être retirée de libchrysacore_la_LDFLAGS dans le Makefile
+ * principal.
+ */
+ repeat_times = pow(16, seq_len - 1);
+
+ *produced = 16 * repeat_times;
+
+ /* Création du réceptacle */
+
+ result = malloc(*produced * sizeof(tracked_scan_atom_t));
+
+ maxiter = result + *produced;
+
+ /* Remplissage */
+
+ for (i = 0; i < seq_len; i++)
+ {
+ for (iter = result; iter < maxiter; )
+ {
+ for (j = 0; j < 16; j++)
+ {
+ assert(bytes[i].mask == 0x0f || bytes[i].mask == 0xf0);
+
+ for (k = 0; k < repeat_times; k++)
+ {
+ if (i == 0)
+ {
+ iter->data = malloc(seq_len);
+ iter->len = seq_len;
+ }
+
+ if (bytes[i].mask == 0x0f)
+ iter->data[i] = bytes[i].value | (j << 4);
+ else
+ iter->data[i] = bytes[i].value | j;
+
+ iter++;
+
+ }
+
+ }
+
+ }
+
+ repeat_times /= 16;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : raw = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* atom = informations de suivi constituées. [OUT] *
+* *
+* Description : Amorce l'insertion de l'atome déterminé d'une série d'octets.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool enroll_prepared_atom(const sized_binary_t *raw, GEngineBackend *backend, tracked_scan_atom_t *atom)
+{
+ bool result; /* Statut à retourner */
+ const bin_t *data; /* Données à rechercher */
+
+ data = raw->static_bin_data + atom->pos;
+
+ result = g_engine_backend_enroll_plain_pattern(backend, data, atom->len, atom->tmp_id);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : atom = informations de suivi constituées. [OUT] *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère un identifiant final pour un atome d'octets. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool build_atom_pattern_id(tracked_scan_atom_t *atom, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+
+ atom->pid = g_engine_backend_build_plain_pattern_id(backend, atom->tmp_id);
+
+ result = (atom->pid != INVALID_PATTERN_ID);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/tokens/atom.h b/src/analysis/scan/patterns/tokens/atom.h
new file mode 100644
index 0000000..1ef8f40
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/atom.h
@@ -0,0 +1,88 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * atom.h - prototypes pour la détermination d'atomes à partir de motifs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H
+
+
+#include <stdbool.h>
+
+
+#include "../backend.h"
+#include "../../../../arch/vmpa.h"
+#include "../../../../common/szstr.h"
+
+
+
+/* Suivi des motifs réellement recherchés */
+typedef struct _tracked_scan_atom_t
+{
+ phys_t pos; /* Début de sélection atomique */
+ phys_t len; /* Taille de ladite sélection */
+ phys_t rem; /* Reste après l'atome */
+
+ bool fast_check; /* Besoin de vérifications ? */
+
+ uint32_t tmp_id[2]; /* Couple d'identifiants temp. */
+
+ patid_t pid; /* Identifiant de la bribe */
+
+} tracked_scan_atom_t;
+
+/* Note l'intêret de rechercher un octet particulier. */
+int rate_byte_quality(bin_t, uint8_t *, size_t *, size_t *);
+
+/* Annihile l'intêret de rechercher un octet particulier. */
+int unrate_byte_quality(bin_t, uint8_t *, size_t *, size_t *);
+
+/* Termine la notation d'un ensemble d'octets. */
+int finish_quality_rating(int, size_t, size_t);
+
+/* Détermine la portion idéale de recherche. */
+void find_best_atom(const sized_binary_t *, size_t , tracked_scan_atom_t *, size_t *);
+
+/* Etablit la liste des cas de figures ignorant la casse. */
+sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, const tracked_scan_atom_t *, size_t);
+
+/* Mémorisation d'un octet visé avec son masque */
+typedef struct _masked_byte_t
+{
+ bin_t value; /* Valeur de l'octet visé */
+ bin_t mask; /* Masque à appliquer */
+
+} masked_byte_t;
+
+#define MASK_MAX_LEN_FOR_ATOMS 2
+
+/* Etablit la liste des cas de figures avec des octets partiels. */
+sized_binary_t *make_atoms_from_masked_bytes(const masked_byte_t *, size_t, size_t *);
+
+/* Amorce l'insertion de l'atome déterminé d'une série d'octets. */
+bool enroll_prepared_atom(const sized_binary_t *, GEngineBackend *, tracked_scan_atom_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+bool build_atom_pattern_id(tracked_scan_atom_t *, GEngineBackend *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H */
diff --git a/src/analysis/scan/patterns/tokens/hex-int.h b/src/analysis/scan/patterns/tokens/hex-int.h
new file mode 100644
index 0000000..dca9848
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/hex-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex-int.h - prototypes internes pour la recherche de morceaux de binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H
+
+
+#include "hex.h"
+
+
+#include "atom.h"
+#include "../token-int.h"
+
+
+
+/* Encadrement d'une recherche de morceaux de binaire (instance) */
+struct _GScanHexBytes
+{
+ GBytesToken parent; /* A laisser en premier */
+
+};
+
+/* Encadrement d'une recherche de morceaux de binaire (classe) */
+struct _GScanHexBytesClass
+{
+ GBytesTokenClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un gestionnaire de recherche de binaire. */
+bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *, bool);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/hex.c b/src/analysis/scan/patterns/tokens/hex.c
new file mode 100644
index 0000000..89d7ca4
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/hex.c
@@ -0,0 +1,259 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.c - recherche de morceaux de binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hex.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "hex-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des recherches de texte brut. */
+static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass);
+
+/* Initialise une instance de recherche de texte brut. */
+static void g_scan_hex_bytes_init(GScanHexBytes *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_hex_bytes_dispose(GScanHexBytes *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_hex_bytes_finalize(GScanHexBytes *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Affiche un motif de recherche au format texte. */
+static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *, GScanContext *, int);
+
+/* Affiche un motif de recherche au format JSON. */
+static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *, GScanContext *, const sized_string_t *, unsigned int, int);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */
+G_DEFINE_TYPE(GScanHexBytes, g_scan_hex_bytes, G_TYPE_BYTES_TOKEN);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des recherches de texte brut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GSearchPatternClass *pattern; /* Version de classe ancêtre */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_hex_bytes_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_hex_bytes_finalize;
+
+ pattern = G_SEARCH_PATTERN_CLASS(klass);
+
+ pattern->to_text = (output_pattern_to_text_fc)g_scan_hex_bytes_output_to_text;
+ pattern->to_json = (output_pattern_to_json_fc)g_scan_hex_bytes_output_to_json;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = instance à initialiser. *
+* *
+* Description : Initialise une instance de recherche de texte brut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_bytes_init(GScanHexBytes *bytes)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_bytes_dispose(GScanHexBytes *bytes)
+{
+ G_OBJECT_CLASS(g_scan_hex_bytes_parent_class)->dispose(G_OBJECT(bytes));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes)
+{
+ G_OBJECT_CLASS(g_scan_hex_bytes_parent_class)->finalize(G_OBJECT(bytes));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : root = représentation du motif à recherche. *
+* private = donne une vocation privée au motif de recherche. *
+* *
+* Description : Construit un gestionnaire de recherche de texte brut. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root, bool private)
+{
+ GSearchPattern *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_HEX_BYTES, NULL);
+
+ if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root, private))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = encadrement de motif à initialiser pleinement. *
+* root = représentation du motif à recherche. *
+* private = donne une vocation privée au motif de recherche. *
+* *
+* Description : Met en place un gestionnaire de recherche de binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root, bool private)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_bytes_token_create(G_BYTES_TOKEN(bytes), root, false, private);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un motif de recherche au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *pattern, GScanContext *context, int fd)
+{
+ G_SEARCH_PATTERN_CLASS(g_scan_hex_bytes_parent_class)->to_text(G_SEARCH_PATTERN(pattern), context, fd);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un motif de recherche au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd)
+{
+ G_SEARCH_PATTERN_CLASS(g_scan_hex_bytes_parent_class)->to_json(G_SEARCH_PATTERN(pattern), context, padding, level, fd);
+
+ /* TODO */
+
+}
diff --git a/src/analysis/scan/patterns/tokens/hex.h b/src/analysis/scan/patterns/tokens/hex.h
new file mode 100644
index 0000000..fe5268c
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/hex.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.h - prototypes pour la recherche de morceaux de binaire
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H
+
+
+#include <glib-object.h>
+
+
+#include "node.h"
+#include "../../pattern.h"
+
+
+
+#define G_TYPE_SCAN_HEX_BYTES g_scan_hex_bytes_get_type()
+#define G_SCAN_HEX_BYTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_HEX_BYTES, GScanHexBytes))
+#define G_IS_SCAN_HEX_BYTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_HEX_BYTES))
+#define G_SCAN_HEX_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_HEX_BYTES, GScanHexBytesClass))
+#define G_IS_SCAN_HEX_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_HEX_BYTES))
+#define G_SCAN_HEX_BYTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_HEX_BYTES, GScanHexBytesClass))
+
+
+/* Encadrement d'une recherche de morceaux de binaire (instance) */
+typedef struct _GScanHexBytes GScanHexBytes;
+
+/* Encadrement d'une recherche de morceaux de binaire (classe) */
+typedef struct _GScanHexBytesClass GScanHexBytesClass;
+
+
+/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */
+GType g_scan_hex_bytes_get_type(void);
+
+/* Construit un gestionnaire de recherche de texte brut. */
+GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *, bool);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H */
diff --git a/src/analysis/scan/patterns/tokens/node-int.h b/src/analysis/scan/patterns/tokens/node-int.h
new file mode 100644
index 0000000..520e2a4
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/node-int.h
@@ -0,0 +1,108 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * node-int.h - prototypes internes pour la décomposition d'un motif de recherche en atomes assemblés
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H
+
+
+#include "node.h"
+
+
+
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+typedef float (* compute_scan_token_node_weight_fc) (const GScanTokenNode *);
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+typedef void (* apply_scan_token_node_flags_fc) (GScanTokenNode *, ScanTokenNodeFlags);
+
+/* Noeuds clefs de l'arborescence mise en place */
+typedef struct _scan_tree_points_t
+{
+ GScanTokenNode *first_plain; /* Premier noeud textuel */
+ GScanTokenNode *best_masked; /* Noeud masqué le plus long */
+
+} scan_tree_points_t;
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+typedef void (* visit_scan_token_node_fc) (GScanTokenNode *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+typedef bool (* build_scan_token_node_id_fc) (GScanTokenNode *, GEngineBackend *);
+
+typedef enum _TokenNodeCheckFlags
+{
+ TNCF_UPDATE_IN_PLACE = (1 << 0), /* Actualisation de l'entrée */
+ TNCF_CREATE_NEW = (1 << 1), /* Allocation de positions */
+ TNCF_KEEP_DISCARDED = (1 << 2), /* Inversion des résultats */
+
+} TokenNodeCheckFlags;
+
+/* Transforme les correspondances locales en trouvailles. */
+typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+/* Décomposition d'un motif de recherche en atomes (instance) */
+struct _GScanTokenNode
+{
+ GObject parent; /* A laisser en premier */
+
+ ScanTokenNodeFlags flags; /* Propriétés particulières */
+
+};
+
+/* Décomposition d'un motif de recherche en atomes (classe) */
+struct _GScanTokenNodeClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ compute_scan_token_node_weight_fc compute_weight; /* Evaluation */
+ visit_scan_token_node_fc visit; /* Phase de répérage initial */
+ apply_scan_token_node_flags_fc apply; /* Prise en compte de fanions */
+
+ enroll_scan_token_node_fc enroll; /* Inscription d'un motif */
+ build_scan_token_node_id_fc build_id; /* Récupération d'identifiant */
+
+ check_scan_token_node_fc check_forward; /* Conversion en trouvailles */
+ check_scan_token_node_fc check_backward;/* Conversion en trouvailles */
+
+};
+
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+void g_scan_token_node_visit(GScanTokenNode *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+bool _g_scan_token_node_enroll(GScanTokenNode *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void _g_scan_token_node_check_forward(const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void _g_scan_token_node_check_backward(const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/node.c b/src/analysis/scan/patterns/tokens/node.c
new file mode 100644
index 0000000..767cc6d
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/node.c
@@ -0,0 +1,675 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * node.c - décomposition d'un motif de recherche en atomes assemblés
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "node.h"
+
+
+#include <assert.h>
+
+
+#include "node-int.h"
+#include "nodes/any.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des éléments de décomposition. */
+static void g_scan_token_node_class_init(GScanTokenNodeClass *);
+
+/* Initialise une instance d'élément décomposant un motif. */
+static void g_scan_token_node_init(GScanTokenNode *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_dispose(GScanTokenNode *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_finalize(GScanTokenNode *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */
+G_DEFINE_TYPE(GScanTokenNode, g_scan_token_node, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des éléments de décomposition. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_class_init(GScanTokenNodeClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = instance à initialiser. *
+* *
+* Description : Initialise une instance d'élément décomposant un motif. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_init(GScanTokenNode *node)
+{
+ node->flags = STNF_NONE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_dispose(GScanTokenNode *node)
+{
+ G_OBJECT_CLASS(g_scan_token_node_parent_class)->dispose(G_OBJECT(node));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_finalize(GScanTokenNode *node)
+{
+ G_OBJECT_CLASS(g_scan_token_node_parent_class)->finalize(G_OBJECT(node));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à consulter. *
+* *
+* Description : Communique l'intérêt d'un noeud au sein d'une analyse. *
+* *
+* Retour : Poids de l'importance pour un départ de scan. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+float g_scan_token_node_compute_weight_for_scan(const GScanTokenNode *node)
+{
+ float result; /* Valeur à retourner */
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ if (class->compute_weight != NULL)
+ result = class->compute_weight(node);
+ else
+ result = 0;
+
+ return result;
+
+}
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à consulter. *
+* *
+* Description : Indique les propriétés particulières d'un noeud d'analyse. *
+* *
+* Retour : Propriétés particulières associées au noeud. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *node)
+{
+ ScanTokenNodeFlags result; /* Statut à retourner */
+
+ result = node->flags;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à mettre à jour. *
+* flags = propriétés particulières à associer au noeud. *
+* *
+* Description : Marque le noeud avec des propriétés particulières. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_set_flags(GScanTokenNode *node, ScanTokenNodeFlags flags)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ node->flags |= flags;
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ if (class->apply != NULL)
+ class->apply(node, flags);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_visit(GScanTokenNode *node, scan_tree_points_t *points)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ if (class->visit != NULL)
+ class->visit(node, points);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à préparer. *
+* *
+* Description : Détermine et prépare les éléments clefs d'une arborescence. *
+* *
+* Retour : true si une analyse à rebourd complémentaire est requise. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_setup_tree(GScanTokenNode *node)
+{
+ bool result; /* Prévision à retourner */
+ scan_tree_points_t points; /* Repérage de points capitaux */
+ GScanTokenNode *main; /* Principal noeud d'opération */
+
+ /* Phase de localisation */
+
+ points.first_plain = NULL;
+ points.best_masked = NULL;
+
+ g_scan_token_node_visit(node, &points);
+
+ /* Phase d'application */
+
+ g_scan_token_node_set_flags(node, STNF_FIRST);
+ g_scan_token_node_set_flags(node, STNF_LAST);
+
+ if (points.first_plain != NULL)
+ main = points.first_plain;
+
+ else if (points.best_masked != NULL)
+ main = points.best_masked;
+
+ else
+ main = node;
+
+ g_scan_token_node_set_flags(main, STNF_MAIN);
+
+ result = (main != node);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool _g_scan_token_node_enroll(GScanTokenNode *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ result = class->enroll(node, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_enroll(GScanTokenNode *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+
+ assert(g_engine_backend_get_atom_max_size(backend) == maxsize);
+
+ *slow = 0;
+
+ result = _g_scan_token_node_enroll(node, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à peaufiner. *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère un identifiant final pour un atome d'octets. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_build_id(GScanTokenNode *node, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ if (class->build_id == NULL)
+ result = true;
+ else
+ result = class->build_id(node, backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void _g_scan_token_node_check_forward(const GScanTokenNode *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ if (node->flags & STNF_MAIN)
+ {
+ //assert(*skip); //REMME
+ *skip = false;
+ }
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ class->check_forward(node, params, cflags, skip);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_check_forward(const GScanTokenNode *node, scan_node_check_params_t *params)
+{
+ node_search_offset_t offset; /* Espace des correspondances */
+ bool skip; /* Mise en attente des analyses*/
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t p; /* Boucle de parcours #2 */
+ match_area_t *pending; /* Correspondance à traiter */
+ phys_t old_end; /* Ancien point d'arrivée */
+ size_t o; /* Boucle de parcours #1 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ phys_t new_end; /* Nouveau point d'arrivée */
+
+ init_node_search_offset(&params->offset);
+
+ skip = true;
+
+ _g_scan_token_node_check_forward(node, params, TNCF_UPDATE_IN_PLACE, &skip);
+
+
+#if 0 // FIXME
+
+ /**
+ * Si un décalage entre octets n'a pas été consommé,
+ * les résultats sont étendus à minima.
+ */
+
+ ranges_ptr = get_node_search_offset_ranges(&offset, &ocount);
+
+ if (ocount > 0)
+ {
+ /**
+ * Dans le cas où un unique noeud ne renvoie que vers un espace (par
+ * exemple : "$a = { [0] }"), il n'y a pas de résultats, donc pas
+ * d'initialisation.
+ *
+ * La réinitialisation des décomptes va tiquer pour cet état. La
+ * phase d'extension des résultats inexistants est ainsi sautée.
+ */
+ if (count_pending_matches(matches) == 0)
+ {
+
+
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+
+ printf("range: %u - %u\n",
+ (unsigned int)range->min,
+ (unsigned int)range->max);
+
+
+ /*
+ new_end = old_end + range->min;
+
+ if (new_end > matches->content_end)
+ new_end = matches->content_end;
+
+ add_pending_match(pending_matches_t *, phys_t, phys_t);
+
+ extend_pending_match_ending(matches, p, new_end);
+ */
+
+ }
+
+
+
+
+
+
+ goto offset_done;
+
+ }
+
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ old_end = pending->end;
+
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ new_end = old_end + range->min;
+
+ if (new_end > matches->content_end)
+ new_end = matches->content_end;
+
+ extend_pending_match_ending(matches, p, new_end);
+
+ }
+
+ }
+
+ /**
+ * Pas besoin de purge ici puisque tous les résultats ont été traités
+ * au moins une fois, sans condition.
+ */
+ /* purge_pending_matches(matches); */
+
+ offset_done:
+
+ disable_all_ranges_in_node_search_offset(&offset);
+
+ }
+
+ assert(offset.used == 0);
+
+#endif
+
+ exit_node_search_offset(&params->offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void _g_scan_token_node_check_backward(const GScanTokenNode *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ class->check_backward(node, params, cflags, skip);
+
+ if (node->flags & STNF_MAIN)
+ {
+ //assert(*skip); //REMME
+ *skip = false;
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_check_backward(const GScanTokenNode *node, scan_node_check_params_t *params)
+{
+ node_search_offset_t offset; /* Espace des correspondances */
+ bool skip; /* Mise en attente des analyses*/
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t p; /* Boucle de parcours #2 */
+ match_area_t *pending; /* Correspondance à traiter */
+ phys_t old_start; /* Ancien point d'arrivée */
+ size_t o; /* Boucle de parcours #1 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ phys_t new_start; /* Nouveau point d'arrivée */
+
+ init_node_search_offset(&params->offset);
+
+ skip = true;
+
+ _g_scan_token_node_check_backward(node, params, TNCF_UPDATE_IN_PLACE, &skip);
+
+#if 0 // FIXME
+
+ /**
+ * Si un décalage entre octets n'a pas été consommé,
+ * les résultats sont étendus à minima.
+ */
+
+ ranges_ptr = get_node_search_offset_ranges(&offset, &ocount);
+
+ if (ocount > 0)
+ {
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ old_start = pending->start;
+
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ if (old_start < range->min)
+ new_start = 0;
+ else
+ new_start = old_start - range->min;
+
+ if (new_start < matches->content_start)
+ new_start = matches->content_start;
+
+ extend_pending_match_beginning(matches, p, new_start);
+
+ }
+
+ }
+
+ /**
+ * Pas besoin de purge ici puisque tous les résultats ont été traités
+ * au moins une fois, sans condition.
+ */
+ /* purge_pending_matches(matches); */
+
+ disable_all_ranges_in_node_search_offset(&offset);
+
+ }
+
+ assert(offset.used == 0);
+
+#endif
+
+ exit_node_search_offset(&params->offset);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/node.h b/src/analysis/scan/patterns/tokens/node.h
new file mode 100644
index 0000000..5b1a247
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/node.h
@@ -0,0 +1,127 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * node.h - prototypes pour la décomposition d'un motif de recherche en atomes assemblés
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "offset.h"
+#include "../backend.h"
+#include "../../context.h"
+#include "../../matches/bytes.h"
+#include "../../../../glibext/umemslice.h"
+
+
+#define G_TYPE_SCAN_TOKEN_NODE g_scan_token_node_get_type()
+#define G_SCAN_TOKEN_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNode))
+#define G_IS_SCAN_TOKEN_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE))
+#define G_SCAN_TOKEN_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNodeClass))
+#define G_IS_SCAN_TOKEN_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE))
+#define G_SCAN_TOKEN_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNodeClass))
+
+
+/* Décomposition d'un motif de recherche en atomes (instance) */
+typedef struct _GScanTokenNode GScanTokenNode;
+
+/* Décomposition d'un motif de recherche en atomes (classe) */
+typedef struct _GScanTokenNodeClass GScanTokenNodeClass;
+
+
+/* Propriétés particulières pour noeud d'analyse */
+typedef enum _ScanTokenNodeFlags
+{
+ STNF_NONE = (0 << 0), /* Absence de singularité */
+ STNF_FIRST = (1 << 0), /* Premier noeud de traitement */
+ STNF_LAST = (1 << 1), /* Dernier noeud de traitement */
+ STNF_MAIN = (1 << 2), /* Point de départ d'analyse */
+
+} ScanTokenNodeFlags;
+
+
+/* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */
+GType g_scan_token_node_get_type(void);
+
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+float g_scan_token_node_compute_weight_for_scan(const GScanTokenNode *);
+
+
+
+/* Indique les propriétés particulières d'un noeud d'analyse. */
+ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *);
+
+/* Marque le noeud avec des propriétés particulières. */
+void g_scan_token_node_set_flags(GScanTokenNode *, ScanTokenNodeFlags);
+
+/* Détermine et prépare les éléments clefs d'une arborescence. */
+bool g_scan_token_node_setup_tree(GScanTokenNode *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+bool g_scan_token_node_enroll(GScanTokenNode *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+bool g_scan_token_node_build_id(GScanTokenNode *, GEngineBackend *);
+
+/* Accès direct aux éléments utiles aux contrôles */
+typedef struct _scan_node_check_params_t
+{
+ GScanContext *context; /* Contexte de scan en cours */
+ GBinContent *content; /* Contenu binaire associé */
+ GUMemSlice *allocator; /* Allocateur pour zones */
+
+ phys_t content_start; /* Point de début du contenu */
+ phys_t content_end; /* Point de fin du contenu */
+
+ node_search_offset_t offset; /* Décalages à respecter */
+
+ bool initialized; /* Etat du suivi */
+
+ /* TNCF_UPDATE_IN_PLACE */
+
+ match_area_t *main_areas; /* Zones principales à analyser*/
+ size_t main_count; /* Taille de cette liste */
+
+ /* TNCF_CREATE_NEW */
+
+ match_area_t *created_areas; /* Zones principales à analyser*/
+ size_t created_count; /* Taille de cette liste */
+
+ /* TNCF_KEEP_DISCARDED */
+
+ match_area_t *kept_areas; /* Zones principales à analyser*/
+ size_t kept_count; /* Taille de cette liste */
+
+} scan_node_check_params_t;
+
+/* Transforme les correspondances locales en trouvailles. */
+void g_scan_token_node_check_forward(const GScanTokenNode *, scan_node_check_params_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void g_scan_token_node_check_backward(const GScanTokenNode *, scan_node_check_params_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/Makefile.am b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
new file mode 100644
index 0000000..b5da1ee
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
@@ -0,0 +1,24 @@
+
+noinst_LTLIBRARIES = libanalysisscanpatternstokensnodes.la
+
+
+libanalysisscanpatternstokensnodes_la_SOURCES = \
+ any-int.h \
+ any.h any.c \
+ choice-int.h \
+ choice.h choice.c \
+ masked-int.h \
+ masked.h masked.c \
+ not-int.h \
+ not.h not.c \
+ plain-int.h \
+ plain.h plain.c \
+ sequence-int.h \
+ sequence.h sequence.c
+
+libanalysisscanpatternstokensnodes_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanpatternstokensnodes_la_SOURCES:%c=)
diff --git a/src/analysis/scan/patterns/tokens/nodes/any-int.h b/src/analysis/scan/patterns/tokens/nodes/any-int.h
new file mode 100644
index 0000000..dd2e2e7
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any-int.h - prototypes internes pour une suite d'octets quelconques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H
+
+
+#include "any.h"
+
+
+#include "../atom.h"
+#include "../node-int.h"
+
+
+
+/* Espace constitué d'un ou plusieurs octets quelconques (instance) */
+struct _GScanTokenNodeAny
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ phys_t min; /* Quantité minimale */
+ phys_t max; /* Quantité maximale */
+ bool has_max; /* Quantité définie ? */
+
+};
+
+/* Espace constitué d'un ou plusieurs octets quelconques (classe) */
+struct _GScanTokenNodeAnyClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un noeud pointant une série d'octets. */
+bool g_scan_token_node_any_create(GScanTokenNodeAny *, const phys_t *, const phys_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/any.c b/src/analysis/scan/patterns/tokens/nodes/any.c
new file mode 100644
index 0000000..4334fff
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.c
@@ -0,0 +1,765 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any.c - suite d'octets quelconques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "any.h"
+
+
+#include <assert.h>
+
+
+#include "any-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des séries d'octets quelconques. */
+static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *);
+
+/* Initialise une instance de série d'octets quelconques. */
+static void g_scan_token_node_any_init(GScanTokenNodeAny *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_any_dispose(GScanTokenNodeAny *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_any_finalize(GScanTokenNodeAny *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série d'octets quelconque, vide ou non. */
+G_DEFINE_TYPE(GScanTokenNodeAny, g_scan_token_node_any, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des séries d'octets quelconques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenNodeClass *node; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_any_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_any_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->apply = (apply_scan_token_node_flags_fc)NULL;
+ node->visit = (visit_scan_token_node_fc)NULL;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_any_enroll;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_any_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_any_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = instance à initialiser. *
+* *
+* Description : Initialise une instance de série d'octets quelconques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_init(GScanTokenNodeAny *any)
+{
+ any->min = 0;
+ any->has_max = false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_dispose(GScanTokenNodeAny *any)
+{
+ G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->dispose(G_OBJECT(any));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_finalize(GScanTokenNodeAny *any)
+{
+ G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->finalize(G_OBJECT(any));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : min = éventuelle quantité minimale à retrouver. *
+* max = éventuelle quantité maximale à retrouver. *
+* *
+* Description : Construit un noeud pointant une série d'octets quelconques. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_any_new(const phys_t *min, const phys_t *max)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_ANY, NULL);
+
+ if (!g_scan_token_node_any_create(G_SCAN_TOKEN_NODE_ANY(result), min, max))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = séquence d'octets quelconques à initialiser pleinement.*
+* min = éventuelle quantité minimale à retrouver. *
+* max = éventuelle quantité maximale à retrouver. *
+* *
+* Description : Met en place un noeud pointant une série d'octets. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_any_create(GScanTokenNodeAny *any, const phys_t *min, const phys_t *max)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (min != NULL)
+ any->min = *min;
+ else
+ any->min = 0;
+
+ if (max != NULL)
+ {
+ any->max = *max;
+
+ result = (any->min <= any->max);
+
+ if (result && any->min == any->max)
+ result = (any->min > 0);
+
+ }
+
+ any->has_max = (max != NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = séquence d'octets quelconques à étendre. *
+* extra = étendue supplémentaire à intégrer. *
+* *
+* Description : Etend un noeud pointant une série d'octets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_any_merge(GScanTokenNodeAny *any, GScanTokenNodeAny *extra)
+{
+ any->min += extra->min;
+
+ if (any->has_max && extra->has_max)
+ any->max += extra->max;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ bool forced; /* Inclusion dans un scan ? */
+
+ result = true;
+
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+ if (forced)
+ *slow += (maxsize * 4);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ ScanTokenNodeFlags flags; /* Particularités du noeud */
+ bool forced; /* Inclusion dans un scan ? */
+ phys_t size; /* Quantité d'octets considérés*/
+ phys_t match_size; /* Taille de correspondance */
+ phys_t i; /* Boucle de parcours #1 */
+ match_area_t *space; /* Nouvelle zone à intégrer */
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t after; /* Espace disposible après */
+ phys_t min_end; /* Fin la plus proche possible */
+ phys_t max_end; /* Fin la plus éloignée trouvée*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours #2 */
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node));
+
+ forced = (flags & STNF_MAIN);
+
+ assert((!params->initialized && forced) || (params->initialized & !forced));
+
+ /**
+ * La situation forcée correspond au cas particulier d'une définition
+ * complètement abstraite : ??, ?? ??, etc.
+ */
+ if (forced)
+ {
+ size = params->content_end - params->content_start;
+
+ if (node->has_max && 0 /* greedy ? */)
+ {
+ match_size = node->max;
+
+ if (match_size > size)
+ match_size = node->min;
+
+ }
+ else
+ match_size = node->min;
+
+ /**
+ * Si le contenu binaire est trop petit pour contenir au moins un enregistrement,
+ * aucune correspondance n'est enregistrée. Comme le noeud est le principale, ie.
+ * seul et unique, l'analyse s'arrête ensuite d'elle même.
+ *
+ * Si le contenu binaire est suffisamment large, des espaces sont créés et l'analyse
+ * se termine ensuite. La conservation des espaces n'est donc pas utile, ni réalisée.
+ */
+
+ if (match_size <= size)
+ {
+ size -= (match_size - 1);
+
+ assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+ for (i = 0; i < size; i++)
+ {
+ space = g_umem_slice_alloc(params->allocator);
+
+ space->start = params->content_start + i;
+ space->end = space->start + match_size;
+
+ add_tail_match_area(space, &params->main_areas);
+
+ }
+
+ params->main_count += size;
+
+ }
+
+ }
+
+ /**
+ * Situation usuelle : des espaces séparent deux noeuds.
+ */
+ else
+ {
+ assert(params->initialized);
+
+ /**
+ * Les espaces existants sont à compléter. La présence de tels espaces
+ * restant à traiter peut provenir d'un aiguillage imposé par un motif
+ * tel que :
+ *
+ * ( aa ?? ?? | bb cc dd ) [0-5] ee ee
+ *
+ * Deux espaces sont à considérer avant de rechercher des octets ee :
+ * [2-7] et [0-5].
+ *
+ * Note : ces espaces peuvent être disjoints.
+ *
+ * Si aucun espace n'est en place, un est créé.
+ */
+
+ extend_node_search_offset(&params->offset, node->min, node->max, node->has_max);
+
+ /**
+ * Si un décalage enregistré ne peut être consommé par un noeud, les
+ * résultats sont étendus ici à minima ou maxima.
+ */
+
+ if (flags & STNF_LAST)
+ {
+ assert(offsets_exist(&params->offset));
+
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(area->end <= params->content_end);
+
+ after = params->content_end - area->end;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ min_end = params->content_end;
+ max_end = params->content_start;
+
+ updated = false;
+
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ if (ranges[r].min > after)
+ continue;
+
+ updated_edge = area->end + ranges[r].min;
+
+ if (updated_edge < min_end)
+ min_end = updated_edge;
+
+ if (ranges[r].has_max)
+ {
+ if (ranges[r].max > after)
+ updated_edge = params->content_end;
+ else
+ updated_edge = area->end + ranges[r].max;
+
+ if (updated_edge > max_end)
+ max_end = updated_edge;
+
+ }
+
+ updated = true;
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->end = (1 /* greedy */ ? min_end : max_end);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ ScanTokenNodeFlags flags; /* Particularités du noeud */
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t before; /* Espace disposible avant */
+ phys_t min_start; /* Début le plus proche trouvé */
+ phys_t max_start; /* Début le plus distant trouvé*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours */
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ /**
+ * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+ * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.
+ */
+
+ assert(params->initialized);
+
+ flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node));
+
+ /**
+ * Si les recherches associées au noeud ont été forcées, alors les traitements
+ * liés ont déjà été effectués, et l'appel de cette fonction aurait dû être sauté.
+ */
+#ifndef NDEBUG
+ forced = (flags & STNF_MAIN);
+ assert(!forced);
+#endif
+
+ /**
+ * Les considérations pour l'extension des espaces en place sont identiques
+ * à celles formulées dans la fonction g_scan_token_node_any_check_forward().
+ */
+
+ extend_node_search_offset(&params->offset, node->min, node->max, node->has_max);
+
+ /**
+ * Si un décalage enregistré ne peut être consommé par un noeud, les
+ * résultats sont étendus ici à minima ou maxima.
+ */
+
+ if (flags & STNF_FIRST)
+ {
+ assert(offsets_exist(&params->offset));
+
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(params->content_start <= area->start);
+
+ before = area->start - params->content_start;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ min_start = params->content_start;
+ max_start = params->content_end;
+
+ updated = false;
+
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ if (ranges[r].min > before)
+ continue;
+
+ updated_edge = area->start - ranges[r].min;
+
+ if (updated_edge > min_start)
+ min_start = updated_edge;
+
+ if (ranges[r].has_max)
+ {
+ if (ranges[r].max > before)
+ updated_edge = params->content_start;
+ else
+ updated_edge = area->start - ranges[r].max;
+
+ if (updated_edge < max_start)
+ max_start = updated_edge;
+
+ }
+
+ updated = true;
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->start = (1 /* greedy */ ? min_start : max_start);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+ }
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/any.h b/src/analysis/scan/patterns/tokens/nodes/any.h
new file mode 100644
index 0000000..9b2233f
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any.h - prototypes pour une suite d'octets quelconques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_ANY g_scan_token_node_any_get_type()
+#define G_SCAN_TOKEN_NODE_ANY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAny))
+#define G_IS_SCAN_TOKEN_NODE_ANY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_ANY))
+#define G_SCAN_TOKEN_NODE_ANY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass))
+#define G_IS_SCAN_TOKEN_NODE_ANY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_ANY))
+#define G_SCAN_TOKEN_NODE_ANY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass))
+
+
+/* Espace constitué d'un ou plusieurs octets quelconques (instance) */
+typedef struct _GScanTokenNodeAny GScanTokenNodeAny;
+
+/* Espace constitué d'un ou plusieurs octets quelconques (classe) */
+typedef struct _GScanTokenNodeAnyClass GScanTokenNodeAnyClass;
+
+
+/* Indique le type défini pour une série d'octets quelconque, vide ou non. */
+GType g_scan_token_node_any_get_type(void);
+
+/* Construit un noeud pointant une série d'octets quelconques. */
+GScanTokenNode *g_scan_token_node_any_new(const phys_t *, const phys_t *);
+
+/* Etend un noeud pointant une série d'octets. */
+void g_scan_token_node_any_merge(GScanTokenNodeAny *, GScanTokenNodeAny *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice-int.h b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
new file mode 100644
index 0000000..77a4058
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice-int.h - prototypes internes pour des décompositions alternatives de motif de recherche
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H
+
+
+#include "choice.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Décompositions alternatives de motif de recherche (instance) */
+struct _GScanTokenNodeChoice
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ GScanTokenNode **children; /* Sous-noeuds à représenter */
+ size_t count; /* Taille de cette liste */
+
+};
+
+/* Décompositions alternatives de motif de recherche (classe) */
+struct _GScanTokenNodeChoiceClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.c b/src/analysis/scan/patterns/tokens/nodes/choice.c
new file mode 100644
index 0000000..2a5e5f5
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.c
@@ -0,0 +1,646 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice.c - décompositions alternatives de motif de recherche
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "choice.h"
+
+
+#include <assert.h>
+
+
+#include "choice-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des décompositions alternatives. */
+static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *);
+
+/* Initialise une instance de décompositions alternatives. */
+static void g_scan_token_node_choice_init(GScanTokenNodeChoice *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+static float g_scan_token_node_choice_compute_weight_for_scan(const GScanTokenNodeChoice *);
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTokenNodeFlags);
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_choice_build_id(GScanTokenNodeChoice *, GEngineBackend *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour des décompositions alternatives de motif de recherche. */
+G_DEFINE_TYPE(GScanTokenNodeChoice, g_scan_token_node_choice, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des décompositions alternatives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenNodeClass *node; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_choice_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_choice_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_choice_compute_weight_for_scan;
+ node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_choice_apply_flags;
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_choice_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_choice_enroll;
+ node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_choice_build_id;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_choice_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_choice_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = instance à initialiser. *
+* *
+* Description : Initialise une instance de décompositions alternatives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_init(GScanTokenNodeChoice *choice)
+{
+ choice->children = NULL;
+ choice->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *choice)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < choice->count; i++)
+ g_clear_object(&choice->children[i]);
+
+ G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->dispose(G_OBJECT(choice));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *choice)
+{
+ if (choice->children != NULL)
+ free(choice->children);
+
+ G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->finalize(G_OBJECT(choice));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit une série de décompositions alternatives de motif. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_choice_new(void)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_CHOICE, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = ensemble de noeuds à compléter. *
+* node = nouveau noeud à intégrer. *
+* *
+* Description : Ajoute un noeud à aux décompositions alternatives de motif. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_choice_add(GScanTokenNodeChoice *choice, GScanTokenNode *node)
+{
+ choice->children = realloc(choice->children, ++choice->count * sizeof(GScanTokenNode *));
+
+ choice->children[choice->count - 1] = node;
+ g_object_ref(G_OBJECT(node));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à consulter. *
+* *
+* Description : Communique l'intérêt d'un noeud au sein d'une analyse. *
+* *
+* Retour : Poids de l'importance pour un départ de scan. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static float g_scan_token_node_choice_compute_weight_for_scan(const GScanTokenNodeChoice *node)
+{
+ float result; /* Valeur à retourner */
+ size_t weight_count; /* Nombre de comptabilisations */
+ size_t i; /* Boucle de parcours */
+ float weight; /* Nouveau poids à intégrer */
+
+ result = 0;
+
+ weight_count = 0;
+
+ for (i = 0; i < node->count; i++)
+ {
+ weight = g_scan_token_node_compute_weight_for_scan(node->children[i]);
+
+ if (weight > 0)
+ {
+ result += weight;
+ weight_count++;
+ }
+
+ }
+
+ if (weight_count != node->count)
+ result = 0;
+ else
+ result /= weight_count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à mettre à jour. *
+* flags = propriétés particulières à associer au noeud. *
+* *
+* Description : Prend acte d'une nouvelle propriété pour le noeud. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *node, ScanTokenNodeFlags flags)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < node->count; i++)
+ g_scan_token_node_set_flags(node->children[i], flags);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree_points_t *points)
+{
+ size_t first_plain_count; /* Décompte de noeuds textuels */
+ size_t i; /* Boucle de parcours */
+ scan_tree_points_t tmp_points; /* Synthèse d'analyse locale */
+
+ if (points->first_plain != NULL)
+ return;
+
+ first_plain_count = 0;
+
+ for (i = 0; i < node->count; i++)
+ {
+ tmp_points.first_plain = NULL;
+ tmp_points.best_masked = NULL;
+
+ g_scan_token_node_visit(node->children[i], &tmp_points);
+
+ if (tmp_points.first_plain != NULL)
+ first_plain_count++;
+
+ }
+
+ if (first_plain_count == node->count)
+ points->first_plain = G_SCAN_TOKEN_NODE(node);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ for (i = 0; i < node->count && result; i++)
+ result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à peaufiner. *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère un identifiant final pour un atome d'octets. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_choice_build_id(GScanTokenNodeChoice *node, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ result = true;
+
+ for (i = 0; i < node->count && result; i++)
+ result = g_scan_token_node_build_id(node->children[i], backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ bool initialized; /* Initialisation du suivi ? */
+ match_area_t *collected_areas; /* Zones mises en place ici */
+ size_t collected_count; /* Quantité de ces zones */
+ TokenNodeCheckFlags local_cflags; /* Particularités nouvelles */
+ size_t i; /* Boucle de parcours */
+ scan_node_check_params_t local_params; /* Rassemblement de paramètres */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ /* Lancement des sous-traitements */
+
+ initialized = false;
+
+ collected_areas = NULL;
+ collected_count = 0;
+
+ local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW;
+
+ for (i = 0; i < node->count; i++)
+ {
+ local_params = *params;
+
+ local_params.created_areas = NULL;
+ local_params.created_count = 0;
+
+ local_params.kept_areas = NULL;
+ local_params.kept_count = 0;
+
+ if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count)
+ local_cflags = cflags;
+
+ _g_scan_token_node_check_forward(node->children[i], &local_params, local_cflags, skip);
+
+ initialized |= local_params.initialized;
+
+ if (local_cflags & TNCF_KEEP_DISCARDED)
+ {
+ merge_match_areas(&collected_areas, &local_params.kept_areas);
+ collected_count += local_params.kept_count;
+ }
+
+ else if (local_cflags & TNCF_CREATE_NEW)
+ {
+ merge_match_areas(&collected_areas, &local_params.created_areas);
+ collected_count += local_params.created_count;
+ }
+
+ else
+ {
+ assert(local_cflags & TNCF_UPDATE_IN_PLACE);
+
+ merge_match_areas(&collected_areas, &local_params.main_areas);
+ collected_count += local_params.main_count;
+
+ }
+
+ }
+
+ /* Enregistrement des résultats finaux */
+
+ if (collected_count > 1)
+ sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL);
+
+ if (0x0) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count);
+
+ params->initialized = initialized;
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ params->kept_areas = collected_areas;
+ params->kept_count = collected_count;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ params->created_areas = collected_areas;
+ params->created_count = collected_count;
+ }
+
+ else
+ {
+ assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+ params->main_areas = collected_areas;
+ params->main_count = collected_count;
+
+ }
+
+
+
+
+
+ /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python)
+
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ match_area_t *collected_areas; /* Zones mises en place ici */
+ size_t collected_count; /* Quantité de ces zones */
+ TokenNodeCheckFlags local_cflags; /* Particularités nouvelles */
+ size_t i; /* Boucle de parcours */
+ scan_node_check_params_t local_params; /* Rassemblement de paramètres */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ /**
+ * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+ * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.
+ */
+
+ assert(params->initialized);
+
+ /* Lancement des sous-traitements */
+
+ collected_areas = NULL;
+ collected_count = 0;
+
+ local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW;
+
+ for (i = 0; i < node->count; i++)
+ {
+ local_params = *params;
+
+ local_params.created_areas = NULL;
+ local_params.created_count = 0;
+
+ local_params.kept_areas = NULL;
+ local_params.kept_count = 0;
+
+ if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count)
+ local_cflags = cflags;
+
+ _g_scan_token_node_check_backward(node->children[i], &local_params, local_cflags, skip);
+
+ if (local_cflags & TNCF_KEEP_DISCARDED)
+ {
+ merge_match_areas(&collected_areas, &local_params.kept_areas);
+ collected_count += local_params.kept_count;
+ }
+
+ else if (local_cflags & TNCF_CREATE_NEW)
+ {
+ merge_match_areas(&collected_areas, &local_params.created_areas);
+ collected_count += local_params.created_count;
+ }
+
+ else
+ {
+ assert(local_cflags & TNCF_UPDATE_IN_PLACE);
+
+ merge_match_areas(&collected_areas, &local_params.main_areas);
+ collected_count += local_params.main_count;
+
+ }
+
+ }
+
+ /* Enregistrement des résultats finaux */
+
+ if (collected_count > 1)
+ sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL);
+
+ if (0x0) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count);
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ params->kept_areas = collected_areas;
+ params->kept_count = collected_count;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ params->created_areas = collected_areas;
+ params->created_count = collected_count;
+ }
+
+ else
+ {
+ assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+ params->main_areas = collected_areas;
+ params->main_count = collected_count;
+
+ }
+
+
+
+
+
+ /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python)
+
+
+
+
+
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.h b/src/analysis/scan/patterns/tokens/nodes/choice.h
new file mode 100644
index 0000000..e793b1e
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice.h - prototypes pour des décompositions alternatives de motif de recherche
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_CHOICE g_scan_token_node_choice_get_type()
+#define G_SCAN_TOKEN_NODE_CHOICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoice))
+#define G_IS_SCAN_TOKEN_NODE_CHOICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE))
+#define G_SCAN_TOKEN_NODE_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass))
+#define G_IS_SCAN_TOKEN_NODE_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE))
+#define G_SCAN_TOKEN_NODE_CHOICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass))
+
+
+/* Décompositions alternatives de motif de recherche (instance) */
+typedef struct _GScanTokenNodeChoice GScanTokenNodeChoice;
+
+/* Décompositions alternatives de motif de recherche (classe) */
+typedef struct _GScanTokenNodeChoiceClass GScanTokenNodeChoiceClass;
+
+
+/* Indique le type défini pour des décompositions alternatives de motif de recherche. */
+GType g_scan_token_node_choice_get_type(void);
+
+/* Construit une série de décompositions alternatives de motif. */
+GScanTokenNode *g_scan_token_node_choice_new(void);
+
+/* Ajoute un noeud à aux décompositions alternatives de motif. */
+void g_scan_token_node_choice_add(GScanTokenNodeChoice *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked-int.h b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
new file mode 100644
index 0000000..5fcc330
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
@@ -0,0 +1,64 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked-int.h - prototypes internes pour la gestion d'une recherche de motif partielle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H
+
+
+#include "masked.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Bribe de motif partielle pour recherches (instance) */
+struct _GScanTokenNodeMasked
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ masked_byte_t *bytes; /* Série d'octets masqués */
+ size_t len; /* Taille de cette série */
+
+ sized_binary_t *raw; /* Liste de motifs à couvrir */
+ size_t raw_count; /* Taille de cette liste */
+
+ tracked_scan_atom_t *enrolled_atoms; /* Atomes correspondants */
+ size_t enrolled_count; /* Quantité avec identifiant */
+
+};
+
+/* Bribe de motif partielle pour recherches (classe) */
+struct _GScanTokenNodeMaskedClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une bribe de motif partielle. */
+bool g_scan_token_node_masked_create(GScanTokenNodeMasked *, const masked_byte_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.c b/src/analysis/scan/patterns/tokens/nodes/masked.c
new file mode 100644
index 0000000..5194cb8
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.c
@@ -0,0 +1,1135 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked.c - gestion d'une recherche de motif partielle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "masked.h"
+
+
+#include <assert.h>
+
+
+#include "masked-int.h"
+#include "../../backends/bitap.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des bribes de motif partielles. */
+static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *);
+
+/* Initialise une instance de bribe de motif partielle. */
+static void g_scan_token_node_masked_init(GScanTokenNodeMasked *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_masked_build_id(GScanTokenNodeMasked *, GEngineBackend *);
+
+/* Détermine si un contenu d'intérêt est présent à une position. */
+static bool check_scan_token_node_masked_content(const masked_byte_t *, size_t, phys_t, GBinContent *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */
+G_DEFINE_TYPE(GScanTokenNodeMasked, g_scan_token_node_masked, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bribes de motif partielles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenNodeClass *node; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_masked_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_masked_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->apply = (apply_scan_token_node_flags_fc)NULL;
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_masked_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_masked_enroll;
+ node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_masked_build_id;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_masked_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_masked_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = instance à initialiser. *
+* *
+* Description : Initialise une instance de bribe de motif partielle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_init(GScanTokenNodeMasked *masked)
+{
+ masked->bytes = NULL;
+ masked->len = 0;
+
+ masked->raw = NULL;
+ masked->raw_count = 0;
+
+ masked->enrolled_atoms = NULL;
+ masked->enrolled_count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *masked)
+{
+ G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->dispose(G_OBJECT(masked));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *masked)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (masked->bytes != NULL)
+ free(masked->bytes);
+
+ for (i = 0; i < masked->raw_count; i++)
+ exit_szstr(&masked->raw[i]);
+
+ if (masked->raw != NULL)
+ free(masked->raw);
+
+ if (masked->enrolled_atoms != NULL)
+ free(masked->enrolled_atoms);
+
+ G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->finalize(G_OBJECT(masked));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : byte = valeur masquée à intégrer. *
+* *
+* Description : Construit une bribe de motif partielle. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *byte)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_MASKED, NULL);
+
+ if (!g_scan_token_node_masked_create(G_SCAN_TOKEN_NODE_MASKED(result), byte))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = bribe partielle à initialiser pleinement. *
+* byte = valeur masquée à intégrer. *
+* *
+* Description : Met en place une bribe de motif partielle. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_masked_create(GScanTokenNodeMasked *masked, const masked_byte_t *byte)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ g_scan_token_node_masked_add(masked, byte);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = ensemble de noeuds à compléter. *
+* byte = valeur masquée à intégrer. *
+* *
+* Description : Enregistre la valeur d'octet à rechercher avec son masque. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_masked_add(GScanTokenNodeMasked *masked, const masked_byte_t *byte)
+{
+ assert((byte->value & 0x0f) == 0 || (byte->value & 0xf0) == 0);
+
+ masked->bytes = realloc(masked->bytes, ++masked->len * sizeof(masked_byte_t));
+
+ masked->bytes[masked->len - 1] = *byte;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree_points_t *points)
+{
+ GScanTokenNodeMasked *other; /* Concurrence à mesurer */
+
+ if (points->best_masked == NULL)
+ points->best_masked = G_SCAN_TOKEN_NODE(node);
+
+ else
+ {
+ other = G_SCAN_TOKEN_NODE_MASKED(points->best_masked);
+
+ if (node->len > other->len)
+ points->best_masked = G_SCAN_TOKEN_NODE(node);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ bool forced; /* Inclusion dans un scan ? */
+ //size_t len_to_enroll; /* Taille à considérer */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+ if (forced)
+ {
+ *slow += (maxsize * 2);
+
+ node->raw = make_atoms_from_masked_bytes(node->bytes, node->len, &node->raw_count);
+
+ /**
+ * Dans le cas bien précis de l'usage de l'algorithme Bitap pour les recherches
+ * dans le contenu binaire à analyser, on tire parti du coût nul des recherches
+ * multiples pour une même position.
+ */
+
+ if (G_IS_BITAP_BACKEND(backend))
+ {
+ //len_to_enroll = (node->len < maxsize ? node->len : maxsize);
+
+ /* TODO */
+ assert(false);
+
+
+ node->enrolled_count = 1;
+
+ }
+
+ else
+ {
+ node->enrolled_atoms = malloc(node->raw_count * sizeof(tracked_scan_atom_t));
+ node->enrolled_count = node->raw_count;
+
+ for (i = 0; i < node->enrolled_count && result; i++)
+ {
+ find_best_atom(&node->raw[i], maxsize, &node->enrolled_atoms[i], NULL);
+
+ /**
+ * Correction : si l'atome ne représente qu'une vue partielle,
+ * la validation rapide ne peut s'appliquer.
+ */
+ if (node->enrolled_atoms[i].fast_check)
+ node->enrolled_atoms[i].fast_check = (node->enrolled_atoms[i].len == node->len);
+
+ result = enroll_prepared_atom(&node->raw[i], backend, &node->enrolled_atoms[i]);
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à peaufiner. *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère un identifiant final pour un atome d'octets. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_masked_build_id(GScanTokenNodeMasked *node, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ result = true;
+
+ for (i = 0; i < node->enrolled_count && result; i++)
+ result = build_atom_pattern_id(&node->enrolled_atoms[i], backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = octets partiels avec leur masque à interpréter. *
+* len = quantité d'octets à interpréter. *
+* start = point d'analyse à respecter. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* *
+* Description : Détermine si un contenu d'intérêt est présent à une position.*
+* *
+* Retour : Bilan de l'analyse : true pour une correspondance. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, size_t len, phys_t start, GBinContent *content)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t pos; /* Position dans les données */
+ const bin_t *ptr; /* Accès aux données brutes */
+ size_t i; /* Boucle de parcours */
+
+ result = false;
+
+ init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
+
+ ptr = g_binary_content_get_raw_access(content, &pos, len);
+
+ for (i = 0; i < len; i++)
+ {
+ if ((ptr[i] & bytes[i].mask) != bytes[i].value)
+ break;
+ }
+
+ result = (i == len);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ match_area_t **areas; /* Liste de zones à constituer */
+ size_t *count; /* Taille de cette liste */
+ bool copy; /* Besoin d'une copie ? */
+ bool inverted; /* Inversion des bilans ? */
+ size_t i; /* Boucle de parcours #1 */
+ const tracked_scan_atom_t *atom; /* Atome correspondant */
+ match_area_t *atoms; /* Localisations des bribes */
+ bool first_round; /* Premier tour de traitement */
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t start; /* Début potentiel de motif */
+ bool status; /* Bilan d'une correspondance */
+ phys_t after; /* Espace disposible après */
+ phys_t min_end; /* Fin la plus proche possible */
+ phys_t max_end; /* Fin la plus éloignée trouvée*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ /**
+ * Si l'analyse arrive à un ou plusieurs octets masqués, soit il s'agit du
+ * premier noeud, et la génération d'atomes a été forcée pour obtenir des
+ * points de départ, soit des correspondances ont été établies au préalable,
+ * et il ne doit alors pas y avoir d'atome mis en place (si l'initialisation
+ * ne provient pas d'une mise en place artificielle par une inversion NOT).
+ */
+#ifndef NDEBUG
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+ assert((!params->initialized && forced) || (params->initialized && (!forced || cflags & TNCF_KEEP_DISCARDED)));
+#endif
+
+ if (!params->initialized)
+ {
+ /* Destinations établies une fois pour toutes */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ areas = &params->kept_areas;
+ count = &params->kept_count;
+
+ copy = false;
+ inverted = true;
+
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ areas = &params->created_areas;
+ count = &params->created_count;
+
+ copy = true;
+ inverted = false;
+
+ }
+
+ else
+ {
+ assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+ areas = &params->main_areas;
+ count = &params->main_count;
+
+ copy = false;
+ inverted = false;
+
+ }
+
+ /* Parcours des combinaisons enregistrées */
+
+ for (i = 0; i < node->enrolled_count; i++)
+ {
+ atom = &node->enrolled_atoms[i];
+
+ atoms = g_scan_context_get_atom_matches(params->context, atom->pid);
+
+ first_round = (*count == 0);
+
+ if (atom->fast_check)
+ {
+ /**
+ * Toutes les correspondances sont validées d'office car le motif identifié
+ * correspondant au motif complet.
+ */
+
+ if (!inverted)
+ {
+ for_each_match_area(area, atoms)
+ {
+ /**
+ * La modification de la zone d'origine est possible dans tous les cas
+ * car cette zone a été allouée de façon dédiée à un type de correspondances
+ * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+ */
+
+ assert(area->end >= atom->len);
+
+ area->start = area->end - atom->len;
+
+ (*count)++;
+
+ }
+
+ }
+
+ else
+ atoms = NULL;
+
+ }
+
+ else
+ {
+ for_each_match_area_safe(area, &atoms, next)
+ {
+ start = area->end - atom->len - atom->pos;
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ start, params->content);
+
+ if (status)
+ {
+ /**
+ * La modification de la zone d'origine est possible dans tous les cas
+ * car cette zone a été allouée de façon dédiée à un type de correspondances
+ * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+ */
+
+ if (!inverted)
+ {
+ area->start = start;
+ area->end += atom->rem;
+
+ (*count)++;
+
+ }
+ else
+ del_match_area(area, &atoms);
+
+ }
+
+ else
+ {
+ /**
+ * Les principes de modifications restent valables, même inversés.
+ */
+ if (inverted)
+ {
+ area->start = start;
+ area->end += atom->rem;
+
+ (*count)++;
+
+ }
+ else
+ del_match_area(area, &atoms);
+
+ }
+
+ }
+
+
+ }
+
+ /* Mise à jour de la liste */
+
+ if (atoms != NULL)
+ {
+ if (first_round)
+ *areas = atoms;
+
+ else
+ merge_match_areas(areas, &atoms);
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+ * des comparaisons entières de motifs.
+ */
+ else
+ {
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(area->end <= params->content_end);
+
+ after = params->content_end - area->end;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ /**
+ * S'il s'avère qu'il existe de multiples correspondances dans l'espace
+ * analysé, c'est la prise en compte d'une éventuelle avarice quant aux
+ * distances consommées qui va sélectionner la position d'une bribe de
+ * correspondance retenue.
+ *
+ * Par exemple, deux correspondances '?1 ?1 [1-3] ?2 ?2' peuvent être
+ * valides pour un même contenu :
+ *
+ * aa.bbb -> correspondance 'aa.bb'
+ * ^
+ *
+ * aa.bbb -> correspondance 'aa..bb'
+ * ^
+ */
+
+ min_end = params->content_end;
+ max_end = params->content_start;
+
+ updated = false;
+
+ /* Souplesse dans les positions ? */
+ if (offsets_exist(&params->offset))
+ {
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ assert(ranges[r].has_max);
+ assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+ for (p = ranges[r].min; p <= ranges[r].max; p++)
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près de
+ * la fin du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if ((p + node->len) > after)
+ break;
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ area->end + p, params->content);
+
+ if (status)
+ {
+ updated_edge = area->end + p + node->len;
+
+ if (updated_edge < min_end)
+ min_end = updated_edge;
+
+ if (updated_edge > max_end)
+ max_end = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Position immédiatement attendue */
+ else
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près de
+ * la fin du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if (node->len <= after)
+ {
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ area->end, params->content);
+
+ if (status)
+ {
+ updated_edge = area->end + node->len;
+
+ min_end = updated_edge;
+ max_end = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->end = (1 /* greedy */ ? min_end : max_end);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ }
+
+ params->initialized = true;
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+
+
+
+ bool status; /* Bilan d'une correspondance */
+
+
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t before; /* Espace disposible avant */
+ phys_t min_start; /* Début le plus proche trouvé */
+ phys_t max_start; /* Début le plus distant trouvé*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ /**
+ * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+ * du sens de lecteur normal). Donc l'initialisation a déjà dû avoir lieu.
+ */
+ assert(params->initialized);
+
+ /**
+ * Si les recherches associées au noeud ont été forcées, alors les traitements
+ * liés ont déjà été effectués, et l'appel de cette fonction aurait dû être sauté.
+ */
+#ifndef NDEBUG
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+ assert(!forced);
+#endif
+
+
+
+
+ /**
+ * .............
+ */
+ if (0)
+ {
+
+
+ ;
+
+
+
+ }
+
+ /**
+ * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+ * des comparaisons entières de motifs.
+ */
+ else
+ {
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(params->content_start <= area->start);
+
+ before = area->start - params->content_start;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ /**
+ * Il ne peut y avoir qu'une seule séquence d'octets à un même
+ * emplacement. En revanche, des modificateurs peuvent construire
+ * possédant une même base, mais offrant des suffixes différents
+ * (par exemple, un marqueur nul UTF-16 final en complément).
+ *
+ * L'ensemble des combinaisons produites doit ainsi être exploré.
+ */
+
+ min_start = params->content_start;
+ max_start = params->content_end;
+
+ updated = false;
+
+ /* Souplesse dans les positions ? */
+ if (offsets_exist(&params->offset))
+ {
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ assert(ranges[r].has_max);
+ assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+ for (p = ranges[r].min; p <= ranges[r].max; p++)
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près de
+ * la fin du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if ((p + node->len) > before)
+ break;
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ area->start - node->len - p,
+ params->content);
+
+ if (status)
+ {
+ updated_edge = area->start - node->len - p;
+
+ if (updated_edge > min_start)
+ min_start = updated_edge;
+
+ if (updated_edge < max_start)
+ max_start = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Position immédiatement attendue */
+ else
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près du
+ * début du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if (node->len <= before)
+ {
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ area->start - node->len,
+ params->content);
+
+ if (status)
+ {
+ updated_edge = area->start - node->len;
+
+ if (updated_edge > min_start)
+ min_start = updated_edge;
+
+ if (updated_edge < max_start)
+ max_start = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->start = (1 /* greedy */ ? min_start : max_start);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ }
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.h b/src/analysis/scan/patterns/tokens/nodes/masked.h
new file mode 100644
index 0000000..04a05bc
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked.h - prototypes pour la gestion d'une recherche de motif partielle
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H
+
+
+#include <glib-object.h>
+
+
+#include "../atom.h"
+#include "../node.h"
+#include "../../../../../arch/archbase.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_MASKED g_scan_token_node_masked_get_type()
+#define G_SCAN_TOKEN_NODE_MASKED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMasked))
+#define G_IS_SCAN_TOKEN_NODE_MASKED(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED))
+#define G_SCAN_TOKEN_NODE_MASKED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass))
+#define G_IS_SCAN_TOKEN_NODE_MASKED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED))
+#define G_SCAN_TOKEN_NODE_MASKED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass))
+
+
+/* Bribe de motif partielle pour recherches (instance) */
+typedef struct _GScanTokenNodeMasked GScanTokenNodeMasked;
+
+/* Bribe de motif partielle pour recherches (classe) */
+typedef struct _GScanTokenNodeMaskedClass GScanTokenNodeMaskedClass;
+
+
+/* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */
+GType g_scan_token_node_masked_get_type(void);
+
+/* Construit une bribe de motif partielle. */
+GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *);
+
+/* Enregistre la valeur d'octet à rechercher avec son masque. */
+void g_scan_token_node_masked_add(GScanTokenNodeMasked *, const masked_byte_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/not-int.h b/src/analysis/scan/patterns/tokens/nodes/not-int.h
new file mode 100644
index 0000000..5f92afd
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not-int.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not-int.h - prototypes internes pour l'inversion de résultats de correspondances établis
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H
+
+
+#include "not.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Inversion de résultats de correspondances établis (instance) */
+struct _GScanTokenNodeNot
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ GScanTokenNode *child; /* Sous-noeud à considérer */
+
+};
+
+/* Inversion de résultats de correspondances établis (classe) */
+struct _GScanTokenNodeNotClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une inversion de résultats de correspondances. */
+bool g_scan_token_node_not_create(GScanTokenNodeNot *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/not.c b/src/analysis/scan/patterns/tokens/nodes/not.c
new file mode 100644
index 0000000..81fce28
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not.c
@@ -0,0 +1,416 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not.c - inversion de résultats de correspondances établis
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "not.h"
+
+
+#include <assert.h>
+
+
+#include "not-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des inversions de correspondances. */
+static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *);
+
+/* Initialise une instance d'inversion de correspondances. */
+static void g_scan_token_node_not_init(GScanTokenNodeNot *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_not_dispose(GScanTokenNodeNot *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_not_finalize(GScanTokenNodeNot *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+static void g_scan_token_node_not_apply_flags(GScanTokenNodeNot *, ScanTokenNodeFlags);
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_not_visit(GScanTokenNodeNot *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_not_build_id(GScanTokenNodeNot *, GEngineBackend *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une inversion des résultats de correspondances. */
+G_DEFINE_TYPE(GScanTokenNodeNot, g_scan_token_node_not, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des inversions de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenNodeClass *node; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_not_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_not_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_not_apply_flags;
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_not_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_not_enroll;
+ node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_not_build_id;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_not_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_not_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = instance à initialiser. *
+* *
+* Description : Initialise une instance d'inversion de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_init(GScanTokenNodeNot *not)
+{
+ not->child = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_dispose(GScanTokenNodeNot *not)
+{
+ g_clear_object(&not->child);
+
+ G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->dispose(G_OBJECT(not));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_finalize(GScanTokenNodeNot *not)
+{
+ G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->finalize(G_OBJECT(not));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Construit une inversion de résultats de correspondances. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *child)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_NOT, NULL);
+
+ if (!g_scan_token_node_not_create(G_SCAN_TOKEN_NODE_NOT(result), child))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = encadrement d'inversion à initialiser pleinement. *
+* child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Met en place une inversion de résultats de correspondances. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_not_create(GScanTokenNodeNot *not, GScanTokenNode *child)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ not->child = child;
+ g_object_ref(G_OBJECT(child));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à mettre à jour. *
+* flags = propriétés particulières à associer au noeud. *
+* *
+* Description : Prend acte d'une nouvelle propriété pour le noeud. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_apply_flags(GScanTokenNodeNot *node, ScanTokenNodeFlags flags)
+{
+ g_scan_token_node_set_flags(node->child, flags);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_points_t *points)
+{
+ g_scan_token_node_visit(node->child, points);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+
+ result = _g_scan_token_node_enroll(node->child, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à peaufiner. *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère un identifiant final pour un atome d'octets. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_not_build_id(GScanTokenNodeNot *node, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+
+ result = g_scan_token_node_build_id(node->child, backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+
+#if 0
+
+
+ bool initialized; /* Initialisation du suivi ? */
+ phys_t i; /* Boucle de parcours */
+
+
+ /*
+
+ ?????????????????????????
+
+
+ if (*skip)
+ return;
+ */
+
+
+
+ initialized = are_pending_matches_initialized(matches);
+
+
+ //printf("TOTO......(init done? %d)\n", initialized);
+
+
+
+ if (!initialized)
+ {
+ for (i = matches->content_start; i < matches->content_end; i++)
+ add_pending_match(matches, i, 0);
+
+ set_pending_matches_initialized(matches);
+
+ }
+
+ _g_scan_token_node_check_forward(node->child, context, content, matches, offset, !not, skip);
+
+
+#endif
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+
+
+
+ if (*skip)
+ return;
+
+
+
+ printf("TODO\n");
+ assert(0);
+
+
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/not.h b/src/analysis/scan/patterns/tokens/nodes/not.h
new file mode 100644
index 0000000..58630e8
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not.h - prototypes pour l'inversion de résultats de correspondances établis
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+#include "../../../../../arch/archbase.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_NOT g_scan_token_node_not_get_type()
+#define G_SCAN_TOKEN_NODE_NOT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNot))
+#define G_IS_SCAN_TOKEN_NODE_NOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_NOT))
+#define G_SCAN_TOKEN_NODE_NOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass))
+#define G_IS_SCAN_TOKEN_NODE_NOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_NOT))
+#define G_SCAN_TOKEN_NODE_NOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass))
+
+
+/* Inversion de résultats de correspondances établis (instance) */
+typedef struct _GScanTokenNodeNot GScanTokenNodeNot;
+
+/* Inversion de résultats de correspondances établis (classe) */
+typedef struct _GScanTokenNodeNotClass GScanTokenNodeNotClass;
+
+
+/* Indique le type défini pour une inversion des résultats de correspondances. */
+GType g_scan_token_node_not_get_type(void);
+
+/* Construit une inversion de résultats de correspondances. */
+GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain-int.h b/src/analysis/scan/patterns/tokens/nodes/plain-int.h
new file mode 100644
index 0000000..2077c6f
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/plain-int.h
@@ -0,0 +1,64 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain-int.h - prototypes internes pour la gestion d'une recherche de motif textuel
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H
+
+
+#include "plain.h"
+
+
+#include "../atom.h"
+#include "../node-int.h"
+
+
+
+/* Bribe de motif textuelle pour recherches (instance) */
+struct _GScanTokenNodePlain
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ sized_binary_t orig; /* Motif d'origine avant modifs*/
+ GScanTokenModifier *modifier; /* Transformateur pour le motif*/
+ ScanPlainNodeFlags flags; /* Fanions associés au motif */
+
+ sized_binary_t *raw; /* Liste de motifs à couvrir */
+ tracked_scan_atom_t *atoms; /* Atomes correspondants */
+ size_t count; /* Taille de cette liste */
+
+};
+
+/* Bribe de motif textuelle pour recherches (instance) */
+struct _GScanTokenNodePlainClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un noeud représentant un motif textuel. */
+bool g_scan_token_node_plain_create(GScanTokenNodePlain *, const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c
new file mode 100644
index 0000000..5dd45df
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.c
@@ -0,0 +1,1377 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.c - gestion d'une recherche de motif textuel
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "plain.h"
+
+
+#include <assert.h>
+
+
+#include "plain-int.h"
+#include "../../../../../common/extstr.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des noeuds pour motif textuel. */
+static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *);
+
+/* Initialise une instance de noeud pour motif textuel. */
+static void g_scan_token_node_plain_init(GScanTokenNodePlain *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_plain_dispose(GScanTokenNodePlain *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *);
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_plain_visit(GScanTokenNodePlain *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *, GEngineBackend *);
+
+/* Détermine si un contenu d'intérêt est présent à une position. */
+static bool check_scan_token_node_plain_content(const sized_binary_t *, const tracked_scan_atom_t *, bool, phys_t, GBinContent *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un noeud représentant une bribe de texte à retrouver. */
+G_DEFINE_TYPE(GScanTokenNodePlain, g_scan_token_node_plain, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des noeuds pour motif textuel. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenNodeClass *node; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_plain_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_plain_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_plain_compute_weight_for_scan;
+ node->apply = (apply_scan_token_node_flags_fc)NULL;
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_plain_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_plain_enroll;
+ node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_plain_build_id;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_plain_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_plain_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plain = instance à initialiser. *
+* *
+* Description : Initialise une instance de noeud pour motif textuel. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_init(GScanTokenNodePlain *plain)
+{
+ init_szstr(&plain->orig);
+ plain->modifier = NULL;
+ plain->flags = SPNF_NONE;
+
+ plain->raw = NULL;
+ plain->atoms = NULL;
+ plain->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plain = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_dispose(GScanTokenNodePlain *plain)
+{
+ g_clear_object(&plain->modifier);
+
+ G_OBJECT_CLASS(g_scan_token_node_plain_parent_class)->dispose(G_OBJECT(plain));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plain = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *plain)
+{
+ size_t i; /* Boucle de parcours */
+
+ exit_szstr(&plain->orig);
+
+ for (i = 0; i < plain->count; i++)
+ exit_szstr(&plain->raw[i]);
+
+ if (plain->raw != NULL)
+ free(plain->raw);
+
+ if (plain->atoms != NULL)
+ free(plain->atoms);
+
+ G_OBJECT_CLASS(g_scan_token_node_plain_parent_class)->finalize(G_OBJECT(plain));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : text = texte brut à rechercher. *
+* modifier = transformateur éventuel à solliciter. *
+* flags = particularités à prendre en considération. *
+* *
+* Description : Construit un noeud représentant un motif textuel. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainNodeFlags flags)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_PLAIN, NULL);
+
+ if (!g_scan_token_node_plain_create(G_SCAN_TOKEN_NODE_PLAIN(result), text, modifier, flags))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plain = encadrement de motif à initialiser pleinement. *
+* text = texte brut à rechercher. *
+* modifier = transformateur éventuel à solliciter. *
+* flags = particularités à prendre en considération. *
+* *
+* Description : Met en place un noeud représentant un motif textuel. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainNodeFlags flags)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ szstrdup(&plain->orig, text);
+
+ if (modifier != NULL)
+ {
+ plain->modifier = modifier;
+ g_object_ref(G_OBJECT(modifier));
+ }
+
+ plain->flags = flags;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plain = noeud de motif textuel à consulter. *
+* *
+* Description : Indique les propriétés particulières d'un noeud de texte. *
+* *
+* Retour : Propriétés particulières associées au noeud. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *plain)
+{
+ ScanPlainNodeFlags result; /* Statut à retourner */
+
+ result = plain->flags;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à consulter. *
+* index = indice de la combinaison de modificateurs ciblée. *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *node, size_t index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (node->modifier == NULL)
+ result = strdup("plain");
+
+ else
+ result = g_scan_token_modifier_get_path(node->modifier, (size_t []){ index });
+
+ return result;
+
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à consulter. *
+* *
+* Description : Communique l'intérêt d'un noeud au sein d'une analyse. *
+* *
+* Retour : Poids de l'importance pour un départ de scan. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *node)
+{
+ float result; /* Valeur à retourner */
+
+ result = node->orig.len;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_points_t *points)
+{
+ GScanTokenNode *candidate; /* Autre version du noeud */
+ float node_weight; /* Poids du noeud courant */
+ float other_weight; /* Poids de l'autre noeud */
+
+ if (points->first_plain == NULL)
+ points->first_plain = G_SCAN_TOKEN_NODE(node);
+
+ else
+ {
+ candidate = G_SCAN_TOKEN_NODE(node);
+
+ node_weight = g_scan_token_node_compute_weight_for_scan(candidate);
+ other_weight = g_scan_token_node_compute_weight_for_scan(points->first_plain);
+
+ if (node_weight >= other_weight)
+ points->first_plain = candidate;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ tracked_scan_atom_t atom; /* Atome identifié */
+ size_t letters; /* Nombre de lettres présentes */
+ size_t k; /* Boucle de parcours #2 */
+ size_t extra_count; /* Quantité pour l'exhaustivité*/
+ sized_binary_t *extra; /* Couverture supplémntaire */
+ size_t remaining; /* Quantité restant à traiter */
+
+ /* Génération d'une base de chaînes à couvrir */
+
+ if (node->modifier == NULL)
+ {
+ node->raw = malloc(sizeof(sized_binary_t));
+ node->count = 1;
+
+ szstrdup(&node->raw[0], &node->orig);
+
+ result = true;
+
+ }
+ else
+ result = g_scan_token_modifier_transform(node->modifier, &node->orig, 1, &node->raw, &node->count);
+
+ if (!result)
+ goto exit;
+
+ /* Préparation pour la mémorisation des atomes */
+
+ node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t));
+
+ /* Validation du besoin effectif dans les cas extrèmes */
+
+
+
+ // TODO : if (orig.len < ...)
+
+
+
+ /* Recherche des atomes */
+
+ for (i = 0; i < node->count; i++)
+ {
+ if (node->flags & SPNF_CASE_INSENSITIVE)
+ {
+ find_best_atom(&node->raw[i], maxsize, &atom, &letters);
+
+ if (letters == 0)
+ node->atoms[i] = atom;
+
+ /* Insertion des nouvelles combinaisons pour couvrir toutes les casses */
+ else
+ {
+ /* extra_count = 2^letters */
+ for (k = 1, extra_count = 2; k < letters; k++, extra_count *= 2)
+ ;
+
+ extra = make_atoms_case_insensitive(&node->raw[i], &atom, extra_count);
+
+ remaining = node->count - i - 1;
+
+ node->count += (extra_count - 1);
+
+ node->raw = realloc(node->raw, node->count * sizeof(sized_binary_t));
+
+ memmove(&node->raw[i + extra_count], &node->raw[i + 1], remaining * sizeof(sized_binary_t));
+
+ for (k = 0; k < extra_count; k++)
+ node->raw[i + k] = extra[k];
+
+ free(extra);
+
+ node->atoms = realloc(node->atoms, node->count * sizeof(tracked_scan_atom_t));
+
+ for (k = 0; k < extra_count; k++)
+ node->atoms[i + k] = atom;
+
+ i += extra_count - 1;
+
+ }
+
+ }
+
+ else
+ find_best_atom(&node->raw[i], maxsize, &node->atoms[i], &letters);
+
+ }
+
+ /* Enregistrements en masse */
+
+ for (i = 0; i < node->count && result; i++)
+ result = enroll_prepared_atom(&node->raw[i], backend, &node->atoms[i]);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à peaufiner. *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère un identifiant final pour un atome d'octets. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *node, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ result = true;
+
+ for (i = 0; i < node->count && result; i++)
+ result = build_atom_pattern_id(&node->atoms[i], backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : raw = contneu brut à retrouver idéalement. *
+* atom = contenu brut représentatif ciblé. *
+* nocase = marque un éventuel désintérêt pour la casse. *
+* start = point d'analyse à respecter. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* *
+* Description : Détermine si un contenu d'intérêt est présent à une position.*
+* *
+* Retour : Bilan de l'analyse : true pour une correspondance. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, bool nocase, phys_t start, GBinContent *content)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t pos; /* Position dans les données */
+ const bin_t *ptr; /* Accès aux données brutes */
+ int ret; /* Bilan d'une comparaison */
+
+ result = false;
+
+ init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
+
+ /* Validation du motif intégral */
+
+ if (atom == NULL)
+ {
+ ptr = g_binary_content_get_raw_access(content, &pos, raw->len);
+
+ /**
+ * Si la partion atomique recherchée est trouvée en début de contenu,
+ * le reste du motif de recherche va déborder. L'accès correspondant
+ * est donc refusé, et cette situation est prise en compte ici.
+ */
+ if (ptr == NULL) goto done;
+
+ if (nocase)
+ ret = memcasecmp(raw->data, ptr, raw->len);
+ else
+ ret = memcmp(raw->data, ptr, raw->len);
+
+ result = (ret == 0);
+
+ }
+
+ /* Validation des extrémités */
+
+ else
+ {
+ /* Validation du contenu avant l'atome */
+
+ if (atom->pos > 0)
+ {
+ ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
+
+ /**
+ * Si la partion atomique recherchée est trouvée en début de contenu,
+ * le reste du motif de recherche va déborder. L'accès correspondant
+ * est donc refusé, et cette situation est prise en compte ici.
+ */
+ if (ptr == NULL) goto done;
+
+ if (nocase)
+ ret = memcasecmp(raw->data, ptr, atom->pos);
+ else
+ ret = memcmp(raw->data, ptr, atom->pos);
+
+ if (ret != 0) goto done;
+
+ }
+
+ /* Validation du contenu après l'atome */
+
+ if (atom->rem > 0)
+ {
+ advance_vmpa(&pos, atom->len);
+
+ ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
+
+ /**
+ * Si la partion atomique recherchée est trouvée en fin de contenu,
+ * le reste du motif de recherche va déborder. L'accès correspondant
+ * est donc refusé, et cette situation est prise en compte ici.
+ */
+ if (ptr == NULL) goto done;
+
+ if (nocase)
+ ret = memcasecmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+ else
+ ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+
+ if (ret != 0) goto done;
+
+ }
+
+ result = true;
+
+ }
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ bool track_path; /* Conservation du chemin */
+ bool nocase; /* Pas d'intérêt pour la casse */
+ match_area_t **areas; /* Liste de zones à constituer */
+ size_t *count; /* Taille de cette liste */
+ bool copy; /* Besoin d'une copie ? */
+ bool inverted; /* Inversion des bilans ? */
+ size_t i; /* Boucle de parcours #1 */
+ const tracked_scan_atom_t *atom; /* Atome correspondant */
+ match_area_t *atoms; /* Localisations des bribes */
+ bool first_round; /* Premier tour de traitement */
+ match_area_t *area; /* Correspondance à valider */
+ const sized_binary_t *raw; /* Données brutes d'origine */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t start; /* Début potentiel de motif */
+ bool status; /* Bilan d'une correspondance */
+ phys_t after; /* Espace disposible après */
+ phys_t min_end; /* Fin la plus proche possible */
+ phys_t max_end; /* Fin la plus éloignée trouvée*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN);
+
+ nocase = (node->flags & SPNF_CASE_INSENSITIVE);
+
+ /**
+ * Création de premières marques de correspondances.
+ */
+ if (!params->initialized)
+ {
+ /* Destinations établies une fois pour toutes */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ areas = &params->kept_areas;
+ count = &params->kept_count;
+
+ copy = false;
+ inverted = true;
+
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ areas = &params->created_areas;
+ count = &params->created_count;
+
+ copy = true;
+ inverted = false;
+
+ }
+
+ else
+ {
+ assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+ areas = &params->main_areas;
+ count = &params->main_count;
+
+ copy = false;
+ inverted = false;
+
+ }
+
+ /* Parcours des combinaisons enregistrées */
+
+ for (i = 0; i < node->count; i++)
+ {
+ atom = &node->atoms[i];
+
+ atoms = g_scan_context_get_atom_matches(params->context, atom->pid);
+
+ first_round = (*count == 0);
+
+ if (atom->fast_check)
+ {
+ /**
+ * Toutes les correspondances sont validées d'office car le motif identifié
+ * correspondant au motif complet.
+ */
+
+ if (!inverted)
+ {
+ for_each_match_area(area, atoms)
+ {
+ /**
+ * La modification de la zone d'origine est possible dans tous les cas
+ * car cette zone a été allouée de façon dédiée à un type de correspondances
+ * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+ */
+
+ assert(area->end >= atom->len);
+
+ area->start = area->end - atom->len;
+
+ (*count)++;
+
+ }
+
+ }
+
+ else
+ atoms = NULL;
+
+ }
+
+ else
+ {
+ raw = &node->raw[i];
+
+ for_each_match_area_safe(area, &atoms, next)
+ {
+ start = area->end - atom->len - atom->pos;
+
+ status = check_scan_token_node_plain_content(raw, atom, nocase, start, params->content);
+
+ if (status)
+ {
+ /**
+ * La modification de la zone d'origine est possible dans tous les cas
+ * car cette zone a été allouée de façon dédiée à un type de correspondances
+ * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+ */
+
+ if (!inverted)
+ {
+ area->start = start;
+ area->end += atom->rem;
+
+ (*count)++;
+
+ }
+ else
+ del_match_area(area, &atoms);
+
+ }
+
+ else
+ {
+ /**
+ * Les principes de modifications restent valables, même inversés.
+ */
+ if (inverted)
+ {
+ area->start = start;
+ area->end += atom->rem;
+
+ (*count)++;
+
+ }
+ else
+ del_match_area(area, &atoms);
+
+ }
+
+ }
+
+
+ }
+
+ /* Mise à jour de la liste */
+
+ if (atoms != NULL)
+ {
+ if (first_round)
+ *areas = atoms;
+
+ else
+ merge_match_areas(areas, &atoms);
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+ * des comparaisons entières de motifs.
+ */
+ else
+ {
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(area->end <= params->content_end);
+
+ after = params->content_end - area->end;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ /**
+ * Il ne peut y avoir qu'une seule séquence d'octets à un même
+ * emplacement. En revanche, des modificateurs peuvent construire
+ * possédant une même base, mais offrant des suffixes différents
+ * (par exemple, un marqueur nul UTF-16 final en complément).
+ *
+ * L'ensemble des combinaisons produites doit ainsi être exploré.
+ */
+
+ /**
+ * Par ailleurs, même si une base de couples uniques est assurée,
+ * la constitution d'un ensemble de noeuds peut amener une redondance
+ * dans les emplacements de correspondances ; ces doublons éventuels
+ * sont alors filtrés par un appel à sort_match_areas_no_dup().
+ *
+ * Par exemple, pour la séquence d'octets analysés suivante :
+ *
+ * aaa....bbb
+ *
+ * La définition { (61 61 | 61 61 61) [4-5] 62 62 62 } peut établir
+ * les correspondances suivantes :
+ *
+ * aa.....bbb -> couple pending[x] (0;2) puis (0;10)
+ * ^
+ * aa....bbb -> couple pending[y] (1;3) puis (1;10)
+ * ^
+ * aaa....bbb -> couple pending[z] (0;3) puis (0;10)
+ * ^
+ *
+ * Par ailleurs, une même base de départ peut conduire à plusieurs
+ * zones de correspondances.
+ *
+ * Par exemple, pour la séquence d'octets analysés suivante :
+ *
+ * aa..bb..bb
+ *
+ * La définition { 61 61 [2-6] 62 62 } peut établir
+ * les correspondances suivantes :
+ *
+ * aa..bb..bb -> couple pending[x] (0;2) puis (0;6)
+ * ^
+ * aa..bb..bb -> couple pending[x] (0;2) puis (0;10)
+ * ^
+ */
+
+ /**
+ * Dans la première situation, c'est la bribe 62 62 62 qui fait l'objet
+ * d'une recherche de motifs. Les autres bribes sont recherchées
+ * manuellement ici, car l'espace de séparation est léger (inférieur à
+ * MAX_RANGE_FOR_MANUAL_CHECK).
+ *
+ * La seconde situation bénéficie de recherches automatisées pour
+ * l'ensemble des motifs, du fait d'une valeur de séparation plus
+ * importante.
+ *
+ * Dans les deux cas, l'espace de séparation est entièrement considéré.
+ * La sélection de la correspondance à retour s'établit selon un
+ * paramètre de configuation : doit-on être avare sur les distances
+ * consommées ou non ?
+ */
+
+ min_end = params->content_end;
+ max_end = params->content_start;
+
+ updated = false;
+
+ for (i = 0; i < node->count; i++)
+ {
+ raw = &node->raw[i];
+
+ /* Souplesse dans les positions ? */
+ if (offsets_exist(&params->offset))
+ {
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ assert(ranges[r].has_max);
+ assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+ for (p = ranges[r].min; p <= ranges[r].max; p++)
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près de
+ * la fin du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if ((p + raw->len) > after)
+ break;
+
+ status = check_scan_token_node_plain_content(raw, NULL, nocase,
+ area->end + p, params->content);
+
+ if (status)
+ {
+ updated_edge = area->end + p + raw->len;
+
+ if (updated_edge < min_end)
+ min_end = updated_edge;
+
+ if (updated_edge > max_end)
+ max_end = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Position immédiatement attendue */
+ else
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près de
+ * la fin du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if (raw->len > after)
+ continue;
+
+ status = check_scan_token_node_plain_content(raw, NULL, nocase, area->end, params->content);
+
+ if (status)
+ {
+ updated_edge = area->end + raw->len;
+
+ if (updated_edge < min_end)
+ min_end = updated_edge;
+
+ if (updated_edge > max_end)
+ max_end = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->end = (1 /* greedy */ ? min_end : max_end);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ }
+
+ params->initialized = true;
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+
+
+
+
+
+ bool track_path; /* Conservation du chemin */
+ bool nocase; /* Pas d'intérêt pour la casse */
+
+
+
+
+ size_t i; /* Boucle de parcours #1 */
+
+
+ const sized_binary_t *raw; /* Données brutes d'origine */
+
+
+ bool status; /* Bilan d'une correspondance */
+
+
+
+
+
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t before; /* Espace disposible avant */
+ phys_t min_start; /* Début le plus proche trouvé */
+ phys_t max_start; /* Début le plus distant trouvé*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ /**
+ * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+ * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.
+ */
+
+ assert(params->initialized);
+
+ track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN);
+
+ nocase = (node->flags & SPNF_CASE_INSENSITIVE);
+
+
+
+ /**
+ * .............
+ */
+ if (0)
+ {
+
+
+ ;
+
+
+
+ }
+
+ /**
+ * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+ * des comparaisons entières de motifs.
+ */
+ else
+ {
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(params->content_start <= area->start);
+
+ before = area->start - params->content_start;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ /**
+ * Il ne peut y avoir qu'une seule séquence d'octets à un même
+ * emplacement. En revanche, des modificateurs peuvent construire
+ * possédant une même base, mais offrant des suffixes différents
+ * (par exemple, un marqueur nul UTF-16 final en complément).
+ *
+ * L'ensemble des combinaisons produites doit ainsi être exploré.
+ */
+
+ min_start = params->content_start;
+ max_start = params->content_end;
+
+ updated = false;
+
+ for (i = 0; i < node->count; i++)
+ {
+ raw = &node->raw[i];
+
+ /* Souplesse dans les positions ? */
+ if (offsets_exist(&params->offset))
+ {
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ assert(ranges[r].has_max);
+ assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+ for (p = ranges[r].min; p <= ranges[r].max; p++)
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près de
+ * la fin du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if ((p + raw->len) > before)
+ break;
+
+ status = check_scan_token_node_plain_content(raw, NULL, nocase,
+ area->start - raw->len - p,
+ params->content);
+
+ if (status)
+ {
+ updated_edge = area->start - raw->len - p;
+
+ if (updated_edge > min_start)
+ min_start = updated_edge;
+
+ if (updated_edge < max_start)
+ max_start = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Position immédiatement attendue */
+ else
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près du
+ * début du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée sans appel.
+ */
+ if (raw->len > before)
+ continue;
+
+ status = check_scan_token_node_plain_content(raw, NULL, nocase,
+ area->start - raw->len,
+ params->content);
+
+ if (status)
+ {
+ updated_edge = area->start - raw->len;
+
+ if (updated_edge > min_start)
+ min_start = updated_edge;
+
+ if (updated_edge < max_start)
+ max_start = updated_edge;
+
+ updated = true;
+
+ }
+
+ }
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->start = (1 /* greedy */ ? min_start : max_start);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ }
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.h b/src/analysis/scan/patterns/tokens/nodes/plain.h
new file mode 100644
index 0000000..abf71de
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.h
@@ -0,0 +1,83 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.h - prototypes pour la gestion d'une recherche de motif textuel
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+#include "../../modifier.h"
+#include "../../../../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_PLAIN g_scan_token_node_plain_get_type()
+#define G_SCAN_TOKEN_NODE_PLAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlain))
+#define G_IS_SCAN_TOKEN_NODE_PLAIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN))
+#define G_SCAN_TOKEN_NODE_PLAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlainClass))
+#define G_IS_SCAN_TOKEN_NODE_PLAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_PLAIN))
+#define G_SCAN_TOKEN_NODE_PLAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlainClass))
+
+
+/* Bribe de motif textuelle pour recherches (instance) */
+typedef struct _GScanTokenNodePlain GScanTokenNodePlain;
+
+/* Bribe de motif textuelle pour recherches (classe) */
+typedef struct _GScanTokenNodePlainClass GScanTokenNodePlainClass;
+
+
+/* Propriétés d'un élément textuel à rechercher */
+typedef enum _ScanPlainNodeFlags
+{
+ SPNF_NONE = (0 << 0), /* Aucune particularité */
+ SPNF_CASE_INSENSITIVE = (1 << 0), /* Ignorance de la casse */
+
+ /**
+ * Les deux propriétés suivantes sont récupérées et traitées
+ * au niveau du Token propriétaire.
+ */
+
+ SPNF_FULLWORD = (1 << 1), /* Recherche de mot entier */
+ SPNF_PRIVATE = (1 << 2), /* Marque privative */
+
+} ScanPlainNodeFlags;
+
+
+/* Indique le type défini pour un noeud représentant une bribe de texte à retrouver. */
+GType g_scan_token_node_plain_get_type(void);
+
+/* Construit un noeud représentant un motif textuel. */
+GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags);
+
+/* Indique les propriétés particulières d'un noeud de texte. */
+ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence-int.h b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h
new file mode 100644
index 0000000..f0ea6ae
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence-int.h - prototypes internes pour des décompositions séquentielles de motif de recherche
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H
+
+
+#include "sequence.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Décompositions séquentielles de motif de recherche (instance) */
+struct _GScanTokenNodeSequence
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ GScanTokenNode **children; /* Sous-noeuds à représenter */
+ size_t count; /* Taille de cette liste */
+
+};
+
+/* Décompositions séquentielles de motif de recherche (classe) */
+struct _GScanTokenNodeSequenceClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une série de décompositions séquentielles. */
+bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.c b/src/analysis/scan/patterns/tokens/nodes/sequence.c
new file mode 100644
index 0000000..394c877
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.c
@@ -0,0 +1,504 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence.c - décompositions séquentielles de motif de recherche
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "sequence.h"
+
+
+#include <assert.h>
+
+
+#include "any.h"
+#include "sequence-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des décompositions séquentielles. */
+static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *);
+
+/* Initialise une instance de décompositions séquentielles. */
+static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+static void g_scan_token_node_sequence_apply_flags(GScanTokenNodeSequence *, ScanTokenNodeFlags);
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_sequence_build_id(GScanTokenNodeSequence *, GEngineBackend *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */
+G_DEFINE_TYPE(GScanTokenNodeSequence, g_scan_token_node_sequence, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des décompositions séquentielles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenNodeClass *node; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_sequence_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_sequence_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_sequence_apply_flags;
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_sequence_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_sequence_enroll;
+ node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_sequence_build_id;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = instance à initialiser. *
+* *
+* Description : Initialise une instance de décompositions séquentielles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *sequence)
+{
+ sequence->children = NULL;
+ sequence->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *sequence)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < sequence->count; i++)
+ g_clear_object(&sequence->children[i]);
+
+ G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->dispose(G_OBJECT(sequence));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *sequence)
+{
+ if (sequence->children != NULL)
+ free(sequence->children);
+
+ G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->finalize(G_OBJECT(sequence));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Construit une série de décompositions séquentielles de motif.*
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *child)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, NULL);
+
+ if (!g_scan_token_node_sequence_create(G_SCAN_TOKEN_NODE_SEQUENCE(result), child))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = décompositions à initialiser pleinement. *
+* child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Met en place une série de décompositions séquentielles. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *sequence, GScanTokenNode *child)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ g_scan_token_node_sequence_add(sequence, child);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = ensemble de noeuds à compléter. *
+* child = nouveau noeud à intégrer. *
+* *
+* Description : Ajoute un noeud à aux décompositions séquentielles de motif. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_sequence_add(GScanTokenNodeSequence *sequence, GScanTokenNode *child)
+{
+ bool processed; /* Intégration traitée ? */
+ GScanTokenNode *last; /* Dernier noeud inscrit */
+
+ processed = false;
+
+ if (sequence->count > 0)
+ {
+ last = sequence->children[sequence->count - 1];
+
+ if (G_IS_SCAN_TOKEN_NODE_ANY(last) && G_IS_SCAN_TOKEN_NODE_ANY(child))
+ {
+ g_scan_token_node_any_merge(G_SCAN_TOKEN_NODE_ANY(last), G_SCAN_TOKEN_NODE_ANY(child));
+ processed = true;
+ }
+
+ }
+
+ if (!processed)
+ {
+ sequence->children = realloc(sequence->children, ++sequence->count * sizeof(GScanTokenNode *));
+
+ sequence->children[sequence->count - 1] = child;
+ g_object_ref(G_OBJECT(child));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = ensemble de noeuds à consulter. *
+* *
+* Description : Indique le nombre de noeuds intégrés dans la séquence. *
+* *
+* Retour : Nombre de noeuds représentés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_scan_token_node_sequence_count(const GScanTokenNodeSequence *sequence)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = sequence->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = ensemble de noeuds à consulter. *
+* index = indice du noeud à retourner. *
+* *
+* Description : Fournit un noeud donné d'une décomposition séquentielle. *
+* *
+* Retour : Noeud inclus dans l'ensemble ou NULL si mauvais indice. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_sequence_get(const GScanTokenNodeSequence *sequence, size_t index)
+{
+ GScanTokenNode *result; /* Instance à retourner */
+
+ assert(index < sequence->count);
+
+ if (index < sequence->count)
+ {
+ result = sequence->children[index];
+ g_object_ref(G_OBJECT(result));
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à mettre à jour. *
+* flags = propriétés particulières à associer au noeud. *
+* *
+* Description : Prend acte d'une nouvelle propriété pour le noeud. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_apply_flags(GScanTokenNodeSequence *node, ScanTokenNodeFlags flags)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (node->count == 1)
+ g_scan_token_node_set_flags(node->children[0], flags);
+
+ else if (node->count > 1)
+ {
+ g_scan_token_node_set_flags(node->children[0], flags & ~STNF_LAST);
+
+ for (i = 1; i < (node->count - 1); i++)
+ g_scan_token_node_set_flags(node->children[i], flags & ~(STNF_FIRST | STNF_LAST));
+
+ g_scan_token_node_set_flags(node->children[node->count - 1], flags & ~STNF_FIRST);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *points)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < node->count; i++)
+ g_scan_token_node_visit(node->children[i], points);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ for (i = 0; i < node->count && result; i++)
+ result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à peaufiner. *
+* backend = moteur de recherche à préchauffer. *
+* *
+* Description : Récupère un identifiant final pour un atome d'octets. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_sequence_build_id(GScanTokenNodeSequence *node, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ result = true;
+
+ for (i = 0; i < node->count && result; i++)
+ result = g_scan_token_node_build_id(node->children[i], backend);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < node->count; i++)
+ _g_scan_token_node_check_forward(node->children[i], params, cflags, skip);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = node->count; i > 0 ; i--)
+ _g_scan_token_node_check_backward(node->children[i - 1], params, cflags, skip);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.h b/src/analysis/scan/patterns/tokens/nodes/sequence.h
new file mode 100644
index 0000000..12df9d1
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence.h - prototypes pour des décompositions séquentielles de motif de recherche
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_SEQUENCE g_scan_token_node_sequence_get_type()
+#define G_SCAN_TOKEN_NODE_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequence))
+#define G_IS_SCAN_TOKEN_NODE_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE))
+#define G_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass))
+#define G_IS_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE))
+#define G_SCAN_TOKEN_NODE_SEQUENCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass))
+
+
+/* Décompositions séquentielles de motif de recherche (instance) */
+typedef struct _GScanTokenNodeSequence GScanTokenNodeSequence;
+
+/* Décompositions séquentielles de motif de recherche (classe) */
+typedef struct _GScanTokenNodeSequenceClass GScanTokenNodeSequenceClass;
+
+
+/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */
+GType g_scan_token_node_sequence_get_type(void);
+
+/* Construit une série de décompositions séquentielles de motif. */
+GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *);
+
+/* Ajoute un noeud à aux décompositions séquentielles de motif. */
+void g_scan_token_node_sequence_add(GScanTokenNodeSequence *, GScanTokenNode *);
+
+/* Indique le nombre de noeuds intégrés dans la séquence. */
+size_t g_scan_token_node_sequence_count(const GScanTokenNodeSequence *);
+
+/* Fournit un noeud donné d'une décomposition séquentielle. */
+GScanTokenNode *g_scan_token_node_sequence_get(const GScanTokenNodeSequence *, size_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H */
diff --git a/src/analysis/scan/patterns/tokens/offset.c b/src/analysis/scan/patterns/tokens/offset.c
new file mode 100644
index 0000000..0a4fd91
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.c
@@ -0,0 +1,438 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * offset.c - décomposition d'un motif de recherche en atomes assemblés
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "offset.h"
+
+
+#include <assert.h>
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : range = bornes décrivant un espace quelconque. *
+* available = espace restant disponible. *
+* min = point de départ pour parcourir une zone. [OUT] *
+* max = point d'arrivée pour parcourir une zone. [OUT] *
+* *
+* Description : Fournit les bornes d'une zone à analyser. *
+* *
+* Retour : true si assez d'espace est disponible, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool get_node_offset_range(const node_offset_range_t *range, phys_t len, phys_t available, phys_t *min, phys_t *max)
+{
+ bool result; /* Bilan à retourner */
+
+ if ((len + range->min) > available)
+ result = false;
+
+ else
+ {
+ result = true;
+
+ *min = range->min;
+ *max = range->max;
+
+ if ((len + *max) > available)
+ {
+ *max = available - len;
+ assert(*max >= *min);
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à initialiser. *
+* *
+* Description : Initialise une mémorisation d'intervales de tolérance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void init_node_search_offset(node_search_offset_t *offset)
+{
+ offset->ranges = NULL;
+ offset->allocated = 0;
+
+ offset->gen_ptr = NULL;
+
+ offset->used = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] *
+* src = suivi de tolérances bornées à copier. *
+* *
+* Description : Copie une mémorisation d'intervales entre positions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void copy_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src)
+{
+ init_node_search_offset(dest);
+
+ switch (src->used)
+ {
+ case 0:
+ dest->gen_ptr = NULL;
+ break;
+
+ case 1:
+ dest->range = src->range;
+ dest->gen_ptr = &dest->range;
+ break;
+
+ default:
+ dest->ranges = malloc(src->used * sizeof(node_offset_range_t));
+ memcpy(dest->ranges, src->ranges, src->used * sizeof(node_offset_range_t));
+ dest->gen_ptr = dest->ranges;;
+ break;
+
+ }
+
+ dest->used = src->used;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] *
+* src = suivi de tolérances bornées à copier. *
+* *
+* Description : Fusionne une mémorisation d'intervales entre positions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void merge_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src)
+{
+ node_offset_range_t * const *list; /* Liste d'intervales à copier */
+ size_t i; /* Boucle de parcours */
+
+ if ((dest->used + src->used) > 1 && (dest->used + src->used) > dest->allocated)
+ {
+ dest->allocated += src->used;
+
+ dest->ranges = realloc(dest->ranges, dest->allocated * sizeof(node_offset_range_t));
+
+ }
+
+ list = get_node_search_offset_ranges(src, (size_t []){ 0 });
+
+ for (i = 0; i < src->used; i++)
+ add_range_to_node_search_offset(dest, (*list)[i].min, (*list)[i].max, NULL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à terminer. *
+* *
+* Description : Met fin à une mémorisation d'intervales de tolérance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void exit_node_search_offset(node_search_offset_t *offset)
+{
+ if (offset->ranges != NULL)
+ free(offset->ranges);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* count = nombre de bornes enregistrées. [OUT] *
+* *
+* Description : Fournit la liste des tolérances bornées établies à présent. *
+* *
+* Retour : Liste d'intervales en lecture seule. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *offset, size_t *count)
+{
+ node_offset_range_t * const *result; /* Série à renvoyer */
+
+ result = &offset->gen_ptr;
+
+ *count = offset->used;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* count = nombre de bornes enregistrées. [OUT] *
+* *
+* Description : Fournit la liste des tolérances bornées établies à présent. *
+* *
+* Retour : Liste d'intervales en lecture seule. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const node_offset_range_t * const get_node_search_offset_ranges_2(const node_search_offset_t *offset, size_t *count)
+{
+ node_offset_range_t *result; /* Série à renvoyer */
+
+ result = offset->gen_ptr;
+
+ *count = offset->used;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* min = point de départ pour parcourir une zone. *
+* max = point d'arrivée pour parcourir une zone. *
+* datasize = taille maximale pour définir une inversion NOT. *
+* *
+* Description : Ajoute un nouvel espace borné aux décalages tolérés. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void add_range_to_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, const phys_t *datasize)
+{
+ bool not; /* Traduction de la taille */
+ size_t needed; /* Nombre d'emplacements requis*/
+
+ not = (datasize != NULL);
+
+ /* Si le réceptacle unique peut être employé... */
+ if (offset->used == 0 && !not)
+ {
+ offset->range.min = min;
+ offset->range.max = max;
+
+ offset->used = 1;
+
+ offset->gen_ptr = &offset->range;
+
+ }
+
+ /* Sinon le groupe dynamique est sollicité */
+ else
+ {
+ needed = offset->used + (not ? 2 : 1);
+
+ if (needed > offset->allocated)
+ {
+ offset->ranges = realloc(offset->ranges, needed * sizeof(node_offset_range_t));
+ offset->allocated = needed;
+ }
+
+ /* Bascule d'un éventuel intervale courant */
+ if (offset->used == 1)
+ {
+ offset->ranges[0].min = offset->range.min;
+ offset->ranges[0].max = offset->range.max;
+ }
+
+ if (not)
+ {
+ if (min > 0)
+ {
+ offset->ranges[offset->used].min = 0;
+ offset->ranges[offset->used].max = min - 1;
+
+ offset->used++;
+
+ }
+
+ if ((max + 1) < *datasize)
+ {
+ offset->ranges[offset->used].min = max + 1;
+ offset->ranges[offset->used].max = *datasize - (max + 1);
+
+ offset->used++;
+
+ }
+
+ }
+ else
+ {
+ offset->ranges[offset->used].min = min;
+ offset->ranges[offset->used].max = max;
+
+ offset->used++;
+
+ }
+
+ offset->gen_ptr = offset->ranges;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* min = point de départ pour parcourir une zone. *
+* max = point d'arrivée pour parcourir une zone. *
+* has_max = validité de la valeur maximale transmise. *
+* *
+* Description : Etend les décalages tolérés avec un nouvel espace. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void extend_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, bool has_max)
+{
+ size_t i; /* Boucle de parcours */
+
+ switch (offset->used)
+ {
+ /* Si le réceptacle unique peut être employé... */
+ case 0:
+
+ offset->range.min = min;
+ offset->range.max = max;
+ offset->range.has_max = has_max;
+
+ offset->used = 1;
+
+ offset->gen_ptr = &offset->range;
+
+ break;
+
+ /* Si un espace unique est enregistré */
+ case 1:
+
+ offset->range.min += min;
+ offset->range.max += max;
+ offset->range.has_max &= has_max;
+
+ break;
+
+ /* Sinon le groupe dynamique est sollicité */
+ default:
+
+ for (i = 0; i < offset->used; i++)
+ {
+ offset->ranges[i].min += min;
+ offset->ranges[i].max += max;
+ offset->ranges[i].has_max &= has_max;
+ }
+
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* last = dernière position validée. *
+* pos = nouvelle position potentielle. *
+* *
+* Description : Indique si une position est comprise dans un intervale. *
+* *
+* Retour : Bilan de la détermination. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool does_node_search_offset_include_pos_forward(const node_search_offset_t *offset, phys_t last, phys_t pos)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ const node_offset_range_t *range; /* Accès rapide aux infos. */
+
+ result = false;
+
+ for (i = 0; i < offset->used; i++)
+ {
+ range = &offset->gen_ptr[i];
+
+ result = ((last + range->min) <= pos && pos <= (last + range->max));
+ if (result) break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/tokens/offset.h b/src/analysis/scan/patterns/tokens/offset.h
new file mode 100644
index 0000000..130aaea
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.h
@@ -0,0 +1,111 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * offset.h - prototypes pour la prise en compte des espaces entre octets dans un motif de recherche
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H
+
+
+#include <stdbool.h>
+
+#include "../../../../arch/vmpa.h"
+
+
+
+/* Mémorisation d'une souplesse dans les positions visées */
+typedef struct _node_offset_range_t
+{
+ /**
+ * Les deux champs ci-après font bien référence à des positions absolues,
+ * et non à des bornes d'espace, lorsque les résultats de correspondances
+ * sont encore non initialisés.
+ *
+ * Ensuite ces bornes représentent bien un espace séparant les résultats
+ * issus de deux noeuds.
+ */
+ phys_t min; /* Position minimale */
+ phys_t max; /* Position maximale */
+ bool has_max; /* Quantité définie ? */
+
+} node_offset_range_t;
+
+
+/* Fournit les bornes d'une zone à analyser. */
+bool get_node_offset_range(const node_offset_range_t *, phys_t, phys_t, phys_t *, phys_t *);
+
+
+
+#define MAX_RANGE_FOR_MANUAL_CHECK 5
+
+
+
+/* Mémorisation d'une souplesse dans les positions visées */
+typedef struct _node_search_offset_t
+{
+ node_offset_range_t range; /* Bornes de décalage uniques */
+
+ node_offset_range_t *ranges; /* Bornes de décalage multiples*/
+ size_t allocated; /* Nombre d'allocations */
+
+ node_offset_range_t *gen_ptr; /* Accès générique à la liste */
+
+ size_t used; /* Nombre de bornes présentes */
+
+} node_search_offset_t;
+
+
+/* Initialise une mémorisation d'intervales de tolérance. */
+void init_node_search_offset(node_search_offset_t *);
+
+/* Copie une mémorisation d'intervales entre positions. */
+void copy_node_search_offset(node_search_offset_t *, const node_search_offset_t *);
+
+/* Fusionne une mémorisation d'intervales entre positions. */
+void merge_node_search_offset(node_search_offset_t *, const node_search_offset_t *);
+
+/* Met fin à une mémorisation d'intervales de tolérance. */
+void exit_node_search_offset(node_search_offset_t *);
+
+#define offsets_exist(off) \
+ ((off)->used > 0)
+
+
+/* Fournit la liste des tolérances bornées établies à présent. */
+/* TODO : supprimer un niveau d'indirection */
+node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *, size_t *);
+const node_offset_range_t * const get_node_search_offset_ranges_2(const node_search_offset_t *, size_t *);
+
+/* Ajoute un nouvel espace borné aux décalages tolérés. */
+void add_range_to_node_search_offset(node_search_offset_t *, phys_t, phys_t, const phys_t *);
+
+/* Etend les décalages tolérés avec un nouvel espace. */
+void extend_node_search_offset(node_search_offset_t *, phys_t, phys_t, bool);
+
+#define disable_all_ranges_in_node_search_offset(off) \
+ (off)->used = 0
+
+/* Indique si une position est comprise dans un intervale. */
+bool does_node_search_offset_include_pos_forward(const node_search_offset_t *, phys_t, phys_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H */
diff --git a/src/analysis/scan/patterns/tokens/plain-int.h b/src/analysis/scan/patterns/tokens/plain-int.h
new file mode 100644
index 0000000..b0ef106
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/plain-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain-int.h - prototypes internes pour la recherche d'une chaîne de caractères brute
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H
+
+
+#include "plain.h"
+
+
+#include "atom.h"
+#include "../token-int.h"
+
+
+
+/* Encadrement d'une recherche de texte brut (instance) */
+struct _GScanPlainBytes
+{
+ GBytesToken parent; /* A laisser en premier */
+
+};
+
+/* Encadrement d'une recherche de texte brut (classe) */
+struct _GScanPlainBytesClass
+{
+ GBytesTokenClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un gestionnaire de recherche de texte brut. */
+bool g_scan_plain_bytes_create(GScanPlainBytes *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/plain.c b/src/analysis/scan/patterns/tokens/plain.c
new file mode 100644
index 0000000..3d6c39d
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/plain.c
@@ -0,0 +1,266 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.c - recherche d'une chaîne de caractères brute
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "plain.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "plain-int.h"
+#include "nodes/plain.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des recherches de texte brut. */
+static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass);
+
+/* Initialise une instance de recherche de texte brut. */
+static void g_scan_plain_bytes_init(GScanPlainBytes *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_plain_bytes_dispose(GScanPlainBytes *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_plain_bytes_finalize(GScanPlainBytes *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Affiche un motif de recherche au format texte. */
+static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *, GScanContext *, int);
+
+/* Affiche un motif de recherche au format JSON. */
+static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *, GScanContext *, const sized_string_t *, unsigned int, int);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */
+G_DEFINE_TYPE(GScanPlainBytes, g_scan_plain_bytes, G_TYPE_BYTES_TOKEN);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des recherches de texte brut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GSearchPatternClass *pattern; /* Version de classe ancêtre */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_plain_bytes_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_plain_bytes_finalize;
+
+ pattern = G_SEARCH_PATTERN_CLASS(klass);
+
+ pattern->to_text = (output_pattern_to_text_fc)g_scan_plain_bytes_output_to_text;
+ pattern->to_json = (output_pattern_to_json_fc)g_scan_plain_bytes_output_to_json;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = instance à initialiser. *
+* *
+* Description : Initialise une instance de recherche de texte brut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_bytes_init(GScanPlainBytes *bytes)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes)
+{
+ G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->dispose(G_OBJECT(bytes));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
+{
+ G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->finalize(G_OBJECT(bytes));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : root = représentation du motif à recherche. *
+* *
+* Description : Construit un gestionnaire de recherche de texte brut. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *root)
+{
+ GSearchPattern *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_PLAIN_BYTES, NULL);
+
+ if (!g_scan_plain_bytes_create(G_SCAN_PLAIN_BYTES(result), root))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = encadrement de motif à initialiser pleinement. *
+* root = représentation du motif à recherche. *
+* *
+* Description : Met en place un gestionnaire de recherche de texte brut. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, GScanTokenNode *root)
+{
+ bool result; /* Bilan à retourner */
+ ScanPlainNodeFlags flags; /* Propriétés à interpréter */
+ bool fullword; /* Cible de mots entiers ? */
+ bool private; /* Vocation privée ? */
+
+ flags = g_scan_token_node_plain_get_flags(G_SCAN_TOKEN_NODE_PLAIN(root));
+
+ fullword = (flags & SPNF_FULLWORD);
+ private = (flags & SPNF_PRIVATE);
+
+ result = g_bytes_token_create(G_BYTES_TOKEN(bytes), root, fullword, private);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un motif de recherche au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *pattern, GScanContext *context, int fd)
+{
+ G_SEARCH_PATTERN_CLASS(g_scan_plain_bytes_parent_class)->to_text(G_SEARCH_PATTERN(pattern), context, fd);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pattern = définition de motif à considérer. *
+* context = contexte de l'analyse à mener. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un motif de recherche au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd)
+{
+ G_SEARCH_PATTERN_CLASS(g_scan_plain_bytes_parent_class)->to_json(G_SEARCH_PATTERN(pattern), context, padding, level, fd);
+
+ /* TODO */
+
+}
diff --git a/src/analysis/scan/patterns/tokens/plain.h b/src/analysis/scan/patterns/tokens/plain.h
new file mode 100644
index 0000000..6ff48d7
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/plain.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plain.h - prototypes pour la recherche d'une chaîne de caractères brute
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H
+
+
+#include <glib-object.h>
+
+
+#include "node.h"
+#include "../../pattern.h"
+
+
+
+#define G_TYPE_SCAN_PLAIN_BYTES g_scan_plain_bytes_get_type()
+#define G_SCAN_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytes))
+#define G_IS_SCAN_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PLAIN_BYTES))
+#define G_SCAN_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytesClass))
+#define G_IS_SCAN_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PLAIN_BYTES))
+#define G_SCAN_PLAIN_BYTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytesClass))
+
+
+/* Représentation d'une suite d'octets à retrouver (instance) */
+typedef struct _GScanPlainBytes GScanPlainBytes;
+
+/* Représentation d'une suite d'octets à retrouver (classe) */
+typedef struct _GScanPlainBytesClass GScanPlainBytesClass;
+
+
+/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */
+GType g_scan_plain_bytes_get_type(void);
+
+/* Construit un gestionnaire de recherche de texte brut. */
+GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H */
diff --git a/src/analysis/scan/rule-int.h b/src/analysis/scan/rule-int.h
new file mode 100644
index 0000000..17d4dc2
--- /dev/null
+++ b/src/analysis/scan/rule-int.h
@@ -0,0 +1,69 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rule-int.h - prototypes internes pour la gestion d'une règle de détection par motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_RULE_INT_H
+#define _ANALYSIS_SCAN_RULE_INT_H
+
+
+#include "rule.h"
+
+
+
+#define PATTERN_ALLOC_SIZE 20
+
+
+/* Représentation d'une règle de détection statique (instance) */
+struct _GScanRule
+{
+ GObject parent; /* A laisser en premier */
+
+ ScanRuleFlags flags; /* Propriétés de la règle */
+
+ char *name; /* Désignation de la règle */
+ fnv64_t name_hash; /* Empreinte de la désignation */
+
+ char **tags; /* Etiquettes associées */
+ char tags_count; /* Quantité de ces étiquettes */
+
+ GSearchPattern **bytes_locals; /* Variables de données */
+ size_t bytes_allocated; /* Taille allouée du tableau */
+ size_t bytes_used; /* Nombre d'éléments présents */
+
+ GScanExpression *condition; /* Condition de correspondance */
+
+};
+
+/* Représentation d'une règle de détection statique (classe) */
+struct _GScanRuleClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une règle de détection statique avec motifs. */
+bool g_scan_rule_create(GScanRule *, ScanRuleFlags, const char *);
+
+
+
+#endif /* _ANALYSIS_SCAN_RULE_INT_H */
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
new file mode 100644
index 0000000..d3acbc2
--- /dev/null
+++ b/src/analysis/scan/rule.c
@@ -0,0 +1,1084 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rule.c - parcours de contenus à la recherche de motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "rule.h"
+
+
+#include <assert.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+
+#include "rule-int.h"
+#include "matches/bytes.h"
+#include "patterns/token.h"
+#include "../../common/extstr.h"
+#include "../../core/logs.h"
+
+
+
+/* Initialise la classe des règles de détection statique. */
+static void g_scan_rule_class_init(GScanRuleClass *);
+
+/* Initialise une instance de règle de détection statique. */
+static void g_scan_rule_init(GScanRule *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_rule_dispose(GScanRule *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_rule_finalize(GScanRule *);
+
+
+
+/* Indique le type défini pour une règle de détection par motifs. */
+G_DEFINE_TYPE(GScanRule, g_scan_rule, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des règles de détection statique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_rule_class_init(GScanRuleClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_rule_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_rule_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = instance à initialiser. *
+* *
+* Description : Initialise une instance de règle de détection statique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_rule_init(GScanRule *rule)
+{
+ rule->flags = SRF_NONE;
+
+ rule->name = NULL;
+ rule->name_hash = 0;
+
+ rule->tags = NULL;
+ rule->tags_count = 0;
+
+ rule->bytes_locals = NULL;
+ rule->bytes_allocated = 0;
+ rule->bytes_used = 0;
+
+ rule->condition = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_rule_dispose(GScanRule *rule)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < rule->bytes_used; i++)
+ g_clear_object(&rule->bytes_locals[i]);
+
+ g_clear_object(&rule->condition);
+
+ G_OBJECT_CLASS(g_scan_rule_parent_class)->dispose(G_OBJECT(rule));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_rule_finalize(GScanRule *rule)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (rule->name != NULL)
+ free(rule->name);
+
+ for (i = 0; i < rule->tags_count; i++)
+ free(rule->tags[i]);
+
+ if (rule->tags != NULL)
+ free(rule->tags);
+
+ if (rule->bytes_locals != NULL)
+ free(rule->bytes_locals);
+
+ G_OBJECT_CLASS(g_scan_rule_parent_class)->finalize(G_OBJECT(rule));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : flags = propriétés particulières à conférer à la règle. *
+* name = désignation à associer à la future règle. *
+* *
+* Description : Crée une règle de détection statique à l'aide de motifs. *
+* *
+* Retour : Règle de détection mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRule *g_scan_rule_new(ScanRuleFlags flags, const char *name)
+{
+ GScanRule *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_RULE, NULL);
+
+ result->flags = flags;
+
+ result->name = strdup(name);
+ result->name_hash = fnv_64a_hash(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à initialiser pleinement. *
+* flags = propriétés particulières à conférer à la règle. *
+* name = désignation à associer à la future règle. *
+* *
+* Description : Met en place une règle de détection statique avec motifs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_rule_create(GScanRule *rule, ScanRuleFlags flags, const char *name)
+{
+ GScanRule *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_RULE, NULL);
+
+ result->flags = flags;
+
+ result->name = strdup(name);
+ result->name_hash = fnv_64a_hash(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* *
+* Description : Indique les particularités liées à une règle de détection. *
+* *
+* Retour : Propriétés particulières attachées à la règle. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanRuleFlags g_scan_rule_get_flags(const GScanRule *rule)
+{
+ ScanRuleFlags result; /* Fanions à retourner */
+
+ result = rule->flags;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* hash = empreinte précalculée associée au nom. [OUT] *
+* *
+* Description : Indique le nom associé à une règle de détection. *
+* *
+* Retour : Désignation humaine associée à la règle. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_scan_rule_get_name(const GScanRule *rule, fnv64_t *hash)
+{
+ const char *result; /* Désignation à retourner */
+
+ result = rule->name;
+
+ if (hash != NULL)
+ *hash = rule->name_hash;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à compléter. *
+* tag = étiquette à associer à la règle. *
+* *
+* Description : Lie une règle à une nouvelle étiquette. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_add_tag(GScanRule *rule, const char *tag)
+{
+ rule->tags = realloc(rule->tags, ++rule->tags_count * sizeof(char *));
+
+ rule->tags[rule->tags_count - 1] = strdup(tag);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* count = quantité d'éléments retournés. [OUT] *
+* *
+* Description : Indique les éventuelles étiquettes associées à une règle. *
+* *
+* Retour : Liste d'étiquettes associées à la règle consultée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char * const *g_scan_rule_list_tags(const GScanRule *rule, size_t *count)
+{
+ const char * const *result; /* Liste à retourner */
+
+ result = rule->tags;
+
+ *count = rule->tags_count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à compléter. *
+* pattern = nouveau motif de détection. *
+* *
+* Description : Intègre une nouvelle variable locale à une règle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_add_local_variable(GScanRule *rule, GSearchPattern *pattern)
+{
+ if (G_IS_BYTES_TOKEN(pattern))
+ {
+ if (rule->bytes_used == rule->bytes_allocated)
+ {
+ rule->bytes_allocated += PATTERN_ALLOC_SIZE;
+ rule->bytes_locals = realloc(rule->bytes_locals, rule->bytes_allocated * sizeof(GSearchPattern *));
+ }
+
+ rule->bytes_locals[rule->bytes_used++] = pattern;
+ g_object_ref(G_OBJECT(pattern));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* target = nom d'une variable locale à retrouver. *
+* *
+* Description : Fournit une variable locale à une règle selon un nom. *
+* *
+* Retour : Motif de détection retrouvé ou NULL en cas d'échec. *
+* *
+* Remarques : La propriétée de l'instance renvoyée est partagée ! *
+* *
+******************************************************************************/
+
+const GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *target)
+{
+ const GSearchPattern *result; /* Variable à retourner */
+ size_t i; /* Boucle de parcours */
+ const char *name; /* Désignation d'un motif */
+
+ result = NULL;
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ name = g_search_pattern_get_name(rule->bytes_locals[i]);
+
+ if (strcmp(name, target) == 0)
+ {
+ result = rule->bytes_locals[i];
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* target = nom d'une variable locale à retrouver. *
+* count = quantité de motifs renvoyés. [OUT] *
+* *
+* Description : Fournit une liste de variables locales à partir d'un nom. *
+* *
+* Retour : Motifs de détection retrouvés ou NULL en cas d'échec. *
+* *
+* Remarques : La propriétée des instances renvoyées est partagée ! *
+* *
+******************************************************************************/
+
+const GSearchPattern **g_scan_rule_get_local_variables(GScanRule *rule, const char *target, size_t *count)
+{
+ const GSearchPattern **result; /* Variables à retourner */
+ size_t target_len; /* Nbre de caractères à évaluer*/
+ size_t len_without_star; /* Taille sans masque */
+ bool need_regex; /* Traitement complexe requis */
+ size_t i; /* Boucle de parcours */
+ char *regex; /* Définition complète */
+ regex_t preg; /* Expression compilée */
+ int ret; /* Bilan d'un appel */
+ const char *name; /* Désignation d'un motif */
+
+ result = NULL;
+
+ *count = 0;
+
+ /* Premier cas de figure : la liste complète est attendue */
+
+ if (target == NULL)
+ {
+ need_all_of_them:
+
+ *count = rule->bytes_used;
+ result = malloc(*count * sizeof(GSearchPattern *));
+
+ memcpy(result, rule->bytes_locals, *count);
+
+ }
+
+ /* Second cas de figure : identification au cas par cas */
+
+ else
+ {
+ target_len = strlen(target);
+
+ len_without_star = 0;
+
+ need_regex = false;
+
+ for (i = 0; i < target_len; i++)
+ if (target[i] == '*')
+ break;
+ else
+ len_without_star++;
+
+ for (i++; i < target_len; i++)
+ if (target[i] != '*')
+ {
+ need_regex = true;
+ goto try_harder;
+ }
+
+ if (len_without_star == 0)
+ goto need_all_of_them;
+
+ result = malloc(rule->bytes_used * sizeof(GSearchPattern *));
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ name = g_search_pattern_get_name(rule->bytes_locals[i]);
+
+ if (strncmp(name, target, len_without_star) == 0)
+ {
+ result[*count] = rule->bytes_locals[i];
+ (*count)++;
+ }
+
+ }
+
+ if (*count == 0)
+ {
+ free(result);
+ result = NULL;
+ }
+
+ }
+
+ try_harder:
+
+ /* Dernier cas de figure : une expression régulière est vraisemblablement de mise */
+
+ if (need_regex)
+ {
+ regex = strdup(target);
+
+ regex = strrpl(regex, "*", ".*");
+ regex = strprep(regex, "^");
+ regex = stradd(regex, "$");
+
+ ret = regcomp(&preg, regex, REG_NOSUB);
+
+ if (ret != 0)
+ {
+ LOG_ERROR_REGCOMP(&preg, ret);
+ goto done;
+ }
+
+ result = malloc(rule->bytes_used * sizeof(GSearchPattern *));
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ name = g_search_pattern_get_name(rule->bytes_locals[i]);
+
+ ret = regexec(&preg, name, 0, NULL, 0);
+
+ if (ret != REG_NOMATCH)
+ {
+ result[*count] = rule->bytes_locals[i];
+ (*count)++;
+ }
+
+ }
+
+ if (*count == 0)
+ {
+ free(result);
+ result = NULL;
+ }
+
+ regfree(&preg);
+
+ done:
+
+ free(regex);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à compléter. *
+* expr = expression de condition à satisfaire. *
+* *
+* Description : Définit l'expression d'une correspondance recherchée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_set_match_condition(GScanRule *rule, GScanExpression *expr)
+{
+ rule->condition = expr;
+
+ g_object_ref(G_OBJECT(expr));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* backend = moteur d'analyse pour données brutes. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Prépare le suivi de recherche de motifs pour une règle. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanContext *context)
+{
+ bool result; /* Statut à retourner */
+ size_t maxsize; /* Taille maximale des atomes */
+ GSearchPattern *pattern; /* Motif à intégrer */
+ size_t i; /* Boucle de parcours */
+
+ /* Suivi des conditions de correspondance */
+
+ result = g_scan_context_set_rule_condition(context, rule->name, rule->condition);
+ if (!result) goto exit;
+
+ /* Programmation des motifs recherchés */
+
+ maxsize = g_engine_backend_get_atom_max_size(backend);
+
+ for (i = 0; i < rule->bytes_used && result; i++)
+ {
+ pattern = rule->bytes_locals[i];
+ result = g_bytes_token_enroll(G_BYTES_TOKEN(pattern), backend, maxsize);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* backend = moteur d'analyse pour données brutes. *
+* *
+* Description : Récupère les identifiants finaux pour les motifs recherchés. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_rule_define_pattern_ids(GScanRule *rule, GEngineBackend *backend)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours */
+ GSearchPattern *pattern; /* Motif à intégrer */
+
+ result = true;
+
+ for (i = 0; i < rule->bytes_used && result; i++)
+ {
+ pattern = rule->bytes_locals[i];
+ result = g_bytes_token_build_id(G_BYTES_TOKEN(pattern), backend);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* backend = moteur d'analyse pour données brutes. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Lance une analyse d'un contenu binaire selon une règle. *
+* *
+* Retour : Contexte de suivi pour l'analyse menée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *context)
+{
+ scan_node_check_params_t params; /* Rassemblement de paramètres */
+ vmpa2t start; /* Point de début du contenu */
+ vmpa2t end; /* Point de fin du contenu */
+ size_t i; /* Boucle de parcours */
+ GSearchPattern *pattern; /* Motif à intégrer */
+ GScanMatches *matches; /* Correspondances établies */
+
+ /* Définition d'un contexte */
+
+ params.context = context;
+ params.content = g_scan_context_get_content(context);
+ params.allocator = g_umem_slice_new(sizeof(match_area_t));
+
+ g_binary_content_compute_start_pos(params.content, &start);
+ g_binary_content_compute_end_pos(params.content, &end);
+
+ params.content_start = start.physical;
+ params.content_end = end.physical;
+
+ /* Vérifications */
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ pattern = rule->bytes_locals[i];
+
+ matches = g_scan_bytes_matches_new();
+
+ g_bytes_token_check(G_BYTES_TOKEN(pattern), G_SCAN_BYTES_MATCHES(matches), &params);
+
+ g_scan_context_register_full_matches(context, pattern, matches);
+
+ g_object_unref(G_OBJECT(matches));
+
+ }
+
+ g_object_unref(G_OBJECT(params.content));
+ //g_object_unref(G_OBJECT(params.allocator));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* full = force un affichage complet des résultats. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche une règle au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_output_to_text(const GScanRule *rule, GScanContext *context, bool full, int fd)
+{
+ GScanOptions *options; /* Options de l'utilisateur */
+ bool selected; /* Affichage attendu ? */
+ size_t i; /* Boucle de parcours */
+ GBinContent *content; /* Contenu binaire scanné */
+ char *desc; /* Description de ce contenu */
+
+ /**
+ * Si la règle n'a pas fait mouche, rien n'est imprimé.
+ */
+ if (!g_scan_context_has_match_for_rule(context, rule->name))
+ return;
+
+ options = g_scan_context_get_options(context);
+
+ selected = g_scan_options_has_tag_as_selected(options, NULL);
+
+ /**
+ * Si la règle comporte des étiquettes et que l'utilisateur en a spécifié
+ * également.
+ */
+ if (rule->tags_count > 0 && !selected)
+ {
+ for (i = 0; i < rule->tags_count && !selected; i++)
+ selected = g_scan_options_has_tag_as_selected(options, rule->tags[i]);
+ }
+
+ if (selected)
+ {
+ write(fd, rule->name, strlen(rule->name));
+
+ if (g_scan_options_get_print_tags(options))
+ {
+ write(fd, " [", 2);
+
+ for (i = 0; i < rule->tags_count; i++)
+ {
+ if (i > 0)
+ write(fd, ",", 1);
+
+ write(fd, rule->tags[i], strlen(rule->tags[i]));
+
+ }
+
+ write(fd, "]", 1);
+
+ }
+
+ write(fd, " ", 1);
+
+ content = g_scan_context_get_content(context);
+
+ desc = g_binary_content_describe(content, true);
+
+ write(fd, desc, strlen(desc));
+ write(fd, "\n", 1);
+
+ free(desc);
+
+ g_object_unref(G_OBJECT(content));
+
+ if (full)
+ for (i = 0; i < rule->bytes_used; i++)
+ g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd);
+
+ }
+
+ g_object_unref(G_OBJECT(options));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit une règle en texte. *
+* *
+* Retour : Données textuelles ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_rule_convert_as_text(const GScanRule *rule, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-rule2text-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ g_scan_rule_output_to_text(rule, context, true, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* tail = décline la pose d'une virgule finale ? *
+* *
+* Description : Affiche une règle au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_output_to_json(const GScanRule *rule, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd, bool tail)
+{
+ size_t i; /* Boucle de parcours #1 */
+ bool sub_tail; /* Saut de la virgule finale ? */
+ size_t k; /* Boucle de parcours #2 */
+ GBinContent *content; /* Contenu binaire scanné */
+ char *desc; /* Description de ce contenu */
+
+ /* Introduction */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "{\n", 2);
+
+ /* Désignation de la règle */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"name\": \"", 9);
+
+ write(fd, rule->name, strlen(rule->name));
+
+ write(fd, "\",\n", 3);
+
+ /* Etiquettes ? */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"tags\": [", 9);
+
+ if (rule->tags_count > 0)
+ {
+ write(fd, "\n", 1);
+
+ for (k = 0; k < rule->tags_count; k++)
+ {
+ for (i = 0; i < (level + 2); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"", 1);
+
+ write(fd, rule->tags[k], strlen(rule->tags[k]));
+
+ write(fd, "\"", 1);
+
+ if ((k + 1) < rule->tags_count)
+ write(fd, ",", 1);
+
+ write(fd, "\n", 1);
+
+ }
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ }
+
+ write(fd, "],\n", 3);
+
+ /* Cible du scan */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"target\": \"", 11);
+
+ content = g_scan_context_get_content(context);
+
+ desc = g_binary_content_describe(content, true);
+
+ write(fd, desc, strlen(desc));
+
+ free(desc);
+
+ g_object_unref(G_OBJECT(content));
+
+ write(fd, "\",\n", 3);
+
+ /* Affichage des correspondances d'octets */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"bytes_patterns\": [\n", 20);
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ sub_tail = ((i + 1) == rule->bytes_used);
+
+ g_search_pattern_output_to_json(rule->bytes_locals[i], context, padding, level + 2, fd, sub_tail);
+
+ }
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "],\n", 3);
+
+ /* Bilan du filtrage */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"matched\": ", 11);
+
+ if (g_scan_context_has_match_for_rule(context, rule->name))
+ write(fd, "true", 4);
+ else
+ write(fd, "false", 5);
+
+ write(fd, "\n", 1);
+
+ /* Conclusion */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ if (tail)
+ write(fd, "}\n", 2);
+ else
+ write(fd, "},\n", 3);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit une règle en JSON. *
+* *
+* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_rule_convert_as_json(const GScanRule *rule, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-rule2json-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ padding.data = " ";
+ padding.len = 3;
+
+ g_scan_rule_output_to_json(rule, context, &padding, 0, fd, false);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/rule.h b/src/analysis/scan/rule.h
new file mode 100644
index 0000000..c2c58dc
--- /dev/null
+++ b/src/analysis/scan/rule.h
@@ -0,0 +1,119 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scanner.h - prototypes pour le parcours de contenus à la recherche de motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_RULE_H
+#define _ANALYSIS_SCAN_RULE_H
+
+
+#include <glib-object.h>
+
+
+#include "cond.h"
+#include "context.h"
+#include "pattern.h"
+#include "expr.h"
+#include "patterns/backend.h"
+#include "../../common/fnv1a.h"
+#include "../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_RULE g_scan_rule_get_type()
+#define G_SCAN_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_RULE, GScanRule))
+#define G_IS_SCAN_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_RULE))
+#define G_SCAN_RULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_RULE, GScanRuleClass))
+#define G_IS_SCAN_RULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_RULE))
+#define G_SCAN_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_RULE, GScanRuleClass))
+
+
+/* Représentation d'une règle de détection statique (instance) */
+typedef struct _GScanRule GScanRule;
+
+/* Représentation d'une règle de détection statique (classe) */
+typedef struct _GScanRuleClass GScanRuleClass;
+
+
+/* Particularités de règle à faire valoir */
+typedef enum _ScanRuleFlags
+{
+ SRF_NONE = (0 << 0), /* Absence de particularité */
+ SRF_PRIVATE = (1 << 0), /* Règle silencieuse */
+ SRF_GLOBAL = (1 << 1) /* Règle de base implicite */
+
+} ScanRuleFlags;
+
+
+/* Indique le type défini pour une règle de détection par motifs. */
+GType g_scan_rule_get_type(void);
+
+/* Crée une règle de détection statique à l'aide de motifs. */
+GScanRule *g_scan_rule_new(ScanRuleFlags, const char *);
+
+/* Indique les particularités liées à une règle de détection. */
+ScanRuleFlags g_scan_rule_get_flags(const GScanRule *);
+
+/* Indique le nom associé à une règle de détection. */
+const char *g_scan_rule_get_name(const GScanRule *, fnv64_t *);
+
+/* Lie une règle à une nouvelle étiquette. */
+void g_scan_rule_add_tag(GScanRule *, const char *);
+
+/* Indique les éventuelles étiquettes associées à une règle. */
+const char * const *g_scan_rule_list_tags(const GScanRule *, size_t *);
+
+/* Intègre une nouvelle variable locale à une règle. */
+void g_scan_rule_add_local_variable(GScanRule *, GSearchPattern *);
+
+/* Fournit une variable locale à une règle selon un nom. */
+const GSearchPattern *g_scan_rule_get_local_variable(GScanRule *, const char *);
+
+/* Fournit une liste de variables locales à partir d'un nom. */
+const GSearchPattern **g_scan_rule_get_local_variables(GScanRule *, const char *, size_t *);
+
+/* Définit l'expression d'une correspondance recherchée. */
+void g_scan_rule_set_match_condition(GScanRule *, GScanExpression *);
+
+/* Prépare le suivi de recherche de motifs pour une règle. */
+bool g_scan_rule_setup_backend(GScanRule *, GEngineBackend *, GScanContext *);
+
+/* Récupère les identifiants finaux pour les motifs recherchés. */
+bool g_scan_rule_define_pattern_ids(GScanRule *, GEngineBackend *);
+
+/* Lance une analyse d'un contenu binaire selon une règle. */
+void g_scan_rule_check(GScanRule *, GEngineBackend *, GScanContext *);
+
+/* Affiche une règle au format texte. */
+void g_scan_rule_output_to_text(const GScanRule *, GScanContext *, bool, int);
+
+/* Convertit une règle en texte. */
+char *g_scan_rule_convert_as_text(const GScanRule *, GScanContext *);
+
+/* Affiche une règle au format JSON. */
+void g_scan_rule_output_to_json(const GScanRule *, GScanContext *, const sized_string_t *, unsigned int, int, bool);
+
+/* Convertit une règle en JSON. */
+char *g_scan_rule_convert_as_json(const GScanRule *, GScanContext *);
+
+
+
+#endif /* _ANALYSIS_SCAN_RULE_H */
diff --git a/src/analysis/scan/scanner-int.h b/src/analysis/scan/scanner-int.h
new file mode 100644
index 0000000..02fd6b3
--- /dev/null
+++ b/src/analysis/scan/scanner-int.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scanner-int.h - prototypes internes pour le parcours de contenus à la recherche de motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_SCANNER_INT_H
+#define _ANALYSIS_SCAN_SCANNER_INT_H
+
+
+#include "scanner.h"
+
+
+#include "patterns/backend.h"
+
+
+
+/* Encadrement d'une recherche au sein de contenus binaires (instance) */
+struct _GContentScanner
+{
+ GObject parent; /* A laisser en premier */
+
+ char *filename; /* Eventuel fichier d'origine */
+
+ GScanRule **rules; /* Règles de détection */
+ size_t rule_count; /* Nombre de ces règles */
+
+ GEngineBackend *data_backend; /* Moteur pour les données */
+
+};
+
+/* Encadrement d'une recherche au sein de contenus binaires (classe) */
+struct _GContentScannerClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un scanner de contenus binaires. */
+bool g_content_scanner_create_from_text(GContentScanner *, const char *, size_t);
+
+/* Met en place un scanner de contenus binaires. */
+bool g_content_scanner_create_from_file(GContentScanner *, const char *);
+
+
+
+#endif /* _ANALYSIS_SCAN_SCANNER_INT_H */
diff --git a/src/analysis/scan/scanner.c b/src/analysis/scan/scanner.c
new file mode 100644
index 0000000..02a93fa
--- /dev/null
+++ b/src/analysis/scan/scanner.c
@@ -0,0 +1,808 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scanner.c - parcours de contenus à la recherche de motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "scanner.h"
+
+
+#include <assert.h>
+#include <libgen.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+
+#include "decl.h"
+#include "scanner-int.h"
+#include "../contents/file.h"
+#include "../../common/extstr.h"
+#include "../../core/logs.h"
+
+
+
+/* Initialise la classe des recherches dans du binaire. */
+static void g_content_scanner_class_init(GContentScannerClass *);
+
+/* Initialise une instance de recherche dans du binaire. */
+static void g_content_scanner_init(GContentScanner *);
+
+/* Supprime toutes les références externes. */
+static void g_content_scanner_dispose(GContentScanner *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_content_scanner_finalize(GContentScanner *);
+
+/* Intègre une nouvelle règle de détection. */
+static bool _g_content_scanner_add_rule(GContentScanner *, GScanRule *);
+
+
+
+/* Indique le type défini pour une recherche dans du binaire. */
+G_DEFINE_TYPE(GContentScanner, g_content_scanner, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des recherches dans du binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_content_scanner_class_init(GContentScannerClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_content_scanner_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_content_scanner_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = instance à initialiser. *
+* *
+* Description : Initialise une instance de recherche dans du binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_content_scanner_init(GContentScanner *scanner)
+{
+ scanner->filename = NULL;
+
+ scanner->rules = NULL;
+ scanner->rule_count = 0;
+
+ scanner->data_backend = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_content_scanner_dispose(GContentScanner *scanner)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < scanner->rule_count; i++)
+ g_clear_object(&scanner->rules[i]);
+
+ g_clear_object(&scanner->data_backend);
+
+ G_OBJECT_CLASS(g_content_scanner_parent_class)->dispose(G_OBJECT(scanner));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_content_scanner_finalize(GContentScanner *scanner)
+{
+ if (scanner->filename != NULL)
+ free(scanner->filename);
+
+ if (scanner->rules != NULL)
+ free(scanner->rules);
+
+ G_OBJECT_CLASS(g_content_scanner_parent_class)->finalize(G_OBJECT(scanner));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : text = définitions textuelles de règles de recherche. *
+* length = taille de la définition. *
+* *
+* Description : Prépare une recherche de motifs dans du contenu binaire. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GContentScanner *g_content_scanner_new_from_text(const char *text, size_t length)
+{
+ GContentScanner *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_CONTENT_SCANNER, NULL);
+
+ if (!g_content_scanner_create_from_text(result, text, length))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = scanner de contenus à initialiser pleinement. *
+* text = définitions textuelles de règles de recherche. *
+* length = taille de la définition. *
+* *
+* Description : Met en place un scanner de contenus binaires. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_content_scanner_create_from_text(GContentScanner *scanner, const char *text, size_t length)
+{
+ bool result; /* Bilan à retourner */
+
+ result = process_rules_definitions(scanner, text, length);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : filename = chemin vers des définitions de règles. *
+* *
+* Description : Prépare une recherche de motifs dans du contenu binaire. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GContentScanner *g_content_scanner_new_from_file(const char *filename)
+{
+ GContentScanner *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_CONTENT_SCANNER, NULL);
+
+ if (!g_content_scanner_create_from_file(result, filename))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = scanner de contenus à initialiser pleinement. *
+* filename = chemin vers des définitions de règles. *
+* *
+* Description : Met en place un scanner de contenus binaires. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_content_scanner_create_from_file(GContentScanner *scanner, const char *filename)
+{
+ bool result; /* Bilan à retourner */
+ GBinContent *content; /* Fichier à parcourir */
+ phys_t size; /* Taille du contenu associé */
+ vmpa2t start; /* Tête de lecture */
+ const bin_t *data; /* Données à consulter */
+
+ result = false;
+
+ content = g_file_content_new(filename);
+ if (content == NULL) goto no_content;
+
+ scanner->filename = strdup(filename);
+
+ size = g_binary_content_compute_size(content);
+
+ g_binary_content_compute_start_pos(content, &start);
+ data = g_binary_content_get_raw_access(content, &start, size);
+
+ result = process_rules_definitions(scanner, (char *)data, size);
+
+ g_object_unref(G_OBJECT(content));
+
+ no_content:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = scanner de contenus à consulter. *
+* *
+* Description : Indique le chemin d'un éventuel fichier de source. *
+* *
+* Retour : Chemin d'un éventuel fichier de définitions ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_content_scanner_get_filename(const GContentScanner *scanner)
+{
+ const char *result; /* Chemin à retourner */
+
+ result = scanner->filename;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à compléter. *
+* path = chemin vers une définition de règles à intégrer. *
+* *
+* Description : Inclut les définitions d'un fichier de règles externe. *
+* *
+* Retour : Bilan de l'inclusion à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_content_scanner_include_resource(GContentScanner *scanner, const char *path)
+{
+ bool result; /* Bilan à retourner */
+ GContentScanner *included; /* Définition à inclure */
+ char *tmp; /* Copie de travail */
+ char *filename; /* Chemin d'accès reconstruit */
+ size_t i; /* Boucle de parcours */
+ const char *inc_name; /* Nom de la nouvelle règle */
+
+ /* Cas le plus simple : un chemin absolu */
+ if (path[0] == '/')
+ included = g_content_scanner_new_from_file(path);
+
+ /* Chemin relatif à l'emplacement de la définition courante ? */
+ else if (scanner->filename != NULL)
+ {
+ tmp = strdup(scanner->filename);
+
+ filename = strdup(dirname(tmp));
+ filename = stradd(filename, G_DIR_SEPARATOR_S);
+ filename = stradd(filename, path);
+
+ included = g_content_scanner_new_from_file(filename);
+
+ free(filename);
+ free(tmp);
+
+ }
+
+ else
+ included = NULL;
+
+ /* Inclusion des règles chargées */
+
+ result = (included != NULL);
+
+ if (result)
+ {
+ for (i = 0; i < included->rule_count && result; i++)
+ {
+ result = _g_content_scanner_add_rule(scanner, included->rules[i]);
+
+ if (!result)
+ {
+ inc_name = g_scan_rule_get_name(included->rules[i], NULL);
+
+ log_variadic_message(LMT_ERROR, "Can not import from '%s': rule '%s' already exists!",
+ path, inc_name);
+
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(included));
+
+ }
+
+ return result;
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à compléter. *
+* rule = règle de détection à intégrer. *
+* *
+* Description : Intègre une nouvelle règle de détection. *
+* *
+* Retour : Bilan de l'ajout à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool _g_content_scanner_add_rule(GContentScanner *scanner, GScanRule *rule)
+{
+ bool result; /* Bilan à retourner */
+ const char *inc_name; /* Nom de la nouvelle règle */
+ fnv64_t inc_hash; /* Empreinte de ce nom */
+ size_t i; /* Boucle de parcours */
+ const char *cur_name; /* Nom d'une règle en place */
+ fnv64_t cur_hash; /* Empreinte de ce nom */
+
+ result = false;
+
+ inc_name = g_scan_rule_get_name(rule, &inc_hash);
+
+ for (i = 0; i < scanner->rule_count; i++)
+ {
+ cur_name = g_scan_rule_get_name(scanner->rules[i], &cur_hash);
+
+ if (inc_hash != cur_hash)
+ continue;
+
+ if (strcmp(inc_name, cur_name) == 0)
+ goto exit_add;
+
+ }
+
+ result = true;
+
+ scanner->rules = realloc(scanner->rules, ++scanner->rule_count * sizeof(GScanRule *));
+
+ scanner->rules[scanner->rule_count - 1] = rule;
+
+ g_object_ref(G_OBJECT(rule));
+
+ exit_add:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à compléter. *
+* rule = règle de détection à intégrer. *
+* *
+* Description : Intègre une nouvelle règle de détection. *
+* *
+* Retour : Bilan de l'ajout à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_content_scanner_add_rule(GContentScanner *scanner, GScanRule *rule)
+{
+ bool result; /* Bilan à retourner */
+ const char *inc_name; /* Nom de la nouvelle règle */
+
+ result = _g_content_scanner_add_rule(scanner, rule);
+
+ if (!result)
+ {
+ inc_name = g_scan_rule_get_name(rule, NULL);
+
+ log_variadic_message(LMT_ERROR, "Can not add rule: '%s' already exists!", inc_name);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à compléter. *
+* options = ensemble des options d'analyses à respecter. *
+* content = contenu à parcourir et analyser. *
+* *
+* Description : Lance une analyse d'un contenu binaire. *
+* *
+* Retour : Contexte de suivi pour l'analyse menée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanContext *g_content_scanner_analyze(GContentScanner *scanner, GScanOptions *options, GBinContent *content)
+{
+ GScanContext *result; /* Bilan global à retourner */
+ bool status; /* Bilan d'opération locale */
+ size_t i; /* Boucle de parcours */
+ size_t ids_count; /* Quantité de motifs prévus */
+ bool global; /* Bilan des règles globales */
+ GScanRule *rule; /* Règle à consulter */
+ const char *name; /* Désignation de la règle */
+
+ /* Préparations... */
+
+ result = g_scan_context_new(options);
+
+ if (scanner->data_backend == NULL)
+ {
+ scanner->data_backend = g_object_new(g_scan_options_get_backend_for_data(options), NULL);
+ assert(scanner->data_backend != NULL);
+
+ status = (scanner->data_backend != NULL);
+
+ for (i = 0; i < scanner->rule_count && status; i++)
+ status = g_scan_rule_setup_backend(scanner->rules[i], scanner->data_backend, result);
+
+ if (status)
+ status = g_engine_backend_warm_up(scanner->data_backend);
+
+ for (i = 0; i < scanner->rule_count && status; i++)
+ status = g_scan_rule_define_pattern_ids(scanner->rules[i], scanner->data_backend);
+
+ if (!status)
+ {
+ g_clear_object(&result);
+ goto exit;
+ }
+
+ /* Affichage éventuel de statistiques */
+
+ if (g_scan_options_get_print_stats(options))
+ g_engine_backend_output_stats(scanner->data_backend);
+
+ }
+
+ /* Phase d'analyse */
+
+ ids_count = g_engine_backend_count_plain_pattern_ids(scanner->data_backend);
+
+ g_scan_context_set_content(result, content, ids_count);
+
+ g_engine_backend_run_scan(scanner->data_backend, result);
+
+ g_scan_context_mark_scan_as_done(result);
+
+ for (i = 0; i < scanner->rule_count; i++)
+ g_scan_rule_check(scanner->rules[i], scanner->data_backend, result);
+
+ /* Etablissement d'un bilan global */
+
+ global = true;
+
+ for (i = 0; i < scanner->rule_count && global; i++)
+ {
+ rule = scanner->rules[i];
+
+ if ((g_scan_rule_get_flags(rule) & SRF_GLOBAL) == 0)
+ continue;
+
+ name = g_scan_rule_get_name(rule, NULL);
+
+ global = g_scan_context_has_match_for_rule(result, name);
+
+ }
+
+ g_scan_context_set_global_match(result, global);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à consulter. *
+* context = contexte de l'analyse à mener. *
+* full = force un affichage complet des résultats. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un gestionnaire de recherches au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_content_scanner_output_to_text(const GContentScanner *scanner, GScanContext *context, bool full, int fd)
+{
+ size_t i; /* Boucle de parcours */
+
+ /* Sous-traitance aux règles */
+
+ for (i = 0; i < scanner->rule_count; i++)
+ g_scan_rule_output_to_text(scanner->rules[i], context, full, fd);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à consulter. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit un gestionnaire de recherches en texte. *
+* *
+* Retour : Données textuelles ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_content_scanner_convert_to_text(const GContentScanner *scanner, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-scanner2text-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ g_content_scanner_output_to_text(scanner, context, true, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à consulter. *
+* context = contexte de l'analyse à mener. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche un gestionnaire de recherches au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_content_scanner_output_to_json(const GContentScanner *scanner, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd)
+{
+ size_t k; /* Boucle de parcours #1 */
+ size_t i; /* Boucle de parcours #2 */
+ size_t last_displayed; /* Dernier indice affiché */
+ bool tail; /* Saut de la virgule finale ? */
+
+ /* Introduction */
+
+ for (k = 0; k < level; k++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "[\n", 2);
+
+ /* Sous-traitance aux règles */
+
+ for (i = scanner->rule_count; i > 0; i--)
+ if ((g_scan_rule_get_flags(scanner->rules[i - 1]) & SRF_PRIVATE) == 0)
+ break;
+
+ if (i == 0)
+ goto nothing_to_display;
+ else
+ last_displayed = i - 1;
+
+ for (i = 0; i < scanner->rule_count; i++)
+ {
+ if ((g_scan_rule_get_flags(scanner->rules[i]) & SRF_PRIVATE) == SRF_PRIVATE)
+ continue;
+
+ tail = (i == last_displayed);
+
+ g_scan_rule_output_to_json(scanner->rules[i], context, padding, level + 1, fd, tail);
+
+ }
+
+ /* Conclusion */
+
+ nothing_to_display:
+
+ for (k = 0; k < level; k++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "]\n", 2);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scanner = gestionnaire de recherche à consulter. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit un gestionnaire de recherches en JSON. *
+* *
+* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_content_scanner_convert_to_json(const GContentScanner *scanner, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-scanner2json-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ padding.data = " ";
+ padding.len = 3;
+
+ g_content_scanner_output_to_json(scanner, context, &padding, 0, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/scanner.h b/src/analysis/scan/scanner.h
new file mode 100644
index 0000000..7926ba1
--- /dev/null
+++ b/src/analysis/scan/scanner.h
@@ -0,0 +1,89 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scanner.h - prototypes pour le parcours de contenus à la recherche de motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_SCANNER_H
+#define _ANALYSIS_SCAN_SCANNER_H
+
+
+#include <glib-object.h>
+
+
+#include "context.h"
+#include "expr.h"
+#include "options.h"
+#include "rule.h"
+#include "../../common/szstr.h"
+
+
+
+#define G_TYPE_CONTENT_SCANNER g_content_scanner_get_type()
+#define G_CONTENT_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_CONTENT_SCANNER, GContentScanner))
+#define G_IS_CONTENT_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_CONTENT_SCANNER))
+#define G_CONTENT_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_CONTENT_SCANNER, GContentScannerClass))
+#define G_IS_CONTENT_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_CONTENT_SCANNER))
+#define G_CONTENT_SCANNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_CONTENT_SCANNER, GContentScannerClass))
+
+
+/* Encadrement d'une recherche au sein de contenus binaires (instance) */
+typedef struct _GContentScanner GContentScanner;
+
+/* Encadrement d'une recherche au sein de contenus binaires (classe) */
+typedef struct _GContentScannerClass GContentScannerClass;
+
+
+/* Indique le type défini pour une recherche dans du binaire. */
+GType g_content_scanner_get_type(void);
+
+/* Prépare une recherche de motifs dans du contenu binaire. */
+GContentScanner *g_content_scanner_new_from_text(const char *, size_t);
+
+/* Prépare une recherche de motifs dans du contenu binaire. */
+GContentScanner *g_content_scanner_new_from_file(const char *);
+
+/* Indique le chemin d'un éventuel fichier de source. */
+const char *g_content_scanner_get_filename(const GContentScanner *);
+
+/* Inclut les définitions d'un fichier de règles externe. */
+bool g_content_scanner_include_resource(GContentScanner *, const char *);
+
+/* Intègre une nouvelle règle de détection. */
+bool g_content_scanner_add_rule(GContentScanner *, GScanRule *);
+
+/* Définit l'expression d'une correspondance recherchée. */
+GScanContext *g_content_scanner_analyze(GContentScanner *, GScanOptions *, GBinContent *);
+
+/* Affiche un gestionnaire de recherches au format texte. */
+void g_content_scanner_output_to_text(const GContentScanner *, GScanContext *, bool, int);
+
+/* Convertit un gestionnaire de recherches en texte. */
+char *g_content_scanner_convert_to_text(const GContentScanner *, GScanContext *);
+
+/* Affiche un gestionnaire de recherches au format JSON. */
+void g_content_scanner_output_to_json(const GContentScanner *, GScanContext *, const sized_string_t *, unsigned int, int);
+
+/* Convertit un gestionnaire de recherches en JSON. */
+char *g_content_scanner_convert_to_json(const GContentScanner *, GScanContext *);
+
+
+
+#endif /* _ANALYSIS_SCAN_SCANNER_H */
diff --git a/src/analysis/scan/scope-int.h b/src/analysis/scan/scope-int.h
new file mode 100644
index 0000000..2d70532
--- /dev/null
+++ b/src/analysis/scan/scope-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scope-int.h - prototypes internes pour la définition d'une portée locale de variables
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_SCOPE_INT_H
+#define _ANALYSIS_SCAN_SCOPE_INT_H
+
+
+#include "scope.h"
+
+
+
+/* Portée locale de variables et règle d'appartenance (instance) */
+struct _GScanScope
+{
+ GObject parent; /* A laisser en premier */
+
+ char *rule; /* Règle d'appartenance */
+
+};
+
+/* Portée locale de variables et règle d'appartenance (classe) */
+struct _GScanScopeClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une définition de portée pour variables. */
+bool g_scan_scope_create(GScanScope *, const char *);
+
+
+
+#endif /* _ANALYSIS_SCAN_SCOPE_INT_H */
diff --git a/src/analysis/scan/scope.c b/src/analysis/scan/scope.c
new file mode 100644
index 0000000..852b1d3
--- /dev/null
+++ b/src/analysis/scan/scope.c
@@ -0,0 +1,209 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scope.c - définition d'une portée locale de variables
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "scope.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "scope-int.h"
+
+
+
+/* Initialise la classe des définitions de portée locale. */
+static void g_scan_scope_class_init(GScanScopeClass *);
+
+/* Initialise une instance de définition de portée locale. */
+static void g_scan_scope_init(GScanScope *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_scope_dispose(GScanScope *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_scope_finalize(GScanScope *);
+
+
+
+/* Indique le type défini pour la définition de portée de variables. */
+G_DEFINE_TYPE(GScanScope, g_scan_scope, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des définitions de portée locale. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_scope_class_init(GScanScopeClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_scope_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_scope_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scope = instance à initialiser. *
+* *
+* Description : Initialise une instance de définition de portée locale. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_scope_init(GScanScope *scope)
+{
+ scope->rule = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scope = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_scope_dispose(GScanScope *scope)
+{
+ G_OBJECT_CLASS(g_scan_scope_parent_class)->dispose(G_OBJECT(scope));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scope = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_scope_finalize(GScanScope *scope)
+{
+ if (scope->rule != NULL)
+ free(scope->rule);
+
+ G_OBJECT_CLASS(g_scan_scope_parent_class)->finalize(G_OBJECT(scope));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = désignation de la règle courante dans l'analyse. *
+* *
+* Description : Prépare une définition de portée pour variables. *
+* *
+* Retour : Définition mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanScope *g_scan_scope_new(const char *rule)
+{
+ GScanScope *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_SCOPE, NULL);
+
+ if (!g_scan_scope_create(result, rule))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scope = définition de portée à à initialiser pleinement. *
+* rule = désignation de la règle courante dans l'analyse. *
+* *
+* Description : Met en place une définition de portée pour variables. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_scope_create(GScanScope *scope, const char *rule)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ scope->rule = strdup(rule);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : scope = définition de portée à consulter. *
+* *
+* Description : Fournit le nom de la règle d'appartenance. *
+* *
+* Retour : Nom de la règle courante pour une analyse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_scan_scope_get_rule_name(const GScanScope *scope)
+{
+ const char *result; /* Chemin à retourner */
+
+ result = scope->rule;
+
+ return result;
+
+}
diff --git a/src/analysis/scan/scope.h b/src/analysis/scan/scope.h
new file mode 100644
index 0000000..26b8757
--- /dev/null
+++ b/src/analysis/scan/scope.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * scope.h - prototypes pour la définition d'une portée locale de variables
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_SCOPE_H
+#define _ANALYSIS_SCAN_SCOPE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+
+#define G_TYPE_SCAN_SCOPE g_scan_scope_get_type()
+#define G_SCAN_SCOPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SCOPE, GScanScope))
+#define G_IS_SCAN_SCOPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SCOPE))
+#define G_SCAN_SCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SCOPE, GScanScopeClass))
+#define G_IS_SCAN_SCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SCOPE))
+#define G_SCAN_SCOPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SCOPE, GScanScopeClass))
+
+
+/* Portée locale de variables et règle d'appartenance (instance) */
+typedef struct _GScanScope GScanScope;
+
+/* Portée locale de variables et règle d'appartenance (classe) */
+typedef struct _GScanScopeClass GScanScopeClass;
+
+
+/* Indique le type défini pour la définition de portée de variables. */
+GType g_scan_scope_get_type(void);
+
+/* Prépare une définition de portée pour variables. */
+GScanScope *g_scan_scope_new(const char *);
+
+/* Fournit le nom de la règle d'appartenance. */
+const char *g_scan_scope_get_rule_name(const GScanScope *);
+
+
+
+#endif /* _ANALYSIS_SCAN_SCOPE_H */
diff --git a/src/analysis/scan/space-int.h b/src/analysis/scan/space-int.h
new file mode 100644
index 0000000..34c481c
--- /dev/null
+++ b/src/analysis/scan/space-int.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space-int.h - prototypes internes pour la définition d'un espace de noms pour les fonctions de scan
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_SPACE_INT_H
+#define _ANALYSIS_SCAN_SPACE_INT_H
+
+
+#include "space.h"
+
+
+#include "item-int.h"
+
+
+
+/* Espace de noms pour un groupe de fonctions (instance) */
+struct _GScanNamespace
+{
+ GScanRegisteredItem parent; /* A laisser en premier */
+
+ char *name; /* Désignation de l'espace */
+
+ GScanRegisteredItem **children; /* Sous-éléments inscrits */
+ char **names; /* Désignations correspondantes*/
+ size_t count; /* Quantité de sous-éléments */
+
+};
+
+/* Espace de noms pour un groupe de fonctions (classe) */
+struct _GScanNamespaceClass
+{
+ GScanRegisteredItemClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un nouvel espace de noms pour scan. */
+bool g_scan_namespace_create(GScanNamespace *, const char *);
+
+
+
+#endif /* _ANALYSIS_SCAN_SPACE_INT_H */
diff --git a/src/analysis/scan/space.c b/src/analysis/scan/space.c
new file mode 100644
index 0000000..38556a3
--- /dev/null
+++ b/src/analysis/scan/space.c
@@ -0,0 +1,451 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space.c - définition d'un espace de noms pour les fonctions de scan
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "space.h"
+
+
+#include <stdio.h>
+#include <string.h>
+
+
+#include "space-int.h"
+#include "../../core/logs.h"
+
+
+
+/* ------------------------- SOCLE POUR LES ESPACES DE NOMS ------------------------- */
+
+
+/* Initialise la classe des espaces de noms pour scan. */
+static void g_scan_namespace_class_init(GScanNamespaceClass *);
+
+/* Initialise une instance d'espace de noms pour scan. */
+static void g_scan_namespace_init(GScanNamespace *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_namespace_dispose(GScanNamespace *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_namespace_finalize(GScanNamespace *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_namespace_get_name(const GScanNamespace *);
+
+/* Lance une résolution d'élément à solliciter. */
+static bool g_scan_namespace_resolve(GScanNamespace *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* SOCLE POUR LES ESPACES DE NOMS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une définition d'espace de noms. */
+G_DEFINE_TYPE(GScanNamespace, g_scan_namespace, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des espaces de noms pour scan. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_namespace_class_init(GScanNamespaceClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_namespace_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_namespace_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_namespace_get_name;
+ registered->resolve = (resolve_registered_item_fc)g_scan_namespace_resolve;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance à initialiser. *
+* *
+* Description : Initialise une instance d'espace de noms pour scan. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_namespace_init(GScanNamespace *space)
+{
+ space->name = NULL;
+
+ space->children = NULL;
+ space->names = NULL;
+ space->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_namespace_dispose(GScanNamespace *space)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < space->count; i++)
+ g_clear_object(&space->children[i]);
+
+ G_OBJECT_CLASS(g_scan_namespace_parent_class)->dispose(G_OBJECT(space));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_namespace_finalize(GScanNamespace *space)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (space->name != NULL)
+ free(space->name);
+
+ if (space->children != NULL)
+ free(space->children);
+
+ for (i = 0; i < space->count; i++)
+ free(space->names[i]);
+
+ if (space->names != NULL)
+ free(space->names);
+
+ G_OBJECT_CLASS(g_scan_namespace_parent_class)->finalize(G_OBJECT(space));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : name = désignation du futur espace de noms. *
+* *
+* Description : Construit un nouvel espace de noms pour scan. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanNamespace *g_scan_namespace_new(const char *name)
+{
+ GScanNamespace *result; /* Instance à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_NAMESPACE, NULL);
+
+ if (!g_scan_namespace_create(result, name))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = instance d'espace de noms à initialiser. *
+* name = désignation du futur espace de noms. *
+* *
+* Description : Met en place un nouvel espace de noms pour scan. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_namespace_create(GScanNamespace *space, const char *name)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (name != NULL)
+ space->name = strdup(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = espace de noms à compléter. *
+* child = élément d'évaluation à intégrer. *
+* *
+* Description : Intègre un nouvel élément dans l'espace de noms. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_namespace_register_item(GScanNamespace *space, GScanRegisteredItem *child)
+{
+ bool result; /* Bilan à retourner */
+ char *name; /* Nom de l'élément à ajouter */
+ size_t i; /* Boucle de parcours */
+
+ name = g_scan_registered_item_get_name(child);
+
+ /* Validation de l'unicité du nom */
+
+ for (i = 0; i < space->count; i++)
+ if (strcmp(name, space->names[i]) == 0)
+ break;
+
+ result = (i == space->count);
+
+ /* Inscription de l'élément ? */
+
+ if (!result)
+ free(name);
+
+ else
+ {
+ space->count++;
+
+ space->children = realloc(space->children, space->count * sizeof(GScanRegisteredItem *));
+ space->children[space->count - 1] = child;
+ g_object_ref(G_OBJECT(child));
+
+ space->names = realloc(space->names, space->count * sizeof(char *));
+ space->names[space->count - 1] = name;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : space = espace de noms à compléter. *
+* count = nombre d'éléments exportés. [OUT] *
+* *
+* Description : Réalise l'inventaire d'un espace de noms. *
+* *
+* Retour : Liste d'éléments enregistrés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char **g_scan_namespace_explore(const GScanNamespace *space, size_t *count)
+{
+ char **result; /* Liste à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ GScanRegisteredItem *child; /* Elément à considérer */
+ char **sub_result; /* Sous-éléments obtenus */
+ size_t sub_count; /* Quantité de ces éléments */
+ size_t k; /* Boucle de parcours #2 */
+ int ret; /* Bilan d'une construction */
+
+ result = NULL;
+ *count = 0;
+
+ for (i = 0; i < space->count; i++)
+ {
+ child = space->children[i];
+
+ if (G_IS_SCAN_NAMESPACE(child))
+ {
+ sub_result = g_scan_namespace_explore(G_SCAN_NAMESPACE(child), &sub_count);
+
+ result = realloc(result, (*count + sub_count) * sizeof(char *));
+
+ for (k = 0; k < sub_count; k++)
+ {
+ if (space->name == NULL)
+ result[(*count)++] = sub_result[k];
+
+ else
+ {
+ ret = asprintf(&result[*count], "%s.%s", space->name, sub_result[k]);
+
+ if (ret == -1)
+ {
+ LOG_ERROR_N("asprintf");
+ result[*count] = sub_result[k];
+ }
+
+ else
+ free(sub_result[k]);
+
+ (*count)++;
+
+ }
+
+ }
+
+ if (sub_result != NULL)
+ free(sub_result);
+
+ }
+
+ else
+ {
+ result = realloc(result, (*count + 1) * sizeof(char *));
+
+ if (space->name == NULL)
+ result[(*count)++] = strdup(space->names[i]);
+
+ else
+ {
+ ret = asprintf(&result[*count], "%s.%s", space->name, space->names[i]);
+
+ if (ret == -1)
+ {
+ LOG_ERROR_N("asprintf");
+ result[*count] = strdup(space->names[i]);
+ }
+
+ (*count)++;
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : space = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_namespace_get_name(const GScanNamespace *space)
+{
+ char *result; /* Désignation à retourner */
+
+ if (space->name != NULL)
+ result = strdup(space->name);
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* target = désignation de l'objet d'appel à identifier. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT]*
+* *
+* Description : Lance une résolution d'élément à solliciter. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_namespace_resolve(GScanNamespace *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = false;
+
+ for (i = 0; i < item->count; i++)
+ if (strcmp(target, item->names[i]) == 0)
+ {
+ *out = item->children[i];
+ g_object_ref(G_OBJECT(*out));
+
+ result = true;
+ break;
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/space.h b/src/analysis/scan/space.h
new file mode 100644
index 0000000..1b998d8
--- /dev/null
+++ b/src/analysis/scan/space.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * space.h - prototypes pour la définition d'un espace de noms pour les fonctions de scan
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_SPACE_H
+#define _ANALYSIS_SCAN_SPACE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "item.h"
+
+
+
+#define G_TYPE_SCAN_NAMESPACE g_scan_namespace_get_type()
+#define G_SCAN_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_NAMESPACE, GScanNamespace))
+#define G_IS_SCAN_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_NAMESPACE))
+#define G_SCAN_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_NAMESPACE, GScanNamespaceClass))
+#define G_IS_SCAN_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_NAMESPACE))
+#define G_SCAN_NAMESPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_NAMESPACE, GScanNamespaceClass))
+
+
+/* Espace de noms pour un groupe de fonctions (instance) */
+typedef struct _GScanNamespace GScanNamespace;
+
+/* Espace de noms pour un groupe de fonctions (classe) */
+typedef struct _GScanNamespaceClass GScanNamespaceClass;
+
+
+/* Indique le type défini pour une définition d'espace de noms. */
+GType g_scan_namespace_get_type(void);
+
+/* Construit un nouvel espace de noms pour scan. */
+GScanNamespace *g_scan_namespace_new(const char *);
+
+/* Intègre un nouvel élément dans l'espace de noms. */
+bool g_scan_namespace_register_item(GScanNamespace *, GScanRegisteredItem *);
+
+/* Réalise l'inventaire d'un espace de noms. */
+char **g_scan_namespace_explore(const GScanNamespace *, size_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_SPACE_H */
diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l
new file mode 100644
index 0000000..e075cee
--- /dev/null
+++ b/src/analysis/scan/tokens.l
@@ -0,0 +1,1236 @@
+
+%top {
+
+#include "grammar.h"
+
+}
+
+
+%{
+
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+
+/* Tête de lecture pour conversions */
+typedef union _read_ptr_t
+{
+ const uint8_t *byte_pos; /* Lecture par blocs de 8 bits */
+ const uint16_t *hword_pos; /* Lecture par blocs de 16 bits*/
+
+} read_ptr_t;
+
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+# define MAKE_HWORD(ch1, ch2) ((uint16_t)(ch2 << 8 | ch1))
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+# define MAKE_HWORD(ch1, ch2) ((uint16_t)(ch1 << 8 | ch2))
+
+#else
+
+ /* __PDP_ENDIAN et Cie... */
+# error "Congratulations! Your byte order is not supported!"
+
+#endif
+
+
+
+/******************************************************************************
+* *
+* Paramètres : src = liste d'octets à traiter. *
+* len = taille de cette liste. *
+* out = série d'octets bruts obtenue. [OUT] *
+* *
+* Description : Transcrit une série d'octets en en remplaçant certains. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void rost_unescape_string(const char *src, size_t len, sized_string_t *out)
+{
+ read_ptr_t reader; /* Tête de lecture */
+ const bin_t *max; /* Fin du parcours */
+ uint16_t half; /* Moitié de mot */
+ bin_t byte; /* Octet à analyser */
+ bin_t *writer; /* Tête d'écriture */
+
+ reader.byte_pos = (const uint8_t *)src;
+ max = reader.byte_pos + len;
+
+ writer = out->bin_data;
+
+ while (reader.byte_pos < max)
+ {
+ /**
+ * La lecture par groupes de deux octets n'est pas forcément toujours
+ * logique : pour "\nabc", la dernière lecture va considérer 'c"',
+ * incluant ainsi le caractère '"' qui a été écarté pour l'appel.
+ *
+ * Le code est cependant suffisamment souple pour ignore le superflu.
+ */
+ switch (*reader.hword_pos)
+ {
+ case MAKE_HWORD('\\', 'a'):
+ reader.hword_pos++;
+ *writer++ = '\a';
+ break;
+
+ case MAKE_HWORD('\\', 'b'):
+ reader.hword_pos++;
+ *writer++ = '\b';
+ break;
+
+ case MAKE_HWORD('\\', 't'):
+ reader.hword_pos++;
+ *writer++ = '\t';
+ break;
+
+ case MAKE_HWORD('\\', 'n'):
+ reader.hword_pos++;
+ *writer++ = '\n';
+ break;
+
+ case MAKE_HWORD('\\', 'v'):
+ reader.hword_pos++;
+ *writer++ = '\v';
+ break;
+
+ case MAKE_HWORD('\\', 'f'):
+ reader.hword_pos++;
+ *writer++ = '\f';
+ break;
+
+ case MAKE_HWORD('\\', 'r'):
+ reader.hword_pos++;
+ *writer++ = '\r';
+ break;
+
+ case MAKE_HWORD('\\', 'e'):
+ reader.hword_pos++;
+ *writer++ = '\e';
+ break;
+
+ case MAKE_HWORD('\\', '"'):
+ reader.hword_pos++;
+ *writer++ = '\"';
+ break;
+
+ case MAKE_HWORD('\\', '\\'):
+ reader.hword_pos++;
+ *writer++ = '\\';
+ break;
+
+ case MAKE_HWORD('\\', 'x'):
+ reader.hword_pos++;
+
+ /**
+ * Le jeu des expressions régulières qui amène à l'appel de
+ * cette fonction limite les caractères possibles à trois
+ * ensembles : chiffres et lettres en majuscules et minuscules.
+ *
+ * La bascule des lettres en minuscules ramène les possibles
+ * à deux ensembles uniquement, simplifiant ainsi les règles
+ * de filtrage : aucun switch case n'est ainsi requis !
+ */
+
+ half = *reader.hword_pos++;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ byte = (half & 0xff);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ byte = (half >> 8);
+#endif
+
+ /* '0' ... '9' */
+ if (byte <= '9')
+ *writer = (byte - '0');
+
+ /* 'A' ... 'F' || 'a' ... 'f' */
+ else
+ {
+ byte |= 0x20;
+ *writer = 0xa + (byte - 'a');
+ }
+
+ *writer <<= 4;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ byte = (half >> 8);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ byte = (half & 0xff);
+#endif
+
+ /* '0' ... '9' */
+ if (byte <= '9')
+ *writer++ |= (byte - '0');
+
+ /* 'A' ... 'F' || 'a' ... 'f' */
+ else
+ {
+ byte |= 0x20;
+ *writer++ |= 0xa + (byte - 'a');
+ }
+
+ break;
+
+ default:
+ *writer++ = *reader.byte_pos++;
+ break;
+
+ }
+
+ }
+
+ out->len = writer - out->bin_data;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = liste d'octets à traiter. *
+* len = taille de cette liste. *
+* out = série d'octets bruts obtenue. [OUT] *
+* *
+* Description : Transcrit une série d'octets en en remplaçant certains. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void rost_unescape_regex(const char *src, size_t len, sized_string_t *out)
+{
+ read_ptr_t reader; /* Tête de lecture */
+ const bin_t *max; /* Fin du parcours */
+ uint16_t half; /* Moitié de mot */
+ bin_t byte; /* Octet à analyser */
+ bin_t *writer; /* Tête d'écriture */
+
+ reader.byte_pos = (const uint8_t *)src;
+ max = reader.byte_pos + len;
+
+ writer = out->bin_data;
+
+ while (reader.byte_pos < max)
+ {
+ /**
+ * La lecture par groupes de deux octets n'est pas forcément toujours
+ * logique : pour "\nabc", la dernière lecture va considérer 'c"',
+ * incluant ainsi le caractère '"' qui a été écarté pour l'appel.
+ *
+ * Le code est cependant suffisamment souple pour ignore le superflu.
+ */
+ switch (*reader.hword_pos)
+ {
+ case MAKE_HWORD('\\', 'a'):
+ reader.hword_pos++;
+ *writer++ = '\a';
+ break;
+
+ case MAKE_HWORD('\\', 'b'):
+ reader.hword_pos++;
+ *writer++ = '\b';
+ break;
+
+ case MAKE_HWORD('\\', 't'):
+ reader.hword_pos++;
+ *writer++ = '\t';
+ break;
+
+ case MAKE_HWORD('\\', 'n'):
+ reader.hword_pos++;
+ *writer++ = '\n';
+ break;
+
+ case MAKE_HWORD('\\', 'v'):
+ reader.hword_pos++;
+ *writer++ = '\v';
+ break;
+
+ case MAKE_HWORD('\\', 'f'):
+ reader.hword_pos++;
+ *writer++ = '\f';
+ break;
+
+ case MAKE_HWORD('\\', 'r'):
+ reader.hword_pos++;
+ *writer++ = '\r';
+ break;
+
+ case MAKE_HWORD('\\', 'e'):
+ reader.hword_pos++;
+ *writer++ = '\e';
+ break;
+
+ case MAKE_HWORD('\\', '"'):
+ reader.hword_pos++;
+ *writer++ = '\"';
+ break;
+
+ case MAKE_HWORD('\\', '\\'):
+ reader.hword_pos++;
+ *writer++ = '\\';
+ break;
+
+ case MAKE_HWORD('\\', 'x'):
+ reader.hword_pos++;
+
+ /**
+ * Le jeu des expressions régulières qui amène à l'appel de
+ * cette fonction limite les caractères possibles à trois
+ * ensembles : chiffres et lettres en majuscules et minuscules.
+ *
+ * La bascule des lettres en minuscules ramène les possibles
+ * à deux ensembles uniquement, simplifiant ainsi les règles
+ * de filtrage : aucun switch case n'est ainsi requis !
+ */
+
+ half = *reader.hword_pos++;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ byte = (half & 0xff);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ byte = (half >> 8);
+#endif
+
+ /* '0' ... '9' */
+ if (byte <= '9')
+ *writer = (byte - '0');
+
+ /* 'A' ... 'F' || 'a' ... 'f' */
+ else
+ {
+ byte |= 0x20;
+ *writer = 0xa + (byte - 'a');
+ }
+
+ *writer <<= 4;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ byte = (half >> 8);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ byte = (half & 0xff);
+#endif
+
+ /* '0' ... '9' */
+ if (byte <= '9')
+ *writer++ |= (byte - '0');
+
+ /* 'A' ... 'F' || 'a' ... 'f' */
+ else
+ {
+ byte |= 0x20;
+ *writer++ |= 0xa + (byte - 'a');
+ }
+
+ break;
+
+ case MAKE_HWORD('\\', '{'):
+ reader.hword_pos++;
+ *writer++ = '{';
+ break;
+
+ case MAKE_HWORD('\\', '}'):
+ reader.hword_pos++;
+ *writer++ = '}';
+ break;
+
+ default:
+ *writer++ = *reader.byte_pos++;
+ break;
+
+ }
+
+ }
+
+ out->len = writer - out->bin_data;
+
+}
+
+
+#define PUSH_STATE(s) yy_push_state(s, yyscanner)
+#define POP_STATE yy_pop_state(yyscanner)
+
+
+#define STOP_LEXER(msg, fbmsg) \
+ do \
+ { \
+ char *__text; \
+ int __ret; \
+ __ret = asprintf(&__text, "%s: '%s'", msg, yytext); \
+ if (__ret == -1) \
+ YY_FATAL_ERROR(fbmsg); \
+ else \
+ { \
+ YY_FATAL_ERROR(__text); \
+ free(__text); \
+ } \
+ } \
+ while (0)
+
+#define HANDLE_UNCOMPLETED_TOKEN \
+ STOP_LEXER("Uncompleted token in rule definition", "Undisclosed uncompleted token in rule definition")
+
+
+%}
+
+
+%option bison-bridge reentrant
+%option stack
+%option nounput
+%option noinput
+%option noyywrap
+%option noyy_top_state
+%option yylineno
+%option never-interactive
+
+%x inc_path
+
+%x rule_intro
+%x raw_block
+
+%x meta
+%x meta_value
+
+%x bytes
+%x bytes_value
+%x bytes_value_raw
+
+%x bytes_hex
+%x bytes_hex_range
+
+%x bytes_regex
+%x bytes_regex_quantifier
+%x bytes_regex_range
+
+%x condition
+
+%x wait_for_colon
+
+
+%x comment
+
+
+str_not_escaped [^\"\\]
+str_escaped \\a|\\b|\\t|\\n|\\v|\\f|\\r|\\e|\\\"|\\\\|\\x{hbyte}
+str_mixed ({str_not_escaped}|{str_escaped})
+
+hbyte [0-9a-fA-F]{2}
+mbyte (\?[0-9a-fA-F]|[0-9a-fA-F]\?)
+
+reg_allowed [^^$.|/{}()\[\]*+?\\]
+reg_allowed_escaped \\^|\\$|\\\.|\\\||\\\/|\\\{|\\\}|\\\(|\\\)|\\\[|\\\]|\\\*|\\\+|\\\?|\\\\
+reg_escaped \\a|\\t|\\n|\\v|\\f|\\r
+reg_byte \\x[0-9a-fA-F]{2}
+
+regular_chars {reg_allowed}|{reg_allowed_escaped}|{reg_escaped}|{reg_byte}
+
+reg_classes \\w|\\W|\\s|\\S|\\d|\\D|\\b|\\B
+
+
+bytes_id [A-Za-z_][A-Za-z0-9_]*
+bytes_fuzzy_id [\*A-Za-z_][\*A-Za-z0-9_]*
+
+
+%%
+
+
+"include" { PUSH_STATE(inc_path); return INCLUDE; }
+
+<inc_path>\"{str_not_escaped}+\" {
+ POP_STATE;
+
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+
+ return PLAIN_TEXT;
+ }
+
+<inc_path>\"{str_mixed}+\" {
+ POP_STATE;
+
+ rost_unescape_string(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+
+ return ESCAPED_TEXT;
+ }
+
+
+%{ /* Définition locale d'une règle */ %}
+
+ "global" { return GLOBAL; }
+ "private" { return PRIVATE; }
+
+ "rule" {
+ PUSH_STATE(rule_intro);
+ return RAW_RULE;
+ }
+
+ <rule_intro>{bytes_id} {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return RULE_IDENTIFIER;
+ }
+
+ <rule_intro>":" { return COLON; }
+
+ <rule_intro>[ \t]* { }
+
+ <rule_intro>"{" {
+ POP_STATE;
+ PUSH_STATE(raw_block);
+ return BRACE_IN;
+ }
+
+ <raw_block>"meta" {
+ POP_STATE;
+ PUSH_STATE(meta);
+ PUSH_STATE(wait_for_colon);
+ return META;
+ }
+
+ <raw_block,meta>"bytes" {
+ POP_STATE;
+ PUSH_STATE(bytes);
+ PUSH_STATE(wait_for_colon);
+ return BYTES;
+ }
+
+ <raw_block,meta,bytes>"condition" {
+ POP_STATE;
+ PUSH_STATE(condition);
+ PUSH_STATE(wait_for_colon);
+ return CONDITION;
+ }
+
+ <wait_for_colon>":" {
+ POP_STATE;
+ return COLON;
+ }
+
+<raw_block,meta,bytes,condition>"}" {
+ POP_STATE;
+ return BRACE_OUT;
+ }
+
+
+%{ /* Définitions communes pour la section "meta:" */ %}
+
+ <meta>{bytes_id} {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return INFO_KEY;
+ }
+
+ <meta>"=" { PUSH_STATE(meta_value); return ASSIGN; }
+
+ <meta_value>"true" { POP_STATE; return TRUE_; }
+ <meta_value>"false" { POP_STATE; return FALSE_; }
+
+ <meta_value>-(0|[1-9][0-9]*) {
+ POP_STATE;
+ yylval->signed_integer = strtoll(yytext, NULL, 10);
+ return SIGNED_INTEGER;
+ }
+
+ <meta_value>-0x[0-9a-f]+ {
+ POP_STATE;
+ yylval->signed_integer = strtoll(yytext, NULL, 16);
+ return SIGNED_INTEGER;
+ }
+
+ <meta_value>(0|[1-9][0-9]*) {
+ POP_STATE;
+ yylval->unsigned_integer = strtoull(yytext, NULL, 10);
+ return UNSIGNED_INTEGER;
+ }
+
+ <meta_value>0x[0-9a-f]+ {
+ POP_STATE;
+ yylval->unsigned_integer = strtoull(yytext, NULL, 16);
+ return UNSIGNED_INTEGER;
+ }
+
+ <meta_value>\"{str_not_escaped}*\" {
+ POP_STATE;
+
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+
+ return PLAIN_TEXT;
+ }
+
+ <meta_value>\"{str_mixed}*\" {
+ POP_STATE;
+
+ rost_unescape_string(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+
+ return ESCAPED_TEXT;
+ }
+
+
+%{ /* A déplacer... */ %}
+
+
+<condition>"true" { return TRUE_; }
+<condition>"false" { return FALSE_; }
+
+<condition>-(0|[1-9][0-9]*) { yylval->signed_integer = strtoll(yytext, NULL, 10); return SIGNED_INTEGER; }
+<condition>-0x[0-9a-f]+ { yylval->signed_integer = strtoll(yytext, NULL, 16); return SIGNED_INTEGER; }
+
+<bytes_hex_range,bytes_regex_quantifier,condition>(0|[1-9][0-9]*) { yylval->unsigned_integer = strtoull(yytext, NULL, 10); return UNSIGNED_INTEGER; }
+<bytes_hex_range,bytes_regex_quantifier,condition>0x[0-9a-f]+ { yylval->unsigned_integer = strtoull(yytext, NULL, 16); return UNSIGNED_INTEGER; }
+
+<condition>[kK][bB] { return KB; }
+<condition>[mM][bB] { return MB; }
+<condition>[gG][bB] { return GB; }
+
+<condition>\"{str_not_escaped}*\" {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+
+ return PLAIN_TEXT;
+ }
+
+<condition>\"{str_mixed}*\" {
+ rost_unescape_string(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+
+ return ESCAPED_TEXT;
+ }
+
+
+%{ /* Définitions communes pour la section "bytes:" */ %}
+
+ <bytes>"fullword" { return FULLWORD; }
+ <bytes>"nocase" { return NOCASE; }
+ <bytes>"private" { return PRIVATE; }
+
+ <bytes>"=" { PUSH_STATE(bytes_value); return ASSIGN; }
+
+
+%{ /* Définition de motif en texte brut */ %}
+
+<bytes_value>\"{str_not_escaped}+\" {
+ POP_STATE;
+
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+
+ return PLAIN_TEXT;
+ }
+
+<bytes_value>\"{str_mixed}+\" {
+ POP_STATE;
+
+ rost_unescape_string(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+
+ return ESCAPED_TEXT;
+ }
+
+
+
+<bytes>[A-Za-z_][A-Za-z0-9_]* {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return NAME;
+ }
+
+
+ <bytes>"((" { return MOD_GROUP_O; }
+
+ <bytes>"))" { return MOD_GROUP_C; }
+
+ <bytes>"(" { return PAREN_O; }
+
+ <bytes>")" { return PAREN_C; }
+
+ <bytes>"," { return COMMA; }
+
+
+<bytes>\"{str_not_escaped}+\" {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+
+ return PLAIN_TEXT;
+ }
+
+
+
+
+
+%{ /* Définition de motif en hexadécimal */ %}
+
+ <bytes_value>"{" {
+ POP_STATE;
+ PUSH_STATE(bytes_hex);
+ }
+
+ <bytes_hex>"}" { POP_STATE; }
+
+ <bytes_hex>"[" {
+ PUSH_STATE(bytes_hex_range);
+ return HOOK_O;
+ }
+
+ <bytes_hex_range>"-" { return MINUS; }
+
+ <bytes_hex_range>"]" {
+ POP_STATE;
+ return HOOK_C;
+ }
+
+ <bytes_hex>"(" { return PAREN_O; }
+
+ <bytes_hex>")" { return PAREN_C; }
+
+ <bytes_hex>"|" { return PIPE; }
+
+ <bytes_hex>"~" { return TILDE; }
+
+ <bytes_hex>{hbyte}([ ]*{hbyte})*[ ]* {
+ bool even;
+ size_t i;
+ bin_t byte;
+ bin_t value;
+
+ tmp_0->len = 0;
+
+ even = true;
+
+ for (i = 0; i < yyleng; i++)
+ {
+ byte = yytext[i];
+
+ switch (byte)
+ {
+ case ' ':
+ continue;
+ break;
+
+ case '0' ... '9':
+ value = (byte - '0');
+ break;
+
+ case 'A' ... 'F':
+ value = 0xa + (byte - 'A');
+ break;
+
+ case 'a' ... 'f':
+ value = 0xa + (byte - 'a');
+ break;
+
+ }
+
+ if (even)
+ tmp_0->data[tmp_0->len] = (value << 4);
+ else
+ tmp_0->data[tmp_0->len++] |= value;
+
+ even = !even;
+
+ }
+
+ assert(even);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+ return HEX_BYTES;
+
+ }
+
+ <bytes_hex>[\?]{2}([ ]*[\?]{2})*[ ]* {
+ unsigned long long counter;
+ size_t i;
+
+ counter = 0;
+
+ for (i = 0; i < yyleng; i++)
+ if (yytext[i] == '?')
+ counter++;
+
+ assert(counter % 2 == 0);
+
+ yylval->unsigned_integer = counter / 2;
+ return FULL_MASK;
+
+ }
+
+ <bytes_hex>{mbyte}([ ]*{mbyte})*[ ]* {
+ bool even;
+ size_t i;
+ bin_t byte;
+ bin_t value;
+
+ tmp_0->len = 0;
+ tmp_1->len = 0;
+
+ even = true;
+
+ for (i = 0; i < yyleng; i++)
+ {
+ byte = yytext[i];
+
+ switch (byte)
+ {
+ case ' ':
+ continue;
+ break;
+
+ case '?':
+ even = !even;
+ continue;
+ break;
+
+ case '0' ... '9':
+ value = (byte - '0');
+ break;
+
+ case 'A' ... 'F':
+ value = 0xa + (byte - 'A');
+ break;
+
+ case 'a' ... 'f':
+ value = 0xa + (byte - 'a');
+ break;
+
+ }
+
+ if (even)
+ {
+ tmp_0->data[tmp_0->len++] = (value << 4);
+ tmp_1->data[tmp_1->len++] = 0xf0;
+ }
+ else
+ {
+ tmp_0->data[tmp_0->len++] = value;
+ tmp_1->data[tmp_1->len++] = 0x0f;
+ }
+
+ even = !even;
+
+ }
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+ tmp_1->data[tmp_1->len] = '\0';
+#endif
+
+ yylval->masked.tmp_values = tmp_0;
+ yylval->masked.tmp_masks = tmp_1;
+ return SEMI_MASK;
+
+ }
+
+
+%{ /* Définition d'expressions régulières */ %}
+
+ <bytes_value>"/" {
+ POP_STATE;
+ printf(" -- regex\n");
+ PUSH_STATE(bytes_regex);
+ }
+
+ <bytes_regex>"/" { printf("exit regex\n"); POP_STATE; }
+
+ <bytes_regex>"." { return DOT; }
+
+ <bytes_regex>({regular_chars})+ {
+ rost_unescape_regex(yytext, yyleng, tmp_0);
+
+ printf(" regular: '%s'\n", yytext);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+ return REGEX_BYTES;
+
+ }
+
+ <bytes_regex>({reg_classes})+ {
+
+ return REGEX_CLASSES;
+
+ }
+
+%{ /* <bytes_regex>\[({regular_chars}|({regular_chars})-z|{reg_classes})+\] { */ %}
+
+
+ <bytes_regex>"[" {
+ PUSH_STATE(bytes_regex_range);
+ printf(" !! entering range\n");
+ return HOOK_O;
+ }
+
+ <bytes_regex_range>"]" {
+ POP_STATE;
+ printf(" !! exiting range\n");
+ return HOOK_C;
+ }
+
+
+
+
+<bytes_regex_range>({regular_chars}|({regular_chars}-{regular_chars})|{reg_classes})+ {
+
+ printf("range: '%s'\n", yytext);
+ return REGEX_RANGE;
+
+ }
+
+ <bytes_regex>"(" { return PAREN_O; }
+
+ <bytes_regex>")" { return PAREN_C; }
+
+ <bytes_regex>"|" { return PIPE; }
+
+ <bytes_regex>"*" { return MUL; }
+ <bytes_regex>"+" { return PLUS; }
+ <bytes_regex>"?" { return QUESTION; }
+
+ <bytes_regex>"{" {
+ PUSH_STATE(bytes_regex_quantifier);
+ return BRACE_IN;
+ }
+
+ <bytes_regex_quantifier>"," { return COMMA; }
+
+ <bytes_regex_quantifier>"}" {
+ POP_STATE;
+ return BRACE_OUT;
+ }
+
+
+%{ /* Condition de correspondance */ %}
+
+<condition>"and" { return AND; }
+<condition>"or" { return OR; }
+<condition>"not" { return NOT; }
+
+<condition>"<" { return LT; }
+<condition>"<=" { return LE; }
+<condition>"==" { return EQ; }
+<condition>"!=" { return NE; }
+<condition>">" { return GT; }
+<condition>">=" { return GE; }
+
+<condition>"contains" { return CONTAINS; }
+<condition>"startswith" { return STARTSWITH; }
+<condition>"endswith" { return ENDSWITH; }
+<condition>"matches" { return MATCHES; }
+<condition>"icontains" { return ICONTAINS; }
+<condition>"istartswith" { return ISTARTSWITH; }
+<condition>"iendswith" { return IENDSWITH; }
+<condition>"iequals" { return IEQUALS; }
+
+<condition>"+" { return PLUS; }
+<condition>"-" { return MINUS; }
+<condition>"*" { return MUL; }
+<condition>"/" { return DIV; }
+<condition>"%" { return MOD; }
+
+<condition>"(" { return PAREN_O; }
+<condition>")" { return PAREN_C; }
+<condition>"," { return COMMA; }
+
+
+<condition>"[" { return HOOK_O; }
+<condition>"]" { return HOOK_C; }
+
+
+<condition>"." { return DOT; }
+<bytes>"|" { return PIPE; }
+
+<condition>"none" { return NONE; }
+<condition>"any" { return ANY; }
+<condition>"all" { return ALL; }
+<condition>"of" { return OF; }
+<condition>"them" { return THEM; }
+<condition>"in" { return IN; }
+
+
+ <bytes,condition>${bytes_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_ID;
+ }
+
+ <condition>${bytes_fuzzy_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_FUZZY_ID;
+ }
+
+ <condition>#{bytes_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_ID_COUNTER;
+ }
+
+ <condition>#{bytes_fuzzy_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_FUZZY_ID_COUNTER;
+ }
+
+ <condition>@{bytes_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_ID_START;
+ }
+
+ <condition>@{bytes_fuzzy_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_FUZZY_ID_START;
+ }
+
+ <condition>!{bytes_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_ID_LENGTH;
+ }
+
+ <condition>!{bytes_fuzzy_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_FUZZY_ID_LENGTH;
+ }
+
+ <condition>~{bytes_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_ID_END;
+ }
+
+ <condition>~{bytes_fuzzy_id} {
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 1;
+ return BYTES_FUZZY_ID_END;
+ }
+
+
+
+
+
+
+<condition>[A-Za-z_][A-Za-z0-9_]* {
+ yylval->sized_cstring.data = yytext;
+ yylval->sized_cstring.len = yyleng;
+ return NAME;
+ }
+
+
+
+
+
+
+
+%{ /* Commentaires */ %}
+
+<*>"/*" { PUSH_STATE(comment); }
+<comment>"*/" { POP_STATE; }
+<comment>(.|\n) { }
+
+<*>"//"[^\n]* { }
+
+
+%{ /* Suppression du besoin de sauvegardes pour retours en arrière */ %}
+
+"i" { HANDLE_UNCOMPLETED_TOKEN; }
+"in" { HANDLE_UNCOMPLETED_TOKEN; }
+"inc" { HANDLE_UNCOMPLETED_TOKEN; }
+"incl" { HANDLE_UNCOMPLETED_TOKEN; }
+"inclu" { HANDLE_UNCOMPLETED_TOKEN; }
+"includ" { HANDLE_UNCOMPLETED_TOKEN; }
+
+<inc_path>\" { HANDLE_UNCOMPLETED_TOKEN; }
+<inc_path>\"{str_not_escaped}+ { HANDLE_UNCOMPLETED_TOKEN; }
+
+<inc_path>\"\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<inc_path>\"\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<inc_path>\"\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+<inc_path>\"{str_mixed}+ { HANDLE_UNCOMPLETED_TOKEN; }
+<inc_path>\"{str_mixed}+\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<inc_path>\"{str_mixed}+\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<inc_path>\"{str_mixed}+\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+"g" { HANDLE_UNCOMPLETED_TOKEN; }
+"gl" { HANDLE_UNCOMPLETED_TOKEN; }
+"glo" { HANDLE_UNCOMPLETED_TOKEN; }
+"glob" { HANDLE_UNCOMPLETED_TOKEN; }
+"globa" { HANDLE_UNCOMPLETED_TOKEN; }
+
+"p" { HANDLE_UNCOMPLETED_TOKEN; }
+"pr" { HANDLE_UNCOMPLETED_TOKEN; }
+"pri" { HANDLE_UNCOMPLETED_TOKEN; }
+"priv" { HANDLE_UNCOMPLETED_TOKEN; }
+"priva" { HANDLE_UNCOMPLETED_TOKEN; }
+"privat" { HANDLE_UNCOMPLETED_TOKEN; }
+
+"r" { HANDLE_UNCOMPLETED_TOKEN; }
+"ru" { HANDLE_UNCOMPLETED_TOKEN; }
+"rul" { HANDLE_UNCOMPLETED_TOKEN; }
+
+<raw_block>"m" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block>"me" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block>"met" { HANDLE_UNCOMPLETED_TOKEN; }
+
+<raw_block,meta>"b" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta>"by" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta>"byt" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta>"byte" { HANDLE_UNCOMPLETED_TOKEN; }
+
+<raw_block,meta,bytes>"c" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta,bytes>"co" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta,bytes>"con" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta,bytes>"cond" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta,bytes>"condi" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta,bytes>"condit" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta,bytes>"conditi" { HANDLE_UNCOMPLETED_TOKEN; }
+<raw_block,meta,bytes>"conditio" { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<meta_value>"t" { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>"tr" { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>"tru" { HANDLE_UNCOMPLETED_TOKEN; }
+
+<meta_value>"f" { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>"fa" { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>"fal" { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>"fals" { HANDLE_UNCOMPLETED_TOKEN; }
+
+<meta_value>-0x { HANDLE_UNCOMPLETED_TOKEN; }
+
+<meta_value>0x { HANDLE_UNCOMPLETED_TOKEN; }
+
+<meta_value>\"{str_mixed}* { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>\"{str_mixed}*\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>\"{str_mixed}*\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<meta_value>\"{str_mixed}*\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<condition>-0x { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes_hex_range,bytes_regex_quantifier,condition>0x { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<condition>\"{str_not_escaped}* { HANDLE_UNCOMPLETED_TOKEN; }
+
+<condition>\" { HANDLE_UNCOMPLETED_TOKEN; }
+<condition>\"\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<condition>\"\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<condition>\"\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+<condition>\"{str_mixed}+ { HANDLE_UNCOMPLETED_TOKEN; }
+<condition>\"{str_mixed}+\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<condition>\"{str_mixed}+\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<condition>\"{str_mixed}+\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes_value>\" { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_value>\"\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_value>\"\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_value>\"\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_value>\"{str_mixed}+ { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_value>\"{str_mixed}+\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_value>\"{str_mixed}+\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_value>\"{str_mixed}+\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes>\"{str_not_escaped}+ { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes_hex>{hbyte}([ ]*{hbyte})*[ ]*[0-9a-fA-F]/[^?] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes_hex>[\?]{2}([ ]*[\?]{2})*[ ]*[\?]/[^0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes_hex>{mbyte}([ ]*{mbyte})*[ ]*\?/[^?] { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_hex>{mbyte}([ ]*{mbyte})*[ ]*[0-9a-fA-F]/[^0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes_regex>\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex>\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex>\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex>({regular_chars})+\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex>({regular_chars})+\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex>({regular_chars})+\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+<bytes_regex>({reg_classes})+\\
+
+
+<bytes_regex_range>({regular_chars}|({regular_chars}-{regular_chars})|{reg_classes})+\\ { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex_range>({regular_chars}|({regular_chars}-{regular_chars})|{reg_classes})+\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex_range>({regular_chars}|({regular_chars}-{regular_chars})|{reg_classes})+\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex_range>\\x { HANDLE_UNCOMPLETED_TOKEN; }
+<bytes_regex_range>\\x[0-9a-fA-F] { HANDLE_UNCOMPLETED_TOKEN; }
+
+
+%{ /* Actions par défaut */ %}
+
+<*>[ \t]+ { }
+
+<*>[\n] { static int ln = 1; if (0) printf("----------- %%< -------------- %%< ---- %d\n", ln++); }
+
+<*>. {
+ char *msg;
+ int ret;
+ ret = asprintf(&msg, "Unhandled token in rule definition: '%s'", yytext);
+ if (ret == -1)
+ YY_FATAL_ERROR("Unhandled token in undisclosed rule definition");
+ else
+ {
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+ }
+
+
+%%
diff --git a/src/analysis/storage/Makefile.am b/src/analysis/storage/Makefile.am
index aee0faf..3eb287b 100644
--- a/src/analysis/storage/Makefile.am
+++ b/src/analysis/storage/Makefile.am
@@ -13,18 +13,9 @@ libanalysisstorage_la_SOURCES = \
storage.h storage.c \
tpmem.h tpmem.c
-libanalysisstorage_la_LIBADD =
-
-libanalysisstorage_la_LDFLAGS = $(LIBSSL_LIBS)
+libanalysisstorage_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisstorage_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS) $(LIBSSL_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/analysis/type.c b/src/analysis/type.c
index f05b9a8..9ed5f3f 100644
--- a/src/analysis/type.c
+++ b/src/analysis/type.c
@@ -43,7 +43,7 @@ static void g_data_type_class_init(GDataTypeClass *);
static void g_data_type_init(GDataType *);
/* Procède à l'initialisation de l'interface de sérialisation. */
-static void g_serializable_object_interface_init(GSerializableObjectIface *);
+static void g_data_type_serializable_interface_init(GSerializableObjectIface *);
/* Supprime toutes les références externes. */
static void g_data_type_dispose(GDataType *);
@@ -67,7 +67,7 @@ static bool g_data_type_store(const GDataType *, GObjectStorage *, packed_buffer
/* Indique le type défini pour un type quelconque. */
G_DEFINE_TYPE_WITH_CODE(GDataType, g_data_type, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_serializable_object_interface_init));
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_data_type_serializable_interface_init));
/******************************************************************************
@@ -136,7 +136,7 @@ static void g_data_type_init(GDataType *type)
* *
******************************************************************************/
-static void g_serializable_object_interface_init(GSerializableObjectIface *iface)
+static void g_data_type_serializable_interface_init(GSerializableObjectIface *iface)
{
iface->load = (load_serializable_object_cb)g_data_type_load;
iface->store = (store_serializable_object_cb)g_data_type_store;
diff --git a/src/analysis/types/Makefile.am b/src/analysis/types/Makefile.am
index e3cbda0..bc6ff14 100644
--- a/src/analysis/types/Makefile.am
+++ b/src/analysis/types/Makefile.am
@@ -12,18 +12,9 @@ libanalysistypes_la_SOURCES = \
proto.h proto.c \
template.h template.c
-libanalysistypes_la_LIBADD =
-
-libanalysistypes_la_LDFLAGS =
+libanalysistypes_la_CFLAGS = $(TOOLKIT_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysistypes_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am
index 8a2eea3..bdfceb7 100644
--- a/src/arch/Makefile.am
+++ b/src/arch/Makefile.am
@@ -1,29 +1,29 @@
noinst_LTLIBRARIES = libarch.la
-libarch_la_SOURCES = \
- archbase.h archbase.c \
- context-int.h \
- context.h context.c \
- instriter.h instriter.c \
- instruction-int.h \
- instruction.h instruction.c \
- link.h link.c \
- operand-int.h operand-int.c \
- operand.h operand.c \
- post.h post.c \
- processor-int.h \
- processor.h processor.c \
- register-int.h \
- register.h register.c \
- storage.h storage.c \
+libarch_la_SOURCES = \
+ archbase.h archbase.c \
+ context-int.h \
+ context.h context.c \
+ instriter.h instriter.c \
+ instruction-int.h \
+ instruction.h instruction.c \
+ link.h link.c \
+ operand-int.h operand-int.c \
+ operand.h operand.c \
+ post.h post.c \
+ processor-int.h \
+ processor.h processor.c \
+ register-int.h \
+ register.h register.c \
+ storage.h storage.c \
vmpa.h vmpa.c
-libarch_la_LIBADD = \
- instructions/libarchinstructions.la \
- operands/libarchoperands.la
+libarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
-libarch_la_LDFLAGS =
+libarch_la_LIBADD = \
+ instructions/libarchinstructions.la \
+ operands/libarchoperands.la
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -31,9 +31,4 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libarch_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
SUBDIRS = instructions operands
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index 4de16d6..cd1e9c7 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -35,11 +35,11 @@
#include "instruction-int.h"
#include "storage.h"
#include "../analysis/storage/serialize-int.h"
+#include "../core/columns.h"
#include "../core/logs.h"
#include "../core/processors.h"
#include "../glibext/gbinarycursor.h"
#include "../glibext/linegen-int.h"
-#include "../gtkext/gtkblockdisplay.h"
@@ -81,12 +81,16 @@ bool g_arch_instruction_store_destinations(GArchInstruction *, GObjectStorage *,
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_arch_instruction_count_lines(const GArchInstruction *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_arch_instruction_compute_cursor(const GArchInstruction *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_arch_instruction_contain_cursor(const GArchInstruction *, size_t, size_t, const GLineCursor *);
+#endif
+
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *, size_t, size_t);
@@ -195,8 +199,10 @@ static void g_arch_instruction_init(GArchInstruction *instr)
static void g_arch_instruction_generator_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_arch_instruction_count_lines;
+#ifdef INCLUDE_GTK_SUPPORT
iface->compute = (linegen_compute_fc)g_arch_instruction_compute_cursor;
iface->contain = (linegen_contain_fc)g_arch_instruction_contain_cursor;
+#endif
iface->get_flags = (linegen_get_flags_fc)g_arch_instruction_get_flags2;
iface->print = (linegen_print_fc)g_arch_instruction_print;
@@ -1835,6 +1841,9 @@ static size_t g_arch_instruction_count_lines(const GArchInstruction *instr)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : instr = générateur à consulter. *
@@ -1891,6 +1900,9 @@ static int g_arch_instruction_contain_cursor(const GArchInstruction *instr, size
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : instr = générateur à consulter. *
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index 26eadc9..3c9c149 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -38,12 +38,12 @@
-#define G_TYPE_ARCH_INSTRUCTION g_arch_instruction_get_type()
-#define G_ARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_instruction_get_type(), GArchInstruction))
-#define G_IS_ARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_instruction_get_type()))
-#define G_ARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass))
-#define G_IS_ARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_INSTRUCTION))
-#define G_ARCH_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass))
+#define G_TYPE_ARCH_INSTRUCTION g_arch_instruction_get_type()
+#define G_ARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_instruction_get_type(), GArchInstruction))
+#define G_IS_ARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_instruction_get_type()))
+#define G_ARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass))
+#define G_IS_ARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_INSTRUCTION))
+#define G_ARCH_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass))
/* Définition générique d'une instruction d'architecture (instance) */
diff --git a/src/arch/instructions/Makefile.am b/src/arch/instructions/Makefile.am
index 24d3eb5..28cf90f 100644
--- a/src/arch/instructions/Makefile.am
+++ b/src/arch/instructions/Makefile.am
@@ -1,24 +1,14 @@
noinst_LTLIBRARIES = libarchinstructions.la
-libarchinstructions_la_SOURCES = \
- raw.h raw.c \
- undefined-int.h \
+libarchinstructions_la_SOURCES = \
+ raw.h raw.c \
+ undefined-int.h \
undefined.h undefined.c
-libarchinstructions_la_LIBADD =
-
-libarchinstructions_la_LDFLAGS =
+libarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libarchinstructions_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
-SUBDIRS =
diff --git a/src/arch/instructions/raw.c b/src/arch/instructions/raw.c
index 6340e46..26282fa 100644
--- a/src/arch/instructions/raw.c
+++ b/src/arch/instructions/raw.c
@@ -35,7 +35,7 @@
#include "../instruction-int.h"
#include "../operands/immediate.h"
#include "../operands/target.h"
-#include "../../gtkext/gtkblockdisplay.h"
+#include "../../core/columns.h"
diff --git a/src/arch/instructions/undefined.c b/src/arch/instructions/undefined.c
index 7ed5db9..15c63e7 100644
--- a/src/arch/instructions/undefined.c
+++ b/src/arch/instructions/undefined.c
@@ -31,7 +31,7 @@
#include "undefined-int.h"
-#include "../../gtkext/gtkblockdisplay.h"
+#include "../../core/columns.h"
diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h
index e78c2b0..e6c1232 100644
--- a/src/arch/operand-int.h
+++ b/src/arch/operand-int.h
@@ -48,9 +48,13 @@ typedef GArchOperand * (* get_inner_operand_fc) (const GArchOperand *, const cha
/* Traduit un opérande en version humainement lisible. */
typedef void (* operand_print_fc) (const GArchOperand *, GBufferLine *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Construit un petit résumé concis de l'opérande. */
typedef char * (* operand_build_tooltip_fc) (const GArchOperand *, const GLoadedBinary *);
+#endif
+
/* Fournit une liste de candidats embarqués par un candidat. */
typedef GArchOperand ** (* operand_list_inners_fc) (const GArchOperand *, size_t *);
@@ -113,7 +117,9 @@ struct _GArchOperandClass
get_inner_operand_fc get_inner; /* Récupération d'un opérande */
operand_print_fc print; /* Texte humain équivalent */
+#ifdef INCLUDE_GTK_SUPPORT
operand_build_tooltip_fc build_tooltip; /* Construction de description */
+#endif
operand_list_inners_fc list_inner; /* Récupération d'internes */
operand_update_inners_fc update_inner; /* Mise à jour des éléments */
diff --git a/src/arch/operand.c b/src/arch/operand.c
index f262373..0f5ffd5 100644
--- a/src/arch/operand.c
+++ b/src/arch/operand.c
@@ -408,6 +408,9 @@ void g_arch_operand_print(const GArchOperand *operand, GBufferLine *line)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : operand = opérande à consulter. *
@@ -438,6 +441,9 @@ char *g_arch_operand_build_tooltip(const GArchOperand *operand, const GLoadedBin
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : operand = opérande à venir modifier. *
diff --git a/src/arch/operand.h b/src/arch/operand.h
index a93e898..234ee64 100644
--- a/src/arch/operand.h
+++ b/src/arch/operand.h
@@ -88,9 +88,13 @@ GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *, c
/* Traduit un opérande en version humainement lisible. */
void g_arch_operand_print(const GArchOperand *, GBufferLine *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Construit un petit résumé concis de l'opérande. */
char *g_arch_operand_build_tooltip(const GArchOperand *, const GLoadedBinary *);
+#endif
+
/* Ajoute une information complémentaire à un opérande. */
bool g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag);
diff --git a/src/arch/operands/Makefile.am b/src/arch/operands/Makefile.am
index 4371457..f2a8767 100644
--- a/src/arch/operands/Makefile.am
+++ b/src/arch/operands/Makefile.am
@@ -18,19 +18,9 @@ libarchoperands_la_SOURCES = \
targetable-int.h \
targetable.h targetable.c
-libarchoperands_la_LIBADD =
-
-libarchoperands_la_LDFLAGS =
+libarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libarchoperands_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-
-SUBDIRS =
diff --git a/src/arch/operands/immediate.c b/src/arch/operands/immediate.c
index 0df8bbb..f40c645 100644
--- a/src/arch/operands/immediate.c
+++ b/src/arch/operands/immediate.c
@@ -43,7 +43,7 @@
#include "../../common/asm.h"
#include "../../common/extstr.h"
#include "../../common/sort.h"
-#include "../../gtkext/gtkblockdisplay.h"
+#include "../../core/columns.h"
@@ -82,9 +82,13 @@ static void g_imm_operand_print(const GImmOperand *, GBufferLine *);
/* Compare un opérande avec un autre. */
static int g_imm_operand_compare(const GImmOperand *, const GImmOperand *, bool);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Construit un petit résumé concis de l'opérande. */
static char *g_imm_operand_build_tooltip(const GImmOperand *, const GLoadedBinary *);
+#endif
+
/* Fournit l'empreinte d'un candidat à une centralisation. */
static guint g_imm_operand_hash(const GImmOperand *, bool);
@@ -148,7 +152,9 @@ static void g_imm_operand_class_init(GImmOperandClass *klass)
operand->compare = (operand_compare_fc)g_imm_operand_compare;
operand->print = (operand_print_fc)g_imm_operand_print;
+#ifdef INCLUDE_GTK_SUPPORT
operand->build_tooltip = (operand_build_tooltip_fc)g_imm_operand_build_tooltip;
+#endif
operand->hash = (operand_hash_fc)g_imm_operand_hash;
@@ -1226,6 +1232,9 @@ static int g_imm_operand_compare(const GImmOperand *a, const GImmOperand *b, boo
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : operand = opérande à consulter. *
@@ -1314,6 +1323,9 @@ static char *g_imm_operand_build_tooltip(const GImmOperand *operand, const GLoad
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : operand = objet dont l'instance se veut unique. *
diff --git a/src/arch/operands/known.c b/src/arch/operands/known.c
index 152bdac..5402879 100644
--- a/src/arch/operands/known.c
+++ b/src/arch/operands/known.c
@@ -32,8 +32,8 @@
#include "immediate-int.h"
#include "rename-int.h"
#include "../../analysis/db/misc/rlestr.h"
+#include "../../core/columns.h"
#include "../../core/logs.h"
-#include "../../gtkext/gtkblockdisplay.h"
diff --git a/src/arch/operands/target.c b/src/arch/operands/target.c
index 068d060..61f683a 100644
--- a/src/arch/operands/target.c
+++ b/src/arch/operands/target.c
@@ -41,7 +41,7 @@
#include "../../format/format.h"
#include "../../format/strsym.h"
#include "../../glibext/gbinarycursor.h"
-#include "../../gtkext/gtkblockdisplay.h"
+#include "../../core/columns.h"
@@ -74,9 +74,13 @@ static int g_target_operand_compare(const GTargetOperand *, const GTargetOperand
/* Traduit un opérande en version humainement lisible. */
static void g_target_operand_print(const GTargetOperand *, GBufferLine *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Construit un petit résumé concis de l'opérande. */
static char *g_target_operand_build_tooltip(const GTargetOperand *, const GLoadedBinary *);
+#endif
+
/* Fournit l'empreinte d'un candidat à une centralisation. */
static guint g_target_operand_hash(const GTargetOperand *, bool);
@@ -132,7 +136,9 @@ static void g_target_operand_class_init(GTargetOperandClass *klass)
operand->compare = (operand_compare_fc)g_target_operand_compare;
operand->print = (operand_print_fc)g_target_operand_print;
+#ifdef INCLUDE_GTK_SUPPORT
operand->build_tooltip = (operand_build_tooltip_fc)g_target_operand_build_tooltip;
+#endif
operand->hash = (operand_hash_fc)g_target_operand_hash;
@@ -382,6 +388,9 @@ GArchOperand *g_target_operand_new(MemoryDataSize size, const vmpa2t *addr)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : operand = opérande à consulter. *
@@ -462,6 +471,9 @@ static char *g_target_operand_build_tooltip(const GTargetOperand *operand, const
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : operand = structure dont le contenu est à consulter. *
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index f353ebd..4f35ebe 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -156,6 +156,62 @@ bool store_vmpa(const vmpa2t *, const char *, bound_value **, size_t *);
+/* ------------------------ DEFINITION DE POSITION AVEC BITS ------------------------ */
+
+
+/* Adresse mémoire ou position physique */
+typedef struct _ext_vmpa_t
+{
+ vmpa2t base; /* Vision macroscopique */
+
+ uint8_t consumed_extra_bits; /* Avancée supplémentaire */
+
+} ext_vmpa_t;
+
+
+#define init_evmpa_from_vmpa(d, s) \
+ do \
+ { \
+ copy_vmpa(&(d)->base, (s)); \
+ (d)->consumed_extra_bits = 0; \
+ } \
+ while (0)
+
+#define copy_evmpa(d, s) \
+ do \
+ { \
+ copy_vmpa(&(d)->base, &(s)->base); \
+ (d)->consumed_extra_bits = (s)->consumed_extra_bits; \
+ } \
+ while (0)
+
+#define advance_evmpa_bits(a, q) \
+ do \
+ { \
+ uint8_t __sum; \
+ __sum = (a)->consumed_extra_bits + q; \
+ if (__sum > 8) \
+ { \
+ advance_vmpa(&(a)->base, __sum / 8); \
+ (a)->consumed_extra_bits = __sum % 8; \
+ } \
+ else \
+ (a)->consumed_extra_bits = __sum; \
+ } \
+ while (0)
+
+#define align_evmpa_on_byte(a) \
+ do \
+ { \
+ if ((a)->consumed_extra_bits > 0) \
+ { \
+ advance_vmpa(&(a)->base, 1); \
+ (a)->consumed_extra_bits = 0; \
+ } \
+ } \
+ while (0);
+
+
/* ------------------------ AIDES FONCTIONNELLES AUXILIAIRES ------------------------ */
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 28e5459..1a8f8c4 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -9,7 +9,7 @@ libcommon_la_SOURCES = \
bits.h bits.c \
compression.h compression.c \
cpp.h \
- curl.h curl.c \
+ cpu.h cpu.c \
dllist.h dllist.c \
endianness.h endianness.c \
environment.h environment.c \
@@ -17,6 +17,7 @@ libcommon_la_SOURCES = \
hex.h hex.c \
ibuf.h ibuf.c \
io.h io.c \
+ itoa.h itoa.c \
fnv1a.h fnv1a.c \
leb128.h leb128.c \
macros.h \
@@ -27,20 +28,29 @@ libcommon_la_SOURCES = \
shuffle.h shuffle.c \
sort.h sort.c \
sqlite.h sqlite.c \
+ szstr.h \
utf8.h utf8.c \
xdg.h xdg.c \
xml.h xml.c
-libcommon_la_LDFLAGS = $(LIBGTK_LIBS) $(LIBXML_LIBS) $(LIBCURL_LIBS)
+if BUILD_CURL_SUPPORT
+libcommon_la_SOURCES += \
+ curl.h curl.c
-devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+endif
-dev_HEADERS = $(libcommon_la_SOURCES:%c=)
+cpu.lo: CFLAGS += -mavx512f
+
+libcommon_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+
+if BUILD_CURL_SUPPORT
+libcommon_la_CFLAGS += $(LIBCURL_CFLAGS)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBCURL_CFLAGS)
+endif
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-SUBDIRS =
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libcommon_la_SOURCES:%c=)
diff --git a/src/common/bits.c b/src/common/bits.c
index a450bb2..0e5afc8 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -38,7 +38,11 @@
struct _bitfield_t
{
size_t length; /* Nombre de bits représentés */
- size_t requested; /* Nombre de mots alloués */
+
+ size_t allocated_words; /* Nombre de mots alloués */
+ size_t used_words; /* Nombre de mots utilisés */
+
+ bool default_state; /* Etat d'initialisation */
unsigned long bits[0]; /* Mémoire d'accès associée */
@@ -51,6 +55,9 @@ static bitfield_t *_create_bit_field(size_t);
/* Détermine si un ensemble de bits est homogène dans un champ. */
static bool test_state_in_bit_field(const bitfield_t *, size_t, size_t, bool);
+/* Teste l'état de bits selon un masque de bits. */
+static bool test_state_within_bit_field(const bitfield_t *, size_t, const bitfield_t *, bool);
+
/******************************************************************************
@@ -68,18 +75,20 @@ static bool test_state_in_bit_field(const bitfield_t *, size_t, size_t, bool);
static bitfield_t *_create_bit_field(size_t length)
{
bitfield_t *result; /* Création à retourner */
- size_t requested; /* Nombre de mots à allouer */
+ size_t needed; /* Nombre de mots à allouer */
size_t base; /* Allocation de base en octets*/
- requested = length / (sizeof(unsigned long) * 8);
- if (length % (sizeof(unsigned long) * 8) != 0) requested++;
+ needed = length / (sizeof(unsigned long) * 8);
+ if (length % (sizeof(unsigned long) * 8) != 0) needed++;
- base = sizeof(bitfield_t) + requested * sizeof(unsigned long);
+ base = sizeof(bitfield_t) + needed * sizeof(unsigned long);
result = (bitfield_t *)malloc(base);
result->length = length;
- result->requested = requested;
+
+ result->allocated_words = needed;
+ result->used_words = needed;
return result;
@@ -105,6 +114,8 @@ bitfield_t *create_bit_field(size_t length, bool state)
result = _create_bit_field(length);
+ result->default_state = state;
+
if (state)
set_all_in_bit_field(result);
else
@@ -133,7 +144,7 @@ bitfield_t *dup_bit_field(const bitfield_t *field)
result = _create_bit_field(field->length);
- memcpy(result->bits, field->bits, result->requested * sizeof(unsigned long));
+ memcpy(result->bits, field->bits, result->used_words * sizeof(unsigned long));
return result;
@@ -176,7 +187,124 @@ void copy_bit_field(bitfield_t *dest, const bitfield_t *src)
{
assert(dest->length == src->length);
- memcpy(dest->bits, src->bits, dest->requested * sizeof(unsigned long));
+ memcpy(dest->bits, src->bits, dest->used_words * sizeof(unsigned long));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = champ de bits à modifier. [OUT] *
+* length = nouveau nombre de bits du champ à représenter. *
+* *
+* Description : Réduit ou étend la taille d'un champ en évitant l'allocation.*
+* *
+* Retour : - *
+* *
+* Remarques : Les éventuels bits supplémentaires ou disparus ne sont pas *
+* (ré)initialisés. *
+* *
+******************************************************************************/
+
+void truncate_bit_field(bitfield_t **field, size_t length)
+{
+ bitfield_t *_field; /* Commodité d'accès */
+ size_t needed; /* Nombre de mots à allouer */
+
+ _field = *field;
+
+ needed = length / (sizeof(unsigned long) * 8);
+ if (length % (sizeof(unsigned long) * 8) != 0) needed++;
+
+ if (needed <= _field->allocated_words)
+ {
+ _field->length = length;
+
+ _field->used_words = needed;
+
+ }
+
+ else
+ resize_bit_field(field, length);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = champ de bits à modifier. [OUT] *
+* length = nouveau nombre de bits du champ à représenter. *
+* *
+* Description : Redimensionne un champ de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void resize_bit_field(bitfield_t **field, size_t length)
+{
+ bitfield_t *_field; /* Commodité d'accès */
+ size_t needed; /* Nombre de mots à allouer */
+ size_t base; /* Allocation de base en octets*/
+ size_t remaining; /* Nombre de derniers bits */
+ size_t last; /* Dernier mot utilisé */
+ unsigned long mask; /* Masque d'initialisation */
+ size_t i; /* Boucle de parcours */
+
+ _field = *field;
+
+ if (_field->length != length)
+ {
+ /* Redimensionnement */
+
+ needed = length / (sizeof(unsigned long) * 8);
+ if (length % (sizeof(unsigned long) * 8) != 0) needed++;
+
+ base = sizeof(bitfield_t) + needed * sizeof(unsigned long);
+
+ /* Initialisation, si nécessaire */
+
+ if (_field->length < length)
+ {
+ *field = realloc(_field, base);
+ _field = *field;
+
+ last = _field->length / (sizeof(unsigned long) * 8);
+ remaining = _field->length % (sizeof(unsigned long) * 8);
+
+ if (remaining != 0)
+ {
+ mask = (1ul << remaining) - 1;
+
+ if (_field->default_state)
+ _field->bits[last] |= ~mask;
+ else
+ _field->bits[last] &= mask;
+
+ last++;
+
+ }
+
+ for (i = last; i < needed; i++)
+ {
+ if (_field->default_state)
+ _field->bits[i] = ~0ul;
+ else
+ _field->bits[i] = 0ul;
+ }
+
+ }
+
+ /* Actualisation des tailles */
+
+ _field->length = length;
+
+ _field->allocated_words = needed;
+ _field->used_words = needed;
+
+ }
}
@@ -242,12 +370,12 @@ int compare_bit_fields(const bitfield_t *a, const bitfield_t *b)
else
final = (1 << final) - 1;
- for (i = 0; i < a->requested && result == 0; i++)
+ for (i = 0; i < a->used_words && result == 0; i++)
{
val_a = a->bits[i];
val_b = b->bits[i];
- if ((i + 1) == a->requested)
+ if ((i + 1) == a->used_words)
{
val_a &= final;
val_b &= final;
@@ -282,7 +410,7 @@ int compare_bit_fields(const bitfield_t *a, const bitfield_t *b)
void reset_all_in_bit_field(bitfield_t *field)
{
- memset(field->bits, 0u, field->requested * sizeof(unsigned long));
+ memset(field->bits, 0u, field->used_words * sizeof(unsigned long));
}
@@ -301,7 +429,7 @@ void reset_all_in_bit_field(bitfield_t *field)
void set_all_in_bit_field(bitfield_t *field)
{
- memset(field->bits, ~0u, field->requested * sizeof(unsigned long));
+ memset(field->bits, ~0u, field->used_words * sizeof(unsigned long));
}
@@ -399,7 +527,7 @@ void and_bit_field(bitfield_t *dest, const bitfield_t *src)
assert(dest->length == src->length);
- for (i = 0; i < dest->requested; i++)
+ for (i = 0; i < dest->used_words; i++)
dest->bits[i] &= src->bits[i];
}
@@ -424,7 +552,7 @@ void or_bit_field(bitfield_t *dest, const bitfield_t *src)
assert(dest->length == src->length);
- for (i = 0; i < dest->requested; i++)
+ for (i = 0; i < dest->used_words; i++)
dest->bits[i] |= src->bits[i];
}
@@ -432,6 +560,61 @@ void or_bit_field(bitfield_t *dest, const bitfield_t *src)
/******************************************************************************
* *
+* Paramètres : dest = champ de bits à modifier. *
+* src = champ de bits à utiliser pour l'opération. *
+* first = point de départ pour l'opération à réaliser. *
+* *
+* Description : Réalise une opération OU logique entre deux champs de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void or_bit_field_at(bitfield_t *dest, const bitfield_t *src, size_t first)
+{
+ size_t start; /* Mot de départ dans le champ */
+ size_t offset; /* Décalage des mots à basculer*/
+ size_t remaining; /* Taille du dernier tronçon */
+ size_t last_iter; /* Dernière itération à mener */
+ size_t i; /* Boucle de parcours */
+ unsigned long word; /* Mot reconstituté à tester */
+
+ assert((first + src->length) <= dest->length);
+
+ start = first / (sizeof(unsigned long) * 8);
+ offset = first % (sizeof(unsigned long) * 8);
+
+ remaining = (first + src->length) % (sizeof(unsigned long) * 8);
+
+ if ((first + src->length) % (sizeof(unsigned long) * 8) > 0)
+ last_iter = src->used_words;
+ else
+ last_iter = src->used_words - 1;
+
+ for (i = 0; i <= last_iter; i++)
+ {
+ if (i < src->used_words)
+ word = src->bits[i] << offset;
+ else
+ word = 0;
+
+ if (i > 0 && offset > 0)
+ word |= src->bits[i - 1] >> (sizeof(unsigned long) * 8 - offset);
+
+ if (i == last_iter && remaining > 0)
+ word &= (1ul << remaining) - 1;
+
+ dest->bits[start + i] |= word;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : field = champ de bits à consulter. *
* n = indice du bit à traiter. *
* *
@@ -463,6 +646,42 @@ bool test_in_bit_field(const bitfield_t *field, size_t n)
/******************************************************************************
* *
+* Paramètres : field = champ de bits à consulter. *
+* n = indice du bit à traiter. *
+* *
+* Description : Détermine si un bit est à 1 dans un champ puis le définit. *
+* *
+* Retour : true si le bit correspondant était déjà à l'état haut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool test_and_set_in_bit_field(bitfield_t *field, size_t n)
+{
+ bool result; /* Valeur retrouvée à renvoyer */
+ size_t index; /* Cellule de tableau visée */
+ size_t remaining; /* Nombre de bits restants */
+ unsigned long *bits; /* Accès mis en commun */
+
+ assert(n < field->length);
+
+ index = n / (sizeof(unsigned long) * 8);
+ remaining = n % (sizeof(unsigned long) * 8);
+
+ bits = field->bits + index;
+
+ result = *bits & (1ul << remaining);
+
+ *bits |= (1ul << remaining);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : field = champ de bits à modifier. *
* first = indice du premier bit à traiter. *
* count = nombre de bits à marquer. *
@@ -556,6 +775,255 @@ bool test_all_in_bit_field(const bitfield_t *field, size_t first, size_t count)
/******************************************************************************
* *
+* Paramètres : field = champ de bits à modifier. *
+* first = indice du premier bit à traiter. *
+* mask = second champ de bits à tester logiquement. *
+* state = état global à retrouver idéalement. *
+* *
+* Description : Teste l'état de bits selon un masque de bits. *
+* *
+* Retour : true si les bits visés sont tous à l'état indiqué. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool test_state_within_bit_field(const bitfield_t *field, size_t first, const bitfield_t *mask, bool state)
+{
+ bool result; /* Bilan à retourner */
+ size_t start; /* Mot de départ dans le champ */
+ size_t offset; /* Décalage des mots à testter */
+ size_t remaining; /* Taille du dernier tronçon */
+ unsigned long finalcut; /* Limitation du mot final */
+ size_t i; /* Boucle de parcours */
+ size_t windex; /* Indice du mot courant */
+ unsigned long word; /* Mot reconstituté à tester */
+ unsigned long bitmask; /* Masque à appliquer */
+ unsigned long test; /* Valeur résultante du test */
+
+ result = true;
+
+ assert((first + mask->length) <= field->length);
+
+ start = first / (sizeof(unsigned long) * 8);
+ offset = first % (sizeof(unsigned long) * 8);
+
+ remaining = mask->length % (sizeof(unsigned long) * 8);
+
+ if (remaining == 0)
+ finalcut = ~0lu;
+ else
+ finalcut = (1lu << remaining) - 1;
+
+ for (i = 0; i < mask->used_words && result; i++)
+ {
+ windex = start + i;
+
+ if (offset == 0)
+ word = field->bits[windex];
+
+ else
+ {
+ word = field->bits[windex] >> offset;
+ if ((windex + 1) < field->used_words)
+ word |= field->bits[windex + 1] << (sizeof(unsigned long) * 8 - offset);
+ }
+
+ bitmask = mask->bits[i];
+
+ test = word ^ bitmask;
+
+ test &= bitmask;
+
+ if ((i + 1) == mask->used_words)
+ {
+ bitmask &= finalcut;
+ test &= finalcut;
+ }
+
+ result = (state ? test == 0 : test == bitmask);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = champ de bits à modifier. *
+* first = indice du premier bit à traiter. *
+* mask = second champ de bits à tester logiquement. *
+* *
+* Description : Teste l'état à 0 de bits selon un masque de bits. *
+* *
+* Retour : true si les bits visés sont à l'état bas. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool test_zeros_within_bit_field(const bitfield_t *field, size_t first, const bitfield_t *mask)
+{
+ bool result; /* Valeur retrouvée à renvoyer */
+
+ result = test_state_within_bit_field(field, first, mask, false);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = champ de bits à modifier. *
+* first = indice du premier bit à traiter. *
+* mask = second champ de bits à tester logiquement. *
+* *
+* Description : Teste l'état à 1 de bits selon un masque de bits. *
+* *
+* Retour : true si les bits visés sont à l'état haut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool test_ones_within_bit_field(const bitfield_t *field, size_t first, const bitfield_t *mask)
+{
+ bool result; /* Valeur retrouvée à renvoyer */
+
+ result = test_state_within_bit_field(field, first, mask, true);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : field = champ de bits à consulter. *
+* extra = champ de bits à placer. *
+* *
+* Description : Recherche l'indice idéal pour placer un champ dans un autre. *
+* *
+* Retour : Position du premier bit à insérer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t find_interleaving_index_for_acism(const bitfield_t *field, const bitfield_t *extra, size_t *first)
+{
+ size_t result; /* Dimension à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ const unsigned long *bits; /* Itérateurs sur les bits */
+ size_t init_k; /* Point de départ optimal */
+ size_t k; /* Boucle de parcours #2 */
+ unsigned long mask; /* Valeur à comparer */
+ size_t j; /* Boucle de parcours #3 */
+
+ /**
+ * La procédure s'appuie sur deux particularité du contexte d'exécution (scan ACISM) :
+ * - il y a toujours au moins 257 bits (taille maximale du champs "extra") libres
+ * en fin de champs "field" ;
+ * - le premier bit du champ "extra" est toujours fixé à 1.
+ */
+
+ result = 0;
+
+ for (i = *first; i < field->used_words; i++)
+ {
+ /* S'il ne reste plus aucune place */
+ if (field->bits[i] != ~0lu)
+ break;
+ }
+
+ *first = i;
+
+ bits = field->bits + i;
+
+ for (; i < field->used_words; i++, bits++)
+ {
+ /* S'il ne reste plus aucune place */
+ if (*bits == ~0lu)
+ continue;
+
+ init_k = __builtin_ffsl(~*bits) - 1;
+
+ for (k = init_k; k < __WORDSIZE; k++)
+ {
+ /**
+ * Le champs de bits à placer ne comporte pas forcément au moins
+ * 32/64 bits, mais les bits non comptabilisés du mot sont toujours
+ * initialisés à zéro.
+ *
+ * Aucune prise en compte particulière d'un champ de petite taille
+ * n'est donc à réaliser ici.
+ */
+
+ mask = (extra->bits[0] << k);
+
+ /* Si tous les bits nécessaires au début sont libres... */
+ if ((*bits & mask) == 0)
+ {
+ for (j = 1; j < extra->used_words; j++)
+ {
+ if (k == 0)
+ mask = extra->bits[j];
+
+ else
+ {
+ /* Portion du mot courant */
+ mask = (extra->bits[j] << k);
+
+ /* Relicat du mot précédent */
+ mask |= (extra->bits[j - 1] >> (__WORDSIZE - k));
+
+ }
+
+ if (mask == 0)
+ continue;
+
+ if ((bits[j] & mask) != 0)
+ break;
+
+ }
+
+ if (j == extra->used_words)
+ {
+ /* Eventuelle dernière bribe débordant sur un dernier mot ? */
+ if (k > 0)
+ {
+ mask = (extra->bits[j - 1] >> (__WORDSIZE - k));
+
+ if ((bits[j] & mask) != 0)
+ continue;
+
+ }
+
+ result = i * __WORDSIZE + k;
+ goto found;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ found:
+
+ assert(result > 0);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : field = champ de bits à consulter. *
* *
* Description : Détermine le nombre de bits à 1 dans un champ. *
@@ -577,7 +1045,7 @@ size_t popcount_for_bit_field(const bitfield_t *field)
remaining = field->length;
- for (i = 0; i < field->requested; i++)
+ for (i = 0; i < field->used_words; i++)
{
value = field->bits[i];
@@ -599,3 +1067,55 @@ size_t popcount_for_bit_field(const bitfield_t *field)
return result;
}
+
+
+#if 0
+
+/******************************************************************************
+* *
+* Paramètres : field = champ de bits à consulter. *
+* *
+* Description : Imprime sur la sortie standard la valeur représentée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void output_bit_field(const bitfield_t *field)
+{
+ size_t i; /* Boucle de parcours #1 */
+ unsigned long value; /* Valeur masquée à traiter */
+ size_t k; /* Boucle de parcours #2 */
+
+ printf("[len=%zu] \n", field->length);
+
+#define MAX_BITS (sizeof(unsigned long) * 8)
+
+ for (i = 0; i < field->used_words; i++)
+ {
+ value = field->bits[i];
+
+ if (i > 0)
+ printf("| ");
+
+ for (k = 0; k < MAX_BITS; k++)
+ {
+ if ((i * MAX_BITS + k) >= field->length)
+ break;
+
+ printf("%c", value & (1lu << k) ? '1' : '.');
+
+ if ((k + 1) % 8 == 0)
+ printf(" ");
+
+ }
+
+ }
+
+ printf("\n");
+
+}
+
+#endif
diff --git a/src/common/bits.h b/src/common/bits.h
index 96ea06a..cd71681 100644
--- a/src/common/bits.h
+++ b/src/common/bits.h
@@ -45,6 +45,12 @@ void delete_bit_field(bitfield_t *);
/* Copie un champ de bits dans un autre. */
void copy_bit_field(bitfield_t *, const bitfield_t *);
+/* Réduit ou étend la taille d'un champ en évitant l'allocation. */
+void truncate_bit_field(bitfield_t **, size_t);
+
+/* Redimensionne un champ de bits. */
+void resize_bit_field(bitfield_t **, size_t);
+
/* Indique la taille d'un champ de bits donné. */
size_t get_bit_field_size(const bitfield_t *);
@@ -69,18 +75,40 @@ void and_bit_field(bitfield_t *, const bitfield_t *);
/* Réalise une opération OU logique entre deux champs de bits. */
void or_bit_field(bitfield_t *, const bitfield_t *);
+/* Réalise une opération OU logique entre deux champs de bits. */
+void or_bit_field_at(bitfield_t *, const bitfield_t *, size_t);
+
/* Détermine si un bit est à 1 dans un champ de bits. */
bool test_in_bit_field(const bitfield_t *, size_t);
+/* Détermine si un bit est à 1 dans un champ puis le définit. */
+bool test_and_set_in_bit_field(bitfield_t *, size_t);
+
/* Détermine si un ensemble de bits est à 0 dans un champ. */
bool test_none_in_bit_field(const bitfield_t *, size_t, size_t);
/* Détermine si un ensemble de bits est à 1 dans un champ. */
bool test_all_in_bit_field(const bitfield_t *, size_t, size_t);
+/* Teste l'état à 0 de bits selon un masque de bits. */
+bool test_zeros_within_bit_field(const bitfield_t *, size_t, const bitfield_t *);
+
+/* Teste l'état à 1 de bits selon un masque de bits. */
+bool test_ones_within_bit_field(const bitfield_t *, size_t, const bitfield_t *);
+
+/* Recherche l'indice idéal pour placer un champ dans un autre. */
+size_t find_interleaving_index_for_acism(const bitfield_t *, const bitfield_t *, size_t *);
+
/* Détermine le nombre de bits à 1 dans un champ. */
size_t popcount_for_bit_field(const bitfield_t *);
+#if 0
+
+/* Imprime sur la sortie standard la valeur représentée. */
+void output_bit_field(const bitfield_t *);
+
+#endif
+
#endif /* _COMMON_BITS_H */
diff --git a/src/common/cpp.h b/src/common/cpp.h
index b1606ed..39e7676 100644
--- a/src/common/cpp.h
+++ b/src/common/cpp.h
@@ -46,6 +46,8 @@
#define SIZE_T_MAXLEN strlen(XSTR(LONG_MAX))
+#define ULLONG_MAXLEN (sizeof(XSTR(ULLONG_MAX)) + 1)
+
/**
* Emprunt au noyau Linux (cf. include/linux/bug.h) pour les vérifications à la compilation.
diff --git a/src/common/cpu.c b/src/common/cpu.c
new file mode 100644
index 0000000..968def5
--- /dev/null
+++ b/src/common/cpu.c
@@ -0,0 +1,100 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cpu.c - obtention d'indications de fonctionnalités liées au CPU
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "cpu.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Indique les capacités de calculs parallèles anticipées. *
+* *
+* Retour : Fonctionnalités disponibles lors de la compilation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+CPUSMIDFeature get_supported_cpu_smid_feature(void)
+{
+ CPUSMIDFeature result; /* Indications à retourner */
+
+ result = CSF_NONE;
+
+ /**
+ * $ gcc -mavx512f -dM -E - < /dev/null | grep AVX
+ * #define __AVX512F__ 1
+ * #define __AVX__ 1
+ * #define __AVX2__ 1
+ */
+
+#ifdef __AVX2__
+ result |= CSF_AVX2;
+#endif
+
+#ifdef __AVX512F__
+ result |= CSF_AVX512;
+#endif
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Indique les capacités de calculs parallèles sollicitables. *
+* *
+* Retour : Fonctionnalités disponibles dans l'environnement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+CPUSMIDFeature get_avalaible_cpu_smid_feature(void)
+{
+ CPUSMIDFeature result; /* Indications à retourner */
+
+ result = CSF_NONE;
+
+ /**
+ * Cf. Documentations suivantes :
+ * - https://www.intel.com/content/dam/develop/external/us/en/documents/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family.pdf
+ * - https://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html
+ */
+
+ __builtin_cpu_init();
+
+ if (__builtin_cpu_supports("ssse3"))
+ result |= CSF_AVX2;
+
+ if (__builtin_cpu_supports("avx512f"))
+ result |= CSF_AVX512;
+
+ return result;
+
+}
diff --git a/src/common/cpu.h b/src/common/cpu.h
new file mode 100644
index 0000000..58e53bd
--- /dev/null
+++ b/src/common/cpu.h
@@ -0,0 +1,50 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cpu.h - prototypes pour l'obtention d'indications de fonctionnalités liées au CPU
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _COMMON_CPU_H
+#define _COMMON_CPU_H
+
+
+
+/* Indication de capacité de calculs parallèles */
+typedef enum _CPUSMIDFeature
+{
+ CSF_NONE = (0 << 0), /* Absence d'indication */
+
+ CSF_AVX2 = (1 << 0), /* Advanced Vector Extensions */
+ CSF_AVX512 = (1 << 1), /* Advanced Vector Extensions */
+
+ CSF_ALL = ((1 << 2) - 1),
+
+} CPUSMIDFeature;
+
+
+/* Indique les capacités de calculs parallèles anticipées. */
+CPUSMIDFeature get_supported_cpu_smid_feature(void);
+
+/* Indique les capacités de calculs parallèles sollicitables. */
+CPUSMIDFeature get_avalaible_cpu_smid_feature(void);
+
+
+
+#endif /* _COMMON_CPU_H */
diff --git a/src/common/dllist.c b/src/common/dllist.c
index a953ad0..1ee7b0d 100644
--- a/src/common/dllist.c
+++ b/src/common/dllist.c
@@ -24,6 +24,17 @@
#include "dllist.h"
+#include <assert.h>
+
+
+
+/* Découpe une liste en deux parties. */
+static void split_dl_lists(dl_list_head, dl_list_head *, dl_list_head *);
+
+/* Trie une liste chaînée en supprimant les éléments identiques. */
+static dl_list_head sort_and_merge_dl_lists_no_dup(dl_list_head *, dl_list_head *, size_t *, __dl_item_compar_fn_t, dl_list_head *);
+
+
/******************************************************************************
* *
@@ -79,3 +90,187 @@ void __dl_list_del(dl_list_item *item, dl_list_head *head)
}
}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = liste à découper. *
+* part1 = première partie constituée. [OUT] *
+* part2 = seconde partie constituée. [OUT] *
+* *
+* Description : Découpe une liste en deux parties. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void split_dl_lists(dl_list_head list, dl_list_head *part1, dl_list_head *part2)
+{
+ dl_list_item *iter_slow; /* Boucle de parcours #1 */
+ dl_list_item *iter_fast; /* Boucle de parcours #2 */
+
+ *part1 = list;
+
+ iter_slow = list;
+ iter_fast = _dl_list_next(iter_slow, list);
+
+ while (iter_fast != NULL)
+ {
+ iter_fast = _dl_list_next(iter_fast, list);
+
+ if (iter_fast != NULL)
+ {
+ iter_slow = _dl_list_next(iter_slow, list);
+ iter_fast = _dl_list_next(iter_fast, list);
+ }
+
+ }
+
+ *part2 = _dl_list_next(iter_slow, list);
+
+ /* Réalisation d'une coupure */
+
+ if (*part2 != NULL)
+ {
+ (*part2)->prev = (*part1)->prev;
+ (*part2)->prev->next = (*part2);
+ }
+
+ iter_slow->next = *part1;
+ (*part1)->prev = iter_slow;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : head = tête de la liste à trier. *
+* length = taille de la liste fournie. *
+* compar = méthode de comparaison des éléments. *
+* duplicated = liste des éléments présents en double. [OUT] *
+* *
+* Description : Trie une liste chaînée en supprimant les éléments identiques.*
+* *
+* Retour : Nouvelle liste obtenue. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static dl_list_head sort_and_merge_dl_lists_no_dup(dl_list_head *a, dl_list_head *b, size_t *length, __dl_item_compar_fn_t compar, dl_list_head *duplicated)
+{
+ dl_list_head result; /* Liste fusionnée à renvoyer */
+ int ret; /* Bilan d'une comparaison */
+ dl_list_head next; /* Maillons de liste suivants */
+
+ if (dl_list_empty(*a))
+ result = *b;
+
+ else if (dl_list_empty(*b))
+ result = *a;
+
+ else
+ {
+ ret = compar(*a, *b);
+
+ if (ret < 0)
+ {
+ result = *a;
+ __dl_list_del(result, a);
+ DL_LIST_ITEM_INIT(result);
+
+ next = sort_and_merge_dl_lists_no_dup(a, b, length, compar, duplicated);
+ assert(!dl_list_empty(next));
+ _dl_list_merge(result, next);
+
+ }
+
+ else if (ret == 0)
+ {
+ result = *a;
+ __dl_list_del(result, a);
+ DL_LIST_ITEM_INIT(result);
+
+ if (length != NULL)
+ (*length)--;
+
+ if (duplicated != NULL)
+ {
+ /**
+ * L'élément est ici ajouté à la liste sans respect d'un ordre particulier.
+ */
+
+ if (dl_list_empty(*duplicated))
+ *duplicated = result;
+ else
+ __dl_list_add(result, duplicated, (*duplicated)->prev, *duplicated);
+
+ }
+
+ result = *b;
+ __dl_list_del(result, b);
+ DL_LIST_ITEM_INIT(result);
+
+ next = sort_and_merge_dl_lists_no_dup(a, b, length, compar, duplicated);
+ if (!dl_list_empty(next))
+ _dl_list_merge(result, next);
+
+ }
+
+ else
+ {
+ result = *b;
+ __dl_list_del(result, b);
+ DL_LIST_ITEM_INIT(result);
+
+ next = sort_and_merge_dl_lists_no_dup(a, b, length, compar, duplicated);
+ assert(!dl_list_empty(next));
+ _dl_list_merge(result, next);
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : head = tête de la liste à trier. *
+* length = taille de la liste fournie. *
+* compar = méthode de comparaison des éléments. *
+* duplicated = liste des éléments présents en double. [OUT] *
+* *
+* Description : Trie une liste chaînée en notant les éléments identiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void sort_dl_list_no_dup(dl_list_head *head, size_t *length, __dl_item_compar_fn_t compar, dl_list_head *duplicated)
+{
+ dl_list_head part1; /* Première moitiée à traiter */
+ dl_list_head part2; /* Seconde moitiée à traiter */
+
+ /* S'il y a réellement quelque chose à faire */
+ if (!dl_list_empty(*head) && !_dl_list_is_last(*head, *head))
+ {
+ /* Découpage en deux sous-listes */
+ split_dl_lists(*head, &part1, &part2);
+
+ /* Tri des deux listes obtenues */
+ sort_dl_list_no_dup(&part1, length, compar, duplicated);
+ sort_dl_list_no_dup(&part2, length, compar, duplicated);
+
+ /* Fusion des deux listes triées */
+ *head = sort_and_merge_dl_lists_no_dup(&part1, &part2, length, compar, duplicated);
+
+ }
+
+}
diff --git a/src/common/dllist.h b/src/common/dllist.h
index 111843b..1fb010a 100644
--- a/src/common/dllist.h
+++ b/src/common/dllist.h
@@ -62,6 +62,12 @@ void __dl_list_del(dl_list_item *, dl_list_head *);
#define dl_list_empty(head) \
((head) == NULL)
+#define _dl_list_is_last(item, head) \
+ ((item)->next == head)
+
+#define dl_list_is_last(item, head, member) \
+ item->member.next == &head->member
+
#define dl_list_last(head, type, member) \
(dl_list_empty(head) ? NULL : (type *)container_of(head->member.prev, type, member))
@@ -108,6 +114,17 @@ void __dl_list_del(dl_list_item *, dl_list_head *);
} \
while(0)
+#define _dl_list_merge(head1, head2) \
+ do \
+ { \
+ dl_list_item *mid = head1->prev; \
+ mid->next = head2; \
+ head1->prev = head2->prev; \
+ head2->prev->next = head1; \
+ head2->prev = mid; \
+ } \
+ while(0)
+
#define dl_list_merge(head1, head2, type, member) \
do \
{ \
@@ -134,6 +151,16 @@ void __dl_list_del(dl_list_item *, dl_list_head *);
_result; \
})
+#define _dl_list_next(iter, head) \
+ ({ \
+ dl_list_item *__next; \
+ __next = iter->next; \
+ if (__next == head) \
+ __next = NULL; \
+ __next; \
+ })
+
+
#define dl_list_next_iter(iter, head, type, member) \
(iter->member.next == &head->member ? \
NULL : container_of(iter->member.next, type, member))
@@ -164,5 +191,12 @@ void __dl_list_del(dl_list_item *, dl_list_head *);
pos = dl_list_prev_iter(pos, (head), type, member))
+/* Prototype pour un comparateur d'éléments */
+typedef int (*__dl_item_compar_fn_t) (const dl_list_item *, const dl_list_item *);
+
+/* Trie une liste chaînée en notant les éléments identiques. */
+void sort_dl_list_no_dup(dl_list_head *, size_t *, __dl_item_compar_fn_t, dl_list_head *);
+
+
#endif /* _COMMON_DLLIST_H */
diff --git a/src/common/extstr.c b/src/common/extstr.c
index 9142bd9..ac93f5d 100644
--- a/src/common/extstr.c
+++ b/src/common/extstr.c
@@ -24,9 +24,12 @@
#include "extstr.h"
+#include <ctype.h>
#include <malloc.h>
#include <regex.h>
+#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
@@ -96,6 +99,47 @@ char *strnadd(char *str1, const char *str2, size_t n)
/******************************************************************************
* *
* Paramètres : str1 = chaîne de caractères à compléter. *
+* fmt = description de la forme de la chaîne complémentaire. *
+* ... = éléments associés au format à construire. *
+* *
+* Description : Complète une chaîne de caractères avec une chaîne à formater.*
+* *
+* Retour : Chaîne de caractères complétée, à libérer de la mémoire. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *straddfmt(char *str1, const char *fmt, ...)
+{
+ char *result; /* Chaîne à renvoyer */
+ va_list ap; /* Liste des arguments */
+ char *tmp; /* Conservation temporaire */
+ int ret; /* Bilan intermédiaire */
+
+ va_start(ap, fmt);
+
+ ret = vasprintf(&tmp, fmt, ap);
+
+ if (ret != -1)
+ {
+ result = stradd(str1, tmp);
+ free(tmp);
+ }
+
+ else
+ result = str1;
+
+ va_end(ap);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : str1 = chaîne de caractères à compléter. *
* str2 = chaîne de caractères à ajouter. *
* *
* Description : Fait précéder une chaîne de caractères par une autre. *
@@ -522,3 +566,106 @@ bool _endswith(const char *str, const char *suffix, const char **end)
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : haystack = botte de foin composant l'espace de recherche. *
+* haystacklen = taille de cet espace. *
+* needle = aiguille visée, cible des recherches. *
+* needlelen = taille de l'aiguille à rechercher. *
+* *
+* Description : Recherche une séquence d'octets dans un ensemble de données. *
+* *
+* Retour : Adresse de l'éventuelle trouvaille ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const void *memcasemem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
+{
+ const void *result; /* Trouvaille à renvoyer */
+ const char *_haystack; /* Autre version de la botte */
+ const char *_needle; /* Autre version de l'aiguille */
+ size_t i; /* Boucle de parcours #1 */
+ size_t k; /* Boucle de parcours #2 */
+ int c1; /* Caractère de la chaîne #1 */
+ int c2; /* Caractère de la chaîne #2 */
+
+ result = NULL;
+
+ if (needlelen > haystacklen)
+ goto done;
+
+ _haystack = (const char *)haystack;
+ _needle = (const char *)needle;
+
+ for (i = 0; i <= (haystacklen - needlelen); i++, _haystack++)
+ {
+ for (k = 0; k < needlelen; k++)
+ {
+ c1 = toupper(_haystack[k]);
+ c2 = toupper(_needle[k]);
+
+ if (c1 != c2)
+ break;
+
+ }
+
+ if (k == needlelen)
+ {
+ result = _haystack;
+ break;
+ }
+
+ }
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : s1 = première séquence d'octets à consulter. *
+* s2 = second séquence d'octets à consulter. *
+* n = quantité d'octets à comparer. *
+* *
+* Description : Compare sans casse deux série d'octets entre elles. *
+* *
+* Retour : Status de la comparaison des séries d'octets. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int memcasecmp(const void *s1, const void *s2, size_t n)
+{
+ int result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours */
+ const char *_s1; /* Séquence avec taille #1 */
+ const char *_s2; /* Séquence avec taille #2 */
+ int c1; /* Caractère de la chaîne #1 */
+ int c2; /* Caractère de la chaîne #2 */
+
+ result = 0;
+
+ _s1 = (const char *)s1;
+ _s2 = (const char *)s2;
+
+ for (i = 0; i < n; i++)
+ {
+ c1 = toupper(_s1[i]);
+ c2 = toupper(_s2[i]);
+
+ result = c1 - c2;
+ if (result != 0) break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/common/extstr.h b/src/common/extstr.h
index 1c39603..a2293be 100644
--- a/src/common/extstr.h
+++ b/src/common/extstr.h
@@ -37,6 +37,9 @@ char *stradd(char *, const char *);
/* Complète une chaîne de caractères avec une autre. */
char *strnadd(char *, const char *, size_t);
+/* Complète une chaîne de caractères avec une chaîne à formater. */
+char *straddfmt(char *, const char *, ...);
+
/* Fait précéder une chaîne de caractères par une autre. */
char *strprep(char *, const char *);
@@ -76,6 +79,12 @@ bool _endswith(const char *, const char *, const char **);
#define startswith(str, prefix) _startswith(str, prefix, NULL)
#define endswith(str, suffix) _endswith(str, suffix, NULL)
+/* Recherche une séquence d'octets dans un ensemble de données. */
+const void *memcasemem(const void *, size_t, const void *, size_t);
+
+/* Compare sans casse deux série d'octets entre elles. */
+int memcasecmp(const void *, const void *, size_t);
+
#endif /* _COMMON_EXTSTR_H */
diff --git a/src/common/itoa.c b/src/common/itoa.c
new file mode 100644
index 0000000..56fc638
--- /dev/null
+++ b/src/common/itoa.c
@@ -0,0 +1,135 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * itoa.c - conversion d'un nombre en chaîne de caractères
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "itoa.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <math.h>
+
+
+
+/******************************************************************************
+* *
+* Paramètres : n = nombre à transformer. *
+* base = base à considérer pour la sortie. *
+* *
+* Description : Convertit une valeur en une forme textuelle. *
+* *
+* Retour : Chaîne de caractères mises en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *itoa(long long n, unsigned char base)
+{
+ char *result; /* Texte à retourner */
+ size_t size; /* Taille de chaîne en sortie */
+ char *iter; /* Tête d'écriture */
+#ifndef NDEBUG
+ size_t counter; /* Décompte des impressions */
+#endif
+ long long rem; /* Unité à transposer */
+
+ /**
+ * Préparation du stockage de la chaîne finale.
+ */
+
+ if (n == 0)
+ size = 1;
+
+ else if (n < 0)
+ {
+ size = (size_t)(log(-n) / log(base) + 1);
+ size++;
+ }
+ else
+ size = (size_t)(log(n) / log(base) + 1);
+
+ /* '\0' final */
+ size++;
+
+ result = malloc(size);
+ if (result == NULL) goto exit;
+
+ /**
+ * Remplissage avec la valeur textuelle correspondant à la valeur fournie.
+ */
+
+#ifndef NDEBUG
+ counter = 0;
+#endif
+
+ if (n < 0)
+ {
+ result[0] = '-';
+#ifndef NDEBUG
+ counter++;
+#endif
+
+ n *= -1;
+
+ }
+
+ iter = result + size - 1;
+
+ *iter-- = '\0';
+#ifndef NDEBUG
+ counter++;
+#endif
+
+ if (n == 0)
+ {
+ *iter-- = '0';
+#ifndef NDEBUG
+ counter++;
+#endif
+ }
+
+ else
+ while (n > 0)
+ {
+ rem = n % base;
+
+ if (rem >= 10)
+ *iter-- = 'a' + (rem - 10);
+ else
+ *iter-- = '0' + rem;
+
+#ifndef NDEBUG
+ counter++;
+#endif
+
+ n = n / base;
+
+ }
+
+ assert(counter < size);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/common/itoa.h b/src/common/itoa.h
new file mode 100644
index 0000000..4608a50
--- /dev/null
+++ b/src/common/itoa.h
@@ -0,0 +1,34 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * itoa.h - prototypes pour la conversion d'un nombre en chaîne de caractères
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _COMMON_ITOA_H
+#define _COMMON_ITOA_H
+
+
+
+/* Convertit une valeur en une forme textuelle. */
+char *itoa(long long, unsigned char);
+
+
+
+#endif /* _COMMON_ITOA_H */
diff --git a/src/common/sort.c b/src/common/sort.c
index 32a7457..d79d71a 100644
--- a/src/common/sort.c
+++ b/src/common/sort.c
@@ -97,6 +97,68 @@ int sort_unsigned_long(unsigned long a, unsigned long b)
* Paramètres : a = premier élément à consulter et comparer. *
* b = second élément à consulter et comparer. *
* *
+* Description : Compare une valeur avec une autre. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int sort_signed_long_long(signed long long a, signed long long b)
+{
+ int result; /* Bilan à renvoyer */
+
+ if (a < b)
+ result = -1;
+
+ else if (a > b)
+ result = 1;
+
+ else
+ result = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à consulter et comparer. *
+* b = second élément à consulter et comparer. *
+* *
+* Description : Compare une valeur avec une autre. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int sort_unsigned_long_long(unsigned long long a, unsigned long long b)
+{
+ int result; /* Bilan à renvoyer */
+
+ if (a < b)
+ result = -1;
+
+ else if (a > b)
+ result = 1;
+
+ else
+ result = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à consulter et comparer. *
+* b = second élément à consulter et comparer. *
+* *
* Description : Compare une valeur de 64 bits avec une autre. *
* *
* Retour : Bilan de la comparaison. *
@@ -370,6 +432,91 @@ void *qinsert_multi(void *base, size_t *nmemb, size_t size, __compar_fn_t compar
/******************************************************************************
* *
+* Paramètres : base = adresse du tableau à parcourir. *
+* nmemb = nombre d'éléments présents au total. [OUT] *
+* allocated = taille déjà allouée pour le tableau. [OUT] *
+* size = taille de chaque élément du tableau. *
+* new = nouvel élément à insérer. *
+* index = indice du point d'insertion. *
+* *
+* Description : Ajoute à l'endroit indiqué un élément dans un tableau. *
+* *
+* Retour : Nouvel emplacement du tableau agrandi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void *_qinsert_managed(void *base, size_t *nmemb, size_t *allocated, size_t size, void *new, size_t index)
+{
+ void *result; /* Tableau trié à retourner */
+
+ if (*nmemb == *allocated)
+ {
+ if (*allocated == 0)
+ *allocated = 1024 * 8;
+ else
+ *allocated *= 2;
+
+ result = realloc(base, *allocated * size);
+
+ }
+ else
+ result = base;
+
+ if (index < *nmemb)
+ memmove((char *)result + (index + 1) * size, (char *)result + index * size, (*nmemb - index) * size);
+
+ (*nmemb)++;
+
+ memcpy((char *)result + index * size, new, size);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : base = adresse du tableau à parcourir. *
+* nmemb = nombre d'éléments présents au total. [OUT] *
+* allocated = taille déjà allouée pour le tableau. [OUT] *
+* size = taille de chaque élément du tableau. *
+* compar = méthode de comparaison entre éléments. *
+* new = nouvel élément à insérer. *
+* *
+* Description : Ajoute au bon endroit un élément dans un tableau trié. *
+* *
+* Retour : Nouvel emplacement du tableau agrandi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void *qinsert_managed(void *base, size_t *nmemb, size_t *allocated, size_t size, __compar_fn_t compar, void *new)
+{
+ void *result; /* Tableau trié à retourner */
+#ifndef NDEBUG
+ bool found; /* Présence de partage existant*/
+#endif
+ size_t index; /* Indice du point d'insertion */
+
+#ifndef NDEBUG
+ found = bsearch_index(new, base, *nmemb, size, compar, &index);
+ assert(!found);
+#else
+ bsearch_index(new, base, *nmemb, size, compar, &index);
+#endif
+
+ result = _qinsert_managed(base, nmemb, allocated, size, new, index);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : base = adresse du tableau à parcourir. *
* nmem = nombre d'éléments présents au total. [OUT] *
* size = taille de chaque élément du tableau. *
diff --git a/src/common/sort.h b/src/common/sort.h
index fbdecec..39a6f33 100644
--- a/src/common/sort.h
+++ b/src/common/sort.h
@@ -37,6 +37,12 @@ int sort_boolean(bool, bool);
/* Compare une valeur avec une autre. */
int sort_unsigned_long(unsigned long, unsigned long);
+/* Compare une valeur avec une autre. */
+int sort_signed_long_long(signed long long, signed long long);
+
+/* Compare une valeur avec une autre. */
+int sort_unsigned_long_long(unsigned long long, unsigned long long);
+
/* Compare une valeur de 64 bits avec une autre. */
int sort_uint64_t(uint64_t, uint64_t);
@@ -58,6 +64,12 @@ void *qinsert(void *, size_t *, size_t, __compar_fn_t, void *);
/* Ajoute au bon endroit un élément dans un tableau trié. */
void *qinsert_multi(void *, size_t *, size_t, __compar_fn_t, void *);
+/* Ajoute à l'endroit indiqué un élément dans un tableau. */
+void *_qinsert_managed(void *, size_t *, size_t *, size_t, void *, size_t);
+
+/* Ajoute au bon endroit un élément dans un tableau trié. */
+void *qinsert_managed(void *, size_t *, size_t *, size_t, __compar_fn_t, void *);
+
/* Supprime un élément dans un tableau trié. */
void *_qdelete(void *, size_t *, size_t, size_t);
diff --git a/src/common/szstr.h b/src/common/szstr.h
new file mode 100644
index 0000000..406a9f1
--- /dev/null
+++ b/src/common/szstr.h
@@ -0,0 +1,112 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * szstr.h - prototypes pour une manipulation de chaînes issues de Flex/Bison
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _COMMON_SZSTR_H
+#define _COMMON_SZSTR_H
+
+
+#include <string.h>
+#include <sys/types.h>
+
+
+#include "sort.h"
+#include "../arch/archbase.h"
+
+
+
+/* Structure associant une chaîne et sa taille */
+typedef struct _sized_string_t
+{
+ union {
+
+ const char *static_data; /* Données non modifiées */
+ char *data; /* Chaîne de caractères */
+
+ const bin_t *static_bin_data; /* Données brutes non modifiées*/
+ bin_t *bin_data; /* Données brutes */
+
+ };
+
+ size_t len; /* Taille correspondante */
+
+} sized_string_t;
+
+
+typedef sized_string_t sized_binary_t;
+
+
+#define init_szstr(s) \
+ do \
+ { \
+ (s)->data = NULL; \
+ (s)->len = 0; \
+ } \
+ while (0)
+
+#define szstrdup(dst, src) \
+ do \
+ { \
+ (dst)->data = malloc((src)->len); \
+ memcpy((dst)->data, (src)->data, (src)->len); \
+ (dst)->len = (src)->len; \
+ } \
+ while (0)
+
+#define copy_szstr(d, s) (d) = (s);
+
+#define exit_szstr(s) \
+ do \
+ { \
+ if ((s)->data != NULL) \
+ { \
+ free((s)->data); \
+ init_szstr(s); \
+ } \
+ } \
+ while (0)
+
+#define szstrcmp(s1, s2) \
+ ({ \
+ int __ret; \
+ size_t __n; \
+ __n = (s1)->len < (s2)->len ? (s1)->len : (s2)->len; \
+ __ret = strncmp((s1)->data, (s2)->data, __n); \
+ if (__ret == 0) \
+ __ret = sort_unsigned_long_long((s1)->len, (s2)->len); \
+ __ret; \
+ })
+
+#define szmemcmp(s1, s2) \
+ ({ \
+ int __ret; \
+ size_t __n; \
+ __n = (s1)->len < (s2)->len ? (s1)->len : (s2)->len; \
+ __ret = memcmp((s1)->data, (s2)->data, __n); \
+ if (__ret == 0) \
+ __ret = sort_unsigned_long_long((s1)->len, (s2)->len); \
+ __ret; \
+ })
+
+
+
+#endif /* _COMMON_SZSTR_H */
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 12dcddd..ac1ae14 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libcore.la
libcore_la_SOURCES = \
collections.h collections.c \
+ columns.h \
core.h core.c \
demanglers.h demanglers.c \
global.h global.c \
@@ -13,16 +14,9 @@ libcore_la_SOURCES = \
processors.h processors.c \
queue.h queue.c
-libcore_la_LDFLAGS = $(LIBGTK_LIBS) $(LIBXML_LIBS)
+libcore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libcore_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/core/collections.h b/src/core/collections.h
index 69da6f7..87f2435 100644
--- a/src/core/collections.h
+++ b/src/core/collections.h
@@ -49,4 +49,4 @@ void delete_collections_list(GList **);
-#endif /* _ANALYSIS_DB_COLLECTION_H */
+#endif /* _CORE_COLLECTIONS_H */
diff --git a/src/core/columns.h b/src/core/columns.h
new file mode 100644
index 0000000..81f78f8
--- /dev/null
+++ b/src/core/columns.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * columns.h - prototypes pour l'énumération globale des colonnes de rendu
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _CORE_COLUMNS_H
+#define _CORE_COLUMNS_H
+
+
+
+/* Désignation des colonnes d'une ligne */
+typedef enum _DisassLineColumn
+{
+ DLC_PHYSICAL, /* Position physique */
+ DLC_VIRTUAL, /* Adresse virtuelle */
+ DLC_BINARY, /* Contenu sous forme binaire */
+ DLC_ASSEMBLY_LABEL, /* Etiquette dans les données */
+ DLC_ASSEMBLY_HEAD, /* Instruction pour assembleur */
+ DLC_ASSEMBLY, /* Code pour assembleur */
+ DLC_COMMENTS, /* Commentaires éventuels */
+
+ DLC_COUNT,
+
+} DisassLineColumn;
+
+
+/* Désignation des colonnes d'une ligne */
+typedef enum _HexLineColumn
+{
+ HLC_PHYSICAL, /* Position physique */
+ HLC_BINARY, /* Données binaires brutes */
+ HLC_PADDING, /* Espacement forcé */
+ HLC_TRANSLATION, /* Traduction de contenu */
+
+ HLC_COUNT,
+
+} HexLineColumn;
+
+
+
+#endif /* _CORE_COLUMNS_H */
diff --git a/src/core/core.c b/src/core/core.c
index 62f6821..636e41e 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -31,19 +31,19 @@
#include <openssl/ssl.h>
-#include <config.h>
-
-
#include "collections.h"
#include "demanglers.h"
#include "global.h"
#include "params.h"
#include "processors.h"
#include "queue.h"
+#include "../analysis/scan/core.h"
+#ifdef INCLUDE_MAGIC_SUPPORT
+# include "../analysis/scan/items/magic/cookie.h"
+#endif
#include "../common/io.h"
#include "../common/xdg.h"
#include "../glibext/linesegment.h"
-#include "../plugins/dt.h"
@@ -65,6 +65,7 @@ bool load_all_core_components(bool cs)
char *cfgdir; /* Répertoire de configuration */
GContentExplorer *explorer; /* Explorateur de contenus */
GContentResolver *resolver; /* Résolveur de contenus */
+ GScanNamespace *root_ns; /* Espace de noms ROST racine */
/**
* On mémorise les passages réussis.
@@ -99,17 +100,28 @@ bool load_all_core_components(bool cs)
explorer = g_content_explorer_new();
set_current_content_explorer(explorer);
+ g_object_unref(G_OBJECT(explorer));
resolver = g_content_resolver_new();
set_current_content_resolver(resolver);
+ g_object_unref(G_OBJECT(resolver));
+
+#ifdef INCLUDE_MAGIC_SUPPORT
+ if (result) result = init_magic_cookie();
+#endif
+
+ root_ns = g_scan_namespace_new(NULL);
+ set_rost_root_namespace(root_ns);
+ g_object_unref(G_OBJECT(root_ns));
+
+ if (result) result = populate_main_scan_namespace(root_ns);
+ if (result) result = load_all_known_scan_token_modifiers();
if (result) result = init_segment_content_hash_table();
register_arch_gtypes();
init_operands_factory();
- if (result) result = init_chrysalide_dynamic_types();
-
}
}
@@ -135,14 +147,21 @@ void unload_all_core_components(bool cs)
{
if (cs)
{
- exit_chrysalide_dynamic_types();
-
exit_operands_factory();
+ exit_segment_content_hash_table();
+
unload_demanglers_definitions();
unload_processors_definitions();
+ unload_all_scan_token_modifiers();
+ set_rost_root_namespace(NULL);
+
+#ifdef INCLUDE_MAGIC_SUPPORT
+ exit_magic_cookie();
+#endif
+
set_current_content_resolver(NULL);
set_current_content_explorer(NULL);
@@ -160,3 +179,79 @@ void unload_all_core_components(bool cs)
ERR_free_strings();
}
+
+
+/******************************************************************************
+* *
+* Paramètres : selected = liste d'éléments à décharger. *
+* *
+* Description : Charge une sélection d'éléments de base du programme. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_core_components(AvailableCoreComponent flags)
+{
+ static bool result = false; /* Bilan à retourner */
+ static bool done = false; /* Mémorisation des passages */
+ GScanNamespace *root_ns; /* Espace de noms ROST racine */
+
+ /**
+ * On mémorise les passages réussis.
+ */
+ if (!done)
+ {
+ done = true;
+ result = true;
+
+ if (flags & ACC_SCAN_FEATURES)
+ {
+#ifdef INCLUDE_MAGIC_SUPPORT
+ if (result) result = init_magic_cookie();
+#endif
+
+ root_ns = g_scan_namespace_new(NULL);
+ set_rost_root_namespace(root_ns);
+ g_object_unref(G_OBJECT(root_ns));
+
+ if (result) result = populate_main_scan_namespace(root_ns);
+ if (result) result = load_all_known_scan_token_modifiers();
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : selected = liste d'éléments à décharger. *
+* *
+* Description : Décharge une sélection d'éléments de base du programme. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void unload_core_components(AvailableCoreComponent flags)
+{
+ if (flags & ACC_SCAN_FEATURES)
+ {
+ unload_all_scan_token_modifiers();
+ set_rost_root_namespace(NULL);
+
+#ifdef INCLUDE_MAGIC_SUPPORT
+ exit_magic_cookie();
+#endif
+
+ }
+
+}
diff --git a/src/core/core.h b/src/core/core.h
index 0221f56..def2813 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -36,5 +36,19 @@ bool load_all_core_components(bool);
void unload_all_core_components(bool);
+/* Eléments à (dé)charger disponibles */
+typedef enum _AvailableCoreComponent
+{
+ ACC_SCAN_FEATURES = (1 << 0), /* Espace de noms pour scan */
+
+} AvailableCoreComponent;
+
+/* Charge une sélection d'éléments de base du programme. */
+bool load_core_components(AvailableCoreComponent);
+
+/* Décharge une sélection d'éléments de base du programme. */
+void unload_core_components(AvailableCoreComponent);
+
+
#endif /* _CORE_CORE_H */
diff --git a/src/core/demanglers.c b/src/core/demanglers.c
index 0eb4e36..5518008 100644
--- a/src/core/demanglers.c
+++ b/src/core/demanglers.c
@@ -85,12 +85,12 @@ bool register_demangler_type(GType type)
else
{
- _demanglers_definitions = (demangler_t *)realloc(_demanglers_definitions,
- ++_demanglers_definitions_count * sizeof(demangler_t));
+ _demanglers_definitions = realloc(_demanglers_definitions,
+ ++_demanglers_definitions_count * sizeof(demangler_t));
new = &_demanglers_definitions[_demanglers_definitions_count - 1];
- new->key = strdup(key);
+ new->key = key;
new->type = type;
result = true;
diff --git a/src/core/global.c b/src/core/global.c
index 4ebb9e0..c99d711 100644
--- a/src/core/global.c
+++ b/src/core/global.c
@@ -40,6 +40,9 @@ static GContentExplorer *_explorer = NULL;
/* Résolveur de contenus */
static GContentResolver *_resolver = NULL;
+/* Espace de noms racine pour ROST */
+static GScanNamespace *_rost_root_ns = NULL;
+
/* Projet global actif */
static GStudyProject *_project = NULL;
@@ -224,6 +227,54 @@ GContentResolver *get_current_content_resolver(void)
/******************************************************************************
* *
+* Paramètres : ns = espace de noms racine de ROST. *
+* *
+* Description : Définit l'adresse de l'espace de noms principal pour ROST. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void set_rost_root_namespace(GScanNamespace *ns)
+{
+ if (_rost_root_ns != NULL)
+ g_object_unref(G_OBJECT(_rost_root_ns));
+
+ _rost_root_ns = ns;
+
+ if (ns != NULL)
+ g_object_ref_sink(G_OBJECT(ns));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit l'adresse de l'espace de noms principal pour ROST. *
+* *
+* Retour : Espace de noms racine de ROST ou NULL si aucun (!). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanNamespace *get_rost_root_namespace(void)
+{
+ assert(_rost_root_ns != NULL);
+
+ g_object_ref(G_OBJECT(_rost_root_ns));
+
+ return _rost_root_ns;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : project = éventuelle adresse du nouveau projet principal. *
* *
* Description : Définit l'adresse du projet courant. *
diff --git a/src/core/global.h b/src/core/global.h
index 088a7c9..0a9172b 100644
--- a/src/core/global.h
+++ b/src/core/global.h
@@ -30,6 +30,7 @@
#include "../analysis/loading.h"
#include "../analysis/project.h"
+#include "../analysis/scan/space.h"
#include "../glibext/delayed.h"
@@ -58,6 +59,12 @@ void set_current_content_resolver(GContentResolver *);
/* Fournit l'adresse du résolveur de contenus courant. */
GContentResolver *get_current_content_resolver(void);
+/* Définit l'adresse de l'espace de noms principal pour ROST. */
+void set_rost_root_namespace(GScanNamespace *);
+
+/* Fournit l'adresse de l'espace de noms principal pour ROST. */
+GScanNamespace *get_rost_root_namespace(void);
+
/* Définit l'adresse du projet courant. */
void set_current_project(GStudyProject *);
diff --git a/src/core/logs.c b/src/core/logs.c
index 2769bd5..2b2b1ab 100644
--- a/src/core/logs.c
+++ b/src/core/logs.c
@@ -29,8 +29,10 @@
#include "../common/extstr.h"
-#include "../gui/core/items.h"
-#include "../gui/panels/log.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../gui/core/items.h"
+# include "../gui/panels/log.h"
+#endif
@@ -107,10 +109,14 @@ void set_log_verbosity(LogMessageType level)
void log_simple_message(LogMessageType type, const char *msg)
{
+#ifdef INCLUDE_GTK_SUPPORT
GEditorItem *item; /* Eventuel affichage présent */
+#endif
if (type >= _verbosity)
{
+#ifdef INCLUDE_GTK_SUPPORT
+
item = find_editor_item_by_type(G_TYPE_LOG_PANEL);
if (item != NULL)
@@ -120,6 +126,9 @@ void log_simple_message(LogMessageType type, const char *msg)
}
else
+
+#endif
+
print_message_without_gui(type, msg);
}
diff --git a/src/core/paths.c b/src/core/paths.c
index 5902e83..c9213bc 100644
--- a/src/core/paths.c
+++ b/src/core/paths.c
@@ -125,15 +125,13 @@ char *get_effective_directory(const char *template)
char *get_effective_directory_new(TargetDirectoryType type)
{
char *result; /* Répertoire à retourner */
-#ifdef DISCARD_LOCAL
+#if defined DISCARD_LOCAL && defined PYTHON_PACKAGE
Dl_info info; /* Informations dynamiques */
int ret; /* Bilan d'une récupération */
char *dyn_path_tmp; /* Chemin d'accès modifiable */
const char *dyn_path; /* Chemin d'accès courant */
-# ifdef PYTHON_PACKAGE
size_t len; /* Taille de comparaison */
size_t pos; /* Position dans une chaîne */
-# endif
#endif
/**
@@ -155,20 +153,6 @@ char *get_effective_directory_new(TargetDirectoryType type)
result = NULL;
-#ifdef DISCARD_LOCAL
-
- ret = dladdr(__FUNCTION__, &info);
- if (ret == 0)
- {
- LOG_ERROR_DL_N("dladdr");
- goto exit;
- }
-
- dyn_path_tmp = strdup(info.dli_fname);
- dyn_path = dirname(dyn_path_tmp);
-
-#endif
-
switch (type)
{
case TDT_PLUGINS_LIB:
@@ -178,6 +162,16 @@ char *get_effective_directory_new(TargetDirectoryType type)
#else
# ifdef PYTHON_PACKAGE
+ ret = dladdr(__FUNCTION__, &info);
+ if (ret == 0)
+ {
+ LOG_ERROR_DL_N("dladdr");
+ break;
+ }
+
+ dyn_path_tmp = strdup(info.dli_fname);
+ dyn_path = dirname(dyn_path_tmp);
+
len = strlen("chrysalide-libs");
pos = strlen(dyn_path);
@@ -193,9 +187,12 @@ char *get_effective_directory_new(TargetDirectoryType type)
result[pos] = '\0';
result = stradd(result, "chrysalide-plugins");
+ bad_sync:
+
+ free(dyn_path_tmp);
+
# else
- result = strdup(dyn_path);
- result = stradd(result, G_DIR_SEPARATOR_S "chrysalide-plugins");
+ result = strdup(PLUGINS_LIB_DIR);
# endif
#endif
break;
@@ -206,20 +203,6 @@ char *get_effective_directory_new(TargetDirectoryType type)
}
-#ifdef DISCARD_LOCAL
-
-# ifdef PYTHON_PACKAGE
-
- bad_sync:
-
-# endif
-
- free(dyn_path_tmp);
-
- exit:
-
-#endif
-
assert(result != NULL);
return result;
diff --git a/src/debug/Makefile.am b/src/debug/Makefile.am
index 6cfc90f..ce21776 100644
--- a/src/debug/Makefile.am
+++ b/src/debug/Makefile.am
@@ -12,18 +12,9 @@ libdebug_la_SOURCES = \
stream-int.h \
stream.h stream.c
-libdebug_la_LIBADD =
-
-libdebug_la_CFLAGS = $(AM_CFLAGS)
+libdebug_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libdebug_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/format/Makefile.am b/src/format/Makefile.am
index 2004f93..305cd92 100644
--- a/src/format/Makefile.am
+++ b/src/format/Makefile.am
@@ -19,18 +19,9 @@ libformat_la_SOURCES = \
symbol-int.h \
symbol.h symbol.c
-libformat_la_LIBADD =
-
-libformat_la_LDFLAGS =
+libformat_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libformat_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/format/format-int.h b/src/format/format-int.h
index 3e6ae3e..f18bb24 100644
--- a/src/format/format-int.h
+++ b/src/format/format-int.h
@@ -31,7 +31,6 @@
#include "known-int.h"
#include "preload.h"
#include "../glibext/objhole.h"
-#include "../gtkext/gtkstatusstack.h"
#include "../mangling/demangler.h"
diff --git a/src/format/format.h b/src/format/format.h
index a23782c..f9aa430 100644
--- a/src/format/format.h
+++ b/src/format/format.h
@@ -34,6 +34,7 @@
#include "../analysis/content.h"
#include "../arch/context.h"
#include "../glibext/delayed.h"
+#include "../glibext/notifier.h"
diff --git a/src/format/known.h b/src/format/known.h
index 8319a63..dcc8669 100644
--- a/src/format/known.h
+++ b/src/format/known.h
@@ -31,6 +31,7 @@
#include "../analysis/content.h"
#include "../glibext/delayed.h"
+#include "../glibext/notifier.h"
diff --git a/src/format/strsym.c b/src/format/strsym.c
index d585434..c352a0e 100644
--- a/src/format/strsym.c
+++ b/src/format/strsym.c
@@ -33,7 +33,7 @@
#include "symbol-int.h"
#include "../arch/operands/feeder-int.h"
#include "../common/alloc.h"
-#include "../gtkext/gtkblockdisplay.h"
+#include "../core/columns.h"
diff --git a/src/format/symbol.c b/src/format/symbol.c
index 9b054e6..5684928 100644
--- a/src/format/symbol.c
+++ b/src/format/symbol.c
@@ -31,9 +31,11 @@
#include "symbol-int.h"
#include "../analysis/db/misc/rlestr.h"
-#include "../glibext/gbinarycursor.h"
+#include "../core/columns.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../glibext/gbinarycursor.h"
+#endif
#include "../glibext/linegen-int.h"
-#include "../gtkext/gtkblockdisplay.h"
@@ -66,12 +68,16 @@ static void g_binary_symbol_finalize(GBinSymbol *);
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_binary_symbol_count_lines(const GBinSymbol *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_binary_symbol_compute_cursor(const GBinSymbol *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_binary_symbol_contain_cursor(const GBinSymbol *, size_t, size_t, const GLineCursor *);
+#endif
+
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_binary_symbol_get_line_flags(const GBinSymbol *, size_t, size_t);
@@ -177,8 +183,10 @@ static void g_binary_symbol_init(GBinSymbol *symbol)
static void g_binary_symbol_interface_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_binary_symbol_count_lines;
+#ifdef INCLUDE_GTK_SUPPORT
iface->compute = (linegen_compute_fc)g_binary_symbol_compute_cursor;
iface->contain = (linegen_contain_fc)g_binary_symbol_contain_cursor;
+#endif
iface->get_flags = (linegen_get_flags_fc)g_binary_symbol_get_line_flags;
iface->print = (linegen_print_fc)g_binary_symbol_print;
@@ -784,6 +792,9 @@ static size_t g_binary_symbol_count_lines(const GBinSymbol *symbol)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : symbol = générateur à consulter. *
@@ -851,6 +862,9 @@ static int g_binary_symbol_contain_cursor(const GBinSymbol *symbol, size_t index
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : symbol = générateur à consulter. *
@@ -1015,7 +1029,7 @@ static bool _g_binary_symbol_load(GBinSymbol *symbol, GObjectStorage *storage, p
static bool g_binary_symbol_load(GBinSymbol *symbol, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
- GBinSymbolClass *class; /* Classe à activer */
+ GBinSymbolClass *class; /* Classe à activer */
class = G_BIN_SYMBOL_GET_CLASS(symbol);
@@ -1098,7 +1112,7 @@ static bool _g_binary_symbol_store(GBinSymbol *symbol, GObjectStorage *storage,
static bool g_binary_symbol_store(GBinSymbol *symbol, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
- GBinSymbolClass *class; /* Classe à activer */
+ GBinSymbolClass *class; /* Classe à activer */
class = G_BIN_SYMBOL_GET_CLASS(symbol);
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index 6bcf4b8..986bbd1 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -3,53 +3,60 @@ BUILT_SOURCES = chrysamarshal.h chrysamarshal.c
noinst_LTLIBRARIES = libglibext.la
-libglibext_la_SOURCES = \
- buffercache-int.h \
- buffercache.h buffercache.c \
- bufferline.h bufferline.c \
- bufferview.h bufferview.c \
- chrysamarshal.h chrysamarshal.c \
- configuration-int.h \
- configuration.h configuration.c \
- delayed-int.h \
- delayed.h delayed.c \
- gbinarycursor.h gbinarycursor.c \
- gbinportion-int.h \
- gbinportion.h gbinportion.c \
- gdisplayoptions.h gdisplayoptions.c \
- glinecursor-int.h \
- glinecursor.h glinecursor.c \
- gloadedpanel-int.h \
- gloadedpanel.h gloadedpanel.c \
- gnhash.h gnhash.c \
- linecolumn.h linecolumn.c \
- linegen-int.h \
- linegen.h linegen.c \
- linesegment.h linesegment.c \
- named-int.h \
- named.h named.c \
- objhole.h \
- proto.h \
- seq.h seq.c \
- signal.h signal.c \
- singleton.h singleton.c \
+libglibext_la_SOURCES = \
+ buffercache-int.h \
+ buffercache.h buffercache.c \
+ bufferline.h bufferline.c \
+ chrysamarshal.h chrysamarshal.c \
+ comparison-int.h \
+ comparison.h comparison.c \
+ configuration-int.h \
+ configuration.h configuration.c \
+ delayed-int.h \
+ delayed.h delayed.c \
+ gbinarycursor.h gbinarycursor.c \
+ gbinportion-int.h \
+ gbinportion.h gbinportion.c \
+ gdisplayoptions.h gdisplayoptions.c \
+ glinecursor-int.h \
+ glinecursor.h glinecursor.c \
+ gnhash.h gnhash.c \
+ linecolumn.h linecolumn.c \
+ linegen-int.h \
+ linegen.h linegen.c \
+ notifier.h \
+ objhole.h \
+ proto.h \
+ seq.h seq.c \
+ signal.h signal.c \
+ singleton.h singleton.c \
+ linesegment.h linesegment.c \
+ umemslice-int.h \
+ umemslice.h umemslice.c
+
+if BUILD_GTK_SUPPORT
+
+libglibext_la_SOURCES += \
+ bufferview.h bufferview.c \
+ gloadedpanel-int.h \
+ gloadedpanel.h gloadedpanel.c \
+ named-int.h \
+ named.h named.c \
widthtracker.h widthtracker.c
+endif
+
+libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+
libglibext_la_LIBADD = \
generators/libglibextgenerators.la
-libglibext_la_LDFLAGS =
-
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libglibext_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = generators
diff --git a/src/glibext/buffercache-int.h b/src/glibext/buffercache-int.h
index 36e4369..0e831a2 100644
--- a/src/glibext/buffercache-int.h
+++ b/src/glibext/buffercache-int.h
@@ -68,7 +68,9 @@ struct _GBufferCache
GBinContent *content; /* Contenu binaire global */
+#ifdef INCLUDE_GTK_SUPPORT
GWidthTracker *tracker; /* Suivi des largeurs */
+#endif
cache_info *lines; /* Liste des lignes intégrées */
size_t count; /* Quantité en cache */
diff --git a/src/glibext/buffercache.c b/src/glibext/buffercache.c
index fd2adc5..78c7479 100644
--- a/src/glibext/buffercache.c
+++ b/src/glibext/buffercache.c
@@ -59,9 +59,13 @@ static void get_cache_info_cursor(const cache_info *, size_t, gint, GLineCursor
/* Suivit les variations du compteur de références d'une ligne. */
static void on_line_ref_toggle(cache_info *, GBufferLine *, gboolean);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit la ligne de tampon correspondant aux générateurs. */
static GBufferLine *get_cache_info_line(cache_info *, const GWidthTracker *, size_t, const GBinContent *);
+#endif
+
/* Force la réinitialisation d'une éventuelle ligne cachée. */
static void _reset_cache_info_line_unlocked(cache_info *);
@@ -367,6 +371,9 @@ static void on_line_ref_toggle(cache_info *info, GBufferLine *line, gboolean las
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : info = informations sur une ligne à venir manipuler. *
@@ -422,6 +429,9 @@ static GBufferLine *get_cache_info_line(cache_info *info, const GWidthTracker *t
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : info = informations sur une ligne à venir manipuler. *
@@ -547,7 +557,9 @@ static void g_buffer_cache_init(GBufferCache *cache)
cache->used = 0;
g_rw_lock_init(&cache->access);
+#ifdef INCLUDE_GTK_SUPPORT
cache->tracker = NULL;
+#endif
}
@@ -587,7 +599,9 @@ static void g_buffer_cache_dispose(GBufferCache *cache)
}
+#ifdef INCLUDE_GTK_SUPPORT
g_clear_object(&cache->tracker);
+#endif
G_OBJECT_CLASS(g_buffer_cache_parent_class)->dispose(G_OBJECT(cache));
@@ -656,7 +670,9 @@ GBufferCache *g_buffer_cache_new(GBinContent *content, size_t col_count, size_t
g_object_ref(G_OBJECT(content));
}
+#ifdef INCLUDE_GTK_SUPPORT
result->tracker = g_width_tracker_new(result, col_count, opt_count);
+#endif
return result;
@@ -758,6 +774,9 @@ gint g_buffer_cache_get_text_position(const GBufferCache *cache)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : cache = composant GLib à consulter. *
@@ -783,6 +802,9 @@ GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache)
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : cache = cache de lignes à mettre à jour. *
@@ -905,7 +927,7 @@ static size_t g_buffer_cache_compute_repetition(GBufferCache *cache, size_t inde
void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator *generator, BufferLineFlags flags, bool before, bool after)
{
-#ifndef NDEBUG
+#if !defined(NDEBUG) && defined(INCLUDE_GTK_SUPPORT)
GLineCursor *gen_cursor; /* Position du générateur */
GLineCursor *line_cursor; /* Position de la ligne */
int ret; /* Bilan de comparaison */
@@ -919,7 +941,7 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
assert(!(before && after));
-#ifndef NDEBUG
+#if !defined(NDEBUG) && defined(INCLUDE_GTK_SUPPORT)
if (!before && !after)
{
@@ -981,7 +1003,9 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
cache->used += needed;
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update_added(cache->tracker, index, needed);
+#endif
g_signal_emit_by_name(cache, "size-changed", true, index, needed);
@@ -991,7 +1015,9 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
{
extend_cache_info(&cache->lines[index], generator, flags);
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update(cache->tracker, index);
+#endif
if (needed > 1)
{
@@ -1005,7 +1031,9 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
cache->used += needed - 1;
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update_added(cache->tracker, index + 1, needed - 1);
+#endif
}
@@ -1051,7 +1079,9 @@ void g_buffer_cache_delete_at(GBufferCache *cache, size_t index)
cache->used--;
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update_deleted(cache->tracker, index, index);
+#endif
g_signal_emit_by_name(cache, "size-changed", false, index, 1);
@@ -1170,7 +1200,9 @@ GLineGenerator *g_buffer_cache_delete_type_at(GBufferCache *cache, size_t index,
cache->used--;
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update_deleted(cache->tracker, delete, delete);
+#endif
g_signal_emit_by_name(cache, "size-changed", false, delete, 1);
@@ -1235,7 +1267,9 @@ void g_buffer_cache_append(GBufferCache *cache, GLineGenerator *generator, Buffe
cache->used += count;
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update_added(cache->tracker, index, count);
+#endif
g_signal_emit_by_name(cache, "size-changed", true, index, count);
@@ -1292,7 +1326,9 @@ void g_buffer_cache_extend_with(GBufferCache *cache, size_t count, GLineGenerato
if (added > 0)
{
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update_added(cache->tracker, index, added);
+#endif
g_signal_emit_by_name(cache, "size-changed", true, index, added);
@@ -1349,7 +1385,9 @@ void g_buffer_cache_truncate(GBufferCache *cache, size_t max)
cache->used = max;
+#ifdef INCLUDE_GTK_SUPPORT
g_width_tracker_update_deleted(cache->tracker, max, max + removed - 1);
+#endif
g_signal_emit_by_name(cache, "size-changed", false, max, removed);
@@ -1358,6 +1396,9 @@ void g_buffer_cache_truncate(GBufferCache *cache, size_t max)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : cache = tampon de lignes à venir consulter. *
@@ -1384,6 +1425,9 @@ void g_buffer_cache_get_line_cursor(GBufferCache *cache, size_t index, gint x, G
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : cache = tampon de lignes à venir consulter. *
@@ -1508,6 +1552,62 @@ void g_buffer_cache_remove_line_flag(GBufferCache *cache, size_t index, BufferLi
/******************************************************************************
* *
+* Paramètres : cache = tampon de lignes à consulter. *
+* start = point de départ du parcours. *
+* flag = propriétés à retrouver si possible. *
+* *
+* Description : Avance autant que possible vers une ligne idéale. *
+* *
+* Retour : Indice de la ligne recherchée, si elle existe. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_buffer_cache_look_for_flag(GBufferCache *cache, size_t start, BufferLineFlags flag)
+{
+ size_t result; /* Indice de ligne à retourner */
+ GLineCursor *init; /* Localisation de départ */
+ size_t i; /* Boucle de parcours */
+ GLineCursor *next; /* Localisation suivante */
+ int ret; /* Bilan de comparaison */
+
+ assert(!g_rw_lock_writer_trylock(&cache->access));
+
+ assert(start < cache->used);
+
+ result = start;
+
+ get_cache_info_cursor(&cache->lines[start], start, 0, &init);
+
+ for (i = start + 1; i < cache->used; i++)
+ {
+ get_cache_info_cursor(&cache->lines[i], i, 0, &next);
+
+ ret = g_line_cursor_compare(init, next);
+
+ g_object_unref(G_OBJECT(next));
+
+ if (ret != 0)
+ break;
+
+ if ((g_buffer_cache_get_line_flags(cache, i) & flag) != 0)
+ {
+ result = i;
+ break;
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(init));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : cache = tampon de lignes à venir consulter. *
* index = indice de la ligne visée par l'opération. *
* *
@@ -1536,6 +1636,9 @@ void g_buffer_cache_refresh_line(GBufferCache *cache, size_t index)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : cache = tampon de lignes à consulter. *
@@ -1659,6 +1762,9 @@ void g_buffer_cache_draw(const GBufferCache *cache, cairo_t *cr, size_t first, s
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : cache = tampon de lignes à consulter. *
@@ -1766,60 +1872,7 @@ size_t g_buffer_cache_find_index_by_cursor(GBufferCache *cache, const GLineCurso
}
-/******************************************************************************
-* *
-* Paramètres : cache = tampon de lignes à consulter. *
-* start = point de départ du parcours. *
-* flag = propriétés à retrouver si possible. *
-* *
-* Description : Avance autant que possible vers une ligne idéale. *
-* *
-* Retour : Indice de la ligne recherchée, si elle existe. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-size_t g_buffer_cache_look_for_flag(GBufferCache *cache, size_t start, BufferLineFlags flag)
-{
- size_t result; /* Indice de ligne à retourner */
- GLineCursor *init; /* Localisation de départ */
- size_t i; /* Boucle de parcours */
- GLineCursor *next; /* Localisation suivante */
- int ret; /* Bilan de comparaison */
-
- assert(!g_rw_lock_writer_trylock(&cache->access));
-
- assert(start < cache->used);
-
- result = start;
-
- get_cache_info_cursor(&cache->lines[start], start, 0, &init);
-
- for (i = start + 1; i < cache->used; i++)
- {
- get_cache_info_cursor(&cache->lines[i], i, 0, &next);
-
- ret = g_line_cursor_compare(init, next);
-
- g_object_unref(G_OBJECT(next));
-
- if (ret != 0)
- break;
-
- if ((g_buffer_cache_get_line_flags(cache, i) & flag) != 0)
- {
- result = i;
- break;
- }
-
- }
-
- g_object_unref(G_OBJECT(init));
-
- return result;
-
-}
+#ifdef INCLUDE_GTK_SUPPORT
/******************************************************************************
@@ -1888,3 +1941,6 @@ bool g_buffer_cache_get_cursor_coordinates(GBufferCache *cache, const GLineCurso
return result;
}
+
+
+#endif
diff --git a/src/glibext/buffercache.h b/src/glibext/buffercache.h
index e657fff..68941c5 100644
--- a/src/glibext/buffercache.h
+++ b/src/glibext/buffercache.h
@@ -27,12 +27,16 @@
#include <glib-object.h>
#include <stdbool.h>
-#include <gdk/gdk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gdk/gdk.h>
+#endif
#include "gdisplayoptions.h"
#include "linegen.h"
-#include "widthtracker.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "widthtracker.h"
+#endif
@@ -72,9 +76,13 @@ gint g_buffer_cache_get_left_margin(const GBufferCache *);
/* Fournit la position de départ pour l'impression de texte. */
gint g_buffer_cache_get_text_position(const GBufferCache *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit un lien vers la structure de suivi de largeurs. */
GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *);
+#endif
+
/* Met à disposition un encadrement des accès aux lignes. */
void g_buffer_cache_lock_unlock(GBufferCache *, bool, bool);
@@ -107,9 +115,13 @@ void g_buffer_cache_extend_with(GBufferCache *, size_t, GLineGenerator *);
/* Réduit le tampon à une quantité de lignes précise. */
void g_buffer_cache_truncate(GBufferCache *, size_t);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve l'emplacement correspondant à une position de ligne. */
void g_buffer_cache_get_line_cursor(GBufferCache *, size_t, gint, GLineCursor **);
+#endif
+
/* Ajoute une propriété particulière à une ligne. */
void g_buffer_cache_add_line_flag(GBufferCache *, size_t, BufferLineFlags);
@@ -119,9 +131,14 @@ BufferLineFlags g_buffer_cache_get_line_flags(GBufferCache *, size_t);
/* Retire une propriété particulière attachée à une ligne. */
void g_buffer_cache_remove_line_flag(GBufferCache *, size_t, BufferLineFlags);
+/* Avance autant que possible vers une ligne idéale. */
+size_t g_buffer_cache_look_for_flag(GBufferCache *, size_t, BufferLineFlags);
+
/* Force la mise à jour du contenu d'une ligne donnée. */
void g_buffer_cache_refresh_line(GBufferCache *, size_t);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve une ligne au sein d'un tampon avec un indice. */
GBufferLine *g_buffer_cache_find_line_by_index(GBufferCache *, size_t);
@@ -131,18 +148,21 @@ void g_buffer_cache_collect_widths(GBufferCache *, size_t, size_t, size_t, gint
/* Imprime une partie choisie du tampon contenant des lignes. */
void g_buffer_cache_draw(const GBufferCache *, cairo_t *, size_t, size_t, const cairo_rectangle_int_t *, const GDisplayOptions *, const gint *, const segcnt_list *);
+#endif
+
/* Indique l'indice correspondant à une adresse donnée. */
size_t _g_buffer_cache_find_index_by_cursor(GBufferCache *, const GLineCursor *, bool, size_t, size_t);
/* Indique l'indice correspondant à une adresse donnée. */
size_t g_buffer_cache_find_index_by_cursor(GBufferCache *, const GLineCursor *, bool);
-/* Avance autant que possible vers une ligne idéale. */
-size_t g_buffer_cache_look_for_flag(GBufferCache *, size_t, BufferLineFlags);
+#ifdef INCLUDE_GTK_SUPPORT
/* Indique la position d'affichage d'une adresse donnée. */
bool g_buffer_cache_get_cursor_coordinates(GBufferCache *, const GLineCursor *, size_t, size_t, bool, gint *, gint *);
+#endif
+
#endif /* _GLIBEXT_BUFFERCACHE_H */
diff --git a/src/glibext/bufferline.c b/src/glibext/bufferline.c
index 85fe027..2bdfebc 100644
--- a/src/glibext/bufferline.c
+++ b/src/glibext/bufferline.c
@@ -33,7 +33,6 @@
#include "linecolumn.h"
#include "../common/extstr.h"
#include "../core/paths.h"
-#include "../gtkext/gtkblockdisplay.h"
@@ -70,8 +69,10 @@ struct _GBufferLineClass
{
GObjectClass parent; /* A laisser en premier */
+#ifdef INCLUDE_GTK_SUPPORT
cairo_surface_t *entrypoint_img; /* Image pour les entrées */
cairo_surface_t *bookmark_img; /* Image pour les signets */
+#endif
/* Signaux */
@@ -121,13 +122,17 @@ G_DEFINE_TYPE(GBufferLine, g_buffer_line, G_TYPE_OBJECT);
static void g_buffer_line_class_init(GBufferLineClass *class)
{
GObjectClass *object; /* Autre version de la classe */
+#ifdef INCLUDE_GTK_SUPPORT
gchar *filename; /* Chemin d'accès à utiliser */
+#endif
object = G_OBJECT_CLASS(class);
object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_line_dispose;
object->finalize = (GObjectFinalizeFunc)g_buffer_line_finalize;
+#ifdef INCLUDE_GTK_SUPPORT
+
filename = find_pixmap_file("entrypoint.png");
assert(filename != NULL);
@@ -142,6 +147,8 @@ static void g_buffer_line_class_init(GBufferLineClass *class)
g_free(filename);
+#endif
+
g_signal_new("content-changed",
G_TYPE_BUFFER_LINE,
G_SIGNAL_RUN_LAST,
@@ -885,6 +892,9 @@ void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferE
/* ---------------------------------------------------------------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : line = ligne à venir consulter. *
@@ -1479,3 +1489,6 @@ void g_buffer_line_draw(GBufferLine *line, size_t index, cairo_t *cairo, gint x_
}
}
+
+
+#endif
diff --git a/src/glibext/bufferline.h b/src/glibext/bufferline.h
index 791fd5d..f5f25d0 100644
--- a/src/glibext/bufferline.h
+++ b/src/glibext/bufferline.h
@@ -31,7 +31,9 @@
#include "gdisplayoptions.h"
#include "linesegment.h"
-#include "widthtracker.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "widthtracker.h"
+#endif
#include "../analysis/content.h"
#include "../arch/vmpa.h"
@@ -139,6 +141,8 @@ typedef struct _col_coord_t
} col_coord_t;
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fait remonter les largeurs requises par une ligne donnée. */
void g_buffer_line_collect_widths(const GBufferLine *, size_t, size_t, gint *, gint *);
@@ -160,6 +164,8 @@ bool g_buffer_line_find_near_coord(const GBufferLine *, size_t, col_coord_t *, G
/* Imprime la ligne de texte représentée. */
void g_buffer_line_draw(GBufferLine *, size_t, cairo_t *, gint, gint, GWidthTracker *, const GDisplayOptions *, const segcnt_list *);
+#endif
+
#endif /* _GLIBEXT_BUFFERLINE_H */
diff --git a/src/glibext/comparison-int.h b/src/glibext/comparison-int.h
new file mode 100644
index 0000000..446f25d
--- /dev/null
+++ b/src/glibext/comparison-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparison-int.h - définitions internes propres aux opérations de comparaison d'objets
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_COMPARISON_INT_H
+#define _GLIBEXT_COMPARISON_INT_H
+
+
+#include "comparison.h"
+
+
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+typedef bool (* compare_rich_fc) (const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *);
+
+
+/* Instance d'élément comparable (interface) */
+struct _GComparableItemIface
+{
+ GTypeInterface base_iface; /* A laisser en premier */
+
+ compare_rich_fc cmp_rich; /* Comparaison de façon précise*/
+
+};
+
+
+/* Redéfinition */
+typedef GComparableItemIface GComparableItemInterface;
+
+
+/* Réalise une comparaison riche entre valeurs entière. */
+bool compare_rich_integer_values_signed(long long, long long, RichCmpOperation);
+
+/* Réalise une comparaison riche entre valeurs entière. */
+bool compare_rich_integer_values_unsigned(unsigned long long, unsigned long long, RichCmpOperation);
+
+
+
+#endif /* _GLIBEXT_COMPARISON_INT_H */
diff --git a/src/glibext/comparison.c b/src/glibext/comparison.c
new file mode 100644
index 0000000..8ce6941
--- /dev/null
+++ b/src/glibext/comparison.c
@@ -0,0 +1,199 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparison.c - opérations de comparaison d'objets
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "comparison.h"
+
+
+#include <assert.h>
+
+
+#include "comparison-int.h"
+
+
+
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_comparable_item_default_init(GComparableItemInterface *);
+
+
+
+/* Détermine le type d'une interface pour un objet comparable. */
+G_DEFINE_INTERFACE(GComparableItem, g_comparable_item, G_TYPE_OBJECT)
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_comparable_item_default_init(GComparableItemInterface *iface)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* status = bilan des opérations de comparaison. [OUT] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+ GComparableItemIface *iface; /* Interface utilisée */
+
+ iface = G_COMPARABLE_ITEM_GET_IFACE(item);
+
+ result = iface->cmp_rich(item, other, op, status);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à consulter pour une comparaison. *
+* b = second objet à consulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* *
+* Description : Réalise une comparaison riche entre valeurs entière. *
+* *
+* Retour : Bilan des opérations de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool compare_rich_integer_values_signed(long long a, long long b, RichCmpOperation op)
+{
+ bool result; /* Bilan à retourner */
+
+ switch (op)
+ {
+ case RCO_LT:
+ result = (a < b);
+ break;
+
+ case RCO_LE:
+ result = (a <= b);
+ break;
+
+ case RCO_EQ:
+ result = (a == b);
+ break;
+
+ case RCO_NE:
+ result = (a != b);
+ break;
+
+ case RCO_GT:
+ result = (a > b);
+ break;
+
+ case RCO_GE:
+ result = (a >= b);
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à consulter pour une comparaison. *
+* b = second objet à consulter pour une comparaison. *
+* op = opération de comparaison à réaliser. *
+* *
+* Description : Réalise une comparaison riche entre valeurs entière. *
+* *
+* Retour : Bilan des opérations de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool compare_rich_integer_values_unsigned(unsigned long long a, unsigned long long b, RichCmpOperation op)
+{
+ bool result; /* Bilan à retourner */
+
+ switch (op)
+ {
+ case RCO_LT:
+ result = (a < b);
+ break;
+
+ case RCO_LE:
+ result = (a <= b);
+ break;
+
+ case RCO_EQ:
+ result = (a == b);
+ break;
+
+ case RCO_NE:
+ result = (a != b);
+ break;
+
+ case RCO_GT:
+ result = (a > b);
+ break;
+
+ case RCO_GE:
+ result = (a >= b);
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/glibext/comparison.h b/src/glibext/comparison.h
new file mode 100644
index 0000000..8d43210
--- /dev/null
+++ b/src/glibext/comparison.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparison.h - prototypes pour les opérations de comparaison d'objets
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_COMPARISON_H
+#define _GLIBEXT_COMPARISON_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+
+#define G_TYPE_COMPARABLE_ITEM (g_comparable_item_get_type())
+#define G_COMPARABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_COMPARABLE_ITEM, GComparableItem))
+#define G_COMPARABLE_ITEM_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_COMPARABLE_ITEM, GComparableItemIface))
+#define G_IS_COMPARABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_COMPARABLE_ITEM))
+#define G_IS_COMPARABLE_ITEM_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE((vtable), G_TYPE_COMPARABLE_ITEM))
+#define G_COMPARABLE_ITEM_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), G_TYPE_COMPARABLE_ITEM, GComparableItemIface))
+
+
+/* Instance d'élément comparable (coquille vide) */
+typedef struct _GComparableItem GComparableItem;
+
+/* Instance d'élément comparable (interface) */
+typedef struct _GComparableItemIface GComparableItemIface;
+
+
+/* Modes de comparaison */
+typedef enum _RichCmpOperation
+{
+ RCO_LT, /* Equivalent de '<' */
+ RCO_LE, /* Equivalent de '<=' */
+ RCO_EQ, /* Equivalent de '==' */
+ RCO_NE, /* Equivalent de '!=' */
+ RCO_GT, /* Equivalent de '>' */
+ RCO_GE, /* Equivalent de '>°' */
+
+} RichCmpOperation;
+
+/* Détermination d'un besoin de comparaison supplémentaire */
+#define STATUS_NOT_EQUAL(_s, _o) \
+ ({ \
+ bool __result; \
+ if (_o == RCO_LE || _o == RCO_EQ || _o == RCO_GE) \
+ __result = !_s; \
+ else \
+ __result = _s; \
+ __result; \
+ })
+
+
+/* Détermine le type d'une interface pour un objet comparable. */
+GType g_comparable_item_get_type(void) G_GNUC_CONST;
+
+/* Réalise une comparaison entre objets selon un critère précis. */
+bool g_comparable_item_compare_rich(const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *);
+
+
+
+#endif /* _GLIBEXT_COMPARISON_H */
diff --git a/src/glibext/configuration.c b/src/glibext/configuration.c
index 5bc94a7..ce7fac8 100644
--- a/src/glibext/configuration.c
+++ b/src/glibext/configuration.c
@@ -1224,13 +1224,9 @@ static void g_generic_config_init(GGenConfig *config)
static void g_generic_config_dispose(GGenConfig *config)
{
- g_list_free_full(config->groups, g_object_unref);
+ g_clear_list(&config->groups, g_object_unref);
- config->groups = NULL;
-
- g_list_free_full(config->params, g_object_unref);
-
- config->params = NULL;
+ g_clear_list(&config->params, g_object_unref);
G_OBJECT_CLASS(g_generic_config_parent_class)->dispose(G_OBJECT(config));
diff --git a/src/glibext/configuration.h b/src/glibext/configuration.h
index aac6dc7..05dbc65 100644
--- a/src/glibext/configuration.h
+++ b/src/glibext/configuration.h
@@ -27,7 +27,28 @@
#include <glib-object.h>
#include <stdbool.h>
-#include <gdk/gdk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gdk/gdk.h>
+#endif
+
+
+#if !defined(INCLUDE_GTK_SUPPORT) && !defined(HOMEMADE_RGBA)
+
+# define HOMEMADE_RGBA
+
+/**
+ * Copie depuis /usr/include/gtk-3.0/gdk/gdkrgba.h
+ */
+typedef struct _GdkRGBA
+{
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+ gdouble alpha;
+
+} GdkRGBA;
+
+#endif
diff --git a/src/glibext/delayed-int.h b/src/glibext/delayed-int.h
index dd780d0..4f84e86 100644
--- a/src/glibext/delayed-int.h
+++ b/src/glibext/delayed-int.h
@@ -28,8 +28,8 @@
#include "delayed.h"
+#include "notifier.h"
#include "../common/dllist.h"
-#include "../gtkext/gtkstatusstack.h"
diff --git a/src/glibext/delayed.c b/src/glibext/delayed.c
index ec4063d..6b5ac35 100644
--- a/src/glibext/delayed.c
+++ b/src/glibext/delayed.c
@@ -33,7 +33,9 @@
#include "delayed-int.h"
#include "../core/nproc.h"
-#include "../gui/core/global.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../gui/core/global.h"
+#endif
@@ -612,7 +614,11 @@ static void *g_work_group_process(GWorkGroup *group)
g_mutex_unlock(&group->mutex);
+#ifdef INCLUDE_GTK_SUPPORT
status = get_global_status();
+#else
+ status = NULL;
+#endif
g_delayed_work_process(work, status);
g_object_unref(G_OBJECT(work));
@@ -879,7 +885,7 @@ static void g_work_queue_dispose(GWorkQueue *queue)
g_mutex_lock(&queue->mutex);
for (i = 0; i < queue->groups_count; i++)
- g_object_unref(G_OBJECT(queue->groups[i]));
+ g_clear_object(&queue->groups[i]);
g_mutex_unlock(&queue->mutex);
diff --git a/src/glibext/delayed.h b/src/glibext/delayed.h
index 0fc7e7a..89eed12 100644
--- a/src/glibext/delayed.h
+++ b/src/glibext/delayed.h
@@ -31,11 +31,6 @@
-/* Abstration d'une gestion de barre de statut (instance) */
-typedef struct _GtkStatusStack GtkStatusStack;
-
-
-
/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */
diff --git a/src/glibext/gbinarycursor.c b/src/glibext/gbinarycursor.c
index 5308fdf..d62abfb 100644
--- a/src/glibext/gbinarycursor.c
+++ b/src/glibext/gbinarycursor.c
@@ -25,9 +25,15 @@
#include <assert.h>
+#include <malloc.h>
+
+
+#include <i18n.h>
#include "glinecursor-int.h"
+#include "../analysis/binary.h"
+#include "../common/extstr.h"
@@ -76,6 +82,11 @@ static bool g_binary_cursor_is_valid(const GBinaryCursor *);
/* Construit une étiquette de représentation d'un suivi. */
static char *g_binary_cursor_build_label(const GBinaryCursor *);
+/* Extrait des détails complémentaires et actualise le statut. */
+#ifdef INCLUDE_GTK_SUPPORT
+static void prepare_and_show_status_from_binary_cursor(const mrange_t *, const char *, const GLoadedBinary *, GtkStatusStack *);
+#endif
+
/* Affiche une position dans une barre de statut. */
static void g_binary_cursor_show_status(const GBinaryCursor *, GtkStatusStack *, GLoadedContent *);
@@ -333,6 +344,93 @@ static char *g_binary_cursor_build_label(const GBinaryCursor *cursor)
/******************************************************************************
* *
+* Paramètres : range = emplacement à mettre en valeur. *
+* encoding = encodage d'une éventuelle instruction ou NULL. *
+* binary = binaire chargé rassemblant l'ensemble des infos. *
+* stack = barre de statut à actualiser. *
+* *
+* Description : Extrait des détails complémentaires et actualise le statut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+#ifdef INCLUDE_GTK_SUPPORT
+static void prepare_and_show_status_from_binary_cursor(const mrange_t *range, const char *encoding, const GLoadedBinary *binary, GtkStatusStack *stack)
+{
+ GExeFormat *format; /* Format de binaire à traiter */
+ const vmpa2t *addr; /* Localisation de départ */
+ GBinPortion *portions; /* Couche première de portions */
+ GBinPortion *portion; /* Zone mémoire d'appartenance */
+ const char *text; /* Texte au contenu à copier */
+ const char *segment; /* Désignation d'un segment */
+ GBinSymbol *symbol; /* Symbole présent à l'adresse */
+ phys_t diff; /* Décalage de l'adresse */
+ char *label; /* Description d'un symbole */
+ vmpa2t tmp; /* Zone de construction temp. */
+ VMPA_BUFFER(offset); /* Décalage physique */
+ char *sym_name; /* Position selon un symbole */
+
+ /* Préparations utiles */
+
+ format = g_loaded_binary_get_format(binary);
+
+ addr = get_mrange_addr(range);
+
+ /* Zone d'appartenance */
+
+ portions = g_exe_format_get_portions(format);
+
+ portion = g_binary_portion_find_at_addr(portions, addr);
+
+ text = g_binary_portion_get_desc(portion);
+
+ segment = (text != NULL ? text : _("Binary"));
+
+ g_object_unref(G_OBJECT(portion));
+
+ g_object_unref(G_OBJECT(portions));
+
+ /* Symbole concerné */
+
+ sym_name = NULL;
+
+ if (g_binary_format_resolve_symbol(G_BIN_FORMAT(format), addr, false, &symbol, &diff))
+ {
+ label = g_binary_symbol_get_label(symbol);
+
+ if (label != NULL)
+ {
+ sym_name = label;
+
+ sym_name = stradd(sym_name, "+");
+
+ init_vmpa(&tmp, diff, VMPA_NO_VIRTUAL);
+ vmpa2_phys_to_string(&tmp, MDS_UNDEFINED, offset, NULL);
+
+ sym_name = stradd(sym_name, offset);
+
+ }
+
+ g_object_unref(G_OBJECT(symbol));
+
+ }
+
+ /* Demande d'affichage final */
+
+ gtk_status_stack_update_current_location(stack, range, segment, sym_name, encoding);
+
+ if (sym_name != NULL)
+ free(sym_name);
+
+}
+#endif
+
+
+/******************************************************************************
+* *
* Paramètres : cursor = emplacement du curseur à afficher. *
* stack = pile de statuts à mettre à jour. *
* content = contenu contenant le curseur à représenter. *
@@ -347,6 +445,7 @@ static char *g_binary_cursor_build_label(const GBinaryCursor *cursor)
static void g_binary_cursor_show_status(const GBinaryCursor *cursor, GtkStatusStack *stack, GLoadedContent *content)
{
+#ifdef INCLUDE_GTK_SUPPORT
GLoadedBinary *binary; /* Binaire chargé et analysé */
GArchProcessor *proc; /* Architecture du binaire */
mrange_t tmp; /* Emplacement réduit */
@@ -364,7 +463,7 @@ static void g_binary_cursor_show_status(const GBinaryCursor *cursor, GtkStatusSt
{
init_mrange(&tmp, &cursor->addr, VMPA_NO_PHYSICAL);
- gtk_status_stack_update_current_location(stack, binary, &tmp, NULL);
+ prepare_and_show_status_from_binary_cursor(&tmp, NULL, binary, stack);
}
@@ -378,7 +477,7 @@ static void g_binary_cursor_show_status(const GBinaryCursor *cursor, GtkStatusSt
range = g_arch_instruction_get_range(instr);
encoding = g_arch_instruction_get_encoding(instr);
- gtk_status_stack_update_current_location(stack, binary, range, encoding);
+ prepare_and_show_status_from_binary_cursor(range, encoding, binary, stack);
g_object_unref(G_OBJECT(instr));
@@ -390,7 +489,7 @@ static void g_binary_cursor_show_status(const GBinaryCursor *cursor, GtkStatusSt
else
gtk_status_stack_reset_current_location(stack);
-
+#endif
}
diff --git a/src/glibext/gbinportion-int.h b/src/glibext/gbinportion-int.h
index b5c70c8..a29f53c 100644
--- a/src/glibext/gbinportion-int.h
+++ b/src/glibext/gbinportion-int.h
@@ -36,7 +36,9 @@ struct _GBinPortion
char *code; /* Code de la couleur de fond */
+#ifdef INCLUDE_GTK_SUPPORT
cairo_surface_t *icon; /* Image de représentation */
+#endif
char *desc; /* Désignation humaine */
char **text; /* Lignes brutes à représenter */
diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c
index 884c31d..12e12fb 100644
--- a/src/glibext/gbinportion.c
+++ b/src/glibext/gbinportion.c
@@ -38,9 +38,9 @@
#include "../analysis/human/asm/lang.h"
#include "../common/extstr.h"
#include "../common/sort.h"
+#include "../core/columns.h"
#include "../glibext/gbinarycursor.h"
#include "../glibext/linegen-int.h"
-#include "../gtkext/gtkblockdisplay.h"
@@ -62,9 +62,13 @@ static void g_binary_portion_dispose(GBinPortion *);
/* Procède à la libération totale de la mémoire. */
static void g_binary_portion_finalize(GBinPortion *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Détermine l'aire d'une sous-portion. */
static bool g_binary_portion_compute_sub_area(const GBinPortion *, phys_t, const GdkRectangle *, GdkRectangle *);
+#endif
+
/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
@@ -73,12 +77,16 @@ static bool g_binary_portion_compute_sub_area(const GBinPortion *, phys_t, const
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_binary_portion_count_lines(const GBinPortion *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_binary_portion_compute_cursor(const GBinPortion *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_binary_portion_contain_cursor(const GBinPortion *, size_t, size_t, const GLineCursor *);
+#endif
+
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_binary_portion_get_flags(const GBinPortion *, size_t, size_t);
@@ -93,12 +101,19 @@ static void g_binary_portion_print(GBinPortion *, GBufferLine *, size_t, size_t,
/* Détermine si une portion contient une adresse donnée. */
static bool g_binary_portion_contains_vmpa(const GBinPortion *, const vmpa2t *);
+#ifdef INCLUDE_GTK_SUPPORT
+
+/* Recherche la portion présente à une adresse donnée. */
+static GBinPortion *g_binary_portion_find_with_area_at_addr(GBinPortion *, const vmpa2t *, GdkRectangle *);
+
/* Détermine si une portion contient une position donnée. */
static bool g_binary_portion_contains_physical(const GBinPortion *, phys_t);
/* Détermine si une portion contient une adresse donnée. */
static bool g_binary_portion_contains_virtual(const GBinPortion *, virt_t);
+#endif
+
/* ---------------------------------------------------------------------------------- */
@@ -154,6 +169,10 @@ static void g_binary_portion_init(GBinPortion *portion)
portion->code = NULL;
+#ifdef INCLUDE_GTK_SUPPORT
+ portion->icon = NULL;
+#endif
+
portion->desc = NULL;
portion->text = NULL;
portion->lcount = 0;
@@ -181,8 +200,10 @@ static void g_binary_portion_init(GBinPortion *portion)
static void g_binary_portion_interface_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_binary_portion_count_lines;
+#ifdef INCLUDE_GTK_SUPPORT
iface->compute = (linegen_compute_fc)g_binary_portion_compute_cursor;
iface->contain = (linegen_contain_fc)g_binary_portion_contain_cursor;
+#endif
iface->get_flags = (linegen_get_flags_fc)g_binary_portion_get_flags;
iface->print = (linegen_print_fc)g_binary_portion_print;
@@ -232,8 +253,10 @@ static void g_binary_portion_finalize(GBinPortion *portion)
if (portion->code != NULL)
free(portion->code);
+#ifdef INCLUDE_GTK_SUPPORT
if (portion->icon != NULL)
cairo_surface_destroy(portion->icon);
+#endif
if (portion->desc != NULL)
free(portion->desc);
@@ -310,6 +333,9 @@ int g_binary_portion_compare(const GBinPortion **a, const GBinPortion **b)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : portion = description de partie à mettre à jour. *
@@ -360,6 +386,9 @@ cairo_surface_t *g_binary_portion_get_icon(const GBinPortion *portion)
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : portion = description de partie à mettre à jour. *
@@ -588,6 +617,9 @@ PortionAccessRights g_binary_portion_get_rights(const GBinPortion *portion)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : portion = description de partie à mettre à jour. *
@@ -669,6 +701,9 @@ void g_binary_portion_query_tooltip(GBinPortion *portion, GtkTooltip *tooltip)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : portion = portion mère à consulter. *
@@ -707,6 +742,9 @@ static bool g_binary_portion_compute_sub_area(const GBinPortion *portion, phys_t
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : portion = description de partie à consulter. *
@@ -762,6 +800,9 @@ void g_binary_portion_draw(const GBinPortion *portion, GtkStyleContext *context,
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : portion = portion principale à compléter. *
@@ -1025,6 +1066,9 @@ static size_t g_binary_portion_count_lines(const GBinPortion *portion)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : portion = générateur à consulter. *
@@ -1081,6 +1125,9 @@ static int g_binary_portion_contain_cursor(const GBinPortion *portion, size_t in
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : portion = générateur à consulter. *
@@ -1143,6 +1190,9 @@ static void g_binary_portion_print(GBinPortion *portion, GBufferLine *line, size
/* ---------------------------------------------------------------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : portion = couche de portions à parcourir pour les recherches.*
@@ -1237,6 +1287,9 @@ GBinPortion *g_binary_portion_find_at_pos(GBinPortion *portion, gint x, GdkRecta
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : portion = portion mère à consulter. *
@@ -1276,6 +1329,55 @@ static bool g_binary_portion_contains_vmpa(const GBinPortion *portion, const vmp
* *
* Paramètres : portion = couche de portions à parcourir pour les recherches.*
* addr = adresse du point de recherche. *
+* *
+* Description : Recherche la portion présente à une adresse donnée. *
+* *
+* Retour : Portion trouvée à l'endroit indiqué. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBinPortion *g_binary_portion_find_at_addr(GBinPortion *portion, const vmpa2t *addr)
+{
+ GBinPortion *result; /* Portion à retourner */
+ phys_t full; /* Espace total représenté */
+ size_t i; /* Boucle de parcours #1 */
+ GBinPortion *sub; /* Portion incluse à traiter */
+
+ result = NULL;
+
+ full = get_mrange_length(&portion->range);
+
+ for (i = 0; i < portion->count && result == NULL; i++)
+ {
+ sub = portion->subs[i];
+
+ if (!g_binary_portion_contains_vmpa(sub, addr))
+ continue;
+
+ result = g_binary_portion_find_at_addr(sub, addr);
+
+ }
+
+ if (result == NULL)
+ {
+ result = portion;
+ g_object_ref(G_OBJECT(result));
+ }
+
+ return result;
+
+}
+
+
+#ifdef INCLUDE_GTK_SUPPORT
+
+
+/******************************************************************************
+* *
+* Paramètres : portion = couche de portions à parcourir pour les recherches.*
+* addr = adresse du point de recherche. *
* area = étendue de portion mère, puis celle trouvée. [OUT] *
* *
* Description : Recherche la portion présente à une adresse donnée. *
@@ -1286,7 +1388,7 @@ static bool g_binary_portion_contains_vmpa(const GBinPortion *portion, const vmp
* *
******************************************************************************/
-GBinPortion *g_binary_portion_find_at_addr(GBinPortion *portion, const vmpa2t *addr, GdkRectangle *area)
+static GBinPortion *g_binary_portion_find_with_area_at_addr(GBinPortion *portion, const vmpa2t *addr, GdkRectangle *area)
{
GBinPortion *result; /* Portion à retourner */
phys_t full; /* Espace total représenté */
@@ -1308,7 +1410,7 @@ GBinPortion *g_binary_portion_find_at_addr(GBinPortion *portion, const vmpa2t *a
if (!g_binary_portion_compute_sub_area(sub, full, area, &sub_area))
continue;
- result = g_binary_portion_find_at_addr(sub, addr, &sub_area);
+ result = g_binary_portion_find_with_area_at_addr(sub, addr, &sub_area);
if (result != NULL)
*area = sub_area;
@@ -1385,7 +1487,7 @@ bool get_binary_portion_pos_from_addr(GBinPortion *root, const vmpa2t *addr, con
owner_area = *area;
- owner = g_binary_portion_find_at_addr(root, addr, &owner_area);
+ owner = g_binary_portion_find_with_area_at_addr(root, addr, &owner_area);
if (owner == NULL) return false;
diff = compute_vmpa_diff(addr, get_mrange_addr(&owner->range));
@@ -1431,6 +1533,9 @@ gboolean query_tooltip_for_binary_portion(GBinPortion *root, gint x, gint y, con
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : portion = portion mère à consulter. *
diff --git a/src/glibext/gbinportion.h b/src/glibext/gbinportion.h
index 3a960b7..ea4b4aa 100644
--- a/src/glibext/gbinportion.h
+++ b/src/glibext/gbinportion.h
@@ -27,7 +27,9 @@
#include <glib-object.h>
#include <stdbool.h>
-#include <gtk/gtk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gtk/gtk.h>
+#endif
#include "../arch/vmpa.h"
@@ -87,12 +89,16 @@ GBinPortion *g_binary_portion_new(const char *, const vmpa2t *, phys_t);
/* Etablit la comparaison ascendante entre deux portions. */
int g_binary_portion_compare(const GBinPortion **, const GBinPortion **);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Attribue à la portion une éventuelle image de représentation. */
void g_binary_portion_set_icon(GBinPortion *, cairo_surface_t *);
/* Fournit une éventuelle image de représentation de portion. */
cairo_surface_t *g_binary_portion_get_icon(const GBinPortion *);
+#endif
+
/* Attribue une description humaine à une partie de code. */
void g_binary_portion_set_desc(GBinPortion *, const char *);
@@ -117,12 +123,16 @@ void g_binary_portion_set_rights(GBinPortion *, PortionAccessRights);
/* Fournit les droits associés à une partie de code. */
PortionAccessRights g_binary_portion_get_rights(const GBinPortion *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Prépare une astuce concernant une portion pour son affichage. */
void g_binary_portion_query_tooltip(GBinPortion *, GtkTooltip *);
/* Représente la portion sur une bande dédiée. */
void g_binary_portion_draw(const GBinPortion *, GtkStyleContext *, cairo_t *, const GdkRectangle *);
+#endif
+
/* Procède à l'inclusion d'une portion dans une autre. */
void g_binary_portion_include(GBinPortion *, GBinPortion *);
@@ -147,14 +157,20 @@ bool g_binary_portion_visit(GBinPortion *, visit_portion_fc, void *);
/* ------------------------ PARCOURS D'ENSEMBLES DE PORTIONS ------------------------ */
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Compte le nombre de portions présentes dans une arborescence. */
size_t g_binary_portion_count(const GBinPortion *);
/* Recherche la portion présente à un point donné. */
GBinPortion *g_binary_portion_find_at_pos(GBinPortion *, gint, GdkRectangle *);
+#endif
+
/* Recherche la portion présente à une adresse donnée. */
-GBinPortion *g_binary_portion_find_at_addr(GBinPortion *, const vmpa2t *, GdkRectangle *);
+GBinPortion *g_binary_portion_find_at_addr(GBinPortion *, const vmpa2t *);
+
+#ifdef INCLUDE_GTK_SUPPORT
/* Fournit la position correspondant à une adresse donnée. */
bool get_binary_portion_addr_from_pos(GBinPortion *, gint, const GdkRectangle *, vmpa2t *);
@@ -165,6 +181,8 @@ bool get_binary_portion_pos_from_addr(GBinPortion *, const vmpa2t *, const GdkRe
/* Prépare une astuce concernant une portion pour son affichage. */
gboolean query_tooltip_for_binary_portion(GBinPortion *, gint, gint, const GdkRectangle *, GtkTooltip *);
+#endif
+
/* Fournit l'emplacement correspondant à une position physique. */
bool g_binary_portion_translate_offset_into_vmpa(const GBinPortion *, phys_t, vmpa2t *);
diff --git a/src/glibext/generators/Makefile.am b/src/glibext/generators/Makefile.am
index c448bb7..a332498 100644
--- a/src/glibext/generators/Makefile.am
+++ b/src/glibext/generators/Makefile.am
@@ -1,21 +1,21 @@
noinst_LTLIBRARIES = libglibextgenerators.la
-libglibextgenerators_la_SOURCES = \
- hex.h hex.c \
- prologue.h prologue.c \
- rborder.h rborder.c
-libglibextgenerators_la_LDFLAGS =
+libglibextgenerators_la_SOURCES = \
+ prologue.h prologue.c \
+ rborder.h rborder.c
+if BUILD_GTK_SUPPORT
-devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+libglibextgenerators_la_SOURCES += \
+ hex.h hex.c
-dev_HEADERS = $(libglibextgenerators_la_SOURCES:%c=)
+endif
+libglibextgenerators_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
-SUBDIRS =
+dev_HEADERS = $(libglibextgenerators_la_SOURCES:%c=)
diff --git a/src/glibext/generators/hex.c b/src/glibext/generators/hex.c
index 7de2d6b..668ebae 100644
--- a/src/glibext/generators/hex.c
+++ b/src/glibext/generators/hex.c
@@ -32,11 +32,15 @@
#include "../gbinarycursor.h"
#include "../linegen-int.h"
#include "../linesegment.h"
+#include "../../core/columns.h"
#include "../../core/params.h"
#include "../../gtkext/hexdisplay.h"
+/* --------------------------- RENDU AMIQUE D'HEXADECIMAL --------------------------- */
+
+
/* Tampon pour générateur de lignes hexadécimales (instance) */
struct _GHexGenerator
{
@@ -79,15 +83,24 @@ static void g_hex_generator_dispose(GHexGenerator *);
/* Procède à la libération totale de la mémoire. */
static void g_hex_generator_finalize(GHexGenerator *);
+
+
+/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+
+
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_hex_generator_count_lines(const GHexGenerator *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_hex_generator_compute_cursor(const GHexGenerator *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_hex_generator_contain_cursor(const GHexGenerator *, size_t, size_t, const GLineCursor *);
+#endif
+
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_hex_generator_get_flags(const GHexGenerator *, size_t, size_t);
@@ -96,6 +109,11 @@ static void g_hex_generator_print(GHexGenerator *, GBufferLine *, size_t, size_t
+/* ---------------------------------------------------------------------------------- */
+/* RENDU AMIQUE D'HEXADECIMAL */
+/* ---------------------------------------------------------------------------------- */
+
+
/* Détermine le type du générateur de lignes hexadécimales à la volée. */
G_DEFINE_TYPE_WITH_CODE(GHexGenerator, g_hex_generator, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_hex_generator_interface_init));
@@ -186,8 +204,10 @@ static void g_hex_generator_init(GHexGenerator *generator)
static void g_hex_generator_interface_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_hex_generator_count_lines;
+#ifdef INCLUDE_GTK_SUPPORT
iface->compute = (linegen_compute_fc)g_hex_generator_compute_cursor;
iface->contain = (linegen_contain_fc)g_hex_generator_contain_cursor;
+#endif
iface->get_flags = (linegen_get_flags_fc)g_hex_generator_get_flags;
iface->print = (linegen_print_fc)g_hex_generator_print;
@@ -262,6 +282,12 @@ GHexGenerator *g_hex_generator_new(GBinContent *content)
}
+
+/* ---------------------------------------------------------------------------------- */
+/* OFFRE DE CAPACITES DE GENERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
@@ -291,6 +317,9 @@ static size_t g_hex_generator_count_lines(const GHexGenerator *generator)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
@@ -407,6 +436,9 @@ static int g_hex_generator_contain_cursor(const GHexGenerator *generator, size_t
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
diff --git a/src/glibext/generators/prologue.c b/src/glibext/generators/prologue.c
index e19107b..6b3260d 100644
--- a/src/glibext/generators/prologue.c
+++ b/src/glibext/generators/prologue.c
@@ -29,14 +29,19 @@
#include "../bufferline.h"
-#include "../gbinarycursor.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../gbinarycursor.h"
+#endif
#include "../linegen-int.h"
#include "../linesegment.h"
+#include "../../core/columns.h"
#include "../../format/executable.h"
-#include "../../gtkext/gtkblockdisplay.h"
+/* ------------------------- MARQUE D'INTRODUCTION DE RENDU ------------------------- */
+
+
/* Tampon pour générateur de lignes en prologue (instance) */
struct _GIntroGenerator
{
@@ -72,15 +77,24 @@ static void g_intro_generator_dispose(GIntroGenerator *);
/* Procède à la libération totale de la mémoire. */
static void g_intro_generator_finalize(GIntroGenerator *);
+
+
+/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+
+
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_intro_generator_count_lines(const GIntroGenerator *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_intro_generator_compute_cursor(const GIntroGenerator *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_intro_generator_contain_cursor(const GIntroGenerator *, size_t, size_t, const GLineCursor *);
+#endif
+
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_intro_generator_get_flags(const GIntroGenerator *, size_t, size_t);
@@ -89,6 +103,11 @@ static void g_intro_generator_print(GIntroGenerator *, GBufferLine *, size_t, si
+/* ---------------------------------------------------------------------------------- */
+/* MARQUE D'INTRODUCTION DE RENDU */
+/* ---------------------------------------------------------------------------------- */
+
+
/* Détermine le type du générateur de lignes d'introduction à la volée. */
G_DEFINE_TYPE_WITH_CODE(GIntroGenerator, g_intro_generator, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_intro_generator_interface_init));
@@ -153,8 +172,10 @@ static void g_intro_generator_init(GIntroGenerator *generator)
static void g_intro_generator_interface_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_intro_generator_count_lines;
+#ifdef INCLUDE_GTK_SUPPORT
iface->compute = (linegen_compute_fc)g_intro_generator_compute_cursor;
iface->contain = (linegen_contain_fc)g_intro_generator_contain_cursor;
+#endif
iface->get_flags = (linegen_get_flags_fc)g_intro_generator_get_flags;
iface->print = (linegen_print_fc)g_intro_generator_print;
@@ -263,6 +284,12 @@ GIntroGenerator *g_intro_generator_new(const GBinFormat *format, const GCodingLa
}
+
+/* ---------------------------------------------------------------------------------- */
+/* OFFRE DE CAPACITES DE GENERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
@@ -282,6 +309,9 @@ static size_t g_intro_generator_count_lines(const GIntroGenerator *generator)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
@@ -338,6 +368,9 @@ static int g_intro_generator_contain_cursor(const GIntroGenerator *generator, si
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
diff --git a/src/glibext/generators/rborder.c b/src/glibext/generators/rborder.c
index 97e7a22..8379c7a 100644
--- a/src/glibext/generators/rborder.c
+++ b/src/glibext/generators/rborder.c
@@ -30,13 +30,18 @@
#include "../bufferline.h"
-#include "../gbinarycursor.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../gbinarycursor.h"
+#endif
#include "../linegen-int.h"
#include "../linesegment.h"
-#include "../../gtkext/gtkblockdisplay.h"
+#include "../../core/columns.h"
+/* -------------------------- MARQUE DE BORDURE DE ROUTINE -------------------------- */
+
+
/* Tampon pour générateur de délimitations de routines (instance) */
struct _GBorderGenerator
{
@@ -79,15 +84,24 @@ static void g_border_generator_dispose(GBorderGenerator *);
/* Procède à la libération totale de la mémoire. */
static void g_border_generator_finalize(GBorderGenerator *);
+
+
+/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+
+
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_border_generator_count_lines(const GBorderGenerator *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_border_generator_compute_cursor(const GBorderGenerator *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_border_generator_contain_cursor(const GBorderGenerator *, size_t, size_t, const GLineCursor *);
+#endif
+
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_border_generator_get_flags(const GBorderGenerator *, size_t, size_t);
@@ -96,6 +110,11 @@ static void g_border_generator_print(GBorderGenerator *, GBufferLine *, size_t,
+/* ---------------------------------------------------------------------------------- */
+/* MARQUE DE BORDURE DE ROUTINE */
+/* ---------------------------------------------------------------------------------- */
+
+
/* Détermine le type du générateur de délimitations de routines à la volée. */
G_DEFINE_TYPE_WITH_CODE(GBorderGenerator, g_border_generator, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_border_generator_interface_init));
@@ -158,8 +177,10 @@ static void g_border_generator_init(GBorderGenerator *generator)
static void g_border_generator_interface_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_border_generator_count_lines;
+#ifdef INCLUDE_GTK_SUPPORT
iface->compute = (linegen_compute_fc)g_border_generator_compute_cursor;
iface->contain = (linegen_contain_fc)g_border_generator_contain_cursor;
+#endif
iface->get_flags = (linegen_get_flags_fc)g_border_generator_get_flags;
iface->print = (linegen_print_fc)g_border_generator_print;
@@ -240,6 +261,12 @@ GBorderGenerator *g_border_generator_new(GCodingLanguage *lang, const vmpa2t *ad
}
+
+/* ---------------------------------------------------------------------------------- */
+/* OFFRE DE CAPACITES DE GENERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
@@ -259,6 +286,9 @@ static size_t g_border_generator_count_lines(const GBorderGenerator *generator)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
@@ -315,6 +345,9 @@ static int g_border_generator_contain_cursor(const GBorderGenerator *generator,
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
diff --git a/src/glibext/glinecursor-int.h b/src/glibext/glinecursor-int.h
index b440f76..5a2f84d 100644
--- a/src/glibext/glinecursor-int.h
+++ b/src/glibext/glinecursor-int.h
@@ -26,7 +26,7 @@
#include "glinecursor.h"
-#include "../gtkext/gtkstatusstack.h"
+#include "notifier.h"
diff --git a/src/glibext/glinecursor.h b/src/glibext/glinecursor.h
index 5c35c52..549dfbe 100644
--- a/src/glibext/glinecursor.h
+++ b/src/glibext/glinecursor.h
@@ -32,11 +32,7 @@
#include "../analysis/loaded.h"
#include "../common/packed.h"
#include "../common/sqlite.h"
-
-
-
-/* Depuis ../gtkext/gtkstatusstack.h : abstration d'une gestion de barre de statut (instance) */
-typedef struct _GtkStatusStack GtkStatusStack;
+#include "../glibext/notifier.h"
diff --git a/src/glibext/linecolumn.c b/src/glibext/linecolumn.c
index 38088d2..35f7698 100644
--- a/src/glibext/linecolumn.c
+++ b/src/glibext/linecolumn.c
@@ -49,7 +49,9 @@ void init_line_column(line_column *column)
column->segments = NULL;
column->count = 0;
+#ifdef INCLUDE_GTK_SUPPORT
column->max_width = 0;
+#endif
}
@@ -81,11 +83,16 @@ void reset_line_column(line_column *column)
column->count = 0;
+#ifdef INCLUDE_GTK_SUPPORT
column->max_width = 0;
+#endif
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : column = colonne de ligne à mettre à jour. *
@@ -129,6 +136,9 @@ gint get_column_width(const line_column *column)
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : column = colonne de ligne à venir compléter. *
@@ -157,7 +167,9 @@ size_t append_text_to_line_column(line_column *column, const char *text, size_t
column->segments[result] = segment;
+#ifdef INCLUDE_GTK_SUPPORT
column->max_width += get_line_segment_width(segment);
+#endif
return result;
@@ -200,11 +212,16 @@ void replace_text_in_line_column(line_column *column, size_t index, const char *
column->segments[index] = segment;
+#ifdef INCLUDE_GTK_SUPPORT
refresh_line_column_width(column);
+#endif
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : column = colonne de ligne de texte à consulter. *
@@ -432,6 +449,9 @@ void draw_line_column_segments(const line_column *column, cairo_t *cairo, gint x
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : column = colonne de ligne de texte à venir consulter. *
diff --git a/src/glibext/linecolumn.h b/src/glibext/linecolumn.h
index 05624c5..6dd50f6 100644
--- a/src/glibext/linecolumn.h
+++ b/src/glibext/linecolumn.h
@@ -27,7 +27,9 @@
#include <stdbool.h>
#include <glib-object.h>
-#include <gdk/gdk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gdk/gdk.h>
+#endif
#include "linesegment.h"
@@ -44,7 +46,9 @@ struct _line_column
line_segment **segments; /* Liste des segments contenus */
size_t count; /* Taille de cette liste */
+#ifdef INCLUDE_GTK_SUPPORT
int max_width; /* Largeur max. de l'espace */
+#endif
};
@@ -55,18 +59,24 @@ void init_line_column(line_column *);
/* Réinitialise une colonne de ligne. */
void reset_line_column(line_column *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Recalcule la largeur d'une colonne de segments. */
void refresh_line_column_width(line_column *);
/* Fournit la quantité de pixels requise pour l'impression. */
gint get_column_width(const line_column *);
+#endif
+
/* Ajoute un fragment de texte à une colonne de ligne. */
size_t append_text_to_line_column(line_column *, const char *, size_t, RenderingTagType);
/* Remplace un fragment de texte dans une colonne de ligne. */
void replace_text_in_line_column(line_column *, size_t, const char *, size_t);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Indique l'indice du premier contenu de la colonne. */
bool get_line_column_first_content_index(const line_column *, size_t *);
@@ -85,6 +95,8 @@ line_segment *get_line_column_content_from_index(const line_column *, size_t);
/* Imprime le contenu d'une colonne de ligne de texte. */
void draw_line_column_segments(const line_column *, cairo_t *, gint, gint, const segcnt_list *);
+#endif
+
/* Donne le texte représenté par une colonne de ligne de texte. */
char *get_line_column_text(const line_column *, bool);
diff --git a/src/glibext/linesegment.c b/src/glibext/linesegment.c
index da6fbe2..192e030 100644
--- a/src/glibext/linesegment.c
+++ b/src/glibext/linesegment.c
@@ -30,13 +30,14 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-#include <gtk/gtk.h>
#include "../common/extstr.h"
#include "../common/fnv1a.h"
#include "../core/paths.h"
-#include "../gtkext/rendering.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../gtkext/rendering.h"
+#endif
@@ -80,6 +81,9 @@ static const char *_segment_names[RTT_COUNT] = {
};
+
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Compléments à Cairo */
#define CAIRO_FONT_SLANT_COUNT 3
@@ -96,6 +100,7 @@ typedef struct _segment_rendering
cairo_t *font_ctxts[CAIRO_FONTS_COUNT]; /* Contextes de police */
double x_advances[CAIRO_FONTS_COUNT]; /* Largeurs par caractère */
+
rendering_pattern_t patterns[RTT_COUNT];/* Modèles d'impression */
} segment_rendering;
@@ -104,6 +109,8 @@ typedef struct _segment_rendering
/* Configuration globale des rendus */
static segment_rendering _seg_params;
+#endif
+
/* ----------------------- ISOLATION DE CONTENUS PARTAGEABLES ----------------------- */
@@ -114,7 +121,11 @@ struct _line_segment
{
gint ref_count; /* Compteur de références */
- rendering_pattern_t *pattern; /* Propriétés du rendu */
+#ifdef INCLUDE_GTK_SUPPORT
+ rendering_pattern_t *pattern; /* Propriétés du rendu */
+#else
+ RenderingTagType type; /* Type de rendu attendu */
+#endif
fnv64_t hash; /* Empreinte pour comparaisons */
char text[0]; /* Texte brut conservé */
@@ -144,6 +155,8 @@ static void release_shared_segment_content(line_segment *);
/* -------------------- GESTION OPTIMALE D'UNE LISTE DE CONTENUS -------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Liste identifiant un ensemble de segments */
struct _segcnt_list
{
@@ -158,6 +171,8 @@ struct _segcnt_list
/* Indique si le contenu d'un segment est notable ou non. */
bool selection_list_has_segment_content(const segcnt_list *, const line_segment *);
+#endif
+
/* ---------------------------------------------------------------------------------- */
@@ -165,6 +180,9 @@ bool selection_list_has_segment_content(const segcnt_list *, const line_segment
/* ---------------------------------------------------------------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : - *
@@ -223,6 +241,9 @@ bool load_segment_rendering_parameters(void)
}
+#endif
+
+
/* ---------------------------------------------------------------------------------- */
/* ISOLATION DE CONTENUS PARTAGEABLES */
@@ -309,7 +330,11 @@ static bool is_line_segment_equal(const line_segment *content, const line_segmen
{
bool result; /* Résultat à retourner */
+#ifdef INCLUDE_GTK_SUPPORT
result = (content->pattern == other->pattern);
+#else
+ result = (content->type == other->type);
+#endif
if (result)
result = (cmp_fnv_64a(content->hash, other->hash) == 0);
@@ -452,7 +477,11 @@ line_segment *get_new_line_segment(RenderingTagType type, const char *text, size
else
content = (line_segment *)malloc(sizeof(line_segment) + length + 1);
+#ifdef INCLUDE_GTK_SUPPORT
content->pattern = &_seg_params.patterns[type];
+#else
+ content->type = type;
+#endif
content->hash = fnv_64a_hash(text);
@@ -523,7 +552,11 @@ RenderingTagType get_line_segment_type(const line_segment *segment)
{
RenderingTagType result; /* Résultat à renvoyer */
+#ifdef INCLUDE_GTK_SUPPORT
result = (RenderingTagType)(segment->pattern - _seg_params.patterns);
+#else
+ result = segment->type;
+#endif
return result;
@@ -545,6 +578,16 @@ RenderingTagType get_line_segment_type(const line_segment *segment)
char *get_line_segment_text(const line_segment *segment, bool markup)
{
+#ifndef INCLUDE_GTK_SUPPORT
+
+ char *result; /* Description à renvoyer */
+
+ result = strdup(segment->text);
+
+ return result;
+
+#else
+
char *result; /* Description à renvoyer */
char color[7]; /* Couleur hexadécimale */
char *valid;
@@ -624,9 +667,14 @@ char *get_line_segment_text(const line_segment *segment, bool markup)
return result;
+#endif
+
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : segment = fragment de texte à consulter. *
@@ -911,6 +959,9 @@ void export_line_segment_style(buffer_export_context *ctx, BufferExportType type
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : segment = fragment de texte à manipuler. *
@@ -927,12 +978,12 @@ void export_line_segment_style(buffer_export_context *ctx, BufferExportType type
void export_line_segment(const line_segment *segment, buffer_export_context *ctx, BufferExportType type)
{
- size_t index; /* Indice du modèle de rendu */
+ RenderingTagType index; /* Indice du modèle de rendu */
switch (type)
{
case BET_HTML:
- index = (segment->pattern - _seg_params.patterns);
+ index = get_line_segment_type(segment);
dprintf(ctx->fd, "<SPAN class=\"%s\">", _segment_names[index]);
break;
default:
@@ -959,6 +1010,9 @@ void export_line_segment(const line_segment *segment, buffer_export_context *ctx
/* ---------------------------------------------------------------------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : - *
@@ -1147,3 +1201,6 @@ bool selection_list_has_segment_content(const segcnt_list *list, const line_segm
return result;
}
+
+
+#endif
diff --git a/src/glibext/linesegment.h b/src/glibext/linesegment.h
index 3585ffb..4859fbb 100644
--- a/src/glibext/linesegment.h
+++ b/src/glibext/linesegment.h
@@ -27,22 +27,31 @@
#include <glib-object.h>
#include <stdbool.h>
-#include <gdk/gdk.h>
-#include <pango/pango.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gdk/gdk.h>
+# include <pango/pango.h>
+#endif
+#ifdef INCLUDE_GTK_SUPPORT
/* Liste identifiant un ensemble de segments */
typedef struct _segcnt_list segcnt_list;
+#endif
+
/* ------------------------ NATURE POUR UN FRAGMENT DE TEXTE ------------------------ */
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Procède à l'initialisation des paramètres de rendu de texte. */
bool load_segment_rendering_parameters(void);
+#endif
+
/* ----------------------- ISOLATION DE CONTENUS PARTAGEABLES ----------------------- */
@@ -127,6 +136,8 @@ RenderingTagType get_line_segment_type(const line_segment *);
/* Fournit le texte brut conservé dans le segment. */
char *get_line_segment_text(const line_segment *, bool);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Fournit la quantité de pixels requise pour l'impression. */
gint get_line_segment_width(const line_segment *);
@@ -139,6 +150,9 @@ bool move_caret_on_line_segment(const line_segment *, gint *, bool, GdkScrollDir
/* Imprime le fragment de texte représenté. */
void draw_line_segment(const line_segment *, cairo_t *, gint *, gint, const segcnt_list *);
+#endif
+
+
/* Types d'exportation */
typedef enum _BufferExportType
{
@@ -171,9 +185,13 @@ typedef struct _buffer_export_context
} buffer_export_context;
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Exporte tous les styles utilisés par des segments. */
void export_line_segment_style(buffer_export_context *, BufferExportType);
+#endif
+
/* Exporte le fragment de texte représenté. */
void export_line_segment(const line_segment *, buffer_export_context *, BufferExportType);
@@ -182,6 +200,8 @@ void export_line_segment(const line_segment *, buffer_export_context *, BufferEx
/* -------------------- GESTION OPTIMALE D'UNE LISTE DE CONTENUS -------------------- */
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Initilise une liste de contenus de segments. */
segcnt_list *init_segment_content_list(void);
@@ -200,6 +220,8 @@ bool reset_segment_content_list(segcnt_list *);
/* Marque le contenu d'un segment comme remarquable. */
bool add_segment_content_to_selection_list(segcnt_list *, const line_segment *);
+#endif
+
#endif /* _GLIBEXT_LINESEGMENT_H */
diff --git a/src/glibext/notifier.h b/src/glibext/notifier.h
new file mode 100644
index 0000000..db19e10
--- /dev/null
+++ b/src/glibext/notifier.h
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * notifier.h - prototypes pour les opérations de comparaison d'objets
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_NOTIFIER_H
+#define _GLIBEXT_NOTIFIER_H
+
+
+
+
+
+
+
+
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../gtkext/gtkstatusstack.h"
+#else
+
+
+
+
+
+
+typedef void GtkStatusStack;
+
+
+
+/* -------------------------- STATUT DES SUIVIS D'ACTIVITE -------------------------- */
+
+
+/* Identifiant unique de rapport de progression */
+typedef unsigned long activity_id_t;
+
+/* Identifiant particulier pour une absence d'identifiant */
+#define NO_ACTIVITY_ID 0
+
+
+#define gtk_status_stack_update_current_location(a0, a1, a2, a3, a4)
+#define gtk_status_stack_reset_current_location(a0)
+
+#define gtk_status_stack_add_activity(a0, a1, a2) 0
+#define gtk_status_stack_extend_activity(a0, a1, a2)
+#define gtk_status_stack_update_activity(a0, a1, a2)
+#define gtk_status_stack_update_activity_value(a0, a1, a2)
+#define gtk_status_stack_remove_activity(a0, a1)
+
+
+
+#endif
+
+
+
+
+
+#endif /* _GLIBEXT_NOTIFIER_H */
diff --git a/src/glibext/seq.h b/src/glibext/seq.h
index c00b4e2..f9051da 100644
--- a/src/glibext/seq.h
+++ b/src/glibext/seq.h
@@ -30,7 +30,7 @@
#include <sys/types.h>
-#include "../gtkext/gtkstatusstack.h"
+#include "notifier.h"
diff --git a/src/glibext/umemslice-int.h b/src/glibext/umemslice-int.h
new file mode 100644
index 0000000..36cc2d4
--- /dev/null
+++ b/src/glibext/umemslice-int.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * umemslice-int.h - prototypes internes pour les allocations en série d'un même type d'objets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_UMEMSLICE_INT_H
+#define _GLIBEXT_UMEMSLICE_INT_H
+
+
+#include <stdbool.h>
+
+
+#include "umemslice.h"
+
+
+
+/* Informations portant sur un bloc */
+typedef struct _slice_slab_info_t
+{
+ void *data_max; /* Zone de débordement */
+ umem_slice_iter_t iter; /* Données pour l'utilisateur */
+
+} slice_slab_info_t;
+
+#define SLICE_INFO_SIZE (sizeof(void *) + sizeof(umem_slice_iter_t))
+
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (instance) */
+struct _GUMemSlice
+{
+ GObject parent; /* A laisser en premier */
+
+ size_t obj_size; /* Taille des objects */
+
+ slice_slab_info_t *slabs; /* Ensembles complets */
+ slice_slab_info_t *last; /* Accès à l'ultime tranche */
+
+};
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (classe) */
+struct _GUMemSliceClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un allocateur de zones identiques. */
+bool g_umem_slice_create(GUMemSlice *, size_t);
+
+
+
+#endif /* _GLIBEXT_UMEMSLICE_INT_H */
diff --git a/src/glibext/umemslice.c b/src/glibext/umemslice.c
new file mode 100644
index 0000000..40088ef
--- /dev/null
+++ b/src/glibext/umemslice.c
@@ -0,0 +1,423 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * umemslice.c - allocations en série d'un même type d'objets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "umemslice.h"
+
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+
+#include "umemslice-int.h"
+#include "../core/logs.h"
+
+
+
+/* --------------------------- GESTION D'UN BLOC D'OBJETS --------------------------- */
+
+
+#define SLAB_SIZE (8 * 1024 * 1024)
+
+
+/* Alloue un espace pour un nouveau slab en mémoire. */
+static slice_slab_info_t *create_slice_slab(size_t, size_t);
+
+/* Supprime l'espace correspondant à un slab en mémoire. */
+static void destroy_slice_slab(slice_slab_info_t *, size_t);
+
+
+
+/* --------------------------- ALLOCATIONS ET LIBERATIONS --------------------------- */
+
+
+/* Initialise la classe des allocateurs d'objets similaires. */
+static void g_umem_slice_class_init(GUMemSliceClass *);
+
+/* Initialise une instance d'allocateur d'objets similaires. */
+static void g_umem_slice_init(GUMemSlice *);
+
+/* Supprime toutes les références externes. */
+static void g_umem_slice_dispose(GUMemSlice *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_umem_slice_finalize(GUMemSlice *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION D'UN BLOC D'OBJETS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : slab_size = taille totale du slab à allouer. *
+* obj_size = taille des futurs objets contenus. *
+* *
+* Description : Alloue un espace pour un nouveau slab en mémoire. *
+* *
+* Retour : Adresse du gestionnaire du slab mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static slice_slab_info_t *create_slice_slab(size_t slab_size, size_t obj_size)
+{
+ slice_slab_info_t *result; /* Structure à retourner */
+ void *data; /* Zone de mémoire allouée */
+ int ret; /* Bilan d'une précision */
+ size_t quantity; /* Quantité d'objets allouable */
+
+ assert(obj_size % sizeof(unsigned long) == 0);
+
+ data = mmap(NULL, slab_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS/* | MAP_POPULATE*/, -1, 0);
+
+ if (data == MAP_FAILED)
+ {
+ LOG_ERROR_N("mmap");
+ result = NULL;
+ goto exit;
+ }
+
+ ret = madvise(data, slab_size, MADV_SEQUENTIAL);
+ if (ret == -1)
+ LOG_ERROR_N("madvise");
+
+ /* Initialisation du gestionnaire */
+
+ result = data;
+
+ quantity = (slab_size - SLICE_INFO_SIZE) / obj_size;
+
+ //result->data_max = ((uint8_t *)data) + (quantity * obj_size);
+
+ result->iter.data_end = ((uint8_t *)data) + SLICE_INFO_SIZE;
+ result->iter.next = NULL;
+
+ result->data_max = result->iter.data_end + (quantity * obj_size);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slab = gestionnaire d'une zone mémoire à manipuler. *
+* slab_size = taille totale du slab à allouer. *
+* *
+* Description : Supprime l'espace correspondant à un slab en mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void destroy_slice_slab(slice_slab_info_t *slab, size_t slab_size)
+{
+ void *data; /* Zone de mémoire allouée */
+ int ret; /* Bilan de l'opération */
+
+ data = slab;
+
+ ret = munmap(data, slab_size);
+
+ if (ret == -1)
+ LOG_ERROR_N("munmap");
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ALLOCATIONS ET LIBERATIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un allocateur en série d'objets depuis une même zone mémoire. */
+G_DEFINE_TYPE(GUMemSlice, g_umem_slice, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des allocateurs d'objets similaires. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_umem_slice_class_init(GUMemSliceClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_umem_slice_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_umem_slice_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slice = instance à initialiser. *
+* *
+* Description : Initialise une instance d'allocateur d'objets similaires. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_umem_slice_init(GUMemSlice *slice)
+{
+ slice->obj_size = 0;
+
+ slice->slabs = NULL;
+ slice->last = NULL;
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slice = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_umem_slice_dispose(GUMemSlice *slice)
+{
+ G_OBJECT_CLASS(g_umem_slice_parent_class)->dispose(G_OBJECT(slice));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slice = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_umem_slice_finalize(GUMemSlice *slice)
+{
+ slice_slab_info_t *slab; /* Slab à libérer entièrement */
+ slice_slab_info_t *next; /* Slab suivant à traiter */
+
+ for (slab = slice->slabs; slab != NULL; slab = next)
+ {
+ if (slab->iter.next == NULL)
+ next = NULL;
+ else
+ next = (slice_slab_info_t *)(((uint8_t *)slab->iter.next) - sizeof(void *));
+
+ destroy_slice_slab(slab, SLAB_SIZE);
+
+ }
+
+ G_OBJECT_CLASS(g_umem_slice_parent_class)->finalize(G_OBJECT(slice));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : size = taille des objets à allouer en mémoire. *
+* *
+* Description : Crée un allocateur dédié à la création de zones identiques. *
+* *
+* Retour : Allocateur mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GUMemSlice *g_umem_slice_new(size_t size)
+{
+ GUMemSlice *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_UMEM_SLICE, NULL);
+
+ if (!g_umem_slice_create(result, size))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slice = instance à initialiser pleinement. *
+* size = taille des objets à allouer en mémoire. *
+* *
+* Description : Met en place un allocateur de zones identiques. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_umem_slice_create(GUMemSlice *slice, size_t size)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ slice->obj_size = size;
+
+ slice->slabs = create_slice_slab(SLAB_SIZE, size);
+ slice->last = slice->slabs;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slice = allocateur à manipuler. *
+* *
+* Description : Alloue une nouvelle zone de la taille attendue en mémoire. *
+* *
+* Retour : Adresse de la zone nouvellement disponible ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void *g_umem_slice_alloc(GUMemSlice *slice)
+{
+ void *result; /* Allocation à retourner */
+ slice_slab_info_t *slab; /* Slab concerné par l'opérat° */
+ umem_slice_iter_t *iter; /* Tête d'écriture courante */
+
+ slab = slice->last;
+
+ assert(slab != NULL);
+
+ if (slab->iter.data_end == slab->data_max)
+ {
+ slice->last = create_slice_slab(SLAB_SIZE, slice->obj_size);
+
+ slab->iter.next = &slice->last->iter;
+
+ slab = slice->last;
+
+ }
+
+ iter = &slab->iter;
+
+ result = iter->data_end;
+
+ iter->data_end_ul += slice->obj_size;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slice = allocateur à manipuler. *
+* val = valeur de 64 bits à intégrer. *
+* *
+* Description : Mémorise un mot de 64 bits dans une nouvelle zone en mémoire.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_umem_slice_put_uint64(GUMemSlice *slice, uint64_t val)
+{
+ slice_slab_info_t *slab; /* Slab concerné par l'opérat° */
+
+ assert(slice->obj_size == sizeof(uint64_t));
+
+ slab = slice->last;
+
+ assert(slab != NULL);
+
+ if (slab->iter.data_end == slab->data_max)
+ {
+ slice->last = create_slice_slab(SLAB_SIZE, slice->obj_size);
+
+ slab->iter.next = &slice->last->iter;
+
+ slab = slice->last;
+
+ }
+
+ *slab->iter.data_end_uint64 = val;
+
+ slab->iter.data_end_ul += slice->obj_size;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : slice = allocateur à consulter. *
+* *
+* Description : Fournit un itérateur pour les données allouées. *
+* *
+* Retour : Premier descripteur des données allouées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const umem_slice_iter_t *g_umem_slice_get_iter(const GUMemSlice *slice)
+{
+ const umem_slice_iter_t *result; /* Pointeur à retourner */
+
+ result = &slice->slabs->iter;
+
+ return result;
+
+}
diff --git a/src/glibext/umemslice.h b/src/glibext/umemslice.h
new file mode 100644
index 0000000..54b8433
--- /dev/null
+++ b/src/glibext/umemslice.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * umemslice.h - prototypes pour les allocations en série d'un même type d'objets
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_UMEMSLICE_H
+#define _GLIBEXT_UMEMSLICE_H
+
+
+#include <glib-object.h>
+#include <stdint.h>
+
+
+
+#define G_TYPE_UMEM_SLICE g_umem_slice_get_type()
+#define G_UMEM_SLICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UMEM_SLICE, GUMemSlice))
+#define G_IS_UMEM_SLICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UMEM_SLICE))
+#define G_UMEM_SLICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UMEM_SLICE, GUMemSliceClass))
+#define G_IS_UMEM_SLICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UMEM_SLICE))
+#define G_UMEM_SLICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UMEM_SLICE, GUMemSliceClass))
+
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (instance) */
+typedef struct _GUMemSlice GUMemSlice;
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (classe) */
+typedef struct _GUMemSliceClass GUMemSliceClass;
+
+
+/* Indique le type défini pour un allocateur en série d'objets depuis une même zone mémoire. */
+GType g_umem_slice_get_type(void);
+
+/* Crée un allocateur dédié à la création de zones identiques. */
+GUMemSlice *g_umem_slice_new(size_t);
+
+/* Alloue une nouvelle zone de la taille attendue en mémoire. */
+void *g_umem_slice_alloc(GUMemSlice *);
+
+/* Mémorise un mot de 64 bits dans une nouvelle zone en mémoire. */
+void g_umem_slice_put_uint64(GUMemSlice *, uint64_t);
+
+/* Itérateur pour tranches de mémoire */
+typedef struct _umem_slice_iter_t
+{
+ union
+ {
+ void *data_end; /* Première zone libre */
+ uint64_t *data_end_uint64;
+ unsigned long data_end_ul;
+ };
+ struct _umem_slice_iter_t *next; /* Lien vers tranche suivante */
+
+ void *data[0]; /* Accès au premier élément */
+
+} umem_slice_iter_t;
+
+/* Fournit un itérateur pour les données allouées. */
+const umem_slice_iter_t *g_umem_slice_get_iter(const GUMemSlice *);
+
+
+
+#endif /* _GLIBEXT_UMEMSLICE_H */
diff --git a/src/glibext/widthtracker.h b/src/glibext/widthtracker.h
index 113cf8a..ce0aa93 100644
--- a/src/glibext/widthtracker.h
+++ b/src/glibext/widthtracker.h
@@ -51,6 +51,9 @@ typedef struct _line_width_summary
/* gbuffercache.h : Tampon pour gestion de lignes optimisée (instance) */
typedef struct _GBufferCache GBufferCache;
+/* ../gtkext/gtkstatusstack.h : Abstration d'une gestion de barre de statut (instance) */
+typedef struct _GtkStatusStack GtkStatusStack;
+
#define G_TYPE_WIDTH_TRACKER (g_width_tracker_get_type())
#define G_WIDTH_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_TRACKER, GWidthTracker))
diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am
index 8c46615..5bfc55f 100644
--- a/src/gtkext/Makefile.am
+++ b/src/gtkext/Makefile.am
@@ -32,7 +32,7 @@ libgtkext_la_SOURCES = \
libgtkext_la_LIBADD = \
graph/libgtkextgraph.la
-libgtkext_la_LDFLAGS =
+libgtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -40,10 +40,6 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libgtkext_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = graph
diff --git a/src/gtkext/graph/Makefile.am b/src/gtkext/graph/Makefile.am
index c7f1d4b..ba7318e 100644
--- a/src/gtkext/graph/Makefile.am
+++ b/src/gtkext/graph/Makefile.am
@@ -11,18 +11,9 @@ libgtkextgraph_la_SOURCES = \
rank.h rank.c \
vspace.h vspace.c
-libgtkextgraph_la_LIBADD =
-
-libgtkextgraph_la_LDFLAGS =
+libgtkextgraph_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/gtkext/gtkblockdisplay.c b/src/gtkext/gtkblockdisplay.c
index 1810fc9..00da4cc 100644
--- a/src/gtkext/gtkblockdisplay.c
+++ b/src/gtkext/gtkblockdisplay.c
@@ -28,6 +28,7 @@
#include "../arch/instruction.h"
#include "../arch/operand.h"
#include "../analysis/loaded.h"
+#include "../core/columns.h"
#include "../glibext/gbinarycursor.h"
diff --git a/src/gtkext/gtkblockdisplay.h b/src/gtkext/gtkblockdisplay.h
index 196fe2e..6c0879c 100644
--- a/src/gtkext/gtkblockdisplay.h
+++ b/src/gtkext/gtkblockdisplay.h
@@ -48,22 +48,6 @@ typedef struct _GtkBlockDisplay GtkBlockDisplay;
typedef struct _GtkBlockDisplayClass GtkBlockDisplayClass;
-/* Désignation des colonnes d'une ligne */
-typedef enum _DisassLineColumn
-{
- DLC_PHYSICAL, /* Position physique */
- DLC_VIRTUAL, /* Adresse virtuelle */
- DLC_BINARY, /* Contenu sous forme binaire */
- DLC_ASSEMBLY_LABEL, /* Etiquette dans les données */
- DLC_ASSEMBLY_HEAD, /* Instruction pour assembleur */
- DLC_ASSEMBLY, /* Code pour assembleur */
- DLC_COMMENTS, /* Commentaires éventuels */
-
- DLC_COUNT,
-
-} DisassLineColumn;
-
-
/* Détermine le type du composant d'affichage de bloc en langage d'assemblage. */
GType gtk_block_display_get_type(void);
diff --git a/src/gtkext/gtkstatusstack.c b/src/gtkext/gtkstatusstack.c
index 0b35e1b..fe4e4d5 100644
--- a/src/gtkext/gtkstatusstack.c
+++ b/src/gtkext/gtkstatusstack.c
@@ -34,7 +34,6 @@
#include "easygtk.h"
-#include "../common/extstr.h"
#include "../gui/agroup.h"
#include "../format/format.h"
@@ -503,8 +502,9 @@ static void on_zoom_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, G
/******************************************************************************
* *
* Paramètres : stack = barre de statut à actualiser. *
-* binary = binaire chargé rassemblant l'ensemble des infos. *
* range = emplacement à mettre en valeur. *
+* segment = zone de binaire d'appartenance. *
+* symbol = éventuelle position par rapport à un symbole. *
* encoding = encodage d'une éventuelle instruction ou NULL. *
* *
* Description : Actualise les informations liées une position d'assemblage. *
@@ -515,25 +515,14 @@ static void on_zoom_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, G
* *
******************************************************************************/
-void gtk_status_stack_update_current_location(GtkStatusStack *stack, const GLoadedBinary *binary, const mrange_t *range, const char *encoding)
+void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrange_t *range, const char *segment, const char *symbol, const char *encoding)
{
assembly_info *info; /* Informations à constituer */
- GExeFormat *format; /* Format de binaire à traiter */
const vmpa2t *addr; /* Localisation de départ */
phys_t size; /* Taille de l'emplacement */
- GBinPortion *portions; /* Couche première de portions */
- GBinPortion *portion; /* Zone mémoire d'appartenance */
- const char *text; /* Texte au contenu à copier */
- GBinSymbol *symbol; /* Symbole présent à l'adresse */
- phys_t diff; /* Décalage de l'adresse */
- char *label; /* Description d'un symbole */
- vmpa2t tmp; /* Zone de construction temp. */
- VMPA_BUFFER(offset); /* Décalage physique */
info = stack->asm_info;
- format = g_loaded_binary_get_format(binary);
-
/* Bascule vers une zone courante nouvelle ? */
addr = get_mrange_addr(range);
@@ -542,7 +531,7 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const GLoad
if (cmp_mrange(&info->current, range) == 0
&& info->size == size
&& info->encoding == encoding)
- goto gssuci_useless;
+ goto useless;
/* Réinitialisation */
@@ -552,20 +541,7 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const GLoad
/* Zone d'appartenance */
- portions = g_exe_format_get_portions(format);
-
- portion = g_binary_portion_find_at_addr(portions, addr, (GdkRectangle []) { { 0 } });
-
- text = g_binary_portion_get_desc(portion);
-
- if (text != NULL)
- info->segment = strdup(text);
- else
- info->segment = strdup(_("Binary"));
-
- g_object_unref(G_OBJECT(portion));
-
- g_object_unref(G_OBJECT(portions));
+ info->segment = strdup(segment);
/* Adresses de base */
@@ -578,26 +554,8 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const GLoad
/* Symbole concerné */
- if (g_binary_format_resolve_symbol(G_BIN_FORMAT(format), addr, false, &symbol, &diff))
- {
- label = g_binary_symbol_get_label(symbol);
-
- if (label != NULL)
- {
- info->symbol = label;
-
- info->symbol = stradd(info->symbol, "+");
-
- init_vmpa(&tmp, diff, VMPA_NO_VIRTUAL);
- vmpa2_phys_to_string(&tmp, MDS_UNDEFINED, offset, NULL);
-
- info->symbol = stradd(info->symbol, offset);
-
- }
-
- g_object_unref(G_OBJECT(symbol));
-
- }
+ if (symbol != NULL)
+ info->symbol = strdup(symbol);
/* Nettoyage et conclusion */
@@ -605,9 +563,9 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const GLoad
gtk_status_stack_show_current_location(stack);
- gssuci_useless:
+ useless:
- g_object_unref(G_OBJECT(format));
+ ;
}
diff --git a/src/gtkext/gtkstatusstack.h b/src/gtkext/gtkstatusstack.h
index 91182a1..f419014 100644
--- a/src/gtkext/gtkstatusstack.h
+++ b/src/gtkext/gtkstatusstack.h
@@ -28,7 +28,7 @@
#include <gtk/gtk.h>
-#include "../analysis/binary.h"
+#include "../arch/vmpa.h"
@@ -62,7 +62,7 @@ GtkStatusStack *gtk_status_stack_new(void);
/* Actualise les informations liées une position d'assemblage. */
-void gtk_status_stack_update_current_location(GtkStatusStack *, const GLoadedBinary *, const mrange_t *, const char *);
+void gtk_status_stack_update_current_location(GtkStatusStack *, const mrange_t *, const char *, const char *, const char *);
/* Réinitialise les informations associées une position. */
void gtk_status_stack_reset_current_location(GtkStatusStack *);
diff --git a/src/gtkext/hexdisplay.c b/src/gtkext/hexdisplay.c
index f557513..32bd69b 100644
--- a/src/gtkext/hexdisplay.c
+++ b/src/gtkext/hexdisplay.c
@@ -25,6 +25,7 @@
#include "gtkbufferdisplay-int.h"
+#include "../core/columns.h"
#include "../core/params.h"
#include "../format/format.h"
#include "../glibext/generators/hex.h"
diff --git a/src/gtkext/hexdisplay.h b/src/gtkext/hexdisplay.h
index 45a1da9..9190548 100644
--- a/src/gtkext/hexdisplay.h
+++ b/src/gtkext/hexdisplay.h
@@ -48,19 +48,6 @@ typedef struct _GtkHexDisplay GtkHexDisplay;
typedef struct _GtkHexDisplayClass GtkHexDisplayClass;
-/* Désignation des colonnes d'une ligne */
-typedef enum _HexLineColumn
-{
- HLC_PHYSICAL, /* Position physique */
- HLC_BINARY, /* Données binaires brutes */
- HLC_PADDING, /* Espacement forcé */
- HLC_TRANSLATION, /* Traduction de contenu */
-
- HLC_COUNT,
-
-} HexLineColumn;
-
-
/* Détermine le type du composant d'affichage sous forme hexadécimale. */
GType gtk_hex_display_get_type(void);
diff --git a/src/gtkext/rendering.c b/src/gtkext/rendering.c
index bb86791..8badf21 100644
--- a/src/gtkext/rendering.c
+++ b/src/gtkext/rendering.c
@@ -28,6 +28,7 @@
#include <malloc.h>
#include <stdio.h>
#include <string.h>
+#include <gtk/gtk.h>
#include "../common/extstr.h"
diff --git a/src/gtkext/rendering.h b/src/gtkext/rendering.h
index d80c096..9adfe1a 100644
--- a/src/gtkext/rendering.h
+++ b/src/gtkext/rendering.h
@@ -27,7 +27,7 @@
#include <stdbool.h>
-#include <gtk/gtk.h>
+#include <gdk/gdk.h>
diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am
index fcb0298..058b36e 100644
--- a/src/gui/Makefile.am
+++ b/src/gui/Makefile.am
@@ -25,7 +25,7 @@ libgui_la_LIBADD = \
panels/libguipanels.la \
tb/libguitb.la
-libgui_la_LDFLAGS =
+libgui_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -33,10 +33,6 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libgui_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = core dialogs menus panels tb
diff --git a/src/gui/core/Makefile.am b/src/gui/core/Makefile.am
index ebe1278..2077c4b 100644
--- a/src/gui/core/Makefile.am
+++ b/src/gui/core/Makefile.am
@@ -20,7 +20,7 @@ libguicore_la_SOURCES = \
resources.h resources.c \
theme.h theme.c
-libguicore_la_LDFLAGS = $(LIBGTK_LIBS) $(LIBXML_LIBS)
+libguicore_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -28,13 +28,6 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libguicore_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
-
-
resources.c: gresource.xml $(RES_FILES)
glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_core gresource.xml
diff --git a/src/gui/core/core.c b/src/gui/core/core.c
index c68b917..6bebfe2 100644
--- a/src/gui/core/core.c
+++ b/src/gui/core/core.c
@@ -32,7 +32,6 @@
#include "../menus/view.h"
#include "../panels/welcome.h"
#include "../../core/params.h"
-#include "../../glibext/linesegment.h"
#include "../../gtkext/tiledgrid.h"
@@ -199,8 +198,6 @@ bool complete_loading_of_all_gui_components(GGenConfig *config)
void unload_all_gui_components(void)
{
- exit_segment_content_hash_table();
-
unload_all_themes();
}
diff --git a/src/gui/core/items.c b/src/gui/core/items.c
index 6c57b7b..2b93dfd 100644
--- a/src/gui/core/items.c
+++ b/src/gui/core/items.c
@@ -30,6 +30,7 @@
#include "global.h"
+#include "../../analysis/binary.h"
#include "../../analysis/db/items/move.h"
diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am
index a8e7b93..5716f14 100644
--- a/src/gui/dialogs/Makefile.am
+++ b/src/gui/dialogs/Makefile.am
@@ -31,7 +31,7 @@ libguidialogs_la_SOURCES = \
snapshots.h snapshots.c \
storage.h storage.c
-libguidialogs_la_LDFLAGS =
+libguidialogs_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -39,13 +39,6 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libguidialogs_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
-
-
resources.c: gresource.xml $(UI_FILES)
glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_dialogs gresource.xml
diff --git a/src/gui/dialogs/export_disass.c b/src/gui/dialogs/export_disass.c
index 12fc51f..911e345 100644
--- a/src/gui/dialogs/export_disass.c
+++ b/src/gui/dialogs/export_disass.c
@@ -36,6 +36,7 @@
#include "../core/global.h"
#include "../../common/extstr.h"
+#include "../../core/columns.h"
#include "../../core/global.h"
#include "../../core/logs.h"
#include "../../core/queue.h"
diff --git a/src/gui/dialogs/gotox.c b/src/gui/dialogs/gotox.c
index 2179960..9a8a1d2 100644
--- a/src/gui/dialogs/gotox.c
+++ b/src/gui/dialogs/gotox.c
@@ -31,6 +31,7 @@
#include <i18n.h>
+#include "../../core/columns.h"
#include "../../core/paths.h"
#include "../../format/format.h"
#include "../../format/symiter.h"
diff --git a/src/gui/editor.c b/src/gui/editor.c
index c46c137..f809848 100644
--- a/src/gui/editor.c
+++ b/src/gui/editor.c
@@ -45,6 +45,7 @@
#include "core/items.h"
#include "panels/view.h"
#include "tb/portions.h"
+#include "../analysis/binary.h"
#include "../common/extstr.h"
#include "../core/global.h"
#include "../core/logs.h"
diff --git a/src/gui/menus/Makefile.am b/src/gui/menus/Makefile.am
index 3959044..727c0cf 100644
--- a/src/gui/menus/Makefile.am
+++ b/src/gui/menus/Makefile.am
@@ -11,18 +11,9 @@ libguimenus_la_SOURCES = \
project.h project.c \
view.h view.c
-libguimenus_la_LDFLAGS =
-
-libguimenus_la_LIBADD = $(LIBINTL)
+libguimenus_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libguimenus_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am
index 0bde9bf..83e173b 100644
--- a/src/gui/panels/Makefile.am
+++ b/src/gui/panels/Makefile.am
@@ -33,7 +33,7 @@ libguipanels_la_SOURCES = \
view.h view.c \
welcome.h welcome.c
-libguipanels_la_LDFLAGS =
+libguipanels_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -41,13 +41,6 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libguipanels_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
-
-
resources.c: gresource.xml $(UI_FILES)
glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_panels gresource.xml
diff --git a/src/gui/panels/bintree.c b/src/gui/panels/bintree.c
index c31bd88..e90179d 100644
--- a/src/gui/panels/bintree.c
+++ b/src/gui/panels/bintree.c
@@ -37,6 +37,7 @@
#include "../agroup.h"
#include "../panel-int.h"
#include "../core/global.h"
+#include "../../analysis/binary.h"
#include "../../core/queue.h"
#include "../../gtkext/easygtk.h"
#include "../../gtkext/gtkdisplaypanel.h"
diff --git a/src/gui/panels/bookmarks.c b/src/gui/panels/bookmarks.c
index 75d0a85..4601631 100644
--- a/src/gui/panels/bookmarks.c
+++ b/src/gui/panels/bookmarks.c
@@ -37,6 +37,7 @@
#include "../panel-int.h"
#include "../core/global.h"
+#include "../../analysis/binary.h"
#include "../../analysis/db/items/bookmark.h"
#include "../../core/params.h"
#include "../../core/paths.h"
diff --git a/src/gui/panels/errors.c b/src/gui/panels/errors.c
index 873c939..ef956d9 100644
--- a/src/gui/panels/errors.c
+++ b/src/gui/panels/errors.c
@@ -36,6 +36,7 @@
#include "updating-int.h"
#include "../panel-int.h"
#include "../core/global.h"
+#include "../../analysis/binary.h"
#include "../../core/global.h"
#include "../../core/paths.h"
#include "../../core/queue.h"
diff --git a/src/gui/panels/strings.c b/src/gui/panels/strings.c
index f9d6b00..4627850 100644
--- a/src/gui/panels/strings.c
+++ b/src/gui/panels/strings.c
@@ -859,7 +859,7 @@ static void reload_strings_for_new_list_view(const GStringsPanel *panel, GtkStat
vmpa2_phys_to_string(addr, size, phys, NULL);
vmpa2_virt_to_string(addr, size, virt, NULL);
- portion = g_binary_portion_find_at_addr(portions, addr, (GdkRectangle []) { { 0 } });
+ portion = g_binary_portion_find_at_addr(portions, addr);
area = g_binary_portion_get_desc(portion);
g_object_unref(G_OBJECT(portion));
diff --git a/src/gui/panels/updating.h b/src/gui/panels/updating.h
index 2293a02..b30574d 100644
--- a/src/gui/panels/updating.h
+++ b/src/gui/panels/updating.h
@@ -30,6 +30,7 @@
#include <gtk/gtk.h>
+#include "../../glibext/delayed.h"
#include "../../gtkext/gtkstatusstack.h"
diff --git a/src/gui/panels/welcome.c b/src/gui/panels/welcome.c
index 14e88c5..60593d1 100644
--- a/src/gui/panels/welcome.c
+++ b/src/gui/panels/welcome.c
@@ -32,7 +32,6 @@
#include <string.h>
-#include <config.h>
#include <i18n.h>
diff --git a/src/gui/tb/Makefile.am b/src/gui/tb/Makefile.am
index 3286757..a519d05 100644
--- a/src/gui/tb/Makefile.am
+++ b/src/gui/tb/Makefile.am
@@ -6,16 +6,9 @@ libguitb_la_SOURCES = \
tbitem-int.h \
tbitem.h tbitem.c
-libguitb_la_LDFLAGS =
+libguitb_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libguitb_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/hub.c b/src/hub.c
index 574bb1c..6e4f64d 100644
--- a/src/hub.c
+++ b/src/hub.c
@@ -31,10 +31,11 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include <gtk/gtk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gtk/gtk.h>
+#endif
-#include <config.h>
#include <i18n.h>
@@ -354,7 +355,9 @@ int main(int argc, char **argv)
/* Initialisation de GTK */
g_set_prgname("Chrysalide Hub");
+#ifdef INCLUDE_GTK_SUPPORT
gtk_init(&argc, &argv);
+#endif
/* Initialisation du programme */
diff --git a/src/main.c b/src/main.c
index 356e796..5b3f397 100644
--- a/src/main.c
+++ b/src/main.c
@@ -31,10 +31,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <gtk/gtk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gtk/gtk.h>
+#endif
-#include <config.h>
#include <i18n.h>
@@ -50,9 +51,11 @@
#include "core/paths.h"
#include "core/queue.h"
#include "glibext/delayed.h"
-#include "gui/editor.h"
-#include "gui/core/core.h"
-#include "gui/core/global.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "gui/editor.h"
+# include "gui/core/core.h"
+# include "gui/core/global.h"
+#endif
#include "plugins/pglist.h"
@@ -63,9 +66,13 @@ static void show_chrysalide_help(const char *);
/* Affiche des indications sur la version courante du programme. */
static void show_chrysalide_version(void);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Recharge le dernier projet ouvert s'il existe. */
static gboolean load_last_project(GGenConfig *);
+#endif
+
/* Ouvre les éventuels fichiers fournis au démarrage. */
static int open_binaries(char **, int);
@@ -186,16 +193,20 @@ int main(int argc, char **argv)
bool show_help; /* Affichage de l'aide ? */
bool show_version; /* Affichage de la version ? */
LogMessageType verbosity; /* Niveau de filtre de message */
+#ifdef INCLUDE_GTK_SUPPORT
bool batch_mode; /* Exécution sans GUI ? */
+#endif
bool save; /* Sauvegarde du cache ? */
char *prj_filename; /* Chemin vers un projet */
int index; /* Indice d'argument */
int ret; /* Bilan d'un appel */
char *edir; /* Répertoire de base effectif */
bool status; /* Bilan d'opérations */
+#ifdef INCLUDE_GTK_SUPPORT
GtkWidget *editor; /* Fenêtre graphique */
GGenConfig *config; /* Configuration globale */
bool welcome; /* Affichage de la bienvenue ? */
+#endif
char resolved[PATH_MAX]; /* Résolution de nom de fichier*/
GStudyProject *project; /* Nouveau projet courant */
@@ -225,7 +236,9 @@ int main(int argc, char **argv)
show_version = false;
verbosity = LMT_INFO;
+#ifdef INCLUDE_GTK_SUPPORT
batch_mode = false;
+#endif
save = false;
prj_filename = NULL;
@@ -249,7 +262,9 @@ int main(int argc, char **argv)
break;
case 'b':
+#ifdef INCLUDE_GTK_SUPPORT
batch_mode = true;
+#endif
break;
case 's':
@@ -294,11 +309,15 @@ int main(int argc, char **argv)
/* Initialisation de GTK */
g_set_prgname("Chrysalide");
+#ifdef INCLUDE_GTK_SUPPORT
gtk_init(&argc, &argv);
+#endif
/* Initialisation du programme */
+#ifdef INCLUDE_GTK_SUPPORT
if (batch_mode)
+#endif
set_batch_mode();
set_log_verbosity(verbosity);
@@ -308,6 +327,8 @@ int main(int argc, char **argv)
/* Création de l'interface */
+#ifdef INCLUDE_GTK_SUPPORT
+
if (!batch_mode)
{
editor = create_editor();
@@ -330,8 +351,12 @@ int main(int argc, char **argv)
else
editor = NULL;
+#endif
+
init_all_plugins(true);
+#ifdef INCLUDE_GTK_SUPPORT
+
config = get_main_configuration();
if (!batch_mode)
@@ -340,6 +365,8 @@ int main(int argc, char **argv)
if (!status) goto exit_complete_gui;
}
+#endif
+
/* Lancement du serveur local */
status = ensure_internal_connections_setup();
@@ -354,6 +381,8 @@ int main(int argc, char **argv)
/* Charge le dernier projet ? */
+#ifdef INCLUDE_GTK_SUPPORT
+
if (batch_mode)
welcome = true;
else
@@ -363,6 +392,9 @@ int main(int argc, char **argv)
g_idle_add((GSourceFunc)load_last_project, config);
else
+
+#endif
+
{
if (prj_filename != NULL)
{
@@ -382,7 +414,11 @@ int main(int argc, char **argv)
if (ret == 0)
{
+#ifdef INCLUDE_GTK_SUPPORT
project = g_study_project_open(prj_filename, !batch_mode);
+#else
+ project = g_study_project_open(prj_filename, false);
+#endif
if (project == NULL) goto bad_project;
}
@@ -410,7 +446,12 @@ int main(int argc, char **argv)
result = open_binaries(argv + optind, argc - optind);
+#ifdef INCLUDE_GTK_SUPPORT
+
if (batch_mode)
+
+#endif
+
{
wait_for_all_global_works();
@@ -422,22 +463,28 @@ int main(int argc, char **argv)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
else
gtk_main();
+#endif
+
set_current_project(NULL);
bad_project:
no_internal_server:
+#ifdef INCLUDE_GTK_SUPPORT
exit_complete_gui:
+#endif
#ifdef TRACK_GOBJECT_LEAKS
remember_gtypes_for_leaks();
#endif
- exit_all_plugins();
+#ifdef INCLUDE_GTK_SUPPORT
if (!batch_mode)
unload_all_gui_components();
@@ -449,12 +496,16 @@ int main(int argc, char **argv)
failed_to_load_editor:
+#endif
+
unload_all_core_components(true);
#ifdef TRACK_GOBJECT_LEAKS
dump_remaining_gtypes();
#endif
+ exit_all_plugins();
+
done:
return result;
@@ -462,6 +513,9 @@ int main(int argc, char **argv)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : cfg = configuration globale sur laquelle s'appuyer. *
@@ -492,6 +546,9 @@ static gboolean load_last_project(GGenConfig *cfg)
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : files = noms de fichier fournis en ligne de commande. *
diff --git a/src/mangling/Makefile.am b/src/mangling/Makefile.am
index c1a9427..4c868f7 100644
--- a/src/mangling/Makefile.am
+++ b/src/mangling/Makefile.am
@@ -7,18 +7,9 @@ libmangling_la_SOURCES = \
demangler-int.h \
demangler.h demangler.c
-libmangling_la_LDFLAGS =
-
-libmangling_la_LIBADD =
+libmangling_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libmangling_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index b4ac1d5..6cb8d34 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -11,18 +11,9 @@ libplugins_la_SOURCES = \
plugin.h plugin.c \
self.h
-libplugins_la_CFLAGS = $(AM_CFLAGS)
-
-libplugins_la_LDFLAGS =
+libplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libplugins_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/plugins/dt.c b/src/plugins/dt.c
index c476dde..d678637 100644
--- a/src/plugins/dt.c
+++ b/src/plugins/dt.c
@@ -204,6 +204,25 @@ static void g_dynamic_types_interface_init(GTypePluginClass *iface)
static void g_dynamic_types_dispose(GDynamicTypes *types)
{
+ size_t i; /* Boucle de parcours */
+ type_dyn_info_t *info; /* Information à exploiter */
+ gpointer g_class; /* Classe à oublier */
+
+ for (i = 0; i < types->count; i++)
+ {
+ info = types->info[i];
+
+ if (info->type != G_TYPE_INVALID)
+ {
+ g_class = g_type_class_peek(info->type);
+ g_type_class_unref(g_class);
+
+ info->type = G_TYPE_INVALID;
+
+ }
+
+ }
+
G_OBJECT_CLASS(g_dynamic_types_parent_class)->dispose(G_OBJECT(types));
}
@@ -223,6 +242,14 @@ static void g_dynamic_types_dispose(GDynamicTypes *types)
static void g_dynamic_types_finalize(GDynamicTypes *types)
{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < types->count; i++)
+ free(types->info[i]);
+
+ if (types->info != NULL)
+ free(types->info);
+
G_OBJECT_CLASS(g_dynamic_types_parent_class)->finalize(G_OBJECT(types));
}
@@ -367,7 +394,7 @@ static type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, GType t
* *
* Description : Fournit un identifiant GLib pour un nouveau type. *
* *
-* Retour : identifiant d'un nouveau type valide, ou 0. *
+* Retour : identifiant d'un nouveau type valide, ou G_TYPE_INVALID. *
* *
* Remarques : - *
* *
@@ -382,7 +409,7 @@ static GType g_dynamic_types_register_type(GDynamicTypes *types, GType parent, c
result = g_type_register_dynamic(parent, name, G_TYPE_PLUGIN(types), 0);
- if (result == 0)
+ if (result == G_TYPE_INVALID)
goto exit;
new = malloc(sizeof(type_dyn_info_t));
@@ -467,7 +494,7 @@ void exit_chrysalide_dynamic_types(void)
* *
* Description : Fournit un identifiant GLib pour un nouveau type. *
* *
-* Retour : Identifiant d'un nouveau type valide, ou 0. *
+* Retour : Identifiant d'un nouveau type valide, ou G_TYPE_INVALID. *
* *
* Remarques : - *
* *
diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c
index bacb3ac..6b36d2f 100644
--- a/src/plugins/pglist.c
+++ b/src/plugins/pglist.c
@@ -35,6 +35,7 @@
#include <i18n.h>
+#include "dt.h"
#include "plugin-int.h"
#include "../common/extstr.h"
#include "../core/logs.h"
@@ -75,11 +76,15 @@ static void on_plugin_ref_toggle(gpointer, GPluginModule *, gboolean);
bool init_all_plugins(bool load)
{
+ bool result; /* Bilan à retourner */
char *edir; /* Répertoire de base effectif */
char *env; /* Contenu environnemental */
char *saveptr; /* Sauvegarde pour parcours */
char *udir; /* Répertoire supplémentaire ? */
+ result = init_chrysalide_dynamic_types();
+ if (!result) goto exit;
+
g_rw_lock_init(&_pg_lock);
edir = get_effective_directory_new(TDT_PLUGINS_LIB);
@@ -102,7 +107,9 @@ bool init_all_plugins(bool load)
if (load)
load_remaning_plugins();
- return true;
+ exit:
+
+ return result;
}
@@ -178,6 +185,8 @@ void exit_all_plugins(void)
g_rw_lock_clear(&_pg_lock);
+ exit_chrysalide_dynamic_types();
+
}
@@ -342,6 +351,9 @@ void _register_plugin(GPluginModule *plugin)
}
+ else
+ /* FIXME : leak(plugin); */;
+
}
diff --git a/src/plugins/pglist.h b/src/plugins/pglist.h
index e0aec3f..9063e78 100644
--- a/src/plugins/pglist.h
+++ b/src/plugins/pglist.h
@@ -27,7 +27,9 @@
#include <stdbool.h>
-#include <gtk/gtk.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <gtk/gtk.h>
+#endif
#include "plugin-def.h"
diff --git a/src/plugins/plugin-int.h b/src/plugins/plugin-int.h
index 88e0fbb..067edcb 100644
--- a/src/plugins/plugin-int.h
+++ b/src/plugins/plugin-int.h
@@ -57,6 +57,8 @@ typedef void (* pg_handle_content_fc) (const GPluginModule *, PluginAction, GBin
/* Procède à une opération liée à un contenu chargé. */
typedef void (* pg_handle_loaded_fc) (const GPluginModule *, PluginAction, GLoadedContent *, wgroup_id_t, GtkStatusStack *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Complète une liste de resources pour thème. */
typedef void (* pg_include_theme_fc) (const GPluginModule *, PluginAction, gboolean, char ***, size_t *);
@@ -66,6 +68,8 @@ typedef void (* pg_notify_panel_fc) (const GPluginModule *, PluginAction, GPanel
/* Rend compte d'un affichage ou d'un retrait de panneau. */
typedef void (* pg_notify_docking_fc) (const GPluginModule *, PluginAction, GPanelItem *, bool);
+#endif
+
/* Assure l'interprétation d'un format en différé. */
typedef bool (* pg_handle_format_analysis_fc) (const GPluginModule *, PluginAction, GKnownFormat *, wgroup_id_t, GtkStatusStack *);
@@ -115,9 +119,11 @@ struct _GPluginModuleClass
pg_get_modname_fc get_modname; /* Fourniture du nom brut */
+#ifdef INCLUDE_GTK_SUPPORT
pg_include_theme_fc include_theme; /* Extension d'un thème */
pg_notify_panel_fc notify_panel; /* Création de panneau */
pg_notify_docking_fc notify_docking; /* Affichage ou retrait */
+#endif
pg_handle_content_fc handle_content; /* Explorations ou résolutions */
pg_handle_loaded_fc handle_loaded; /* Traitement de contenu chargé*/
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index e563817..b96decd 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -669,8 +669,10 @@ static void g_plugin_module_init_gclass(GPluginModuleClass *class, GModule *modu
switch (action)
{
case PGA_GUI_THEME:
+#ifdef INCLUDE_GTK_SUPPORT
load_plugin_symbol(module, "chrysalide_plugin_include_theme",
&class->include_theme);
+#endif
break;
default:
@@ -686,13 +688,17 @@ static void g_plugin_module_init_gclass(GPluginModuleClass *class, GModule *modu
switch (action)
{
case PGA_PANEL_CREATION:
+#ifdef INCLUDE_GTK_SUPPORT
load_plugin_symbol(module, "chrysalide_plugin_on_panel_creation",
&class->notify_panel);
+#endif
break;
case PGA_PANEL_DOCKING:
+#ifdef INCLUDE_GTK_SUPPORT
load_plugin_symbol(module, "chrysalide_plugin_on_panel_docking",
&class->notify_docking);
+#endif
break;
default:
@@ -814,6 +820,15 @@ char *g_plugin_module_get_modname(const GPluginModule *plugin)
result = class->get_modname(plugin);
+ /**
+ * Tente une opération de la dernière chance.
+ *
+ * Dans le cas d'un module Python, la fonction de classe peut ne pas
+ * trouver de support si l'extension Python n'est pas au point.
+ */
+ if (result == NULL && class->get_modname != _g_plugin_module_get_modname)
+ result = _g_plugin_module_get_modname(plugin);
+
return result;
}
@@ -1423,6 +1438,9 @@ gpointer g_plugin_module_build_type_instance(GPluginModule *plugin, PluginAction
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : plugin = greffon à manipuler. *
@@ -1501,6 +1519,9 @@ void g_plugin_module_notify_panel_docking(const GPluginModule *plugin, PluginAct
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : plugin = greffon à manipuler. *
diff --git a/src/plugins/plugin.h b/src/plugins/plugin.h
index ff456b3..b13608f 100644
--- a/src/plugins/plugin.h
+++ b/src/plugins/plugin.h
@@ -36,8 +36,10 @@
#include "../format/known.h"
#include "../format/preload.h"
#include "../glibext/configuration.h"
-#include "../gtkext/gtkstatusstack.h"
+#include "../glibext/notifier.h"
+#ifdef INCLUDE_GTK_SUPPORT
#include "../gui/panel.h"
+#endif
@@ -119,6 +121,8 @@ void g_plugin_module_notify_plugins_loaded(GPluginModule *, PluginAction, void *
/* Crée une instance à partir d'un type dynamique externe. */
gpointer g_plugin_module_build_type_instance(GPluginModule *, PluginAction, GType);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Complète une liste de resources pour thème. */
void g_plugin_module_include_theme(const GPluginModule *, PluginAction, gboolean, char ***, size_t *);
@@ -128,6 +132,8 @@ void g_plugin_module_notify_panel_creation(const GPluginModule *, PluginAction,
/* Rend compte d'un affichage ou d'un retrait de panneau. */
void g_plugin_module_notify_panel_docking(const GPluginModule *, PluginAction, GPanelItem *, bool);
+#endif
+
/* Procède à une opération liée à un contenu binaire. */
void g_plugin_module_handle_binary_content(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *);
diff --git a/src/plugins/self.h b/src/plugins/self.h
index 6a2e12d..3c14a0a 100644
--- a/src/plugins/self.h
+++ b/src/plugins/self.h
@@ -26,9 +26,6 @@
#define _PLUGINS_SELF_H
-#include <config.h>
-
-
#ifndef _PLUGINS_PLUGIN_H
# include "plugin.h"
#endif
diff --git a/src/rost.c b/src/rost.c
new file mode 100644
index 0000000..4a052c3
--- /dev/null
+++ b/src/rost.c
@@ -0,0 +1,560 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rost.c - fichier d'entrée du centre de collecte
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <assert.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <locale.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include "gleak.h"
+#include "analysis/contents/file.h"
+#include "analysis/scan/core.h"
+#include "analysis/scan/options.h"
+#include "analysis/scan/scanner.h"
+#include "analysis/scan/patterns/backends/acism.h"
+#include "analysis/scan/patterns/backends/bitap.h"
+#include "analysis/scan/patterns/backends/hyperscan.h"
+#include "core/core.h"
+#include "core/global.h"
+#include "core/logs.h"
+#include "core/paths.h"
+#include "plugins/pglist.h"
+
+
+
+/* Affiche des indications quant à l'utilisation du programme. */
+static void show_rost_help(const char *);
+
+/* Affiche des indications sur la version courante du programme. */
+static void show_rost_version(void);
+
+/* Récupère un contenu à traiter depuis l'entrée standard. */
+static void *get_input_data_from_stdin(size_t *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : name = nom du programme en question. *
+* *
+* Description : Affiche des indications quant à l'utilisation du programme. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void show_rost_help(const char *name)
+{
+ char *tmp; /* Conservation modifiable */
+ char *base; /* Version courte du nom */
+
+ tmp = strdup(name);
+
+ base = basename(tmp);
+
+ printf("\n");
+
+ printf("Usage: %s [--help] [--version] [--verbosity] [options] <rules file> <file | dir>\n", base);
+
+ printf("\n");
+
+ printf("\t-h --help\t\tShow this help message.\n");
+ printf("\t-v --version\t\tDisplay the program version.\n");
+
+ printf("\n");
+
+ printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: acism, bitmap, hyperscan (default: acsim).\n");
+ printf("\t-C --check-only\t\tValidate the rule syntax without performing a scan (discard the file/dir argument).\n");
+ printf("\t-j --print-json\t\tPrint matching strings in JSON format instead of simple text.\n");
+ printf("\t-s --print-strings\tPrint matching strings (default text format only).\n");
+ printf("\t-S --print-stats\tPrint rules' statistics.\n");
+ printf("\t-g --print-tags\t\tPrint tags linked to rules on match (default text format only).\n");
+ printf("\t-t --tag=TAG\t\tPrint only matching rules tagged as TAG (default text format only).\n");
+ printf("\t-V --verbosity=level\tSet the log level (0 for all messages, %u for none).\n", LMT_COUNT);
+
+ printf("\n");
+
+ printf("\t--dump-modifiers\tList all registered modifiers for string patterns.\n");
+ printf("\t--dump-namespaces\tExplore the root namespace with all its functions and sub-namespaces.\n");
+
+ printf("\n");
+
+ free(tmp);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Affiche des indications sur la version courante du programme.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void show_rost_version(void)
+{
+ char *edir; /* Répertoire de base effectif */
+
+ printf("\n");
+
+ printf("-o- Chrysalide ROST r%u -o-\n", REVISION);
+ printf(_("Last compiled on %s at %s\n"), __DATE__, __TIME__);
+
+ printf("\n");
+
+ edir = get_effective_directory(PLUGINS_LIB_DIR);
+ printf(_("Plugins library directory: %s\n"), edir);
+ free(edir);
+
+ edir = get_effective_directory(PLUGINS_DATA_DIR);
+ printf(_("Plugins data directory: %s\n"), edir);
+ free(edir);
+
+ edir = get_effective_directory(LOCALE_DIR);
+ printf(_("Locale directory: %s\n"), edir);
+ free(edir);
+
+ printf("\n");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : length = taille de la définition lue. [OUT] *
+* *
+* Description : Récupère un contenu à traiter depuis l'entrée standard. *
+* *
+* Retour : Adresse valide ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *get_input_data_from_stdin(size_t *length)
+{
+ char *result; /* Espace mémoire à retourner */
+ ssize_t got; /* Quantité d'octets lus */
+
+ result = NULL;
+
+ *length = 0;
+
+#define ALLOC_SIZE 2048
+
+ while (true)
+ {
+ result = realloc(result, (*length + ALLOC_SIZE) * sizeof(char));
+
+ got = read(STDIN_FILENO, result + *length, ALLOC_SIZE);
+
+ if (got == -1)
+ {
+ LOG_ERROR_N("read");
+ goto exit_with_error;
+ }
+
+ *length += got;
+
+ if (got < ALLOC_SIZE)
+ break;
+
+ }
+
+ return result;
+
+ exit_with_error:
+
+ free(result);
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : argc = nombre d'arguments dans la ligne de commande. *
+* argv = arguments de la ligne de commande. *
+* *
+* Description : Point d'entrée du programme. *
+* *
+* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int main(int argc, char **argv)
+{
+ int result; /* Bilan de l'exécution */
+ bool show_help; /* Affichage de l'aide ? */
+ bool show_version; /* Affichage de la version ? */
+ bool check_only; /* Validation uniquement */
+ LogMessageType verbosity; /* Niveau de filtre de message */
+ bool dump_modifiers; /* Affichage des modificateurs */
+ bool dump_namespaces; /* Affichage des fonctions */
+ GScanOptions *options; /* Options d'analyses */
+ int index; /* Indice d'argument */
+ int ret; /* Bilan d'un appel */
+ char *edir; /* Répertoire de base effectif */
+ size_t mod_count; /* Quantité de modificateurs */
+ char **modifiers; /* Liste de modificateurs */
+ size_t i; /* Boucle de parcours */
+ GScanNamespace *root_ns; /* Espace de noms ROST racine */
+ size_t items_count; /* Quantité de modificateurs */
+ char **items; /* Liste de modificateurs */
+ char *rules; /* Définition de règles */
+ char *target; /* Cible communiquée */
+ size_t rule_length; /* Taille d'un contenu */
+ void *rule_content; /* Contenu à traduire */
+ GContentScanner *scanner; /* Encadrement d'une recherche */
+ GBinContent *content; /* Contenu à analyser */
+ GScanContext *context; /* Contexte des trouvailles */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ bool full; /* Détailler l'affichage ? */
+
+#define LONG_ID(n) (0x40570000 | n)
+
+ static struct option long_options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "algorithm", required_argument, NULL, 'A' },
+ { "check-only", no_argument, NULL, 'C' },
+ { "print-json", no_argument, NULL, 'j' },
+ { "print-strings", no_argument, NULL, 's' },
+ { "print-stats", no_argument, NULL, 'S' },
+ { "print-tags", no_argument, NULL, 'g' },
+ { "tag", required_argument, NULL, 't' },
+ { "verbosity", required_argument, NULL, 'V' },
+ { "dump-modifiers", no_argument, NULL, LONG_ID(1) },
+ { "dump-namespaces",no_argument, NULL, LONG_ID(2) },
+ { NULL, 0, NULL, 0 }
+ };
+
+ result = EXIT_FAILURE;
+
+ /* Décodage des options */
+
+ show_help = false;
+ show_version = false;
+
+ check_only = false;
+ verbosity = LMT_COUNT;
+ dump_modifiers = false;
+ dump_namespaces = false;
+
+ options = g_scan_options_new();
+
+ g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND);
+
+ while (true)
+ {
+ ret = getopt_long(argc, argv, "hvA:CjsSgt:V:", long_options, &index);
+ if (ret == -1) break;
+
+ switch (ret)
+ {
+ case 'h':
+ show_help = true;
+ break;
+
+ case 'v':
+ show_version = true;
+ break;
+
+ case 'A':
+ if (strcmp(optarg, "acism") == 0)
+ g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND);
+ else if (strcmp(optarg, "bitmap") == 0)
+ g_scan_options_set_backend_for_data(options, G_TYPE_BITAP_BACKEND);
+ else if (strcmp(optarg, "hyperscan") == 0)
+ g_scan_options_set_backend_for_data(options, G_TYPE_HYPERSCAN_BACKEND);
+ else
+ g_scan_options_set_backend_for_data(options, G_TYPE_INVALID);
+ break;
+
+ case 'C':
+ check_only = true;
+ g_scan_options_set_check_only(options, true);
+ break;
+
+ case 'j':
+ g_scan_options_set_print_json(options, true);
+ break;
+
+ case 's':
+ g_scan_options_set_print_strings(options, true);
+ break;
+
+ case 'S':
+ g_scan_options_set_print_stats(options, true);
+ break;
+
+ case 'g':
+ g_scan_options_set_print_tags(options, true);
+ break;
+
+ case 't':
+ g_scan_options_select_tag(options, optarg);
+ break;
+
+ case 'V':
+ verbosity = strtoul(optarg, NULL, 10);
+ break;
+
+ case LONG_ID(1):
+ dump_modifiers = true;
+ break;
+
+ case LONG_ID(2):
+ dump_namespaces = true;
+ break;
+
+ }
+
+ }
+
+ /* Actions de base */
+
+ if (show_help)
+ {
+ show_rost_help(argv[0]);
+ result = EXIT_SUCCESS;
+ goto done;
+ }
+
+ if (show_version)
+ {
+ show_rost_version();
+ result = EXIT_SUCCESS;
+ goto done;
+ }
+
+ if (g_scan_options_get_backend_for_data(options) == G_TYPE_INVALID)
+ {
+ show_rost_help(argv[0]);
+ goto done;
+ }
+
+ /* Lancement des choses sérieuses */
+
+ setlocale(LC_ALL, "");
+ edir = get_effective_directory(LOCALE_DIR);
+ bindtextdomain(PACKAGE, edir);
+ free(edir);
+ textdomain(PACKAGE);
+
+ /* Initialisation de GTK */
+ g_set_prgname("ROST");
+ //gtk_init(&argc, &argv);
+
+ /* Initialisation du programme */
+
+ set_batch_mode();
+
+ set_log_verbosity(verbosity);
+
+#define CORE_COMPONENTS (ACC_SCAN_FEATURES)
+
+ if (!load_core_components(CORE_COMPONENTS))
+ goto done;
+
+ /*
+ init_all_plugins(true);
+ */
+
+ if (dump_modifiers)
+ {
+ modifiers = list_all_scan_token_modifiers(&mod_count);
+
+ for (i = 0; i < mod_count; i++)
+ {
+ printf("%s\n", modifiers[i]);
+ free(modifiers[i]);
+ }
+
+ if (modifiers != NULL)
+ free(modifiers);
+
+ result = EXIT_SUCCESS;
+
+ }
+
+ if (dump_namespaces)
+ {
+ root_ns = get_rost_root_namespace();
+
+ items = g_scan_namespace_explore(root_ns, &items_count);
+
+ for (i = 0; i < items_count; i++)
+ {
+ printf("%s\n", items[i]);
+ free(items[i]);
+ }
+
+ if (items != NULL)
+ free(items);
+
+ result = EXIT_SUCCESS;
+
+ g_object_unref(G_OBJECT(root_ns));
+
+ }
+
+ if ((check_only && (optind + 0) != argc && (optind + 1) != argc)
+ || (!check_only && (optind + 1) != argc && (optind + 2) != argc))
+ {
+ if (result == EXIT_FAILURE)
+ show_rost_help(argv[0]);
+ goto done;
+ }
+
+ /* Réinitialisation en cas de dump... */
+ else
+ result = EXIT_FAILURE;
+
+ /* Traitement des recherches */
+
+ if ((optind + 0) == argc)
+ {
+ assert(check_only);
+
+ rules = NULL;
+ target = NULL;
+
+ }
+ else if ((optind + 1) == argc)
+ {
+ if (check_only)
+ {
+ rules = argv[optind];
+ target = NULL;
+ }
+ else
+ {
+ rules = NULL;
+ target = argv[optind];
+ }
+ }
+ else
+ {
+ rules = argv[optind];
+ target = argv[optind + 1];
+
+ if (strcmp(rules, "-") == 0 || strcmp(rules, "/dev/stdin") == 0)
+ rules = NULL;
+
+ }
+
+ if (rules == NULL)
+ {
+ rule_content = get_input_data_from_stdin(&rule_length);
+
+ if (rule_content != NULL)
+ {
+ scanner = g_content_scanner_new_from_text(rule_content, rule_length);
+ free(rule_content);
+ }
+ else
+ scanner = NULL;
+
+ }
+ else
+ scanner = g_content_scanner_new_from_file(rules);
+
+ if (scanner != NULL)
+ result = EXIT_SUCCESS;
+
+ if (scanner != NULL && !check_only)
+ {
+ content = g_file_content_new(target);
+ if (content == NULL) goto bad_file_content;
+
+ context = g_content_scanner_analyze(scanner, options, content);
+ if (context == NULL) goto bad_scan_context;
+
+ if (g_scan_options_get_print_json(options))
+ {
+ padding.data = " ";
+ padding.len = 3;
+
+ g_content_scanner_output_to_json(scanner, context, &padding, 0, STDOUT_FILENO);
+
+ }
+ else
+ {
+ full = g_scan_options_get_print_strings(options);
+
+ g_content_scanner_output_to_text(scanner, context, full, STDOUT_FILENO);
+
+ }
+
+ g_object_unref(G_OBJECT(context));
+
+ bad_scan_context:
+
+ g_object_unref(G_OBJECT(content));
+
+ bad_file_content:
+
+ }
+
+ g_clear_object(&scanner);
+
+ g_object_unref(G_OBJECT(options));
+
+ /* Sortie */
+
+#ifdef TRACK_GOBJECT_LEAKS
+ remember_gtypes_for_leaks();
+#endif
+
+ unload_core_components(CORE_COMPONENTS);
+
+#ifdef TRACK_GOBJECT_LEAKS
+ dump_remaining_gtypes();
+#endif
+
+ //exit_all_plugins();
+
+ done:
+
+ return result;
+
+}
diff --git a/tests/analysis/scan/booleans.py b/tests/analysis/scan/booleans.py
new file mode 100644
index 0000000..aa3c1a3
--- /dev/null
+++ b/tests/analysis/scan/booleans.py
@@ -0,0 +1,98 @@
+
+from common import RostTestClass
+
+
+class TestRostBooleans(RostTestClass):
+ """TestCases for booleans and ROST."""
+
+ def testFinalCondition(self):
+ """Validate the final condition."""
+
+ rule = '''
+rule test {
+
+ condition:
+ false
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ true
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testBasicBooleanOperations(self):
+ """Evaluate basic boolean operations."""
+
+ rule = '''
+rule test {
+
+ condition:
+ true and false
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ true or false
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testImplicitCast(self):
+ """Imply implicit casts to booleans."""
+
+ rule = '''
+rule test {
+
+ condition:
+ true and 0
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ 1 or false
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ 1 or ()
+
+}
+'''
+
+ self.check_rule_success(rule)
diff --git a/tests/analysis/scan/common.py b/tests/analysis/scan/common.py
new file mode 100644
index 0000000..507b7e2
--- /dev/null
+++ b/tests/analysis/scan/common.py
@@ -0,0 +1,54 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide.analysis.scan import ContentScanner
+from pychrysalide.analysis.scan import ScanOptions
+from pychrysalide.analysis.scan.patterns.backends import AcismBackend
+
+
+class RostTestClass(ChrysalideTestCase):
+ """TestCase for analysis.scan.ScanExpression."""
+
+ @classmethod
+ def setUpClass(cls):
+
+ super(RostTestClass, cls).setUpClass()
+
+ cls._options = ScanOptions()
+ cls._options.backend_for_data = AcismBackend
+
+ cls._empty_content = MemoryContent(b'')
+
+
+ def _validate_rule_result(self, rule, content, expected):
+ """Check for scan success or failure."""
+
+ scanner = ContentScanner(rule)
+ ctx = scanner.analyze(self._options, content)
+
+ self.assertIsNotNone(ctx)
+
+ if expected:
+ self.assertTrue(ctx.has_match_for_rule('test'))
+ else:
+ self.assertFalse(ctx.has_match_for_rule('test'))
+
+ return scanner, ctx
+
+
+ def check_rule_success(self, rule, content = None):
+ """Check for scan success."""
+
+ if content is None:
+ content = self._empty_content
+
+ self._validate_rule_result(rule, content, True)
+
+
+ def check_rule_failure(self, rule, content = None):
+ """Check for scan failure."""
+
+ if content is None:
+ content = self._empty_content
+
+ self._validate_rule_result(rule, content, False)
diff --git a/tests/analysis/scan/examples.py b/tests/analysis/scan/examples.py
new file mode 100644
index 0000000..74b5094
--- /dev/null
+++ b/tests/analysis/scan/examples.py
@@ -0,0 +1,70 @@
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+
+
+class TestRostExamples(RostTestClass):
+ """TestCases for the examples provides in the ROST documentation."""
+
+ def testComments(self):
+ """Ensure comments do not bother rule definitions."""
+
+ rule = '''
+/*
+ Multi-line header...
+*/
+
+rule test { // comment
+
+ /*
+ * Some context
+ */
+
+ condition: /* List of condition(s) */
+ true // Dummy condition
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testArithmeticPrecedence(self):
+ """Take care of arithmetic operators precedence."""
+
+ rule = '''
+rule test { // MulFirst
+
+ condition:
+ 1 + 4 * (3 + 2) == 21
+ and
+ (1 + 4) * (3 + 2) == 25
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testUintCast(self):
+ """Process nested integer values from binary content."""
+
+ cnt = MemoryContent(b'\x4d\x5a\x00\x00' + b'\x50\x45\x00\x00' + 52 * b'\x00' + b'\x04\x00\x00\x00')
+
+ rule = '''
+rule test { // IsPE
+
+ condition:
+
+ // MZ signature at offset 0 and ...
+
+ uint16(0) == 0x5a4d and
+
+ // ... PE signature at offset stored in the MZ header at offset 0x3c
+
+ uint32(uint32(0x3c)) == 0x00004550
+
+}
+'''
+
+ self.check_rule_success(rule, cnt)
diff --git a/tests/analysis/scan/functions.py b/tests/analysis/scan/functions.py
new file mode 100644
index 0000000..6aca957
--- /dev/null
+++ b/tests/analysis/scan/functions.py
@@ -0,0 +1,239 @@
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+
+
+class TestRostFunctions(RostTestClass):
+ """TestCases for the core functions of ROST."""
+
+ # Core
+ # ====
+
+ def testSetCounter(self):
+ """Count quantities and set sizes."""
+
+ rule = '''
+rule test {
+
+ condition:
+ count("ABC") == 3
+ and count("AB", "C") == count("ABC")
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ cnt = MemoryContent(b'\x01\x02\x02\x03\x03\x03')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $int_01 = "\x01"
+ $int_02 = "\x02"
+ $int_3 = "\x03"
+
+ condition:
+ count($int_0*, $int_3) == #int_*
+
+}
+'''
+
+ self.check_rule_success(rule, cnt)
+
+
+ def testDatasize(self):
+ """Handle the size of the provided data."""
+
+ cnt = MemoryContent(b'\x01\x02\x03\x04')
+
+ cases = [
+ 'datasize == 4',
+ 'uint16(0) == 0x201 and uint16(datasize - 2) == 0x0403',
+ ]
+
+ for c in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ %s
+
+}
+''' % c
+
+ self.check_rule_success(rule, cnt)
+
+
+ def testMaxCommon(self):
+ """Count the largest quantity of same items in a set."""
+
+ cnt = MemoryContent(b'')
+
+ cases = [
+ [ '1', 1 ],
+ [ '1, 2, 3', 1 ],
+ [ '1, 2, 1, 3, 1', 3 ],
+ [ '1, "a", 2, 3, "a"', 2 ],
+ ]
+
+ for c, q in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ maxcommon(%s) == %u
+
+}
+''' % (c, q)
+
+ self.check_rule_success(rule, cnt)
+
+
+ # Modules
+ # =======
+
+ def testConsole(self):
+ """Ensure logging always returns true."""
+
+ rule = '''
+rule test {
+
+ condition:
+ console.log()
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testMagic(self):
+ """Scan text content with the Magic module."""
+
+ cnt = MemoryContent(b'aaaa')
+
+ cases = [
+ [ 'type', 'ASCII text, with no line terminators' ],
+ [ 'mime_encoding', 'us-ascii' ],
+ [ 'mime_type', 'text/plain' ],
+ ]
+
+ for target, expected in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ magic.%s() == "%s"
+
+}
+''' % (target, expected)
+
+ self.check_rule_success(rule, cnt)
+
+
+ def testMathOperations(self):
+ """Perform math operations with core functions."""
+
+ rule = '''
+rule test {
+
+ condition:
+ math.to_string(123) == "123"
+ and math.to_string(291, 16) == "0x123"
+ and math.to_string(-83, 8) == "-0123"
+ and math.to_string(123, 2) == "0b1111011"
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testStringOperations(self):
+ """Perform string operations with core functions."""
+
+ rule = '''
+rule test {
+
+ condition:
+ string.lower("ABCd") == "abcd" and string.lower("123abc") == "123abc"
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ string.upper("abcD") == "ABCD" and string.upper("123ABC") == "123ABC"
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ string.to_int("123") == 123
+ and string.to_int("123", 16) == 291
+ and string.to_int("0x123") == 291
+ and string.to_int("-0123") == -83
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = r'''
+rule test {
+
+ condition:
+ "A\x00B\x00C\x00D\x00" endswith string.wide("CD")
+ and "A\x00B\x00C\x00D\x00" contains string.wide("BC")
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testTime(self):
+ """Check current time."""
+
+ # Cf. https://www.epochconverter.com/
+
+ rule = '''
+rule test {
+
+ condition:
+ time.make(2023, 8, 5, 22, 8, 41) == 0x64cec869
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ time.now() >= 0x64cec874 and time.now() <= time.now()
+
+}
+'''
+
+ self.check_rule_success(rule)
diff --git a/tests/analysis/scan/fuzzing.py b/tests/analysis/scan/fuzzing.py
new file mode 100644
index 0000000..1b9b25b
--- /dev/null
+++ b/tests/analysis/scan/fuzzing.py
@@ -0,0 +1,289 @@
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide.analysis.scan import ContentScanner
+from pychrysalide.analysis.scan import ScanOptions
+from pychrysalide.analysis.scan.patterns.backends import AcismBackend
+from pychrysalide.analysis.scan.patterns.backends import BitapBackend
+
+
+class TestRostFuzzingFixes(RostTestClass):
+ """TestCases to remember all the fixes for crashes identified by fuzzing."""
+
+ def testEmptyPatternListWithContent(self):
+ """Check no backend is run if there is no pattern to look for."""
+
+ content = MemoryContent(b'\n')
+
+ rule = '''
+'''
+
+ backends = [
+ AcismBackend, # This one was segfaulting
+ BitapBackend,
+ ]
+
+ for b in backends:
+
+ options = ScanOptions()
+ options.backend_for_data = b
+
+ scanner = ContentScanner(rule)
+ ctx = scanner.analyze(options, content)
+
+ self.assertIsNotNone(ctx)
+
+
+ def testMandatoryCondition(self):
+ """Ensure a condition section exists in a rule."""
+
+ rule = '''
+rule test {
+
+}
+'''
+
+ with self.assertRaisesRegex(ValueError, 'Unable to create content scanner'):
+
+ scanner = ContentScanner(rule)
+
+
+ def testNonExistingPattern(self):
+ """Avoid to count the matches of a non-existing pattern."""
+
+ rule = '''
+rule test {
+
+ condition:
+ #badid
+
+}
+'''
+
+ with self.assertRaisesRegex(ValueError, 'Unable to create content scanner'):
+
+ scanner = ContentScanner(rule)
+
+
+ def testNamespacesWithoutReductionCode(self):
+ """Clean the code for ROST namespaces."""
+
+ rule = '''
+rule test {
+
+ condition:
+ console
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ def testCallOnNonCallable(self):
+ """Reject calls on non callable expressions softly."""
+
+ rule = '''
+rule test {
+
+ condition:
+ console.log().log()
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ def testSelfReferencingRule(self):
+ """Reject any rule referencing itself as match condition."""
+
+ rule = '''
+rule test {
+
+ condition:
+ test
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ def testSelfReferencingRule(self):
+ """Expect only one argument for the not operator, even in debug mode."""
+
+ rule = '''
+rule test {
+
+ condition:
+ not(0)
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testNoCommon(self):
+ """Handle the case where no common item is found from an empty set."""
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "a"
+
+ condition:
+ maxcommon($a) == 0
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testAAsAcharacter(self):
+ """Consider the 'a' character as a valid lowercase character."""
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "0000a0I0" nocase
+
+ condition:
+ $a
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ def testAAsAcharacter(self):
+ """Do not expect initialized trackers when there is no real defined search pattern."""
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = {[0]}
+
+ condition:
+ $a
+
+}
+'''
+
+ with self.assertRaisesRegex(ValueError, 'Unable to create content scanner'):
+
+ scanner = ContentScanner(rule)
+
+
+ def testAllocations(self):
+ """Handle big alloctions for strings in conditions with regular expressions."""
+
+ rule = '''
+rule test {
+
+ condition:
+ "%s" == "%s"
+
+}
+''' % ("0" * (256 * 2 + 8), "0" * (256 * 2 + 8))
+
+ self.check_rule_success(rule)
+
+
+ def testFileFinalAccess(self):
+ """Ensure patterns found at the edges of scanned content do not crash the scanner."""
+
+ cnt = MemoryContent(bytes([ 0 for i in range(16) ]))
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 00 00 00 00 00 00 00 00 }
+
+ condition:
+ $a
+
+}
+'''
+
+ self.check_rule_success(rule, cnt)
+
+
+ def testValidHexRangeMerge(self):
+ """Merge valid hexadecimal ranges."""
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { [0] ?? }
+
+ condition:
+ $a
+
+}
+'''
+
+ with self.assertRaisesRegex(ValueError, 'Unable to create content scanner'):
+
+ scanner = ContentScanner(rule)
+
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { [2] ?? }
+
+ condition:
+ $a
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ def testSmallBase64(self):
+ """Handle small base64 encodings which may produce few patterns."""
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "0" base64
+
+ condition:
+ $a
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ def testCountIndex(self):
+ """Ban pattern count indexes from the grammer."""
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "1"
+
+ condition:
+ #*[0]
+
+}
+'''
+
+ with self.assertRaisesRegex(ValueError, 'Unable to create content scanner'):
+
+ scanner = ContentScanner(rule)
diff --git a/tests/analysis/scan/grammar.py b/tests/analysis/scan/grammar.py
new file mode 100644
index 0000000..14f67fa
--- /dev/null
+++ b/tests/analysis/scan/grammar.py
@@ -0,0 +1,484 @@
+
+import json
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+
+
+class TestRostGrammar(RostTestClass):
+ """TestCases for the ROST grammar."""
+
+ def testRelationalExpressions(self):
+ """Build expressions with relational comparisons."""
+
+ cases = [
+
+ # Regular
+ [ '-1', '<=', '2', True ],
+ [ '-1', '<=', '2', True ],
+ [ '"aaa"', '==', '"aaa"', True ],
+ [ '"aaa"', '<', '"aaaa"', True ],
+ [ '""', '<', '"aaaa"', True ],
+
+ # Cast
+ [ 'false', '==', '0', True ],
+ [ 'false', '==', '1', False ],
+ [ 'true', '!=', '0', True ],
+ [ '1', '==', 'true', True ],
+ [ 'false', '==', '()', True ],
+ [ 'true', '==', '(0,)', True ],
+
+ ]
+
+ for op1, kwd, op2, expected in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ %s %s %s
+
+}
+''' % (op1, kwd, op2)
+
+ if expected:
+ self.check_rule_success(rule)
+ else:
+ self.check_rule_failure(rule)
+
+
+ def testLogicalOperations(self):
+ """Evaluate some logical operations."""
+
+ cases = [
+ [ 'true and false', False ],
+ [ 'false or false', False ],
+ [ 'true and true or false', True ],
+ [ 'false or true and false', False ],
+ [ '1 or false', True ],
+ ]
+
+ for cond, expected in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ %s
+
+}
+''' % (cond)
+
+ if expected:
+ self.check_rule_success(rule)
+ else:
+ self.check_rule_failure(rule)
+
+
+ def testArithmeticOperations(self):
+ """Evaluate some arithmetic operations."""
+
+ cases = [
+
+ # Clever
+ '1 + 2 == 3',
+ '10 + -3 == 7',
+ '-3 + 10 == 7',
+ '-10 - 1 < 0',
+ '-10 - 1 == -11',
+ '(-10 - 1) == -11',
+ '(-1 - -10) == 9',
+ '-2 * -3 == 6',
+ '-2 * 3 == -6',
+
+ # Legacy
+ '1 + 4 * 3 + 2 == 15',
+ '(1 + 4) * 3 + 2 == 17',
+ '1 + 4 * (3 + 2) == 21',
+ '(1 + 4) * (3 + 2) == 25',
+
+ ]
+
+ for c in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ %s
+
+}
+''' % (c)
+
+ self.check_rule_success(rule)
+
+
+ def testBasicStringsOperations(self):
+ """Build expressions with basic strings operations."""
+
+ cases = [
+
+ # Clever
+ [ '123---456', 'contains', '---', True ],
+ [ '123---456', 'contains', 'xxx', False ],
+ [ '---123---456', 'startswith', '---', True ],
+ [ '---123---456', 'startswith', 'xxx', False ],
+ [ '123---456---', 'endswith', '---', True ],
+ [ '123---456---', 'endswith', 'xxx', False ],
+ [ 'AAA---BBB', 'icontains', 'aaa', True ],
+ [ 'AAA---BBB', 'icontains', 'xxx', False ],
+ [ 'AAA---BBB', 'istartswith', 'aAa', True ],
+ [ 'AAA---BBB', 'istartswith', 'xxx', False ],
+ [ 'AAA---BBB', 'iendswith', 'bBb', True ],
+ [ 'AAA---BBB', 'iendswith', 'xxx', False ],
+ [ 'AzertY', 'iequals', 'AZERTY', True ],
+ [ 'AzertY', 'iequals', 'AZERTY-', False ],
+
+ # Legacy
+ [ '123\t456', 'contains', '\t', True ],
+ [ '123-456', 'startswith', '1', True ],
+ [ '123-456', 'startswith', '1234', False ],
+ [ '123-456', 'endswith', '6', True ],
+ [ '123-456', 'endswith', '3456', False ],
+
+ ]
+
+ for op1, kwd, op2, expected in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ "%s" %s "%s"
+
+}
+''' % (op1, kwd, op2)
+
+ if expected:
+ self.check_rule_success(rule)
+ else:
+ self.check_rule_failure(rule)
+
+
+ def testSizeUnits(self):
+ """Evaluate size units."""
+
+ cases = [
+ '1KB == 1024',
+ '2MB == 2 * 1024 * 1024',
+ '4Kb == (4 * 1024)',
+ '1KB <= 1024 and 1024 < 1MB',
+ ]
+
+ for c in cases:
+
+ rule = '''
+rule test {
+
+ condition:
+ %s
+
+}
+''' % (c)
+
+ self.check_rule_success(rule)
+
+
+ def testPrivateRules(self):
+ """Ensure private rules remain silent."""
+
+ for private in [ True, False ]:
+ for state in [ True, False ]:
+
+ rule = '''
+%srule silent {
+
+ condition:
+ %s
+
+}
+
+rule test {
+
+ condition:
+ silent
+
+}
+''' % ('private ' if private else '', 'true' if state else 'false')
+
+ scanner, ctx = self._validate_rule_result(rule, self._empty_content, state)
+
+ data = scanner.convert_to_json(ctx)
+ jdata = json.loads(data)
+
+ # Exemple :
+ #
+ # [{'bytes_patterns': [], 'matched': True, 'name': 'test'},
+ # {'bytes_patterns': [], 'matched': True, 'name': 'silent'}]
+
+ found = len([ j['name'] for j in jdata if j['name'] == 'silent' ]) > 0
+
+ self.assertTrue(private ^ found)
+
+
+ def testGlobalRules(self):
+ """Take global rules into account."""
+
+ for glob_state in [ True, False ]:
+ for state in [ True, False ]:
+
+ rule = '''
+%srule silent {
+
+ condition:
+ %s
+
+}
+
+rule test {
+
+ condition:
+ true
+
+}
+''' % ('global ' if glob_state else '', 'true' if state else 'false')
+
+ expected = not(glob_state) or state
+
+ if expected:
+ self.check_rule_success(rule)
+ else:
+ self.check_rule_failure(rule)
+
+
+ def testMatchCount(self):
+ """Ensure match count provides expected values."""
+
+ cnt = MemoryContent(b'\x01\x02\x02\x03\x03\x03')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $int_01 = "\x01"
+ $int_02 = "\x02"
+ $int_03 = "\x03"
+
+ condition:
+ #int_01 == count($int_01) and #int_01 == 1
+ and #int_02 == count($int_02) and #int_02 == 2
+ and #int_03 == count($int_03) and #int_03 == 3
+ and #int_0* == count($int_0*) and #int_0* == 6
+
+}
+'''
+
+ self.check_rule_success(rule, cnt)
+
+
+ def testBackingUpHandlers(self):
+ """Ensure handlers for backing up removals do not limit the grammar."""
+
+ cnt = MemoryContent(b'AB12')
+
+ # Uncompleted token in rule definition: '?? ?? '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? ?? }
+
+ condition:
+ #a == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '?? '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? 4? }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '?? ?'
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? ?2 }
+
+ condition:
+ #a == 2
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '?? '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? 42 }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ # Uncompleted token in rule definition: '?1 ?'
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?1 ?? }
+
+ condition:
+ #a == 2
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '?1 4? '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?1 4? }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '?1 ?2 '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?1 ?2 }
+
+ condition:
+ #a == 2
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '?1 4'
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?1 42 }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ # Uncompleted token in rule definition: '41 '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 ?? }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '41 4'
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 4? }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '41 '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 ?2 }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+ # Uncompleted token in rule definition: '41 42 '
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 42 }
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+
+
+# TODO : test <haystack> matches <regex>
+
+
+
diff --git a/tests/analysis/scan/matches.py b/tests/analysis/scan/matches.py
new file mode 100644
index 0000000..efcae4f
--- /dev/null
+++ b/tests/analysis/scan/matches.py
@@ -0,0 +1,64 @@
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+
+
+class TestRostMatchs(RostTestClass):
+ """TestCases for the ROST pattern matching engine."""
+
+ def testCountMatches(self):
+ """Count matched patterns."""
+
+ cnt = MemoryContent(b'aaa aaa bbb aaa')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "aaa"
+ $b = "bbb"
+
+ condition:
+ #a == 3 and #b < 2
+
+}
+'''
+
+ self.check_rule_success(rule, cnt)
+
+
+ def testCountSameMatches(self):
+ """Count matches of similar patterns."""
+
+ cnt = MemoryContent(b'ABCDabcdABCDabcd')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "\x61\x62\x63\x64"
+ $b = "\x61\x62\x63\x64"
+
+ condition:
+ #a == 2 and #b == 2
+
+}
+'''
+
+ self.check_rule_success(rule, cnt)
+
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "\x61\x62\x63\x64"
+ $b = "\x61\x62\x63"
+
+ condition:
+ #a == 2 and #b == 2
+
+}
+'''
+
+ self.check_rule_success(rule, cnt)
diff --git a/tests/analysis/scan/pyapi.py b/tests/analysis/scan/pyapi.py
new file mode 100644
index 0000000..7a697b3
--- /dev/null
+++ b/tests/analysis/scan/pyapi.py
@@ -0,0 +1,297 @@
+
+import binascii
+import struct
+
+from chrysacase import ChrysalideTestCase
+from gi._constants import TYPE_INVALID
+from pychrysalide.analysis.scan import ScanExpression
+from pychrysalide.analysis.scan import ScanOptions
+from pychrysalide.analysis.scan import find_token_modifiers_for_name
+from pychrysalide.glibext import ComparableItem
+
+
+class TestRostPythonAPI(ChrysalideTestCase):
+ """TestCase for the ROST Python API."""
+
+ def testEmptyOptions(self):
+ """Check default scan options."""
+
+ ops = ScanOptions()
+
+ self.assertEqual(ops.backend_for_data, TYPE_INVALID)
+
+
+ def testDirectInstancesOfExpression(self):
+ """Reject direct instances of ROST expressions."""
+
+ with self.assertRaisesRegex(RuntimeError, 'pychrysalide.analysis.scan.ScanExpression is an abstract class'):
+
+ e = ScanExpression()
+
+
+ def testBooleanComparison(self):
+ """Compare custom scan expressions."""
+
+ class StrLenExpr(ScanExpression):
+
+ def __init__(self, value):
+ super().__init__(ScanExpression.ScanReductionState.REDUCED)
+ self._value = value
+
+ def _cmp_rich(self, other, op):
+
+ if op == ComparableItem.RichCmpOperation.EQ:
+ return len(self._value) == len(other._value)
+
+
+ e0 = StrLenExpr('00000000000')
+
+ e1 = StrLenExpr('00000000000')
+
+ e2 = StrLenExpr('000000000000000000000000000')
+
+ self.assertTrue(e0 == e1)
+
+ # !?
+ # Python teste e0 != e1 (non implémenté), puis e1 != e0 (pareil) et en déduit une différence !
+ # self.assertFalse(e0 != e1)
+
+ self.assertFalse(e0 == e2)
+
+ # TypeError: '<' not supported between instances of 'StrLenExpr' and 'StrLenExpr'
+ with self.assertRaisesRegex(TypeError, '\'<\' not supported between instances'):
+ self.assertTrue(e0 < e1)
+
+
+ def testBytePatternModifiers(self):
+ """Validate the bytes produced by modifiers."""
+
+ mod = find_token_modifiers_for_name('plain')
+ self.assertIsNotNone(mod)
+
+ source = b'ABC'
+ transformed = mod.transform(source)
+
+ self.assertEqual(source, transformed[0])
+
+
+ mod = find_token_modifiers_for_name('hex')
+ self.assertIsNotNone(mod)
+
+ source = b'ABC'
+ transformed = mod.transform(source)
+
+ self.assertEqual(binascii.hexlify(source), transformed[0])
+
+
+ mod = find_token_modifiers_for_name('rev')
+ self.assertIsNotNone(mod)
+
+ source = b'ABC'
+ transformed = mod.transform(source)
+
+ self.assertEqual(source[::-1], transformed[0])
+
+
+ mod = find_token_modifiers_for_name('lower')
+ self.assertIsNotNone(mod)
+
+ source = b'AbC'
+ transformed = mod.transform(source)
+
+ self.assertEqual(source.lower(), transformed[0])
+
+
+ mod = find_token_modifiers_for_name('upper')
+ self.assertIsNotNone(mod)
+
+ source = b'AbC'
+ transformed = mod.transform(source)
+
+ self.assertEqual(source.upper(), transformed[0])
+
+
+ mod = find_token_modifiers_for_name('wide')
+ self.assertIsNotNone(mod)
+
+ source = b'ABC'
+ transformed = mod.transform(source)
+
+ self.assertEqual(source.decode('ascii'), transformed[0].decode('utf-16-le'))
+
+
+ mod = find_token_modifiers_for_name('base64')
+ self.assertIsNotNone(mod)
+
+ source = b'ABC'
+ transformed = mod.transform(source)
+
+ self.assertEqual(len(transformed), 3)
+ self.assertEqual(transformed[0], b'QUJD')
+ self.assertEqual(transformed[1], b'FCQ')
+ self.assertEqual(transformed[2], b'BQk')
+
+
+ def testClassicalAPIHashing(self):
+ """Reproduce classical API Hashing results."""
+
+ def b2i(t):
+ return struct.unpack('<I', t)[0]
+
+
+ # Example:
+ # - PlugX (2020) - https://vms.drweb.fr/virus/?i=21512304
+
+ mod = find_token_modifiers_for_name('crc32')
+ self.assertIsNotNone(mod)
+
+ source = b'GetCurrentProcess\x00'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0x3690e66)
+
+
+ # Example:
+ # - GuLoader (2020) - https://www.crowdstrike.com/blog/guloader-malware-analysis/
+
+ mod = find_token_modifiers_for_name('djb2')
+ self.assertIsNotNone(mod)
+
+ source = b'GetProcAddress'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0xcf31bb1f)
+
+
+ def testCustomAPIHashing(self):
+ """Reproduce custom API Hashing results."""
+
+ def b2i(t):
+ return struct.unpack('<I', t)[0]
+
+
+ # Example:
+ # Underminer Exploit Kit (2019) - https://jsac.jpcert.or.jp/archive/2019/pdf/JSAC2019_1_koike-nakajima_jp.pdf
+
+ mod = find_token_modifiers_for_name('add1505-shl5')
+ self.assertIsNotNone(mod)
+
+ source = b'LoadLibraryA'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0x5fbff0fb)
+
+
+ # Example:
+ # Enigma Stealer (2023) https://www.trendmicro.com/es_mx/research/23/b/enigma-stealer-targets-cryptocurrency-industry-with-fake-jobs.html
+
+ mod = find_token_modifiers_for_name('enigma-murmur')
+ self.assertIsNotNone(mod)
+
+ source = b'CreateMutexW'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0xfd43765a)
+
+
+ # Examples:
+ # - ShadowHammer (2019) - https://blog.f-secure.com/analysis-shadowhammer-asus-attack-first-stage-payload/
+ # - ShadowHammer (2019) - https://securelist.com/operation-shadowhammer-a-high-profile-supply-chain-attack/90380/
+
+ mod = find_token_modifiers_for_name('imul21-add')
+ self.assertIsNotNone(mod)
+
+ source = b'VirtualAlloc'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0xdf894b12)
+
+
+ # Examples:
+ # - Bottle Exploit Kit (2019) - https://nao-sec.org/2019/12/say-hello-to-bottle-exploit-kit.html
+ # - ShadowHammer (2019) - https://securelist.com/operation-shadowhammer-a-high-profile-supply-chain-attack/90380/
+
+ mod = find_token_modifiers_for_name('imul83-add')
+ self.assertIsNotNone(mod)
+
+ source = b'GetProcAddress'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0x9ab9b854)
+
+
+ # Examples:
+ # - ?? (2021) - https://www.threatspike.com/blogs/reflective-dll-injection
+ # - Mustang Panda (2022) - https://blog.talosintelligence.com/mustang-panda-targets-europe/
+
+ mod = find_token_modifiers_for_name('ror13')
+ self.assertIsNotNone(mod)
+
+ source = b'GetProcAddress'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0x7c0dfcaa)
+
+ source = b'VirtualAlloc'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0x91afca54)
+
+
+ # Example:
+ # - Energetic Bear (2019) - https://insights.sei.cmu.edu/blog/api-hashing-tool-imagine-that/
+
+ mod = find_token_modifiers_for_name('sll1-add-hash32')
+ self.assertIsNotNone(mod)
+
+ source = b'LoadLibraryA'
+ transformed = mod.transform(source)
+
+ self.assertEqual(b2i(transformed[0]), 0x000d5786)
+
+
+ # Example:
+ # - SideWinder/WarHawk (2022) - https://www.zscaler.com/blogs/security-research/warhawk-new-backdoor-arsenal-sidewinder-apt-group
+
+ mod = find_token_modifiers_for_name('sub42')
+ self.assertIsNotNone(mod)
+
+ source = b'LoadLibraryA'
+ transformed = mod.transform(source)
+
+ self.assertEqual(transformed[0], b'\x8e\xb1\xa3\xa6\x8e\xab\xa4\xb4\xa3\xb4\xbb\x83')
+
+
+ # Example:
+ # - TrickBot (2021) - https://medium.com/walmartglobaltech/trickbot-crews-new-cobaltstrike-loader-32c72b78e81c
+
+ mod = find_token_modifiers_for_name('sub-index1')
+ self.assertIsNotNone(mod)
+
+ source = b'raw.githubusercontent.com'
+ transformed = mod.transform(source)
+
+ self.assertEqual(transformed[0], b'\x73\x63\x7a\x32\x6c\x6f\x7b\x70\x7e\x6c\x80\x7f\x72\x80\x72\x7f\x7f\x86\x78\x82\x89\x44\x7a\x87\x86')
+
+
+ def testBytePatternModifiersAPI(self):
+ """Validate the API for pattern modifiers."""
+
+ mod = find_token_modifiers_for_name('plain')
+ self.assertIsNotNone(mod)
+
+ source = [ b'ABC', b'01234' ]
+ transformed = mod.transform(source)
+
+ self.assertEqual(len(source), len(transformed))
+ self.assertEqual(source[0], transformed[0])
+ self.assertEqual(source[1], transformed[1])
+
+
+ mod = find_token_modifiers_for_name('xor')
+ self.assertIsNotNone(mod)
+
+ source = [ b'ABC' ]
+ transformed = mod.transform(source, 0x20)
+
+ self.assertEqual(transformed[0], b'abc')
diff --git a/tests/analysis/scan/scanning_hex.py b/tests/analysis/scan/scanning_hex.py
new file mode 100644
index 0000000..4b0fda4
--- /dev/null
+++ b/tests/analysis/scan/scanning_hex.py
@@ -0,0 +1,716 @@
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+
+
+class TestRostScanningBinary(RostTestClass):
+ """TestCases for the bytes section syntax (binary)."""
+
+ def testLonelyPatterns(self):
+ """Evaluate the most simple patterns."""
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 }
+
+ condition:
+ #a == 1 and @a[0] == 0
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 62 }
+
+ condition:
+ #a == 1 and @a[0] == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 66 }
+
+ condition:
+ #a == 1 and @a[0] == 5
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?1 }
+
+ condition:
+ #a == 1 and @a[0] == 0
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?2 }
+
+ condition:
+ #a == 1 and @a[0] == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?6 }
+
+ condition:
+ #a == 1 and @a[0] == 5
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def ___testLonelyPatternsNot(self):
+ """Evaluate the most simple patterns (not version)."""
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ~41 }
+
+ condition:
+ #a == 5 and @a[0] == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ~62 }
+
+ condition:
+ #a == 5 and @a[0] == 0
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ~66 }
+
+ condition:
+ #a == 5 and @a[4] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ~?1 }
+
+ condition:
+ #a == 5 and @a[0] == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ~?2 }
+
+ condition:
+ #a == 5 and @a[0] == 0
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'Abcdef')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ~?6 }
+
+ condition:
+ #a == 5 and @a[4] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testSimpleHexPattern(self):
+ """Test a simple hex pattern."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 62 63 }
+
+ condition:
+ #a == 1 and @a[0] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 2d 41 62 63 }
+
+ condition:
+ #a == 1 and @a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testSimpleMaskedHexPattern(self):
+ """Test a simple masked hex pattern."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?1 6? ?3 }
+
+ condition:
+ #a == 1 and @a[0] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testHexPatternWithPlainAndMasked(self):
+ """Test hex patterns with plain and masked bytes."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 6? ?3 }
+
+ condition:
+ #a == 1 and @a[0] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 4? 62 ?3 }
+
+ condition:
+ #a == 1 and @a[0] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 4? ?2 63 }
+
+ condition:
+ #a == 1 and @a[0] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 4? ?2 ?3 }
+
+ condition:
+ #a == 1 and @a[0] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 2d 4? ?2 63 }
+
+ condition:
+ #a == 1 and @a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 2d 4? 62 ?3 2d }
+
+ condition:
+ #a == 1 and @a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 2? 41 6? 63 ?d }
+
+ condition:
+ #a == 1 and @a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testHexPatternWithPlainAndHoles(self):
+ """Test hex patterns with plain bytes and holes."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 33 ?? 41 ?? 63 ?? 34 }
+
+ condition:
+ #a == 1 and @a[0] == 2
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? 33 ?? 41 ?? 63 ?? 34 ?? }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? 33 [1-5] 63 ?? 34 ?? }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { [3-4] 41 ?? 63 ?? 34 ?? }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? 33 ?? 41 ?? 63 [3-] }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testHexPatternWithMaskedAndHoles(self):
+ """Test hex patterns with masked bytes and holes."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?3 ?? 4? ?? 6? ?? ?4 }
+
+ condition:
+ #a == 1 and @a[0] == 2
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? ?3 ?? 4? ?? 6? ?? ?4 ?? }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? ?3 [1-5] ?3 ?? ?4 ?? }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { [3-4] ?1 ?? ?3 ?? ?4 ?? }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ?? 3? ?? 4? ?? 6? [3-] }
+
+ condition:
+ #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testPipedPlainHexPatterns(self):
+ """Look for several patterns at once with piped definition."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 62 ( 63 | 64 | 65 ) }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ( 41 | f2 | f3 ) 62 63 }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 41 ( 61 | 62 | 63 ) 63 }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ( 41 62 63 | 42 62 63 | 43 62 63 ) }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testPipedMaskedHexPatterns(self):
+ """Look for several patterns at once with piped and masked definition."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 4? 6? ( ?3 | ?4 | ?5 ) }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ( ?1 | ?2 | ?3 ) 6? 6? }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { 4? ( ?1 | ?2 | ?3 ) 6? }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testDuplicatedResultsFiltering(self):
+ """Filter duplicated results."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = { ( 4? ?2 ?3 | 4? 6? 6? | ?3 6? ?3 ) }
+
+ condition:
+ #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
diff --git a/tests/analysis/scan/scanning_str.py b/tests/analysis/scan/scanning_str.py
new file mode 100644
index 0000000..75427a7
--- /dev/null
+++ b/tests/analysis/scan/scanning_str.py
@@ -0,0 +1,194 @@
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+
+
+class TestRostScanningStrings(RostTestClass):
+ """TestCases for the bytes section syntax (strings)."""
+
+ def testSimpleStringPattern(self):
+ """Test a simple string pattern."""
+
+ cnt = MemoryContent(b'123-Abc-456')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "Abc"
+
+ condition:
+ #a == 1 and @a[0] == 4
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testEscapedStringPattern(self):
+ """Test escaped string patterns."""
+
+ cnt = MemoryContent(b'\a\b\t\n\v\f\r' + bytes([ 0x1b ]) + b'"\\\xff')
+
+ rule = r'''
+rule test {
+
+ bytes:
+ $a = "\a\b\t\n\v\f\r\e\"\\\xff"
+
+ condition:
+ #a == 1 and @a[0] == 0
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'\a\b\t\n--123--\v\f\r' + bytes([ 0x1b ]) + b'"\\\xff')
+
+ rule = r'''
+rule test {
+
+ bytes:
+ $a = "\a\b\t\n--123--\v\f\r\e\"\\\xff"
+
+ condition:
+ #a == 1 and @a[0] == 0
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testStringModifiers(self):
+ """Check string modifiers output."""
+
+ cnt = MemoryContent(b'--414243--')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "ABC" hex
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'--ABC--')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "ABC" plain
+
+ condition:
+ #a == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'--CBA--')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "ABC" rev
+
+ condition:
+ #a == 1
+
+}
+'''
+
+
+ def testStringPatternFullword(self):
+ """Test a fullword string pattern."""
+
+ cnt = MemoryContent(b'ABCDEF 123 ')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "DEF" fullword
+ $b = "123" fullword
+
+ condition:
+ #a == 0 and #b == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'DEF 123 ')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "DEF" fullword
+ $b = "123" fullword
+
+ condition:
+ #a == 1 and #b == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ cnt = MemoryContent(b'\tDEF 123 ')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "DEF" fullword
+ $b = "123" fullword
+
+ condition:
+ #a == 1 and #b == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
+
+
+ def testStringPatternCase(self):
+ """Test a string pattern with case care."""
+
+ cnt = MemoryContent(b'abc123-Abc123Def456GHI...z0z1z2z3z4z5z6z7z8z9')
+
+ rule = '''
+rule test {
+
+ bytes:
+ $a = "Abc" nocase
+ $b = "ABC123DEF456GHI" nocase
+ $z = "z0z1z2z3z4z5z6z7z8z9" nocase
+
+ condition:
+ #a == 2 and #b == 1 and #z == 1
+
+}
+'''
+
+ self.check_rule_success(rule, content=cnt)
diff --git a/tests/analysis/scan/sets.py b/tests/analysis/scan/sets.py
new file mode 100644
index 0000000..1d10fbf
--- /dev/null
+++ b/tests/analysis/scan/sets.py
@@ -0,0 +1,118 @@
+
+from common import RostTestClass
+
+
+class TestRostSets(RostTestClass):
+ """TestCases for sets support in ROST."""
+
+ def testSetsAsBooleans(self):
+ """Convert sets to boolean."""
+
+ rule = '''
+rule test {
+
+ condition:
+ ()
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ (1, )
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ ("aaa", true, 123)
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testStringAsArray(self):
+ """Handle strings as arrays."""
+
+ rule = '''
+rule test {
+
+ condition:
+ count("aaa")
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ count("aaa") == 3
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ def testSetsIntersections(self):
+ """Perform sets intersections."""
+
+ rule = '''
+rule test {
+
+ condition:
+ ("aaa", "bbb") in ("AAA", "BBB", "aaa")
+
+}
+'''
+
+ self.check_rule_success(rule)
+
+
+ rule = '''
+rule test {
+
+ condition:
+ ("aaa", "bbb") in ("123", )
+
+}
+'''
+
+ self.check_rule_failure(rule)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ # TODO :
+
+ # test : intersection(a, a) == a
+
+ # test : "123" in "0123456789"
+ # test : "123" in "012987"
+
diff --git a/tests/common/bitfield.py b/tests/common/bitfield.py
index e014111..aff5de6 100644
--- a/tests/common/bitfield.py
+++ b/tests/common/bitfield.py
@@ -19,6 +19,23 @@ class TestBitFields(ChrysalideTestCase):
self.assertEqual(bf.popcount, bf2.popcount)
+ def testResizeBitField(self):
+ """Resize bitfields."""
+
+ bf_a = BitField(10, 0)
+
+ bf_b = BitField(6, 0)
+ bf_b.resize(10)
+
+ self.assertEqual(bf_a, bf_b)
+
+ bf_a = BitField(133, 1)
+
+ bf_b = BitField(64, 1)
+ bf_b.resize(133)
+
+ self.assertEqual(bf_a, bf_b)
+
def testBitFieldValues(self):
"""Evaluate bitfields basic values."""
@@ -70,6 +87,39 @@ class TestBitFields(ChrysalideTestCase):
self.assertEqual(bf_f.popcount, bf_a.popcount)
+ def testBitFieldLogicalOperationsAt(self):
+ """Perform logical operations on bitfields at a given position."""
+
+ bf_a = BitField(75, 0)
+
+ bf_b = BitField(4, 1)
+ bf_b.reset(2, 1)
+
+ bf_a.or_at(bf_b, 63)
+
+ self.assertFalse(bf_a.test(62))
+
+ self.assertTrue(bf_a.test(63))
+ self.assertTrue(bf_a.test(64))
+ self.assertFalse(bf_a.test(65))
+ self.assertTrue(bf_a.test(66))
+
+ self.assertFalse(bf_a.test(67))
+
+ bf_a = BitField(75, 0)
+
+ bf_a.or_at(bf_b, 60)
+
+ self.assertFalse(bf_a.test(59))
+
+ self.assertTrue(bf_a.test(60))
+ self.assertTrue(bf_a.test(61))
+ self.assertFalse(bf_a.test(62))
+ self.assertTrue(bf_a.test(63))
+
+ self.assertFalse(bf_a.test(64))
+
+
def testBitFieldSwitch(self):
"""Switch various bits in bitfields."""
@@ -118,6 +168,47 @@ class TestBitFields(ChrysalideTestCase):
self.assertTrue(bf.test_none(0, 54))
+ def testBitFieldWithBitField(self):
+ """Test bits in bitfields against other bitfields."""
+
+ bf = BitField(32, 0)
+ bf.set(8, 16)
+
+ mask = BitField(8, 1)
+
+ self.assertTrue(bf.test_ones_with(8, mask))
+ self.assertTrue(bf.test_ones_with(16, mask))
+ self.assertFalse(bf.test_ones_with(17, mask))
+ self.assertTrue(bf.test_zeros_with(24, mask))
+
+ bf = BitField(256, 0)
+ bf.set(60, 8)
+ bf.set(126, 10)
+
+ mask = BitField(4, 1)
+
+ self.assertTrue(bf.test_zeros_with(8, mask))
+ self.assertTrue(bf.test_zeros_with(122, mask))
+
+ self.assertFalse(bf.test_zeros_with(58, mask))
+ self.assertFalse(bf.test_ones_with(58, mask))
+ self.assertTrue(bf.test_ones_with(60, mask))
+ self.assertFalse(bf.test_zeros_with(63, mask))
+ self.assertTrue(bf.test_ones_with(64, mask))
+ self.assertFalse(bf.test_zeros_with(65, mask))
+ self.assertFalse(bf.test_ones_with(65, mask))
+
+ self.assertFalse(bf.test_zeros_with(125, mask))
+ self.assertFalse(bf.test_ones_with(125, mask))
+ self.assertTrue(bf.test_ones_with(128, mask))
+ self.assertFalse(bf.test_zeros_with(129, mask))
+ self.assertTrue(bf.test_ones_with(132, mask))
+ self.assertFalse(bf.test_zeros_with(133, mask))
+ self.assertFalse(bf.test_ones_with(133, mask))
+
+ self.assertTrue(bf.test_zeros_with(136, mask))
+
+
def testPopCountForBitField(self):
"""Count bits set to 1 in bitfield."""
@@ -138,3 +229,57 @@ class TestBitFields(ChrysalideTestCase):
bf_b = BitField(9, 1)
self.assertNotEqual(bf_a, bf_b)
+
+
+ def testRealCase00(self):
+ """Test bits in bitfields against other bitfields in a real case (#02)."""
+
+ bf = BitField(128, 0)
+
+ for b in [ 0, 50, 54, 58, 66, 70, 98 ]:
+ bf.set(b, 1)
+
+ mask = BitField(128, 0)
+
+ for b in [ 0, 51 ]:
+ mask.set(b, 1)
+
+ self.assertFalse(bf.test_zeros_with(0, mask))
+
+ self.assertTrue(bf.test_zeros_with(1, mask))
+
+ bf = BitField(32, 0)
+
+ mask = BitField(32, 0)
+
+ self.assertTrue(bf.test_zeros_with(0, mask))
+
+ for b in [ 0, 8, 9, 10 ]:
+ mask.set(b, 1)
+
+ self.assertTrue(bf.test_zeros_with(0, mask))
+
+ bf = BitField(32, 1)
+
+ self.assertFalse(bf.test_zeros_with(0, mask))
+
+ self.assertTrue(bf.test_ones_with(0, mask))
+
+
+ def testRealCase01(self):
+ """Test bits in bitfields against other bitfields in a real case (#01)."""
+
+ bf = BitField(128, 0)
+
+ mask = BitField(128, 0)
+
+ bits = [ 0, 50, 54, 58, 66, 70, 98 ]
+
+ for b in bits:
+ mask.set(b, 1)
+
+ bf.or_at(mask, 0)
+
+ self.assertEqual(mask.popcount, len(bits))
+
+ self.assertEqual(mask.popcount, bf.popcount)
diff --git a/tests/common/itoa.py b/tests/common/itoa.py
new file mode 100644
index 0000000..a004cbd
--- /dev/null
+++ b/tests/common/itoa.py
@@ -0,0 +1,28 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.common import itoa
+
+
+class TestItoa(ChrysalideTestCase):
+ """TestCase for calls to the itoa() implementation."""
+
+ def testItoaCallss(self):
+ """Convert some integer values into strings."""
+
+ val = itoa(123, 10)
+ self.assertEqual(val, '123')
+
+ val = itoa(-123, 10)
+ self.assertEqual(val, '-123')
+
+ val = itoa(0, 10)
+ self.assertEqual(val, '0')
+
+ val = itoa(0, 2)
+ self.assertEqual(val, '0')
+
+ val = itoa(127, 2)
+ self.assertEqual(val, '1111111')
+
+ val = itoa(101, 2)
+ self.assertEqual(val, '1100101')
diff --git a/tests/plugins/encodings/all.py b/tests/plugins/encodings/all.py
new file mode 100644
index 0000000..a856ccb
--- /dev/null
+++ b/tests/plugins/encodings/all.py
@@ -0,0 +1,23 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.plugins import encodings
+
+import base64
+
+
+class TestEncodingsModule(ChrysalideTestCase):
+ """TestCase for encodings plugin."""
+
+ def testBase64Encoding(self):
+ """Validate the base64 implementation."""
+
+ text = '0123456789abcdef'
+
+ for i in range(len(text) + 1):
+
+ src = text[:i].encode('ascii')
+
+ encoded = encodings.base64_encode(src)
+ ref = base64.b64encode(src)
+
+ self.assertEqual(encoded, ref)
diff --git a/tests/plugins/kaitai/__init__.py b/tests/plugins/kaitai/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/plugins/kaitai/__init__.py
diff --git a/tests/plugins/kaitai/language.py b/tests/plugins/kaitai/language.py
new file mode 100644
index 0000000..43b6185
--- /dev/null
+++ b/tests/plugins/kaitai/language.py
@@ -0,0 +1,2474 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+import locale
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide.plugins.kaitai.parsers import KaitaiStruct
+
+
+class TestKaitaiStruct(ChrysalideTestCase):
+ """TestCase for the KaitaiStruct parsing."""
+
+
+ @classmethod
+ def setUpClass(cls):
+
+ super(TestKaitaiStruct, cls).setUpClass()
+
+ cls.log('Setting locale suitable for floats...')
+
+ cls._old_locale = locale.getlocale(locale.LC_NUMERIC)
+
+ locale.setlocale(locale.LC_NUMERIC, 'C')
+
+
+ @classmethod
+ def tearDownClass(cls):
+
+ super(TestKaitaiStruct, cls).tearDownClass()
+
+ cls.log('Reverting locale...')
+
+ locale.setlocale(locale.LC_NUMERIC, cls._old_locale)
+
+
+
+ #################################
+ ### 4. Kaitai Struct language
+ #################################
+
+
+ def testKaitaiFixedLength(self):
+ """Load fixed-size structures."""
+
+ # Cf. 4.1. Fixed-size structures
+
+ definitions = '''
+meta:
+ id: mydesc
+ title: My Long Title
+ endian: be
+seq:
+ - id: field0
+ type: u4
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ self.assertEqual(kstruct.meta.id, 'mydesc')
+ self.assertEqual(kstruct.meta.title, 'My Long Title')
+
+ content = MemoryContent(b'\x01\x02\x03\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.range.length, 4)
+ self.assertEqual(parsed.field0.value, 0x01020304)
+
+ definitions = '''
+meta:
+ endian: le
+seq:
+ - id: field0
+ type: u4
+ - id: field1
+ type: u4be
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ self.assertIsNone(kstruct.meta.id)
+ self.assertIsNone(kstruct.meta.title)
+
+ content = MemoryContent(b'\x01\x02\x03\x04\x01\x02\x03\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.range.length, 4)
+ self.assertEqual(parsed.field0.value, 0x04030201)
+
+ self.assertEqual(parsed.field1.range.length, 4)
+ self.assertEqual(parsed.field1.value, 0x01020304)
+
+
+ definitions = '''
+seq:
+ - id: field0
+ type: u1
+ - id: field1
+ size: 2
+ - id: field2
+ size: field0 + 1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04\x05')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.range.length, 1)
+ self.assertEqual(parsed.field0.value, 0x01)
+
+ self.assertEqual(parsed.field1.range.length, 2)
+ self.assertEqual(parsed.field1.truncated_bytes, b'\x02\x03')
+
+ self.assertEqual(parsed.field2.range.length, 2)
+ self.assertEqual(parsed.field2.truncated_bytes, b'\x04\x05')
+
+
+ def testDocstrings(self):
+ """Handle Kaitai documentation."""
+
+ # Cf. 4.2. Docstrings
+
+ definitions = '''
+seq:
+ - id: rating
+ type: s4
+ doc: Rating, can be negative
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x02\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.rating.creator.doc, 'Rating, can be negative')
+
+
+ def testKaitaiContents(self):
+ """Read various forms of fixed content."""
+
+ # Cf. 4.3. Checking for "magic" signatures
+
+ definitions = '''
+seq:
+ - id: field0
+ contents: [ 0, 0x10, '22', "50 ]
+'''
+
+ # ValueError: Unable to create Kaitai structure.
+ with self.assertRaisesRegex(ValueError, "Unable to create Kaitai structure"):
+ kstruct = KaitaiStruct(definitions)
+ self.assertIsNotNone(kstruct)
+
+
+ definitions = '''
+seq:
+ - id: field0
+ contents: [ 0x41, 66, 'CD' ]
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'ABCD')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.range.length, 4)
+
+ self.assertEqual(parsed.field0.value, b'ABCD')
+
+
+ definitions = '''
+seq:
+ - id: field0
+ contents: ABCD
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'ABCD')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.range.length, 4)
+
+
+ definitions = '''
+seq:
+ - id: field0
+ contents: "ABCD"
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'ABCD')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.range.length, 4)
+
+
+ definitions = '''
+seq:
+ - id: field0
+ contents:
+ - 0x41
+ - "B"
+ - CD
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'ABCD')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.range.length, 4)
+
+
+ def testVariableLengthStructures(self):
+ """Parse variable-length structures."""
+
+ # Cf. 4.4. Variable-length structures
+
+ definitions = '''
+seq:
+ - id: my_len
+ type: u1
+ - id: my_str
+ type: str
+ size: my_len
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x03ABC')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.my_len.value, 3)
+
+ self.assertEqual(parsed.my_str.value, b'ABC')
+
+
+ definitions = '''
+seq:
+ - id: my_len
+ type: u1
+ - id: my_str
+ type: str
+ size: my_len * 2
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x03ABCDEF')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.my_len.value, 3)
+
+ self.assertEqual(parsed.my_str.value, b'ABCDEF')
+
+
+ definitions = '''
+seq:
+ - id: field0
+ size-eos: true
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x02\x03')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(content, parsed.content)
+
+ self.assertEqual(parsed.range.addr.phys, 0)
+ self.assertEqual(parsed.range.length, len(content.data))
+
+
+ def testDelimitedStructures(self):
+ """Parse delimited structures."""
+
+ # Cf. 4.5. Delimited structures
+
+ definitions = '''
+seq:
+ - id: my_string
+ type: str
+ terminator: 0
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'ABC\x00DEF')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.my_string.value, b'ABC')
+
+
+ definitions = '''
+seq:
+ - id: my_string
+ type: strz
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'ABC\x00DEF')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.my_string.value, b'ABC')
+
+
+ definitions = '''
+seq:
+ - id: name
+ type: str
+ size: 8
+ terminator: 0
+ - id: guard
+ size: 1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'ABC\x00\x00\x00\x00\x00x\x00')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.name.value, b'ABC')
+
+ self.assertEqual(parsed.guard.value, b'x')
+
+
+ def __passed__testEnums(self):
+ """Parse delimited structures."""
+
+ # Cf. 4.6. Enums (named integer constants)
+
+ pass
+
+
+ def testSubTypes(self):
+ """Includes subtypes definitions."""
+
+ # Cf. 4.7. Substructures (subtypes)
+
+ definitions = '''
+seq:
+ - id: field0
+ type: custom_type
+ - id: field1
+ type: custom_type
+ - id: field2
+ type: custom_type
+types:
+ custom_type:
+ seq:
+ - id: len
+ type: u1
+ - id: value
+ size: len
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\xaa\x02\xbb\xbb\x03\xcc\xcc\xcc')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.len.value, 1)
+ self.assertEqual(parsed.field0.value.truncated_bytes, b'\xaa')
+
+ self.assertEqual(parsed.field1.len.value, 2)
+ self.assertEqual(parsed.field1.value.truncated_bytes, b'\xbb\xbb')
+
+ self.assertEqual(parsed.field2.len.value, 3)
+ self.assertEqual(parsed.field2.value.truncated_bytes, b'\xcc\xcc\xcc')
+
+
+ def testOtherAttributesAccess(self):
+ """Access attributes in other types."""
+
+ # Cf. 4.8. Accessing attributes in other types
+
+ definitions = '''
+seq:
+ - id: header
+ type: main_header
+ - id: body
+ size: header.body_len
+types:
+ main_header:
+ seq:
+ - id: magic
+ contents: FMT
+ - id: body_len
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'FMT\x04\xaa\xbb\xcc\xdd')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.header.magic.raw_bytes, b'FMT')
+ self.assertEqual(parsed.header.magic.range.length, 3)
+
+ self.assertEqual(parsed.header.body_len.value, 4)
+
+ self.assertEqual(parsed.body.raw_bytes, b'\xaa\xbb\xcc\xdd')
+ self.assertEqual(parsed.body.range.length, 4)
+
+
+ def testConditionals(self):
+ """Read Kaitai values according to previous loaded values."""
+
+ # Cf. 4.9. Conditionals
+
+ definitions = '''
+seq:
+ - id: field1
+ type: u1
+ - id: field2
+ type: u1
+ - id: field3
+ type: u1
+ if: field1 + field2 > 10
+ - id: field4
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field1.value, 0x01)
+ self.assertEqual(parsed.field2.value, 0x02)
+ self.assertFalse(hasattr(parsed, 'field3'))
+ self.assertEqual(parsed.field4.value, 0x03)
+
+
+ definitions = '''
+seq:
+ - id: field1
+ type: u1
+ - id: field2
+ type: u1
+ - id: field3
+ type: u1
+ if: field1 + field2 > 1
+ - id: field4
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field1.value, 0x01)
+ self.assertEqual(parsed.field2.value, 0x02)
+ self.assertTrue(hasattr(parsed, 'field3'))
+ self.assertEqual(parsed.field4.value, 0x04)
+
+
+ definitions = '''
+seq:
+ - id: field1
+ type: u1
+ - id: field2
+ type: u1
+ - id: field3
+ type: u1
+ if: field1 + field2 == threshold::three
+ - id: field4
+ type: u1
+enums:
+ threshold:
+ 1: one
+ 2: two
+ 3: three
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field1.value, 0x01)
+ self.assertEqual(parsed.field2.value, 0x02)
+ self.assertTrue(hasattr(parsed, 'field3'))
+ self.assertEqual(parsed.field4.value, 0x04)
+
+
+ def testRepeatedReadUntilEOS(self):
+ """Read items until the end of the stream."""
+
+ # Cf. 4.10.1. Repeat until end of stream
+
+ definitions = '''
+seq:
+ - id: field0
+ type: u2be
+ repeat: eos
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x00\x02\x00\x03\x00\x04\x00')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(len(parsed.field0), len(content.data) / 2)
+
+ for i in range(4):
+ self.assertEqual(parsed.field0[i].value, (i + 1) << 8)
+
+
+ def testRepeatedReadAccordingToCounter(self):
+ """Repeat read of items for a nomber of times."""
+
+ # Cf. 4.10.2. Repeat for a number of times
+
+ definitions = '''
+seq:
+ - id: field0
+ type: u1
+ - id: field1
+ type: u1
+ repeat: expr
+ repeat-expr: 1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x01')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.value, 0x01)
+
+ self.assertEqual(len(parsed.field1), 1)
+
+ for i in range(1):
+ self.assertEqual(parsed.field1[i].value, i + 1)
+
+ definitions = '''
+seq:
+ - id: field0
+ type: u1
+ - id: field1
+ type: u1
+ - id: field2
+ type: u2
+ repeat: expr
+ repeat-expr: field0 + field1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x01\x00\x02\x00\x03\x00')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field0.value, 0x01)
+ self.assertEqual(parsed.field1.value, 0x02)
+
+ self.assertEqual(len(parsed.field2), 3)
+
+ for i in range(3):
+ self.assertEqual(parsed.field2[i].value, i + 1)
+
+
+ def testRepeatUntilConditionIsMet(self):
+ """Repeat until condition is met."""
+
+ # Cf. 4.10.3. Repeat until condition is met
+
+ definitions = '''
+seq:
+ - id: numbers
+ type: u1
+ repeat: until
+ repeat-until: _ == 0xff
+ - id: extra
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\xff\xcc')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(len(parsed.numbers), 3)
+
+ for i in range(2):
+ self.assertEqual(parsed.numbers[i].value, i + 1)
+
+ self.assertEqual(parsed.numbers[2].value, 0xff)
+
+ self.assertEqual(parsed.extra.value, 0xcc)
+
+ definitions = '''
+seq:
+ - id: records
+ type: buffer_with_len
+ repeat: until
+ repeat-until: _.len == 0
+types:
+ buffer_with_len:
+ seq:
+ - id: len
+ type: u1
+ - id: value
+ size: len
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x02\xaa\xaa\x01\xbb\x00')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.records[0].len.value, 2)
+ self.assertEqual(parsed.records[0].value.raw_bytes, b'\xaa\xaa')
+
+ self.assertEqual(parsed.records[1].len.value, 1)
+ self.assertEqual(parsed.records[1].value.raw_bytes, b'\xbb')
+
+ self.assertEqual(parsed.records[2].len.value, 0)
+ self.assertEqual(parsed.records[2].value.raw_bytes, b'')
+
+
+ def testParseTLVImplementation(self):
+ """Parse a typical TLV implementation."""
+
+ # Cf. 4.11. Typical TLV implementation (switching types on an expression)
+
+ definitions = '''
+seq:
+ - id: record
+ type: rec_def
+ repeat: eos
+types:
+ rec_def:
+ seq:
+ - id: rec_type
+ type: u1
+ - id: len
+ type: u1
+ - id: body
+ size: len
+ type:
+ switch-on: rec_type
+ cases:
+ 1: rec_type_1
+ 2: rec_type_2
+ rec_type_1:
+ seq:
+ - id: field1
+ type: u1
+ rec_type_2:
+ seq:
+ - id: field2
+ type: u2
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x01\xaa\x02\x02\xcc\xbb')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(len(parsed.record), 2)
+
+ self.assertEqual(parsed.record[0].rec_type.value, 1)
+ self.assertEqual(parsed.record[0].len.value, 1)
+ self.assertEqual(parsed.record[0].body.field1.value, 0xaa)
+
+ self.assertEqual(parsed.record[1].rec_type.value, 2)
+ self.assertEqual(parsed.record[1].len.value, 2)
+ self.assertEqual(parsed.record[1].body.field2.value, 0xbbcc)
+
+
+ def testInstanceWithDataBeyondTheSequence(self):
+ """Build instances with data beyond the sequence."""
+
+ # Cf. 4.12. Instances: data beyond the sequence
+
+ definitions = '''
+instances:
+ some_integer:
+ pos: 0x4
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04\x05\x06\x07\x08')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.some_integer.value, 5)
+
+
+ definitions = '''
+seq:
+ - id: file_offset
+ type: u1
+ - id: file_size
+ type: u1
+instances:
+ body:
+ pos: file_offset
+ size: file_size
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x04\x02\x90\x90ABCD')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.file_offset.value, 4)
+
+ self.assertEqual(parsed.file_size.value, 2)
+
+ self.assertEqual(parsed.body.value, b'AB')
+
+
+ def testValueInstances(self):
+ """Build value instances"""
+
+ # Cf. 4.13. Value instances
+
+ definitions = '''
+seq:
+ - id: length
+ type: u1
+ - id: extra
+ type: u1
+instances:
+ length_extended:
+ value: length * 3 + extra
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.length.value, 1)
+
+ self.assertEqual(parsed.extra.value, 2)
+
+ self.assertEqual(parsed.length_extended.value, 5)
+
+
+ def testBitSizedIntegers(self):
+ """Read bit-sized integers."""
+
+ # Cf. 4.14. Bit-sized integers
+
+ definitions = '''
+seq:
+ - id: packed_1
+ type: u1
+instances:
+ version:
+ value: (packed_1 & 0b11110000) >> 4
+ len_header:
+ value: packed_1 & 0b00001111
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x9a')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.packed_1.value, 0x9a)
+
+ self.assertEqual(parsed.version.value, 0x9)
+
+ self.assertEqual(parsed.len_header.value, 0xa)
+
+
+ def __passed__testBitSizedIntegersBigEndian(self):
+ """Read bit-sized integers."""
+
+ # Cf. 4.14.1. Big-endian order
+
+ pass
+
+
+ def __passed__testBitSizedIntegersLittleEndian(self):
+ """Read bit-sized integers."""
+
+ # Cf. 4.14.2. Little-endian order
+
+ pass
+
+
+ def __passed__testBitSizedIntegersSpecifiedEndianness(self):
+ """Read bit-sized integers with specified bit endianness."""
+
+ # Cf. 4.14.3. Specifying bit endianness
+
+ pass
+
+
+
+ #################################
+ ### 5. Streams and substreams
+ #################################
+
+
+ def testTotalSizeLimit(self):
+ """Limit total size of structure."""
+
+ # Cf. 5.1. Limiting total size of structure
+
+ definitions = '''
+seq:
+ - id: body_len
+ type: u1
+ - id: random
+ size: 2
+ - id: comment
+ size: body_len - 2
+ - id: extra
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x05\x01\x02---\xbb')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.body_len.value, 0x05)
+
+ self.assertEqual(parsed.random.raw_bytes, b'\x01\x02')
+
+ self.assertEqual(parsed.comment.raw_bytes, b'---')
+
+ self.assertEqual(parsed.extra.raw_bytes, b'\xbb')
+
+
+ definitions = '''
+seq:
+ - id: body_len
+ type: u1
+ - id: body
+ type: record_body
+ size: body_len
+ - id: extra
+ type: u1
+types:
+ record_body:
+ seq:
+ - id: random
+ size: 2
+ - id: comment
+ size-eos: true
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x05\x01\x02---\xbb')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.body_len.value, 0x05)
+
+ self.assertEqual(parsed.body.random.raw_bytes, b'\x01\x02')
+
+ self.assertEqual(parsed.body.comment.raw_bytes, b'---')
+
+ self.assertEqual(parsed.extra.raw_bytes, b'\xbb')
+
+
+ def testRepeatSizeLimit(self):
+ """Repeating until total size reaches limit."""
+
+ # Cf. 5.2. Repeating until total size reaches limit
+
+ content = MemoryContent(b'\x03\x00\x01\x02\xbb')
+
+ definitions = '''
+seq:
+ - id: total_len
+ type: u1
+ - id: files
+ type: file_entries
+ size: total_len
+ - id: extra
+ type: u1
+types:
+ file_entries:
+ seq:
+ - id: entries
+ type: entry
+ repeat: eos
+ entry:
+ seq:
+ - id: index
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.total_len.value, 3)
+
+ self.assertEqual(len(parsed.files.entries), 3)
+
+ for i in range(3):
+ self.assertEqual(parsed.files.entries[i].index.value, i)
+
+ self.assertEqual(parsed.extra.value, 0xbb)
+
+
+ def testRelativePositioning(self):
+ """Parse with relative positioning."""
+
+ # Cf. 5.3. Relative positioning
+
+ content = MemoryContent(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\0xe\x0f')
+
+ definitions = '''
+seq:
+ - id: some_header
+ size: 4
+ - id: body
+ type: block
+ size: 12
+types:
+ block:
+ seq:
+ - id: foo
+ type: u1
+ instances:
+ some_bytes_in_the_middle:
+ pos: 4
+ size: 4
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.some_header.value, b'\x00\x01\x02\x03')
+ self.assertEqual(parsed.body.foo.value, 0x04)
+
+ self.assertEqual(parsed.body.some_bytes_in_the_middle.value, b'\x08\x09\x0a\x0b')
+
+
+ def testAbsolutePositioning(self):
+ """Read from absolute position."""
+
+ # Cf. 5.4. Absolute positioning
+
+ content = MemoryContent(b'\x06\x03\x00\x00\x00\x00\x01\x02\x03\xbb')
+
+ definitions = '''
+seq:
+ - id: items
+ size: 10
+ type: entry
+ repeat: eos
+types:
+ entry:
+ seq:
+ - id: ofs_body
+ type: u1
+ - id: len_body
+ type: u1
+ instances:
+ body:
+ io: _root._io
+ pos: ofs_body
+ size: len_body
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.items[0].ofs_body.value, 6)
+ self.assertEqual(parsed.items[0].len_body.value, 3)
+
+ self.assertEqual(parsed.items[0].body.value, b'\x01\x02\x03')
+
+
+ def testSubstreamChoice(self):
+ """Choose a substream."""
+
+ # Cf. 5.5. Choosing a substream
+
+ content = MemoryContent(b'\xaa\xaa\xaa\xaa\x01\x02\x03\x04\x05\x06\x07\x08\x02\x03')
+
+ definitions = '''
+seq:
+ - id: global_header
+ size: 4
+ - id: block_one
+ type: big_container
+ size: 8
+ - id: block_two
+ type: smaller_container
+ size: 2
+types:
+ big_container:
+ seq:
+ - id: some_header
+ size: 8
+ smaller_container:
+ seq:
+ - id: ofs_in_big
+ type: u1
+ - id: len_in_big
+ type: u1
+ instances:
+ something_in_big:
+ io: _root.block_one._io
+ pos: ofs_in_big
+ size: len_in_big
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.block_two.ofs_in_big.value, 2)
+ self.assertEqual(parsed.block_two.len_in_big.value, 3)
+
+ self.assertEqual(parsed.block_two.something_in_big.value, b'\x03\x04\x05')
+
+
+ def __passed__testContentPreProcessing(self):
+ """Process content before parsing."""
+
+ # Cf. 5.6. Processing: dealing with compressed, obfuscated and encrypted data
+
+ pass
+
+
+
+ ##############################
+ ### 6. Expression language
+ ##############################
+
+
+ def testBasicDataTypes(self):
+ """Handle basic data types."""
+
+ # Cf. 6.1. Basic data types
+
+ definitions = '''
+seq:
+ - id: field1
+ type: u1
+ - id: field2
+ type: u2
+ - id: field4
+ type: u4
+ - id: field8
+ type: u8
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x02\x04\x04\x04\x04\x08\x08\x08\x08\x08\x08\x08\x08')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field1.range.length, 1)
+ self.assertEqual(parsed.field2.range.length, 2)
+ self.assertEqual(parsed.field4.range.length, 4)
+ self.assertEqual(parsed.field8.range.length, 8)
+
+ definitions = '''
+seq:
+ - id: field1
+ type: u1
+ - id: field4
+ type: u4le
+ - id: field4bis
+ type: u4be
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04\x05\x02\x03\x04\x05')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field1.value, 0x01)
+ self.assertEqual(parsed.field4.value, 0x05040302)
+ self.assertEqual(parsed.field4bis.value, 0x02030405)
+
+
+ definitions = '''
+instances:
+ number1:
+ value: 0xdead_cafe
+ number2:
+ value: 0xdead_cafe_dead_cafe
+ number3:
+ value: 12_345_678
+ number4:
+ value: 0b10100011
+ number5:
+ value: 0b1010_0011_1010_0011
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.number1.value, 0xdeadcafe)
+
+ self.assertEqual(parsed.number2.value, 0xdeadcafedeadcafe)
+
+ self.assertEqual(parsed.number3.value, 12345678)
+
+ self.assertEqual(parsed.number4.value, 0b10100011)
+
+ self.assertEqual(parsed.number5.value, 0b1010001110100011)
+
+
+ definitions = '''
+seq:
+ - id: op0
+ type: u1
+instances:
+ result:
+ value: 0xdeadcafe + op0
+ result2:
+ value: 0XdeadCAFE + op0
+'''
+
+ content = MemoryContent(b'\x00')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result.value, 0xdeadcafe)
+
+ self.assertEqual(parsed.result2.value, 0xdeadcafe)
+
+
+ definitions = '''
+instances:
+ bytes1:
+ value: []
+ bytes2:
+ value: [ ]
+ bytes3:
+ value: [ 0x90 ]
+ bytes4:
+ value: [foo, 0, A, 0xa, 42]
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.bytes1.value, b'')
+
+ self.assertEqual(parsed.bytes2.value, b'')
+
+ self.assertEqual(parsed.bytes3.value, b'\x90')
+
+ self.assertEqual(parsed.bytes4.value, b'\x66\x6f\x6f\x00\x41\x0a\x2a')
+
+
+ definitions = '''
+instances:
+ escaped:
+ value: '[ "\\a\\b\\t\\n\\v\\f", "\\0", 0, " \\r\\e\\\"\\123" ]'
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.escaped.value, b'\x07\x08\x09\x0a\x0b\x0c\x00\x00 \x0d\x1b\x22\x53')
+
+
+ definitions_0 = r'''
+instances:
+ escaped:
+ value: "[ \"\\a\\b\\t\\n\\v\\f\", \"\\0\", 0, \"\\r\\e\\\"'\\123\" ]"
+'''
+
+ definitions_1 = r'''
+instances:
+ escaped:
+ value: [ "\\a\\b\\t\\n\\v\\f", "\\0", 0, "\\r\\e\\\"'\\123" ]
+'''
+
+ definitions_2 = '''
+instances:
+ escaped:
+ value: [ "\\\\a\\\\b\\\\t\\\\n\\\\v\\\\f", "\\\\0", 0, "\\\\r\\\\e\\\\\\"'\\\\123" ]
+'''
+
+ for d in [ definitions_0, definitions_1, definitions_2 ]:
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(d)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.escaped.value, b'\x07\x08\x09\x0a\x0b\x0c\x00\x00\x0d\x1b\x22\x27\x53')
+
+
+ def __passed__testUserDefinedTypes(self):
+ """Create user-defined types."""
+
+ # Cf. 6.2.1. User-defined types
+
+ pass
+
+
+ def testArrays(self):
+ """Create various arrays."""
+
+ # Cf. 6.2.2. Arrays
+
+ definitions = '''
+instances:
+ result_0:
+ value: "[]"
+ result_1:
+ value: "[CAFE, 0, BABE]"
+ result_2:
+ value: "[CAFE, 0, BABE] == 'CAFE' + [ 0x00 ] + 'BABE'"
+ result_3:
+ value: "[CAFE, 0, BABE] == [ 0x43, 0x41, 0x46, 0x45, 0x00, 0x42, 0x41, 0x42, 0x45 ]"
+ result_4:
+ value: "[foo, 0, A, 0xa, 42] == [ 0x66, 0x6f, 0x6f, 0x00, 0x41, 0x0a, 0x2a ]"
+ result_5:
+ value: "[1, 0x55, '▒,3', 3] == [ 0x01, 0x55, 0xe2, 0x96, 0x92, 0x2c, 0x33, 0x03 ]"
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result_0.value, b'')
+
+ self.assertEqual(parsed.result_1.value, b'CAFE\x00BABE')
+
+
+ definitions = '''
+seq:
+ - id: indexes
+ type: u1
+ repeat: eos
+instances:
+ table:
+ value: "[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]"
+ ref:
+ value: indexes
+ result_0:
+ value: table
+ result_1:
+ value: ref
+ result_2:
+ value: table[indexes[0]][indexes[1] - 1]
+ result_3:
+ value: table[indexes[0]][ref[1]]
+'''
+
+ content = MemoryContent(b'\x01\x02\x03\x04')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result_0.value.value, b'\x01\x02\x03\x04\x05\x06\x07\x08\x09')
+
+ self.assertEqual(type(parsed.result_1).__name__, 'RecordDelayed') # result_1
+ self.assertEqual(type(parsed.result_1.value).__name__, 'RecordDelayed') # result_1.ref
+ self.assertEqual(type(parsed.result_1.value.value).__name__, 'RecordList') # result_1.ref.table
+
+ self.assertEqual(parsed.result_1.value.value[3].value, 0x04)
+
+ self.assertEqual(parsed.result_2.value, 5)
+
+ self.assertEqual(parsed.result_3.value, 6)
+
+
+ def testArithmeticOperators(self):
+ """Compute with arithmetic operators."""
+
+ # Cf. 6.3.1. Arithmetic operators
+
+ definitions = '''
+seq:
+ - id: op0
+ type: u1
+ - id: op1
+ type: u1
+instances:
+ result_0:
+ value: op0 + op1 * 3
+ result_1:
+ value: (2 + op0) * op1
+ result_2:
+ value: 7 * 2.0
+ result_3:
+ value: 7 / 2.0
+ result_4:
+ value: -5 % 3
+ result_5:
+ value: 4 % 3
+ result_6:
+ value: 6 - 3 - -4.0
+'''
+
+ content = MemoryContent(b'\x02\x03\x04\x05')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result_0.value, 11)
+
+ self.assertEqual(parsed.result_1.value, 12)
+
+ self.assertEqual(parsed.result_2.value, 14.0)
+
+ self.assertEqual(parsed.result_3.value, 3.5)
+
+ self.assertEqual(parsed.result_4.value, 1)
+
+ self.assertEqual(parsed.result_5.value, 1)
+
+ self.assertEqual(parsed.result_6.value, 7.0)
+
+
+ definitions = '''
+seq:
+ - id: base
+ size: 3
+instances:
+ result_0:
+ value: "'xXx ' + base + ' -- %< --'"
+'''
+
+ content = MemoryContent(b'ABC')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result_0.value, b'xXx ABC -- %< --')
+
+
+ definitions = '''
+seq:
+ - id: nums
+ type: u1
+ repeat: eos
+instances:
+ computed:
+ value: nums[0] + nums[3]
+ computed2:
+ value: nums[0] * nums.size + nums[3]
+ computed3:
+ value: nums[0] * nums[nums.size - 1]
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x03\x04')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.computed.value, 5)
+
+ self.assertEqual(parsed.computed2.value, 8)
+
+ self.assertEqual(parsed.computed3.value, 4)
+
+
+ def testRelationalOperators(self):
+ """Compute with relational operators."""
+
+ # Cf. 6.3.2. Relational operators
+
+ definitions = '''
+seq:
+ - id: op0
+ type: u1
+ - id: op1
+ type: u1
+ - id: op2
+ size: 3
+instances:
+ result0:
+ value: op0 == op1
+ result1:
+ value: op0 != op1
+ result2:
+ value: op2 == 'ABC'
+ result3:
+ value: op2 < 'ABCD'
+ result4:
+ value: (op0 + 1) >= op1
+ result5:
+ value: "(op0 + 1) == 'ABC'.length"
+'''
+
+ content = MemoryContent(b'\x02\x03ABCD')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertFalse(parsed.result0.value)
+
+ self.assertTrue(parsed.result1.value)
+
+ self.assertTrue(parsed.result2.value)
+
+ self.assertTrue(parsed.result3.value)
+
+ self.assertTrue(parsed.result4.value)
+
+ self.assertTrue(parsed.result5.value)
+
+
+ def testBitwiseOperators(self):
+ """Compute with bitwise operators."""
+
+ # Cf. 6.3.3. Bitwise operators
+
+ definitions = '''
+seq:
+ - id: op0
+ type: u1
+ - id: op1
+ type: u1
+ - id: op2
+ type: u1
+instances:
+ result_0:
+ value: op0 & op1
+ result_1:
+ value: op1 << op0 >> 1
+ result_2:
+ value: (op2 | 0x80) >> 1
+'''
+
+ content = MemoryContent(b'\x02\x07\x01')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result_0.value, 0x2)
+
+ self.assertEqual(parsed.result_1.value, 14)
+
+ self.assertEqual(parsed.result_2.value, 0x40)
+
+
+ def testLogicalOperators(self):
+ """Compute with logical boolean operators."""
+
+ # Cf. 6.3.4. Logical (boolean) operators
+
+ definitions = '''
+seq:
+ - id: op0
+ type: u1
+ - id: op1
+ type: u1
+instances:
+ result_0:
+ value: (op0 > 0) and not false
+ result_1:
+ value: op0 == 1 or op1 == 2
+'''
+
+ content = MemoryContent(b'\x01\x02')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertTrue(parsed.result_0.value)
+
+ self.assertTrue(parsed.result_1.value)
+
+
+ def testTernaryOperator(self):
+ """Offer challenges to the ternary operator."""
+
+ # Cf. 6.3.5. Ternary (if-then-else) operator
+
+ definitions = '''
+seq:
+ - id: op0
+ type: u1
+ - id: op1
+ type: u1
+ - id: op2
+ type: u1
+instances:
+ result_0:
+ value: 'op0 == 0x80 ? op1 + 1 : op1 * op2'
+ result_1:
+ value: 'op0 < 0x80 ? op1 + 1 : op1 * op2'
+ result_1:
+ value: 'op0 < 0x80 ? op1 + 1 : op1 * op2'
+ result_2:
+ value: '(op0 + 0x10) >= 0x90 ? true : 123'
+ result_3:
+ value: '(op0 + 0x10) >= 0x90 and false ? true : 123'
+'''
+
+ content = MemoryContent(b'\x80\x03\x04')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result_0.value, 4)
+
+ self.assertEqual(parsed.result_1.value, 12)
+
+ self.assertTrue(parsed.result_2.value)
+
+ self.assertEqual(parsed.result_3.value, 123)
+
+
+ def testIntegersMethods(self):
+ """Run methods from integers."""
+
+ # Cf. 6.4.1. Integers
+
+ definitions = '''
+instances:
+ bytes1:
+ value: 123.to_s == "123" and -123.to_s == '-123'
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertTrue(parsed.bytes1.value)
+
+
+ def testFloatsMethods(self):
+ """Run methods from floating numbers."""
+
+ # Cf. 6.4.2. Floating point numbers
+
+ definitions = '''
+instances:
+ result_0:
+ value: 2.32.to_i == 2 and -7.0.to_i == -7
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertTrue(parsed.result_0.value)
+
+
+ def XXXtestByteArraysAndStringsMethods(self):
+ """Run methods from byte arrays and strings."""
+
+ # Cf. 6.4.3. Byte arrays
+ # 6.4.4. Strings
+
+ definitions = '''
+instances:
+ result_1:
+ value: '[].length == 0'
+ result_2:
+ value: "'edcba'.reverse == 'XXabcdeXX'.substring(2, 6)"
+ result_3:
+ value: "'123'.to_i == 123 and '-123'.to_i == -123"
+ result_4:
+ value: "[ 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x63, 0x69, 0xc3, 0xb3, 0x6e, 0x2e, 0x73, 0x78, 0x69 ].to_s('utf-8')"
+ result_5:
+ value: "'1010'.to_i(2) == 10 and 'cc'.to_i(16) == 204"
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertTrue(parsed.result_1.value)
+
+ self.assertTrue(parsed.result_2.value)
+
+ self.assertTrue(parsed.result_3.value)
+
+ # Cf. https://docs.gtk.org/glib/character-set.html
+ # https://developer-old.gnome.org/glib/stable/glib-Character-Set-Conversion.html#g-convert
+ self.assertEqual(parsed.result_4.value.decode('utf-8'), 'Presentación.sxi')
+
+ self.assertTrue(parsed.result_5.value)
+
+
+ def __passed__testEnumsMethods(self):
+ """Run methods from booleans."""
+
+ # Cf. 6.4.5. Enums
+
+ pass
+
+
+ def testBooleansMethods(self):
+ """Run methods from booleans."""
+
+ # Cf. 6.4.6. Booleans
+
+ definitions = '''
+instances:
+ result_0:
+ value: true.to_i == 1
+ result_1:
+ value: (1 == 2).to_i == 0
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertTrue(parsed.result_0.value)
+
+ self.assertTrue(parsed.result_1.value)
+
+
+ def testUserDefinedTypes(self):
+ """Retrieve user-defined types."""
+
+ # Cf. 6.4.7. User-defined types
+
+ definitions = '''
+instances:
+ result_0:
+ value: _root
+'''
+
+ content = MemoryContent(b'')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.result_0.value, parsed)
+
+
+ def __passed__testArraysMethods(self):
+ """Run methods from arrays."""
+
+ # Cf. 6.4.8. Array types
+
+ pass
+
+
+ def __passed__testStreamsMethods(self):
+ """Run methods from streams."""
+
+ # Cf. 6.4.9. Streams
+
+ pass
+
+
+
+ ##############################
+ ### 7. Advanced techniques
+ ##############################
+
+
+ def testSwitchOverStrings(self):
+ """Switch over strings."""
+
+ # Cf. 7.1.1. Switching over strings
+
+ definitions = '''
+seq:
+ - id: rec_type
+ type: strz
+ - id: body
+ type:
+ switch-on: rec_type
+ cases:
+ '"KETCHUP"': rec_type_1
+ '"MUSTARD"': rec_type_2
+ '"GUACAMOLE"': rec_type_3
+types:
+ rec_type_1:
+ instances:
+ direct:
+ value: 1
+ rec_type_2:
+ instances:
+ direct:
+ value: 2
+ rec_type_3:
+ instances:
+ direct:
+ value: 3
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'GUACAMOLE\x00')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.rec_type.value, b'GUACAMOLE')
+
+ self.assertEqual(parsed.body.direct.value, 3)
+
+
+ def testSwitchOverEnums(self):
+ """Switch over enumerations."""
+
+ # Cf. 7.1.2. Switching over enums
+
+ definitions = '''
+seq:
+ - id: rec_type
+ type: u1
+ enum: media
+ - id: body
+ type:
+ switch-on: rec_type
+ cases:
+ 'media::cdrom': rec_type_1
+ 'media::dvdrom': rec_type_2
+ 'media::cassette': rec_type_3
+types:
+ rec_type_1:
+ instances:
+ direct:
+ value: 1
+ rec_type_2:
+ instances:
+ direct:
+ value: 2
+ rec_type_3:
+ instances:
+ direct:
+ value: 3
+enums:
+ media:
+ 1: cdrom
+ 2: dvdrom
+ 3: cassette
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.rec_type.value, 1)
+
+ self.assertEqual(parsed.body.direct.value, 1)
+
+
+ def testFourCC(self):
+ """Recognize four character code."""
+
+ # Cf. 7.1.3. FourCC
+
+ definitions = '''
+seq:
+ - id: fourcc
+ type: u4le
+ enum: pixel_formats
+ - id: len
+ type: u1
+ - id: body
+ size: len
+ type:
+ switch-on: fourcc
+ cases:
+ 'pixel_formats::rgb2': block_rgb2
+ 'pixel_formats::rle4': block_rle4
+ 'pixel_formats::rle8': block_rle8
+types:
+ block_rgb2:
+ instances:
+ direct:
+ value: 2
+ block_rle4:
+ instances:
+ direct:
+ value: 4
+ block_rle8:
+ instances:
+ direct:
+ value: 8
+enums:
+ pixel_formats:
+ 0x32424752: rgb2
+ 0x34454C52: rle4
+ 0x38454C52: rle8
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'RLE4\x05ABCDE')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.fourcc.value, 0x34454C52)
+
+ self.assertEqual(parsed.len.value, 0x5)
+
+ self.assertEqual(parsed.body.direct.value, 4)
+
+
+ def testNothing(self):
+ """Do nothing."""
+
+ # Cf. 7.2. Do nothing
+
+ definitions = '''
+seq:
+ - id: field_0
+ size: 1
+ - id: field_1
+ type: dummy_1
+ - id: field_2
+ type: dummy_2
+ - id: field_3
+ type: dummy_3
+ - id: field_4
+ type: dummy_4
+ - id: field_5
+ size: 1
+types:
+ # One can use empty JSON object syntax to avoid specifying any of
+ # `seq`, `instances`, etc, sections.
+ dummy_1: {}
+ # One can use explicit doc to note that there's nothing there.
+ dummy_2:
+ doc: This type is intentionally left blank.
+ # One can use empty `seq` or `instances` or `types` section, any
+ # other empty sections, or any combination of thereof.
+ dummy_3:
+ seq: []
+ instances: {}
+ types: {}
+ # One can use a very explicit notion of the fact that we want to parse 0 bytes.
+ dummy_4:
+ seq:
+ - id: no_value
+ size: 0
+'''
+
+ content = MemoryContent(b'az')
+
+ kstruct = KaitaiStruct(definitions)
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.field_0.value, b'a')
+
+ self.assertEqual(type(parsed.field_1).__name__, 'RecordEmpty')
+ self.assertEqual(parsed.field_1.range.length, 0)
+
+ self.assertEqual(type(parsed.field_2).__name__, 'RecordEmpty')
+ self.assertEqual(parsed.field_2.range.length, 0)
+
+ self.assertEqual(type(parsed.field_3).__name__, 'RecordEmpty')
+ self.assertEqual(parsed.field_3.range.length, 0)
+
+ self.assertEqual(type(parsed.field_4.no_value).__name__, 'RecordEmpty')
+ self.assertEqual(parsed.field_4.no_value.range.length, 0)
+
+ self.assertEqual(parsed.field_5.value, b'z')
+
+
+ def testConsumeIncludeTerminators(self):
+ """Consume and/or include terminators."""
+
+ # Cf. 7.3.1. Terminator: consume or include?
+
+ definitions = '''
+seq:
+ - id: str1
+ type: str
+ terminator: 0x2e # `.`
+ - id: str2
+ type: str
+ terminator: 0x2e # `.`
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'foo.bar.')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.str1.value, b'foo')
+
+ self.assertEqual(parsed.str2.value, b'bar')
+
+
+ definitions = '''
+seq:
+ - id: str1
+ type: str
+ terminator: 0x2e # `.`
+ include: true
+ - id: str2
+ type: str
+ terminator: 0x2e # `.`
+ eos-error: false
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'foo.bar')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.str1.value, b'foo.')
+
+ self.assertEqual(parsed.str2.value, b'bar')
+
+
+ definitions = '''
+seq:
+ - id: str1
+ type: str
+ terminator: 0x2e # `.`
+ consume: false
+ - id: the_rest
+ type: str
+ size-eos: true
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'foo.bar.')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.str1.value, b'foo')
+
+ self.assertEqual(parsed.the_rest.value, b'.bar.')
+
+
+ definitions = '''
+seq:
+ - id: str1
+ type: str
+ terminator: .
+ - id: the_rest
+ type: str
+ size-eos: true
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'foo.bar.')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.str1.value, b'foo')
+
+ self.assertEqual(parsed.the_rest.value, b'bar.')
+
+
+ definitions = '''
+seq:
+ - id: str1
+ type: str
+ terminator: xxx.
+ - id: the_rest
+ type: str
+ size-eos: true
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'fooxxx.bar.')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.str1.value, b'foo')
+
+ self.assertEqual(parsed.the_rest.value, b'bar.')
+
+
+ def testIgnoreErrorsInDelimitedStructures(self):
+ """Ignore errors in delimited structures."""
+
+ # Cf. 7.3.2. Ignoring errors in delimited structures
+
+ definitions = '''
+seq:
+ - id: my_string
+ type: str
+ terminator: 0
+ eos-error: false
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x61\x62\x63\x00\x64\x65\x66')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.my_string.value, b'abc')
+
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x61\x62\x63\x00')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.my_string.value, b'abc')
+
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x61\x62\x63')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.my_string.value, b'abc')
+
+
+ def __passed__testImportTypesFromOtherFiles(self):
+ """Import types from other files."""
+
+ # Cf. 7.4. Importing types from other files
+
+ pass
+
+
+ def __passed__testPlugExternalCodeForOpaqueTypes(self):
+ """Plug external code for opaque types."""
+
+ # Cf. 7.5. Opaque types: plugging in external code
+
+ pass
+
+
+ def __passed__testCustomProcessingRoutines(self):
+ """Handle custom processing routines."""
+
+ # Cf. 7.6. Custom processing routines
+
+ pass
+
+
+ def __passed__testParentTypeEnforcing(self):
+ """Enforce parent type."""
+
+ # Cf. 7.7. Enforcing parent type
+
+ pass
+
+
+ def testTypecasting(self):
+ """Ensure there is no need for typecasting."""
+
+ # Cf. 7.8. Typecasting
+
+ definitions = '''
+seq:
+ - id: num_sections
+ type: u1
+ - id: sections
+ type: section
+ repeat: expr
+ repeat-expr: num_sections
+types:
+ section:
+ seq:
+ - id: sect_type
+ type: u1
+ - id: body
+ type:
+ switch-on: sect_type
+ cases:
+ 1: sect_header
+ 2: sect_color_data
+ sect_header:
+ seq:
+ - id: width
+ type: u1
+ - id: height
+ type: u1
+ sect_color_data:
+ seq:
+ - id: rgb
+ size: 3
+instances:
+ check_0:
+ value: sections[0].body.width * sections[0].body.height
+ check_1:
+ value: sections[1].body.rgb
+ check_2:
+ value: sections[2].body.width * sections[2].body.height
+ check_3:
+ value: sections[3].body.rgb
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x04\x01\x02\x04\x02ABC\x01\x03\x05\x02UVW')
+
+ parsed = kstruct.parse(content)
+
+ # Vérifications externes
+
+ self.assertEqual(parsed.num_sections.value, 4)
+
+ self.assertEqual(len(parsed.sections), 4)
+
+ self.assertEqual(parsed.sections[0].body.width.value + parsed.sections[0].body.height.value, 6)
+
+ self.assertEqual(parsed.sections[1].body.rgb.value, b'ABC')
+
+ self.assertEqual(parsed.sections[2].body.width.value + parsed.sections[2].body.height.value, 8)
+
+ self.assertEqual(parsed.sections[3].body.rgb.value, b'UVW')
+
+ # Vérifications internes
+
+ self.assertEqual(parsed.check_0.value, 8)
+
+ self.assertEqual(parsed.check_1.value.value, b'ABC')
+
+ self.assertEqual(parsed.check_2.value, 15)
+
+ self.assertEqual(parsed.check_3.value.value, b'UVW')
+
+
+
+ ##########################
+ ### 8. Common pitfalls
+ ##########################
+
+
+ def testReadTypeWithSubstream(self):
+ """Read user-type with substream."""
+
+ # Cf. 8.1. Specifying size creates a substream
+
+ definitions = '''
+seq:
+ - id: header
+ size: 4
+ - id: block
+ type: block
+ size: 4 # <= important size designation, creates a substream
+instances:
+ byte_3:
+ pos: 3
+ type: u1
+types:
+ block:
+ instances:
+ byte_3:
+ pos: 3
+ type: u1
+ byte_3_alt:
+ io: _root._io # <= thanks to this, always points to a byte in main stream
+ pos: 3
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x00\x01\x02\x03\x04\x05\x06\x07')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.header.value, b'\x00\x01\x02\x03')
+
+ self.assertEqual(parsed.byte_3.value, 0x03)
+
+ self.assertEqual(parsed.block.byte_3.value, 0x07)
+
+ self.assertEqual(parsed.block.byte_3_alt.value, 0x03)
+
+
+ definitions = '''
+seq:
+ - id: header
+ size: 4
+ - id: block
+ type: block
+instances:
+ byte_3:
+ pos: 3
+ type: u1
+types:
+ block:
+ instances:
+ byte_3:
+ pos: 3
+ type: u1
+ byte_3_alt:
+ io: _root._io # <= thanks to this, always points to a byte in main stream
+ pos: 3
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x00\x01\x02\x03\x04\x05\x06\x07')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.header.value, b'\x00\x01\x02\x03')
+
+ self.assertEqual(parsed.byte_3.value, 0x03)
+
+ self.assertEqual(parsed.block.byte_3.value, 0x03)
+
+ self.assertEqual(parsed.block.byte_3_alt.value, 0x03)
+
+
+ def testReadTypeWithoutSubstream(self):
+ """Read user-type without substream."""
+
+ # Cf. 8.2. Not specifying size does not create a substream
+
+ definitions = '''
+seq:
+ - id: header
+ size: 2
+ - id: block_as_type1
+ type: type1
+ size: 2 # <= important, creates a substream
+types:
+ type1:
+ seq:
+ - id: val1
+ size: 2
+ type2:
+ seq:
+ - id: val2
+ size: 2
+instances:
+ block_as_type2:
+ io: block_as_type1._io
+ pos: 0
+ type: type2
+ internal_check:
+ value: block_as_type2._io == _root._io
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'aabb')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.header.value, b'aa')
+
+ self.assertEqual(parsed.block_as_type1.val1.value, b'bb')
+
+ self.assertEqual(parsed.block_as_type2.val2.value, b'bb')
+
+ self.assertFalse(parsed.internal_check.value)
+
+
+ definitions = '''
+seq:
+ - id: header
+ size: 2
+ - id: block_as_type1
+ type: type1
+types:
+ type1:
+ seq:
+ - id: val1
+ size: 2
+ type2:
+ seq:
+ - id: val2
+ size: 2
+instances:
+ block_as_type2:
+ io: block_as_type1._io
+ pos: 0
+ type: type2
+ internal_check:
+ value: block_as_type2._io == _root._io
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'aabb')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.header.value, b'aa')
+
+ self.assertEqual(parsed.block_as_type1.val1.value, b'bb')
+
+ self.assertEqual(parsed.block_as_type2.val2.value, b'aa')
+
+ self.assertTrue(parsed.internal_check.value)
+
+
+ def __passed__testSizedProcess(self):
+ """Provide a sized data to processing."""
+
+ # Cf. 8.3. Applying process without a size
+
+ pass
+
+
+ def __passed__testRelatedKeys(self):
+ """Check refering keys and their related YAML nodes."""
+
+ # Cf. 8.4. Keys relating to the whole array and to each element in repeated attributes
+
+ pass
+
+
+
+ #######################
+ ### x. Extra checks
+ #######################
+
+
+ def testMssingField(self):
+ """Raise error on missing field."""
+
+ definitions = '''
+seq:
+ - id: field0
+ size-eos: true
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\x01\x02\x02\x03')
+
+ parsed = kstruct.parse(content)
+ self.assertIsNotNone(parsed)
+
+ self.assertEqual(parsed.field0.creator.raw_id, 'field0')
+
+ self.assertEqual(parsed.field0.value, b'\x01\x02\x02\x03')
+
+ # AttributeError: 'pychrysalide.plugins.kaitai.records.RecordList' object has no attribute 'xxxx'
+ with self.assertRaisesRegex(AttributeError, "object has no attribute 'xxxx'"):
+ print(parsed.xxxx)
+
+
+ def testLEB128Values(self):
+ """Read some Little Endian Base 128 values."""
+
+ definitions = '''
+seq:
+ - id: groups
+ type: group
+ repeat: until
+ repeat-until: not _.has_next
+types:
+ group:
+ -webide-representation: '{value}'
+ doc: |
+ One byte group, clearly divided into 7-bit "value" chunk and 1-bit "continuation" flag.
+ seq:
+ - id: b
+ type: u1
+ instances:
+ has_next:
+ value: (b & 0b1000_0000) != 0
+ doc: If true, then we have more bytes to read
+ value:
+ value: b & 0b0111_1111
+ doc: The 7-bit (base128) numeric value chunk of this group
+instances:
+ len:
+ value: groups.size
+ value:
+ value: >-
+ groups[0].value
+ + (len >= 2 ? (groups[1].value << 7) : 0)
+ + (len >= 3 ? (groups[2].value << 14) : 0)
+ + (len >= 4 ? (groups[3].value << 21) : 0)
+ + (len >= 5 ? (groups[4].value << 28) : 0)
+ + (len >= 6 ? (groups[5].value << 35) : 0)
+ + (len >= 7 ? (groups[6].value << 42) : 0)
+ + (len >= 8 ? (groups[7].value << 49) : 0)
+ doc: Resulting unsigned value as normal integer
+ sign_bit:
+ value: '1 << (7 * len - 1)'
+ value_signed:
+ value: '(value ^ sign_bit) - sign_bit'
+ doc-ref: https://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ content = MemoryContent(b'\xe5\x8e\x26')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.len.value, 3)
+
+ self.assertEqual(parsed.value.value, parsed.value_signed.value)
+
+ self.assertEqual(parsed.value.value, 624485)
+
+
+ content = MemoryContent(b'\xc0\xbb\x78')
+
+ parsed = kstruct.parse(content)
+
+ self.assertEqual(parsed.len.value, 3)
+
+ self.assertNotEqual(parsed.value.value, parsed.value_signed.value)
+
+ self.assertEqual(parsed.value_signed.value, -123456)
diff --git a/tests/plugins/kaitai/rost.py b/tests/plugins/kaitai/rost.py
new file mode 100644
index 0000000..4a29ef8
--- /dev/null
+++ b/tests/plugins/kaitai/rost.py
@@ -0,0 +1,170 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+import locale
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide.analysis.scan import ContentScanner
+from pychrysalide.analysis.scan import ScanOptions
+from pychrysalide.analysis.scan.patterns.backends import AcismBackend
+from pychrysalide import core
+from pychrysalide.plugins.kaitai.parsers import KaitaiStruct
+from pychrysalide.plugins.kaitai.rost import KaitaiTrigger
+
+
+class TestScansWithKaitai(ChrysalideTestCase):
+ """TestCase for ROST scan with the KaitaiStruct parsing."""
+
+ @classmethod
+ def setUpClass(cls):
+
+ super(TestScansWithKaitai, cls).setUpClass()
+
+ cls._options = ScanOptions()
+ cls._options.backend_for_data = AcismBackend
+
+
+ def testSimpleKaitaiDefinitionForScanning(self):
+ """Rely on basic Kaitai simple definition for scanning."""
+
+ definitions = '''
+meta:
+ id: basic_test
+seq:
+ - id: field0
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ trigger = KaitaiTrigger(kstruct)
+
+ root_ns = core.get_rost_root_namespace()
+
+ ns = root_ns.resolve('kaitai')
+ ns.register_item(trigger)
+
+ ns = ns.resolve('basic_test')
+ self.assertEqual(ns, trigger)
+
+ cnt = MemoryContent(b'\x01\x02\x03')
+
+ rule = '''
+rule testing {
+
+ condition:
+ kaitai.basic_test.field0 == 1
+
+}
+'''
+
+ scanner = ContentScanner(rule)
+ ctx = scanner.analyze(self._options, cnt)
+
+ self.assertIsNotNone(ctx)
+
+ self.assertFalse(ctx.has_match_for_rule('no_such_rule'))
+
+ self.assertTrue(ctx.has_match_for_rule('testing'))
+
+
+ definitions = '''
+meta:
+ id: other_basic_test
+seq:
+ - id: field0
+ type: u1
+ - id: field1
+ type: u1
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ trigger = KaitaiTrigger(kstruct)
+
+ root_ns = core.get_rost_root_namespace()
+
+ ns = root_ns.resolve('kaitai')
+ ns.register_item(trigger)
+
+ ns = ns.resolve('other_basic_test')
+ self.assertEqual(ns, trigger)
+
+ cnt = MemoryContent(b'\x01\x02\x03')
+
+ rule = '''
+rule testing {
+
+ condition:
+ kaitai.other_basic_test.field0 == 1 and kaitai.other_basic_test.field1 == 2
+
+}
+'''
+
+ scanner = ContentScanner(rule)
+ ctx = scanner.analyze(self._options, cnt)
+
+ self.assertIsNotNone(ctx)
+
+ self.assertTrue(ctx.has_match_for_rule('testing'))
+
+
+ rule = '''
+rule testing {
+
+ condition:
+ kaitai.other_basic_test.field0 == 1 and kaitai.other_basic_testXXXX.field1 == 2
+
+}
+'''
+
+ scanner = ContentScanner(rule)
+ ctx = scanner.analyze(self._options, cnt)
+
+ self.assertIsNotNone(ctx)
+
+ self.assertFalse(ctx.has_match_for_rule('testing'))
+
+
+ def testKaitaiDefinitionWithListForScanning(self):
+ """Access list items from Kaitai definition when scanning with ROST."""
+
+ definitions = '''
+meta:
+ id: test_with_list
+seq:
+ - id: field0
+ type: u1
+ repeat: eos
+'''
+
+ kstruct = KaitaiStruct(definitions)
+
+ trigger = KaitaiTrigger(kstruct)
+
+ root_ns = core.get_rost_root_namespace()
+
+ ns = root_ns.resolve('kaitai')
+ ns.register_item(trigger)
+
+ ns = ns.resolve('test_with_list')
+ self.assertEqual(ns, trigger)
+
+ cnt = MemoryContent(b'\x01\x02\x03')
+
+ rule = '''
+rule testing {
+
+ condition:
+ kaitai.test_with_list.field0[0] == 1 and kaitai.test_with_list.field0[1] == 2 and kaitai.test_with_list.field0[2] == 3
+
+}
+'''
+
+ scanner = ContentScanner(rule)
+ ctx = scanner.analyze(self._options, cnt)
+
+ self.assertIsNotNone(ctx)
+
+ self.assertTrue(ctx.has_match_for_rule('testing'))
diff --git a/tests/plugins/yaml.py b/tests/plugins/yaml.py
new file mode 100644
index 0000000..4d2680c
--- /dev/null
+++ b/tests/plugins/yaml.py
@@ -0,0 +1,175 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.plugins import yaml
+
+
+class TestYamlSupport(ChrysalideTestCase):
+ """TestCase for the YAML support."""
+
+
+ def testParseSimpleYamlContent(self):
+ """Parse basic YAML content."""
+
+ definitions = '''
+a: av
+b: bv
+c: cv
+'''
+
+ root = yaml.parse_from_text(definitions)
+
+ self.assertFalse(root.is_sequence)
+
+ self.assertEqual(root.nodes[0].key, 'a')
+ self.assertEqual(root.nodes[1].key, 'b')
+ self.assertEqual(root.nodes[2].key, 'c')
+
+ self.assertEqual(root.nodes[0].value, 'av')
+ self.assertEqual(root.nodes[1].value, 'bv')
+ self.assertEqual(root.nodes[2].value, 'cv')
+
+ definitions = '''
+- a: av
+- b: bv
+- c: cv
+'''
+
+ root = yaml.parse_from_text(definitions)
+
+ self.assertTrue(root.is_sequence)
+
+ self.assertEqual(root.nodes[0].nodes[0].key, 'a')
+ self.assertEqual(root.nodes[1].nodes[0].key, 'b')
+ self.assertEqual(root.nodes[2].nodes[0].key, 'c')
+
+ self.assertEqual(root.nodes[0].nodes[0].value, 'av')
+ self.assertEqual(root.nodes[1].nodes[0].value, 'bv')
+ self.assertEqual(root.nodes[2].nodes[0].value, 'cv')
+
+
+ def testSearchYamlNodes(self):
+ """Search YAML nodes related to paths."""
+
+ definitions = '''
+root:
+ a: v0
+ b: v1
+ c: v2
+ sub:
+ aa: v00
+ bb: v01
+ cc:
+ - i: w
+ - j: x
+ - k: c
+ d: v3
+'''
+
+ root = yaml.parse_from_text(definitions)
+
+ found = root.find_first_by_path('/root/a')
+
+ self.assertEqual(found.value, 'v0')
+
+ found = root.find_first_by_path('/root/sub')
+
+ self.assertEqual(found.value, None)
+
+ found = root.find_first_by_path('/root/sub/cc')
+
+ self.assertEqual(found.value, None)
+
+ found = root.find_first_by_path('/root/sub/cc/j')
+
+ self.assertEqual(found.value, 'x')
+
+ found = root.find_first_by_path('/root/d')
+
+ self.assertEqual(found.value, 'v3')
+
+
+ definitions = '''
+root:
+ - a: av
+ aa: aav
+ ab: abv
+ - b: bv
+ ba: bav
+ bb: bbv
+'''
+
+ root = yaml.parse_from_text(definitions)
+
+ found = root.find_first_by_path('/root/ba')
+
+ self.assertEqual(found.value, 'bav')
+
+ found = root.find_first_by_path('/root/b')
+
+ self.assertEqual(found.value, 'bv')
+
+ found = root.find_first_by_path('/root/')
+
+ self.assertTrue(found.is_sequence)
+ self.assertFalse(found.nodes[0].is_sequence)
+ self.assertEqual(found.nodes[0].nodes[0].value, 'av')
+
+
+ def testComplexYamlContent(self):
+ """Process more complex YAML content."""
+
+ definitions = '''
+root:
+ a: 'v0'
+ b: 'v1 ? 1 : 2'
+ c: v2 # final comment
+ d: "'xx::xx'"
+'''
+
+ root = yaml.parse_from_text(definitions)
+
+ found = root.find_first_by_path('/root/a')
+
+ self.assertEqual(found.value, 'v0')
+
+ found = root.find_first_by_path('/root/b')
+
+ self.assertEqual(found.value, 'v1 ? 1 : 2')
+
+ found = root.find_first_by_path('/root/c')
+
+ self.assertEqual(found.value, 'v2')
+
+ found = root.find_first_by_path('/root/d')
+
+ self.assertEqual(found.value, "'xx::xx'")
+
+
+ def testArrayAsSeq(self):
+ """Handle array as YAML block sequence."""
+
+ definitions = '''
+root:
+ a: [ a, 'b', 0xcc, "\td\n\\"'" ]
+'''
+
+ root = yaml.parse_from_text(definitions)
+
+ found = root.find_first_by_path('/root/a')
+
+ self.assertIsNone(found.value)
+
+ self.assertEqual(len(found.children.nodes), 4)
+
+ self.assertEqual(found.children.nodes[0].key, 'a')
+
+ self.assertEqual(found.children.nodes[1].key, 'b')
+
+ self.assertEqual(found.children.nodes[2].key, '0xcc')
+
+ self.assertEqual(found.children.nodes[3].key, "\td \"'")
+
+ self.assertEqual(found.aggregate_value(), '[ a, \'b\', 0xcc, " d \"\'" ]')
diff --git a/tests/plugins/yamlrdr.py b/tests/plugins/yamlrdr.py
deleted file mode 100644
index 47f02ba..0000000
--- a/tests/plugins/yamlrdr.py
+++ /dev/null
@@ -1,277 +0,0 @@
-#!/usr/bin/python3-dbg
-# -*- coding: utf-8 -*-
-
-
-from chrysacase import ChrysalideTestCase
-from pychrysalide.plugins.yaml import YamlReader
-import tempfile
-
-
-class TestYamlReader(ChrysalideTestCase):
- """TestCase for the Yaml reader."""
-
-
- @classmethod
- def setUpClass(cls):
-
- super(TestYamlReader, cls).setUpClass()
-
- cls._simple_map = tempfile.NamedTemporaryFile()
-
- cls._simple_map_data = b'''
-a: av
-b: bv
-c: cv
-
-'''
-
- cls._simple_seq = tempfile.NamedTemporaryFile()
-
- cls._simple_seq_data = b'''
-- a: av
-- b: bv
-- c: cv
-
-'''
-
- cls._nested = tempfile.NamedTemporaryFile()
-
- cls._nested_data = b'''
-root:
- a: v0
- b: v1
- c: v2
- sub:
- aa: v00
- bb: v01
- cc: v02
- - i: w
- - j: x
- - k: c
- d: v3
-
-'''
-
- cls._mixed = tempfile.NamedTemporaryFile()
-
- cls._mixed_data = b'''
-root:
- - a: av
- aa: aav
- ab: abv
- - b: bv
- ba: bav
- bb: bbv
-
-'''
-
- tmp = [
- [ cls._simple_map, cls._simple_map_data ],
- [ cls._simple_seq, cls._simple_seq_data ],
- [ cls._nested, cls._nested_data ],
- [ cls._mixed, cls._mixed_data ],
- ]
-
- for f, d in tmp:
-
- f.write(d)
- f.flush()
-
- cls.log('Using temporary file "%s"' % f.name)
-
-
- @classmethod
- def tearDownClass(cls):
-
- super(TestYamlReader, cls).tearDownClass()
-
- tmp = [
- cls._simple_map,
- cls._simple_seq,
- cls._nested,
- cls._mixed,
- ]
-
- for f in tmp:
-
- cls.log('Delete file "%s"' % f.name)
-
- f.close()
-
-
- def testSimpleYamlContent(self):
- """Validate Yaml content readers."""
-
- def _build_node_desc(node, left, extra = ''):
-
- if hasattr(node, 'key'):
-
- line = node.yaml_line
-
- prefix = '- ' if line.is_list_item else extra
- desc = left + prefix + line.key + ':' + (' ' + line.value if line.value else '') + '\n'
- indent = ' '
-
- collec = node.collection
-
- else:
-
- desc = ''
- indent = ''
-
- if hasattr(node, 'nodes'):
- collec = node
-
- if collec:
-
- if collec.is_sequence:
- extra = ' '
-
- for child in collec.nodes:
- desc += _build_node_desc(child, left + indent, extra)
-
- return desc
-
-
- reader = YamlReader.new_from_path(self._simple_map.name)
- self.assertIsNotNone(reader)
- self.assertIsNotNone(reader.tree)
-
- fulldesc = _build_node_desc(reader.tree.root, '')
-
- self.assertEqual('\n' + fulldesc + '\n', self._simple_map_data.decode('ascii'))
-
- reader = YamlReader.new_from_path(self._simple_seq.name)
- self.assertIsNotNone(reader)
- self.assertIsNotNone(reader.tree)
-
- fulldesc = _build_node_desc(reader.tree.root, '')
-
- self.assertEqual('\n' + fulldesc + '\n', self._simple_seq_data.decode('ascii'))
-
- reader = YamlReader.new_from_path(self._nested.name)
- self.assertIsNotNone(reader)
- self.assertIsNotNone(reader.tree)
-
- fulldesc = _build_node_desc(reader.tree.root, '')
-
- self.assertEqual('\n' + fulldesc + '\n', self._nested_data.decode('ascii'))
-
- reader = YamlReader.new_from_path(self._mixed.name)
- self.assertIsNotNone(reader)
- self.assertIsNotNone(reader.tree)
-
- fulldesc = _build_node_desc(reader.tree.root, '')
-
- self.assertEqual('\n' + fulldesc + '\n', self._mixed_data.decode('ascii'))
-
-
- def testSimpleYamlContentFinder(self):
- """Validate Yaml nested content search."""
-
- reader = YamlReader.new_from_path(self._nested.name)
- self.assertIsNotNone(reader)
-
- found = reader.tree.find_by_path('/root/sub')
-
- self.assertEqual(len(found), 1)
-
- if len(found) == 1:
- self.assertEqual(found[0].key, 'sub')
-
- found = reader.tree.find_by_path('/root/sub/')
-
- self.assertEqual(len(found), 3)
-
- found = reader.tree.find_by_path('/root/sub/xx')
-
- self.assertEqual(len(found), 0)
-
- found = reader.tree.find_by_path('/root/sub/cc/i')
-
- self.assertEqual(len(found), 1)
-
- if len(found) == 1:
- self.assertEqual(found[0].key, 'i')
- self.assertEqual(found[0].yaml_line.is_list_item, True)
-
- found = reader.tree.find_by_path('/root/sub/cc')
-
- self.assertEqual(len(found), 1)
-
- if len(found) == 1:
-
- root = found[0]
-
- found = root.find_by_path('cc/i')
-
- self.assertEqual(len(found), 1)
-
- if len(found) == 1:
-
- self.assertEqual(found[0].key, 'i')
- self.assertEqual(found[0].yaml_line.is_list_item, True)
-
- found = root.find_by_path('/cc/i')
-
- self.assertEqual(len(found), 1)
-
- if len(found) == 1:
-
- self.assertEqual(found[0].key, 'i')
- self.assertEqual(found[0].yaml_line.is_list_item, True)
-
- found = root.find_by_path('//i')
-
- self.assertEqual(len(found), 1)
-
- if len(found) == 1:
-
- self.assertEqual(found[0].key, 'i')
- self.assertEqual(found[0].yaml_line.is_list_item, True)
-
-
- def testMixedYamlContentFinder(self):
- """Validate Yaml mixed content search."""
-
- reader = YamlReader.new_from_path(self._mixed.name)
- self.assertIsNotNone(reader)
-
- found = reader.tree.find_by_path('/root')
-
- self.assertEqual(len(found), 1)
-
- if len(found) == 1:
- self.assertEqual(found[0].key, 'root')
-
- found = reader.tree.find_by_path('/root/', True)
-
- self.assertEqual(len(found), 1)
-
- found = reader.tree.find_one_by_path('/root/', True)
-
- self.assertIsNotNone(found)
-
- if found:
-
- sub = found.find_one_by_path('/a')
- self.assertIsNotNone(sub)
- self.assertEqual(sub.key, 'a')
-
- sub = found.find_one_by_path('/aa')
- self.assertIsNotNone(sub)
- self.assertEqual(sub.key, 'aa')
-
- found = reader.tree.find_by_path('/root/')
-
- self.assertEqual(len(found), 2)
-
- if len(found) == 2:
-
- sub = found[0].find_one_by_path('/a')
- self.assertIsNotNone(sub)
- self.assertEqual(sub.key, 'a')
-
- sub = found[0].find_one_by_path('/aa')
- self.assertIsNotNone(sub)
- self.assertEqual(sub.key, 'aa')
diff --git a/tools/Makefile.am b/tools/Makefile.am
index ed53403..8b8f38b 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,2 +1,2 @@
-SUBDIRS = d2c
+SUBDIRS = d2c yara2rost
diff --git a/tools/d2c/decl.h b/tools/d2c/decl.h
index bcca0ff..1214d01 100644
--- a/tools/d2c/decl.h
+++ b/tools/d2c/decl.h
@@ -34,4 +34,4 @@ rented_coder *process_definition_file(const char *, pre_processor *);
-#endif /* _TOOLS_D2C_BITS_DECL_H */
+#endif /* _TOOLS_D2C_DECL_H */
diff --git a/tools/d2c/format/decl.h b/tools/d2c/format/decl.h
index e3e4c9c..b12f853 100644
--- a/tools/d2c/format/decl.h
+++ b/tools/d2c/format/decl.h
@@ -34,4 +34,4 @@ bool load_format_from_raw_line(operands_format *, const char *);
-#endif /* _TOOLS_D2C_BITS_DECL_H */
+#endif /* _TOOLS_D2C_FORMAT_DECL_H */
diff --git a/tools/d2c/grammar.y b/tools/d2c/grammar.y
index 4444299..14959cf 100644
--- a/tools/d2c/grammar.y
+++ b/tools/d2c/grammar.y
@@ -1,7 +1,6 @@
%{
-#include <getopt.h>//////
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -15,9 +14,6 @@
/* Affiche un message d'erreur suite à l'analyse en échec. */
static int yyerror(rented_coder *, char *, char *);
-/* Affiche des indications sur l'utilisation du programme. */
-static void show_usage(const char *);
-
/* Prépare le traitement d'un contenu en l'affichant en mémoire. */
static void *map_input_data(const char *, size_t *);
diff --git a/tools/d2c/id/decl.h b/tools/d2c/id/decl.h
index e494b9f..cd156bd 100644
--- a/tools/d2c/id/decl.h
+++ b/tools/d2c/id/decl.h
@@ -37,4 +37,4 @@ bool load_id_from_raw_line(instr_id *, const char *);
-#endif /* _TOOLS_D2C_BITS_DECL_H */
+#endif /* _TOOLS_D2C_ID_DECL_H */
diff --git a/tools/fuzzing/rost/Makefile.am b/tools/fuzzing/rost/Makefile.am
new file mode 100644
index 0000000..81e126f
--- /dev/null
+++ b/tools/fuzzing/rost/Makefile.am
@@ -0,0 +1,14 @@
+
+bin_PROGRAMS = fast-rost
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/src
+
+# EXTRA_rost_DEPENDENCIES = libchrysacore.la
+
+fast_rost_SOURCES = \
+ fast-rost.c
+
+fast_rost_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+
+fast_rost_LDFLAGS = $(LIBGOBJ_LIBS) -L$(top_srcdir)/src/.libs -lchrysacore
diff --git a/tools/fuzzing/rost/convert.py b/tools/fuzzing/rost/convert.py
new file mode 100644
index 0000000..b0ed90c
--- /dev/null
+++ b/tools/fuzzing/rost/convert.py
@@ -0,0 +1,452 @@
+
+import re
+import sys
+
+
+def define_PLAIN_TEXT(name, last):
+ """Create definition for the PLAIN_TEXT token."""
+
+ print(' "<%s>": [ ["\\\"", "<str_not_escaped>", "\\\""] ],' % name.lower())
+ print(' "<str_not_escaped>": [ ["<char>"], ["<char>", "<char>"], ["<char>", "<char>", "<char>"] ],')
+ print(' "<char>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"], ["A"], ["B"], ["C"], ["D"], ["E"], ["F"] ]%s' % (',' if not(last) else ''))
+
+
+def define_IDENTIFIER(name, last):
+ """Create definition for the RULE_IDENTIFIER token."""
+
+ print(' "<%s>": [ [ "<id>", "<id>", "<id>", "<idx>" ] ],' % name.lower())
+ print(' "<id>": [ ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"] ],')
+ print(' "<idx>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ]%s' % (',' if not(last) else ''))
+
+
+def define_SIGNED_INTEGER(name, last):
+ """Create definition for the SIGNED_INTEGER token."""
+
+ print(' "<%s>": [ ["-", "<unsigned_integer>"] ]%s' % (name.lower(), ',' if not(last) else ''))
+
+
+def define_UNSIGNED_INTEGER(name, last):
+ """Create definition for the UNSIGNED_INTEGER token."""
+
+ print(' "<%s>": [ ["<fnumber>"], ["<number>", "<fnumber>"], ["<number>", "<fnumber>", "<fnumber>"] ],' % name.lower())
+ print(' "<number>": [ ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ],')
+ print(' "<fnumber>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ]%s' % (',' if not(last) else ''))
+
+
+def define_BYTES_ID(name, last):
+ """Create definition for the BYTES_ID token."""
+
+ print(' "<%s>": [ ["$"], ["$*"], [ "$", "<id>", "<idx>" ], [ "$", "<id>", "*" ] ],' % name.lower())
+ print(' "<id>": [ ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"] ],')
+ print(' "<idx>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ]%s' % (',' if not(last) else ''))
+
+
+def define_BYTES_ID_COUNTER(name, last):
+ """Create definition for the BYTES_ID_COUNTER token."""
+
+ print(' "<%s>": [ ["#"], ["#*"], [ "#", "<id>", "<idx>" ], [ "#", "<id>", "*" ] ],' % name.lower())
+ print(' "<id>": [ ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"] ],')
+ print(' "<idx>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ]%s' % (',' if not(last) else ''))
+
+
+def define_BYTES_ID_START(name, last):
+ """Create definition for the BYTES_ID_START token."""
+
+ print(' "<%s>": [ ["@"], ["@*"], [ "@", "<id>", "<idx>" ], [ "@", "<id>", "*" ] ],' % name.lower())
+ print(' "<id>": [ ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"] ],')
+ print(' "<idx>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ]%s' % (',' if not(last) else ''))
+
+
+def define_BYTES_ID_LENGTH(name, last):
+ """Create definition for the BYTES_ID_LENGTH token."""
+
+ print(' "<%s>": [ ["!"], ["!*"], [ "!", "<id>", "<idx>" ], [ "!", "<id>", "*" ] ],' % name.lower())
+ print(' "<id>": [ ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"] ],')
+ print(' "<idx>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ]%s' % (',' if not(last) else ''))
+
+
+def define_BYTES_ID_END(name, last):
+ """Create definition for the BYTES_ID_END token."""
+
+ print(' "<%s>": [ ["~"], ["~*"], [ "~", "<id>", "<idx>" ], [ "~", "<id>", "*" ] ],' % name.lower())
+ print(' "<id>": [ ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"] ],')
+ print(' "<idx>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"] ]%s' % (',' if not(last) else ''))
+
+
+def define_HEX_BYTES(name, last):
+ """Create definition for the HEX_BYTES token."""
+
+ print(' "<%s>": [ ["<hex>", "<hex>"] ],' % name.lower())
+ print(' "<hex>": [ ["0"], ["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"], ["a"], ["b"], ["c"], ["d"], ["e"], ["f"] ]%s' % (',' if not(last) else ''))
+
+
+def define_FULL_MASK(name, last):
+ """Create definition for the FULL_MASK token."""
+
+ print(' "<%s>": [ ["?", "?"] ]%s' % (name.lower(), ',' if not(last) else ''))
+
+
+def define_SEMI_MASK(name, last):
+ """Create definition for the SEMI_MASK token."""
+
+ print(' "<%s>": [ ["?0"], ["1?"] ]%s' % (name.lower(), ',' if not(last) else ''))
+
+
+def define_KB(name, last):
+ """Create definition for the KB token."""
+
+ print(' "<%s>": [ ["kb"], ["Kb"], ["kB"], ["KB"] ]%s' % (name.lower(), ',' if not(last) else ''))
+
+
+def define_MB(name, last):
+ """Create definition for the MB token."""
+
+ print(' "<%s>": [ ["mb"], ["Mb"], ["mB"], ["MB"] ]%s' % (name.lower(), ',' if not(last) else ''))
+
+
+def define_GB(name, last):
+ """Create definition for the GB token."""
+
+ print(' "<%s>": [ ["gb"], ["Gb"], ["gB"], ["GB"] ]%s' % (name.lower(), ',' if not(last) else ''))
+
+
+__lexer_tokens = {
+ 'PLAIN_TEXT': define_PLAIN_TEXT,
+ 'ESCAPED_TEXT': define_PLAIN_TEXT,
+ 'RULE_IDENTIFIER': define_IDENTIFIER,
+ 'INFO_KEY': define_PLAIN_TEXT,
+ 'SIGNED_INTEGER': define_SIGNED_INTEGER,
+ 'UNSIGNED_INTEGER': define_UNSIGNED_INTEGER,
+
+ 'BYTES_ID': define_BYTES_ID,
+ 'BYTES_FUZZY_ID': define_BYTES_ID,
+ 'BYTES_ID_COUNTER': define_BYTES_ID_COUNTER,
+ 'BYTES_FUZZY_ID_COUNTER': define_BYTES_ID_COUNTER,
+ 'BYTES_ID_START': define_BYTES_ID_START,
+ 'BYTES_FUZZY_ID_START': define_BYTES_ID_START,
+ 'BYTES_ID_LENGTH': define_BYTES_ID_LENGTH,
+ 'BYTES_FUZZY_ID_LENGTH': define_BYTES_ID_LENGTH,
+ 'BYTES_ID_END': define_BYTES_ID_END,
+ 'BYTES_FUZZY_ID_END': define_BYTES_ID_END,
+
+ 'NAME': define_PLAIN_TEXT,
+ 'HEX_BYTES': define_HEX_BYTES,
+ 'FULL_MASK': define_FULL_MASK,
+ 'SEMI_MASK': define_SEMI_MASK,
+ 'REGEX_BYTES': define_PLAIN_TEXT,
+ 'REGEX_CLASSES': define_PLAIN_TEXT,
+ 'REGEX_RANGE': define_PLAIN_TEXT,
+ 'KB': define_KB,
+ 'MB': define_MB,
+ 'GB': define_GB,
+}
+
+
+def remove_grammar_comments(grammar):
+ """Delete all the C code comments."""
+
+ # Cf. https://stackoverflow.com/questions/241327/remove-c-and-c-comments-using-python/241506#241506
+
+ def replacer(match):
+ s = match.group(0)
+ if s.startswith('/'):
+ return ' ' # note: a space and not an empty string
+ else:
+ return s
+
+ regex = re.compile(
+ r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+ re.DOTALL | re.MULTILINE
+ )
+
+ return regex.sub(replacer, grammar)
+
+
+def remove_grammar_actions(grammar):
+ """Delete all the C code handling tokens."""
+
+ remaining = ''
+
+ scope = 0
+ string = False
+
+ for ch in grammar:
+
+ if ch == '{' and not(string):
+ scope += 1
+
+ elif ch == '}' and not(string):
+ assert(scope > 0)
+ scope -= 1
+
+ elif scope == 0:
+ remaining += ch
+ if ch == '"':
+ string = not(string)
+
+ return remaining
+
+
+def is_upper(text):
+ """State if a string is upper case."""
+
+ return text.upper() == text
+
+
+def parse_rule_definition(grammar):
+ """Process the definition of one rule."""
+
+ result = []
+
+ regex = re.compile('(?<!")\|')
+
+ definitions = regex.split(grammar)
+
+ definitions = [ d.strip() for d in definitions ]
+
+ for d in definitions:
+
+ tokens = d.split()
+
+ converted = []
+
+ for t in tokens:
+
+ if not(t.startswith('"')) and is_upper(t):
+
+ if not(t in __lexer_tokens.keys()):
+ print('Missing def:', t)
+ sys.exit()
+
+ assert(t in __lexer_tokens.keys())
+
+ converted.append('"<%s>"' % t.lower())
+
+ else:
+
+ if t.startswith('"'):
+ converted.append('%s' % t)
+ else:
+ converted.append('"<%s>"' % t)
+
+ result.append(converted)
+
+ return result
+
+
+def parse_rules(grammar):
+ """Process all the rules contained in the grammar."""
+
+ tree = {}
+
+ regex = re.compile('[\n\t ]*([^\n\t :]+)[\n\t ]*:([^;]+);')
+
+ rules = regex.findall(grammar)
+
+ first = True
+
+ for r in rules:
+
+ if first:
+ print(' "<START>": [ ["<%s>"] ],' % r[0])
+ first = False
+
+ definitions = parse_rule_definition(r[1])
+
+ tree[r[0]] = definitions
+
+ return tree
+
+
+def simplify_tree(tree):
+ """Remove nodes which only are links between two levels of nodes."""
+
+ """
+ a = [ [b] ]
+ b = [ [c], [d] ]
+
+ -> replace a by b
+ """
+
+ # Examples: cexpression, modifier_arg
+
+ replaced = {}
+
+ for k, v in tree.items():
+
+ if len(v) == 1 and len(v[0]) == 1:
+
+ replaced['"<%s>"' % k] = v[0][0]
+
+ new_tree = {}
+
+ for k, v in tree.items():
+
+ name = '"<%s>"' % k
+
+ if not(name in replaced.keys()):
+
+ new_v = []
+
+ for vv in v:
+
+ new_vv = vv
+
+ for rk, rv in replaced.items():
+ new_vv = list(map(lambda x: x.replace(rk, rv), new_vv))
+
+ new_v.append(new_vv)
+
+ new_tree[k] = new_v
+
+ return new_tree
+
+
+def find_direct_parent_nodes(tree, name):
+ """Find all the rules containing a rule."""
+
+ rules = []
+
+ name = '"<%s>"' % name
+
+ for k, v in tree.items():
+
+ for vv in v:
+
+ if len(vv) == 1 and vv[0] == name and not(k in rules):
+
+ rules.append(k)
+
+ return rules
+
+
+def remove_indirect_left_recursion(tree):
+ """Remove all nodes which implies indirect left recursion."""
+
+ """
+ a = b
+ b = a + c
+
+ -> a = a + c
+ """
+
+ # Examples: logical_expr, relational_expr, string_op, arithm_expr, intersection
+
+ replaced = {}
+
+ for k, v in tree.items():
+
+ parents = find_direct_parent_nodes(tree, k)
+
+ if len(parents) != 1:
+ continue
+
+ parent = parents[0]
+
+ for vv in v:
+
+ if vv[0] == '"<%s>"' % parent:
+ replaced[k] = v
+ break
+
+ new_tree = {}
+
+ for k, v in tree.items():
+
+ if not(k in replaced.keys()):
+
+ new_v = []
+
+ for vv in v:
+
+ if len(vv) != 1:
+ new_v.append(vv)
+
+ else:
+
+ modified = False
+
+ for rk, rv in replaced.items():
+ if '"<%s>"' % rk == vv[0]:
+ new_v += rv
+ modified = True
+ break
+
+ if not(modified):
+ new_v.append(vv)
+
+ new_tree[k] = new_v
+
+ return new_tree
+
+
+def output_rules(tree):
+ """Output a translated rule."""
+
+ for k, v in tree.items():
+
+ print(' "<%s>": [' % k, end='')
+
+ first = True
+
+ for d in v:
+
+ if not(first):
+ print(',', end='')
+
+ if len(d) == 0:
+ print(' []', end='')
+
+ else:
+
+ print(' [', end='')
+
+ sub_first = True
+
+ for sub_d in d:
+
+ if not(sub_first):
+ print(', ', end='')
+
+ print('%s' % sub_d, end='')
+
+ sub_first = False
+
+ print(']', end='')
+
+ first = False
+
+ print(' ],')
+
+
+if __name__ == '__main__':
+ """Script entrypoint."""
+
+ # Cf. https://github.com/AFLplusplus/Grammar-Mutator/blob/stable/doc/customizing-grammars.md
+
+ with open(sys.argv[1], 'r') as fd:
+ grammar = fd.read()
+
+ grammar = grammar.split('%%')[1]
+
+ grammar = remove_grammar_comments(grammar)
+
+ grammar = remove_grammar_actions(grammar)
+
+ print('{')
+
+ tree = parse_rules(grammar)
+
+ tree = simplify_tree(tree)
+
+ tree = remove_indirect_left_recursion(tree)
+
+ output_rules(tree)
+
+ count = len(__lexer_tokens.keys())
+
+ for name, cb in __lexer_tokens.items():
+ cb(name, count == 1)
+ count -= 1
+
+ print('}')
diff --git a/tools/fuzzing/rost/fast-rost.c b/tools/fuzzing/rost/fast-rost.c
new file mode 100644
index 0000000..f161273
--- /dev/null
+++ b/tools/fuzzing/rost/fast-rost.c
@@ -0,0 +1,283 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * fast-rost.c - fichier d'entrée du centre de collecte, adapté pour un fuzzing optimal
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <assert.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <locale.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include <analysis/contents/file.h>
+#include <analysis/scan/options.h>
+#include <analysis/scan/scanner.h>
+#include <analysis/scan/patterns/backends/bitap.h>
+#include <analysis/scan/patterns/backends/acism.h>
+#include <core/core.h>
+#include <core/global.h>
+#include <core/logs.h>
+#include <core/paths.h>
+#include <plugins/pglist.h>
+
+
+
+#ifndef __AFL_FUZZ_TESTCASE_LEN
+
+ssize_t fuzz_len;
+unsigned char fuzz_buf[1024000];
+
+# define __AFL_FUZZ_TESTCASE_LEN fuzz_len
+# define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
+# define __AFL_FUZZ_INIT() void sync(void);
+# define __AFL_LOOP(x) \
+ ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0)
+# define __AFL_INIT() sync()
+
+#endif
+
+
+__AFL_FUZZ_INIT();
+
+
+/******************************************************************************
+* *
+* Paramètres : argc = nombre d'arguments dans la ligne de commande. *
+* argv = arguments de la ligne de commande. *
+* *
+* Description : Point d'entrée du programme. *
+* *
+* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int main(int argc, char **argv)
+{
+ int result; /* Bilan de l'exécution */
+ bool check_only; /* Validation uniquement */
+ LogMessageType verbosity; /* Niveau de filtre de message */
+ GScanOptions *options; /* Options d'analyses */
+ int index; /* Indice d'argument */
+ int ret; /* Bilan d'un appel */
+ char *edir; /* Répertoire de base effectif */
+ char *target; /* Cible communiquée */
+ unsigned char *afl_buf; /* Tampon de travail d'AFL */
+ int afl_len; /* Taille de ce tampon */
+ GContentScanner *scanner; /* Encadrement d'une recherche */
+ GBinContent *content; /* Contenu à analyser */
+ GScanContext *context; /* Contexte des trouvailles */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ bool full; /* Détailler l'affichage ? */
+
+ static struct option long_options[] = {
+ { "algorithm", required_argument, NULL, 'A' },
+ { "check-only", no_argument, NULL, 'C' },
+ { "print-json", no_argument, NULL, 'j' },
+ { "print-strings", no_argument, NULL, 's' },
+ { "print-stats", no_argument, NULL, 'S' },
+ { "print-tags", no_argument, NULL, 'g' },
+ { "tag", required_argument, NULL, 't' },
+ { "verbosity", required_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ result = EXIT_FAILURE;
+
+ /* Décodage des options */
+
+ check_only = false;
+ verbosity = LMT_COUNT;
+
+ options = g_scan_options_new();
+
+ g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND);
+
+ while (true)
+ {
+ ret = getopt_long(argc, argv, "A:CjsSgt:V:", long_options, &index);
+ if (ret == -1) break;
+
+ switch (ret)
+ {
+ case 'A':
+ if (strcmp(optarg, "bitmap") == 0)
+ g_scan_options_set_backend_for_data(options, G_TYPE_BITAP_BACKEND);
+ else if (strcmp(optarg, "acism") == 0)
+ g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND);
+ else
+ g_scan_options_set_backend_for_data(options, G_TYPE_INVALID);
+ break;
+
+ case 'C':
+ check_only = true;
+ g_scan_options_set_check_only(options, true);
+ break;
+
+ case 'j':
+ g_scan_options_set_print_json(options, true);
+ break;
+
+ case 's':
+ g_scan_options_set_print_strings(options, true);
+ break;
+
+ case 'S':
+ g_scan_options_set_print_stats(options, true);
+ break;
+
+ case 'g':
+ g_scan_options_set_print_tags(options, true);
+ break;
+
+ case 't':
+ g_scan_options_select_tag(options, optarg);
+ break;
+
+ case 'V':
+ verbosity = strtoul(optarg, NULL, 10);
+ break;
+
+ }
+
+ }
+
+ if ((check_only && (optind + 0) != argc && (optind + 1) != argc)
+ || (!check_only && (optind + 1) != argc && (optind + 2) != argc))
+ {
+ goto done;
+ }
+
+ /* Actions de base */
+
+ if (g_scan_options_get_backend_for_data(options) == G_TYPE_INVALID)
+ {
+ goto done;
+ }
+
+ /* Lancement des choses sérieuses */
+
+ setlocale(LC_ALL, "");
+ edir = get_effective_directory(LOCALE_DIR);
+ bindtextdomain(PACKAGE, edir);
+ free(edir);
+ textdomain(PACKAGE);
+
+ /* Initialisation de GTK */
+ g_set_prgname("ROST");
+ //gtk_init(&argc, &argv);
+
+ /* Initialisation du programme */
+
+ set_batch_mode();
+
+ set_log_verbosity(verbosity);
+
+ if (!load_all_core_components(true))
+ goto done;
+
+ init_all_plugins(true);
+
+ /* Traitement des recherches */
+
+ if ((optind + 1) == argc)
+ target = argv[optind];
+ else
+ goto done;
+
+ __AFL_INIT();
+
+ afl_buf = __AFL_FUZZ_TESTCASE_BUF;
+
+ while (__AFL_LOOP(10000))
+ {
+ afl_len = __AFL_FUZZ_TESTCASE_LEN;
+
+ scanner = g_content_scanner_new_from_text((char *)afl_buf, afl_len);
+
+#if 0
+ do
+ {
+ FILE *stream;
+
+ stream = fopen("/dev/shm/ctrl.log", "a");
+ fprintf(stream, "running %d bytes => %p\n", afl_len, scanner);
+ fclose(stream);
+
+ } while (0);
+#endif
+
+ if (scanner != NULL)
+ result = EXIT_SUCCESS;
+
+ if (scanner != NULL && !check_only)
+ {
+ content = g_file_content_new(target);
+ if (content == NULL) goto bad_file_content;
+
+ context = g_content_scanner_analyze(scanner, options, content);
+
+ if (g_scan_options_get_print_json(options))
+ {
+ padding.data = " ";
+ padding.len = 3;
+
+ g_content_scanner_output_to_json(scanner, context, &padding, 0, STDOUT_FILENO);
+
+ }
+ else
+ {
+ full = g_scan_options_get_print_strings(options);
+
+ g_content_scanner_output_to_text(scanner, context, full, STDOUT_FILENO);
+
+ }
+
+ g_object_unref(G_OBJECT(context));
+ g_object_unref(G_OBJECT(content));
+
+ bad_file_content:
+
+ g_object_unref(G_OBJECT(scanner));
+
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(options));
+
+ /* Sortie */
+
+ unload_all_core_components(false);
+
+ done:
+
+ return result;
+
+}
diff --git a/tools/fuzzing/rost/gen-dict.sh b/tools/fuzzing/rost/gen-dict.sh
new file mode 100755
index 0000000..dfebc0a
--- /dev/null
+++ b/tools/fuzzing/rost/gen-dict.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+TOP_DIR="$SCRIPT_DIR/../../.."
+OUTPUT="$SCRIPT_DIR/rost.dict"
+
+
+echo > "$OUTPUT"
+
+
+echo "# Syntax core keywords" >> "$OUTPUT"
+
+cat "$TOP_DIR/src/analysis/scan/grammar.y" | \
+ grep '%token.*".*' | grep -o -E '"[^"]+"' | sort >> "$OUTPUT"
+
+
+echo >> "$OUTPUT"
+echo "# Modifiers" >> "$OUTPUT"
+
+"$TOP_DIR/src/rost" --dump-modifiers | sort | sed -e 's/^/"/' -e 's/$/"/' >> "$OUTPUT"
+
+
+echo >> "$OUTPUT"
+echo "# Namespace" >> "$OUTPUT"
+
+"$TOP_DIR/src/rost" --dump-namespaces | sort | sed -e 's/^/"/' -e 's/$/"/' >> "$OUTPUT"
+
+
+echo >> "$OUTPUT"
+echo "# Identifiers" >> "$OUTPUT"
+
+for t in "$" "#" "@" "!" "~" ;
+do
+ echo "\"${t}a0\"" >> "$OUTPUT"
+ echo "\"${t}a1\"" >> "$OUTPUT"
+ echo "\"${t}b\"" >> "$OUTPUT"
+ echo "\"${t}c\"" >> "$OUTPUT"
+ echo "\"${t}a*\"" >> "$OUTPUT"
+ echo "\"${t}*\"" >> "$OUTPUT"
+ echo "\"${t}\"" >> "$OUTPUT"
+
+done
+
+
+echo >> "$OUTPUT"
+echo "# Numbers" >> "$OUTPUT"
+
+for i in $( seq 0 32 );
+do
+ echo -$(( 2 ** i - 1 )) ;
+ echo -$(( 2 ** i )) ;
+ echo -$(( 2 ** i + 1 )) ;
+
+ echo $(( 2 ** i - 1 )) ;
+ echo $(( 2 ** i )) ;
+ echo $(( 2 ** i + 1 )) ;
+
+done | sort | uniq | sort -n >> "$OUTPUT"
+
+
+echo >> "$OUTPUT"
+echo "# Misc" >> "$OUTPUT"
+
+echo "\"kb\"" >> "$OUTPUT"
+echo "\"mb\"" >> "$OUTPUT"
+echo "\"gb\"" >> "$OUTPUT"
+
+echo "\"a0\"" >> "$OUTPUT"
+echo "\"a1\"" >> "$OUTPUT"
+echo "\"b\"" >> "$OUTPUT"
+echo "\"c\"" >> "$OUTPUT"
+
+echo "\"\\\"abcdef\\\"\"" >> "$OUTPUT"
+echo "\"\\\"azerty\\\"\"" >> "$OUTPUT"
+echo "\"\\\"qwertyqwerty\\\"\"" >> "$OUTPUT"
+echo "\"??\"" >> "$OUTPUT"
+echo "\"0?\"" >> "$OUTPUT"
+echo "\"?a\"" >> "$OUTPUT"
+
+echo >> "$OUTPUT"
diff --git a/tools/fuzzing/rost/minall.sh b/tools/fuzzing/rost/minall.sh
new file mode 100755
index 0000000..e32777d
--- /dev/null
+++ b/tools/fuzzing/rost/minall.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+if [ -z "$FUZ_OUT" ]; then
+ echo "$0 needs a \$FUZ_OUT environment variable!"
+ exit 1
+fi
+
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+MIN_DIR="$SCRIPT_DIR/min"
+
+
+mkdir -p "$MIN_DIR"
+
+find "$FUZ_OUT/default/crashes/" -name 'id*' | while read f;
+do
+
+ id=$( echo $f | cut -d: -f2 | cut -d, -f1 )
+
+ h=$( sha256sum $f | cut -d " " -f1 )
+
+ afl-tmin -i "$f" -o "$MIN_DIR/$id-$h.rost" -- /dev/shm/fuzzing-sys/bin/fast-rost /bin/ls
+
+done
diff --git a/tools/fuzzing/rost/rerun.sh b/tools/fuzzing/rost/rerun.sh
new file mode 100755
index 0000000..3e75189
--- /dev/null
+++ b/tools/fuzzing/rost/rerun.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+TOP_DIR="$SCRIPT_DIR/../../.."
+MIN_DIR="$SCRIPT_DIR/min"
+
+
+find "$MIN_DIR" -type f -name '*rost' | while read f;
+do
+ echo "=========== $f"
+
+ "$TOP_DIR/src/rost" $f /bin/ls
+
+ status=$?
+
+ if [ $status -le 2 ]; then
+ rm $f
+ fi
+
+ sleep 1s
+
+done
+
+
+
+
diff --git a/tools/fuzzing/rost/test.rost b/tools/fuzzing/rost/test.rost
new file mode 100644
index 0000000..02daabe
--- /dev/null
+++ b/tools/fuzzing/rost/test.rost
@@ -0,0 +1,12 @@
+
+rule basic {
+
+ bytes:
+ $a = "ABC" base64
+ $b = "12"
+ $c = { 00 01 f0 ff ff [0-9] 23 }
+
+ condition:
+ (#a == 123 or $b or $c) and console.log(maxcommon(modpath($a, $b)))
+
+}
diff --git a/tools/maint/extra.supp b/tools/maint/extra.supp
new file mode 100644
index 0000000..58cbd32
--- /dev/null
+++ b/tools/maint/extra.supp
@@ -0,0 +1,777 @@
+
+# ==2020629== 64 bytes in 1 blocks are still reachable in loss record 516 of 1,020
+# ==2020629== at 0x48406C4: malloc (vg_replace_malloc.c:380)
+# ==2020629== by 0x49044CD: g_realloc (gmem.c:201)
+# ==2020629== by 0x48EBCDC: g_hash_table_realloc_key_or_value_array (ghash.c:382)
+# ==2020629== by 0x48EBCDC: g_hash_table_setup_storage (ghash.c:591)
+# ==2020629== by 0x48EC6C8: g_hash_table_new_full (ghash.c:1085)
+# ==2020629== by 0x48EC6F0: g_hash_table_new (ghash.c:1036)
+# ==2020629== by 0x48E84A4: g_error_init (gerror.c:525)
+# ==2020629== by 0x48FA392: glib_init (glib-init.c:342)
+# ==2020629== by 0x48FA3A0: glib_init_ctor (glib-init.c:455)
+# ==2020629== by 0x4004ABD: call_init (dl-init.c:70)
+# ==2020629== by 0x4004ABD: call_init (dl-init.c:26)
+# ==2020629== by 0x4004BA3: _dl_init (dl-init.c:117)
+# ==2020629== by 0x401AA5F: ??? (in /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)
+# ==2020629== by 0x2: ???
+# ==2020629== by 0x1FFF0002B2: ???
+# ==2020629== by 0x1FFF0002C3: ???
+# ==2020629== by 0x1FFF0002CF: ???
+# ==2020629==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:g_realloc
+ fun:g_hash_table_realloc_key_or_value_array
+ fun:g_hash_table_setup_storage
+ fun:g_hash_table_new_full
+ fun:g_hash_table_new
+ fun:g_error_init
+ fun:glib_init
+ fun:glib_init_ctor
+ fun:call_init
+ fun:call_init
+ fun:_dl_init
+ ...
+}
+
+
+# ==1996673== 32 bytes in 1 blocks are still reachable in loss record 415 of 1,026
+# ==1996673== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
+# ==1996673== by 0x490447A: g_malloc0 (gmem.c:163)
+# ==1996673== by 0x490466E: g_malloc0_n (gmem.c:404)
+# ==1996673== by 0x48EBCF1: g_hash_table_setup_storage (ghash.c:593)
+# ==1996673== by 0x48EC6C8: g_hash_table_new_full (ghash.c:1085)
+# ==1996673== by 0x48EC6F0: g_hash_table_new (ghash.c:1036)
+# ==1996673== by 0x48E84A4: g_error_init (gerror.c:525)
+# ==1996673== by 0x48FA392: glib_init (glib-init.c:342)
+# ==1996673== by 0x48FA3A0: glib_init_ctor (glib-init.c:455)
+# ==1996673== by 0x4004ABD: call_init (dl-init.c:70)
+# ==1996673== by 0x4004ABD: call_init (dl-init.c:26)
+# ==1996673== by 0x4004BA3: _dl_init (dl-init.c:117)
+# ==1996673== by 0x401AA5F: ??? (in /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)
+# ==1996673== by 0x2: ???
+# ==1996673== by 0x1FFF0002B2: ???
+# ==1996673== by 0x1FFF0002C3: ???
+# ==1996673== by 0x1FFF0002CF: ???
+# ==1996673==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:calloc
+ fun:g_malloc0
+ fun:g_malloc0_n
+ fun:g_hash_table_setup_storage
+ fun:g_hash_table_new_full
+ fun:g_hash_table_new
+ fun:g_error_init
+ fun:glib_init
+ fun:glib_init_ctor
+ fun:call_init
+ fun:call_init
+ fun:_dl_init
+ ...
+}
+
+
+# ==1995462== 88 bytes in 1 blocks are still reachable in loss record 729 of 1,026
+# ==1995462== at 0x48815F4: type_node_any_new_W (gtype.c:457)
+# ==1995462== by 0x4881770: type_node_fundamental_new_W (gtype.c:564)
+# ==1995462== by 0x4883A1B: g_type_register_fundamental (gtype.c:2748)
+# ==1995462== by 0x488B1E1: _g_value_types_init (gvaluetypes.c:529)
+# ==1995462== by 0x4886E9B: gobject_init (gtype.c:4521)
+# ==1995462== by 0x4886F31: gobject_init_ctor (gtype.c:4636)
+# ==1995462== by 0x4004ABD: call_init (dl-init.c:70)
+# ==1995462== by 0x4004ABD: call_init (dl-init.c:26)
+# ==1995462== by 0x4004BA3: _dl_init (dl-init.c:117)
+# ==1995462== by 0x401AA5F: ??? (in /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)
+# ==1995462== by 0x2: ???
+# ==1995462== by 0x1FFF0002B2: ???
+# ==1995462== by 0x1FFF0002C3: ???
+# ==1995462== by 0x1FFF0002CF: ???
+# ==1995462==
+
+{
+ Code in type_data_unref_U is disabled
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:type_node_any_new_W
+ fun:type_node_fundamental_new_W
+ fun:g_type_register_fundamental
+ fun:*_init
+ fun:gobject_init
+ fun:gobject_init_ctor
+ fun:call_init
+ fun:call_init
+ fun:_dl_init
+ ...
+}
+
+
+# ==1995681== 96 bytes in 1 blocks are still reachable in loss record 745 of 1,026
+# ==1995681== at 0x48407B4: malloc (vg_replace_malloc.c:381)
+# ==1995681== by 0x4904422: g_malloc (gmem.c:130)
+# ==1995681== by 0x491A9B1: g_slice_alloc (gslice.c:1074)
+# ==1995681== by 0x48EC68A: g_hash_table_new_full (ghash.c:1073)
+# ==1995681== by 0x48EC6F0: g_hash_table_new (ghash.c:1036)
+# ==1995681== by 0x48E84A4: g_error_init (gerror.c:525)
+# ==1995681== by 0x48FA392: glib_init (glib-init.c:342)
+# ==1995681== by 0x48FA3A0: glib_init_ctor (glib-init.c:455)
+# ==1995681== by 0x4004ABD: call_init (dl-init.c:70)
+# ==1995681== by 0x4004ABD: call_init (dl-init.c:26)
+# ==1995681== by 0x4004BA3: _dl_init (dl-init.c:117)
+# ==1995681== by 0x401AA5F: ??? (in /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)
+# ==1995681== by 0x2: ???
+# ==1995681== by 0x1FFF0002B2: ???
+# ==1995681== by 0x1FFF0002C3: ???
+# ==1995681== by 0x1FFF0002CF: ???
+# ==1995681==
+
+{
+ Code in type_data_unref_U is disabled
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:g_malloc
+ fun:g_slice_alloc
+ fun:g_hash_table_new_full
+ fun:g_hash_table_new
+ fun:g_error_init
+ fun:glib_init
+ fun:glib_init_ctor
+ fun:call_init
+ fun:call_init
+ fun:_dl_init
+ ...
+}
+
+
+# ==1995732== 88 bytes in 1 blocks are still reachable in loss record 721 of 1,026
+# ==1995732== at 0x48815F4: type_node_any_new_W (gtype.c:457)
+# ==1995732== by 0x4881770: type_node_fundamental_new_W (gtype.c:564)
+# ==1995732== by 0x4886E35: gobject_init (gtype.c:4504)
+# ==1995732== by 0x4886F31: gobject_init_ctor (gtype.c:4636)
+# ==1995732== by 0x4004ABD: call_init (dl-init.c:70)
+# ==1995732== by 0x4004ABD: call_init (dl-init.c:26)
+# ==1995732== by 0x4004BA3: _dl_init (dl-init.c:117)
+# ==1995732== by 0x401AA5F: ??? (in /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)
+# ==1995732== by 0x2: ???
+# ==1995732== by 0x1FFF0002B2: ???
+# ==1995732== by 0x1FFF0002C3: ???
+# ==1995732== by 0x1FFF0002CF: ???
+# ==1995732==
+
+{
+ Code in type_data_unref_U is disabled
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:type_node_any_new_W
+ fun:type_node_fundamental_new_W
+ fun:gobject_init
+ fun:gobject_init_ctor
+ fun:call_init
+ fun:call_init
+ fun:_dl_init
+ ...
+}
+
+
+######################################################
+
+
+# ==1994638== 88 bytes in 1 blocks are still reachable in loss record 740 of 1,026
+# ==1994638== at 0x48815F4: type_node_any_new_W (gtype.c:457)
+# ==1994638== by 0x4881770: type_node_fundamental_new_W (gtype.c:564)
+# ==1994638== by 0x4883A1B: g_type_register_fundamental (gtype.c:2748)
+# ==1994638== by 0x486C204: _g_object_type_init (gobject.c:456)
+# ==1994638== by 0x4886EAF: gobject_init (gtype.c:4537)
+# ==1994638== by 0x4886F31: gobject_init_ctor (gtype.c:4636)
+# ==1994638== by 0x4004ABD: call_init (dl-init.c:70)
+# ==1994638== by 0x4004ABD: call_init (dl-init.c:26)
+# ==1994638== by 0x4004BA3: _dl_init (dl-init.c:117)
+# ==1994638== by 0x401AA5F: ??? (in /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)
+# ==1994638== by 0x2: ???
+# ==1994638== by 0x1FFF0002B2: ???
+# ==1994638== by 0x1FFF0002C3: ???
+# ==1994638== by 0x1FFF0002CF: ???
+# ==1994638==
+
+# g_type_free_instance / g_type_class_unref / type_data_unref_U (cf. glib2.0-2.74.6/gobject/gtype.c)
+
+{
+ Code in type_data_unref_U is disabled
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:type_node_any_new_W
+ fun:type_node_fundamental_new_W
+ fun:g_type_register_fundamental
+ fun:_g_object_type_init
+ fun:gobject_init
+ fun:gobject_init_ctor
+ fun:call_init
+ fun:call_init
+ fun:_dl_init
+ ...
+}
+
+
+# ==1994765== 8 bytes in 1 blocks are still reachable in loss record 14 of 1,026
+# ==1994765== at 0x485FAD8: freelist_alloc (gatomicarray.c:85)
+# ==1994765== by 0x485FB28: _g_atomic_array_copy (gatomicarray.c:147)
+# ==1994765== by 0x48810CE: iface_node_set_offset_L (gtype.c:1371)
+# ==1994765== by 0x4881318: type_node_add_iface_entry_W (gtype.c:1456)
+# ==1994765== by 0x4882417: type_add_interface_Wm (gtype.c:1501)
+# ==1994765== by 0x4884B69: g_type_add_interface_static (gtype.c:2939)
+# ==1994765== by 0x4A73709: g_arch_instruction_get_type_once (instruction.c:122)
+# ==1994765== by 0x4A73662: g_arch_instruction_get_type (instruction.c:122)
+# ==1994765== by 0x4A7DBED: g_raw_instruction_get_type_once (raw.c:105)
+# ==1994765== by 0x4A7DBAA: g_raw_instruction_get_type (raw.c:105)
+# ==1994765== by 0x4A8FED8: register_arch_gtypes (processors.c:80)
+# ==1994765== by 0x4A8E4C4: load_all_core_components (core.c:123)
+# ==1994765== by 0x10AAD1: main (rost.c:369)
+# ==1994765==
+
+# g_type_free_instance / g_type_class_unref / type_data_unref_U (cf. glib2.0-2.74.6/gobject/gtype.c)
+
+{
+ Code in type_data_unref_U is disabled
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:freelist_alloc
+ fun:_g_atomic_array_copy
+ fun:iface_node_set_offset_L
+ fun:type_node_add_iface_entry_W
+ fun:type_add_interface_Wm
+ fun:g_type_add_interface_static
+ ...
+}
+
+
+# ==1995318== 184 bytes in 1 blocks are still reachable in loss record 991 of 1,026
+# ==1995318== at 0x484582F: realloc (vg_replace_malloc.c:1437)
+# ==1995318== by 0x49044CD: g_realloc (gmem.c:201)
+# ==1995318== by 0x49046E4: g_realloc_n (gmem.c:433)
+# ==1995318== by 0x488150E: type_node_any_new_W (gtype.c:516)
+# ==1995318== by 0x488184A: type_node_new_W (gtype.c:582)
+# ==1995318== by 0x48857D3: g_type_register_dynamic (gtype.c:2900)
+# ==1995318== by 0x4AA8962: g_dynamic_types_register_type (dt.c:383)
+# ==1995318== by 0x4AA8AC1: build_dynamic_type (dt.c:483)
+# ==1995318== by 0x4AAABDA: g_plugin_module_new (plugin.c:506)
+# ==1995318== by 0x4AA90C0: browse_directory_for_plugins (pglist.c:272)
+# ==1995318== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1995318== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1995318== by 0x4AA8C33: init_all_plugins (pglist.c:86)
+# ==1995318== by 0x10AAE6: main (rost.c:372)
+# ==1995318==
+
+{
+ Code in type_data_unref_U is disabled
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:realloc
+ fun:g_realloc
+ fun:g_realloc_n
+ fun:type_node_any_new_W
+ fun:type_node_new_W
+ fun:g_type_register_dynamic
+ ...
+}
+
+
+# ==1995789== 2,048 bytes in 1 blocks are still reachable in loss record 1,020 of 1,026
+# ==1995789== at 0x484582F: realloc (vg_replace_malloc.c:1437)
+# ==1995789== by 0x49044CD: g_realloc (gmem.c:201)
+# ==1995789== by 0x48EC1A6: g_hash_table_realloc_key_or_value_array (ghash.c:382)
+# ==1995789== by 0x48EC1A6: realloc_arrays (ghash.c:724)
+# ==1995789== by 0x48EC283: g_hash_table_resize (ghash.c:877)
+# ==1995789== by 0x48EC308: g_hash_table_maybe_resize (ghash.c:917)
+# ==1995789== by 0x48EC460: g_hash_table_insert_node (ghash.c:1370)
+# ==1995789== by 0x48EC4B3: g_hash_table_insert_internal (ghash.c:1629)
+# ==1995789== by 0x48ECD1D: g_hash_table_insert (ghash.c:1658)
+# ==1995789== by 0x4881561: type_node_any_new_W (gtype.c:528)
+# ==1995789== by 0x488184A: type_node_new_W (gtype.c:582)
+# ==1995789== by 0x48857D3: g_type_register_dynamic (gtype.c:2900)
+# ==1995789== by 0x4AA8962: g_dynamic_types_register_type (dt.c:383)
+# ==1995789== by 0x4AA8AC1: build_dynamic_type (dt.c:483)
+# ==1995789== by 0x4AAABDA: g_plugin_module_new (plugin.c:506)
+# ==1995789== by 0x4AA90C0: browse_directory_for_plugins (pglist.c:272)
+# ==1995789== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1995789== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1995789== by 0x4AA8C33: init_all_plugins (pglist.c:86)
+# ==1995789== by 0x10AAE6: main (rost.c:372)
+# ==1995789==
+
+{
+ Code in type_data_unref_U is disabled
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:realloc
+ fun:g_realloc
+ fun:g_hash_table_realloc_key_or_value_array
+ fun:realloc_arrays
+ fun:g_hash_table_resize
+ fun:g_hash_table_maybe_resize
+ fun:g_hash_table_insert_node
+ fun:g_hash_table_insert_internal
+ fun:g_hash_table_insert
+ fun:type_node_any_new_W
+ fun:type_node_new_W
+ fun:g_type_register_dynamic
+ ...
+}
+
+
+# ==1995842== 56 bytes in 1 blocks are still reachable in loss record 518 of 1,026
+# ==1995842== at 0x485FAD8: freelist_alloc (gatomicarray.c:85)
+# ==1995842== by 0x485FB57: _g_atomic_array_copy (gatomicarray.c:141)
+# ==1995842== by 0x48816AB: type_node_any_new_W (gtype.c:500)
+# ==1995842== by 0x488184A: type_node_new_W (gtype.c:582)
+# ==1995842== by 0x4883C8A: g_type_register_static (gtype.c:2853)
+# ==1995842== by 0x4883D4C: g_type_register_static_simple (gtype.c:2806)
+# ==1995842== by 0x21266631: ???
+# ==1995842== by 0x212665C1: ???
+# ==1995842== by 0x20F18DB4: ???
+# ==1995842== by 0x20F18E0D: ???
+# ==1995842== by 0x20F1335A: ???
+# ==1995842== by 0x4AABB63: g_plugin_module_load (plugin.c:1115)
+# ==1995842== by 0x4AA957C: load_remaning_plugins (pglist.c:469)
+# ==1995842== by 0x4AA8CD2: init_all_plugins (pglist.c:103)
+# ==1995842== by 0x10AAE6: main (rost.c:372)
+# ==1995842==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:freelist_alloc
+ fun:_g_atomic_array_copy
+ fun:type_node_any_new_W
+ fun:type_node_new_W
+ fun:g_type_register_static
+ fun:g_type_register_static_simple
+ ...
+}
+
+
+# ==1995893== 8 bytes in 1 blocks are still reachable in loss record 36 of 1,026
+# ==1995893== at 0x48406C4: malloc (vg_replace_malloc.c:380)
+# ==1995893== by 0x49044CD: g_realloc (gmem.c:201)
+# ==1995893== by 0x49046E4: g_realloc_n (gmem.c:433)
+# ==1995893== by 0x487FE9F: type_iface_add_prerequisite_W (gtype.c:1542)
+# ==1995893== by 0x4884F28: g_type_interface_add_prerequisite (gtype.c:1632)
+# ==1995893== by 0x4A9E5C5: g_comparable_item_get_type (comparison.c:40)
+# ==1995893== by 0x4A42873: g_scan_expression_get_type_once (expr.c:73)
+# ==1995893== by 0x4A427E2: g_scan_expression_get_type (expr.c:73)
+# ==1995893== by 0x4A53253: g_scan_pattern_handler_get_type_once (handler.c:76)
+# ==1995893== by 0x4A53210: g_scan_pattern_handler_get_type (handler.c:76)
+# ==1995893== by 0x4A5347B: g_scan_pattern_handler_new (handler.c:197)
+# ==1995893== by 0x4A467F1: rost_parse (grammar.y:1606)
+# ==1995893== by 0x4A47785: process_rules_definitions (grammar.y:1895)
+# ==1995893== by 0x4A4AE47: g_content_scanner_create_from_file (scanner.c:275)
+# ==1995893== by 0x4A4AD6E: g_content_scanner_new_from_file (scanner.c:234)
+# ==1995893== by 0x10AC85: main (rost.c:421)
+# ==1995893==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:g_realloc
+ fun:g_realloc_n
+ fun:type_iface_add_prerequisite_W
+ fun:g_type_interface_add_prerequisite
+ fun:*_get_type
+ fun:*_get_type_once
+ ...
+}
+
+
+
+
+######################################################
+
+
+# ==1995203== 1,024 bytes in 1 blocks are still reachable in loss record 1,015 of 1,026
+# ==1995203== at 0x484582F: realloc (vg_replace_malloc.c:1437)
+# ==1995203== by 0x49044CD: g_realloc (gmem.c:201)
+# ==1995203== by 0x49046E4: g_realloc_n (gmem.c:433)
+# ==1995203== by 0x48EC186: realloc_arrays (ghash.c:723)
+# ==1995203== by 0x48EC283: g_hash_table_resize (ghash.c:877)
+# ==1995203== by 0x48EC308: g_hash_table_maybe_resize (ghash.c:917)
+# ==1995203== by 0x48EC460: g_hash_table_insert_node (ghash.c:1370)
+# ==1995203== by 0x48EC4B3: g_hash_table_insert_internal (ghash.c:1629)
+# ==1995203== by 0x48ECD1D: g_hash_table_insert (ghash.c:1658)
+# ==1995203== by 0x4881561: type_node_any_new_W (gtype.c:528)
+# ==1995203== by 0x488184A: type_node_new_W (gtype.c:582)
+# ==1995203== by 0x48857D3: g_type_register_dynamic (gtype.c:2900)
+# ==1995203== by 0x4AA8962: g_dynamic_types_register_type (dt.c:383)
+# ==1995203== by 0x4AA8AC1: build_dynamic_type (dt.c:483)
+# ==1995203== by 0x4AAABDA: g_plugin_module_new (plugin.c:506)
+# ==1995203== by 0x4AA90C0: browse_directory_for_plugins (pglist.c:272)
+# ==1995203== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1995203== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1995203== by 0x4AA8C33: init_all_plugins (pglist.c:86)
+# ==1995203== by 0x10AAE6: main (rost.c:372)
+# ==1995203==
+
+{
+ Lack of g_hash_table_unref() call with static_type_nodes_ht (cf. glib2.0-2.74.6/gobject/gtype.c)
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:realloc
+ fun:g_realloc
+ fun:g_realloc_n
+ fun:realloc_arrays
+ fun:g_hash_table_resize
+ fun:g_hash_table_maybe_resize
+ fun:g_hash_table_insert_node
+ fun:g_hash_table_insert_internal
+ fun:g_hash_table_insert
+ fun:type_node_any_new_W
+ fun:type_node_new_W
+ fun:g_type_register_dynamic
+ ...
+}
+
+
+######################################################
+
+
+# ==1996736== 40 bytes in 1 blocks are still reachable in loss record 485 of 1,026
+# ==1996736== at 0x48407B4: malloc (vg_replace_malloc.c:381)
+# ==1996736== by 0x494C2C3: g_rec_mutex_impl_new (gthread-posix.c:286)
+# ==1996736== by 0x494C36E: g_rec_mutex_get_impl (gthread-posix.c:312)
+# ==1996736== by 0x494C6CB: g_rec_mutex_lock (gthread-posix.c:397)
+# ==1996736== by 0x4D8CCBD: g_module_open_full (gmodule.c:515)
+# ==1996736== by 0x4D8D1A3: g_module_open (gmodule.c:698)
+# ==1996736== by 0x4AA9EB3: g_plugin_module_new (plugin.c:240)
+# ==1996736== by 0x4AA90C0: browse_directory_for_plugins (pglist.c:272)
+# ==1996736== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1996736== by 0x4AA90B2: browse_directory_for_plugins (pglist.c:268)
+# ==1996736== by 0x4AA8C33: init_all_plugins (pglist.c:86)
+# ==1996736== by 0x10AAE6: main (rost.c:372)
+# ==1996736==
+
+{
+ Lack of g_rec_mutex_clear() call with g_module_global_lock (cf. glib2.0-2.74.6/gmodule/gmodule.c)
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:g_rec_mutex_impl_new
+ fun:g_rec_mutex_get_impl
+ fun:g_rec_mutex_lock
+ fun:g_module_open_full
+ fun:g_module_open
+ ...
+}
+
+
+
+######################################################
+
+
+# ==2015061== 64 bytes in 1 blocks are still reachable in loss record 532 of 1,026
+# ==2015061== at 0x484582F: realloc (vg_replace_malloc.c:1437)
+# ==2015061== by 0x49044CD: g_realloc (gmem.c:201)
+# ==2015061== by 0x48EC1A6: g_hash_table_realloc_key_or_value_array (ghash.c:382)
+# ==2015061== by 0x48EC1A6: realloc_arrays (ghash.c:724)
+# ==2015061== by 0x48EC2D7: g_hash_table_resize (ghash.c:895)
+# ==2015061== by 0x48EC308: g_hash_table_maybe_resize (ghash.c:917)
+# ==2015061== by 0x48EC530: g_hash_table_remove_internal (ghash.c:1775)
+# ==2015061== by 0x48ECDBA: g_hash_table_remove (ghash.c:1802)
+# ==2015061== by 0x487BF82: g_signal_handlers_destroy (gsignal.c:2841)
+# ==2015061== by 0x486A853: g_object_real_dispose (gobject.c:1362)
+# ==2015061== by 0x4A9E9D2: g_config_param_dispose (configuration.c:199)
+# ==2015061== by 0x486BD35: g_object_unref (gobject.c:3867)
+# ==2015061== by 0x48FADD2: g_list_foreach (glist.c:1092)
+# ==2015061== by 0x48FADED: g_list_free_full (glist.c:246)
+# ==2015061== by 0x4AA07A6: g_generic_config_dispose (configuration.c:1233)
+# ==2015061== by 0x486BD35: g_object_unref (gobject.c:3867)
+# ==2015061== by 0x4A8FC05: unload_main_config_parameters (params.c:146)
+# ==2015061== by 0x4A8E552: unload_all_core_components (core.c:174)
+# ==2015061== by 0x10ADFC: main (rost.c:470)
+# ==2015061==
+
+{
+ Need to fix all GObject memory leaks?
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:realloc
+ fun:g_realloc
+ fun:g_hash_table_realloc_key_or_value_array
+ fun:realloc_arrays
+ fun:g_hash_table_resize
+ fun:g_hash_table_maybe_resize
+ fun:g_hash_table_remove_internal
+ fun:g_hash_table_remove
+ fun:g_signal_handlers_destroy
+ fun:g_object_real_dispose
+ ...
+}
+
+
+# ==2017718== 32 bytes in 1 blocks are still reachable in loss record 474 of 1,026
+# ==2017718== at 0x484582F: realloc (vg_replace_malloc.c:1437)
+# ==2017718== by 0x49044CD: g_realloc (gmem.c:201)
+# ==2017718== by 0x49046E4: g_realloc_n (gmem.c:433)
+# ==2017718== by 0x48EC186: realloc_arrays (ghash.c:723)
+# ==2017718== by 0x48EC2D7: g_hash_table_resize (ghash.c:895)
+# ==2017718== by 0x48EC308: g_hash_table_maybe_resize (ghash.c:917)
+# ==2017718== by 0x48EC530: g_hash_table_remove_internal (ghash.c:1775)
+# ==2017718== by 0x48ECDBA: g_hash_table_remove (ghash.c:1802)
+# ==2017718== by 0x487BF28: g_signal_handlers_destroy (gsignal.c:2823)
+# ==2017718== by 0x486A853: g_object_real_dispose (gobject.c:1362)
+# ==2017718== by 0x4A9E9D2: g_config_param_dispose (configuration.c:199)
+# ==2017718== by 0x486BD35: g_object_unref (gobject.c:3867)
+# ==2017718== by 0x48FADD2: g_list_foreach (glist.c:1092)
+# ==2017718== by 0x48FADED: g_list_free_full (glist.c:246)
+# ==2017718== by 0x4AA07A6: g_generic_config_dispose (configuration.c:1233)
+# ==2017718== by 0x486BD35: g_object_unref (gobject.c:3867)
+# ==2017718== by 0x4A8FC05: unload_main_config_parameters (params.c:146)
+# ==2017718== by 0x4A8E552: unload_all_core_components (core.c:174)
+# ==2017718== by 0x10ADFC: main (rost.c:470)
+# ==2017718==
+
+
+{
+ Need to fix all GObject memory leaks?
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:realloc
+ fun:g_realloc
+ fun:g_realloc_n
+ fun:realloc_arrays
+ fun:g_hash_table_resize
+ fun:g_hash_table_maybe_resize
+ fun:g_hash_table_remove_internal
+ fun:g_hash_table_remove
+ fun:g_signal_handlers_destroy
+ fun:g_object_real_dispose
+ ...
+}
+
+
+######################################################
+
+
+# ==2037130== 368 bytes in 23 blocks are still reachable in loss record 1,004 of 1,018
+# ==2037130== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
+# ==2037130== by 0x490447A: g_malloc0 (gmem.c:163)
+# ==2037130== by 0x487FD25: type_set_qdata_W (gtype.c:3813)
+# ==2037130== by 0x4880085: type_add_flags_W (gtype.c:3878)
+# ==2037130== by 0x48857E1: g_type_register_dynamic (gtype.c:2901)
+# ==2037130== by 0x4AA89FA: g_dynamic_types_register_type (dt.c:410)
+# ==2037130== by 0x4AA8B59: build_dynamic_type (dt.c:510)
+# ==2037130== by 0x4AAAC93: g_plugin_module_new (plugin.c:506)
+# ==2037130== by 0x4AA9179: browse_directory_for_plugins (pglist.c:281)
+# ==2037130== by 0x4AA916B: browse_directory_for_plugins (pglist.c:277)
+# ==2037130== by 0x4AA916B: browse_directory_for_plugins (pglist.c:277)
+# ==2037130== by 0x4AA8CE2: init_all_plugins (pglist.c:91)
+# ==2037130== by 0x10AB0A: main (rost.c:372)
+# ==2037130==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:calloc
+ fun:g_malloc0
+ fun:type_set_qdata_W
+ fun:type_add_flags_W
+ fun:g_type_register_dynamic
+ ...
+}
+
+
+# ==2037232== 1,840 bytes in 23 blocks are still reachable in loss record 1,008 of 1,018
+# ==2037232== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
+# ==2037232== by 0x490447A: g_malloc0 (gmem.c:163)
+# ==2037232== by 0x4881971: type_data_make_W (gtype.c:1141)
+# ==2037232== by 0x4881F8C: type_data_ref_Wm (gtype.c:1272)
+# ==2037232== by 0x4882ECF: g_type_class_ref (gtype.c:3034)
+# ==2037232== by 0x486CE03: g_object_new_with_properties (gobject.c:2370)
+# ==2037232== by 0x486D625: g_object_new (gobject.c:2037)
+# ==2037232== by 0x4AAACB8: g_plugin_module_new (plugin.c:512)
+# ==2037232== by 0x4AA9179: browse_directory_for_plugins (pglist.c:281)
+# ==2037232== by 0x4AA916B: browse_directory_for_plugins (pglist.c:277)
+# ==2037232== by 0x4AA916B: browse_directory_for_plugins (pglist.c:277)
+# ==2037232== by 0x4AA8CE2: init_all_plugins (pglist.c:91)
+# ==2037232== by 0x10AB0A: main (rost.c:372)
+# ==2037232==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:calloc
+ fun:g_malloc0
+ fun:type_data_make_W
+ fun:type_data_ref_Wm
+ fun:g_type_class_ref
+ fun:g_object_new_with_properties
+ fun:g_object_new
+ ...
+}
+
+
+# ==2038514== 104 bytes in 1 blocks are still reachable in loss record 845 of 1,018
+# ==2038514== at 0x485FAD8: freelist_alloc (gatomicarray.c:85)
+# ==2038514== by 0x485FB57: _g_atomic_array_copy (gatomicarray.c:141)
+# ==2038514== by 0x4881259: type_node_add_iface_entry_W (gtype.c:1429)
+# ==2038514== by 0x4882417: type_add_interface_Wm (gtype.c:1501)
+# ==2038514== by 0x4884B69: g_type_add_interface_static (gtype.c:2939)
+# ==2038514== by 0x4A7FA23: g_imm_operand_get_type_once (feeder.c:125)
+# ==2038514== by 0x4A7F93F: g_imm_operand_get_type (feeder.c:125)
+# ==2038514== by 0x4A8FEE1: register_arch_gtypes (processors.c:83)
+# ==2038514== by 0x4A8E4D4: load_all_core_components (core.c:122)
+# ==2038514== by 0x10AAF5: main (rost.c:369)
+# ==2038514==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:freelist_alloc
+ fun:_g_atomic_array_copy
+ fun:type_node_add_iface_entry_W
+ fun:type_add_interface_Wm
+ fun:g_type_add_interface_static
+ fun:*_get_type_once
+ ...
+}
+
+
+# ==2038565== 80 bytes in 1 blocks are still reachable in loss record 651 of 1,018
+# ==2038565== at 0x485FAD8: freelist_alloc (gatomicarray.c:85)
+# ==2038565== by 0x485FB57: _g_atomic_array_copy (gatomicarray.c:141)
+# ==2038565== by 0x4881259: type_node_add_iface_entry_W (gtype.c:1429)
+# ==2038565== by 0x4882417: type_add_interface_Wm (gtype.c:1501)
+# ==2038565== by 0x4884B69: g_type_add_interface_static (gtype.c:2939)
+# ==2038565== by 0x217225B5: ???
+# ==2038565== by 0x21722507: ???
+# ==2038565== by 0x2171E32A: ???
+# ==2038565== by 0x2171E360: ???
+# ==2038565== by 0x4AABC1C: g_plugin_module_load (plugin.c:1115)
+# ==2038565== by 0x4AA9635: load_remaning_plugins (pglist.c:478)
+# ==2038565== by 0x4AA8D81: init_all_plugins (pglist.c:108)
+# ==2038565== by 0x10AB0A: main (rost.c:372)
+# ==2038565==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:freelist_alloc
+ fun:_g_atomic_array_copy
+ fun:type_node_add_iface_entry_W
+ fun:type_add_interface_Wm
+ fun:g_type_add_interface_static
+ obj:*
+ obj:*
+ obj:*
+ obj:*
+ ...
+}
+
+
+######################################################
+
+
+# XML2
+
+# ==2031163== 104 bytes in 1 blocks are still reachable in loss record 874 of 1,018
+# ==2031163== at 0x48407B4: malloc (vg_replace_malloc.c:381)
+# ==2031163== by 0x4E5D79A: xmlNewRMutex (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.14)
+# ==2031163== by 0x4EC04AC: __xmlInitializeDict (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.14)
+# ==2031163== by 0x4EC053C: __xmlRandom (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.14)
+# ==2031163== by 0x4DFFBA5: xmlHashCreate (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.14)
+# ==2031163== by 0x4E495EF: xmlXPathNewContext (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.14)
+# ==2031163== by 0x4A8CAB0: create_new_xml_file (xml.c:70)
+# ==2031163== by 0x4AA0BFF: g_generic_config_write (configuration.c:1485)
+# ==2031163== by 0x4AA9EFA: g_plugin_module_dispose (plugin.c:173)
+# ==2031163== by 0x486BD35: g_object_unref (gobject.c:3867)
+# ==2031163== by 0x4AA94F0: on_plugin_ref_toggle (pglist.c:393)
+# ==2031163== by 0x486B946: toggle_refs_notify (gobject.c:3599)
+# ==2031163== by 0x486BCB7: g_object_unref (gobject.c:3806)
+# ==2031163== by 0x4AA8F23: exit_all_plugins (pglist.c:162)
+# ==2031163== by 0x10AE01: main (rost.c:476)
+# ==2031163==
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:xmlNewRMutex
+ fun:__xmlInitializeDict
+ fun:__xmlRandom
+ fun:xmlHashCreate
+ fun:xmlXPathNewContext
+ fun:create_new_xml_file
+ fun:g_generic_config_write
+ fun:g_plugin_module_dispose
+ fun:g_object_unref
+ fun:on_plugin_ref_toggle
+ fun:toggle_refs_notify
+ fun:g_object_unref
+ fun:exit_all_plugins
+ fun:main
+}
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:xmlNewRMutex
+ fun:__xmlInitializeDict
+ fun:__xmlRandom
+ fun:xmlHashCreate
+ fun:xmlXPathNewContext
+ fun:create_new_xml_file
+ fun:g_generic_config_write
+ fun:g_plugin_module_dispose
+ fun:g_object_unref
+ fun:on_plugin_ref_toggle
+ fun:exit_all_plugins
+ fun:main
+}
+
+
+# Python...
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:PyImport_Import
+ fun:create_python_plugin
+ fun:load_python_plugins
+ fun:chrysalide_plugin_on_plugins_loaded
+ fun:load_remaning_plugins
+ fun:init_all_plugins
+ fun:main
+}
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:PyImport_Import
+ fun:PyImport_ImportModule
+ fun:chrysalide_plugin_init
+ fun:g_plugin_module_load
+ fun:load_remaning_plugins
+ fun:init_all_plugins
+ fun:main
+}
diff --git a/tools/yara2rost/Makefile.am b/tools/yara2rost/Makefile.am
new file mode 100644
index 0000000..2830b03
--- /dev/null
+++ b/tools/yara2rost/Makefile.am
@@ -0,0 +1,36 @@
+
+BUILT_SOURCES = grammar.h
+
+
+# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS
+# afin de conserver des noms de fichiers simples, ie sans le nom de la
+# bibliothèque de sortie en préfixe.
+
+AM_YFLAGS = -v -d -p yara2rost_ -Wno-yacc #-Wcounterexamples
+
+AM_LFLAGS = -P yara2rost_ -o lex.yy.c --header-file=tokens.h \
+ -Dyyget_lineno=yara2rost_get_lineno \
+ -Dyy_scan_bytes=yara2rost__scan_bytes \
+ -Dyy_delete_buffer=yara2rost__delete_buffer
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS)
+
+
+bin_PROGRAMS = yara2rost
+
+.NOTPARALLEL: $(bin_PROGRAMS)
+
+yara2rost_SOURCES = \
+ decl.h \
+ enums.h \
+ tokens.l \
+ grammar.y \
+ yara2rost.c
+
+
+# Automake fait les choses à moitié
+CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
+
+# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions !
+# On rajoute également de quoi générer les Makefiles.
+EXTRA_DIST = tokens.h
diff --git a/tools/yara2rost/decl.h b/tools/yara2rost/decl.h
new file mode 100644
index 0000000..05d63d4
--- /dev/null
+++ b/tools/yara2rost/decl.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * decl.h - déclarations de prototypes utiles
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_YARA2ROST_DECL_H
+#define _TOOLS_YARA2ROST_DECL_H
+
+
+#include <stdbool.h>
+
+
+
+/* Parcourt des définitions de règles pour traduction. */
+bool process_rules_definitions(const char *, size_t);
+
+
+
+#endif /* _TOOLS_YARA2ROST_DECL_H */
diff --git a/tools/yara2rost/demo.yar b/tools/yara2rost/demo.yar
new file mode 100644
index 0000000..081973f
--- /dev/null
+++ b/tools/yara2rost/demo.yar
@@ -0,0 +1,27 @@
+
+include "demobis.yar"
+
+import "modname"
+
+
+private global rule Test : tag1 tag2 {
+
+ meta:
+ desc_0 = "abc"
+ desc_1 = 123
+ desc_2 = true
+ desc_3 = false
+ desc_z = ""
+
+ strings:
+ $text = "value"
+ $text_b = "value" wide ascii fullword private xor(0x12)
+ $re = /hash: [0-9a-fA-F]{32}/
+ $re_b = /hash: [0-9a-fA-F]{32}/ wide ascii nocase fullword private
+ $hex = { AA bb [2-4] 61 62 63 }
+ $hex_b = { AA bb [2-4] 61 62 63 } private
+
+ condition:
+ filesize == 123 and entrypoint == 456 and for all of ($text*) : ( @ > @hex_b ) and any of them
+
+}
diff --git a/tools/yara2rost/enums.h b/tools/yara2rost/enums.h
new file mode 100644
index 0000000..19fe49c
--- /dev/null
+++ b/tools/yara2rost/enums.h
@@ -0,0 +1,47 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enums.h - Reprise des fanions de la syntaxe YARA
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_YARA2ROST_ENUMS_H
+#define _TOOLS_YARA2ROST_ENUMS_H
+
+
+typedef enum _RuleFlags
+{
+ RULE_FLAGS_NONE = (0 << 0),
+ RULE_FLAGS_PRIVATE = (1 << 0),
+ RULE_FLAGS_GLOBAL = (1 << 1)
+
+} RuleFlags;
+
+typedef enum _StringExtraFlags
+{
+ STRING_FLAGS_NONE = (0 << 0),
+ STRING_FLAGS_NO_CASE = (1 << 0),
+ STRING_FLAGS_FULL_WORD = (1 << 1),
+ STRING_FLAGS_PRIVATE = (1 << 2)
+
+} StringExtraFlags;
+
+
+
+#endif /* _TOOLS_YARA2ROST_ENUMS_H */
diff --git a/tools/yara2rost/grammar.y b/tools/yara2rost/grammar.y
new file mode 100644
index 0000000..0d756b1
--- /dev/null
+++ b/tools/yara2rost/grammar.y
@@ -0,0 +1,1332 @@
+
+%{
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+
+#include "decl.h"
+#include "tokens.h"
+
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int yyerror(yyscan_t, const char *);
+
+/* Initialise une amorce de copie. */
+static void init_dump(sz_str_t *, const sz_cst_str_t *);
+
+#define init_dump_with_fixed(d, s) \
+ init_dump(d, (sz_cst_str_t []) { { .data = s, .len = sizeof(s) - 1 } })
+
+/* Complète une chaîne de caractères avec une autre. */
+static void add_to_dump(sz_str_t *, const sz_cst_str_t *);
+
+#define add_fixed_to_dump(d, s) \
+ add_to_dump(d, (sz_cst_str_t []) { { .data = s, .len = sizeof(s) - 1 } })
+
+#define add_dyn_to_dump(d, s) \
+ do \
+ { \
+ add_to_dump(d, (sz_cst_str_t *)s); \
+ free((s)->data); \
+ } \
+ while (0)
+
+/* Imprime une bribe de définition formant une règle ROST. */
+void dump_string(const char *, size_t);
+
+#define dump_fixed_string(s) \
+ dump_string(s, sizeof(s) - 1)
+
+
+%}
+
+
+%code requires {
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "enums.h"
+
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void *yyscan_t;
+
+
+typedef struct _sz_str_t
+{
+ char *data;
+ size_t len;
+
+} sz_str_t;
+
+typedef struct _sz_cst_str_t
+{
+ char *data;
+ size_t len;
+
+} sz_cst_str_t;
+
+}
+
+%union {
+
+ sz_str_t string; /* Chaîne de caractères #1 */
+ sz_cst_str_t cstring; /* Chaîne de caractères #2 */
+
+ RuleFlags rule_flags; /* Fanions pour règle */
+ StringExtraFlags string_flags; /* Fanions pour motif */
+
+}
+
+
+%expect 1
+
+%define api.pure full
+%define parse.error verbose
+
+%parse-param { yyscan_t yyscanner }
+%lex-param { yyscan_t yyscanner }
+
+
+%code provides {
+
+#define YY_DECL \
+ int yara2rost_lex(YYSTYPE *yylval_param, yyscan_t yyscanner)
+
+YY_DECL;
+
+}
+
+%token COLON ":"
+%token CURLY_BRACKET_O "{"
+%token CURLY_BRACKET_C "}"
+%token EQUAL "="
+%token PAREN_O "("
+%token PAREN_C ")"
+%token DOT_DOT ".."
+%token COMMA ","
+%token BRACKET_O "["
+%token BRACKET_C "]"
+%token PERCENT "%"
+%token DOT "."
+
+%token ADD_OP "+"
+%token SUB_OP "-"
+%token MUL_OP "*"
+%token DIV_OP "\\"
+%token EOR_OP "^"
+%token AND_OP "&"
+%token OR_OP "|"
+%token INV_OP "~"
+%token SHIFT_LEFT_OP "<<"
+%token SHIFT_RIGHT_OP ">>"
+
+%token LT "<"
+%token GT ">"
+%token LE "<="
+%token GE ">="
+%token EQ "=="
+%token NEQ "!="
+
+%token ALL "all"
+%token AND "and"
+%token ANY "any"
+%token ASCII "ascii"
+%token AT "at"
+%token BASE64 "base64"
+%token BASE64WIDE "base64wide"
+%token CONDITION "condition"
+%token CONTAINS "contains"
+%token DEFINED "defined"
+%token ENDSWITH "endswith"
+%token ENTRYPOINT "entrypoint"
+%token FILESIZE "filesize"
+%token FOR "for"
+%token FULLWORD "fullword"
+%token GLOBAL "global"
+%token ICONTAINS "icontains"
+%token IENDSWITH "iendswith"
+%token IEQUALS "iequals"
+%token IMPORT "import"
+%token IN "in"
+%token INCLUDE "include"
+%token ISTARTSWITH "istartswith"
+%token MATCHES "matches"
+%token META "meta"
+%token NOCASE "nocase"
+%token NONE "none"
+%token NOT "not"
+%token OF "of"
+%token OR "or"
+%token PRIVATE "private"
+%token RULE "rule"
+%token STARTSWITH "startswith"
+%token STRINGS "strings"
+%token THEM "them"
+%token WIDE "wide"
+%token XOR "xor"
+
+%token _FALSE "false"
+%token _TRUE "true"
+
+%token STRING_IDENTIFIER_WITH_WILDCARD
+%token STRING_IDENTIFIER
+%token STRING_COUNT
+%token STRING_OFFSET
+%token STRING_LENGTH
+%token INTEGER_FUNCTION
+%token IDENTIFIER
+%token NUMBER
+%token DOUBLE
+%token TEXT_STRING
+%token REGEXP
+%token HEX_STRING
+
+%type <cstring> STRING_IDENTIFIER_WITH_WILDCARD
+%type <cstring> STRING_IDENTIFIER
+%type <cstring> STRING_COUNT
+%type <cstring> STRING_OFFSET
+%type <cstring> STRING_LENGTH
+%type <cstring> INTEGER_FUNCTION
+%type <cstring> IDENTIFIER
+%type <cstring> NUMBER
+%type <cstring> DOUBLE
+%type <cstring> TEXT_STRING
+%type <cstring> REGEXP
+%type <cstring> HEX_STRING
+
+%type <rule_flags> rule_modifiers
+%type <rule_flags> rule_modifier
+
+%type <string_flags> string_modifiers
+%type <string_flags> string_modifier
+%type <string_flags> regexp_modifiers
+%type <string_flags> regexp_modifier
+%type <string_flags> hex_modifiers
+%type <string_flags> hex_modifier
+
+%type <string> boolean_expression
+%type <string> identifier
+%type <string> arguments
+%type <string> arguments_list
+%type <string> expression
+%type <string> for_iteration
+%type <string> for_variables
+%type <string> iterator
+%type <string> set
+%type <string> range
+%type <string> enumeration
+%type <string> string_iterator
+%type <string> string_set
+%type <string> string_enumeration
+%type <string> string_enumeration_item
+%type <string> rule_set
+%type <string> rule_enumeration
+%type <string> rule_enumeration_item
+%type <string> for_expression
+%type <string> for_quantifier
+%type <string> primary_expression
+%type <string> regexp
+
+%left OR
+%left AND
+%right NOT DEFINED
+%left EQ NEQ CONTAINS ICONTAINS STARTSWITH ENDSWITH ISTARTSWITH IENDSWITH IEQUALS MATCHES
+%left LT LE GT GE
+%left OR_OP
+%left EOR_OP
+%left AND_OP
+%left SHIFT_LEFT_OP SHIFT_RIGHT_OP
+%left ADD_OP SUB_OP
+%left MUL_OP DIV_OP PERCENT
+%right INV_OP UNARY_MINUS
+
+
+%%
+
+ rules : /* empty */
+ | rules include
+ | rules import
+ | rules rule
+ ;
+
+
+ include : "include" TEXT_STRING
+ {
+ dump_fixed_string("include ");
+ dump_string($2.data, $2.len);
+ dump_fixed_string("\n");
+ }
+ ;
+
+ import : "import" TEXT_STRING
+ {
+ dump_fixed_string("/* import ");
+ dump_string($2.data, $2.len);
+ dump_fixed_string(" */\n");
+ }
+ ;
+
+
+ rule : rule_modifiers "rule" IDENTIFIER
+ {
+ if ($1 != RULE_FLAGS_NONE)
+ {
+ if ($1 & RULE_FLAGS_PRIVATE)
+ {
+ dump_fixed_string("private");
+ dump_fixed_string(" ");
+ }
+
+ if ($1 & RULE_FLAGS_GLOBAL)
+ {
+ dump_fixed_string("global");
+ dump_fixed_string(" ");
+ }
+
+ }
+
+ dump_fixed_string("rule ");
+ dump_string($3.data, $3.len);
+
+ }
+ tags "{"
+ {
+ dump_fixed_string(" {\n");
+ }
+ meta strings condition "}"
+ {
+ dump_fixed_string("}\n");
+ }
+ ;
+
+
+ rule_modifiers : /* empty */
+ {
+ $$ = RULE_FLAGS_NONE;
+ }
+ | rule_modifiers rule_modifier
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+ rule_modifier : "private"
+ {
+ $$ = RULE_FLAGS_PRIVATE;
+ }
+ | "global"
+ {
+ $$ = RULE_FLAGS_GLOBAL;
+ }
+ ;
+
+
+ tags : /* empty */
+ | ":"
+ {
+ dump_fixed_string(" :");
+ }
+ tag_list
+ ;
+
+ tag_list : IDENTIFIER
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ }
+ | tag_list IDENTIFIER
+ {
+ dump_fixed_string(" ");
+ dump_string($2.data, $2.len);
+ }
+ ;
+
+
+/**
+ * Section "meta:"
+ */
+
+ meta : /* empty */
+ | "meta" ":"
+ {
+ dump_fixed_string("\n ");
+ dump_fixed_string("meta:\n");
+ }
+ meta_declarations
+ ;
+
+ meta_declarations : meta_declaration
+ {
+ dump_fixed_string("\n");
+ }
+ | meta_declarations meta_declaration
+ {
+ dump_fixed_string("\n");
+ }
+ ;
+
+ meta_declaration : IDENTIFIER "=" TEXT_STRING
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = ");
+ dump_string($3.data, $3.len);
+ }
+ | IDENTIFIER "=" NUMBER
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = ");
+ dump_string($3.data, $3.len);
+ }
+ | IDENTIFIER "=" "-" NUMBER
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = -");
+ dump_string($4.data, $4.len);
+ }
+ | IDENTIFIER "=" "true"
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = true");
+ }
+ | IDENTIFIER "=" "false"
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = false");
+ }
+ ;
+
+
+/**
+ * Section "strings:"
+ */
+
+ strings : /* empty */
+ | "strings" ":"
+ {
+ dump_fixed_string("\n ");
+ dump_fixed_string("bytes:\n");
+ }
+ string_declarations
+ ;
+
+ string_declarations : string_declaration
+ {
+ dump_fixed_string("\n");
+ }
+ | string_declarations string_declaration
+ {
+ dump_fixed_string("\n");
+ }
+ ;
+
+ string_declaration : STRING_IDENTIFIER "="
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = ");
+ }
+ TEXT_STRING
+ {
+ dump_string($4.data, $4.len);
+ }
+ string_modifiers
+ {
+ if ($6 & STRING_FLAGS_NO_CASE)
+ dump_fixed_string(" nocase");
+
+ if ($6 & STRING_FLAGS_FULL_WORD)
+ dump_fixed_string(" fullword");
+
+ if ($6 & STRING_FLAGS_PRIVATE)
+ dump_fixed_string(" private");
+
+ }
+ | STRING_IDENTIFIER "="
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = ");
+ }
+ REGEXP
+ {
+ dump_fixed_string("/");
+ dump_string($4.data, $4.len);
+ }
+ regexp_modifiers
+ {
+ if ($6 & STRING_FLAGS_NO_CASE)
+ dump_fixed_string(" nocase");
+
+ if ($6 & STRING_FLAGS_FULL_WORD)
+ dump_fixed_string(" fullword");
+
+ if ($6 & STRING_FLAGS_PRIVATE)
+ dump_fixed_string(" private");
+
+ }
+ | STRING_IDENTIFIER "="
+ {
+ dump_fixed_string(" ");
+ dump_string($1.data, $1.len);
+ dump_fixed_string(" = ");
+ }
+ HEX_STRING
+ {
+ dump_string($4.data, $4.len);
+ }
+ hex_modifiers
+ {
+ if ($6 & STRING_FLAGS_NO_CASE)
+ dump_fixed_string(" nocase");
+
+ if ($6 & STRING_FLAGS_FULL_WORD)
+ dump_fixed_string(" fullword");
+
+ if ($6 & STRING_FLAGS_PRIVATE)
+ dump_fixed_string(" private");
+
+ }
+ ;
+
+
+ string_modifiers : /* empty */
+ {
+ $$ = STRING_FLAGS_NONE;
+ }
+ | string_modifiers string_modifier
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+ string_modifier : "wide"
+ {
+ dump_fixed_string(" wide");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "ascii"
+ {
+ dump_fixed_string(" plain");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "nocase"
+ {
+ $$ = STRING_FLAGS_NO_CASE;
+ }
+ | "fullword"
+ {
+ $$ = STRING_FLAGS_FULL_WORD;
+ }
+ | "private"
+ {
+ $$ = STRING_FLAGS_PRIVATE;
+ }
+ | "xor"
+ {
+ dump_fixed_string(" xor");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "xor" "(" NUMBER ")"
+ {
+ dump_fixed_string(" xor(");
+ dump_string($3.data, $3.len);
+ dump_fixed_string(")");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "xor" "(" NUMBER "-" NUMBER ")"
+ {
+ dump_fixed_string(" xor(");
+ dump_string($3.data, $3.len);
+ dump_fixed_string("-");
+ dump_string($5.data, $5.len);
+ dump_fixed_string(")");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "base64"
+ {
+ dump_fixed_string(" base64");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "base64" "(" TEXT_STRING ")"
+ {
+ dump_fixed_string(" base64(");
+ dump_string($3.data, $3.len);
+ dump_fixed_string(")");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "base64wide"
+ {
+ dump_fixed_string(" (base64 | wide)");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "base64wide" "(" TEXT_STRING ")"
+ {
+ dump_fixed_string(" (base64(");
+ dump_string($3.data, $3.len);
+ dump_fixed_string(") | wide)");
+ $$ = STRING_FLAGS_NONE;
+ }
+ ;
+
+ regexp_modifiers : /* empty */
+ {
+ $$ = STRING_FLAGS_NONE;
+ }
+ | regexp_modifiers regexp_modifier
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+ regexp_modifier : "wide"
+ {
+ dump_fixed_string(" wide");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "ascii"
+ {
+ dump_fixed_string(" plain");
+ $$ = STRING_FLAGS_NONE;
+ }
+ | "nocase"
+ {
+ $$ = STRING_FLAGS_NO_CASE;
+ }
+ | "fullword"
+ {
+ $$ = STRING_FLAGS_FULL_WORD;
+ }
+ | "private"
+ {
+ $$ = STRING_FLAGS_PRIVATE;
+ }
+ ;
+
+ hex_modifiers : /* empty */
+ {
+ $$ = STRING_FLAGS_NONE;
+ }
+ | hex_modifiers hex_modifier
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+ hex_modifier : "private"
+ {
+ $$ = STRING_FLAGS_PRIVATE;
+ }
+ ;
+
+
+/**
+ * Section "condition:"
+ */
+
+ condition : "condition" ":" boolean_expression
+ {
+ dump_fixed_string("\n ");
+ dump_fixed_string("condition:\n");
+ dump_fixed_string(" ");
+ dump_string($3.data, $3.len);
+ free($3.data);
+ dump_fixed_string("\n\n");
+ }
+ ;
+
+ boolean_expression : expression { $$ = $1; }
+ ;
+
+ identifier : IDENTIFIER
+ {
+ init_dump(&$$, &$1);
+ }
+ | identifier "." IDENTIFIER
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, ".");
+ add_to_dump(&$$, &$3);
+ }
+ | identifier "[" primary_expression "]"
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, "[");
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, "]");
+ }
+ | identifier "(" arguments ")"
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, "(");
+ if ($3.len > 0)
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, ")");
+ }
+ ;
+
+
+ arguments : { $$.len = 0; /* empty */ }
+ | arguments_list { $$ = $1; }
+ ;
+
+
+ arguments_list : expression
+ {
+ $$ = $1;
+ }
+ | arguments_list "," expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, ", ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ ;
+
+
+ expression : "true"
+ {
+ init_dump_with_fixed(&$$, "true");
+ }
+ | "false"
+ {
+ init_dump_with_fixed(&$$, "false");
+ }
+ | primary_expression "matches" regexp
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " matches ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "contains" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " contains ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "icontains" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " icontains ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "startswith" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " startswith ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "istartswith" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " istartswith ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "endswith" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " endswith ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "iendswith" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " iendswith ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "iequals" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " iequals ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | STRING_IDENTIFIER
+ {
+ init_dump(&$$, &$1);
+ }
+ | STRING_IDENTIFIER "at" primary_expression
+ {
+ init_dump(&$$, &$1);
+ add_fixed_to_dump(&$$, " at ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | STRING_IDENTIFIER "in" range
+ {
+ init_dump(&$$, &$1);
+ add_fixed_to_dump(&$$, " in ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | "for" for_expression for_iteration ":" "(" boolean_expression ")"
+ {
+ init_dump_with_fixed(&$$, "for ");
+ add_dyn_to_dump(&$$, &$2);
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, " : (");
+ add_dyn_to_dump(&$$, &$6);
+ add_fixed_to_dump(&$$, ")");
+ }
+ | for_expression "of" string_set
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " of ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | for_expression "of" rule_set
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " of ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+
+ | primary_expression "%" "of" string_set
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, "% of ");
+ add_dyn_to_dump(&$$, &$4);
+ }
+ | primary_expression "%" "of" rule_set
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, "% of ");
+ add_dyn_to_dump(&$$, &$4);
+ }
+
+ | for_expression "of" string_set "in" range
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " of ");
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, " in ");
+ add_dyn_to_dump(&$$, &$5);
+ }
+ | for_expression "of" string_set "at" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " of ");
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, " at ");
+ add_dyn_to_dump(&$$, &$5);
+ }
+ | "not" boolean_expression
+ {
+ init_dump_with_fixed(&$$, "not ");
+ add_dyn_to_dump(&$$, &$2);
+ }
+ | "defined" boolean_expression
+ {
+ init_dump_with_fixed(&$$, "defined ");
+ add_dyn_to_dump(&$$, &$2);
+ }
+ | boolean_expression "and" boolean_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " and ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | boolean_expression "or" boolean_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " or ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "<" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " < ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression ">" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " > ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "<=" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " <= ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression ">=" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " >= ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "==" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " == ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "!=" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " != ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression
+ {
+ $$ = $1;
+ }
+ | "(" expression ")"
+ {
+ init_dump_with_fixed(&$$, "(");
+ add_dyn_to_dump(&$$, &$2);
+ add_fixed_to_dump(&$$, ")");
+ }
+ ;
+
+
+ for_iteration : for_variables "in" iterator
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " in ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | "of" string_iterator
+ {
+ init_dump_with_fixed(&$$, "of ");
+ add_dyn_to_dump(&$$, &$2);
+ }
+ ;
+
+ for_variables : IDENTIFIER
+ {
+ init_dump(&$$, &$1);
+ }
+ | for_variables "," IDENTIFIER
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, ", ");
+ add_to_dump(&$$, &$3);
+ }
+ ;
+
+
+ iterator : identifier { $$ = $1; }
+ | set { $$ = $1; }
+ ;
+
+
+ set : "(" enumeration ")"
+ {
+ init_dump_with_fixed(&$$, "(");
+ add_dyn_to_dump(&$$, &$2);
+ add_fixed_to_dump(&$$, ")");
+ }
+ | range { $$ = $1; }
+ ;
+
+
+ range : "(" primary_expression ".." primary_expression ")"
+ {
+ init_dump_with_fixed(&$$, "(");
+ add_dyn_to_dump(&$$, &$2);
+ add_fixed_to_dump(&$$, " .. ");
+ add_dyn_to_dump(&$$, &$4);
+ add_fixed_to_dump(&$$, ")");
+ }
+ ;
+
+
+ enumeration : primary_expression { $$ = $1; }
+ | enumeration "," primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, ", ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ ;
+
+
+ string_iterator : string_set { $$ = $1; }
+ ;
+
+ string_set : "(" string_enumeration ")"
+ {
+ init_dump_with_fixed(&$$, "(");
+ add_dyn_to_dump(&$$, &$2);
+ add_fixed_to_dump(&$$, ")");
+ }
+ | "them"
+ {
+ init_dump_with_fixed(&$$, "them");
+ }
+ ;
+
+ string_enumeration : string_enumeration_item
+ {
+ $$ = $1;
+ }
+ | string_enumeration "," string_enumeration_item
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, ", ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ ;
+
+string_enumeration_item : STRING_IDENTIFIER
+ {
+ init_dump(&$$, &$1);
+ }
+ | STRING_IDENTIFIER_WITH_WILDCARD
+ {
+ init_dump(&$$, &$1);
+ }
+ ;
+
+
+ rule_set : "(" rule_enumeration ")"
+ {
+ init_dump_with_fixed(&$$, "(");
+ add_dyn_to_dump(&$$, &$2);
+ add_fixed_to_dump(&$$, ")");
+ }
+ ;
+
+ rule_enumeration : rule_enumeration_item
+ {
+ $$ = $1;
+ }
+ | rule_enumeration "," rule_enumeration_item
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, ", ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ ;
+
+ rule_enumeration_item : IDENTIFIER
+ {
+ init_dump(&$$, &$1);
+ }
+ | IDENTIFIER "*"
+ {
+ init_dump(&$$, &$1);
+ add_fixed_to_dump(&$$, "*");
+ }
+ ;
+
+
+ for_expression : primary_expression { $$ = $1; }
+ | for_quantifier { $$ = $1; }
+ ;
+
+ for_quantifier : "all"
+ {
+ init_dump_with_fixed(&$$, "all");
+ }
+ | "any"
+ {
+ init_dump_with_fixed(&$$, "any");
+ }
+ | "none"
+ {
+ init_dump_with_fixed(&$$, "none");
+ }
+ ;
+
+
+ primary_expression : "(" primary_expression ")"
+ {
+ init_dump_with_fixed(&$$, "(");
+ add_dyn_to_dump(&$$, &$2);
+ add_fixed_to_dump(&$$, ")");
+ }
+ | "filesize"
+ {
+ init_dump_with_fixed(&$$, "datasize");
+ }
+ | "entrypoint"
+ {
+ init_dump_with_fixed(&$$, "/* entrypoint */ 0");
+ }
+ | INTEGER_FUNCTION "(" primary_expression ")"
+ {
+ init_dump(&$$, &$1);
+ add_fixed_to_dump(&$$, "(");
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, ")");
+ }
+ | NUMBER
+ {
+ init_dump(&$$, &$1);
+ }
+ | DOUBLE
+ {
+ init_dump(&$$, &$1);
+ }
+ | TEXT_STRING
+ {
+ init_dump(&$$, &$1);
+ }
+ | STRING_COUNT "in" range
+ {
+ init_dump(&$$, &$1);
+ add_fixed_to_dump(&$$, " in ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | STRING_COUNT
+ {
+ init_dump(&$$, &$1);
+ }
+ | STRING_OFFSET "[" primary_expression "]"
+ {
+ init_dump(&$$, &$1);
+ add_fixed_to_dump(&$$, "[");
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, "]");
+ }
+ | STRING_OFFSET
+ {
+ init_dump(&$$, &$1);
+ }
+ | STRING_LENGTH "[" primary_expression "]"
+ {
+ init_dump(&$$, &$1);
+ add_fixed_to_dump(&$$, "[");
+ add_dyn_to_dump(&$$, &$3);
+ add_fixed_to_dump(&$$, "]");
+ }
+ | STRING_LENGTH
+ {
+ init_dump(&$$, &$1);
+ }
+ | identifier
+ {
+ $$ = $1;
+ }
+ | "-" primary_expression %prec UNARY_MINUS
+ {
+ init_dump_with_fixed(&$$, "-");
+ add_dyn_to_dump(&$$, &$2);
+ }
+ | primary_expression "+" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " + ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "-" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " - ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "*" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " * ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "\\" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " \\ ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "%" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " % ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "^" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " ^ ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "&" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " & ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression "|" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " | ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | "~" primary_expression
+ {
+ init_dump_with_fixed(&$$, "~");
+ add_dyn_to_dump(&$$, &$2);
+ }
+ | primary_expression "<<" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " << ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | primary_expression ">>" primary_expression
+ {
+ $$ = $1;
+ add_fixed_to_dump(&$$, " >> ");
+ add_dyn_to_dump(&$$, &$3);
+ }
+ | regexp
+ ;
+
+
+ regexp : REGEXP
+ {
+ init_dump_with_fixed(&$$, "/");
+ add_to_dump(&$$, &$1);
+ }
+ ;
+
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : yyscanner = décodeur impliqué dans le processus. *
+* msg = message d'erreur. *
+* *
+* Description : Affiche un message d'erreur suite à l'analyse en échec. *
+* *
+* Retour : 0 *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int yyerror(yyscan_t yyscanner, const char *msg)
+{
+ printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dst = chaîne de caractères à créer. *
+* src = chaîne de caractères à ajouter. *
+* *
+* Description : Initialise une amorce de copie. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_dump(sz_str_t *dst, const sz_cst_str_t *src)
+{
+ dst->data = malloc((src->len + 1) * sizeof(char));
+ dst->len = src->len;
+
+ memcpy(dst->data, src->data, src->len);
+
+ dst->data[dst->len] = '\0';
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dst = chaîne de caractères à créer. *
+* src = chaîne de caractères à ajouter. *
+* *
+* Description : Complète une chaîne de caractères avec une autre. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void add_to_dump(sz_str_t *dst, const sz_cst_str_t *src)
+{
+ dst->data = realloc(dst->data, (dst->len + src->len + 1) * sizeof(char));
+
+ memcpy(&dst->data[dst->len], src->data, src->len);
+
+ dst->len += src->len;
+
+ dst->data[dst->len] = '\0';
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : string = texte à copier sur la sortie standard. *
+* length = longueur de ce texte. *
+* *
+* Description : Imprime une bribe de définition formant une règle ROST. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void dump_string(const char *string, size_t length)
+{
+ ssize_t ret; /* Bilan de l'appel */
+
+ ret = write(STDOUT_FILENO, string, length);
+
+ if (ret != length)
+ perror("write");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* *
+* Description : Parcourt des définitions de règles pour traduction. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool process_rules_definitions(const char *text, size_t length)
+{
+ bool result; /* Bilan à renvoyer */
+ yyscan_t lexstate; /* Gestion d'analyse lexicale */
+ YY_BUFFER_STATE state; /* Contexte d'analyse */
+ int status; /* Bilan d'une analyse */
+
+ result = false;
+
+ yara2rost_lex_init(&lexstate);
+
+ state = yara2rost__scan_bytes(text, length, lexstate);
+
+ status = yyparse(lexstate);
+
+ result = (status == EXIT_SUCCESS);
+
+ yy_delete_buffer(state, lexstate);
+
+ yara2rost_lex_destroy(lexstate);
+
+ return result;
+
+}
diff --git a/tools/yara2rost/tokens.l b/tools/yara2rost/tokens.l
new file mode 100644
index 0000000..34e61d0
--- /dev/null
+++ b/tools/yara2rost/tokens.l
@@ -0,0 +1,292 @@
+
+%top {
+
+#include "grammar.h"
+
+}
+
+
+%{
+
+#include "decl.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+
+#define PUSH_STATE(s) yy_push_state(s, yyscanner)
+#define POP_STATE yy_pop_state(yyscanner)
+
+%}
+
+
+%option bison-bridge reentrant
+%option stack
+%option nounput
+%option noinput
+%option noyywrap
+%option noyy_top_state
+%option yylineno
+%option never-interactive
+
+
+%x regexp
+%x comment
+
+
+str_not_escaped [^\"\\]
+str_escaped \\a|\\b|\\t|\\n|\\v|\\f|\\r|\\e|\\\"|\\\\|\\x{hbyte}
+str_mixed ({str_not_escaped}|{str_escaped})
+
+hbyte [0-9a-fA-F]{2}
+
+digit [0-9]
+letter [a-zA-Z]
+hexdigit [a-fA-F0-9]
+octdigit [0-7]
+
+
+%%
+
+
+":" { return COLON; }
+"{" { return CURLY_BRACKET_O; }
+"}" { return CURLY_BRACKET_C; }
+"=" { return EQUAL; }
+"(" { return PAREN_O; }
+")" { return PAREN_C; }
+".." { return DOT_DOT; }
+"," { return COMMA; }
+"[" { return BRACKET_O; }
+"]" { return BRACKET_C; }
+"%" { return PERCENT; }
+"." { return DOT; }
+
+"+" { return ADD_OP; }
+"-" { return SUB_OP; }
+"*" { return MUL_OP; }
+"\\" { return DIV_OP; }
+"^" { return EOR_OP; }
+"&" { return AND_OP; }
+"|" { return OR_OP; }
+"~" { return INV_OP; }
+"<<" { return SHIFT_LEFT_OP; }
+">>" { return SHIFT_RIGHT_OP; }
+
+"<" { return LT; }
+">" { return GT; }
+"<=" { return LE; }
+">=" { return GE; }
+"==" { return EQ; }
+"!=" { return NEQ; }
+
+"all" { return ALL; }
+"and" { return AND; }
+"any" { return ANY; }
+"ascii" { return ASCII; }
+"at" { return AT; }
+"base64" { return BASE64; }
+"base64wide" { return BASE64WIDE; }
+"condition" { return CONDITION; }
+"contains" { return CONTAINS; }
+"defined" { return DEFINED; }
+"endswith" { return ENDSWITH; }
+"entrypoint" { return ENTRYPOINT; }
+"filesize" { return FILESIZE; }
+"for" { return FOR; }
+"fullword" { return FULLWORD; }
+"global" { return GLOBAL; }
+"icontains" { return ICONTAINS; }
+"iendswith" { return IENDSWITH; }
+"iequals" { return IEQUALS; }
+"import" { return IMPORT; }
+"in" { return IN; }
+"include" { return INCLUDE; }
+"istartswith" { return ISTARTSWITH; }
+"matches" { return MATCHES; }
+"meta" { return META; }
+"nocase" { return NOCASE; }
+"none" { return NONE; }
+"not" { return NOT; }
+"of" { return OF; }
+"or" { return OR; }
+"private" { return PRIVATE; }
+"rule" { return RULE; }
+"startswith" { return STARTSWITH; }
+"strings" { return STRINGS; }
+"them" { return THEM; }
+"wide" { return WIDE; }
+"xor" { return XOR; }
+
+"false" { return _FALSE; }
+"true" { return _TRUE; }
+
+
+%{ /* Commentaires */ %}
+
+"/*" { PUSH_STATE(comment); }
+<comment>"*/" { POP_STATE; }
+<comment>(.|\n) { }
+
+"//"[^\n]* { }
+
+
+%{ /* Blocs de texte */ %}
+
+$({letter}|{digit}|_)*"*" {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return STRING_IDENTIFIER_WITH_WILDCARD;
+
+}
+
+$({letter}|{digit}|_)* {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return STRING_IDENTIFIER;
+
+}
+
+#({letter}|{digit}|_)* {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return STRING_COUNT;
+
+}
+
+@({letter}|{digit}|_)* {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return STRING_OFFSET;
+
+}
+
+!({letter}|{digit}|_)* {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return STRING_LENGTH;
+
+}
+
+u?int(8|16|32)(be)? {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return INTEGER_FUNCTION;
+
+}
+
+({letter}|_)({letter}|{digit}|_)* {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return IDENTIFIER;
+
+}
+
+{digit}+(MB|KB){0,1} {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return NUMBER;
+
+}
+
+{digit}+"."{digit}+ {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return DOUBLE;
+
+}
+
+0x{hexdigit}+ {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return NUMBER;
+
+}
+
+0o{octdigit}+ {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return NUMBER;
+
+}
+
+\"{str_mixed}*\" {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return TEXT_STRING;
+
+}
+
+"/" {
+
+ PUSH_STATE(regexp);
+
+}
+
+<regexp>(\\\/|\\.|[^/\n\\])+\/i?s? {
+
+ POP_STATE;
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return REGEXP;
+
+}
+
+\{(({hexdigit}|[ \-|\~\?\[\]\(\)\n\r\t]|\/\*(\/|\**[^*/])*\*+\/)+|\/\/.*\n)+\} {
+
+ yylval->cstring.data = yytext;
+ yylval->cstring.len = yyleng;
+
+ return HEX_STRING;
+
+}
+
+
+%{ /* Actions par défaut */ %}
+
+<*>[ \t\r]+ { }
+
+<*>[\n]+ { }
+
+<*>. {
+ char *msg;
+ int ret;
+ ret = asprintf(&msg, "Unhandled token in rule definition: '%s '", yytext);
+ if (ret == -1)
+ YY_FATAL_ERROR("Unhandled token in undisclosed rule definition");
+ else
+ {
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+ }
+
+
+%%
diff --git a/tools/yara2rost/yara2rost.c b/tools/yara2rost/yara2rost.c
new file mode 100644
index 0000000..3206309
--- /dev/null
+++ b/tools/yara2rost/yara2rost.c
@@ -0,0 +1,295 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * yara2rost.c - traduction de règles YARA en règles ROST
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+#include "decl.h"
+
+
+
+/* Affiche des indications sur l'utilisation du programme. */
+static void show_usage(const char *);
+
+/* Récupère un contenu à traiter depuis l'entrée standard. */
+static void *get_input_data_from_stdin(size_t *);
+
+/* Récupère un contenu à traiter depuis un fichier externe. */
+static void *get_input_data_from_file(const char *, size_t *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : argv0 = nombre du programme exécuté. *
+* *
+* Description : Affiche des indications sur l'utilisation du programme. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void show_usage(const char *argv0)
+{
+ printf("\n");
+
+ printf("Usage: %s [options] [<YARA file>]\n", argv0);
+
+ printf("\n");
+
+ printf("General options:\n");
+
+ printf("\n");
+
+ printf("\t-h | --help\t\tDisplay this messsage.\n");
+
+ printf("\n");
+
+ printf("If no YARA file is provided as argument, a rule definition is expected from the standard input.\n");
+
+ printf("\n");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : length = taille de l'espace mémoire mis en place. [OUT] *
+* *
+* Description : Récupère un contenu à traiter depuis l'entrée standard. *
+* *
+* Retour : Adresse valide ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *get_input_data_from_stdin(size_t *length)
+{
+ char *result; /* Espace mémoire à retourner */
+ ssize_t got; /* Quantité d'octets lus */
+
+ result = NULL;
+ *length = 0;
+
+#define ALLOC_SIZE 2048
+
+ while (true)
+ {
+ result = realloc(result, (*length + ALLOC_SIZE) * sizeof(char));
+
+ got = read(STDIN_FILENO, result + *length, ALLOC_SIZE);
+
+ if (got == -1)
+ {
+ perror("read");
+ goto exit_with_error;
+ }
+
+ *length += got;
+
+ if (got < ALLOC_SIZE)
+ break;
+
+ }
+
+ return result;
+
+ exit_with_error:
+
+ free(result);
+
+ *length = 0;
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : filename = chemin du fichier à charger en mémoire. *
+* length = taille de l'espace mémoire mis en place. [OUT] *
+* *
+* Description : Récupère un contenu à traiter depuis un fichier externe. *
+* *
+* Retour : Adresse valide ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *get_input_data_from_file(const char *filename, size_t *length)
+{
+ char *result; /* Espace mémoire à retourner */
+ int fd; /* Descripteur du fichier */
+ struct stat info; /* Informations sur le fichier */
+ int ret; /* Bilan d'un appel */
+ ssize_t got; /* Quantité d'octets lus */
+
+ result = NULL;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ {
+ perror("open");
+ goto exit;
+ }
+
+ ret = fstat(fd, &info);
+ if (ret == -1)
+ {
+ perror("fstat");
+ goto exit_with_fd;
+ }
+
+ *length = info.st_size;
+
+ result = malloc(*length * sizeof(char));
+
+ got = read(fd, result, *length);
+
+ if (got == -1 || got != *length)
+ {
+ perror("read");
+
+ free(result);
+
+ result = NULL;
+ *length = 0;
+
+ }
+
+ exit_with_fd:
+
+ close(fd);
+
+ exit:
+
+ return result;
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : argc = nombre d'arguments dans la ligne de commande. *
+* argv = arguments de la ligne de commande. *
+* *
+* Description : Point d'entrée du programme. *
+* *
+* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int main(int argc, char **argv)
+{
+ int result; /* Bilan à retourner */
+ bool need_help; /* Affichage de l'aide ? */
+ int index; /* Indice d'argument à traiter */
+ int ret; /* Bilan d'une lecture d'arg. */
+ const char *source; /* Source de définitions */
+ void *content; /* Contenu à traduire */
+ size_t length; /* Taille de ce contenu */
+
+ static struct option long_options[] = {
+
+ { "help", no_argument, NULL, 'h' },
+
+ { NULL, 0, NULL, 0 }
+
+ };
+
+ /* Récupération des commandes */
+
+ need_help = false;
+
+ while (true)
+ {
+ ret = getopt_long(argc, argv, "h", long_options, &index);
+ if (ret == -1) break;
+
+ switch (ret)
+ {
+ case 'h':
+ need_help = true;
+ break;
+
+ }
+
+ }
+
+ /* Vérifications supplémentaires */
+
+ if (need_help || (optind != argc && (optind + 1) != argc))
+ {
+ show_usage(argv[0]);
+ result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE);
+ goto exit;
+ }
+
+ /* Execution attendue */
+
+ result = EXIT_FAILURE;
+
+ if (optind == argc)
+ content = get_input_data_from_stdin(&length);
+
+ else
+ {
+ source = argv[optind];
+
+ if (strcmp(source, "-") == 0 || strcmp(source, "/dev/stdin") == 0)
+ content = get_input_data_from_stdin(&length);
+ else
+ content = get_input_data_from_file(source, &length);
+
+ }
+
+ if (content != NULL)
+ {
+ if (process_rules_definitions(content, length))
+ result = EXIT_SUCCESS;
+
+ free(content);
+
+ }
+
+ exit:
+
+ return result;
+
+}