summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--configure.ac63
-rw-r--r--data/images/locked-symbolic.svg62
-rw-r--r--data/images/nolock-symbolic.svg70
-rw-r--r--data/images/unlocked-symbolic.svg62
-rw-r--r--gitrev.m42
-rw-r--r--pixmaps/Makefile.am18
-rw-r--r--pixmaps/chrysalide-full.pngbin28830 -> 0 bytes
-rw-r--r--pixmaps/chrysalide_text.pngbin11432 -> 0 bytes
-rw-r--r--pixmaps/revision.pngbin601 -> 0 bytes
-rw-r--r--pixmaps/revision_0.pngbin760 -> 0 bytes
-rw-r--r--pixmaps/revision_1.pngbin545 -> 0 bytes
-rw-r--r--pixmaps/revision_2.pngbin727 -> 0 bytes
-rw-r--r--pixmaps/revision_3.pngbin719 -> 0 bytes
-rw-r--r--pixmaps/revision_4.pngbin691 -> 0 bytes
-rw-r--r--pixmaps/revision_5.pngbin746 -> 0 bytes
-rw-r--r--pixmaps/revision_6.pngbin775 -> 0 bytes
-rw-r--r--pixmaps/revision_7.pngbin585 -> 0 bytes
-rw-r--r--pixmaps/revision_8.pngbin802 -> 0 bytes
-rw-r--r--pixmaps/revision_9.pngbin791 -> 0 bytes
-rw-r--r--plugins/Makefile.am3
-rw-r--r--plugins/pe/core.c21
-rw-r--r--plugins/pychrysalide/Makefile.am18
-rw-r--r--plugins/pychrysalide/arch/Makefile.am32
-rw-r--r--plugins/pychrysalide/arch/constants.c5
-rw-r--r--plugins/pychrysalide/arch/constants.h5
-rw-r--r--plugins/pychrysalide/arch/instruction.c866
-rw-r--r--plugins/pychrysalide/arch/instructions/Makefile.am3
-rw-r--r--plugins/pychrysalide/arch/instructions/constants.c58
-rw-r--r--plugins/pychrysalide/arch/instructions/constants.h5
-rw-r--r--plugins/pychrysalide/arch/instructions/raw.c142
-rw-r--r--plugins/pychrysalide/arch/instructions/undefined.c145
-rw-r--r--plugins/pychrysalide/arch/instructions/undefined.h4
-rw-r--r--plugins/pychrysalide/arch/module-ui.c66
-rw-r--r--plugins/pychrysalide/arch/module-ui.h38
-rw-r--r--plugins/pychrysalide/arch/module.c14
-rw-r--r--plugins/pychrysalide/arch/operand-ui.c461
-rw-r--r--plugins/pychrysalide/arch/operand-ui.h45
-rw-r--r--plugins/pychrysalide/arch/operand.c480
-rw-r--r--plugins/pychrysalide/arch/operand.h5
-rw-r--r--plugins/pychrysalide/arch/operands/Makefile.am16
-rw-r--r--plugins/pychrysalide/arch/operands/constants.c19
-rw-r--r--plugins/pychrysalide/arch/operands/constants.h7
-rw-r--r--plugins/pychrysalide/arch/operands/immediate.c384
-rw-r--r--plugins/pychrysalide/arch/operands/immediate.h10
-rw-r--r--plugins/pychrysalide/arch/operands/known.c125
-rw-r--r--plugins/pychrysalide/arch/operands/known.h10
-rw-r--r--plugins/pychrysalide/arch/operands/module.c16
-rw-r--r--plugins/pychrysalide/arch/operands/register.c196
-rw-r--r--plugins/pychrysalide/arch/register.c361
-rw-r--r--plugins/pychrysalide/bindings.c511
-rw-r--r--plugins/pychrysalide/bindings.h25
-rw-r--r--plugins/pychrysalide/common/Makefile.am2
-rw-r--r--plugins/pychrysalide/common/leb128.c139
-rw-r--r--plugins/pychrysalide/common/module.c4
-rw-r--r--plugins/pychrysalide/constants.h3
-rw-r--r--plugins/pychrysalide/convert.c120
-rw-r--r--plugins/pychrysalide/convert.h41
-rw-r--r--plugins/pychrysalide/core-ui.c225
-rw-r--r--plugins/pychrysalide/core.c236
-rw-r--r--plugins/pychrysalide/glibext/Makefile.am25
-rw-r--r--plugins/pychrysalide/glibext/bufferline.c109
-rw-r--r--plugins/pychrysalide/glibext/comparable.c482
-rw-r--r--plugins/pychrysalide/glibext/comparable.h45
-rw-r--r--plugins/pychrysalide/glibext/constants-ui.c131
-rw-r--r--plugins/pychrysalide/glibext/constants-ui.h41
-rw-r--r--plugins/pychrysalide/glibext/constants.c100
-rw-r--r--plugins/pychrysalide/glibext/constants.h6
-rw-r--r--plugins/pychrysalide/glibext/generator.c (renamed from plugins/pychrysalide/glibext/linegen.c)584
-rw-r--r--plugins/pychrysalide/glibext/generator.h (renamed from plugins/pychrysalide/glibext/linegen.h)18
-rw-r--r--plugins/pychrysalide/glibext/hashable.c (renamed from plugins/pychrysalide/glibext/comparison.c)251
-rw-r--r--plugins/pychrysalide/glibext/hashable.h (renamed from plugins/pychrysalide/glibext/comparison.h)20
-rw-r--r--plugins/pychrysalide/glibext/module-ui.c62
-rw-r--r--plugins/pychrysalide/glibext/module-ui.h38
-rw-r--r--plugins/pychrysalide/glibext/module.c12
-rw-r--r--plugins/pychrysalide/glibext/objhole.c102
-rw-r--r--plugins/pychrysalide/glibext/secstorage.c625
-rw-r--r--plugins/pychrysalide/glibext/secstorage.h45
-rw-r--r--plugins/pychrysalide/glibext/serialize.c (renamed from plugins/pychrysalide/analysis/storage/serialize.c)141
-rw-r--r--plugins/pychrysalide/glibext/serialize.h (renamed from plugins/pychrysalide/analysis/storage/serialize.h)12
-rw-r--r--plugins/pychrysalide/glibext/singleton.c342
-rw-r--r--plugins/pychrysalide/glibext/storage.c (renamed from plugins/pychrysalide/analysis/storage/storage.c)225
-rw-r--r--plugins/pychrysalide/glibext/storage.h (renamed from plugins/pychrysalide/analysis/storage/storage.h)12
-rw-r--r--plugins/pychrysalide/glibext/strbuilder.c199
-rw-r--r--plugins/pychrysalide/glibext/strbuilder.h2
-rw-r--r--plugins/pychrysalide/glibext/tpmem.c (renamed from plugins/pychrysalide/analysis/storage/tpmem.c)0
-rw-r--r--plugins/pychrysalide/glibext/tpmem.h (renamed from plugins/pychrysalide/analysis/storage/tpmem.h)0
-rw-r--r--plugins/pychrysalide/glibext/workqueue.c6
-rw-r--r--plugins/pychrysalide/gtkext/Makefile.am30
-rw-r--r--plugins/pychrysalide/gtkext/module.c34
-rw-r--r--plugins/pychrysalide/gtkext/panel.c130
-rw-r--r--plugins/pychrysalide/gtkext/panel.h42
-rw-r--r--plugins/pychrysalide/helpers-ui.c141
-rw-r--r--plugins/pychrysalide/helpers-ui.h44
-rw-r--r--plugins/pychrysalide/helpers.c175
-rw-r--r--plugins/pychrysalide/helpers.h67
-rw-r--r--plugins/pynb/Makefile.am77
-rw-r--r--plugins/pynb/core-ui-int.h56
-rw-r--r--plugins/pynb/core-ui.c363
-rw-r--r--plugins/pynb/core-ui.h43
-rw-r--r--plugins/pynb/data/images/pynb-symbolic.svg144
-rw-r--r--plugins/pynb/gresource.xml11
-rw-r--r--plugins/pynb/panel-int.h56
-rw-r--r--plugins/pynb/panel.c210
-rw-r--r--plugins/pynb/panel.h47
-rw-r--r--plugins/pynb/panel.ui21
-rw-r--r--plugins/pynb/params-int.h50
-rw-r--r--plugins/pynb/params.c171
-rw-r--r--plugins/pynb/params.h41
-rw-r--r--plugins/pynb/params.ui52
-rw-r--r--plugins/pynb/prefs-int.h48
-rw-r--r--plugins/pynb/prefs.c143
-rw-r--r--plugins/pynb/prefs.h41
-rw-r--r--plugins/pynb/prefs.ui38
-rw-r--r--src/Makefile.am18
-rw-r--r--src/analysis/contents/encapsulated.c2
-rw-r--r--src/analysis/contents/file.c2
-rw-r--r--src/analysis/contents/memory.c2
-rw-r--r--src/analysis/contents/restricted.c2
-rw-r--r--src/analysis/scan/patterns/backends/Makefile.am8
-rw-r--r--src/analysis/storage/Makefile.am7
-rw-r--r--src/analysis/storage/serialize.h64
-rw-r--r--src/analysis/storage/tpmem.h70
-rw-r--r--src/app.c28
-rw-r--r--src/arch/Makefile.am52
-rw-r--r--src/arch/instruction-int.h126
-rw-r--r--src/arch/instruction-ui-int.h55
-rw-r--r--src/arch/instruction-ui.c254
-rw-r--r--src/arch/instruction-ui.h41
-rw-r--r--src/arch/instruction.c1935
-rw-r--r--src/arch/instruction.h316
-rw-r--r--src/arch/instructions/Makefile.am11
-rw-r--r--src/arch/instructions/raw-int.h56
-rw-r--r--src/arch/instructions/raw-ui.c261
-rw-r--r--src/arch/instructions/raw-ui.h37
-rw-r--r--src/arch/instructions/raw.c696
-rw-r--r--src/arch/instructions/raw.h41
-rw-r--r--src/arch/instructions/undefined-int.h52
-rw-r--r--src/arch/instructions/undefined-ui.c102
-rw-r--r--src/arch/instructions/undefined-ui.h37
-rw-r--r--src/arch/instructions/undefined.c383
-rw-r--r--src/arch/instructions/undefined.h28
-rw-r--r--src/arch/operand-int.h93
-rw-r--r--src/arch/operand-ui-int.h52
-rw-r--r--src/arch/operand-ui.c111
-rw-r--r--src/arch/operand-ui.h54
-rw-r--r--src/arch/operand.c653
-rw-r--r--src/arch/operand.h64
-rw-r--r--src/arch/operands/Makefile.am38
-rw-r--r--src/arch/operands/immediate-int.h66
-rw-r--r--src/arch/operands/immediate-ui.c184
-rw-r--r--src/arch/operands/immediate-ui.h37
-rw-r--r--src/arch/operands/immediate.c1320
-rw-r--r--src/arch/operands/immediate.h86
-rw-r--r--src/arch/operands/known-int.h55
-rw-r--r--src/arch/operands/known-ui.c79
-rw-r--r--src/arch/operands/known-ui.h37
-rw-r--r--src/arch/operands/known.c433
-rw-r--r--src/arch/operands/known.h26
-rw-r--r--src/arch/operands/register-int.h6
-rw-r--r--src/arch/operands/register-ui.c93
-rw-r--r--src/arch/operands/register-ui.h37
-rw-r--r--src/arch/operands/register.c371
-rw-r--r--src/arch/register-int.h24
-rw-r--r--src/arch/register.c225
-rw-r--r--src/arch/register.h33
-rw-r--r--src/arch/vmpa.h29
-rw-r--r--src/common/Makefile.am1
-rw-r--r--src/common/bits.c1
-rw-r--r--src/common/cpp.h9
-rw-r--r--src/common/datatypes.h4
-rw-r--r--src/common/leb128.c171
-rw-r--r--src/common/leb128.h11
-rw-r--r--src/common/pathname.c23
-rw-r--r--src/common/pathname.h2
-rw-r--r--src/common/sort.h3
-rw-r--r--src/common/szbin.h141
-rw-r--r--src/core/Makefile.am5
-rw-r--r--src/core/core.c25
-rw-r--r--src/core/core.h9
-rw-r--r--src/core/global.c46
-rw-r--r--src/core/global.h7
-rw-r--r--src/core/logs.h9
-rw-r--r--src/core/processors.c23
-rw-r--r--src/core/processors.h6
-rw-r--r--src/data/Makefile.am2
-rw-r--r--src/data/images/Makefile.am33
-rw-r--r--src/data/images/dock-station-bottom-symbolic.svg197
-rw-r--r--src/data/images/dock-station-left-symbolic.svg51
-rw-r--r--src/data/images/dock-station-right-symbolic.svg76
-rw-r--r--src/data/images/gresource.xml12
-rw-r--r--src/data/images/logs-symbolic.svg93
-rw-r--r--src/glibext/Makefile.am20
-rw-r--r--src/glibext/bufferline.c334
-rw-r--r--src/glibext/bufferline.h14
-rw-r--r--src/glibext/comparable-int.h47
-rw-r--r--src/glibext/comparable.c124
-rw-r--r--src/glibext/comparable.h46
-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/hashable-int.h47
-rw-r--r--src/glibext/hashable.c82
-rw-r--r--src/glibext/hashable.h42
-rw-r--r--src/glibext/helpers.h28
-rw-r--r--src/glibext/log-int.h58
-rw-r--r--src/glibext/log.c306
-rw-r--r--src/glibext/log.h43
-rw-r--r--src/glibext/objhole-int.h33
-rw-r--r--src/glibext/objhole.c85
-rw-r--r--src/glibext/objhole.h16
-rw-r--r--src/glibext/options/Makefile.am3
-rw-r--r--src/glibext/options/asm.h65
-rw-r--r--src/glibext/secstorage-int.h60
-rw-r--r--src/glibext/secstorage.c950
-rw-r--r--src/glibext/secstorage.h74
-rw-r--r--src/glibext/serialize-int.h (renamed from src/analysis/storage/serialize-int.h)18
-rw-r--r--src/glibext/serialize.c (renamed from src/analysis/storage/serialize.c)28
-rw-r--r--src/glibext/serialize.h52
-rw-r--r--src/glibext/sigredir.c (renamed from src/glibext/signal.c)159
-rw-r--r--src/glibext/sigredir.h (renamed from src/glibext/_signal.h)21
-rw-r--r--src/glibext/singleton-int.h17
-rw-r--r--src/glibext/singleton.c179
-rw-r--r--src/glibext/singleton.h14
-rw-r--r--src/glibext/storage-int.h (renamed from src/analysis/storage/storage-int.h)23
-rw-r--r--src/glibext/storage.c (renamed from src/analysis/storage/storage.c)994
-rw-r--r--src/glibext/storage.h (renamed from src/analysis/storage/storage.h)70
-rw-r--r--src/glibext/strbuilder-int.h2
-rw-r--r--src/glibext/strbuilder.c9
-rw-r--r--src/glibext/strbuilder.h2
-rw-r--r--src/glibext/tpmem-int.h78
-rw-r--r--src/glibext/tpmem.c (renamed from src/analysis/storage/tpmem.c)224
-rw-r--r--src/glibext/tpmem.h57
-rw-r--r--src/glibext/widthtracker.c8
-rw-r--r--src/gtkext/Makefile.am22
-rw-r--r--src/gtkext/area.c2
-rw-r--r--src/gtkext/bindings/Makefile.am42
-rw-r--r--src/gtkext/bindings/generated-enums.c.template41
-rw-r--r--src/gtkext/bindings/generated-enums.h.template23
-rw-r--r--src/gtkext/bufferview.c6
-rw-r--r--src/gtkext/dockstation-int.h18
-rw-r--r--src/gtkext/dockstation.c472
-rw-r--r--src/gtkext/dockstation.h11
-rw-r--r--src/gtkext/dockstation.ui80
-rw-r--r--src/gtkext/gresource.xml9
-rw-r--r--src/gtkext/grid-int.h42
-rw-r--r--src/gtkext/grid.c1310
-rw-r--r--src/gtkext/grid.h46
-rw-r--r--src/gtkext/grid.ui217
-rw-r--r--src/gtkext/hexview.c293
-rw-r--r--src/gtkext/hexview.h6
-rw-r--r--src/gtkext/hexview.ui52
-rw-r--r--src/gtkext/launcher-int.h56
-rw-r--r--src/gtkext/launcher.c211
-rw-r--r--src/gtkext/launcher.h45
-rw-r--r--src/gtkext/launcher.ui76
-rw-r--r--src/gtkext/panel-int.h10
-rw-r--r--src/gtkext/panel.c57
-rw-r--r--src/gtkext/panel.h7
-rw-r--r--src/gtkext/statusstack-int.h12
-rw-r--r--src/gtkext/statusstack.c310
-rw-r--r--src/gtkext/statusstack.h10
-rw-r--r--src/gtkext/statusstack.ui29
-rw-r--r--src/gtkext/tweak-int.h65
-rw-r--r--src/gtkext/tweak.c319
-rw-r--r--src/gtkext/tweak.h90
-rw-r--r--src/gtkext/tweak.ui46
-rw-r--r--src/gui/Makefile.am2
-rw-r--r--src/gui/core/core.c6
-rw-r--r--src/gui/core/logs.c32
-rw-r--r--src/gui/core/panels.c342
-rw-r--r--src/gui/core/panels.h58
-rw-r--r--src/gui/dialogs/Makefile.am24
-rw-r--r--src/gui/dialogs/about-int.h18
-rw-r--r--src/gui/dialogs/about.c61
-rw-r--r--src/gui/dialogs/about.css9
-rw-r--r--src/gui/dialogs/about.ui82
-rw-r--r--src/gui/dialogs/gresource.xml24
-rw-r--r--src/gui/dialogs/preferences-int.h62
-rw-r--r--src/gui/dialogs/preferences.c424
-rw-r--r--src/gui/dialogs/preferences.h16
-rw-r--r--src/gui/dialogs/preferences.ui247
-rw-r--r--src/gui/dialogs/prefs/Makefile.am34
-rw-r--r--src/gui/dialogs/prefs/appearance-int.h64
-rw-r--r--src/gui/dialogs/prefs/appearance.c251
-rw-r--r--src/gui/dialogs/prefs/appearance.h41
-rw-r--r--src/gui/dialogs/prefs/appearance.ui184
-rw-r--r--src/gui/dialogs/prefs/gresource.xml7
-rw-r--r--src/gui/dialogs/prefs/security-int.h64
-rw-r--r--src/gui/dialogs/prefs/security.c400
-rw-r--r--src/gui/dialogs/prefs/security.h41
-rw-r--r--src/gui/dialogs/prefs/security.ui170
-rw-r--r--src/gui/panel-int.h71
-rw-r--r--src/gui/panel.c1207
-rw-r--r--src/gui/panel.h148
-rw-r--r--src/gui/panels/Makefile.am12
-rw-r--r--src/gui/panels/binary-int.h23
-rw-r--r--src/gui/panels/binary-launch.ui65
-rw-r--r--src/gui/panels/binary-params-int.h50
-rw-r--r--src/gui/panels/binary-params.c178
-rw-r--r--src/gui/panels/binary-params.h41
-rw-r--r--src/gui/panels/binary-params.ui (renamed from src/gui/panels/binary-props.ui)11
-rw-r--r--src/gui/panels/binary.c346
-rw-r--r--src/gui/panels/binary.h17
-rw-r--r--src/gui/panels/gresource.xml6
-rw-r--r--src/gui/panels/log.c451
-rw-r--r--src/gui/panels/log.h67
-rw-r--r--src/gui/panels/log.ui59
-rw-r--r--src/gui/panels/logs-col-icon.ui17
-rw-r--r--src/gui/panels/logs-col-message.ui19
-rw-r--r--src/gui/panels/logs-int.h53
-rw-r--r--src/gui/panels/logs.c227
-rw-r--r--src/gui/panels/logs.h47
-rw-r--r--src/gui/panels/logs.ui58
-rw-r--r--src/gui/panels/welcome-int.h28
-rw-r--r--src/gui/panels/welcome.c379
-rw-r--r--src/gui/panels/welcome.h21
-rw-r--r--src/gui/style.css27
-rw-r--r--src/gui/window-int.h5
-rw-r--r--src/gui/window.c317
-rw-r--r--src/gui/window.h8
-rw-r--r--src/gui/window.ui21
-rw-r--r--src/plugins/Makefile.am4
-rw-r--r--src/plugins/manager-int.h10
-rw-r--r--src/plugins/native-int.h13
-rw-r--r--src/plugins/native.c29
-rw-r--r--src/plugins/native.h7
-rw-r--r--src/plugins/pglist.c172
-rw-r--r--src/plugins/pglist.h69
-rw-r--r--src/plugins/plugin.c39
-rw-r--r--src/plugins/tweakable-int.h50
-rw-r--r--src/plugins/tweakable.c98
-rw-r--r--src/plugins/tweakable.h62
-rw-r--r--src/rost.c10
-rw-r--r--src/schemas/re.chrysalide.framework.gschema.xml117
-rw-r--r--system/magic/storage40
-rw-r--r--tests/analysis/storage/storage.py81
-rw-r--r--tests/arch/instruction.py52
-rw-r--r--tests/arch/operand.py72
-rw-r--r--tests/arch/operands/immediate.py76
-rw-r--r--tests/common/leb128.py80
-rw-r--r--tests/constval.py44
-rw-r--r--tests/glibext/comparable.py132
-rw-r--r--tests/glibext/configuration.py106
-rw-r--r--tests/glibext/hashable.py190
-rw-r--r--tests/glibext/re.chrysalide.tests.secstorage.gschema.xml15
-rw-r--r--tests/glibext/secstorage.py153
-rw-r--r--tests/glibext/singleton.py166
-rw-r--r--tests/glibext/storage.py74
-rw-r--r--tests/glibext/strbuilder.py82
-rw-r--r--tools/about/build.py120
-rw-r--r--tools/about/courier-10-pitch-bold_EQ97V.zipbin0 -> 21114 bytes
-rw-r--r--tools/about/courier10point.zipbin0 -> 61784 bytes
-rwxr-xr-xtools/about/gen.sh52
-rw-r--r--tools/about/logo.pngbin0 -> 633982 bytes
-rw-r--r--tools/about/noise.pngbin0 -> 136944 bytes
-rw-r--r--tools/about/ttf.py111
357 files changed, 24990 insertions, 13693 deletions
diff --git a/.gitignore b/.gitignore
index d43ca32..ae3f2cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,6 +66,7 @@ plugins/dalvik/v35/opcodes/
# GLib
src/glibext/chrysamarshal.*
resources.[ch]
+src/gtkext/bindings/*-enums.[ch]
# Binaries
src/chrysalide
@@ -76,6 +77,9 @@ tools/d2c/d2c
tools/fuzzing/rost/fast-rost
tools/yara2rost/yara2rost
+# Images générées
+src/data/images/about-bg.png
+
# Schemas
src/schemas/gschemas.compiled
src/schemas/*.valid
@@ -83,6 +87,8 @@ src/schemas/*.valid
# Misc
plugins/python/androperms/androperms.db
system/pkgconfig/chrysalide.pc
+tools/about/bg.png
+tools/about/cour10p_b.ttf
tools/fuzzing/rost/rost.dict
# Themes
diff --git a/configure.ac b/configure.ac
index 2ff719a..8429ae6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -35,6 +35,10 @@ AC_PROG_INSTALL
AC_PROG_MAKE_SET
LT_INIT
+PKG_PROG_PKG_CONFIG([0.28])
+
+PKG_CHECK_VAR([GLIB_MKENUMS], [glib-2.0], [glib_mkenums])
+
CFLAGS=""
AC_EGREP_CPP(yes,
@@ -241,6 +245,14 @@ AC_ARG_ENABLE([magic-support],
AS_HELP_STRING([--disable-magic-support], [disable magic number recognition [default=no]]),
[], [enable_magic_support=yes])
+AC_ARG_ENABLE([jsonglib-support],
+ AS_HELP_STRING([--disable-jsonglib-support], [disable jsonglib support [default=no]]),
+ [], [enable_jsonglib_support=yes])
+
+AC_ARG_ENABLE([hs-support],
+ AS_HELP_STRING([--disable-hs-support], [disable hs number recognition [default=no]]),
+ [], [enable_hs_support=yes])
+
AC_ARG_ENABLE([python-bindings],
AS_HELP_STRING([--disable-python-bindings], [disable Python bindings [default=no]]),
[], [enable_python_bindings=yes])
@@ -585,10 +597,24 @@ if test "$libhs_found" = "yes"; then
libhs_version=`pkg-config libhs --modversion`
else
libhs_version='-'
+ enable_hs_support=''
+fi
+
+AM_CONDITIONAL([BUILD_HS_SUPPORT], [test "x$enable_hs_support" = "xyes"])
+
+if test "x$BUILD_HS_SUPPORT_TRUE" = "x"; then
+ # Hyperscan support is available and enabled
+ CPPFLAGS="$CPPFLAGS -DINCLUDE_HS_SUPPORT"
fi
-AC_SUBST(LIBHS_CFLAGS)
-AC_SUBST(LIBHS_LIBS)
+if test "x$enable_hs_support" = "xyes"; then
+
+ AC_SUBST(LIBHS_CFLAGS)
+ AC_SUBST(LIBHS_LIBS)
+
+ true # empty if/then body not allowed
+
+fi
#--- Checks for json-glib-1.0
@@ -600,8 +626,6 @@ if test "x$BUILD_JSONGLIB_SUPPORT_TRUE" = "x"; then
CPPFLAGS="$CPPFLAGS -DINCLUDE_JSONGLIB_SUPPORT"
fi
-curl
-
PKG_CHECK_MODULES(LIBJSONGLIB,json-glib-1.0 >= 1.6.6,[libjsonglib_found=yes],[libjsonglib_found=no])
@@ -621,6 +645,20 @@ if test "x$enable_json_glib_support" = "xyes"; then
fi
+#--- Checks for libzip
+
+PKG_CHECK_MODULES(LIBZIP,libzip >= 1.7.3,[libzip_found=yes],[libzip_found=no])
+
+if test "$libzip_found" = "yes"; then
+ libzip_version=`pkg-config libzip --modversion`
+else
+ libzip_version='-'
+fi
+
+AC_SUBST(LIBZIP_CFLAGS)
+AC_SUBST(LIBZIP_LIBS)
+
+
#--- Checks for Python
if test "x$enable_debug" = "xyes"; then
@@ -706,6 +744,8 @@ AC_CONFIG_FILES([stamp-h po/Makefile.in], [echo timestamp > stamp-h])
AC_CONFIG_COMMANDS([marshal], [echo -e "VOID:UINT64\nVOID:INT,UINT64,INT\nVOID:OBJECT,OBJECT\nVOID:ENUM,OBJECT\nVOID:ENUM,ENUM\nVOID:BOOLEAN,UINT64\nVOID:BOOLEAN,ULONG,ULONG\nVOID:INT,INT\nVOID:OBJECT,BOOLEAN\nVOID:ULONG,BOOLEAN\nVOID:DOUBLE,DOUBLE" > src/glibext/chrysamarshal.list])
+AC_CONFIG_COMMANDS([about], [./tools/about/gen.sh $version], [version=r$PACKAGE_VERSION])
+
AC_CONFIG_FILES([Makefile
doc/Makefile
pixmaps/Makefile
@@ -800,6 +840,7 @@ AC_CONFIG_FILES([Makefile
plugins/pychrysalide/gui/panels/Makefile
plugins/pychrysalide/mangling/Makefile
plugins/pychrysalide/plugins/Makefile
+ plugins/pynb/Makefile
plugins/python/Makefile
plugins/python/abackup/Makefile
plugins/python/apkfiles/Makefile
@@ -845,16 +886,20 @@ AC_CONFIG_FILES([Makefile
src/arch/operands/Makefile
src/common/Makefile
src/core/Makefile
+ src/data/Makefile
+ src/data/images/Makefile
src/debug/Makefile
src/format/Makefile
src/glibext/Makefile
src/glibext/generators/Makefile
src/glibext/options/Makefile
src/gtkext/Makefile
+ src/gtkext/bindings/Makefile
src/gtkext/graph/Makefile
src/gui/Makefile
src/gui/core/Makefile
src/gui/dialogs/Makefile
+ src/gui/dialogs/prefs/Makefile
src/gui/menus/Makefile
src/gui/panels/Makefile
src/gui/tb/Makefile
@@ -907,7 +952,8 @@ 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 The JSON Parser for GLib library............. : $libjsonglib_version
+echo The JSON Parser for the GLib library......... : $libjsonglib_version
+echo The library for handling ZIP archives........ : $libzip_version
echo
echo Available Python programming language........ : $python3_version
@@ -935,6 +981,12 @@ else
disable_magic_support="yes"
fi
+if test "x$enable_hs_support" = "xyes"; then
+ disable_hs_support="no"
+else
+ disable_hs_support="yes"
+fi
+
if test "x$enable_python_bindings" = "xyes"; then
disable_python_bindings="no"
else
@@ -947,6 +999,7 @@ 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 Hyperscan support.................... : $disable_hs_support
echo Disable Python bindings...................... : $disable_python_bindings
echo Build a Python binary distribution........... : $build_python_package
diff --git a/data/images/locked-symbolic.svg b/data/images/locked-symbolic.svg
new file mode 100644
index 0000000..1b24147
--- /dev/null
+++ b/data/images/locked-symbolic.svg
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="300"
+ height="300"
+ viewBox="0 0 79.375 79.374998"
+ version="1.1"
+ id="svg341"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ sodipodi:docname="locked-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview343"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="true"
+ inkscape:zoom="2.3450501"
+ inkscape:cx="87.418175"
+ inkscape:cy="159.05844"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ showguides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid462"
+ originx="0"
+ originy="0" />
+ </sodipodi:namedview>
+ <defs
+ id="defs338" />
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ id="path1942"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 39.687499 1.3229166 A 13.229166 13.229166 0 0 0 26.458333 14.552083 A 13.229166 13.229166 0 0 0 31.75 25.124564 L 31.75 14.552083 A 7.9375 7.9375 0 0 1 39.687499 6.6145832 A 7.9375 7.9375 0 0 1 47.624999 14.552083 L 47.624999 25.135416 A 13.229166 13.229166 0 0 0 52.916666 14.552083 A 13.229166 13.229166 0 0 0 39.687499 1.3229166 z " />
+ <path
+ id="rect1950"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 26.458333 14.552083 L 26.458333 39.687499 L 31.75 39.687499 L 31.75 14.552083 L 26.458333 14.552083 z M 47.624999 14.552083 L 47.624999 39.687499 L 52.916666 39.687499 L 52.916666 14.552083 L 47.624999 14.552083 z " />
+ <path
+ id="rect2099"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 18.520833 35.71875 C 14.123462 35.71875 10.583333 39.258879 10.583333 43.656249 L 10.583333 70.114582 C 10.583333 74.511953 14.123462 78.052082 18.520833 78.052082 L 60.854166 78.052082 C 65.251537 78.052082 68.791666 74.511953 68.791666 70.114582 L 68.791666 43.656249 C 68.791666 39.258879 65.251537 35.71875 60.854166 35.71875 L 18.520833 35.71875 z M 37.703125 52.916666 L 41.671874 52.916666 C 42.40477 52.916666 42.994791 53.506688 42.994791 54.239583 L 42.994791 70.114582 C 42.994791 70.847478 42.40477 71.437499 41.671874 71.437499 L 37.703125 71.437499 C 36.970229 71.437499 36.380208 70.847478 36.380208 70.114582 L 36.380208 54.239583 C 36.380208 53.506688 36.970229 52.916666 37.703125 52.916666 z " />
+ </g>
+</svg>
diff --git a/data/images/nolock-symbolic.svg b/data/images/nolock-symbolic.svg
new file mode 100644
index 0000000..ed59858
--- /dev/null
+++ b/data/images/nolock-symbolic.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="300"
+ height="300"
+ viewBox="0 0 79.375 79.374998"
+ version="1.1"
+ id="svg341"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ sodipodi:docname="nolock-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview343"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="true"
+ inkscape:zoom="2.3450501"
+ inkscape:cx="84.006734"
+ inkscape:cy="159.05844"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ showguides="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid462"
+ originx="0"
+ originy="0" />
+ </sodipodi:namedview>
+ <defs
+ id="defs338" />
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ id="path1942"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 39.687499 1.3229166 A 13.229166 13.229166 0 0 0 26.458333 14.552083 A 13.229166 13.229166 0 0 0 31.75 25.124564 L 31.75 14.552083 A 7.9375 7.9375 0 0 1 39.687499 6.6145832 A 7.9375 7.9375 0 0 1 47.624999 14.552083 L 47.624999 25.135416 A 13.229166 13.229166 0 0 0 52.916666 14.552083 A 13.229166 13.229166 0 0 0 39.687499 1.3229166 z " />
+ <path
+ id="rect1950"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 26.458333 14.552083 L 26.458333 39.687499 L 31.75 39.687499 L 31.75 14.552083 L 26.458333 14.552083 z M 47.624999 14.552083 L 47.624999 39.687499 L 52.916666 39.687499 L 52.916666 14.552083 L 47.624999 14.552083 z " />
+ <path
+ id="rect2099"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 18.520833 35.71875 C 14.123466 35.71875 10.583333 39.258884 10.583333 43.656249 L 10.583333 70.114582 C 10.583333 70.465451 10.608349 70.810037 10.652063 71.148628 L 36.380208 57.337585 L 36.380208 54.239583 C 36.380208 53.506688 36.970229 52.916666 37.703125 52.916666 L 41.671874 52.916666 C 42.259126 52.916666 42.753343 53.295986 42.927095 53.823587 L 68.065612 40.329321 C 66.811534 37.603321 64.061787 35.71875 60.854166 35.71875 L 18.520833 35.71875 z M 68.791666 47.447232 L 42.994791 61.294449 L 42.994791 70.114582 C 42.994791 70.847478 42.40477 71.437499 41.671874 71.437499 L 37.703125 71.437499 C 36.970229 71.437499 36.380208 70.847478 36.380208 70.114582 L 36.380208 64.845137 L 14.176912 76.763789 C 15.423753 77.577929 16.914362 78.052082 18.520833 78.052082 L 60.854166 78.052082 C 65.251533 78.052082 68.791666 74.511949 68.791666 70.114582 L 68.791666 47.447232 z " />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ id="rect3055"
+ width="79.375"
+ height="6.614583"
+ x="-30.998156"
+ y="61.111198"
+ transform="rotate(-28.226475)" />
+ </g>
+</svg>
diff --git a/data/images/unlocked-symbolic.svg b/data/images/unlocked-symbolic.svg
new file mode 100644
index 0000000..da7b6ac
--- /dev/null
+++ b/data/images/unlocked-symbolic.svg
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="300"
+ height="300"
+ viewBox="0 0 79.375 79.374998"
+ version="1.1"
+ id="svg341"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ sodipodi:docname="unlocked-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview343"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="true"
+ inkscape:zoom="2.3450501"
+ inkscape:cx="87.418175"
+ inkscape:cy="159.05844"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ showguides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid462"
+ originx="0"
+ originy="0" />
+ </sodipodi:namedview>
+ <defs
+ id="defs338" />
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ id="path1942"
+ style="display:none;fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 39.687499,1.3229166 A 13.229166,13.229166 0 0 0 26.458333,14.552083 V 39.687499 H 31.75 V 25.124564 14.552083 a 7.9375,7.9375 0 0 1 7.937499,-7.9374998 7.9375,7.9375 0 0 1 7.9375,7.9374998 v 10.583333 14.552083 h 5.291667 V 14.552083 A 13.229166,13.229166 0 0 0 39.687499,1.3229166 Z" />
+ <path
+ id="rect2099"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 18.520833 35.71875 C 14.123462 35.71875 10.583333 39.258879 10.583333 43.656249 L 10.583333 70.114582 C 10.583333 74.511953 14.123462 78.052082 18.520833 78.052082 L 60.854166 78.052082 C 65.251537 78.052082 68.791666 74.511953 68.791666 70.114582 L 68.791666 43.656249 C 68.791666 39.258879 65.251537 35.71875 60.854166 35.71875 L 18.520833 35.71875 z M 37.703125 52.916666 L 41.671874 52.916666 C 42.40477 52.916666 42.994791 53.506688 42.994791 54.239583 L 42.994791 70.114582 C 42.994791 70.847478 42.40477 71.437499 41.671874 71.437499 L 37.703125 71.437499 C 36.970229 71.437499 36.380208 70.847478 36.380208 70.114582 L 36.380208 54.239583 C 36.380208 53.506688 36.970229 52.916666 37.703125 52.916666 z " />
+ <path
+ id="path2191"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 60.854166 1.3229166 A 13.229166 13.229166 0 0 0 47.624999 14.552083 L 47.624999 39.687499 L 52.916666 39.687499 L 52.916666 25.124564 L 52.916666 14.552083 A 7.9375 7.9375 0 0 1 60.854166 6.6145832 A 7.9375 7.9375 0 0 1 68.791666 14.552083 L 68.791666 25.135416 L 68.791666 25.24497 C 69.221772 25.173377 69.663543 25.135416 70.114582 25.135416 L 74.083332 25.135416 L 74.083332 14.552083 A 13.229166 13.229166 0 0 0 60.854166 1.3229166 z " />
+ </g>
+</svg>
diff --git a/gitrev.m4 b/gitrev.m4
index bf2057b..12dab77 100644
--- a/gitrev.m4
+++ b/gitrev.m4
@@ -1,4 +1,4 @@
-define([gitrepo], esyscmd([bash -c "echo -n $(( $(test -d .git && git rev-list HEAD | wc -l) + 4))"]))
+define([gitrepo], esyscmd([bash -c "echo -n $(( $(test -d .git && git rev-list --count HEAD) + 4))"]))
define([gitversion], ifelse(gitrepo, , 000, gitrepo))
diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am
index d1dff31..da3de19 100644
--- a/pixmaps/Makefile.am
+++ b/pixmaps/Makefile.am
@@ -4,19 +4,6 @@ APP_ICONS = \
chrysalide-64.png \
chrysalide-128.png
-REVISION_PIX = \
- revision_0.png \
- revision_1.png \
- revision_2.png \
- revision_3.png \
- revision_4.png \
- revision_5.png \
- revision_6.png \
- revision_7.png \
- revision_8.png \
- revision_9.png \
- revision.png
-
TOOLBAR_BUTTONS = \
tbutton_collapse.png \
tbutton_expand.png \
@@ -41,8 +28,6 @@ OTHER_ICONS = \
breakpoint_normal.png
MISC = \
- chrysalide-full.png \
- chrysalide_text.png \
welcome.png
CORE = \
@@ -57,13 +42,12 @@ EXTRA_DIST = \
openida_text.xcf \
before-after.png \
$(APP_ICONS) \
- $(REVISION_PIX) \
$(TOOLBAR_BUTTONS) \
$(LIST_ICONS) \
$(ERROR_ICONS) \
$(MISC) \
$(CORE)
-pix_DATA = $(APP_ICONS) $(REVISION_PIX) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(ERROR_ICONS) $(OTHER_ICONS) $(MISC)
+pix_DATA = $(APP_ICONS) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(ERROR_ICONS) $(OTHER_ICONS) $(MISC)
pixdir = $(pixmapsdir)
diff --git a/pixmaps/chrysalide-full.png b/pixmaps/chrysalide-full.png
deleted file mode 100644
index a153353..0000000
--- a/pixmaps/chrysalide-full.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/chrysalide_text.png b/pixmaps/chrysalide_text.png
deleted file mode 100644
index b4d8c78..0000000
--- a/pixmaps/chrysalide_text.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision.png b/pixmaps/revision.png
deleted file mode 100644
index 330e108..0000000
--- a/pixmaps/revision.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_0.png b/pixmaps/revision_0.png
deleted file mode 100644
index 0a468de..0000000
--- a/pixmaps/revision_0.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_1.png b/pixmaps/revision_1.png
deleted file mode 100644
index 738a881..0000000
--- a/pixmaps/revision_1.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_2.png b/pixmaps/revision_2.png
deleted file mode 100644
index b567b80..0000000
--- a/pixmaps/revision_2.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_3.png b/pixmaps/revision_3.png
deleted file mode 100644
index 7f5e3fc..0000000
--- a/pixmaps/revision_3.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_4.png b/pixmaps/revision_4.png
deleted file mode 100644
index a21ccbb..0000000
--- a/pixmaps/revision_4.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_5.png b/pixmaps/revision_5.png
deleted file mode 100644
index a9130d9..0000000
--- a/pixmaps/revision_5.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_6.png b/pixmaps/revision_6.png
deleted file mode 100644
index 291febd..0000000
--- a/pixmaps/revision_6.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_7.png b/pixmaps/revision_7.png
deleted file mode 100644
index ccd4d4e..0000000
--- a/pixmaps/revision_7.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_8.png b/pixmaps/revision_8.png
deleted file mode 100644
index 054c250..0000000
--- a/pixmaps/revision_8.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_9.png b/pixmaps/revision_9.png
deleted file mode 100644
index 1123669..0000000
--- a/pixmaps/revision_9.png
+++ /dev/null
Binary files differ
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 89a8e25..529f4fe 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -14,7 +14,8 @@ endif
# androhelpers
SUBDIRS = \
$(PYTHON3_SUBDIRS) \
- pe
+ pe \
+ pynb
# arm \
# bootimg \
diff --git a/plugins/pe/core.c b/plugins/pe/core.c
index 42f712d..b752735 100644
--- a/plugins/pe/core.c
+++ b/plugins/pe/core.c
@@ -62,8 +62,8 @@ static void g_pe_plugin_finalize(GPePlugin *);
/* Prend acte de l'activation du greffon. */
static bool g_pe_plugin_enable(GPePlugin *);
-/* Prend acte de l'extinction du greffon. */
-static void g_pe_plugin_disable(GPePlugin *);
+/* Prend acte de la désactivation du greffon. */
+static bool g_pe_plugin_disable(GPePlugin *);
@@ -84,7 +84,7 @@ NATIVE_PLUGIN_ENTRYPOINT(g_pe_plugin_new);
* *
* Paramètres : class = classe à initialiser. *
* *
-* Description : Initialise la classe des greffons de support PE. *
+* Description : Initialise la classe des greffons de support PE. *
* *
* Retour : - *
* *
@@ -191,7 +191,7 @@ static void g_pe_plugin_finalize(GPePlugin *plugin)
/******************************************************************************
* *
-* Paramètres : filename = nom du fichier à charger. *
+* Paramètres : module = extension vue du système. *
* *
* Description : Crée un module pour un greffon de support PE. *
* *
@@ -218,7 +218,7 @@ GPluginModule *g_pe_plugin_new(GModule *module)
/******************************************************************************
* *
* Paramètres : plugin = instance à initialiser pleinement. *
-* module = module système correspondant. *
+* module = extension vue du système. *
* *
* Description : Met en place un module pour un greffon de support PE. *
* *
@@ -288,16 +288,21 @@ static bool g_pe_plugin_enable(GPePlugin *plugin)
* *
* Paramètres : plugin = greffon à manipuler. *
* *
-* Description : Prend acte de l'extinction du greffon. *
+* Description : Prend acte de la désactivation du greffon. *
* *
-* Retour : - *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_pe_plugin_disable(GPePlugin *plugin)
+static bool g_pe_plugin_disable(GPePlugin *plugin)
{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ return result;
}
diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am
index 7b1a331..c574727 100644
--- a/plugins/pychrysalide/Makefile.am
+++ b/plugins/pychrysalide/Makefile.am
@@ -15,12 +15,6 @@ endif
# if BUILD_GTK_SUPPORT
-# GTKEXT_LIBADD = \
-# gtkext/libpychrysagtkext.la
-
-# GTKEXT_SUBDIR = \
-# gtkext
-
# GUI_LIBADD = \
# gui/libpychrysagui.la
@@ -34,6 +28,7 @@ pychrysalide_la_SOURCES = \
access.h access.c \
bindings.h bindings.c \
constants.h constants.c \
+ convert.h convert.c \
core-int.h \
core.h core.c \
helpers.h helpers.c \
@@ -50,7 +45,6 @@ AM_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFL
# common/libpychrysacommon.la \
# core/libpychrysacore.la \
# debug/libpychrysadebug.la \
-# $(GTKEXT_LIBADD) \
# $(GUI_LIBADD) \
# mangling/libpychrysamangling.la \
# plugins/libpychrysaplugins.la
@@ -77,9 +71,13 @@ EXTRA_pychrysalideui_la_DEPENDENCIES = pychrysalide.la
pychrysalideui_la_SOURCES = \
core-ui-int.h \
- core-ui.h core-ui.c
+ core-ui.h core-ui.c \
+ helpers-ui.h helpers-ui.c
-pychrysalideui_la_LIBADD =
+pychrysalideui_la_LIBADD = \
+ arch/libpychrysaarchui.la \
+ glibext/libpychrysaglibextui.la \
+ gtkext/libpychrysagtkext.la
# -ldl: dladdr(), dlerror()
pychrysalideui_la_LDFLAGS = \
@@ -97,4 +95,4 @@ dev_HEADERS = $(pychrysalide_la_SOURCES:%c=)
#SUBDIRS = analysis arch common core debug $(GTKEXT_SUBDIR) $(GUI_SUBDIR) mangling plugins
-SUBDIRS = analysis arch common core format glibext plugins
+SUBDIRS = analysis arch common core format glibext gtkext plugins
diff --git a/plugins/pychrysalide/arch/Makefile.am b/plugins/pychrysalide/arch/Makefile.am
index d3ee3f0..a0dcfdb 100644
--- a/plugins/pychrysalide/arch/Makefile.am
+++ b/plugins/pychrysalide/arch/Makefile.am
@@ -1,19 +1,13 @@
-noinst_LTLIBRARIES = libpychrysaarch4.la # libpychrysaarch.la
+noinst_LTLIBRARIES = libpychrysaarch4.la libpychrysaarchui.la # 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 \
-# vmpa.h vmpa.c
+# processor.h processor.c
# libpychrysaarch_la_LIBADD = \
-# instructions/libpychrysaarchinstructions.la \
+# \
# operands/libpychrysaarchoperands.la
# libpychrysaarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
@@ -22,21 +16,33 @@ noinst_LTLIBRARIES = libpychrysaarch4.la # libpychrysaarch.la
libpychrysaarch4_la_SOURCES = \
constants.h constants.c \
+ instruction.h instruction.c \
module.h module.c \
+ operand.h operand.c \
+ register.h register.c \
vmpa.h vmpa.c
-# libpychrysaarch4_la_LIBADD = \
-# instructions/libpychrysaarchinstructions.la \
-# operands/libpychrysaarchoperands.la
+libpychrysaarch4_la_LIBADD = \
+ instructions/libpychrysaarchinstructions.la \
+ operands/libpychrysaarchoperands.la
libpychrysaarch4_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
$(TOOLKIT_CFLAGS) \
-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+libpychrysaarchui_la_SOURCES = \
+ module-ui.h module-ui.c \
+ operand-ui.h operand-ui.c
+
+libpychrysaarchui_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ $(TOOLKIT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaarch_la_SOURCES:%c=)
-# SUBDIRS = instructions operands
+SUBDIRS = instructions operands
diff --git a/plugins/pychrysalide/arch/constants.c b/plugins/pychrysalide/arch/constants.c
index 3604795..5db59ff 100644
--- a/plugins/pychrysalide/arch/constants.c
+++ b/plugins/pychrysalide/arch/constants.c
@@ -25,7 +25,7 @@
#include "constants.h"
-//#include <arch/instruction.h>
+#include <arch/instruction.h>
//#include <arch/processor.h>
#include <arch/vmpa.h>
@@ -33,7 +33,6 @@
#include "../helpers.h"
-#if 0 // FIXME
/******************************************************************************
* *
@@ -116,6 +115,8 @@ bool define_arch_instruction_constants(PyTypeObject *type)
}
+#if 0 // FIXME
+
/******************************************************************************
* *
* Paramètres : type = type dont le dictionnaire est à compléter. *
diff --git a/plugins/pychrysalide/arch/constants.h b/plugins/pychrysalide/arch/constants.h
index b12579e..2f16c4f 100644
--- a/plugins/pychrysalide/arch/constants.h
+++ b/plugins/pychrysalide/arch/constants.h
@@ -30,10 +30,13 @@
#include <stdbool.h>
-#if 0 // FIXME
+
/* Définit les constantes relatives aux instructions. */
bool define_arch_instruction_constants(PyTypeObject *);
+
+#if 0 // FIXME
+
/* Définit les constantes relatives aux processeurs. */
bool define_arch_processor_constants(PyTypeObject *);
diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c
index 0a9ba16..49daa9c 100644
--- a/plugins/pychrysalide/arch/instruction.c
+++ b/plugins/pychrysalide/arch/instruction.c
@@ -27,13 +27,12 @@
#include <assert.h>
#include <malloc.h>
-#include <string.h>
#include <pygobject.h>
#include <i18n.h>
+#include <plugins/self.h>
#include <arch/instruction-int.h>
-#include <plugins/dt.h>
#include "constants.h"
@@ -41,30 +40,38 @@
#include "vmpa.h"
#include "../access.h"
#include "../helpers.h"
-#include "../glibext/linegen.h"
-
-
-
-static G_DEFINE_QUARK(cached_keyword, get_cached_keyword);
+#include "../glibext/objhole.h"
+#include "../glibext/serialize.h"
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_arch_instruction_new(PyTypeObject *, PyObject *, PyObject *);
-
/* Initialise la classe générique des instructions. */
-static void py_arch_instruction_init_gclass(GArchInstructionClass *, gpointer);
+static int py_arch_instruction_init_gclass(GArchInstructionClass *, PyTypeObject *);
-CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_instruction, G_TYPE_ARCH_INSTRUCTION, py_arch_instruction_init_gclass);
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_instruction, G_TYPE_ARCH_INSTRUCTION);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_arch_instruction_init(PyObject *, PyObject *, PyObject *);
+/* Indique l'encodage d'une instruction de façon détaillée. */
+static char *py_arch_instruction_get_encoding_wrapper(const GArchInstruction *);
+
/* Fournit le nom humain de l'instruction manipulée. */
-static const char *py_arch_instruction_get_class_keyword(GArchInstruction *);
+static char *py_arch_instruction_get_keyword_wrapper(const GArchInstruction *);
+
+
+
+/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */
+
+
+/* Fournit les origines d'une instruction donnée. */
+static PyObject *py_arch_instruction_get_sources(PyObject *, void *);
+
+/* Fournit les destinations d'une instruction donnée. */
+static PyObject *py_arch_instruction_get_destinations(PyObject *, void *);
@@ -72,10 +79,7 @@ static const char *py_arch_instruction_get_class_keyword(GArchInstruction *);
/* Attache un opérande supplémentaire à une instruction. */
-static PyObject *py_arch_instruction_attach_extra_operand(PyObject *, PyObject *);
-
-/* Fournit tous les opérandes d'une instruction. */
-static PyObject *py_arch_instruction_get_operands(PyObject *, void *);
+static PyObject *py_arch_instruction_attach_operand(PyObject *, PyObject *);
/* Remplace un opérande d'une instruction par un autre. */
static PyObject *py_arch_instruction_replace_operand(PyObject *, PyObject *);
@@ -89,34 +93,35 @@ static PyObject *py_arch_instruction_find_operand_path(PyObject *, PyObject *);
/* Obtient l'opérande correspondant à un chemin donné. */
static PyObject *py_arch_instruction_get_operand_from_path(PyObject *, PyObject *);
+/* Fournit tous les opérandes d'une instruction. */
+static PyObject *py_arch_instruction_get_operands(PyObject *, void *);
-/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */
+/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */
-/* Fournit les origines d'une instruction donnée. */
-static PyObject *py_arch_instruction_get_sources(PyObject *, void *);
-/* Fournit les destinations d'une instruction donnée. */
-static PyObject *py_arch_instruction_get_destinations(PyObject *, void *);
+/* Ajoute une information complémentaire à une instruction. */
+static PyObject *py_arch_instruction_set_flag(PyObject *, PyObject *);
+/* Retire une information complémentaire à une instruction. */
+static PyObject *py_arch_instruction_unset_flag(PyObject *, PyObject *);
+/* Détermine si une instruction possède un fanion particulier. */
+static PyObject *py_arch_instruction_has_flag(PyObject *, PyObject *);
-/* --------------------- INSTRUCTIONS D'ARCHITECTURES EN PYTHON --------------------- */
+/* Fournit l'identifiant correspondant à un type d'instructions. */
+static PyObject *py_arch_instruction_get_type_id(PyObject *, void *);
+/* Indique l'encodage d'une instruction de façon détaillée. */
+static PyObject *py_arch_instruction_get_encoding(PyObject *, void *);
-/* Fournit l'identifiant unique pour un ensemble d'instructions. */
-static PyObject *py_arch_instruction_get_unique_id(PyObject *, void *);
+/* Indique l'encodage d'une instruction de façon détaillée. */
+static PyObject *py_arch_instruction_get_keyword(PyObject *, void *);
/* Fournit la place mémoire d'une instruction. */
static PyObject *py_arch_instruction_get_range(PyObject *, void *);
-/* Définit la localisation d'une instruction. */
-static int py_arch_instruction_set_range(PyObject *, PyObject *, void *);
-
-/* Fournit le nom humain de l'instruction manipulée. */
-static PyObject *py_arch_instruction_get_keyword(PyObject *, void *);
-
/* ---------------------------------------------------------------------------------- */
@@ -126,24 +131,23 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *, void *);
/******************************************************************************
* *
-* Paramètres : class = classe à initialiser. *
-* unused = données non utilisées ici. *
+* Paramètres : gclass = classe GLib à initialiser. *
+* pyclass = classe Python à initialiser. *
* *
* Description : Initialise la classe générique des instructions. *
* *
-* Retour : - *
+* Retour : 0 pour indiquer un succès de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void py_arch_instruction_init_gclass(GArchInstructionClass *class, gpointer unused)
+static int py_arch_instruction_init_gclass(GArchInstructionClass *gclass, PyTypeObject *pyclass)
{
- GArchInstructionClass *instr; /* Encore une autre vision... */
-
- instr = G_ARCH_INSTRUCTION_CLASS(class);
+ PY_CLASS_SET_WRAPPER(gclass->get_encoding, py_arch_instruction_get_encoding_wrapper);
+ PY_CLASS_SET_WRAPPER(gclass->get_keyword, py_arch_instruction_get_keyword_wrapper);
- instr->get_keyword = (get_instruction_keyword_fc)py_arch_instruction_get_class_keyword;
+ return 0;
}
@@ -164,17 +168,25 @@ static void py_arch_instruction_init_gclass(GArchInstructionClass *class, gpoint
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 */
+ unsigned short int tid; /* Indentifiant unique de type */
int ret; /* Bilan de lecture des args. */
GArchInstruction *instr; /* Instruction à manipuler */
- GQuark cache_key; /* Emplacement local */
- static char *kwlist[] = { "uid", "keyword", NULL };
+#define ARCH_INSTRUCTION_DOC \
+ "The ArchInstruction object provides a base class for instructions" \
+ " of any architecture.\n" \
+ " operands of any kind for new architectures.\n" \
+ "\n" \
+ "Calls to the *__init__* constructor of this abstract object expect"\
+ " one argument: an unique identifier, as an integer value.\n" \
+ "\n" \
+ "The following methods have to be defined for new classes:\n" \
+ "* pychrysalide.arch.ArchRegister._get_encoding();\n" \
+ "* pychrysalide.arch.ArchRegister._get_keyword().\n"
/* Récupération des paramètres */
- ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword);
+ ret = PyArg_ParseTuple(args, "H", &tid);
if (!ret) return -1;
/* Initialisation d'un objet GLib */
@@ -186,13 +198,72 @@ static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kw
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- cache_key = get_cached_keyword_quark();
+ if (!g_arch_instruction_create(instr, tid))
+ return -1;
+
+ return 0;
- 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;
+/******************************************************************************
+* *
+* Paramètres : instr = instruction quelconque à consulter. *
+* *
+* Description : Indique l'encodage d'une instruction de façon détaillée. *
+* *
+* Retour : Description humaine de l'encodage utilisé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *py_arch_instruction_get_encoding_wrapper(const GArchInstruction *instr)
+{
+ char *result; /* Encodage à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyret; /* Bilan d'exécution */
+
+#define PLUGIN_MODULE_GET_ENCODING_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _get_encoding, "$self, /", \
+ METH_NOARGS, \
+ "Abstract method describing the encoding related to an" \
+ " instruction.\n" \
+ "\n" \
+ "The result should be the string value.\n" \
+)
+
+ result = NULL;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(instr));
+
+ if (has_python_method(pyobj, "_get_encoding"))
+ {
+ pyret = run_python_method(pyobj, "_get_encoding", NULL);
+
+ if (pyret != NULL)
+ {
+ if (!PyUnicode_Check(pyret))
+ log_variadic_message(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;
}
@@ -209,15 +280,50 @@ static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kw
* *
******************************************************************************/
-static const char *py_arch_instruction_get_class_keyword(GArchInstruction *instr)
+static char *py_arch_instruction_get_keyword_wrapper(const GArchInstruction *instr)
{
- const char *result; /* Désignation à retourner */
- GQuark cache_key; /* Emplacement local */
+ char *result; /* Etiquette à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyret; /* Bilan d'exécution */
+
+#define PLUGIN_MODULE_GET_KEYWORD_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _get_keyword, "$self, /", \
+ METH_NOARGS, \
+ "Abstract method giving the official name of the assembly" \
+ " instruction.\n" \
+ "\n" \
+ "The result should be the string value.\n" \
+)
+
+ result = NULL;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(instr));
+
+ if (has_python_method(pyobj, "_get_keyword"))
+ {
+ pyret = run_python_method(pyobj, "_get_keyword", NULL);
+
+ if (pyret != NULL)
+ {
+ if (!PyUnicode_Check(pyret))
+ log_variadic_message(LMT_ERROR, _("The returned raw name must be a string"));
- cache_key = get_cached_keyword_quark();
+ else
+ result = strdup(PyUnicode_DATA(pyret));
- result = g_object_get_qdata(G_OBJECT(instr), cache_key);
- assert(result != NULL);
+ }
+
+ Py_XDECREF(pyret);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
return result;
@@ -226,94 +332,201 @@ static const char *py_arch_instruction_get_class_keyword(GArchInstruction *instr
/* ---------------------------------------------------------------------------------- */
-/* MANIPULATION DES OPERANDES */
+/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : self = architecture concernée par la procédure. *
-* args = instruction représentant le point de départ. *
+* Paramètres : self = instruction d'architecture à manipuler. *
+* unused = adresse non utilisée ici. *
* *
-* Description : Attache un opérande supplémentaire à une instruction. *
+* Description : Fournit les origines d'une instruction donnée. *
* *
-* Retour : None. *
+* Retour : Nombre de ces origines. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_instruction_attach_extra_operand(PyObject *self, PyObject *args)
+static PyObject *py_arch_instruction_get_sources(PyObject *self, void *unused)
{
- GArchOperand *op; /* Opérande concerné à ajouter */
- int ret; /* Bilan de lecture des args. */
- GArchInstruction *instr; /* Instruction manipulée */
+ PyObject *result; /* Instance à retourner */
+ GArchInstruction *instr; /* Version native */
+ size_t count; /* Nombre de liens présents */
+ size_t i; /* Boucle de parcours */
- ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &op);
- if (!ret) return NULL;
+
+ GArchInstruction *src; /* Instruction en source */
+ InstructionLinkType src_type; /* Type de lien */
+ PyObject *linked; /* Source de lien Python */
+ PyObject *lnk_type; /* Nature du lien en Python */
+#ifndef NDEBUG
+ int ret; /* Bilan d'une écriture d'arg. */
+#endif
+
+#define ARCH_INSTRUCTION_SOURCES_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ sources, py_arch_instruction, \
+ "Provide the instructions list driving to the current instruction.\n" \
+ "\n" \
+ "Each item of the resulting tuple is a pair of" \
+ " pychrysalide.arch.ArchInstruction instance and" \
+ " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \
+)
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- g_object_ref(G_OBJECT(op));
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+
+ count = g_arch_instruction_count_src_links(instr);
+
+ result = PyTuple_New(count);
+
+ for (i = 0; i < count; i++)
+ {
+ src = g_arch_instruction_get_linked_source(instr, i, &src_type);
+
+ linked = pygobject_new(G_OBJECT(src));
+ lnk_type = cast_with_constants_group_from_type(get_python_arch_instruction_type(),
+ "InstructionLinkType", src_type);
+
+#ifndef NDEBUG
+ ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type));
+ assert(ret == 0);
+#else
+ PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type));
+#endif
+
+ unref_object(src);
+
+ }
- g_arch_instruction_attach_extra_operand(instr, op);
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
- Py_RETURN_NONE;
+ return result;
}
/******************************************************************************
* *
-* Paramètres : self = objet représentant une instruction. *
+* Paramètres : self = instruction d'architecture à manipuler. *
* unused = adresse non utilisée ici. *
* *
-* Description : Fournit tous les opérandes d'une instruction. *
+* Description : Fournit les destinations d'une instruction donnée. *
* *
-* Retour : Valeur associée à la propriété consultée. *
+* Retour : Nombre de ces destinations. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_instruction_get_operands(PyObject *self, void *unused)
+static PyObject *py_arch_instruction_get_destinations(PyObject *self, void *unused)
{
PyObject *result; /* Instance à retourner */
GArchInstruction *instr; /* Version native */
- size_t count; /* Nombre d'opérandes présents */
+ size_t count; /* Nombre de liens présents */
size_t i; /* Boucle de parcours */
- GArchOperand *operand; /* Opérande à manipuler */
- PyObject *opobj; /* Version Python */
+ GArchInstruction *dest; /* Instruction en source */
+ InstructionLinkType dest_type; /* Type de lien */
+ PyObject *linked; /* Destination de lien Python */
+ PyObject *lnk_type; /* Nature du lien en Python */
#ifndef NDEBUG
int ret; /* Bilan d'une écriture d'arg. */
#endif
+#define ARCH_INSTRUCTION_DESTINATIONS_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ destinations, py_arch_instruction, \
+ "Provide the instructions list following the current instruction.\n" \
+ "\n" \
+ "Each item of the resulting tuple is a pair of" \
+ " pychrysalide.arch.ArchInstruction instance and" \
+ " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \
+)
+
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- g_arch_instruction_lock_operands(instr);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
- count = _g_arch_instruction_count_operands(instr);
+ count = g_arch_instruction_count_dest_links(instr);
result = PyTuple_New(count);
for (i = 0; i < count; i++)
{
- operand = _g_arch_instruction_get_operand(instr, i);
+ dest = g_arch_instruction_get_linked_destination(instr, i, &dest_type);
- opobj = pygobject_new(G_OBJECT(operand));
+ linked = pygobject_new(G_OBJECT(dest));
+ lnk_type = cast_with_constants_group_from_type(get_python_arch_instruction_type(),
+ "InstructionLinkType", dest_type);
#ifndef NDEBUG
- ret = PyTuple_SetItem(result, i, Py_BuildValue("O", opobj));
+ ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type));
assert(ret == 0);
#else
- PyTuple_SetItem(result, i, Py_BuildValue("O", opobj));
+ PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type));
#endif
- g_object_unref(G_OBJECT(operand));
+ unref_object(dest);
}
- g_arch_instruction_unlock_operands(instr);
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION DES OPERANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : self = architecture concernée par la procédure. *
+* args = instruction représentant le point de départ. *
+* *
+* Description : Attache un opérande supplémentaire à une instruction. *
+* *
+* Retour : None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_arch_instruction_attach_operand(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ GArchOperand *op; /* Opérande concerné à ajouter */
+ int ret; /* Bilan de lecture des args. */
+ GArchInstruction *instr; /* Instruction manipulée */
+
+#define ARCH_INSTRUCTION_ATTACH_OPERAND_METHOD PYTHON_METHOD_DEF \
+( \
+ attach_operand, "$self, operand, /", \
+ METH_VARARGS, py_arch_instruction, \
+ "Add an extra operand to an instruction.\n" \
+ "\n" \
+ "The instruction has to be locked during the instruction.\n" \
+ "\n" \
+ "The *operand* argument has to be a pychrysalide.arch.ArchOperand" \
+ " instance." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &op);
+ if (!ret) return NULL;
+
+ instr = G_ARCH_INSTRUCTION(pygobject_get(self));
+
+ g_arch_instruction_attach_operand(instr, op);
+
+ result = Py_None;
+ Py_INCREF(result);
return result;
@@ -342,6 +555,21 @@ static PyObject *py_arch_instruction_replace_operand(PyObject *self, PyObject *a
GArchInstruction *instr; /* Instruction manipulée */
bool status; /* Bilan de l'opération */
+#define ARCH_INSTRUCTION_REPLACE_OPERAND_METHOD PYTHON_METHOD_DEF \
+( \
+ replace_operand, "$self, old, new, /", \
+ METH_VARARGS, py_arch_instruction, \
+ "Replace an old instruction operand by a another one.\n" \
+ "\n" \
+ "The instruction has to be locked during the instruction.\n" \
+ "\n" \
+ "Both the *old* and *new* arguments have to be a" \
+ " pychrysalide.arch.ArchOperand instance.\n" \
+ "\n" \
+ "The status of the operation is returned as a boolean value: *True*"\
+ " if the operand has been replaced, *False* in case of failure." \
+)
+
ret = PyArg_ParseTuple(args, "O&O&", convert_to_arch_operand, &old, convert_to_arch_operand, &new);
if (!ret) return NULL;
@@ -349,9 +577,6 @@ static PyObject *py_arch_instruction_replace_operand(PyObject *self, PyObject *a
status = g_arch_instruction_replace_operand(instr, old, new);
- if (status)
- g_object_ref(G_OBJECT(new));
-
result = status ? Py_True : Py_False;
Py_INCREF(result);
@@ -381,6 +606,21 @@ static PyObject *py_arch_instruction_detach_operand(PyObject *self, PyObject *ar
GArchInstruction *instr; /* Instruction manipulée */
bool status; /* Bilan de l'opération */
+#define ARCH_INSTRUCTION_DETACH_OPERAND_METHOD PYTHON_METHOD_DEF \
+( \
+ detach_operand, "$self, operand, /", \
+ METH_VARARGS, py_arch_instruction, \
+ "Remove an operand from the instruction.\n" \
+ "\n" \
+ "The instruction has to be locked during the instruction.\n" \
+ "\n" \
+ "The *operand* argument has to be a pychrysalide.arch.ArchOperand" \
+ " instance.\n" \
+ "\n" \
+ "The status of the operation is returned as a boolean value: *True*"\
+ " if the operand has been removed, *False* in case of failure." \
+)
+
ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &target);
if (!ret) return NULL;
@@ -500,7 +740,7 @@ static PyObject *py_arch_instruction_get_operand_from_path(PyObject *self, PyObj
if (op != NULL)
{
result = pygobject_new(G_OBJECT(op));
- g_object_unref(G_OBJECT(op));
+ unref_object(op);
}
else
{
@@ -513,182 +753,258 @@ static PyObject *py_arch_instruction_get_operand_from_path(PyObject *self, PyObj
}
-
-/* ---------------------------------------------------------------------------------- */
-/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : self = instruction d'architecture à manipuler. *
+* Paramètres : self = objet représentant une instruction. *
* unused = adresse non utilisée ici. *
* *
-* Description : Fournit les origines d'une instruction donnée. *
+* Description : Fournit tous les opérandes d'une instruction. *
* *
-* Retour : Nombre de ces origines. *
+* Retour : Valeur associée à la propriété consultée. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_instruction_get_sources(PyObject *self, void *unused)
+static PyObject *py_arch_instruction_get_operands(PyObject *self, void *unused)
{
PyObject *result; /* Instance à retourner */
GArchInstruction *instr; /* Version native */
- size_t count; /* Nombre de liens présents */
+ size_t count; /* Nombre d'opérandes présents */
size_t i; /* Boucle de parcours */
- const instr_link_t *source; /* Origine des liens */
- PyObject *linked; /* Source de lien Python */
- PyObject *type; /* Nature du lien en Python */
+ GArchOperand *operand; /* Opérande à manipuler */
+ PyObject *opobj; /* Version Python */
#ifndef NDEBUG
int ret; /* Bilan d'une écriture d'arg. */
#endif
-#define ARCH_INSTRUCTION_SOURCES_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- sources, py_arch_instruction, \
- "Provide the instructions list driving to the current instruction.\n" \
- "\n" \
- "Each item of the resulting tuple is a pair of" \
- " pychrysalide.arch.ArchInstruction instance and" \
- " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \
+#define ARCH_INSTRUCTION_OPERANDS_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ operands, py_arch_instruction, \
+ "List of instruction attached operands.\n" \
+ "\n" \
+ "The result is a list of pychrysalide.arch.ArchOperand" \
+ " instances, which can be empty." \
)
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- g_arch_instruction_lock_src(instr);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
- count = g_arch_instruction_count_sources(instr);
+ count = g_arch_instruction_count_operands(instr);
result = PyTuple_New(count);
for (i = 0; i < count; i++)
{
- source = g_arch_instruction_get_source(instr, i);
+ operand = g_arch_instruction_get_operand(instr, i);
- linked = pygobject_new(G_OBJECT(source->linked));
- type = cast_with_constants_group_from_type(get_python_arch_instruction_type(),
- "InstructionLinkType", source->type);
+ opobj = pygobject_new(G_OBJECT(operand));
#ifndef NDEBUG
- ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type));
+ ret = PyTuple_SetItem(result, i, Py_BuildValue("O", opobj));
assert(ret == 0);
#else
- PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type));
+ PyTuple_SetItem(result, i, Py_BuildValue("O", opobj));
#endif
- unref_instr_link(source);
+ unref_object(operand);
}
- g_arch_instruction_unlock_src(instr);
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* LIAISON DE FONCTIONNALITES AVEC L'API PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : self = instruction d'architecture à manipuler. *
-* unused = adresse non utilisée ici. *
+* Paramètres : self = architecture concernée par la procédure. *
+* args = instruction représentant le point de départ. *
* *
-* Description : Fournit les destinations d'une instruction donnée. *
+* Description : Ajoute une information complémentaire à une instruction. *
* *
-* Retour : Nombre de ces destinations. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_instruction_get_destinations(PyObject *self, void *unused)
+static PyObject *py_arch_instruction_set_flag(PyObject *self, PyObject *args)
{
- PyObject *result; /* Instance à retourner */
- GArchInstruction *instr; /* Version native */
- size_t count; /* Nombre de liens présents */
- size_t i; /* Boucle de parcours */
- const instr_link_t *dest; /* Destination des liens */
- PyObject *linked; /* Destination de lien Python */
- PyObject *type; /* Nature du lien en Python */
-#ifndef NDEBUG
- int ret; /* Bilan d'une écriture d'arg. */
-#endif
-
-#define ARCH_INSTRUCTION_DESTINATIONS_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- destinations, py_arch_instruction, \
- "Provide the instructions list following the current instruction.\n" \
- "\n" \
- "Each item of the resulting tuple is a pair of" \
- " pychrysalide.arch.ArchInstruction instance and" \
- " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \
+ PyObject *result; /* Bilan à retourner */
+ unsigned int flag; /* Fanion(s) à appliquer */
+ int ret; /* Bilan de lecture des args. */
+ GArchInstruction *instr; /* Instruction manipulée */
+ bool status; /* Bilan à transmettre */
+
+#define ARCH_INSTRUCTION_SET_FLAG_METHOD PYTHON_METHOD_DEF \
+( \
+ set_flag, "$self, flag, /", \
+ METH_VARARGS, py_arch_instruction, \
+ "Add some flags to the instruction.\n" \
+ "\n" \
+ "This *flag* argument is an integer value containing" \
+ " bits to apply to the instruction state.\n" \
+ "\n" \
+ "The result is an boolean status: *True* for operation" \
+ " success, *False* otherwise." \
)
+ ret = PyArg_ParseTuple(args, "I", &flag);
+ if (!ret) return NULL;
+
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- g_arch_instruction_lock_dest(instr);
+ status = g_arch_instruction_set_flag(instr, flag);
- count = g_arch_instruction_count_destinations(instr);
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
- result = PyTuple_New(count);
+ return result;
- for (i = 0; i < count; i++)
- {
- dest = g_arch_instruction_get_destination(instr, i);
+}
- linked = pygobject_new(G_OBJECT(dest->linked));
- type = cast_with_constants_group_from_type(get_python_arch_instruction_type(),
- "InstructionLinkType", dest->type);
-#ifndef NDEBUG
- ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type));
- assert(ret == 0);
-#else
- PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type));
-#endif
+/******************************************************************************
+* *
+* Paramètres : self = architecture concernée par la procédure. *
+* args = instruction représentant le point de départ. *
+* *
+* Description : Retire une information complémentaire à une instruction. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_arch_instruction_unset_flag(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ unsigned int flag; /* Fanion(s) à appliquer */
+ int ret; /* Bilan de lecture des args. */
+ GArchInstruction *instr; /* Instruction manipulée */
+ bool status; /* Bilan à transmettre */
+
+#define ARCH_INSTRUCTION_UNSET_FLAG_METHOD PYTHON_METHOD_DEF \
+( \
+ unset_flag, "$self, flag, /", \
+ METH_VARARGS, py_arch_instruction, \
+ "Remove some flags from the instruction.\n" \
+ "\n" \
+ "This *flag* argument is an integer value containing" \
+ " bits to delete from the instruction state.\n" \
+ "\n" \
+ "The result is an boolean status: *True* for operation" \
+ " success, *False* otherwise." \
+)
- unref_instr_link(dest);
+ ret = PyArg_ParseTuple(args, "I", &flag);
+ if (!ret) return NULL;
- }
+ instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- g_arch_instruction_unlock_dest(instr);
+ status = g_arch_instruction_unset_flag(instr, flag);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
return result;
}
+/******************************************************************************
+* *
+* Paramètres : self = architecture concernée par la procédure. *
+* args = instruction représentant le point de départ. *
+* *
+* Description : Détermine si une instruction possède un fanion particulier. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
-/* ---------------------------------------------------------------------------------- */
-/* INSTRUCTIONS D'ARCHITECTURES EN PYTHON */
-/* ---------------------------------------------------------------------------------- */
+static PyObject *py_arch_instruction_has_flag(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ unsigned int flag; /* Fanion(s) à appliquer */
+ int ret; /* Bilan de lecture des args. */
+ GArchInstruction *instr; /* Instruction manipulée */
+ bool status; /* Bilan à transmettre */
+
+#define ARCH_INSTRUCTION_HAS_FLAG_METHOD PYTHON_METHOD_DEF \
+( \
+ has_flag, "$self, flag, /", \
+ METH_VARARGS, py_arch_instruction, \
+ "Tell if some flags are set for the instruction.\n" \
+ "\n" \
+ "This *flag* argument is an integer value containing" \
+ " bits to test for the instruction state.\n" \
+ "\n" \
+ "The result is an boolean status: *True* if the bits" \
+ " are active, *False* otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "I", &flag);
+ if (!ret) return NULL;
+
+ instr = G_ARCH_INSTRUCTION(pygobject_get(self));
+
+ status = g_arch_instruction_has_flag(instr, flag);
+
+ 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. *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
* *
-* Description : Fournit l'identifiant unique pour un ensemble d'instructions.*
+* Description : Fournit l'identifiant correspondant à un type d'instructions.*
* *
-* Retour : Identifiant unique par type d'instruction. *
+* Retour : Identifiant unique par type d'instruction et architecture. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_instruction_get_unique_id(PyObject *self, void *closure)
+static PyObject *py_arch_instruction_get_type_id(PyObject *self, void *closure)
{
- PyObject *result; /* Conversion à retourner */
- GArchInstruction *instr; /* Version native */
- itid_t uid; /* Identifiant unique associé */
+ PyObject *result; /* Valeur à retourner */
+ GArchInstruction *instr; /* Instruction manipulée */
+ itid_t tid; /* Identifiant à transmettre */
+
+#define ARCH_INSTRUCTION_TYPE_ID_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ type_id, py_arch_instruction, \
+ "Provide the unique identifier given to this kind of" \
+ " instruction.\n" \
+ "\n" \
+ "The returned value is an integer." \
+)
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- uid = g_arch_instruction_get_unique_id(instr);
+ tid = g_arch_instruction_get_type_id(instr);
- result = PyLong_FromUnsignedLong(uid);
+ result = PyLong_FromUnsignedLong(tid);
return result;
@@ -697,27 +1013,61 @@ static PyObject *py_arch_instruction_get_unique_id(PyObject *self, void *closure
/******************************************************************************
* *
-* Paramètres : self = classe représentant une instruction. *
-* closure = adresse non utilisée ici. *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
* *
-* Description : Fournit la place mémoire d'une instruction. *
+* Description : Indique l'encodage d'une instruction de façon détaillée. *
* *
-* Retour : Valeur associée à la propriété consultée. *
+* Retour : Description humaine de l'encodage utilisé. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure)
+static PyObject *py_arch_instruction_get_encoding(PyObject *self, void *closure)
{
- PyObject *result; /* Conversion à retourner */
- GArchInstruction *instr; /* Version native */
- const mrange_t *range; /* Espace mémoire à exporter */
+ PyObject *result; /* Valeur à retourner */
+ GArchInstruction *instr; /* Instruction manipulée */
+ char *encoding; /* Encodage d'une instruction */
+
+#define ARCH_INSTRUCTION_ENCODING_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ encoding, py_arch_instruction, \
+ "Describe the encoding related to an instruction.\n" \
+ "\n" \
+ "The returned value is an arbitrary string value." \
+)
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- range = g_arch_instruction_get_range(instr);
- result = build_from_internal_mrange(range);
+ encoding = g_arch_instruction_get_encoding(instr);
+
+ if (encoding != NULL)
+ {
+ result = PyUnicode_FromString(encoding);
+
+ free(encoding);
+
+ }
+
+ else
+ {
+ /**
+ * La méthode de classe sollicitée a renvoyé une valeur nulle.
+ *
+ * Si cette méthode correspond à une implémentation Python
+ * (avec un appel à not_yet_implemented_method()), une exception
+ * est déjà en place.
+ *
+ * Si aucune exception n'a été prévue, un rattrapage est effectué ici.
+ */
+
+ if (PyErr_Occurred() == NULL)
+ PyErr_SetString(PyExc_NotImplementedError, _("unexpected NULL value as encoding"));
+
+ result = NULL;
+
+ }
return result;
@@ -727,59 +1077,108 @@ static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure)
/******************************************************************************
* *
* Paramètres : self = objet Python concerné par l'appel. *
-* value = valeur fournie à intégrer ou prendre en compte. *
-* closure = adresse non utilisée ici. *
+* closure = non utilisé ici. *
* *
-* Description : Définit la localisation d'une instruction. *
+* Description : Indique l'encodage d'une instruction de façon détaillée. *
* *
-* Retour : Bilan de l'opération pour Python. *
+* Retour : Description humaine de l'encodage utilisé. *
* *
* Remarques : - *
* *
******************************************************************************/
-static int py_arch_instruction_set_range(PyObject *self, PyObject *value, void *closure)
+static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *closure)
{
- int ret; /* Bilan d'analyse */
- mrange_t *range; /* Espace mémoire à manipuler */
- GArchInstruction *instr; /* Version native */
+ PyObject *result; /* Valeur à retourner */
+ GArchInstruction *instr; /* Instruction manipulée */
+ char *keyword; /* Désignation d'une instruct° */
+
+#define ARCH_INSTRUCTION_KEYWORD_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ keyword, py_arch_instruction, \
+ "Give the official name of the assembly instruction.\n" \
+ "\n" \
+ "The returned value is a string value." \
+)
- ret = PyObject_IsInstance(value, (PyObject *)get_python_mrange_type());
- if (!ret) return -1;
+ instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- range = get_internal_mrange(value);
+ keyword = g_arch_instruction_get_keyword(instr);
- instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- g_arch_instruction_set_range(instr, range);
+ if (keyword != NULL)
+ {
+ result = PyUnicode_FromString(keyword);
- return 0;
+ free(keyword);
+
+ }
+
+ else
+ {
+ /**
+ * La méthode de classe sollicitée a renvoyé une valeur nulle.
+ *
+ * Si cette méthode correspond à une implémentation Python
+ * (avec un appel à not_yet_implemented_method()), une exception
+ * est déjà en place.
+ *
+ * Si aucune exception n'a été prévue, un rattrapage est effectué ici.
+ */
+
+ if (PyErr_Occurred() == NULL)
+ PyErr_SetString(PyExc_NotImplementedError, _("unexpected NULL value as keyword"));
+
+ result = NULL;
+
+ }
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : self = classe représentant une instruction. *
-* unused = adresse non utilisée ici. *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
* *
-* Description : Fournit le nom humain de l'instruction manipulée. *
+* Description : Fournit la place mémoire d'une instruction. *
* *
-* Retour : Valeur associée à la propriété consultée. *
+* Retour : Définition de localisation ou *None*. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *unused)
+static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure)
{
- PyObject *result; /* Trouvailles à retourner */
- GArchInstruction *instr; /* Version native */
- const char *kw; /* Valeur récupérée */
+ PyObject *result; /* Valeur à retourner */
+ GArchInstruction *instr; /* Instruction manipulée */
+ mrange_t range; /* Localisation d'instruction */
+ bool valid; /* Validité de la localisation */
+
+#define ARCH_INSTRUCTION_RANGE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ range, py_arch_instruction, \
+ "Give access to the memory range covered by the" \
+ " current instruction.\n" \
+ "\n" \
+ "The returned value is a pychrysalide.arch.mrange" \
+ " instance or *None* if no location is currently" \
+ " defined." \
+)
instr = G_ARCH_INSTRUCTION(pygobject_get(self));
- kw = g_arch_instruction_get_keyword(instr);
- result = PyUnicode_FromString(kw);
+ valid = g_arch_instruction_get_range(instr, &range);
+
+ if (valid)
+ result = build_from_internal_mrange(&range);
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
return result;
@@ -801,45 +1200,25 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *unused)
PyTypeObject *get_python_arch_instruction_type(void)
{
static PyMethodDef py_arch_instruction_methods[] = {
- {
- "attach_operand", py_arch_instruction_attach_extra_operand,
- METH_VARARGS,
- "attach_operand($self, op, /)\n--\n\nAdd a new operand to the instruction."
- },
- {
- "replace_operand", py_arch_instruction_replace_operand,
- METH_VARARGS,
- "replace_operand($self, old, new, /)\n--\n\nReplace an old instruction operand by a another one."
- },
- {
- "detach_operand", py_arch_instruction_detach_operand,
- METH_VARARGS,
- "detach_operand($self, target, /)\n--\n\nRemove an operand from the instruction."
- },
+ ARCH_INSTRUCTION_ATTACH_OPERAND_METHOD,
+ ARCH_INSTRUCTION_REPLACE_OPERAND_METHOD,
+ ARCH_INSTRUCTION_DETACH_OPERAND_METHOD,
ARCH_INSTRUCTION_FIND_OPERAND_PATH_METHOD,
ARCH_INSTRUCTION_GET_OPERAND_FROM_PATH_METHOD,
+ ARCH_INSTRUCTION_SET_FLAG_METHOD,
+ ARCH_INSTRUCTION_UNSET_FLAG_METHOD,
+ ARCH_INSTRUCTION_HAS_FLAG_METHOD,
{ NULL }
};
static PyGetSetDef py_arch_instruction_getseters[] = {
- {
- "uid", py_arch_instruction_get_unique_id, NULL,
- "Provide the unique identification number given to this kind of instruction.", NULL
- },
- {
- "range", py_arch_instruction_get_range, py_arch_instruction_set_range,
- "Give access to the memory range covered by the current instruction.", NULL
- },
- {
- "keyword", (getter)py_arch_instruction_get_keyword, (setter)NULL,
- "Give le name of the assembly instruction.", NULL
- },
- {
- "operands", (getter)py_arch_instruction_get_operands, (setter)NULL,
- "Provide the list of instruction attached operands.", NULL
- },
ARCH_INSTRUCTION_SOURCES_ATTRIB,
ARCH_INSTRUCTION_DESTINATIONS_ATTRIB,
+ ARCH_INSTRUCTION_OPERANDS_ATTRIB,
+ ARCH_INSTRUCTION_TYPE_ID_ATTRIB,
+ ARCH_INSTRUCTION_ENCODING_ATTRIB,
+ ARCH_INSTRUCTION_KEYWORD_ATTRIB,
+ ARCH_INSTRUCTION_RANGE_ATTRIB,
{ NULL }
};
@@ -852,7 +1231,7 @@ PyTypeObject *get_python_arch_instruction_type(void)
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE,
- .tp_doc = "PyChrysalide instruction for a given architecture.",
+ .tp_doc = ARCH_INSTRUCTION_DOC,
.tp_methods = py_arch_instruction_methods,
.tp_getset = py_arch_instruction_getseters,
@@ -893,9 +1272,14 @@ bool ensure_python_arch_instruction_is_registered(void)
dict = PyModule_GetDict(module);
- if (!ensure_python_line_generator_is_registered())
+ if (!ensure_python_thick_object_is_registered())
return false;
+ if (!ensure_python_serializable_object_is_registered())
+ return false;
+
+ pyg_register_class_init(G_TYPE_ARCH_INSTRUCTION, (PyGClassInitFunc)py_arch_instruction_init_gclass);
+
if (!register_class_for_pygobject(dict, G_TYPE_ARCH_INSTRUCTION, type))
return false;
diff --git a/plugins/pychrysalide/arch/instructions/Makefile.am b/plugins/pychrysalide/arch/instructions/Makefile.am
index 65efe42..29c2a45 100644
--- a/plugins/pychrysalide/arch/instructions/Makefile.am
+++ b/plugins/pychrysalide/arch/instructions/Makefile.am
@@ -7,7 +7,8 @@ libpychrysaarchinstructions_la_SOURCES = \
raw.h raw.c \
undefined.h undefined.c
-libpychrysaarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+libpychrysaarchinstructions_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ $(TOOLKIT_CFLAGS) \
-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
diff --git a/plugins/pychrysalide/arch/instructions/constants.c b/plugins/pychrysalide/arch/instructions/constants.c
index af7baa9..257c501 100644
--- a/plugins/pychrysalide/arch/instructions/constants.c
+++ b/plugins/pychrysalide/arch/instructions/constants.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* constants.c - ajout des constantes de base pour les instructions
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -112,3 +112,59 @@ bool define_undefined_instruction_constants(PyTypeObject *type)
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 ExpectedBehavior. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_undefined_expected_behavior(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ unsigned long value; /* Valeur récupérée */
+
+ 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 ExpectedBehavior");
+ break;
+
+ case 1:
+ value = PyLong_AsUnsignedLong(arg);
+
+ if (value > IEB_RESERVED)
+ {
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ExpectedBehavior");
+ result = 0;
+ }
+
+ else
+ *((InstrExpectedBehavior *)dst) = value;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/arch/instructions/constants.h b/plugins/pychrysalide/arch/instructions/constants.h
index 2f0c587..b6ef9a4 100644
--- a/plugins/pychrysalide/arch/instructions/constants.h
+++ b/plugins/pychrysalide/arch/instructions/constants.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* constants.h - prototypes pour l'ajout des constantes de base pour les instructions
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -37,6 +37,9 @@ bool define_raw_instruction_constants(PyTypeObject *);
/* Définit les constantes liées aux comportements erratiques. */
bool define_undefined_instruction_constants(PyTypeObject *);
+/* Tente de convertir en constante ExpectedBehavior. */
+int convert_to_undefined_expected_behavior(PyObject *, void *);
+
#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_INSTRUCTIONS_CONSTANTS_H */
diff --git a/plugins/pychrysalide/arch/instructions/raw.c b/plugins/pychrysalide/arch/instructions/raw.c
index 7e58b96..ae730e8 100644
--- a/plugins/pychrysalide/arch/instructions/raw.c
+++ b/plugins/pychrysalide/arch/instructions/raw.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* raw.c - équivalent Python du fichier "arch/instructions/raw.h"
*
- * Copyright (C) 2018-2020 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -28,26 +28,33 @@
#include <pygobject.h>
-#include <i18n.h>
-#include <arch/instructions/raw.h>
-#include <plugins/dt.h>
+#include <arch/instructions/raw-int.h>
#include "constants.h"
#include "../instruction.h"
#include "../vmpa.h"
#include "../../access.h"
+#include "../../constants.h"
#include "../../helpers.h"
#include "../../analysis/content.h"
+#include "../../glibext/portion.h"
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_raw_instruction_new(PyTypeObject *, PyObject *, PyObject *);
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+CREATE_DYN_CONSTRUCTOR(raw_instruction, G_TYPE_RAW_INSTRUCTION);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_raw_instruction_init(PyObject *, PyObject *, PyObject *);
+
+
+/* ------------------------ FONCTIONNALITES DE L'INSTRUCTION ------------------------ */
+
+
/* Indique si le contenu de l'instruction est du bourrage. */
static PyObject *py_raw_instruction_get_padding(PyObject *, void *);
@@ -62,64 +69,9 @@ static int py_raw_instruction_set_string(PyObject *, 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_raw_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_raw_instruction_type();
-
- if (type == base)
- goto simple_way;
-
- /* Mise en place d'un type dédié */
-
- first_time = (g_type_from_name(type->tp_name) == 0);
-
- gtype = build_dynamic_type(G_TYPE_RAW_INSTRUCTION, type->tp_name, NULL, 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() */
-
- simple_way:
-
- result = PyType_GenericNew(type, args, kwds);
-
- exit:
-
- return result;
-
-}
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
@@ -139,20 +91,17 @@ static PyObject *py_raw_instruction_new(PyTypeObject *type, PyObject *args, PyOb
static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwds)
{
int result; /* Bilan à retourner */
+ GBinaryPortion *area; /* Zone de contenance */
vmpa2t *addr; /* Texte de lecture */
- unsigned long mem_size; /* Taille de portion brute */
+ MemoryDataSize size; /* Taille de portion brute */
unsigned long long value; /* Valeur brute à considérer */
GBinContent *content; /* Contenu à lire au besoin */
unsigned long count; /* Nombre d'éléments à lister */
- unsigned int endian; /* Type de boutisme impliqué */
+ SourceEndian endian; /* Type de boutisme impliqué */
int ret; /* Bilan de lecture des args. */
- GArchInstruction *fake; /* Instruction à copier */
- GArchInstruction *instr; /* Instruction à manipuler */
- size_t op_count; /* Nombre d'opérande à copier */
- size_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à transférer */
+ GRawInstruction *instr; /* Instruction à manipuler */
- static char *kwlist[] = { "addr", "mem_size", "value", "content", "count", "endian", NULL };
+ static char *kwlist[] = { "area", "addr", "size", "value", "content", "count", "endian", NULL };
#define RAW_INSTRUCTION_DOC \
"The RawInstruction object handles data which is not (yet?) disassembled" \
@@ -187,9 +136,14 @@ static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwd
count = 0;
endian = 0;
- ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&k|KO&kI", kwlist,
- convert_any_to_vmpa, &addr, &mem_size,
- &value, convert_to_binary_content, &content, &count, &endian);
+ ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&O&O&|KO&kO&", kwlist,
+ convert_to_binary_portion, &area,
+ convert_any_to_vmpa, &addr,
+ convert_to_memory_data_size, &size,
+ &value,
+ convert_to_binary_content, &content,
+ &count,
+ convert_to_source_endian, &endian);
if (!ret) return -1;
/* Initialisation d'un objet GLib */
@@ -199,35 +153,19 @@ static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwd
/* Eléments de base */
- if (content != NULL)
- fake = g_raw_instruction_new_array(content, mem_size, count, addr, endian);
- else
- fake = g_raw_instruction_new_from_value(addr, mem_size, value);
+ instr = G_RAW_INSTRUCTION(pygobject_get(self));
- if (fake == NULL)
+ if (content != NULL)
{
- PyErr_SetString(PyExc_ValueError, _("Unable to build the object with the given parameters."));
- goto clean_exit;
+ if (!g_raw_instruction_create_array(instr, area, addr, size, content, count, endian))
+ goto clean_exit;
}
-
- instr = G_ARCH_INSTRUCTION(pygobject_get(self));
-
- g_arch_instruction_lock_operands(fake);
-
- op_count = _g_arch_instruction_count_operands(fake);
-
- for (i = 0; i < op_count; i++)
+ else
{
- op = _g_arch_instruction_get_operand(fake, i);
- g_arch_instruction_attach_extra_operand(instr, op);
+ if (!g_raw_instruction_create_value(instr, area, addr, size, value))
+ goto clean_exit;
}
- g_arch_instruction_unlock_operands(fake);
-
- g_arch_instruction_set_range(instr, g_arch_instruction_get_range(fake));
-
- g_object_unref(G_OBJECT(fake));
-
result = 0;
clean_exit:
@@ -239,6 +177,12 @@ static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwd
}
+
+/* ---------------------------------------------------------------------------------- */
+/* FONCTIONNALITES DE L'INSTRUCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : self = classe représentant une instruction. *
@@ -271,7 +215,6 @@ static PyObject *py_raw_instruction_get_padding(PyObject *self, void *closure)
result = state ? Py_True : Py_False;
Py_INCREF(result);
-
return result;
}
@@ -342,7 +285,6 @@ static PyObject *py_raw_instruction_get_string(PyObject *self, void *closure)
result = state ? Py_True : Py_False;
Py_INCREF(result);
-
return result;
}
diff --git a/plugins/pychrysalide/arch/instructions/undefined.c b/plugins/pychrysalide/arch/instructions/undefined.c
index 1246daa..1c2bccc 100644
--- a/plugins/pychrysalide/arch/instructions/undefined.c
+++ b/plugins/pychrysalide/arch/instructions/undefined.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* undefined.c - équivalent Python du fichier "arch/instructions/undefined.h"
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -28,9 +28,7 @@
#include <pygobject.h>
-#include <i18n.h>
#include <arch/instructions/undefined-int.h>
-#include <plugins/dt.h>
#include "constants.h"
@@ -40,75 +38,27 @@
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_undef_instruction_new(PyTypeObject *, PyObject *, PyObject *);
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Initialise une instance sur la base du dérivé de GObject. */
-static int py_undef_instruction_init(PyObject *, PyObject *, PyObject *);
-
-/* Indique le type de conséquences réél de l'instruction. */
-static PyObject *py_undef_instruction_get_behavior(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_undef_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_undefined_instruction_type();
+CREATE_DYN_CONSTRUCTOR(undefined_instruction, G_TYPE_UNDEFINED_INSTRUCTION);
- if (type == base)
- goto simple_way;
-
- /* Mise en place d'un type dédié */
-
- first_time = (g_type_from_name(type->tp_name) == 0);
-
- gtype = build_dynamic_type(G_TYPE_UNDEF_INSTRUCTION, type->tp_name, NULL, NULL, NULL);
-
- if (first_time)
- {
- status = register_class_for_dynamic_pygobject(gtype, type);
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_undefined_instruction_init(PyObject *, PyObject *, PyObject *);
- if (!status)
- {
- result = NULL;
- goto exit;
- }
- }
- /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
+/* ------------------------ FONCTIONNALITES DE L'INSTRUCTION ------------------------ */
- simple_way:
- result = PyType_GenericNew(type, args, kwds);
+/* Indique le type de conséquences réél de l'instruction. */
+static PyObject *py_undefined_instruction_get_behavior(PyObject *, void *);
- exit:
- return result;
-}
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
@@ -125,30 +75,27 @@ static PyObject *py_undef_instruction_new(PyTypeObject *type, PyObject *args, Py
* *
******************************************************************************/
-static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *kwds)
+static int py_undefined_instruction_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- unsigned long behavior; /* Conséquence pour l'instruct°*/
+ InstrExpectedBehavior behavior; /* Conséquence pour l'instruct°*/
int ret; /* Bilan de lecture des args. */
- GUndefInstruction *instr; /* Instruction à manipuler */
- undef_extra_data_t *extra; /* Données insérées à modifier */
+ GUndefinedInstruction *instr; /* Instruction à manipuler */
- static char *kwlist[] = { "behavior", NULL };
-
-#define UNDEF_INSTRUCTION_DOC \
- "UndefInstruction represents all kinds of instructions which are" \
+#define UNDEFINED_INSTRUCTION_DOC \
+ "UndefinedInstruction represents all kinds of instructions which are" \
" officially not part of a runnable instruction set.\n" \
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
- " UndefInstruction(behavior)" \
+ " UndefinedInstruction(behavior)" \
"\n" \
"Where behavior is a" \
- " pychrysalide.arch.instructions.UndefInstruction.ExpectedBehavior" \
+ " pychrysalide.arch.instructions.UndefinedInstruction.ExpectedBehavior" \
" constant describing the state of the CPU once the instruction is run."
/* Récupération des paramètres */
- ret = PyArg_ParseTupleAndKeywords(args, kwds, "k", kwlist, &behavior);
+ ret = PyArg_ParseTuple(args, "O&", convert_to_undefined_expected_behavior, &behavior);
if (!ret) return -1;
/* Initialisation d'un objet GLib */
@@ -158,17 +105,22 @@ static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *k
/* Eléments de base */
- instr = G_UNDEF_INSTRUCTION(pygobject_get(self));
-
- extra = GET_UNDEF_INSTR_EXTRA(instr);
+ instr = G_UNDEFINED_INSTRUCTION(pygobject_get(self));
- extra->behavior = behavior;
+ if (!g_undefined_instruction_create(instr, behavior))
+ return -1;
return 0;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* FONCTIONNALITES DE L'INSTRUCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : self = classe représentant une instruction. *
@@ -182,24 +134,25 @@ static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *k
* *
******************************************************************************/
-static PyObject *py_undef_instruction_get_behavior(PyObject *self, void *closure)
+static PyObject *py_undefined_instruction_get_behavior(PyObject *self, void *closure)
{
PyObject *result; /* Conversion à retourner */
- GUndefInstruction *instr; /* Version native */
+ GUndefinedInstruction *instr; /* Version native */
InstrExpectedBehavior behavior; /* Comportement attendu */
-#define UNDEF_INSTRUCTION_BEHAVIOR_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- behavior, py_undef_instruction, \
- "Consequence carried by the undefined instruction.\n" \
- "\n" \
- "The result is provided as a" \
- " pychrysalide.arch.instructions.UndefInstruction.ExpectedBehavior" \
- " constant." \
+#define UNDEFINED_INSTRUCTION_BEHAVIOR_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ behavior, py_undefined_instruction, \
+ "Consequence carried by the undefined instruction.\n" \
+ "\n" \
+ "The result is provided as a" \
+ " pychrysalide.arch.instructions.UndefinedInstruction.ExpectedBehavior" \
+ " constant." \
)
- instr = G_UNDEF_INSTRUCTION(pygobject_get(self));
- behavior = g_undef_instruction_get_behavior(instr);
+ instr = G_UNDEFINED_INSTRUCTION(pygobject_get(self));
+
+ behavior = g_undefined_instruction_get_behavior(instr);
result = cast_with_constants_group_from_type(get_python_undefined_instruction_type(),
"ExpectedBehavior", behavior);
@@ -228,7 +181,7 @@ PyTypeObject *get_python_undefined_instruction_type(void)
};
static PyGetSetDef py_undefined_instruction_getseters[] = {
- UNDEF_INSTRUCTION_BEHAVIOR_ATTRIB,
+ UNDEFINED_INSTRUCTION_BEHAVIOR_ATTRIB,
{ NULL }
};
@@ -236,18 +189,18 @@ PyTypeObject *get_python_undefined_instruction_type(void)
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.arch.instructions.UndefInstruction",
+ .tp_name = "pychrysalide.arch.instructions.UndefinedInstruction",
.tp_basicsize = sizeof(PyGObject),
.tp_flags = Py_TPFLAGS_DEFAULT,
- .tp_doc = UNDEF_INSTRUCTION_DOC,
+ .tp_doc = UNDEFINED_INSTRUCTION_DOC,
.tp_methods = py_undefined_instruction_methods,
.tp_getset = py_undefined_instruction_getseters,
- .tp_init = py_undef_instruction_init,
- .tp_new = py_undef_instruction_new,
+ .tp_init = py_undefined_instruction_init,
+ .tp_new = py_undefined_instruction_new,
};
@@ -260,7 +213,7 @@ PyTypeObject *get_python_undefined_instruction_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide.....UndefInstruction'. *
+* Description : Prend en charge l'objet '....UndefinedInstruction'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -285,7 +238,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))
+ if (!register_class_for_pygobject(dict, G_TYPE_UNDEFINED_INSTRUCTION, type))
return false;
if (!define_undefined_instruction_constants(type))
@@ -329,7 +282,7 @@ int convert_to_undefined_instruction(PyObject *arg, void *dst)
break;
case 1:
- *((GUndefInstruction **)dst) = G_UNDEF_INSTRUCTION(pygobject_get(arg));
+ *((GUndefinedInstruction **)dst) = G_UNDEFINED_INSTRUCTION(pygobject_get(arg));
break;
default:
diff --git a/plugins/pychrysalide/arch/instructions/undefined.h b/plugins/pychrysalide/arch/instructions/undefined.h
index 3fa0453..1453612 100644
--- a/plugins/pychrysalide/arch/instructions/undefined.h
+++ b/plugins/pychrysalide/arch/instructions/undefined.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* undefined.h - prototypes pour l'équivalent Python du fichier "arch/instructions/undefined.h"
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -34,7 +34,7 @@
/* Fournit un accès à une définition de type à diffuser. */
PyTypeObject *get_python_undefined_instruction_type(void);
-/* Prend en charge l'objet 'pychrysalide.arch.instructions.UndefInstruction'. */
+/* Prend en charge l'objet 'pychrysalide.arch.instructions.UndefinedInstruction'. */
bool ensure_python_undefined_instruction_is_registered(void);
/* Tente de convertir en instruction non définie. */
diff --git a/plugins/pychrysalide/arch/module-ui.c b/plugins/pychrysalide/arch/module-ui.c
new file mode 100644
index 0000000..65d1290
--- /dev/null
+++ b/plugins/pychrysalide/arch/module-ui.c
@@ -0,0 +1,66 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire arch (forme graphique) en tant que module
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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-ui.h"
+
+
+#include <assert.h>
+
+
+#include "operand-ui.h"
+#include "../glibext/generator.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'arch' (mode UI). *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_arch_module_ui(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_arch_operand_ui_is_registered();
+
+ /**
+ * Préparation du terrain pour les instructions, sans lien directe
+ * de la partie UI depuis la partie NOX.
+ */
+ if (result) result = ensure_python_token_generator_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/arch/module-ui.h b/plugins/pychrysalide/arch/module-ui.h
new file mode 100644
index 0000000..afa31d2
--- /dev/null
+++ b/plugins/pychrysalide/arch/module-ui.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire arch (forme graphique) en tant que module
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_ARCH_MODULE_UI_H
+#define _PLUGINS_PYCHRYSALIDE_ARCH_MODULE_UI_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+/* Intègre les objets du module 'arch' (mode UI). */
+bool populate_arch_module_ui(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_MODULE_UI_H */
diff --git a/plugins/pychrysalide/arch/module.c b/plugins/pychrysalide/arch/module.c
index 0127348..94f5ad7 100644
--- a/plugins/pychrysalide/arch/module.c
+++ b/plugins/pychrysalide/arch/module.c
@@ -31,16 +31,14 @@
/*
#include "context.h"
#include "instriter.h"
+*/
#include "instruction.h"
#include "operand.h"
-#include "processor.h"
+//#include "processor.h"
#include "register.h"
-*/
#include "vmpa.h"
-/*
#include "instructions/module.h"
#include "operands/module.h"
-*/
#include "../helpers.h"
@@ -77,10 +75,8 @@ bool add_arch_module(PyObject *super)
result = (module != NULL);
- /*
if (result) result = add_arch_instructions_module(module);
if (result) result = add_arch_operands_module(module);
- */
return result;
@@ -108,18 +104,16 @@ bool populate_arch_module(void)
/*
if (result) result = ensure_python_proc_context_is_registered();
if (result) result = ensure_python_instr_iterator_is_registered();
+ */
if (result) result = ensure_python_arch_instruction_is_registered();
if (result) result = ensure_python_arch_operand_is_registered();
- if (result) result = ensure_python_arch_processor_is_registered();
+ //if (result) result = ensure_python_arch_processor_is_registered();
if (result) result = ensure_python_arch_register_is_registered();
- */
if (result) result = ensure_python_vmpa_is_registered();
if (result) result = ensure_python_mrange_is_registered();
- /*
if (result) result = populate_arch_instructions_module();
if (result) result = populate_arch_operands_module();
- */
assert(result);
diff --git a/plugins/pychrysalide/arch/operand-ui.c b/plugins/pychrysalide/arch/operand-ui.c
new file mode 100644
index 0000000..5062513
--- /dev/null
+++ b/plugins/pychrysalide/arch/operand-ui.c
@@ -0,0 +1,461 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * operand-ui.c - équivalent Python du fichier "arch/operand-ui.c"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "operand-ui.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <arch/operand-ui-int.h>
+
+
+#include "../access.h"
+#include "../helpers.h"
+
+
+
+/* Procède à l'initialisation de l'interface d'exportation. */
+static void py_arch_operand_ui_interface_init(GArchOperandUIInterface *, gpointer *);
+
+/* Traduit un opérande en version humainement lisible. */
+static void py_arch_operand_ui_print_wrapper(const GArchOperandUI *, GBufferLine *);
+
+/* Construit un petit résumé concis de l'opérande. */
+static char *py_arch_operand_ui_build_tooltip_wrapper(const GArchOperandUI *, const GLoadedBinary *);
+
+/* Traduit un opérande en version humainement lisible. */
+static PyObject *py_arch_operand_ui_print(PyObject *, PyObject *);
+
+/* Construit un petit résumé concis de l'opérande. */
+static PyObject *py_arch_operand_ui_build_tooltip(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* unused = adresse non utilisée ici. *
+* *
+* Description : Procède à l'initialisation de l'interface d'exportation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_arch_operand_ui_interface_init(GArchOperandUIInterface *iface, gpointer *unused)
+{
+#define ARCH_OPERAND_UI_DOC \
+ "The ArchOperandUI interface ensure pychrysalide.arch.ArchOperand" \
+ " implementations provide UI features when Chrysalide is running with" \
+ " a GUI.\n" \
+ "\n" \
+ "A typical class declaration for a new implementation looks like:\n" \
+ "\n" \
+ " class NewImplem(ArchOperand, ArchOperandUi):\n" \
+ " ...\n" \
+ "\n" \
+ "The following method has to be defined for new implementations:\n" \
+ "* pychrysalide.arch.ArchOperandUI._print();\n" \
+ "* pychrysalide.arch.ArchOperandUI._build_tooltip().\n"
+
+ iface->print = py_arch_operand_ui_print_wrapper;
+ iface->build_tooltip = py_arch_operand_ui_build_tooltip_wrapper;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = registre visé par la procédure. *
+* *
+* Description : Traduit un opérande en version humainement lisible. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_arch_operand_ui_print_wrapper(const GArchOperandUI *operand, GBufferLine *line)
+{
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
+ PyObject *pyret; /* Bilan de consultation */
+
+#define ARCH_OPERAND_UI_PRINT_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _print, "$self, line, /", \
+ METH_VARARGS, \
+ "Abstract method used to print an operand into a rendering" \
+ " *line*, which is a provided pychrysalide.glibext.BufferLine" \
+ " instance." \
+)
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(operand));
+
+ if (has_python_method(pyobj, "_print"))
+ {
+ args = PyTuple_New(1);
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line)));
+
+ pyret = run_python_method(pyobj, "_print", args);
+
+ Py_XDECREF(pyret);
+
+ Py_DECREF(args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande à consulter. *
+* binary = informations relatives au binaire chargé. *
+* *
+* Description : Construit un petit résumé concis de l'opérande. *
+* *
+* Retour : Chaîne de caractères à libérer après usage ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *py_arch_operand_ui_build_tooltip_wrapper(const GArchOperandUI *operand, const GLoadedBinary *binary)
+{
+ char *result; /* Description à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
+ PyObject *pyret; /* Bilan de consultation */
+
+#define ARCH_OPERAND_UI_BUILD_TOOLTIP_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _build_tooltip, "$self, binary, /", \
+ METH_VARARGS, \
+ "Abstract method used to build a tooltip text shown when the" \
+ " mouse is over an operand.\n" \
+ "\n" \
+ "A pychrysalide.analysis.LoadedBinary instance is provided in" \
+ " case of need." \
+)
+
+ result = NULL;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(operand));
+
+ if (has_python_method(pyobj, "_build_tooltip"))
+ {
+ args = PyTuple_New(1);
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(binary)));
+
+ pyret = run_python_method(pyobj, "_build_tooltip", args);
+
+ if (pyret != NULL)
+ {
+ if (PyUnicode_Check(pyret))
+ result = strdup(PyUnicode_AsUTF8(pyret));
+ }
+
+ Py_XDECREF(pyret);
+
+ Py_DECREF(args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet manipulé ici. *
+* args = adresse non utilisée ici. *
+* *
+* Description : Traduit un opérande en version humainement lisible. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_arch_operand_ui_print(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Emplacement à retourner */
+
+#if 0 // TODO
+
+ GBufferLine *line; /* Zone d'impression du rendu */
+ int ret; /* Bilan de lecture des args. */
+ GArchOperandUI *operand; /* Mécanismes natifs */
+
+#define ARCH_OPERAND_UI_PRINT_METHOD PYTHON_METHOD_DEF \
+( \
+ print, "$self, line", \
+ METH_VARARGS, py_arch_operand_ui, \
+ "Translate an operand into a human readable version.\n" \
+ "\n" \
+ "The *line* arguement is a pychrysalide.glibext.BufferLine" \
+ " instance which has to get filled with rendering" \
+ " information.\n" \
+ "\n" \
+ "The result returns nothing (*None*)." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_buffer_line, &line);
+ if (!ret) return NULL;
+
+ operand = G_ARCH_OPERAND_UI(pygobject_get(self));
+
+ g_arch_operand_ui_print(operand, line);
+
+#endif
+
+ result = Py_None;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet manipulé ici. *
+* args = adresse non utilisée ici. *
+* *
+* Description : Construit un petit résumé concis de l'opérande. *
+* *
+* Retour : Chaîne de caractères à libérer après usage ou None. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_arch_operand_ui_build_tooltip(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Emplacement à retourner */
+
+#if 0 // TODO
+
+ GLoadedBinary *binary; /* Infos sur le binaire chargé */
+ int ret; /* Bilan de lecture des args. */
+ GArchOperandUI *operand; /* Mécanismes natifs */
+ char *tooltip; /* Eventuelle indication */
+
+#define ARCH_OPERAND_UI_BUILD_TOOLTIP_METHOD PYTHON_METHOD_DEF \
+( \
+ build_tooltip, "$self, binary", \
+ METH_VARARGS, py_arch_operand_ui, \
+ "Build a tooltip text shown when the mouse is over an" \
+ " operand.\n" \
+ "\n" \
+ "The *binary* argument is a pychrysalide.analysis.LoadedBinary" \
+ " instance provided in case of need." \
+ "\n" \
+ "The result is a string or *None* in case of error." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_loaded_binary, &binary);
+ if (!ret) return NULL;
+
+ operand = G_ARCH_OPERAND_UI(pygobject_get(self));
+
+ tooltip = g_arch_operand_ui_build_tooltip(operand, binary);
+
+ if (tooltip != NULL)
+ {
+ PyUnicode_FromString(tooltip);
+ free(tooltip);
+ }
+ else
+
+#endif
+
+ {
+ 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_arch_operand_ui_type(void)
+{
+ static PyMethodDef py_arch_operand_ui_methods[] = {
+ ARCH_OPERAND_UI_PRINT_WRAPPER,
+ ARCH_OPERAND_UI_BUILD_TOOLTIP_WRAPPER,
+#if 0 // TODO
+ ARCH_OPERAND_UI_PRINT_METHOD,
+ ARCH_OPERAND_UI_BUILD_TOOLTIP_METHOD,
+#endif
+ { NULL }
+ };
+
+ static PyGetSetDef py_arch_operand_ui_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_arch_operand_ui_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.arch.ArchOperandUI",
+ .tp_basicsize = sizeof(PyObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = ARCH_OPERAND_UI_DOC,
+
+ .tp_methods = py_arch_operand_ui_methods,
+ .tp_getset = py_arch_operand_ui_getseters
+
+ };
+
+ return &py_arch_operand_ui_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.arch.ArchOperandUI'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_arch_operand_ui_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ArchOperandUI' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ static GInterfaceInfo info = { /* Paramètres d'inscription */
+
+ .interface_init = (GInterfaceInitFunc)py_arch_operand_ui_interface_init,
+ .interface_finalize = NULL,
+ .interface_data = NULL,
+
+ };
+
+ type = get_python_arch_operand_ui_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.arch");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_interface_for_pygobject(dict, G_TYPE_ARCH_OPERAND_UI, type, &info))
+ 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 interface d'exportation graphique. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_arch_operand_ui(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_arch_operand_ui_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 UI arch operand");
+ break;
+
+ case 1:
+ *((GArchOperandUI **)dst) = G_ARCH_OPERAND_UI(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/arch/operand-ui.h b/plugins/pychrysalide/arch/operand-ui.h
new file mode 100644
index 0000000..b9e2131
--- /dev/null
+++ b/plugins/pychrysalide/arch/operand-ui.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * operand-ui.h - prototypes pour l'équivalent Python du fichier "arch/operand-ui.h"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_ARCH_OPERAND_UI_H
+#define _PLUGINS_PYCHRYSALIDE_ARCH_OPERAND_UI_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_arch_operand_ui_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.arch.ArchOperandUI'. */
+bool ensure_python_arch_operand_ui_is_registered(void);
+
+/* Tente de convertir en interface d'exportation graphique. */
+int convert_to_arch_operand_ui(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERAND_UI_H */
diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c
index 0aee4f7..2281dae 100644
--- a/plugins/pychrysalide/arch/operand.c
+++ b/plugins/pychrysalide/arch/operand.c
@@ -30,23 +30,32 @@
#include <i18n.h>
#include <arch/operand-int.h>
-#include <plugins/dt.h>
+#include <glibext/strbuilder-int.h>
#include "../access.h"
#include "../helpers.h"
+#include "../glibext/comparable.h"
+#include "../glibext/hashable.h"
+#include "../glibext/objhole.h"
+#include "../glibext/serialize.h"
#include "../glibext/singleton.h"
+#include "../glibext/strbuilder.h"
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_arch_operand_new(PyTypeObject *, PyObject *, PyObject *);
-
/* Initialise la classe générique des opérandes. */
-static void py_arch_operand_init_gclass(GArchOperandClass *, gpointer);
+static int py_arch_operand_init_gclass(GArchOperandClass *, PyTypeObject *);
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_operand, G_TYPE_ARCH_OPERAND);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_arch_operand_init(PyObject *, PyObject *, PyObject *);
+
+#if 0
/* Compare un opérande avec un autre. */
static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *, bool);
@@ -57,14 +66,6 @@ static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand
/* Obtient l'opérande correspondant à un chemin donné. */
static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const GArchOperand *, const char *);
-/* 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
@@ -72,6 +73,9 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *, const G
/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
+#if 0
+
+
/* Effectue une comparaison avec un objet Python 'ArchOperand'. */
static PyObject *py_arch_operand_richcompare(PyObject *, PyObject *, int);
@@ -81,6 +85,19 @@ static PyObject *py_arch_operand_find_inner_operand_path(PyObject *, PyObject *)
/* Obtient l'opérande correspondant à un chemin donné. */
static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *, PyObject *);
+#endif
+
+
+/* Ajoute une information complémentaire à un opérande. */
+static PyObject *py_arch_operand_set_flag(PyObject *, PyObject *);
+
+/* Retire une information complémentaire à un opérande. */
+static PyObject *py_arch_operand_unset_flag(PyObject *, PyObject *);
+
+/* Détermine si un opérande possède un fanion particulier. */
+static PyObject *py_arch_operand_has_flag(PyObject *, PyObject *);
+
+
/* ---------------------------------------------------------------------------------- */
@@ -90,113 +107,109 @@ static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *, PyObjec
/******************************************************************************
* *
-* Paramètres : type = type du nouvel objet à mettre en place. *
-* args = éventuelle liste d'arguments. *
-* kwds = éventuel dictionnaire de valeurs mises à disposition. *
+* Paramètres : gclass = classe GLib à initialiser. *
+* pyclass = classe Python à initialiser. *
* *
-* Description : Accompagne la création d'une instance dérivée en Python. *
+* Description : Initialise la classe générique des opérandes. *
* *
-* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. *
+* Retour : 0 pour indiquer un succès de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_arch_operand_init_gclass(GArchOperandClass *gclass, PyTypeObject *pyclass)
{
- 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 */
-
-#define ARCH_OPERAND_DOC \
- "The ArchOperand object aims to get subclassed to create" \
- " operands of any kind for new architectures.\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.arch.ArchRegister.__cmp__();\n" \
- "* pychrysalide.arch.ArchRegister._print();\n" \
- "* pychrysalide.arch.ArchRegister._build_tooltip().\n" \
- "\n" \
- "Some extra method definitions are optional for new classes:\n" \
- "* pychrysalide.arch.ArchRegister._find_inner_operand_path();\n" \
- "* pychrysalide.arch.ArchRegister._get_inner_operand_from_path().\n"\
- "\n" \
- "Chrysalide creates an internal glue to provide rich comparisons" \
- " for operands based on the old-style *__cmp__* function."
- /* Validations diverses */
+#if 0
+ GStringBuilderInterface *iface; /* Interface utilisée */
- base = get_python_arch_operand_type();
+ iface = g_type_interface_peek(gclass, G_TYPE_STRING_BUILDER);
- 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é */
+ /*
+ printf("???????? init Python Operand ?????????????? -> class: %p '%s' - strbuilder iface: %p\n",
+ gclass, g_type_name(G_TYPE_FROM_CLASS(gclass)), iface);
+ */
- first_time = (g_type_from_name(type->tp_name) == 0);
+#endif
- gtype = build_dynamic_type(G_TYPE_ARCH_OPERAND, type->tp_name,
- (GClassInitFunc)py_arch_operand_init_gclass, NULL, NULL);
+#if 0
- if (first_time)
- {
- status = register_class_for_dynamic_pygobject(gtype, type);
+ class->compare = py_arch_operand___cmp___wrapper;
+ class->find_inner = py_arch_operand_find_inner_operand_path_wrapper;
+ class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper;
- if (!status)
- {
- result = NULL;
- goto exit;
- }
- }
+#endif
- /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
- result = PyType_GenericNew(type, args, kwds);
- exit:
+ //PY_CLASS_SET_WRAPPER(gclass->xxx, py_arch_operand_xxx_wrapper);
- return result;
+ return 0;
}
/******************************************************************************
* *
-* Paramètres : class = classe à initialiser. *
-* unused = données non utilisées ici. *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
* *
-* Description : Initialise la classe générique des opérandes. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : - *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unused)
+static int py_arch_operand_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- class->compare = py_arch_operand___cmp___wrapper;
- class->find_inner = py_arch_operand_find_inner_operand_path_wrapper;
- class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper;
+ //unsigned int endianness; /* Boutisme du processeur */
+ int ret; /* Bilan de lecture des args. */
+ //GArchProcessor *proc; /* Processeur à manipuler */
- class->print = py_arch_operand_print_wrapper;
-#ifdef INCLUDE_GTK_SUPPORT
- class->build_tooltip = py_arch_operand_build_tooltip_wrapper;
-#endif
+#define ARCH_OPERAND_DOC \
+ "The ArchOperand object aims to get subclassed to create" \
+ " operands of any kind for new architectures.\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.arch.ArchRegister.__cmp__();\n" \
+ "* pychrysalide.arch.ArchRegister._print();\n" \
+ "* pychrysalide.arch.ArchRegister._build_tooltip().\n" \
+ "\n" \
+ "Some extra method definitions are optional for new classes:\n" \
+ "* pychrysalide.arch.ArchRegister._find_inner_operand_path();\n" \
+ "* pychrysalide.arch.ArchRegister._get_inner_operand_from_path().\n"\
+ "\n" \
+ "Chrysalide creates an internal glue to provide rich comparisons" \
+ " for operands based on the old-style *__cmp__* function."
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ //proc = G_ARCH_PROCESSOR(pygobject_get(self));
+
+ //proc->endianness = endianness;
+
+ return 0;
}
+
+#if 0
+
/******************************************************************************
* *
* Paramètres : a = premier opérande à consulter. *
@@ -410,126 +423,6 @@ static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const G
}
-/******************************************************************************
-* *
-* Paramètres : operand = registre visé par la procédure. *
-* *
-* Description : Traduit un opérande en version humainement lisible. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void py_arch_operand_print_wrapper(const GArchOperand *operand, GBufferLine *line)
-{
- PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyobj; /* Objet Python concerné */
- PyObject *args; /* Arguments pour l'appel */
- PyObject *pyret; /* Bilan de consultation */
-
-#define ARCH_OPERAND_PRINT_WRAPPER PYTHON_WRAPPER_DEF \
-( \
- _print, "$self, line, /", \
- METH_VARARGS, \
- "Abstract method used to print the operand into a rendering" \
- " line, which is a provided pychrysalide.glibext.BufferLine" \
- " instance." \
-)
-
- gstate = PyGILState_Ensure();
-
- pyobj = pygobject_new(G_OBJECT(operand));
-
- if (has_python_method(pyobj, "_print"))
- {
- args = PyTuple_New(1);
- PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line)));
-
- pyret = run_python_method(pyobj, "_print", args);
-
- Py_XDECREF(pyret);
-
- Py_DECREF(args);
-
- }
-
- Py_DECREF(pyobj);
-
- PyGILState_Release(gstate);
-
-}
-
-
-#ifdef INCLUDE_GTK_SUPPORT
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à consulter. *
-* binary = informations relatives au binaire chargé. *
-* *
-* Description : Construit un petit résumé concis de l'opérande. *
-* *
-* Retour : Chaîne de caractères à libérer après usage ou NULL. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand, const GLoadedBinary *binary)
-{
- char *result; /* Description à retourner */
- PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyobj; /* Objet Python concerné */
- PyObject *args; /* Arguments pour l'appel */
- PyObject *pyret; /* Bilan de consultation */
-
-#define ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER PYTHON_WRAPPER_DEF \
-( \
- _build_tooltip, "$self, line, /", \
- METH_VARARGS, \
- "Abstract method used to build a tooltip text shown when the" \
- " mouse is over the operand.\n" \
- "\n" \
- "A pychrysalide.analysis.LoadedBinary instance is provided in" \
- " case of need." \
-)
-
- result = NULL;
-
- gstate = PyGILState_Ensure();
-
- pyobj = pygobject_new(G_OBJECT(operand));
-
- if (has_python_method(pyobj, "_build_tooltip"))
- {
- args = PyTuple_New(1);
- PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(binary)));
-
- pyret = run_python_method(pyobj, "_build_tooltip", args);
-
- if (pyret != NULL)
- {
- if (PyUnicode_Check(pyret))
- result = strdup(PyUnicode_AsUTF8(pyret));
- }
-
- Py_XDECREF(pyret);
-
- Py_DECREF(args);
-
- }
-
- Py_DECREF(pyobj);
-
- PyGILState_Release(gstate);
-
- return result;
-
-}
-
#endif
@@ -540,6 +433,9 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand,
/* ---------------------------------------------------------------------------------- */
+
+#if 0
+
/******************************************************************************
* *
* Paramètres : a = premier object Python à consulter. *
@@ -701,6 +597,164 @@ static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *self, PyO
}
+#endif
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = architecture concernée par la procédure. *
+* args = instruction représentant le point de départ. *
+* *
+* Description : Ajoute une information complémentaire à un opérande. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_arch_operand_set_flag(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ unsigned int flag; /* Fanion(s) à appliquer */
+ int ret; /* Bilan de lecture des args. */
+ GArchOperand *operand; /* Opérande manipulé */
+ bool status; /* Bilan à transmettre */
+
+#define ARCH_OPERAND_SET_FLAG_METHOD PYTHON_METHOD_DEF \
+( \
+ set_flag, "$self, flag, /", \
+ METH_VARARGS, py_arch_operand, \
+ "Add some flags to the operand.\n" \
+ "\n" \
+ "This *flag* argument is an integer value containing" \
+ " bits to apply to the operand state.\n" \
+ "\n" \
+ "The result is an boolean status: *True* for operation" \
+ " success, *False* otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "I", &flag);
+ if (!ret) return NULL;
+
+ operand = G_ARCH_OPERAND(pygobject_get(self));
+
+ status = g_arch_operand_set_flag(operand, flag);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = architecture concernée par la procédure. *
+* args = instruction représentant le point de départ. *
+* *
+* Description : Retire une information complémentaire à un opérande. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_arch_operand_unset_flag(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ unsigned int flag; /* Fanion(s) à appliquer */
+ int ret; /* Bilan de lecture des args. */
+ GArchOperand *operand; /* Opérande manipulé */
+ bool status; /* Bilan à transmettre */
+
+#define ARCH_OPERAND_UNSET_FLAG_METHOD PYTHON_METHOD_DEF \
+( \
+ unset_flag, "$self, flag, /", \
+ METH_VARARGS, py_arch_operand, \
+ "Remove some flags from the operand.\n" \
+ "\n" \
+ "This *flag* argument is an integer value containing" \
+ " bits to delete from the operand state.\n" \
+ "\n" \
+ "The result is an boolean status: *True* for operation" \
+ " success, *False* otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "I", &flag);
+ if (!ret) return NULL;
+
+ operand = G_ARCH_OPERAND(pygobject_get(self));
+
+ status = g_arch_operand_unset_flag(operand, flag);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = architecture concernée par la procédure. *
+* args = instruction représentant le point de départ. *
+* *
+* Description : Détermine si un opérande possède un fanion particulier. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_arch_operand_has_flag(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Bilan à retourner */
+ unsigned int flag; /* Fanion(s) à appliquer */
+ int ret; /* Bilan de lecture des args. */
+ GArchOperand *operand; /* Opérande manipulé */
+ bool status; /* Bilan à transmettre */
+
+#define ARCH_OPERAND_HAS_FLAG_METHOD PYTHON_METHOD_DEF \
+( \
+ has_flag, "$self, flag, /", \
+ METH_VARARGS, py_arch_operand, \
+ "Tell if some flags are set for the operand.\n" \
+ "\n" \
+ "This *flag* argument is an integer value containing" \
+ " bits to test for the operand state.\n" \
+ "\n" \
+ "The result is an boolean status: *True* if the bits" \
+ " are active, *False* otherwise." \
+)
+
+ ret = PyArg_ParseTuple(args, "I", &flag);
+ if (!ret) return NULL;
+
+ operand = G_ARCH_OPERAND(pygobject_get(self));
+
+ status = g_arch_operand_has_flag(operand, flag);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
/******************************************************************************
* *
@@ -717,6 +771,11 @@ static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *self, PyO
PyTypeObject *get_python_arch_operand_type(void)
{
static PyMethodDef py_arch_operand_methods[] = {
+ ARCH_OPERAND_SET_FLAG_METHOD,
+ ARCH_OPERAND_UNSET_FLAG_METHOD,
+ ARCH_OPERAND_HAS_FLAG_METHOD,
+
+ /*
ARCH_OPERAND_CMP_WRAPPER,
ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER,
ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER,
@@ -726,6 +785,7 @@ PyTypeObject *get_python_arch_operand_type(void)
#endif
ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD,
ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD,
+ */
{ NULL }
};
@@ -744,11 +804,12 @@ PyTypeObject *get_python_arch_operand_type(void)
.tp_doc = ARCH_OPERAND_DOC,
- .tp_richcompare = py_arch_operand_richcompare,
+ //.tp_richcompare = py_arch_operand_richcompare,
.tp_methods = py_arch_operand_methods,
.tp_getset = py_arch_operand_getseters,
+ .tp_init = py_arch_operand_init,
.tp_new = py_arch_operand_new,
};
@@ -784,9 +845,26 @@ bool ensure_python_arch_operand_is_registered(void)
dict = PyModule_GetDict(module);
+ if (!ensure_python_thick_object_is_registered())
+ return false;
+
+ if (!ensure_python_comparable_object_is_registered())
+ return false;
+
+ if (!ensure_python_hashable_object_is_registered())
+ return false;
+
+ if (!ensure_python_serializable_object_is_registered())
+ return false;
+
if (!ensure_python_singleton_candidate_is_registered())
return false;
+ if (!ensure_python_string_builder_is_registered())
+ return false;
+
+ pyg_register_class_init(G_TYPE_ARCH_OPERAND, (PyGClassInitFunc)py_arch_operand_init_gclass);
+
if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type))
return false;
diff --git a/plugins/pychrysalide/arch/operand.h b/plugins/pychrysalide/arch/operand.h
index 9cb40a0..f3bfbf2 100644
--- a/plugins/pychrysalide/arch/operand.h
+++ b/plugins/pychrysalide/arch/operand.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* operand.h - prototypes pour l'équivalent Python du fichier "arch/operand.h"
*
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2018-2024 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -31,9 +31,6 @@
-/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
-
-
/* Fournit un accès à une définition de type à diffuser. */
PyTypeObject *get_python_arch_operand_type(void);
diff --git a/plugins/pychrysalide/arch/operands/Makefile.am b/plugins/pychrysalide/arch/operands/Makefile.am
index a41cbbb..3b753cc 100644
--- a/plugins/pychrysalide/arch/operands/Makefile.am
+++ b/plugins/pychrysalide/arch/operands/Makefile.am
@@ -1,19 +1,21 @@
noinst_LTLIBRARIES = libpychrysaarchoperands.la
+# libpychrysaarchoperands_la_SOURCES = \
+# feeder.h feeder.c \
+# proxy.h proxy.c \
+# rename.h rename.c \
+# target.h target.c \
+# targetable.h targetable.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
+ register.h register.c
-libpychrysaarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+libpychrysaarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
diff --git a/plugins/pychrysalide/arch/operands/constants.c b/plugins/pychrysalide/arch/operands/constants.c
index b9d80e4..78eeded 100644
--- a/plugins/pychrysalide/arch/operands/constants.c
+++ b/plugins/pychrysalide/arch/operands/constants.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* constants.c - ajout des constantes de base pour les opérandes
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -47,20 +47,33 @@
* *
******************************************************************************/
-bool define_imm_operand_constants(PyTypeObject *type)
+bool define_immediate_operand_constants(PyTypeObject *type)
{
bool result; /* Bilan à retourner */
PyObject *values; /* Groupe de valeurs à établir */
values = PyDict_New();
+ result = add_const_to_group(values, "ZERO_PADDING_BY_DEFAULT", IOF_ZERO_PADDING_BY_DEFAULT);
+ if (result) result = add_const_to_group(values, "ZERO_PADDING", IOF_ZERO_PADDING);
+
+ if (!result)
+ {
+ Py_DECREF(values);
+ goto exit;
+ }
+
+ result = attach_constants_group_to_type(type, true, "ImmOperandFlag", values,
+ "Specific state bits for immediate operands.");
+
+ values = PyDict_New();
+
result = add_const_to_group(values, "BIN", IOD_BIN);
if (result) result = add_const_to_group(values, "OCT", IOD_OCT);
if (result) result = add_const_to_group(values, "DEC", IOD_DEC);
if (result) result = add_const_to_group(values, "HEX", IOD_HEX);
if (result) result = add_const_to_group(values, "CHAR", IOD_CHAR);
if (result) result = add_const_to_group(values, "COUNT", IOD_COUNT);
- if (result) result = add_const_to_group(values, "LAST_VALID", IOD_LAST_VALID);
if (!result)
{
diff --git a/plugins/pychrysalide/arch/operands/constants.h b/plugins/pychrysalide/arch/operands/constants.h
index 71a26cc..5170faa 100644
--- a/plugins/pychrysalide/arch/operands/constants.h
+++ b/plugins/pychrysalide/arch/operands/constants.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* constants.h - prototypes pour l'ajout des constantes de base pour les opérandes
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -32,11 +32,14 @@
/* Définit les constantes relatives aux opérandes d'immédiats. */
-bool define_imm_operand_constants(PyTypeObject *);
+bool define_immediate_operand_constants(PyTypeObject *);
/* Tente de convertir en constante ImmOperandDisplay. */
int convert_to_imm_operand_display(PyObject *, void *);
+#define cast_imm_operand_display_to_python(v) \
+ cast_with_constants_group_from_type(get_python_immediate_operand_type(), "ImmOperandDisplay", v)
+
#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_CONSTANTS_H */
diff --git a/plugins/pychrysalide/arch/operands/immediate.c b/plugins/pychrysalide/arch/operands/immediate.c
index 2239eb2..a335db3 100644
--- a/plugins/pychrysalide/arch/operands/immediate.c
+++ b/plugins/pychrysalide/arch/operands/immediate.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* immediate.c - équivalent Python du fichier "arch/operands/immediate.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -30,201 +30,119 @@
#include <i18n.h>
-
-
-#include <arch/operands/immediate.h>
+#include <arch/operands/immediate-int.h>
#include "constants.h"
-#include "rename.h"
-#include "targetable.h"
#include "../operand.h"
#include "../../access.h"
+#include "../../constants.h"
#include "../../helpers.h"
#include "../../analysis/content.h"
-#include "../../glibext/bufferline.h"
-/* Crée un nouvel objet Python de type 'ImmOperand'. */
-static PyObject *py_imm_operand_new(PyTypeObject *, PyObject *, PyObject *);
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+CREATE_DYN_CONSTRUCTOR(immediate_operand, G_TYPE_IMMEDIATE_OPERAND);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_immediate_operand_init(PyObject *, PyObject *, PyObject *);
+
+
-/* Compare un opérande avec un autre. */
-static PyObject *py_imm_operand___cmp__(PyObject *, PyObject *);
+/* ---------------------------- DEFINITION D'UN IMMEDIAT ---------------------------- */
-/* Traduit un opérande en version humainement lisible. */
-static PyObject *py_imm_operand__print(PyObject *, PyObject *);
/* Renseigne la taille de la valeur indiquée à la construction. */
-static PyObject *py_imm_operand_get_size(PyObject *, void *);
+static PyObject *py_immediate_operand_get_size(PyObject *, void *);
/* Fournit la valeur portée par une opérande numérique. */
-static PyObject *py_imm_operand_get_value(PyObject *, void *);
+static PyObject *py_immediate_operand_get_value(PyObject *, void *);
+
+/* Indique le signe d'une valeur immédiate. */
+static PyObject *py_immediate_operand_is_negative(PyObject *, void *);
/* Indique le format textuel par défaut de la valeur. */
-static PyObject *py_imm_operand_get_default_display(PyObject *, void *);
+static PyObject *py_immediate_operand_get_default_display(PyObject *, void *);
/* Définit le format textuel par défaut de la valeur. */
-static int py_imm_operand_set_default_display(PyObject *, PyObject *, void *);
+static int py_immediate_operand_set_default_display(PyObject *, PyObject *, void *);
/* Indique la grande ligne du format textuel de la valeur. */
-static PyObject *py_imm_operand_get_display(PyObject *, void *);
+static PyObject *py_immediate_operand_get_display(PyObject *, void *);
/* Définit la grande ligne du format textuel de la valeur. */
-static int py_imm_operand_set_display(PyObject *, PyObject *, void *);
+static int py_immediate_operand_set_display(PyObject *, PyObject *, void *);
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
/******************************************************************************
* *
-* 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 'ImmOperand'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_immediate_operand_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
- unsigned int raw_size; /* Taille obtenue de Python */
+ MemoryDataSize size; /* Taille des données finale */
unsigned long long value; /* Valeur brute à représenter */
int ret; /* Bilan de lecture des args. */
- MemoryDataSize size; /* Taille des données finale */
- GArchOperand *operand; /* Création GLib à transmettre */
+ GImmediateOperand *operand; /* Opérande natif à manipuler */
-#define IMM_OPERAND_DOC \
- "The ImmOperand deals with immediate value as operand." \
+#define IMMEDIATE_OPERAND_DOC \
+ "The ImmediateOperand deals with immediate value as operand." \
"\n" \
"There are several ways to display these values in a disassembly," \
" the operand handles that.\n" \
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
- " ImmOperand(size, value)" \
+ " ImmediateOperand(size, value)" \
"\n" \
- "Where size specifies the original size of the provided value, as" \
- " a pychrysalide.analysis.BinContent.MemoryDataSize."
+ "Where *size* specifies the original size of the provided *value*," \
+ " as a pychrysalide.MemoryDataSize."
- ret = PyArg_ParseTuple(args, "IK", &raw_size, &value);
- if (!ret) return NULL;
+ /* Récupération des paramètres */
- size = raw_size;
+ ret = PyArg_ParseTuple(args, "O&K", convert_to_memory_data_size, &size, &value);
+ if (!ret) return -1;
- if (size != MDS_UNDEFINED
- && !(MDS_4_BITS_UNSIGNED <= size && size <= MDS_64_BITS_UNSIGNED)
- && !(MDS_4_BITS_SIGNED <= size && size <= MDS_64_BITS_SIGNED))
- {
- PyErr_SetString(PyExc_ValueError, _("Invalid size to build an immediate operand"));
- return NULL;
- }
+ /* Initialisation d'un objet GLib */
- operand = g_imm_operand_new_from_value(size, value);
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- result = pygobject_new(G_OBJECT(operand));
+ /* Eléments de base */
- g_object_unref(operand);
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
- return (PyObject *)result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = serveur à manipuler. *
-* args = arguments associés à l'appel. *
-* *
-* Description : Compare un opérande avec un autre. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_imm_operand___cmp__(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Bilan à retourner */
- GImmOperand *other; /* Autre opérande à manipuler */
- int ret; /* Bilan de lecture des args. */
- GImmOperand *operand; /* Elément à manipuler */
- int status; /* Bilan de comparaison */
-
-#define IMM_OPERAND_CMP_METHOD PYTHON_METHOD_DEF \
-( \
- __cmp__, "$self, other, /", \
- METH_VARARGS, py_imm_operand, \
- "Implementation of the required method used to compare the" \
- " operand with another one. This second object is always" \
- " an pychrysalide.arch.ImmOperand instance.\n" \
- "\n" \
- "See the parent class for more information about this method." \
-)
-
- ret = PyArg_ParseTuple(args, "O&", convert_to_imm_operand, &other);
- if (!ret) return NULL;
-
- operand = G_IMM_OPERAND(pygobject_get(self));
-
- status = g_arch_operand_compare(G_ARCH_OPERAND(operand), G_ARCH_OPERAND(other));
-
- result = PyLong_FromLong(status);
+ if (!g_immediate_operand_create_from_value(operand, size, value))
+ return -1;
- return result;
+ return 0;
}
-/******************************************************************************
-* *
-* Paramètres : self = serveur à manipuler. *
-* args = arguments associés à l'appel. *
-* *
-* Description : Traduit un opérande en version humainement lisible. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-static PyObject *py_imm_operand__print(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Bilan à retourner */
- GBufferLine *line; /* Ligne fournie à peupler */
- int ret; /* Bilan de lecture des args. */
- GImmOperand *operand; /* Elément à manipuler */
-
-#define IMM_OPERAND_PRINT_METHOD PYTHON_METHOD_DEF \
-( \
- _print, "$self, line, /", \
- METH_VARARGS, py_imm_operand, \
- "Implementation of the required method used to print the operand" \
- " into a rendering line, which is a provided" \
- " pychrysalide.glibext.BufferLine instance.\n" \
- "\n" \
- "See the parent class for more information about this method." \
-)
-
- ret = PyArg_ParseTuple(args, "O&", convert_to_buffer_line, &line);
- if (!ret) return NULL;
-
- operand = G_IMM_OPERAND(pygobject_get(self));
-
- g_arch_operand_print(G_ARCH_OPERAND(operand), line);
-
- result = Py_None;
- Py_INCREF(result);
-
- return result;
-
-}
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UN IMMEDIAT */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
@@ -240,25 +158,26 @@ static PyObject *py_imm_operand__print(PyObject *self, PyObject *args)
* *
******************************************************************************/
-static PyObject *py_imm_operand_get_size(PyObject *self, void *closure)
+static PyObject *py_immediate_operand_get_size(PyObject *self, void *closure)
{
PyObject *result; /* Instance Python à retourner */
- GImmOperand *operand; /* Version GLib de l'opérande */
+ GImmediateOperand *operand; /* Version GLib de l'opérande */
MemoryDataSize size; /* Type de donnée représentée */
-#define IMM_OPERAND_SIZE_ATTRIB PYTHON_GET_DEF_FULL \
+#define IMMEDIATE_OPERAND_SIZE_ATTRIB PYTHON_GET_DEF_FULL \
( \
- size, py_imm_operand, \
+ size, py_immediate_operand, \
"Get or set the size of the value contained in the operand." \
"\n" \
"The property is a value of type" \
- " pychrysalide.analysis.BinContent.MemoryDataSize." \
+ " pychrysalide.MemoryDataSize." \
)
- operand = G_IMM_OPERAND(pygobject_get(self));
- size = g_imm_operand_get_size(operand);
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
+
+ size = g_immediate_operand_get_size(operand);
- result = cast_with_constants_group_from_type(get_python_binary_content_type(), "MemoryDataSize", size);
+ result = cast_memory_data_size_to_python(size);
return result;
@@ -278,10 +197,10 @@ static PyObject *py_imm_operand_get_size(PyObject *self, void *closure)
* *
******************************************************************************/
-static PyObject *py_imm_operand_get_value(PyObject *self, void *closure)
+static PyObject *py_immediate_operand_get_value(PyObject *self, void *closure)
{
PyObject *result; /* Instance Python à retourner */
- GImmOperand *operand; /* Version GLib de l'opérande */
+ GImmediateOperand *operand; /* Version GLib de l'opérande */
MemoryDataSize size; /* Type de donnée représentée */
uint8_t uval8; /* Valeur sur 8 bits */
uint16_t uval16; /* Valeur sur 16 bits */
@@ -292,15 +211,15 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure)
int32_t sval32; /* Valeur sur 32 bits */
int64_t sval64; /* Valeur sur 64 bits */
-#define IMM_OPERAND_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- value, py_imm_operand, \
- "Value of the immediate operand, as an integer." \
+#define IMMEDIATE_OPERAND_VALUE_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ value, py_immediate_operand, \
+ "Value of the immediate operand, as an integer." \
)
- operand = G_IMM_OPERAND(pygobject_get(self));
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
- size = g_imm_operand_get_size(operand);
+ size = g_immediate_operand_get_size(operand);
switch (size)
{
@@ -311,36 +230,36 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure)
break;
case MDS_4_BITS_UNSIGNED:
case MDS_8_BITS_UNSIGNED:
- g_imm_operand_get_value(operand, size, &uval8);
+ g_immediate_operand_get_value(operand, size, &uval8);
result = PyLong_FromUnsignedLong(uval8);
break;
case MDS_16_BITS_UNSIGNED:
- g_imm_operand_get_value(operand, size, &uval16);
+ g_immediate_operand_get_value(operand, size, &uval16);
result = PyLong_FromUnsignedLong(uval16);
break;
case MDS_32_BITS_UNSIGNED:
- g_imm_operand_get_value(operand, size, &uval32);
+ g_immediate_operand_get_value(operand, size, &uval32);
result = PyLong_FromUnsignedLong(uval32);
break;
case MDS_64_BITS_UNSIGNED:
- g_imm_operand_get_value(operand, size, &uval64);
+ g_immediate_operand_get_value(operand, size, &uval64);
result = PyLong_FromUnsignedLongLong(uval64);
break;
case MDS_4_BITS_SIGNED:
case MDS_8_BITS_SIGNED:
- g_imm_operand_get_value(operand, size, &sval8);
+ g_immediate_operand_get_value(operand, size, &sval8);
result = PyLong_FromLong(sval8);
break;
case MDS_16_BITS_SIGNED:
- g_imm_operand_get_value(operand, size, &sval16);
+ g_immediate_operand_get_value(operand, size, &sval16);
result = PyLong_FromLong(sval16);
break;
case MDS_32_BITS_SIGNED:
- g_imm_operand_get_value(operand, size, &sval32);
+ g_immediate_operand_get_value(operand, size, &sval32);
result = PyLong_FromLong(sval32);
break;
case MDS_64_BITS_SIGNED:
- g_imm_operand_get_value(operand, size, &sval64);
+ g_immediate_operand_get_value(operand, size, &sval64);
result = PyLong_FromLongLong(sval64);
break;
@@ -363,6 +282,43 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
+* Description : Indique le signe d'une valeur immédiate. *
+* *
+* Retour : True si la valeur est strictement négative, False sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_immediate_operand_is_negative(PyObject *self, void *closure)
+{
+ PyObject *result; /* Instance Python à retourner */
+ GImmediateOperand *operand; /* Version GLib de l'opérande */
+ bool status; /* Etat à faire connaître */
+
+#define IMMEDIATE_OPERAND_NEGATIVE_ATTRIB PYTHON_IS_DEF_FULL \
+( \
+ negative, py_immediate_operand, \
+ "Sign of the value, as a boolean status." \
+)
+
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
+
+ status = g_immediate_operand_is_negative(operand);
+
+ 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 : Indique le format textuel par défaut de la valeur. *
* *
* Retour : Format global d'un affichage de valeur. *
@@ -371,25 +327,26 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure)
* *
******************************************************************************/
-static PyObject *py_imm_operand_get_default_display(PyObject *self, void *closure)
+static PyObject *py_immediate_operand_get_default_display(PyObject *self, void *closure)
{
PyObject *result; /* Instance Python à retourner */
- GImmOperand *operand; /* Version GLib de l'opérande */
+ GImmediateOperand *operand; /* Version GLib de l'opérande */
ImmOperandDisplay display; /* Type d'affichage courant */
-#define IMM_OPERAND_DEFAULT_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \
+#define IMMEDIATE_OPERAND_DEFAULT_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \
( \
- default_display, py_imm_operand, \
+ default_display, py_immediate_operand, \
"Define of the immediate operand default textual representation." \
"\n" \
"The property is a value of type" \
" pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay." \
)
- operand = G_IMM_OPERAND(pygobject_get(self));
- display = g_imm_operand_get_default_display(operand);
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
+
+ display = g_immediate_operand_get_default_display(operand);
- result = cast_with_constants_group_from_type(get_python_imm_operand_type(), "ImmOperandDisplay", display);
+ result = cast_imm_operand_display_to_python(display);
return result;
@@ -410,10 +367,10 @@ static PyObject *py_imm_operand_get_default_display(PyObject *self, void *closur
* *
******************************************************************************/
-static int py_imm_operand_set_default_display(PyObject *self, PyObject *value, void *closure)
+static int py_immediate_operand_set_default_display(PyObject *self, PyObject *value, void *closure)
{
ImmOperandDisplay display; /* Type d'affichage demandé */
- GImmOperand *operand; /* Version GLib de l'opérande */
+ GImmediateOperand *operand; /* Version GLib de l'opérande */
if (!PyLong_Check(value))
{
@@ -429,9 +386,9 @@ static int py_imm_operand_set_default_display(PyObject *self, PyObject *value, v
return -1;
}
- operand = G_IMM_OPERAND(pygobject_get(self));
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
- g_imm_operand_set_default_display(operand, display);
+ g_immediate_operand_set_default_display(operand, display);
return 0;
@@ -451,25 +408,27 @@ static int py_imm_operand_set_default_display(PyObject *self, PyObject *value, v
* *
******************************************************************************/
-static PyObject *py_imm_operand_get_display(PyObject *self, void *closure)
+static PyObject *py_immediate_operand_get_display(PyObject *self, void *closure)
{
PyObject *result; /* Instance Python à retourner */
- GImmOperand *operand; /* Version GLib de l'opérande */
+ GImmediateOperand *operand; /* Version GLib de l'opérande */
ImmOperandDisplay display; /* Type d'affichage courant */
-#define IMM_OPERAND_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \
-( \
- display, py_imm_operand, \
- "Define of the immediate operand current textual representation." \
- "\n" \
- "The property is a value of type" \
- " pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay." \
+#define IMMEDIATE_OPERAND_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ display, py_immediate_operand, \
+ "Retrieve or define of the immediate operand current textual" \
+ " representation." \
+ "\n" \
+ "The property is a value of type" \
+ " pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay." \
)
- operand = G_IMM_OPERAND(pygobject_get(self));
- display = g_imm_operand_get_display(operand);
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
- result = cast_with_constants_group_from_type(get_python_imm_operand_type(), "ImmOperandDisplay", display);
+ display = g_immediate_operand_get_display(operand);
+
+ result = cast_imm_operand_display_to_python(display);
return result;
@@ -490,10 +449,10 @@ static PyObject *py_imm_operand_get_display(PyObject *self, void *closure)
* *
******************************************************************************/
-static int py_imm_operand_set_display(PyObject *self, PyObject *value, void *closure)
+static int py_immediate_operand_set_display(PyObject *self, PyObject *value, void *closure)
{
ImmOperandDisplay display; /* Type d'affichage demandé */
- GImmOperand *operand; /* Version GLib de l'opérande */
+ GImmediateOperand *operand; /* Version GLib de l'opérande */
if (!PyLong_Check(value))
{
@@ -509,9 +468,9 @@ static int py_imm_operand_set_display(PyObject *self, PyObject *value, void *clo
return -1;
}
- operand = G_IMM_OPERAND(pygobject_get(self));
+ operand = G_IMMEDIATE_OPERAND(pygobject_get(self));
- g_imm_operand_set_display(operand, display);
+ g_immediate_operand_set_display(operand, display);
return 0;
@@ -530,40 +489,41 @@ static int py_imm_operand_set_display(PyObject *self, PyObject *value, void *clo
* *
******************************************************************************/
-PyTypeObject *get_python_imm_operand_type(void)
+PyTypeObject *get_python_immediate_operand_type(void)
{
- static PyMethodDef py_imm_operand_methods[] = {
- IMM_OPERAND_CMP_METHOD,
- IMM_OPERAND_PRINT_METHOD,
+ static PyMethodDef py_immediate_operand_methods[] = {
{ NULL }
};
- static PyGetSetDef py_imm_operand_getseters[] = {
- IMM_OPERAND_SIZE_ATTRIB,
- IMM_OPERAND_VALUE_ATTRIB,
- IMM_OPERAND_DEFAULT_DISPLAY_ATTRIB,
- IMM_OPERAND_DISPLAY_ATTRIB,
+ static PyGetSetDef py_immediate_operand_getseters[] = {
+ IMMEDIATE_OPERAND_SIZE_ATTRIB,
+ IMMEDIATE_OPERAND_VALUE_ATTRIB,
+ IMMEDIATE_OPERAND_NEGATIVE_ATTRIB,
+ IMMEDIATE_OPERAND_DEFAULT_DISPLAY_ATTRIB,
+ IMMEDIATE_OPERAND_DISPLAY_ATTRIB,
{ NULL }
};
- static PyTypeObject py_imm_operand_type = {
+ static PyTypeObject py_immediate_operand_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.arch.operands.ImmOperand",
+ .tp_name = "pychrysalide.arch.operands.ImmediateOperand",
.tp_basicsize = sizeof(PyGObject),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_doc = IMM_OPERAND_DOC,
+ .tp_doc = IMMEDIATE_OPERAND_DOC,
+
+ .tp_methods = py_immediate_operand_methods,
+ .tp_getset = py_immediate_operand_getseters,
- .tp_methods = py_imm_operand_methods,
- .tp_getset = py_imm_operand_getseters,
- .tp_new = py_imm_operand_new
+ .tp_init = py_immediate_operand_init,
+ .tp_new = py_immediate_operand_new,
};
- return &py_imm_operand_type;
+ return &py_immediate_operand_type;
}
@@ -580,13 +540,13 @@ PyTypeObject *get_python_imm_operand_type(void)
* *
******************************************************************************/
-bool ensure_python_imm_operand_is_registered(void)
+bool ensure_python_immediate_operand_is_registered(void)
{
- PyTypeObject *type; /* Type Python 'ImmOperand' */
+ PyTypeObject *type; /* Type 'ImmediateOperand' */
PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
- type = get_python_imm_operand_type();
+ type = get_python_immediate_operand_type();
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
@@ -597,16 +557,10 @@ bool ensure_python_imm_operand_is_registered(void)
if (!ensure_python_arch_operand_is_registered())
return false;
- if (!ensure_python_targetable_operand_is_registered())
- return false;
-
- if (!ensure_python_renameable_operand_is_registered())
- return false;
-
- if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type))
+ if (!register_class_for_pygobject(dict, G_TYPE_IMMEDIATE_OPERAND, type))
return false;
- if (!define_imm_operand_constants(type))
+ if (!define_immediate_operand_constants(type))
return false;
}
@@ -629,11 +583,11 @@ bool ensure_python_imm_operand_is_registered(void)
* *
******************************************************************************/
-int convert_to_imm_operand(PyObject *arg, void *dst)
+int convert_to_immediate_operand(PyObject *arg, void *dst)
{
int result; /* Bilan à retourner */
- result = PyObject_IsInstance(arg, (PyObject *)get_python_imm_operand_type());
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_immediate_operand_type());
switch (result)
{
@@ -647,7 +601,7 @@ int convert_to_imm_operand(PyObject *arg, void *dst)
break;
case 1:
- *((GImmOperand **)dst) = G_IMM_OPERAND(pygobject_get(arg));
+ *((GImmediateOperand **)dst) = G_IMMEDIATE_OPERAND(pygobject_get(arg));
break;
default:
diff --git a/plugins/pychrysalide/arch/operands/immediate.h b/plugins/pychrysalide/arch/operands/immediate.h
index 4a1e6de..8b8de83 100644
--- a/plugins/pychrysalide/arch/operands/immediate.h
+++ b/plugins/pychrysalide/arch/operands/immediate.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* immediate.h - prototypes pour l'équivalent Python du fichier "arch/operands/immediate.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -32,13 +32,13 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_imm_operand_type(void);
+PyTypeObject *get_python_immediate_operand_type(void);
-/* Prend en charge l'objet 'pychrysalide.arch.ImmOperand'. */
-bool ensure_python_imm_operand_is_registered(void);
+/* Prend en charge l'objet 'pychrysalide.arch.ImmediateOperand'. */
+bool ensure_python_immediate_operand_is_registered(void);
/* Tente de convertir en opérande de valeur immédiate. */
-int convert_to_imm_operand(PyObject *, void *);
+int convert_to_immediate_operand(PyObject *, void *);
diff --git a/plugins/pychrysalide/arch/operands/known.c b/plugins/pychrysalide/arch/operands/known.c
index fab426e..85cabc2 100644
--- a/plugins/pychrysalide/arch/operands/known.c
+++ b/plugins/pychrysalide/arch/operands/known.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* known.c - équivalent Python du fichier "arch/operands/known.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -29,70 +29,92 @@
#include <pygobject.h>
-#include <arch/operands/known.h>
+#include <arch/operands/known-int.h>
#include "immediate.h"
-#include "rename.h"
#include "../../access.h"
#include "../../helpers.h"
-/* Crée un nouvel objet Python de type 'KnownImmOperand'. */
-static PyObject *py_known_imm_operand_new(PyTypeObject *, PyObject *, PyObject *);
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+CREATE_DYN_CONSTRUCTOR(known_immediate_operand, G_TYPE_KNOWN_IMMEDIATE_OPERAND);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_known_immediate_operand_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
/******************************************************************************
* *
-* 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 'KnownImmOperand'. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Instance Python mise en place. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_known_immediate_operand_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *result; /* Instance à retourner */
- GImmOperand *imm; /* Opérande à remplacer */
+ GImmediateOperand *imm; /* Opérande à remplacer */
const char *alt; /* Impression alternative */
int ret; /* Bilan de lecture des args. */
- GArchOperand *operand; /* Création GLib à transmettre */
-
-#define KNOWN_IMM_OPERAND_DOC \
- "The KnownImmOperand provides replacement of" \
- " pychrysalide.arch.operands.ImmOperand instances by an alternative" \
- " text.\n" \
- "\n" \
- "Instances can be created using the following constructor:\n" \
- "\n" \
- " KnownImmOperand(imm, alt)" \
- "\n" \
- "Where imm is an operand of type pychrysalide.arch.operands.ImmOperand" \
- " and alt is a string providing the text to be rendered at object" \
+ GKnownImmediateOperand *operand; /* Opérande natif à manipuler */
+
+#define KNOWN_IMMEDIATE_OPERAND_DOC \
+ "The KnownImmediateOperand provides replacement of" \
+ " pychrysalide.arch.operands.ImmediateOperand instances by an alternative" \
+ " text.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " KnownImmediateOperand(imm, alt)" \
+ "\n" \
+ "Where *imm* is an operand of type pychrysalide.arch.operands.ImmediateOperand" \
+ " and *alt* is a string providing the text to be rendered at object" \
" display."
- ret = PyArg_ParseTuple(args, "O&s", convert_to_imm_operand, &imm, &alt);
- if (!ret) return NULL;
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "O&s", convert_to_immediate_operand, &imm, &alt);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
- operand = g_known_imm_operand_new(imm, alt);
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- result = pygobject_new(G_OBJECT(operand));
+ /* Eléments de base */
- g_object_unref(operand);
+ operand = G_KNOWN_IMMEDIATE_OPERAND(pygobject_get(self));
- return (PyObject *)result;
+ if (!g_known_immediate_operand_create(operand, imm, alt))
+ return -1;
+
+ return 0;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'UN IMMEDIAT CONNU */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : - *
@@ -105,34 +127,36 @@ static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, Py
* *
******************************************************************************/
-PyTypeObject *get_python_known_imm_operand_type(void)
+PyTypeObject *get_python_known_immediate_operand_type(void)
{
- static PyMethodDef py_known_imm_operand_methods[] = {
+ static PyMethodDef py_known_immediate_operand_methods[] = {
{ NULL }
};
- static PyGetSetDef py_known_imm_operand_getseters[] = {
+ static PyGetSetDef py_known_immediate_operand_getseters[] = {
{ NULL }
};
- static PyTypeObject py_known_imm_operand_type = {
+ static PyTypeObject py_known_immediate_operand_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.arch.operands.KnownImmOperand",
+ .tp_name = "pychrysalide.arch.operands.KnownImmediateOperand",
.tp_basicsize = sizeof(PyGObject),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_doc = KNOWN_IMM_OPERAND_DOC,
+ .tp_doc = KNOWN_IMMEDIATE_OPERAND_DOC,
- .tp_methods = py_known_imm_operand_methods,
- .tp_getset = py_known_imm_operand_getseters,
- .tp_new = py_known_imm_operand_new
+ .tp_methods = py_known_immediate_operand_methods,
+ .tp_getset = py_known_immediate_operand_getseters,
+
+ .tp_init = py_known_immediate_operand_init,
+ .tp_new = py_known_immediate_operand_new,
};
- return &py_known_imm_operand_type;
+ return &py_known_immediate_operand_type;
}
@@ -141,7 +165,7 @@ PyTypeObject *get_python_known_imm_operand_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. *
+* Description : Prend en charge l'objet '....KnownImmediateOperand'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -149,13 +173,13 @@ PyTypeObject *get_python_known_imm_operand_type(void)
* *
******************************************************************************/
-bool ensure_python_known_imm_operand_is_registered(void)
+bool ensure_python_known_immediate_operand_is_registered(void)
{
- PyTypeObject *type; /* Type Python 'ImmOperand' */
+ PyTypeObject *type; /* Type 'KnownImmediateOperand'*/
PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
- type = get_python_known_imm_operand_type();
+ type = get_python_known_immediate_operand_type();
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
@@ -163,13 +187,10 @@ bool ensure_python_known_imm_operand_is_registered(void)
dict = PyModule_GetDict(module);
- if (!ensure_python_imm_operand_is_registered())
- return false;
-
- if (!ensure_python_renamed_operand_is_registered())
+ if (!ensure_python_immediate_operand_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type))
+ if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMMEDIATE_OPERAND, type))
return false;
}
@@ -192,11 +213,11 @@ bool ensure_python_known_imm_operand_is_registered(void)
* *
******************************************************************************/
-int convert_to_known_imm_operand(PyObject *arg, void *dst)
+int convert_to_known_immediate_operand(PyObject *arg, void *dst)
{
int result; /* Bilan à retourner */
- result = PyObject_IsInstance(arg, (PyObject *)get_python_known_imm_operand_type());
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_known_immediate_operand_type());
switch (result)
{
@@ -210,7 +231,7 @@ int convert_to_known_imm_operand(PyObject *arg, void *dst)
break;
case 1:
- *((GKnownImmOperand **)dst) = G_KNOWN_IMM_OPERAND(pygobject_get(arg));
+ *((GKnownImmediateOperand **)dst) = G_KNOWN_IMMEDIATE_OPERAND(pygobject_get(arg));
break;
default:
diff --git a/plugins/pychrysalide/arch/operands/known.h b/plugins/pychrysalide/arch/operands/known.h
index b5ced68..f5b80e8 100644
--- a/plugins/pychrysalide/arch/operands/known.h
+++ b/plugins/pychrysalide/arch/operands/known.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* known.h - prototypes pour l'équivalent Python du fichier "arch/operands/known.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -32,13 +32,13 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_known_imm_operand_type(void);
+PyTypeObject *get_python_known_immediate_operand_type(void);
-/* Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. */
-bool ensure_python_known_imm_operand_is_registered(void);
+/* Prend en charge l'objet 'pychrysalide.arch.KnownImmediateOperand'. */
+bool ensure_python_known_immediate_operand_is_registered(void);
/* Tente de convertir en remplaçant d'opérande d'immédiat. */
-int convert_to_known_imm_operand(PyObject *, void *);
+int convert_to_known_immediate_operand(PyObject *, void *);
diff --git a/plugins/pychrysalide/arch/operands/module.c b/plugins/pychrysalide/arch/operands/module.c
index 89adecc..486e259 100644
--- a/plugins/pychrysalide/arch/operands/module.c
+++ b/plugins/pychrysalide/arch/operands/module.c
@@ -28,14 +28,20 @@
#include <assert.h>
+/*
#include "feeder.h"
+*/
#include "immediate.h"
#include "known.h"
+/*
#include "proxy.h"
+*/
#include "register.h"
+/*
#include "rename.h"
#include "target.h"
#include "targetable.h"
+*/
#include "../../helpers.h"
@@ -101,15 +107,21 @@ bool populate_arch_operands_module(void)
result = true;
+ /*
if (result) result = ensure_python_proxy_feeder_is_registered();
- if (result) result = ensure_python_imm_operand_is_registered();
- if (result) result = ensure_python_known_imm_operand_is_registered();
+ */
+ if (result) result = ensure_python_immediate_operand_is_registered();
+ if (result) result = ensure_python_known_immediate_operand_is_registered();
+ /*
if (result) result = ensure_python_proxy_operand_is_registered();
+ */
if (result) result = ensure_python_register_operand_is_registered();
+ /*
if (result) result = ensure_python_renamed_operand_is_registered();
if (result) result = ensure_python_renameable_operand_is_registered();
if (result) result = ensure_python_target_operand_is_registered();
if (result) result = ensure_python_targetable_operand_is_registered();
+ */
assert(result);
diff --git a/plugins/pychrysalide/arch/operands/register.c b/plugins/pychrysalide/arch/operands/register.c
index 2a48a0f..707524a 100644
--- a/plugins/pychrysalide/arch/operands/register.c
+++ b/plugins/pychrysalide/arch/operands/register.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* register.c - équivalent Python du fichier "arch/operands/register.c"
*
- * Copyright (C) 2019-2020 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -30,25 +30,19 @@
#include <i18n.h>
#include <arch/operands/register-int.h>
-#include <plugins/dt.h>
#include "../operand.h"
#include "../register.h"
#include "../../access.h"
#include "../../helpers.h"
-#include "../../glibext/bufferline.h"
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_register_operand_new(PyTypeObject *, PyObject *, PyObject *);
-
-/* Initialise la classe des descriptions de fichier binaire. */
-static void py_register_operand_init_gclass(GRegisterOperandClass *, gpointer);
+CREATE_DYN_CONSTRUCTOR(register_operand, G_TYPE_REGISTER_OPERAND);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_register_operand_init(PyObject *, PyObject *, PyObject *);
@@ -58,12 +52,6 @@ static int py_register_operand_init(PyObject *, PyObject *, PyObject *);
/* ------------------------- REGISTRE SOUS FORME D'OPERANDE ------------------------- */
-/* Compare un opérande avec un autre. */
-static PyObject *py_register_operand___cmp__(PyObject *, PyObject *);
-
-/* Traduit un opérande en version humainement lisible. */
-static PyObject *py_register_operand__print(PyObject *, PyObject *);
-
/* Fournit le registre associé à l'opérande. */
static PyObject *py_register_operand_get_register(PyObject *, void *);
@@ -76,86 +64,6 @@ static PyObject *py_register_operand_get_register(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_register_operand_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_register_operand_type();
-
- if (type == base)
- goto simple_way;
-
- /* Mise en place d'un type dédié */
-
- first_time = (g_type_from_name(type->tp_name) == 0);
-
- gtype = build_dynamic_type(G_TYPE_REGISTER_OPERAND, type->tp_name,
- (GClassInitFunc)py_register_operand_init_gclass, 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() */
-
- simple_way:
-
- result = PyType_GenericNew(type, args, kwds);
-
- exit:
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à initialiser. *
-* unused = données non utilisées ici. *
-* *
-* Description : Initialise la classe des descriptions de fichier binaire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void py_register_operand_init_gclass(GRegisterOperandClass *class, gpointer unused)
-{
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
@@ -182,7 +90,7 @@ static int py_register_operand_init(PyObject *self, PyObject *args, PyObject *kw
"\n" \
" RegisterOperand(reg)" \
"\n" \
- "Where reg is an architecture register defined from a subclass of" \
+ "Where *reg* is an architecture register defined from a subclass of" \
" pychrysalide.arch.ArchRegister."
/* Récupération des paramètres */
@@ -199,8 +107,8 @@ static int py_register_operand_init(PyObject *self, PyObject *args, PyObject *kw
operand = G_REGISTER_OPERAND(pygobject_get(self));
- g_object_ref(G_OBJECT(reg));
- operand->reg = reg;
+ if (!g_register_operand_create(operand, reg))
+ return -1;
return 0;
@@ -215,98 +123,6 @@ static int py_register_operand_init(PyObject *self, PyObject *args, PyObject *kw
/******************************************************************************
* *
-* Paramètres : self = serveur à manipuler. *
-* args = arguments associés à l'appel. *
-* *
-* Description : Compare un opérande avec un autre. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_register_operand___cmp__(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Bilan à retourner */
- GRegisterOperand *other; /* Autre opérande à manipuler */
- int ret; /* Bilan de lecture des args. */
- GRegisterOperand *operand; /* Elément à manipuler */
- int status; /* Bilan de comparaison */
-
-#define REGISTER_OPERAND_CMP_METHOD PYTHON_METHOD_DEF \
-( \
- __cmp__, "$self, other, /", \
- METH_VARARGS, py_register_operand, \
- "Implementation of the required method used to compare the" \
- " operand with another one. This second object is always" \
- " a pychrysalide.arch.RegisterOperand instance.\n" \
- "\n" \
- "See the parent class for more information about this method." \
-)
-
- ret = PyArg_ParseTuple(args, "O&", convert_to_register_operand, &other);
- if (!ret) return NULL;
-
- operand = G_REGISTER_OPERAND(pygobject_get(self));
-
- status = g_arch_operand_compare(G_ARCH_OPERAND(operand), G_ARCH_OPERAND(other));
-
- result = PyLong_FromLong(status);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : self = serveur à manipuler. *
-* args = arguments associés à l'appel. *
-* *
-* Description : Traduit un opérande en version humainement lisible. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_register_operand__print(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Bilan à retourner */
- GBufferLine *line; /* Ligne fournie à peupler */
- int ret; /* Bilan de lecture des args. */
- GRegisterOperand *operand; /* Elément à manipuler */
-
-#define REGISTER_OPERAND_PRINT_METHOD PYTHON_METHOD_DEF \
-( \
- _print, "$self, line, /", \
- METH_VARARGS, py_register_operand, \
- "Implementation of the required method used to print the operand" \
- " into a rendering line, which is a provided" \
- " pychrysalide.glibext.BufferLine instance.\n" \
- "\n" \
- "See the parent class for more information about this method." \
-)
-
- ret = PyArg_ParseTuple(args, "O&", convert_to_buffer_line, &line);
- if (!ret) return NULL;
-
- operand = G_REGISTER_OPERAND(pygobject_get(self));
-
- g_arch_operand_print(G_ARCH_OPERAND(operand), line);
-
- result = Py_None;
- Py_INCREF(result);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
@@ -367,8 +183,6 @@ static PyObject *py_register_operand_get_register(PyObject *self, void *closure)
PyTypeObject *get_python_register_operand_type(void)
{
static PyMethodDef py_register_operand_methods[] = {
- REGISTER_OPERAND_CMP_METHOD,
- REGISTER_OPERAND_PRINT_METHOD,
{ NULL }
};
diff --git a/plugins/pychrysalide/arch/register.c b/plugins/pychrysalide/arch/register.c
index 615a5b7..7139e47 100644
--- a/plugins/pychrysalide/arch/register.c
+++ b/plugins/pychrysalide/arch/register.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* register.c - équivalent Python du fichier "arch/register.c"
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -31,32 +31,27 @@
#include <i18n.h>
#include <arch/register-int.h>
-#include <plugins/dt.h>
#include "../access.h"
#include "../helpers.h"
-#include "../analysis/storage/serialize.h"
+#include "../glibext/comparable.h"
+#include "../glibext/hashable.h"
+#include "../glibext/serialize.h"
+#include "../glibext/strbuilder.h"
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_arch_register_new(PyTypeObject *, PyObject *, PyObject *);
-
/* Initialise la classe des registres. */
-static void py_arch_register_init_gclass(GArchRegisterClass *, gpointer);
-
-/* Produit une empreinte à partir d'un registre. */
-static guint py_arch_register___hash___wrapper(const GArchRegister *);
+static int py_arch_register_init_gclass(GArchRegisterClass *, PyTypeObject *);
-/* Compare un registre avec un autre. */
-static int py_arch_register___cmp___wrapper(const GArchRegister *, const GArchRegister *);
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_register, G_TYPE_ARCH_REGISTER);
-/* Traduit un registre en version humainement lisible. */
-static void py_arch_register_print_wrapper(const GArchRegister *, GBufferLine *);
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_arch_register_init(PyObject *, PyObject *, PyObject *);
/* Indique si le registre correspond à ebp ou similaire. */
static bool py_arch_register_is_base_pointer_wrapper(const GArchRegister *);
@@ -69,9 +64,6 @@ static bool py_arch_register_is_stack_pointer_wrapper(const GArchRegister *);
/* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */
-/* Effectue une comparaison avec un objet Python 'ArchRegister'. */
-static PyObject *py_arch_register_richcompare(PyObject *, PyObject *, int);
-
/* Indique si le registre correspond à ebp ou similaire. */
static PyObject *py_arch_register_is_base_pointer(PyObject *, void *);
@@ -87,88 +79,8 @@ static PyObject *py_arch_register_is_stack_pointer(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_arch_register_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 registre */
- bool status; /* Bilan d'un enregistrement */
-
-#define ARCH_REGISTER_DOC \
- "The ArchRegister object aims to get subclassed to create" \
- " registers suitable for new architectures.\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.arch.ArchRegister.__hash__();\n" \
- "* pychrysalide.arch.ArchRegister.__cmp__();\n" \
- "* pychrysalide.arch.ArchRegister._print();\n" \
- "* pychrysalide.arch.ArchRegister._is_base_pointer();\n" \
- "* pychrysalide.arch.ArchRegister._is_stack_pointer().\n" \
- "\n" \
- "Chrysalide creates an internal glue to provide rich comparisons" \
- " for registers based on the old-style *__cmp__* function."
-
- /* Validations diverses */
-
- base = get_python_arch_register_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_ARCH_REGISTER, type->tp_name,
- (GClassInitFunc)py_arch_register_init_gclass, 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 : class = classe à initialiser. *
-* unused = données non utilisées ici. *
+* Paramètres : gclass = classe GLib à initialiser. *
+* pyclass = classe Python à initialiser. *
* *
* Description : Initialise la classe des registres. *
* *
@@ -178,190 +90,51 @@ static PyObject *py_arch_register_new(PyTypeObject *type, PyObject *args, PyObje
* *
******************************************************************************/
-static void py_arch_register_init_gclass(GArchRegisterClass *class, gpointer unused)
-{
- class->hash = py_arch_register___hash___wrapper;
- class->compare = py_arch_register___cmp___wrapper;
- class->print = py_arch_register_print_wrapper;
- class->is_bp = py_arch_register_is_base_pointer_wrapper;
- class->is_sp = py_arch_register_is_stack_pointer_wrapper;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : reg = registre visé par la procédure. *
-* *
-* Description : Produit une empreinte à partir d'un registre. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static guint py_arch_register___hash___wrapper(const GArchRegister *reg)
-{
- guint result; /* Empreinte à retourner */
- PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyobj; /* Objet Python concerné */
- PyObject *pyret; /* Bilan de consultation */
-
-#define ARCH_REGISTER_HASH_WRAPPER PYTHON_WRAPPER_DEF \
-( \
- __hash__, "$self, /", \
- METH_NOARGS, \
- "Abstract method used to produce a hash of the object. The" \
- " result must be an integer value." \
-)
-
- result = 0;
-
- gstate = PyGILState_Ensure();
-
- pyobj = pygobject_new(G_OBJECT(reg));
-
- if (has_python_method(pyobj, "__hash__"))
- {
- pyret = run_python_method(pyobj, "__hash__", NULL);
-
- if (pyret != NULL)
- {
- if (PyLong_Check(pyret))
- result = PyLong_AsUnsignedLong(pyret);
-
- Py_DECREF(pyret);
-
- }
-
- }
-
- Py_DECREF(pyobj);
-
- PyGILState_Release(gstate);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : a = premier registre à consulter. *
-* b = second registre à consulter. *
-* *
-* Description : Compare un registre avec un autre. *
-* *
-* Retour : Bilan de la comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int py_arch_register___cmp___wrapper(const GArchRegister *a, const GArchRegister *b)
+static int py_arch_register_init_gclass(GArchRegisterClass *gclass, PyTypeObject *pyclass)
{
- int result; /* Empreinte à retourner */
- PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyobj; /* Objet Python concerné */
- PyObject *args; /* Arguments pour l'appel */
- PyObject *pyret; /* Bilan de consultation */
-
-#define ARCH_REGISTER_CMP_WRAPPER PYTHON_WRAPPER_DEF \
-( \
- __cmp__, "$self, other, /", \
- METH_VARARGS, \
- "Abstract method used to compare the register with another" \
- " one. This second object is always an" \
- " pychrysalide.arch.ArchRegister instance.\n" \
- "\n" \
- " This is the Python old-style comparison method, but" \
- " Chrysalide provides a glue to automatically build a rich" \
- " version of this function." \
-)
-
- result = 0;
-
- gstate = PyGILState_Ensure();
-
- pyobj = pygobject_new(G_OBJECT(a));
-
- if (has_python_method(pyobj, "__cmp__"))
- {
- args = PyTuple_New(1);
- PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(b)));
-
- pyret = run_python_method(pyobj, "__cmp__", args);
-
- if (pyret != NULL)
- {
- if (PyLong_Check(pyret))
- result = PyLong_AsLong(pyret);
- }
+ PY_CLASS_SET_WRAPPER(gclass->is_bp, py_arch_register_is_base_pointer_wrapper);
+ PY_CLASS_SET_WRAPPER(gclass->is_sp, py_arch_register_is_stack_pointer_wrapper);
- Py_DECREF(args);
-
- Py_XDECREF(pyret);
-
- }
-
- Py_DECREF(pyobj);
-
- PyGILState_Release(gstate);
-
- return result;
+ return 0;
}
/******************************************************************************
* *
-* Paramètres : reg = registre visé par la procédure. *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
* *
-* Description : Traduit un registre en version humainement lisible. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : - *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void py_arch_register_print_wrapper(const GArchRegister *reg, GBufferLine *line)
+static int py_arch_register_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyobj; /* Objet Python concerné */
- PyObject *args; /* Arguments pour l'appel */
- PyObject *pyret; /* Bilan de consultation */
-
-#define ARCH_REGISTER_PRINT_WRAPPER PYTHON_WRAPPER_DEF \
-( \
- _print, "$self, line, /", \
- METH_VARARGS, \
- "Abstract method used to print the register into a rendering" \
- " line, which is a provided pychrysalide.glibext.BufferLine" \
- " instance." \
-)
-
- gstate = PyGILState_Ensure();
-
- pyobj = pygobject_new(G_OBJECT(reg));
-
- if (has_python_method(pyobj, "_print"))
- {
- args = PyTuple_New(1);
- PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line)));
-
- pyret = run_python_method(pyobj, "_print", args);
-
- Py_DECREF(args);
+ int ret; /* Bilan de lecture des args. */
- Py_XDECREF(pyret);
+#define ARCH_REGISTER_DOC \
+ "The ArchRegister object aims to get subclassed in order to create" \
+ " registers suitable for new architectures.\n" \
+ "\n" \
+ "Calls to the *__init__* constructor of this abstract object expect"\
+ " no particular argument.\n" \
+ "\n" \
+ "The following methods may to be implemnted for new classes:\n" \
+ "* pychrysalide.arch.ArchRegister._is_base_pointer();\n" \
+ "* pychrysalide.arch.ArchRegister._is_stack_pointer().\n"
- }
+ /* Initialisation d'un objet GLib */
- Py_DECREF(pyobj);
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- PyGILState_Release(gstate);
+ return 0;
}
@@ -486,51 +259,6 @@ static bool py_arch_register_is_stack_pointer_wrapper(const GArchRegister *reg)
/******************************************************************************
* *
-* 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 Python 'ArchRegister'.*
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_arch_register_richcompare(PyObject *a, PyObject *b, int op)
-{
- PyObject *result; /* Bilan à retourner */
- int ret; /* Bilan de lecture des args. */
- const GArchRegister *reg_a; /* Premier élément à traiter */
- const GArchRegister *reg_b; /* Second élément à traiter */
- int status; /* Résultat d'une comparaison */
-
- ret = PyObject_IsInstance(b, (PyObject *)get_python_arch_register_type());
- if (!ret)
- {
- result = Py_NotImplemented;
- goto cmp_done;
- }
-
- reg_a = G_ARCH_REGISTER(pygobject_get(a));
- reg_b = G_ARCH_REGISTER(pygobject_get(b));
-
- status = py_arch_register___cmp___wrapper(reg_a, reg_b);
-
- result = status_to_rich_cmp_state(status, op);
-
- cmp_done:
-
- Py_INCREF(result);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
@@ -618,9 +346,6 @@ static PyObject *py_arch_register_is_stack_pointer(PyObject *self, void *closure
PyTypeObject *get_python_arch_register_type(void)
{
static PyMethodDef py_arch_register_methods[] = {
- ARCH_REGISTER_HASH_WRAPPER,
- ARCH_REGISTER_CMP_WRAPPER,
- ARCH_REGISTER_PRINT_WRAPPER,
ARCH_REGISTER_IS_BASE_POINTER_WRAPPER,
ARCH_REGISTER_IS_STACK_POINTER_WRAPPER,
{ NULL }
@@ -643,11 +368,10 @@ PyTypeObject *get_python_arch_register_type(void)
.tp_doc = ARCH_REGISTER_DOC,
- .tp_richcompare = py_arch_register_richcompare,
-
.tp_methods = py_arch_register_methods,
.tp_getset = py_arch_register_getseters,
+ .tp_init = py_arch_register_init,
.tp_new = py_arch_register_new,
};
@@ -683,9 +407,20 @@ bool ensure_python_arch_register_is_registered(void)
dict = PyModule_GetDict(module);
+ if (!ensure_python_comparable_object_is_registered())
+ return false;
+
+ if (!ensure_python_hashable_object_is_registered())
+ return false;
+
if (!ensure_python_serializable_object_is_registered())
return false;
+ if (!ensure_python_string_builder_is_registered())
+ return false;
+
+ pyg_register_class_init(G_TYPE_ARCH_REGISTER, (PyGClassInitFunc)py_arch_register_init_gclass);
+
if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type))
return false;
diff --git a/plugins/pychrysalide/bindings.c b/plugins/pychrysalide/bindings.c
index 02850d1..f120c3b 100644
--- a/plugins/pychrysalide/bindings.c
+++ b/plugins/pychrysalide/bindings.c
@@ -25,16 +25,17 @@
#include "bindings.h"
-#ifdef PYTHON_PACKAGE
-# include <dlfcn.h>
-#endif
+#include <assert.h>
+#include <dlfcn.h>
#include <pygobject.h>
+#include <stddef.h>
#include <stdio.h>
-#include <config.h>
#include <common/cpp.h>
+#include <common/environment.h>
#include <common/extstr.h>
+#include <core/core.h>
#include <plugins/pglist.h>
#include <plugins/self.h>
@@ -52,10 +53,6 @@
#include "glibext/module.h"
/* #include "debug/module.h" */
#include "format/module.h"
-/* #ifdef INCLUDE_GTK_SUPPORT */
-/* # include "gtkext/module.h" */
-/* # include "gui/module.h" */
-/* #endif */
/* #include "mangling/module.h" */
#include "plugins/module.h"
@@ -106,6 +103,42 @@ static bool install_metaclass_for_python_gobjects(void);
/* Met en place un environnement pour l'extension Python. */
static bool setup_python_context(void);
+/* Intègre les éventuelles fonctions natives des interfaces. */
+static void inherit_interface_slots(PyObject *);
+
+/**
+ * Conservation d'anciens pointeurs remplacés
+ */
+static initproc __old_gobject_meta_base_init = NULL;
+static initproc __old_gobject_meta_init = NULL;
+
+/**
+ * La fonction unhook_pygobject_behaviour(), inversant les opérations de la fonction
+ * unhook_pygobject_behaviour() manipulerait volontiers les fonctions PyImport_ImportModule()
+ * et PyObject_GetAttrString().
+ *
+ * Cependant, les appels à ces dernières depuis la clôture organisée par la fonction
+ * PyExit_pychrysalide() provoque l'erreur suivante :
+ *
+ * Fatal Python error: _PyInterpreterState_GET: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
+ *
+ * Les accès nécessaires sont donc conservés ici.
+ */
+static PyTypeObject *__gobject_meta_base = NULL;
+static PyTypeObject *__gobject_meta = NULL;
+
+/* Interceptionne une initialisation pour types gi._gi.GObject. */
+static int hook_gobject_meta_base_init(PyObject *, PyObject *, PyObject *);
+
+/* Interceptionne une initialisation pour types GObject.Object. */
+static int hook_gobject_meta_init(PyObject *, PyObject *, PyObject *);
+
+/* Modifie légèrement le comportement des GObjects en Python. */
+static bool hook_pygobject_behaviour(void);
+
+/* Restaure le comportement d'origine des GObjects en Python. */
+static void unhook_pygobject_behaviour(void);
+
/* Assure la définition d'un type GObject pour Python adapté. */
static void ensure_native_pygobject_type(PyTypeObject **);
@@ -113,7 +146,7 @@ static void ensure_native_pygobject_type(PyTypeObject **);
static PyObject *get_existing_modules(void);
/* Définit les différents modules du support Python. */
-static PyObject *create_basic_modules(void);
+static PyObject *create_basic_modules(const pyinit_details_t *);
/* Inscrit les défintions des objets Python de Chrysalide. */
static bool populate_python_modules(const pyinit_details_t *);
@@ -122,9 +155,12 @@ static bool populate_python_modules(const pyinit_details_t *);
static void restore_original_pygobject_type(PyTypeObject *);
+
/* ------------------------ FONCTIONS GLOBALES DE CHRYSALIDE ------------------------ */
+/* Assure le plein chargement dans un interpréteur Python. */
+static bool init_python_interpreter_for_standalone_mode(const pyinit_details_t *);
/* Point de sortie pour l'initialisation de Python. */
static void PyExit_pychrysalide(void);
@@ -503,6 +539,265 @@ static bool setup_python_context(void)
/******************************************************************************
* *
+* Paramètres : cls = classe instanciée pour la construction d'un objet. *
+* *
+* Description : Intègre les éventuelles fonctions natives des interfaces. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void inherit_interface_slots(PyObject *cls)
+{
+ GType gtype; /* Type GObject lié au Python */
+ GType *ifaces; /* Interfaces implémentées */
+ guint ifaces_count; /* Nombre de ces interfaces */
+ guint i; /* Boucle de parcours */
+ PyTypeObject *iface_type; /* Type Python pour interface */
+ size_t k; /* Boucle de parcours */
+ size_t offset; /* Position dans une structure */
+ void *src_slot; /* Eventuelle fonction idéale */
+ void *dst_slot; /* Eventuelle fonction en place*/
+
+ static size_t slot_offsets[] = { /* Emplacements à actualiser */
+ //offsetof(PyTypeObject, tp_str),
+ offsetof(PyTypeObject, tp_hash),
+ offsetof(PyTypeObject, tp_richcompare),
+ };
+
+ /**
+ * Cette fonction reprend les principes de la fonction d'importation de
+ * PyGObject pygobject_inherit_slots().
+ *
+ * Cependant, cette dernière n'est appelée que depuis les fonctions :
+ * - pygobject_register_class() (send C -> Python), qui peut écraser des
+ * slots existants ;
+ * - pygobject_new_with_interfaces() / pygobject_lookup_class(), qui ne
+ * remplace pas les fonctions par défaut déjà en place.
+ *
+ * Pour mémoire, les types créés dynamiquement depuis des scripts (sens
+ * Python -> C) passent par la fonction _wrap_pyg_type_register().
+ */
+
+ gtype = pyg_type_from_object(cls);
+ assert(gtype != G_TYPE_INVALID);
+
+ ifaces = g_type_interfaces(gtype, &ifaces_count);
+
+ for (i = 0; i < ifaces_count; i++)
+ {
+ iface_type = pygobject_lookup_class(ifaces[i]);
+
+#define PYTYPE_SLOT(tp, off) \
+ *(void **)(void *)(((char *)tp) + off)
+
+ for (k = 0; k < ARRAY_SIZE(slot_offsets); k++)
+ {
+ offset = slot_offsets[k];
+
+ src_slot = PYTYPE_SLOT(iface_type, offset);
+
+ if (src_slot == NULL)
+ continue;
+
+ if (src_slot == PYTYPE_SLOT(&PyBaseObject_Type, offset)
+ || src_slot == PYTYPE_SLOT(&PyGObject_Type, offset))
+ continue;
+
+ dst_slot = PYTYPE_SLOT(cls, offset);
+
+ if (src_slot == dst_slot)
+ continue;
+
+ if (dst_slot != NULL)
+ {
+ if (dst_slot != PYTYPE_SLOT(&PyBaseObject_Type, offset)
+ && dst_slot != PYTYPE_SLOT(&PyGObject_Type, offset))
+ continue;
+ }
+
+ /**
+ * Usage du *(void **)(void *)
+ */
+ PYTYPE_SLOT(cls, offset) = src_slot;
+
+ }
+
+ }
+
+ g_free(ifaces);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Interceptionne une initialisation pour types gi._gi.GObject. *
+* *
+* Retour : Bilan de l'initialisation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int hook_gobject_meta_base_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int result; /* Bilan à retourner */
+
+ /**
+ * Le type de self (self->ob_type->tp_name) est ici _GObjectMetaBase.
+ */
+
+ result = __old_gobject_meta_base_init(self, args, kwds);
+
+ if (result == 0)
+ inherit_interface_slots(self);
+
+ return result;
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
+* *
+* Description : Interceptionne une initialisation pour types GObject.Object. *
+* *
+* Retour : Bilan de l'initialisation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int hook_gobject_meta_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int result; /* Bilan à retourner */
+
+ /**
+ * Le type de self (self->ob_type->tp_name) est ici GObjectMeta.
+ */
+
+ result = __old_gobject_meta_init(self, args, kwds);
+
+ if (result == 0)
+ inherit_interface_slots(self);
+
+ return result;
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Modifie légèrement le comportement des GObjects en Python. *
+* *
+* Retour : Bilan de l'initialisation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool hook_pygobject_behaviour(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *gi_types_mod; /* Module Python-GObject */
+
+ result = false;
+
+ /**
+ * Validation des accès.
+ *
+ * Les références prises sur les attributs sont restituées dans
+ * unhook_pygobject_behaviour().
+ */
+
+ gi_types_mod = PyImport_ImportModule("gi.types");
+ if (gi_types_mod == NULL) goto exit;
+
+ __gobject_meta_base = (PyTypeObject *)PyObject_GetAttrString(gi_types_mod, "_GObjectMetaBase");
+ assert(__gobject_meta_base != NULL);
+ if (__gobject_meta_base == NULL) goto exit_with_mod;
+
+ __gobject_meta = (PyTypeObject *)PyObject_GetAttrString(gi_types_mod, "GObjectMeta");
+ assert(__gobject_meta != NULL);
+ if (__gobject_meta == NULL) goto exit_with_mod;
+
+ /**
+ * Modification des comportements.
+ */
+
+ __old_gobject_meta_base_init = __gobject_meta_base->tp_init;
+
+ __gobject_meta_base->tp_init = hook_gobject_meta_base_init;
+
+ __old_gobject_meta_init = __gobject_meta->tp_init;
+
+ __gobject_meta->tp_init = hook_gobject_meta_init;
+
+ result = true;
+
+ exit_with_mod:
+
+ Py_DECREF(gi_types_mod);
+
+ exit:
+
+ if (!result)
+ PyErr_SetString(PyExc_SystemError, "unable to hook the GObject behaviour in Python.");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Restaure le comportement d'origine des GObjects en Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void unhook_pygobject_behaviour(void)
+{
+ /**
+ * Le déclenchement de la fonction PyExit_pychrysalide() appelante est
+ * programmé depuis init_python_pychrysalide_module(), appelée si
+ * hook_pygobject_behaviour() a opéré avec réussite.
+ */
+ assert(__gobject_meta_base != NULL);
+ assert(__gobject_meta != NULL);
+
+ __gobject_meta_base->tp_init = __old_gobject_meta_base_init;
+
+ Py_XDECREF(__gobject_meta_base);
+
+ __gobject_meta->tp_init = __old_gobject_meta_init;
+
+ Py_XDECREF(__gobject_meta);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : namespace = module particulier à charger à partir de gi. *
* version = idenfiant de la version à stipuler. *
* *
@@ -681,7 +976,7 @@ static PyObject *get_existing_modules(void)
/******************************************************************************
* *
-* Paramètres : - *
+* Paramètres : details = précisions de chargement complémentaires. *
* *
* Description : Définit les différents modules du support Python. *
* *
@@ -691,7 +986,7 @@ static PyObject *get_existing_modules(void)
* *
******************************************************************************/
-static PyObject *create_basic_modules(void)
+static PyObject *create_basic_modules(const pyinit_details_t *details)
{
PyObject *result; /* Module Python à retourner */
bool status; /* Bilan des inclusions */
@@ -739,14 +1034,17 @@ static PyObject *create_basic_modules(void)
*/
if (status) status = add_format_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);
+ /**
+ * Ajout de modules UI supplémentaires éventuels.
+ */
+
+ if (status && details->add_extra != NULL)
+ status = details->add_extra(result);
+
if (!status)
{
Py_DECREF(result);
@@ -784,8 +1082,8 @@ static bool populate_python_modules(const pyinit_details_t *details)
* un chargement préliminaire, si besoin est.
*/
- if (details->populate_extra)
- result = details->populate_extra();
+ if (details->populate_extra != NULL)
+ result = details->populate_extra(false);
else
result = true;
@@ -804,14 +1102,22 @@ static bool populate_python_modules(const pyinit_details_t *details)
*/
if (result) result = populate_format_module();
/*
-#ifdef INCLUDE_GTK_SUPPORT
- if (result) result = populate_gtkext_module();
- if (result) result = populate_gui_module();
-#endif
if (result) result = populate_mangling_module();
*/
if (result) result = populate_plugins_module();
+ /**
+ * Certaines définitions reposent sur une déclinaison de GtkWidget,
+ * dont le chargement va remplacer la définition statique de GObject
+ * par une version allouée dynamiquement.
+ *
+ * De telles définitions doivent donc être prise en compte à la fin
+ * du chargement.
+ */
+
+ if (result && details->populate_extra != NULL)
+ result = details->populate_extra(true);
+
return result;
}
@@ -873,6 +1179,9 @@ PyObject *init_python_pychrysalide_module(const pyinit_details_t *details)
if (!setup_python_context())
goto exit;
+ if (!hook_pygobject_behaviour())
+ goto exit;
+
/**
* Le chargement forcé de l'espace GLib pour Python permet d'éviter un écueil,
* à savoir des types convertis de façon incomplète. Par exemple, pour une
@@ -902,7 +1211,7 @@ PyObject *init_python_pychrysalide_module(const pyinit_details_t *details)
ensure_native_pygobject_type(&py_gobj_def);
- result = create_basic_modules();
+ result = create_basic_modules(details);
if (result == NULL)
PyErr_SetString(PyExc_SystemError, "failed to create all PyChrysalide modules.");
@@ -915,7 +1224,7 @@ PyObject *init_python_pychrysalide_module(const pyinit_details_t *details)
PyErr_SetString(PyExc_SystemError, "failed to load all PyChrysalide components.");
else if (details->standalone)
- status = do_global_init();
+ status = init_python_interpreter_for_standalone_mode(details);
if (!status)
{
@@ -1056,121 +1365,141 @@ void log_pychrysalide_exception(const char *prefix, ...)
/* ---------------------------------------------------------------------------------- */
-/* FONCTIONS GLOBALES DE CHRYSALIDE */
+/* INTERVENTION DANS LA GESTION DE GREFFONS */
/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : py_gobj_def = définition de type actuelle. [OUT] *
+* Paramètres : plugin = instance représentant le greffon courant. *
+* path = chemin supplémentaire pour l'espace de recherche. *
* *
-* Description : Restore une ancienne définition de type GObject au besoin. *
+* Description : Complète les chemins de recherches de Python. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-bool do_global_init(void)
+void extend_python_path(const GPluginModule *plugin, const char *path)
{
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *list; /* Liste de chemins à compléter*/
+ PyObject *new; /* Nouveau chemin à intégrer */
+
+ gstate = PyGILState_Ensure();
+
+ list = PySys_GetObject("path");
+ assert(list != NULL);
+
+ new = PyUnicode_FromString(path);
+ assert(new != NULL);
+
+ PyList_Append(list, new);
+
+ Py_DECREF(new);
+
+ add_to_env_var("PYTHONPATH", path, ":");
+
+ PyGILState_Release(gstate);
+
+ g_plugin_module_log_variadic_message(plugin, LMT_INFO,
+ _("PYTHONPATH environment variable set to '%s'"),
+ getenv("PYTHONPATH"));
+
+}
- return true;
- return false;
-#if 0
+/* ---------------------------------------------------------------------------------- */
+/* FONCTIONS GLOBALES DE CHRYSALIDE */
+/* ---------------------------------------------------------------------------------- */
+
+/******************************************************************************
+* *
+* Paramètres : details = précisions de chargement complémentaires. *
+* *
+* Description : Assure le plein chargement dans un interpréteur Python. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+static bool init_python_interpreter_for_standalone_mode(const pyinit_details_t *details)
+{
bool result; /* Bilan à retourner */
int ret; /* Bilan de préparatifs */
-#ifdef PYTHON_PACKAGE
Dl_info info; /* Informations dynamiques */
-#endif
+ GModule *module; /* Structure de chargement GLib*/
GPluginModule *self; /* Représentation interne */
- PluginStatusFlags self_flags; /* Fanions à mettre à jour */
+
+ result = false;
ret = Py_AtExit(PyExit_pychrysalide);
if (ret == -1)
{
PyErr_SetString(PyExc_SystemError, "failed to register a cleanup function.");
- goto exit_and_restore;
+ goto exit;
+ }
+
+ if (!load_core_components(ACC_ALL_COMPONENTS))
+ {
+ PyErr_SetString(PyExc_SystemError, "unable to load core components.");
+ goto exit;
}
/**
- * Si cette extension pour Python est chargée depuis un dépôt Python,
- * elle ne se trouve pas dans le répertoire classique des extensions et
- * n'est donc pas chargée et enregistrée comme attendu.
+ * Le module chargé par Python n'apparaît pas dans la liste des greffons de
+ * Chrysalide et ne peut donc pas être référencé comme dépendance par d'autres
+ * extensions.
*
- * Cet enregistrement est donc forcé ici.
+ * Par ailleurs, lors de la recherche d'autres greffons via l'appel à la
+ * fonction init_all_plugins() ci-après, il faut que le nom du greffon soit
+ * déjà réservé pour faire échouer le second chargement du greffon courant
+ * lors du parcours des répertoires conservant les fichiers d'extensions.
*/
-#ifdef PYTHON_PACKAGE
-
ret = dladdr(__FUNCTION__, &info);
if (ret == 0)
{
LOG_ERROR_DL_N("dladdr");
-
- // err msg
-
-
- Py_DECREF(result);
- result = NULL;
-
- goto exit_and_restore;
- }
-
- self = g_plugin_module_new(info.dli_fname);
- assert(self != NULL);
-
- register_plugin(self);
-
-#endif
-
-
- if (!load_core_components(ACC_GLOBAL_VARS))
- {
- PyErr_SetString(PyExc_SystemError, "unable to load core components.");
+ PyErr_SetString(PyExc_SystemError, "failed to force bindings registration.");
goto exit;
- }
- init_all_plugins(false);
+ }
- lock_plugin_list_for_reading();
+ module = g_module_open(info.dli_fname, G_MODULE_BIND_LAZY);
+ assert(module != NULL);
- self = get_plugin_by_name("PyChrysalide", NULL);
- assert(self != NULL);
+ self = details->create_self(module);
- self_flags = g_plugin_module_get_flags(self);
- self_flags &= ~(PSF_FAILURE | PSF_LOADED);
- self_flags |= (status ? PSF_LOADED : PSF_FAILURE);
+ /* A ce stade, le greffon a été chargé correctement */
+ g_plugin_module_override_flags(self, PSF_LOADED);
- g_plugin_module_override_flags(self, self_flags);
+ register_plugin(self);
unref_object(self);
- unlock_plugin_list_for_reading();
-
- load_remaning_plugins();
-
-
+ /**
+ * Intégration des fonctionnalités portées par d'autres greffons.
+ */
+ result = true;
+ init_all_plugins(true);
- done:
+ exit:
return result;
-#endif
-
}
-
/******************************************************************************
* *
* Paramètres : - *
@@ -1185,24 +1514,10 @@ bool do_global_init(void)
static void PyExit_pychrysalide(void)
{
- //assert(_standalone);
-
- /*
- extern void set_current_project(void *project);
-
- set_current_project(NULL);
- */
-
-#ifdef TRACK_GOBJECT_LEAKS
- remember_gtypes_for_leaks();
-#endif
+ unhook_pygobject_behaviour();
exit_all_plugins();
- //unload_all_core_components(true);
-
-#ifdef TRACK_GOBJECT_LEAKS
- dump_remaining_gtypes();
-#endif
+ unload_core_components(ACC_ALL_COMPONENTS);
}
diff --git a/plugins/pychrysalide/bindings.h b/plugins/pychrysalide/bindings.h
index e9ee421..036f852 100644
--- a/plugins/pychrysalide/bindings.h
+++ b/plugins/pychrysalide/bindings.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* bindings.h - prototypes pour les éléments d'un socle commun aux fonctionnalités graphiques et non graphiques
*
- * Copyright (C) 2024 Cyrille Bagard
+ * Copyright (C) 2024-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -36,9 +36,16 @@
#include <Python.h>
+#include <gmodule.h>
#include <stdbool.h>
+#include <plugins/plugin.h>
+
+
+
+/* ------------------------ FONCTIONNALITES DE MISE EN PLACE ------------------------ */
+
/* Charge un module GI dans Python avec une version attendue. */
bool import_namespace_from_gi_repository(const char *, const char *);
@@ -48,7 +55,15 @@ typedef struct _pyinit_details_t
{
bool standalone; /* Chargement depuis Python ? */
- bool (* populate_extra) (void); /* Ajout de types ? */
+ bool (* add_extra) (PyObject *); /* Ajout de modules ? */
+
+ bool (* populate_extra) (bool); /* Ajout de types ? */
+
+ /**
+ * Prototype de la fonction de création, à garder synchronisé avec
+ * NATIVE_PLUGIN_ENTRYPOINT() (cf. native-int.h).
+ */
+ GPluginModule * (* create_self) (GModule *);
} pyinit_details_t;
@@ -60,7 +75,11 @@ void log_pychrysalide_exception(const char *, ...);
-bool do_global_init(void);
+/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */
+
+
+/* Complète les chemins de recherches de Python. */
+void extend_python_path(const GPluginModule *, const char *);
diff --git a/plugins/pychrysalide/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am
index 43e1fc4..ad58900 100644
--- a/plugins/pychrysalide/common/Makefile.am
+++ b/plugins/pychrysalide/common/Makefile.am
@@ -6,7 +6,6 @@ noinst_LTLIBRARIES = libpychrysacommon.la
# 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 \
@@ -15,6 +14,7 @@ noinst_LTLIBRARIES = libpychrysacommon.la
libpychrysacommon_la_SOURCES = \
bits.h bits.c \
entropy.h entropy.c \
+ leb128.h leb128.c \
module.h module.c \
xdg.h xdg.c
diff --git a/plugins/pychrysalide/common/leb128.c b/plugins/pychrysalide/common/leb128.c
index 8b15303..2eeb191 100644
--- a/plugins/pychrysalide/common/leb128.c
+++ b/plugins/pychrysalide/common/leb128.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* leb128.c - équivalent Python du fichier "common/leb128.c"
*
- * Copyright (C) 2018-2020 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,13 +26,13 @@
#include <assert.h>
+#include <malloc.h>
#include <pygobject.h>
#include <common/leb128.h>
-#include "packed.h"
#include "../access.h"
#include "../helpers.h"
@@ -69,31 +69,29 @@ static PyObject *py_leb128_pack_uleb128(PyObject *self, PyObject *args)
{
PyObject *result; /* Valeur à retourner */
uleb128_t value; /* Valeur à manipuler */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
int ret; /* Bilan de lecture des args. */
- bool status; /* Bilan de l'opération */
-
-#define LEB128_PACK_ULEB128_METHOD PYTHON_METHOD_DEF \
-( \
- pack_uleb128, "value, pbuf", \
- METH_VARARGS, py_leb128, \
- "Pack an unsigned LEB128 value into a data buffer.\n" \
- "\n" \
- "The *value* is an integer value. The *pbuf* argument has to" \
- " be a pychrysalide.common.PackedBuffer instance where data" \
- " will be appended.\n" \
- "\n" \
- "The returned value is the operation status: *True* for" \
- " success, *False* for failure." \
+ size_t count; /* Nombre d'octets produits */
+ void *bytes; /* Octets de représentation */
+
+#define LEB128_PACK_ULEB128_METHOD PYTHON_METHOD_DEF \
+( \
+ pack_uleb128, "value", \
+ METH_VARARGS, py_leb128, \
+ "Pack an unsigned LEB128 value into bytes.\n" \
+ "\n" \
+ "The *value* has to be an integer value.\n" \
+ "\n" \
+ "The returned value is byte data." \
)
- ret = PyArg_ParseTuple(args, "O&O&", convert_to_uleb128_value, &value, convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "O&", convert_to_uleb128_value, &value);
if (!ret) return NULL;
- status = pack_uleb128(&value, pbuf);
+ bytes = pack_uleb128(&value, &count);
- result = status ? Py_True : Py_False;
- Py_INCREF(result);
+ result = PyBytes_FromStringAndSize(bytes, count);
+
+ free(bytes);
return result;
@@ -117,31 +115,29 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args)
{
PyObject *result; /* Valeur à retourner */
leb128_t value; /* Valeur à manipuler */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
int ret; /* Bilan de lecture des args. */
- bool status; /* Bilan de l'opération */
-
-#define LEB128_PACK_LEB128_METHOD PYTHON_METHOD_DEF \
-( \
- pack_leb128, "value, pbuf", \
- METH_VARARGS, py_leb128, \
- "Pack a signed LEB128 value into a data buffer.\n" \
- "\n" \
- "The *value* is an integer value. The *pbuf* argument has to" \
- " be a pychrysalide.common.PackedBuffer instance where data" \
- " will be appended.\n" \
- "\n" \
- "The returned value is the operation status: *True* for" \
- " success, *False* for failure." \
+ size_t count; /* Nombre d'octets produits */
+ void *bytes; /* Octets de représentation */
+
+#define LEB128_PACK_LEB128_METHOD PYTHON_METHOD_DEF \
+( \
+ pack_leb128, "value", \
+ METH_VARARGS, py_leb128, \
+ "Pack a signed LEB128 value into bytes.\n" \
+ "\n" \
+ "The *value* has to be an integer value.\n" \
+ "\n" \
+ "The returned value is byte data." \
)
- ret = PyArg_ParseTuple(args, "O&O&", convert_to_leb128_value, &value, convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "O&", convert_to_leb128_value, &value);
if (!ret) return NULL;
- status = pack_leb128(&value, pbuf);
+ bytes = pack_leb128(&value, &count);
+
+ result = PyBytes_FromStringAndSize(bytes, count);
- result = status ? Py_True : Py_False;
- Py_INCREF(result);
+ free(bytes);
return result;
@@ -164,33 +160,42 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args)
static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args)
{
PyObject *result; /* Valeur à retourner */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
+ const char *bytes; /* Octets brutes transmis */
+ Py_ssize_t count; /* Quantité de ces octets */
int ret; /* Bilan de lecture des args. */
+ const void *pos; /* Tëte de lecture */
+ const void *max; /* Position de lecture maximale*/
uleb128_t value; /* Valeur à manipuler */
bool status; /* Bilan de l'opération */
#define LEB128_UNPACK_ULEB128_METHOD PYTHON_METHOD_DEF \
( \
- unpack_uleb128, "pbuf", \
+ unpack_uleb128, "buf", \
METH_VARARGS, py_leb128, \
- "Unpack an unsigned LEB128 value into a data buffer.\n" \
+ "Unpack an unsigned LEB128 value from bytes.\n" \
"\n" \
- "The *pbuf* argument has to be a" \
- " pychrysalide.common.PackedBuffer instance from where data" \
- " will be read.\n" \
+ "The *buf* argument needs to be bytes with enough data aimed" \
+ " to get translated into an unsigned LEB128 value.\n" \
"\n" \
"The returned value depends on the operation status: *None*" \
- " for failure or a integer value for success." \
+ " for failure or a tuple with two items for success: the" \
+ " decoded value and the remaining bytes." \
)
- ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "y#", &bytes, &count);
if (!ret) return NULL;
- status = unpack_uleb128(&value, pbuf);
+ pos = bytes;
+ max = bytes + count;
- if (status)
- result = PyLong_FromUnsignedLongLong(value);
+ status = unpack_uleb128(&value, &pos, max);
+ if (status)
+ {
+ result = PyTuple_New(2);
+ PyTuple_SetItem(result, 0, PyLong_FromUnsignedLongLong(value));
+ PyTuple_SetItem(result, 1, PyBytes_FromStringAndSize(pos, (char *)max - (char *)pos));
+ }
else
{
result = Py_None;
@@ -218,33 +223,43 @@ static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args)
static PyObject *py_leb128_unpack_leb128(PyObject *self, PyObject *args)
{
PyObject *result; /* Valeur à retourner */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
+ const char *bytes; /* Octets brutes transmis */
+ Py_ssize_t count; /* Quantité de ces octets */
int ret; /* Bilan de lecture des args. */
+ const void *pos; /* Tëte de lecture */
+ const void *max; /* Position de lecture maximale*/
leb128_t value; /* Valeur à manipuler */
bool status; /* Bilan de l'opération */
#define LEB128_UNPACK_LEB128_METHOD PYTHON_METHOD_DEF \
( \
- unpack_leb128, "pbuf", \
+ unpack_leb128, "buf", \
METH_VARARGS, py_leb128, \
- "Unpack a signed LEB128 value into a data buffer.\n" \
+ "Unpack a signed LEB128 value from bytes.\n" \
"\n" \
- "The *pbuf* argument has to be a" \
- " pychrysalide.common.PackedBuffer instance from where data" \
- " will be read.\n" \
+ "\n" \
+ "The *buf* argument needs to be bytes with enough data aimed" \
+ " to get translated into a signed LEB128 value.\n" \
"\n" \
"The returned value depends on the operation status: *None*" \
- " for failure or a integer value for success." \
+ " for failure or a tuple with two items for success: the" \
+ " decoded value and the remaining bytes." \
)
- ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "y#", &bytes, &count);
if (!ret) return NULL;
- status = unpack_leb128(&value, pbuf);
+ pos = bytes;
+ max = bytes + count;
- if (status)
- result = PyLong_FromLongLong(value);
+ status = unpack_leb128(&value, &pos, max);
+ if (status)
+ {
+ result = PyTuple_New(2);
+ PyTuple_SetItem(result, 0, PyLong_FromLongLong(value));
+ PyTuple_SetItem(result, 1, PyBytes_FromStringAndSize(pos, (char *)max - (char *)pos));
+ }
else
{
result = Py_None;
diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c
index fa2b4de..c82c7bc 100644
--- a/plugins/pychrysalide/common/module.c
+++ b/plugins/pychrysalide/common/module.c
@@ -30,7 +30,7 @@
//#include "fnv1a.h"
//#include "hex.h"
//#include "itoa.h"
-//#include "leb128.h"
+#include "leb128.h"
//#include "packed.h"
//#include "pathname.h"
//#include "pearson.h"
@@ -104,11 +104,11 @@ 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();
*/
if (result) result = populate_common_module_with_entropy();
+ if (result) result = populate_common_module_with_leb128();
if (result) result = populate_common_module_with_xdg();
if (result) result = ensure_python_bitfield_is_registered();
diff --git a/plugins/pychrysalide/constants.h b/plugins/pychrysalide/constants.h
index 332afe0..151f1eb 100644
--- a/plugins/pychrysalide/constants.h
+++ b/plugins/pychrysalide/constants.h
@@ -46,6 +46,9 @@ int convert_to_source_endian(PyObject *, void *);
/* Tente de convertir en constante MemoryDataSize. */
int convert_to_memory_data_size(PyObject *, void *);
+#define cast_memory_data_size_to_python(v) \
+ cast_with_constants_group_from_module("pychrysalide", "MemoryDataSize", v)
+
#endif /* _PLUGINS_PYCHRYSALIDE_CONSTANTS_H */
diff --git a/plugins/pychrysalide/convert.c b/plugins/pychrysalide/convert.c
new file mode 100644
index 0000000..08866cb
--- /dev/null
+++ b/plugins/pychrysalide/convert.c
@@ -0,0 +1,120 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * convert.c - conversion d'arguments en éléments usuels externes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "convert.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+#ifndef NDEBUG
+# include <stdbool.h>
+#endif
+#include <gio/gio.h>
+
+
+
+/******************************************************************************
+* *
+* 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 GSettings. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_gsettings(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ GType type; /* Type obtenu ou 0 */
+
+ result = PyObject_IsInstance(arg, (PyObject *)&PyGObject_Type);
+
+ if (result == 1)
+ {
+ type = pyg_type_from_object(arg);
+
+ if (type != G_TYPE_SETTINGS)
+ result = 0;
+
+ }
+
+ 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 GSetting instance");
+ break;
+
+ case 1:
+ *((GSettings **)dst) = G_SETTINGS(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ 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 instance GSettings ou NULL. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_gsettings_or_none(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ if (arg == Py_None)
+ {
+ *((GSettings **)dst) = NULL;
+ result = 1;
+ }
+
+ else
+ result = convert_to_gsettings(arg, dst);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/convert.h b/plugins/pychrysalide/convert.h
new file mode 100644
index 0000000..86d7528
--- /dev/null
+++ b/plugins/pychrysalide/convert.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * convert.h - prototypes pour la conversion d'arguments en éléments usuels externes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_CONVERT_H
+#define _PLUGINS_PYCHRYSALIDE_CONVERT_H
+
+
+#include <Python.h>
+
+
+
+/* Tente de convertir en instance GSettings. */
+int convert_to_gsettings(PyObject *, void *);
+
+/* Tente de convertir en instance GSettings ou NULL. */
+int convert_to_gsettings_or_none(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_CONVERT_H */
diff --git a/plugins/pychrysalide/core-ui.c b/plugins/pychrysalide/core-ui.c
index 32d3516..00d1cc1 100644
--- a/plugins/pychrysalide/core-ui.c
+++ b/plugins/pychrysalide/core-ui.c
@@ -28,11 +28,19 @@
#include <i18n.h>
+#ifdef DISCARD_LOCAL
+# include <core/paths.h>
+#endif
+#include <plugins/manager-int.h>
#include <plugins/self.h>
#include "bindings.h"
#include "core-ui-int.h"
+#include "arch/module-ui.h"
+#include "glibext/module-ui.h"
+#include "gtkext/module.h"
+//#include "gui/module.h"
@@ -47,14 +55,17 @@ static bool _standalone = true;
/* Initialise la classe des greffons de support Python. */
static void g_pychrysalide_plugin_ui_class_init(GPyChrysalidePluginUIClass *);
+/* Procède à l'initialisation de l'interface de gestion. */
+static void g_pychrysalide_plugin_ui_plugin_manager_interface_init(GPluginManagerInterface *);
+
/* Initialise une instance de greffon de support Python. */
static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *);
/* Supprime toutes les références externes. */
-static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *);
+static void g_pychrysalide_plugin_ui_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *);
+static void g_pychrysalide_plugin_ui_finalize(GObject *);
@@ -62,7 +73,26 @@ static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *);
/* Prend acte de l'activation du greffon. */
-static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *);
+static bool g_pychrysalide_plugin_ui_enable(GPluginModule *);
+
+
+
+/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */
+
+
+/* Prend acte du chargement de l'ensemble des greffons natifs. */
+static void g_pychrysalide_plugin_ui_handle_native_plugins_loaded_event(GPluginManager *);
+
+
+
+/* --------------------------- POINT D'ENTREE POUR PYTHON --------------------------- */
+
+
+/*Ajoute des modules UI aux extensions Python. */
+static bool add_python_ui_modules(PyObject *);
+
+/* Inscrit les défintions des objets UI Python de Chrysalide. */
+static bool populate_python_modules_ui(bool);
@@ -72,7 +102,8 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *);
/* Indique le type défini pour un greffon de liaison Python */
-G_DEFINE_TYPE(GPyChrysalidePluginUI, g_pychrysalide_plugin_ui, G_TYPE_PYCHRYSALIDE_PLUGIN);
+G_DEFINE_TYPE_WITH_CODE(GPyChrysalidePluginUI, g_pychrysalide_plugin_ui, G_TYPE_PYCHRYSALIDE_PLUGIN,
+ G_IMPLEMENT_INTERFACE(G_TYPE_PLUGIN_MANAGER, g_pychrysalide_plugin_ui_plugin_manager_interface_init));
NATIVE_PLUGIN_ENTRYPOINT(g_pychrysalide_plugin_ui_new);
@@ -97,12 +128,31 @@ static void g_pychrysalide_plugin_ui_class_init(GPyChrysalidePluginUIClass *clas
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_pychrysalide_plugin_ui_dispose;
- object->finalize = (GObjectFinalizeFunc)g_pychrysalide_plugin_ui_finalize;
+ object->dispose = g_pychrysalide_plugin_ui_dispose;
+ object->finalize = g_pychrysalide_plugin_ui_finalize;
plugin = G_PLUGIN_MODULE_CLASS(class);
- plugin->enable = (pg_management_fc)g_pychrysalide_plugin_ui_enable;
+ plugin->enable = g_pychrysalide_plugin_ui_enable;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de gestion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_pychrysalide_plugin_ui_plugin_manager_interface_init(GPluginManagerInterface *iface)
+{
+ iface->handle_native = g_pychrysalide_plugin_ui_handle_native_plugins_loaded_event;
}
@@ -127,7 +177,7 @@ static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *plugin)
/******************************************************************************
* *
-* Paramètres : plugin = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -137,16 +187,16 @@ static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *plugin)
* *
******************************************************************************/
-static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *plugin)
+static void g_pychrysalide_plugin_ui_dispose(GObject *object)
{
- G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->dispose(G_OBJECT(plugin));
+ G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : plugin = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -156,16 +206,16 @@ static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *plugin)
* *
******************************************************************************/
-static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *plugin)
+static void g_pychrysalide_plugin_ui_finalize(GObject *object)
{
- G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->finalize(G_OBJECT(plugin));
+ G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->finalize(object);
}
/******************************************************************************
* *
-* Paramètres : filename = nom du fichier à charger. *
+* Paramètres : module = extension vue du système. *
* *
* Description : Crée un module pour un greffon de support Python. *
* *
@@ -179,7 +229,7 @@ GPluginModule *g_pychrysalide_plugin_ui_new(GModule *module)
{
GPyChrysalidePluginUI *result; /* Structure à retourner */
- result = g_object_new(G_TYPE_PYCHRYSALIDE_PLUGIN, NULL);
+ result = g_object_new(G_TYPE_PYCHRYSALIDE_PLUGIN_UI, NULL);
if (!g_pychrysalide_plugin_ui_create(result, module))
g_clear_object(&result);
@@ -192,7 +242,7 @@ GPluginModule *g_pychrysalide_plugin_ui_new(GModule *module)
/******************************************************************************
* *
* Paramètres : plugin = instance à initialiser pleinement. *
-* module = module système correspondant. *
+* module = extension vue du système. *
* *
* Description : Met en place un module pour un greffon de support Python. *
* *
@@ -231,22 +281,24 @@ bool g_pychrysalide_plugin_ui_create(GPyChrysalidePluginUI *plugin, GModule *mod
* *
******************************************************************************/
-static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin)
+static bool g_pychrysalide_plugin_ui_enable(GPluginModule *plugin)
{
bool result; /* Bilan à retourner */
+ GPyChrysalidePlugin *pychr_plugin; /* Version spécialisée */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
int ret; /* Bilan de préparatifs */
_standalone = false;
+ pychr_plugin = G_PYCHRYSALIDE_PLUGIN(plugin);
+
/* Chargement du module pour Python */
ret = PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalideui);
if (ret == -1)
{
- g_plugin_module_log_simple_message(G_PLUGIN_MODULE(plugin),
- LMT_ERROR,
+ g_plugin_module_log_simple_message(plugin, LMT_ERROR,
_("Can not extend the existing table of Python built-in modules."));
result = false;
@@ -258,7 +310,7 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin)
gstate = PyGILState_Ensure();
- G_PYCHRYSALIDE_PLUGIN(plugin)->py_module = PyImport_ImportModule("pychrysalide");
+ pychr_plugin->py_module = PyImport_ImportModule("pychrysalide");
/**
* Pour mémoire, une situation concrête conduisant à un échec :
@@ -273,7 +325,7 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin)
// TODO : check (2025)
- result = (G_PYCHRYSALIDE_PLUGIN(plugin)->py_module != NULL);
+ result = (pychr_plugin->py_module != NULL);
PyGILState_Release(gstate);
@@ -286,12 +338,139 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin)
/* ---------------------------------------------------------------------------------- */
+/* INTERVENTION DANS LA GESTION DE GREFFONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = interface à manipuler. *
+* *
+* Description : Accompagne la fin du chargement des modules natifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_pychrysalide_plugin_ui_handle_native_plugins_loaded_event(GPluginManager *manager)
+{
+ GPluginModule *plugin; /* Version de base du greffon */
+#ifdef DISCARD_LOCAL
+ char *edir; /* Répertoire de base effectif */
+ DIR *dir; /* Répertoire à parcourir */
+#endif
+ GPluginManagerInterface *iface; /* Interface utilisée */
+ GPluginManagerInterface *parent_iface; /* Interface parente */
+
+ plugin = G_PLUGIN_MODULE(manager);
+
+ /* Définition des zones d'influence */
+
+#ifndef DISCARD_LOCAL
+
+ extend_python_path(plugin, PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "pythonui");
+
+#else
+
+ edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "pythonui");
+
+ dir = opendir(edir);
+
+ if (dir != NULL)
+ {
+ closedir(dir);
+
+ extend_python_path(plugin, edir);
+
+ }
+
+ free(edir);
+
+#endif
+
+ /* Chargements des extensions Python */
+
+ iface = G_PLUGIN_MANAGER_GET_IFACE(manager);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ parent_iface->handle_native(manager);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
/* POINT D'ENTREE POUR PYTHON */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Ajoute des modules UI aux extensions Python. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool add_python_ui_modules(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = add_gtkext_module(super);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : modify = autorisation de motification du type GObject. *
+* *
+* Description : Inscrit les défintions des objets UI Python de Chrysalide. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool populate_python_modules_ui(bool modify)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (!modify)
+ {
+ if (result) result = populate_arch_module_ui();
+ if (result) result = populate_glibext_module_ui();
+
+ }
+
+ else
+ {
+ if (result) result = populate_gtkext_module();
+ //if (result) result = populate_gui_module();
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : - *
* *
* Description : Point d'entrée pour l'initialisation de Python. *
@@ -309,7 +488,9 @@ PyMODINIT_FUNC PyInit_pychrysalideui(void)
details.standalone = _standalone;
- details.populate_extra = NULL;
+ details.add_extra = add_python_ui_modules;
+ details.populate_extra = populate_python_modules_ui;
+ details.create_self = g_pychrysalide_plugin_ui_new;
result = init_python_pychrysalide_module(&details);
diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index fde1028..0fea9c4 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -24,24 +24,14 @@
#include "core.h"
-#include "core-int.h"
-
-
-
-
-
#undef NO_IMPORT_PYGOBJECT
#include <pygobject.h>
#define NO_IMPORT_PYGOBJECT
-#include "core.h"
-
-
#include <assert.h>
#include <errno.h>
#include <malloc.h>
-//#include <pygobject.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
@@ -60,10 +50,9 @@
#include <plugins/self.h>
-
-
#include "access.h"
#include "bindings.h"
+#include "core-int.h"
@@ -72,14 +61,6 @@ static bool _standalone = true;
-
-
-
-
-
-
-
-
/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */
@@ -93,10 +74,10 @@ static void g_pychrysalide_plugin_plugin_manager_interface_init(GPluginManagerIn
static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *);
/* Supprime toutes les références externes. */
-static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *);
+static void g_pychrysalide_plugin_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *);
+static void g_pychrysalide_plugin_finalize(GObject *);
@@ -104,19 +85,16 @@ static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *);
/* Prend acte de l'activation du greffon. */
-static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *);
+static bool g_pychrysalide_plugin_enable(GPluginModule *);
/* Prend acte de la désactivation du greffon. */
-static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *);
+static bool g_pychrysalide_plugin_disable(GPluginModule *);
/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */
-/* Complète les chemins de recherches de Python. */
-static void extend_python_path(const char *);
-
/* Crée un greffon à partir de code Python. */
static GPluginModule *create_python_plugin(const char *, const char *);
@@ -124,7 +102,7 @@ static GPluginModule *create_python_plugin(const char *, const char *);
static void load_python_plugins(GPluginModule *);
/* Prend acte du chargement de l'ensemble des greffons natifs. */
-static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPyChrysalidePlugin *);
+static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPluginManager *);
@@ -160,13 +138,13 @@ static void g_pychrysalide_plugin_class_init(GPyChrysalidePluginClass *class)
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_pychrysalide_plugin_dispose;
- object->finalize = (GObjectFinalizeFunc)g_pychrysalide_plugin_finalize;
+ object->dispose = g_pychrysalide_plugin_dispose;
+ object->finalize = g_pychrysalide_plugin_finalize;
plugin = G_PLUGIN_MODULE_CLASS(class);
- plugin->enable = (pg_management_fc)g_pychrysalide_plugin_enable;
- plugin->disable = (pg_management_fc)g_pychrysalide_plugin_disable;
+ plugin->enable = g_pychrysalide_plugin_enable;
+ plugin->disable = g_pychrysalide_plugin_disable;
}
@@ -185,7 +163,7 @@ static void g_pychrysalide_plugin_class_init(GPyChrysalidePluginClass *class)
static void g_pychrysalide_plugin_plugin_manager_interface_init(GPluginManagerInterface *iface)
{
- iface->handle_native = (handle_native_plugins_cb)g_pychrysalide_plugin_handle_native_plugins_loaded_event;
+ iface->handle_native = g_pychrysalide_plugin_handle_native_plugins_loaded_event;
}
@@ -213,7 +191,7 @@ static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *plugin)
/******************************************************************************
* *
-* Paramètres : plugin = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -223,16 +201,16 @@ static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *plugin)
* *
******************************************************************************/
-static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *plugin)
+static void g_pychrysalide_plugin_dispose(GObject *object)
{
- G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->dispose(G_OBJECT(plugin));
+ G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : plugin = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -242,16 +220,16 @@ static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *plugin)
* *
******************************************************************************/
-static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *plugin)
+static void g_pychrysalide_plugin_finalize(GObject *object)
{
- G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->finalize(G_OBJECT(plugin));
+ G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->finalize(object);
}
/******************************************************************************
* *
-* Paramètres : filename = nom du fichier à charger. *
+* Paramètres : module = extension vue du système. *
* *
* Description : Crée un module pour un greffon de support Python. *
* *
@@ -278,7 +256,7 @@ GPluginModule *g_pychrysalide_plugin_new(GModule *module)
/******************************************************************************
* *
* Paramètres : plugin = instance à initialiser pleinement. *
-* module = module système correspondant. *
+* module = extension vue du système. *
* *
* Description : Met en place un module pour un greffon de support Python. *
* *
@@ -323,22 +301,24 @@ bool g_pychrysalide_plugin_create(GPyChrysalidePlugin *plugin, GModule *module)
* *
******************************************************************************/
-static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin)
+static bool g_pychrysalide_plugin_enable(GPluginModule *plugin)
{
bool result; /* Bilan à retourner */
+ GPyChrysalidePlugin *pychr_plugin; /* Version spécialisée */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
int ret; /* Bilan de préparatifs */
_standalone = false;
+ pychr_plugin = G_PYCHRYSALIDE_PLUGIN(plugin);
+
/* Chargement du module pour Python */
ret = PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalide);
if (ret == -1)
{
- g_plugin_module_log_simple_message(G_PLUGIN_MODULE(plugin),
- LMT_ERROR,
+ g_plugin_module_log_simple_message(plugin, LMT_ERROR,
_("Can not extend the existing table of Python built-in modules."));
result = false;
@@ -350,7 +330,7 @@ static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin)
gstate = PyGILState_Ensure();
- plugin->py_module = PyImport_ImportModule("pychrysalide");
+ pychr_plugin->py_module = PyImport_ImportModule("pychrysalide");
/**
* Pour mémoire, une situation concrête conduisant à un échec :
@@ -365,7 +345,7 @@ static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin)
// TODO : check (2025)
- result = (plugin->py_module != NULL);
+ result = (pychr_plugin->py_module != NULL);
PyGILState_Release(gstate);
@@ -388,58 +368,66 @@ static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin)
* *
******************************************************************************/
-static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *plugin)
+static bool g_pychrysalide_plugin_disable(GPluginModule *plugin)
{
+ bool result; /* Bilan à retourner */
+ GPyChrysalidePlugin *pychr_plugin; /* Version spécialisée */
+ bool standalone; /* Nature du chargement */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- gstate = PyGILState_Ensure();
+ result = true;
- clear_all_accesses_to_python_modules();
-
- Py_XDECREF(plugin->py_module);
- plugin->py_module = NULL;
-
- PyGILState_Release(gstate);
-
-}
+ pychr_plugin = G_PYCHRYSALIDE_PLUGIN(plugin);
+ /**
+ * Le champ plugin->py_module n'est défini que via la fonction
+ * g_pychrysalide_plugin_enable(), qui n'est pas sollicitée lorsque
+ * le module PyChrysalide est mis en place directement par Python.
+ *
+ * L'analyse de ce champ pour retrouver la situation courante est
+ * plus fiable que celle du champ _standalone, potentiellement
+ * cohérent dans la version UI du greffon et resté à son état
+ * initial ici.
+ */
+ standalone = (pychr_plugin->py_module == NULL);
-/* ---------------------------------------------------------------------------------- */
-/* INTERVENTION DANS LA GESTION DE GREFFONS */
-/* ---------------------------------------------------------------------------------- */
+ /**
+ * Si on se trouve embarqué dans un interpréteur Python, le déchargement
+ * des greffons est organisé à partir de la fonction PyExit_pychrysalide(),
+ * directement appelée depuis un contexte Python.
+ *
+ * Un verrou n'est alors pas souhaité ici :
+ *
+ * python3d: ../Python/pystate.c:1687: PyGILState_Ensure: Assertion `gilstate->autoInterpreterState' failed.
+ *
+ * Avec :
+ *
+ * $ python3d --version
+ * Python 3.11.2
+ *
+ */
+ if (!standalone)
+ gstate = PyGILState_Ensure();
-/******************************************************************************
-* *
-* Paramètres : path = chemin supplémentaire pour l'espace de recherche. *
-* *
-* Description : Complète les chemins de recherches de Python. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ clear_all_accesses_to_python_modules();
-static void extend_python_path(const char *path)
-{
- PyObject *list; /* Liste de chemins à compléter*/
- PyObject *new; /* Nouveau chemin à intégrer */
+ Py_XDECREF(pychr_plugin->py_module);
+ pychr_plugin->py_module = NULL;
- list = PySys_GetObject("path");
- assert(list != NULL);
+ if (!standalone)
+ PyGILState_Release(gstate);
- new = PyUnicode_FromString(path);
- assert(new != NULL);
+ return result;
- PyList_Append(list, new);
+}
- Py_DECREF(new);
- add_to_env_var("PYTHONPATH", path, ":");
-}
+/* ---------------------------------------------------------------------------------- */
+/* INTERVENTION DANS LA GESTION DE GREFFONS */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
@@ -531,48 +519,18 @@ static GPluginModule *create_python_plugin(const char *modname, const char *file
static void load_python_plugins(GPluginModule *plugin)
{
-#ifdef DISCARD_LOCAL
- char *edir; /* Répertoire de base effectif */
-#endif
- DIR *dir; /* Répertoire à parcourir */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
char *paths; /* Emplacements de greffons */
char *save; /* Sauvegarde pour ré-entrance */
char *path; /* Chemin à fouiller */
+ DIR *dir; /* Répertoire à parcourir */
struct dirent *entry; /* Elément trouvé */
char *modname; /* Nom du module pour Python */
char *filename; /* Chemin d'accès reconstruit */
GPluginModule *pyplugin; /* Lien vers un grffon Python */
bool status; /* Bilan d'une opération */
- /* Définition des zones d'influence */
-
-#ifndef DISCARD_LOCAL
-
- extend_python_path(PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "python");
-
-#else
-
- edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python");
-
- dir = opendir(edir);
-
- if (dir != NULL)
- {
- closedir(dir);
-
- extend_python_path(edir);
-
- }
-
- free(edir);
-
-#endif
-
- g_plugin_module_log_variadic_message(plugin, LMT_INFO,
- _("PYTHONPATH environment variable set to '%s'"),
- getenv("PYTHONPATH"));
-
- /* Chargements des extensions Python */
+ gstate = PyGILState_Ensure();
paths = get_env_var("PYTHONPATH");
@@ -585,7 +543,7 @@ static void load_python_plugins(GPluginModule *plugin)
dir = opendir(path);
if (dir == NULL)
{
- perror("opendir");
+ LOG_ERROR_N("opendir");
continue;
}
@@ -602,7 +560,7 @@ static void load_python_plugins(GPluginModule *plugin)
if (entry == NULL)
{
if (errno != 0)
- perror("readdir");
+ LOG_ERROR_N("readdir");
break;
@@ -666,12 +624,14 @@ static void load_python_plugins(GPluginModule *plugin)
free(paths);
+ PyGILState_Release(gstate);
+
}
/******************************************************************************
* *
-* Paramètres : plugin = interface à manipuler. *
+* Paramètres : manager = interface à manipuler. *
* *
* Description : Accompagne la fin du chargement des modules natifs. *
* *
@@ -681,15 +641,43 @@ static void load_python_plugins(GPluginModule *plugin)
* *
******************************************************************************/
-static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPyChrysalidePlugin *plugin)
+static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPluginManager *manager)
{
- PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ GPluginModule *plugin; /* Version de base du greffon */
+#ifdef DISCARD_LOCAL
+ char *edir; /* Répertoire de base effectif */
+ DIR *dir; /* Répertoire à parcourir */
+#endif
- gstate = PyGILState_Ensure();
+ plugin = G_PLUGIN_MODULE(manager);
+
+ /* Définition des zones d'influence */
+
+#ifndef DISCARD_LOCAL
- load_python_plugins(G_PLUGIN_MODULE(plugin));
+ extend_python_path(plugin, PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "python");
- PyGILState_Release(gstate);
+#else
+
+ edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python");
+
+ dir = opendir(edir);
+
+ if (dir != NULL)
+ {
+ closedir(dir);
+
+ extend_python_path(plugin, edir);
+
+ }
+
+ free(edir);
+
+#endif
+
+ /* Chargements des extensions Python */
+
+ load_python_plugins(plugin);
}
@@ -719,7 +707,9 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
details.standalone = _standalone;
+ details.add_extra = NULL;
details.populate_extra = NULL;
+ details.create_self = g_pychrysalide_plugin_new;
result = init_python_pychrysalide_module(&details);
diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am
index 007ceee..6d3d746 100644
--- a/plugins/pychrysalide/glibext/Makefile.am
+++ b/plugins/pychrysalide/glibext/Makefile.am
@@ -1,15 +1,11 @@
-noinst_LTLIBRARIES = libpychrysaglibext.la
+noinst_LTLIBRARIES = libpychrysaglibext.la libpychrysaglibextui.la
# libpychrysaglibext_la_SOURCES = \
# binarycursor.h binarycursor.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
+# linecursor.h linecursor.c
# if BUILD_GTK_SUPPORT
@@ -21,11 +17,16 @@ noinst_LTLIBRARIES = libpychrysaglibext.la
# endif
libpychrysaglibext_la_SOURCES = \
+ comparable.h comparable.c \
constants.h constants.c \
+ hashable.h hashable.c \
module.h module.c \
objhole.h objhole.c \
portion.h portion.c \
+ secstorage.h secstorage.c \
+ serialize.h serialize.c \
singleton.h singleton.c \
+ storage.h storage.c \
strbuilder.h strbuilder.c \
work.h work.c \
workqueue.h workqueue.c
@@ -34,6 +35,16 @@ libpychrysaglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS)
-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+libpychrysaglibextui_la_SOURCES = \
+ bufferline.h bufferline.c \
+ constants-ui.h constants-ui.c \
+ generator.h generator.c \
+ module-ui.h module-ui.c
+
+libpychrysaglibextui_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+
devdir = $(includedir)/chrysalide/$(subdir)
-dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=)
+dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=) $(libpychrysaglibextui_la_SOURCES:%c=)
diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c
index 09404bc..c5b3664 100644
--- a/plugins/pychrysalide/glibext/bufferline.c
+++ b/plugins/pychrysalide/glibext/bufferline.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* bufferline.c - équivalent Python du fichier "glibext/bufferline.h"
*
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,25 +26,38 @@
#include <assert.h>
-#include <malloc.h>
+//#include <malloc.h>
#include <pygobject.h>
-#include <i18n.h>
-#include <glibext/bufferline.h>
-#include <plugins/dt.h>
+#include <glibext/bufferline-int.h>
-#include "constants.h"
+//#include "constants.h"
#include "../access.h"
#include "../helpers.h"
-#include "../arch/vmpa.h"
+//#include "../arch/vmpa.h"
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+CREATE_DYN_CONSTRUCTOR(buffer_line, G_TYPE_BUFFER_LINE);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_buffer_line_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */
+
+
/* Accompagne la création d'une instance dérivée en Python. */
static PyObject *py_buffer_line_new(PyTypeObject *, PyObject *, PyObject *);
+#if 0
+
/* Ajoute du texte à formater dans une ligne donnée. */
static PyObject *py_buffer_line_append_text(PyObject *, PyObject *);
@@ -54,29 +67,34 @@ static PyObject *py_buffer_line_get_text(PyObject *, PyObject *);
/* Renseigne sur les propriétés particulières liées à une ligne. */
static PyObject *py_buffer_line_get_flags(PyObject *, void *);
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* 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. *
+* Paramètres : self = objet à initialiser (théoriquement). *
+* args = arguments fournis à l'appel. *
+* kwds = arguments de type key=val fournis. *
* *
-* Description : Accompagne la création d'une instance dérivée en Python. *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
* *
-* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. *
+* Retour : 0. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_buffer_line_init(PyObject *self, 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 */
+ unsigned char col_count; /* Qté de colonnes attendues */
+ int ret; /* Bilan de lecture des args. */
+ GBufferLine *line; /* Ligne en version native */
#define BUFFER_LINE_DOC \
"The BufferLine object is used to display processed data: disassembled" \
@@ -84,51 +102,40 @@ static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
- " BufferLine()" \
+ " BufferLine(col_count)" \
+ "\n" \
+ " Where *col_count* is a integer value providing the expected number of"\
+ " rendering columns." \
"\n" \
"Such objets aim to be created from the Chrysalide core only, and" \
" then get populated on demand. Thus, these lines can be viewed as" \
" cached lines and their properties have to be set through the" \
" pychrysalide.glibext.BufferCache instance which contains them."
- /* Validations diverses */
-
- base = get_python_buffer_line_type();
+ /* Récupération des paramètres */
- if (type == base)
- goto simple_way;
+ ret = PyArg_ParseTuple(args, "B", &col_count);
+ if (!ret) return -1;
- /* Mise en place d'un type dédié */
+ /* Initialisation d'un objet GLib */
- first_time = (g_type_from_name(type->tp_name) == 0);
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
- gtype = build_dynamic_type(G_TYPE_BUFFER_LINE, type->tp_name, NULL, NULL, NULL);
-
- if (first_time)
- {
- status = register_class_for_dynamic_pygobject(gtype, type);
+ /* Eléments de base */
- if (!status)
- {
- result = NULL;
- goto exit;
- }
-
- }
-
- /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
-
- simple_way:
-
- result = PyType_GenericNew(type, args, kwds);
+ line = G_BUFFER_LINE(pygobject_get(self));
- exit:
+ if (!g_buffer_line_create(line, col_count))
+ return -1;
- return result;
+ return 0;
}
+#if 0
+
/******************************************************************************
* *
* Paramètres : self = classe représentant une ligne de tampon. *
@@ -256,6 +263,7 @@ static PyObject *py_buffer_line_get_flags(PyObject *self, void *closure)
return result;
}
+#endif
/******************************************************************************
@@ -273,20 +281,24 @@ static PyObject *py_buffer_line_get_flags(PyObject *self, void *closure)
PyTypeObject *get_python_buffer_line_type(void)
{
static PyMethodDef py_buffer_line_methods[] = {
+ /*
BUFFER_LINE_APPEND_TEXT_METHOD,
{
"get_text", py_buffer_line_get_text,
METH_VARARGS,
"get_text($self, first_col, last_col, markup, /)\n--\n\nProvide the text of a buffer line."
},
+ */
{ NULL }
};
static PyGetSetDef py_buffer_line_getseters[] = {
+ /*
{
"flags", py_buffer_line_get_flags, NULL,
"Current flags of the buffer line.", NULL
},
+ */
{ NULL }
};
@@ -304,7 +316,8 @@ PyTypeObject *get_python_buffer_line_type(void)
.tp_methods = py_buffer_line_methods,
.tp_getset = py_buffer_line_getseters,
- .tp_new = py_buffer_line_new
+ .tp_init = py_buffer_line_init,
+ .tp_new = py_buffer_line_new,
};
@@ -342,11 +355,13 @@ bool ensure_python_buffer_line_is_registered(void)
if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type))
return false;
+ /*
if (!define_line_segment_constants(type))
return false;
if (!define_buffer_line_constants(type))
return false;
+ */
}
diff --git a/plugins/pychrysalide/glibext/comparable.c b/plugins/pychrysalide/glibext/comparable.c
new file mode 100644
index 0000000..e4982d7
--- /dev/null
+++ b/plugins/pychrysalide/glibext/comparable.c
@@ -0,0 +1,482 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparable.c - équivalent Python du fichier "glibext/comparable.c"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "comparable.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <glibext/comparable-int.h>
+
+
+#include "../access.h"
+#include "../helpers.h"
+
+
+
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Procède à l'initialisation de l'interface de détermination. */
+static void py_comparable_object_interface_init(GComparableObjectInterface *, gpointer *);
+
+/* Réalise une comparaison étendue entre objets. */
+static int py_comparable_object_compare_wrapper(const GComparableObject *, const GComparableObject *);
+
+
+
+/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+
+
+/* Transmet le statut d'une comparaison effectuée par le parent. */
+static PyObject *py_comparable_object_parent_compare(PyObject *, PyObject *);
+
+/* Effectue une comparaison avec un objet 'ComparableObject'. */
+static PyObject *py_comparable_object_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 détermination. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_comparable_object_interface_init(GComparableObjectInterface *iface, gpointer *unused)
+{
+#define COMPARABLE_OBJECT_DOC \
+ "The ComparableObject class provides an interface to compare" \
+ " objects.\n" \
+ "\n" \
+ "A typical class declaration for a new implementation looks like:\n" \
+ "\n" \
+ " class NewImplem(GObject.Object, ComparableObject):\n" \
+ " ...\n" \
+ "\n" \
+ "The following method has to be defined for new implementations:\n" \
+ "* pychrysalide.glibext.ComparableObject._compare().\n"
+
+ iface->compare = py_comparable_object_compare_wrapper;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* *
+* Description : Réalise une comparaison étendue entre objets. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_comparable_object_compare_wrapper(const GComparableObject *object, const GComparableObject *other)
+{
+ int 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 */
+
+#define COMPARABLE_OBJECT_COMPARE_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _compare, "$self, other", \
+ METH_VARARGS, \
+ "Abstract method allowing to compare two objects implementing" \
+ " the interface. This method is used to handle rich comparisons"\
+ " automatically.\n" \
+ "\n" \
+ "The result has to be an integer lesser than, equal to, or" \
+ " greater than zero if *self* is found, respectively, to be" \
+ " lesser than, to match, or to be greater than *other*.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the return value is not" \
+ " an integer." \
+)
+
+ result = 0;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(object));
+
+ args = PyTuple_New(1);
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other)));
+
+ pyret = run_python_method(pyobj, "_compare", args);
+
+ if (pyret != NULL)
+ {
+ if (PyLong_Check(pyret))
+ result = PyLong_AsLong(pyret);
+
+ else
+ PyErr_SetString(PyExc_TypeError, _("comparison status has to be a signed integer"));
+
+ }
+
+ Py_XDECREF(pyret);
+
+ Py_DECREF(args);
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONNEXION AVEC L'API DE PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet dont l'instance se veut unique. *
+* args = adresse non utilisée ici. *
+* *
+* Description : Transmet le statut d'une comparaison effectuée par le parent.*
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_comparable_object_parent_compare(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ GComparableObject *other; /* Second objet à comparer */
+ int ret; /* Bilan de lecture des args. */
+ GComparableObject *object; /* Mécanismes natifs */
+ GComparableObjectInterface *iface; /* Interface utilisée */
+ GComparableObjectInterface *parent_iface; /* Interface parente */
+ int status; /* Bilan d'une comparaison */
+
+#define COMPARABLE_OBJECT_PARENT_COMPARE_METHOD PYTHON_METHOD_DEF \
+( \
+ parent_compare, "$sel, otherf", \
+ METH_VARARGS, py_comparable_object, \
+ "Provide the comparison status defined by the interface" \
+ " implementation from the object native parent.\n" \
+ "\n" \
+ "The result is a signed integer.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the object parent does" \
+ " not implement the pychrysalide.glibext.ComparableObject" \
+ " interface.\n" \
+ "\n" \
+ "A *RuntimeError* exception is raised if the direct parent type"\
+ " of the object has not a native implementation. For Python" \
+ " implementations, the super()._compare() function has to be" \
+ " used instead." \
+)
+
+ if (!check_for_native_parent(self))
+ return NULL;
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_comparable_object, &other);
+ if (!ret) return NULL;
+
+ object = G_COMPARABLE_OBJECT(pygobject_get(self));
+
+ iface = G_COMPARABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ if (parent_iface == NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, _("object parent does not implement the ComparableObject interface"));
+
+ result = NULL;
+
+ }
+ else
+ {
+ status = parent_iface->compare(object, other);
+
+ result = PyLong_FromLong(status);
+
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 'ComparableObject'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_comparable_object_richcompare(PyObject *a, PyObject *b, int op)
+{
+ PyObject *result; /* Bilan à retourner */
+ int ret; /* Bilan de lecture des args. */
+ GComparableObject *obj_a; /* Instance à manipuler #1 */
+ GComparableObject *obj_b; /* Instance à manipuler #2 */
+ int status; /* Bilan d'une comparaison */
+
+ ret = PyObject_IsInstance(b, (PyObject *)get_python_comparable_object_type());
+ if (!ret)
+ {
+ result = Py_NotImplemented;
+ goto cmp_done;
+ }
+
+ obj_a = G_COMPARABLE_OBJECT(pygobject_get(a));
+ obj_b = G_COMPARABLE_OBJECT(pygobject_get(b));
+
+ status = g_comparable_object_compare(obj_a, obj_b);
+
+ switch (op)
+ {
+ case Py_LT:
+ result = (status < 0 ? Py_True : Py_False);
+ break;
+
+ case Py_LE:
+ result = (status <= 0 ? Py_True : Py_False);
+ break;
+
+ case Py_EQ:
+ result = (status == 0 ? Py_True : Py_False);
+ break;
+
+ case Py_NE:
+ result = (status != 0 ? Py_True : Py_False);
+ break;
+
+ case Py_GT:
+ result = (status > 0 ? Py_True : Py_False);
+ break;
+
+ case Py_GE:
+ result = (status >= 0 ? Py_True : Py_False);
+ break;
+
+ default:
+ assert(false);
+ result = Py_NotImplemented;
+ break;
+
+ }
+
+ cmp_done:
+
+ Py_INCREF(result);
+
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(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_object_type(void)
+{
+ static PyMethodDef py_comparable_object_methods[] = {
+ COMPARABLE_OBJECT_COMPARE_WRAPPER,
+ COMPARABLE_OBJECT_PARENT_COMPARE_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_comparable_object_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_comparable_object_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.glibext.ComparableObject",
+ .tp_basicsize = sizeof(PyObject),
+
+ /**
+ * Une valeur de .tp_richcompare non nulle écarte la définition du
+ * champ .tp_hash à la valeur par défaut du type PyBaseObject_Type
+ * dans les préparatifs de la fonction Python inherit_slots().
+ *
+ * Ces préparatifs se poursuivent avec type_ready_set_hash(),
+ * qui initialise .tp_hash avec PyObject_HashNotImplemented(),
+ * qui n'est donc pas un comportement par défaut.
+ *
+ * Côté PyGObject, la fonction pygobject_inherit_slots() y voit
+ * une implémentation de .tp_hash personnalisée, ce qui bloque
+ * la défintion d'autres personnalisations, comme celle de
+ * l'interface HashableObject.
+ *
+ * La valeur nominale nulle est ainsi écartée au préalable ici.
+ */
+ .tp_hash = (hashfunc)_Py_HashPointer,
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = COMPARABLE_OBJECT_DOC,
+
+ .tp_richcompare = py_comparable_object_richcompare,
+
+ .tp_methods = py_comparable_object_methods,
+ .tp_getset = py_comparable_object_getseters
+
+ };
+
+ return &py_comparable_object_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.....ComparableObject'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_comparable_object_is_registered(void)
+{
+ PyTypeObject *type; /* Type 'ComparableObject' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ static GInterfaceInfo info = { /* Paramètres d'inscription */
+
+ .interface_init = (GInterfaceInitFunc)py_comparable_object_interface_init,
+ .interface_finalize = NULL,
+ .interface_data = NULL,
+
+ };
+
+ type = get_python_comparable_object_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_OBJECT, type, &info))
+ 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 interface d'objet comparable. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_comparable_object(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_object_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 object");
+ break;
+
+ case 1:
+ *((GComparableObject **)dst) = G_COMPARABLE_OBJECT(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/comparable.h b/plugins/pychrysalide/glibext/comparable.h
new file mode 100644
index 0000000..d4c6ecf
--- /dev/null
+++ b/plugins/pychrysalide/glibext/comparable.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparable.h - prototypes pour l'équivalent Python du fichier "glibext/comparable.h"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_COMPARABLE_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARABLE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_comparable_object_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.glibext.ComparableObject'. */
+bool ensure_python_comparable_object_is_registered(void);
+
+/* Tente de convertir en interface d'objet comparable. */
+int convert_to_comparable_object(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARABLE_H */
diff --git a/plugins/pychrysalide/glibext/constants-ui.c b/plugins/pychrysalide/glibext/constants-ui.c
new file mode 100644
index 0000000..4101600
--- /dev/null
+++ b/plugins/pychrysalide/glibext/constants-ui.c
@@ -0,0 +1,131 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants-ui.c - ajout des constantes pour les extensions graphique à la GLib
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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-ui.h"
+
+
+#include <glibext/bufferline.h>
+
+
+#include "../helpers.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type dont le dictionnaire est à compléter. *
+* *
+* Description : Définit les constantes relatives aux lignes de tampon. *
+* *
+* Retour : true en cas de succès de l'opération, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_buffer_line_constants(PyTypeObject *type)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *values; /* Groupe de valeurs à établir */
+
+ values = PyDict_New();
+
+ result = add_const_to_group(values, "NONE", BLF_NONE);
+ if (result) result = add_const_to_group(values, "HAS_CODE", BLF_HAS_CODE);
+ if (result) result = add_const_to_group(values, "IS_LABEL", BLF_IS_LABEL);
+ if (result) result = add_const_to_group(values, "ENTRYPOINT", BLF_ENTRYPOINT);
+ if (result) result = add_const_to_group(values, "BOOKMARK", BLF_BOOKMARK);
+ if (result) result = add_const_to_group(values, "WIDTH_MANAGER", BLF_WIDTH_MANAGER);
+ if (result) result = add_const_to_group(values, "ALL", BLF_ALL);
+
+ if (!result)
+ {
+ Py_DECREF(values);
+ goto exit;
+ }
+
+ result = attach_constants_group_to_type(type, true, "BufferLineFlags", values,
+ "Optional flags linked to a rendering line.");
+
+ 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 BufferLineFlags. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_buffer_line_flags(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 BufferLineFlags");
+ break;
+
+ case 1:
+ value = PyLong_AsUnsignedLong(arg);
+
+ if ((value & BLF_ALL) != value)
+ {
+ PyErr_SetString(PyExc_TypeError, "invalid value for BufferLineFlags");
+ result = 0;
+ }
+
+ else
+ *((BufferLineFlags *)dst) = value;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/constants-ui.h b/plugins/pychrysalide/glibext/constants-ui.h
new file mode 100644
index 0000000..6c7bc6e
--- /dev/null
+++ b/plugins/pychrysalide/glibext/constants-ui.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants-ui.h - prototypes pour l'ajout des constantes pour les extensions graphique à la GLib
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_CONSTANTS_UI_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_UI_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+/* Définit les constantes relatives aux lignes de tampon. */
+bool define_buffer_line_constants(PyTypeObject *);
+
+/* Tente de convertir en constante BufferLineFlags. */
+int convert_to_buffer_line_flags(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_UI_H */
diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c
index 90ce8cd..f733cf6 100644
--- a/plugins/pychrysalide/glibext/constants.c
+++ b/plugins/pychrysalide/glibext/constants.c
@@ -29,7 +29,6 @@
/*
#include <i18n.h>
-#include <glibext/bufferline.h>
#include <glibext/comparison.h>
#include <glibext/configuration.h>
#include <glibext/linesegment.h>
@@ -159,105 +158,6 @@ int convert_to_portion_access_rights(PyObject *arg, void *dst)
* *
* Paramètres : type = type dont le dictionnaire est à compléter. *
* *
-* Description : Définit les constantes relatives aux lignes de tampon. *
-* *
-* Retour : true en cas de succès de l'opération, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool define_buffer_line_constants(PyTypeObject *type)
-{
- bool result; /* Bilan à retourner */
- PyObject *values; /* Groupe de valeurs à établir */
-
- values = PyDict_New();
-
- result = add_const_to_group(values, "NONE", BLF_NONE);
- if (result) result = add_const_to_group(values, "HAS_CODE", BLF_HAS_CODE);
- if (result) result = add_const_to_group(values, "IS_LABEL", BLF_IS_LABEL);
- if (result) result = add_const_to_group(values, "ENTRYPOINT", BLF_ENTRYPOINT);
- if (result) result = add_const_to_group(values, "BOOKMARK", BLF_BOOKMARK);
- if (result) result = add_const_to_group(values, "WIDTH_MANAGER", BLF_WIDTH_MANAGER);
- if (result) result = add_const_to_group(values, "ALL", BLF_ALL);
-
- if (!result)
- {
- Py_DECREF(values);
- goto exit;
- }
-
- result = attach_constants_group_to_type(type, true, "BufferLineFlags", values,
- "Optional flags linked to a rendering line.");
-
- 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 BufferLineFlags. *
-* *
-* Retour : Bilan de l'opération, voire indications supplémentaires. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-int convert_to_buffer_line_flags(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 BufferLineFlags");
- break;
-
- case 1:
- value = PyLong_AsUnsignedLong(arg);
-
- if ((value & BLF_ALL) != value)
- {
- PyErr_SetString(PyExc_TypeError, "invalid value for BufferLineFlags");
- result = 0;
- }
-
- else
- *((BufferLineFlags *)dst) = value;
-
- break;
-
- default:
- assert(false);
- break;
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* 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. *
diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h
index a950125..c695aa9 100644
--- a/plugins/pychrysalide/glibext/constants.h
+++ b/plugins/pychrysalide/glibext/constants.h
@@ -39,12 +39,6 @@ int convert_to_portion_access_rights(PyObject *, void *);
#if 0
-/* Définit les constantes relatives aux lignes de tampon. */
-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 *);
diff --git a/plugins/pychrysalide/glibext/linegen.c b/plugins/pychrysalide/glibext/generator.c
index d7e96fd..3a9a8ab 100644
--- a/plugins/pychrysalide/glibext/linegen.c
+++ b/plugins/pychrysalide/glibext/generator.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * linegen.c - équivalent Python du fichier "glibext/linegen.h"
+ * generator.c - équivalent Python du fichier "glibext/generator.h"
*
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,21 +22,21 @@
*/
-#include "linegen.h"
+#include "generator.h"
#include <pygobject.h>
-#include <glibext/linegen-int.h>
+#include <glibext/generator-int.h>
#include "bufferline.h"
-#include "constants.h"
-#include "linecursor.h"
+#include "constants-ui.h"
+//#include "linecursor.h"
#include "../access.h"
#include "../helpers.h"
-#include "../analysis/content.h"
+//#include "../analysis/content.h"
@@ -44,42 +44,55 @@
/* Procède à l'initialisation de l'interface de génération. */
-static void py_line_generator_interface_init(GLineGeneratorIface *, gpointer *);
+static void py_token_generator_interface_init(GTokenGeneratorInterface *, gpointer *);
/* Indique le nombre de ligne prêtes à être générées. */
-static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *);
+static size_t py_token_generator_count_lines_wrapper(const GTokenGenerator *);
+
+/* Renseigne sur les propriétés liées à un générateur. */
+static BufferLineFlags py_token_generator_get_flags_wrapper(const GTokenGenerator *, size_t, size_t);
+
+/*Description : Etablit dans une ligne de rendu le contenu représenté. */
+static void py_token_generator_populate_line_wrappper(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *);
+
+
+#if 0
+
/* Retrouve l'emplacement correspondant à une position donnée. */
-static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *, gint, size_t, size_t, GLineCursor **);
+static void py_token_generator_compute_cursor_wrapper(const GTokenGenerator *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
-static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *, size_t, size_t, const GLineCursor *);
+static int py_token_generator_contain_cursor_wrapper(const GTokenGenerator *, size_t, size_t, const GLineCursor *);
+
+
+#endif
-/* Renseigne sur les propriétés liées à un générateur. */
-static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator *, size_t, size_t);
-/* Imprime dans une ligne de rendu le contenu représenté. */
-static void py_line_generator_print_wrapper(GLineGenerator *, GBufferLine *, size_t, size_t, const GBinContent *);
+/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */
-/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+/* Renseigne sur les propriétés liées à un générateur. */
+static PyObject *py_token_generator_get_flags(PyObject *, PyObject *);
+
+/* Etablit dans une ligne de rendu le contenu représenté. */
+static PyObject *py_token_generator_populate_line(PyObject *self, PyObject *args);
+
+#if 0
/* Retrouve l'emplacement correspondant à une position donnée. */
-static PyObject *py_line_generator_compute_cursor(PyObject *, PyObject *);
+static PyObject *py_token_generator_compute_cursor(PyObject *, PyObject *);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
-static PyObject *py_line_generator_contain_cursor(PyObject *, PyObject *);
+static PyObject *py_token_generator_contain_cursor(PyObject *, PyObject *);
-/* Renseigne sur les propriétés liées à un générateur. */
-static PyObject *py_line_generator_get_flags(PyObject *, PyObject *);
+#endif
-/* Imprime dans une ligne de rendu le contenu représenté. */
-static PyObject *py_line_generator_print(PyObject *, PyObject *);
/* Indique le nombre de ligne prêtes à être générées. */
-static PyObject *py_line_generator_get_lines_count(PyObject *, void *);
+static PyObject *py_token_generator_get_lines_count(PyObject *, void *);
@@ -101,31 +114,33 @@ static PyObject *py_line_generator_get_lines_count(PyObject *, void *);
* *
******************************************************************************/
-static void py_line_generator_interface_init(GLineGeneratorIface *iface, gpointer *unused)
+static void py_token_generator_interface_init(GTokenGeneratorInterface *iface, gpointer *unused)
{
-#define LINE_GENERATOR_DOC \
- "LineGenerator gives an interface to all objects which aim to produce" \
+#define TOKEN_GENERATOR_DOC \
+ "TokenGenerator gives an interface to all objects which aim to produce" \
" content for rendering lines. Such lines can be exported to graphical" \
" interfaces or text files.\n" \
"\n" \
"A typical class declaration for a new implementation looks like:\n" \
"\n" \
- " class NewImplem(GObject.Object, LineGenerator):\n" \
+ " class NewImplem(GObject.Object, TokenGenerator):\n" \
" ...\n" \
"\n" \
"The following methods have to be defined for new implementations:\n" \
- "* pychrysalide.glibext.LineGenerator._count_lines();\n" \
- "* pychrysalide.glibext.LineGenerator._compute_cursor();\n" \
- "* pychrysalide.glibext.LineGenerator._contain_cursor();\n" \
- "* pychrysalide.glibext.LineGenerator._get_flags();\n" \
- "* pychrysalide.glibext.LineGenerator._print();\n" \
-
- iface->count = py_line_generator_count_lines_wrapper;
- iface->compute = py_line_generator_compute_cursor_wrapper;
- iface->contain = py_line_generator_contain_cursor_wrapper;
- iface->get_flags = py_line_generator_get_flags_wrapper;
- iface->print = py_line_generator_print_wrapper;
+ "* pychrysalide.glibext.TokenGenerator._count_lines();\n" \
+ "* pychrysalide.glibext.TokenGenerator._get_flags();\n" \
+ "* pychrysalide.glibext.TokenGenerator._populate_line();\n" \
+ "* pychrysalide.glibext.TokenGenerator._compute_cursor();\n" \
+ "* pychrysalide.glibext.TokenGenerator._contain_cursor().\n"
+
+ iface->count = py_token_generator_count_lines_wrapper;
+ iface->get_flags = py_token_generator_get_flags_wrapper;
+ iface->populate = py_token_generator_populate_line_wrappper;
+#if 0
+ iface->compute = py_token_generator_compute_cursor_wrapper;
+ iface->contain = py_token_generator_contain_cursor_wrapper;
+#endif
}
@@ -142,7 +157,7 @@ static void py_line_generator_interface_init(GLineGeneratorIface *iface, gpointe
* *
******************************************************************************/
-static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *generator)
+static size_t py_token_generator_count_lines_wrapper(const GTokenGenerator *generator)
{
size_t result; /* Décompte à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
@@ -150,7 +165,7 @@ static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *genera
PyObject *pyret; /* Bilan de consultation */
int ret; /* Bilan d'une conversion */
-#define LINE_GENERATOR_COUNT_LINES_WRAPPER PYTHON_WRAPPER_DEF \
+#define TOKEN_GENERATOR_COUNT_LINES_WRAPPER PYTHON_WRAPPER_DEF \
( \
_count_lines, "$self, /", \
METH_NOARGS, \
@@ -193,61 +208,61 @@ static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *genera
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
-* x = position géographique sur la ligne concernée. *
* index = indice de cette même ligne dans le tampon global.*
* repeat = indice d'utilisations successives du générateur. *
* *
-* Description : Retrouve l'emplacement correspondant à une position donnée. *
+* Description : Renseigne sur les propriétés liées à un générateur. *
* *
-* Retour : Emplacement constitué. *
+* Retour : Propriétés particulières associées. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *generator, gint x, size_t index, size_t repeat, GLineCursor **cursor)
+static BufferLineFlags py_token_generator_get_flags_wrapper(const GTokenGenerator *generator, size_t index, size_t repeat)
{
+ BufferLineFlags result; /* Fanions à 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 LINE_GENERATOR_COMPUTE_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \
+#define TOKEN_GENERATOR_GET_FLAGS_WRAPPER PYTHON_WRAPPER_DEF \
( \
- _compute_cursor, "$self, x, index, repeat, /", \
+ _get_flags, "$self, index, repeat, /", \
METH_VARARGS, \
- "Abstract method used to create a new cursor for a given" \
- " location inside displayed lines.\n" \
+ "Abstract method used to provide flags for a given rendering" \
+ " line.\n" \
"\n" \
- "The position on the horizontal axis, the line index and the" \
- " number of repetitions (only relevant if the generator" \
- " produces several lines) give indications about the active" \
- " position.\n" \
+ "The line index and the number of repetitions (only relevant" \
+ " if the generator produces several lines) give indications" \
+ " about the active position.\n" \
"\n" \
- "The result has to be a pychrysalide.glibext.LineCursor" \
- " instance." \
+ "The result has to be a" \
+ " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n" \
)
+ result = BLF_NONE;
+
gstate = PyGILState_Ensure();
pyobj = pygobject_new(G_OBJECT(generator));
- if (has_python_method(pyobj, "_compute_cursor"))
+ if (has_python_method(pyobj, "_get_flags"))
{
- args = PyTuple_New(3);
- PyTuple_SetItem(args, 0, PyLong_FromSize_t(x));
- PyTuple_SetItem(args, 1, PyLong_FromSize_t(index));
- PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat));
+ args = PyTuple_New(2);
+ PyTuple_SetItem(args, 0, PyLong_FromSize_t(index));
+ PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat));
- pyret = run_python_method(pyobj, "_compute_cursor", args);
+ pyret = run_python_method(pyobj, "_get_flags", args);
if (pyret != NULL)
{
- ret = convert_to_line_cursor(pyret, cursor);
+ ret = convert_to_buffer_line_flags(pyret, &result);
if (ret != 1)
- *cursor = NULL;
+ result = BLF_NONE;
Py_DECREF(pyret);
@@ -261,75 +276,66 @@ static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *gener
PyGILState_Release(gstate);
+ return result;
+
}
/******************************************************************************
* *
-* Paramètres : generator = générateur à consulter. *
+* Paramètres : generator = générateur à utiliser pour l'impression. *
* index = indice de cette même ligne dans le tampon global.*
* repeat = indice d'utilisations successives du générateur. *
-* cursor = emplacement à analyser. *
+* line = ligne de rendu à compléter. *
+* data = éventuelle donnée complémentaire fournie. *
* *
-* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
+* Description : Etablit dans une ligne de rendu le contenu représenté. *
* *
-* Retour : Bilan de la détermination, utilisable en comparaisons. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *generator, size_t index, size_t repeat, const GLineCursor *cursor)
+static void py_token_generator_populate_line_wrappper(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data)
{
- int result; /* Bilan d'analyse à 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 LINE_GENERATOR_CONTAIN_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \
+#define TOKEN_GENERATOR_POPULATE_LINE_WRAPPER PYTHON_WRAPPER_DEF \
( \
- _contain_cursor, "$self, index, repeat, cursor, /", \
+ _populate_line, "$self, index, repeat, line, /", \
METH_VARARGS, \
- "Abstract method used to check the position of a cursor in" \
- " relation to rendering lines.\n" \
+ "Abstract method used to generate content into a rendering" \
+ " line.\n" \
"\n" \
- "The line index and the number of repetitions (only relevant" \
+ "This rendering output is pointed by the *line* argument, which"\
+ " is a provided pychrysalide.glibext.BufferLine instance. The" \
+ " line *index* and the number of repetitions (only relevant" \
" if the generator produces several lines) give indications" \
- " about the active position. The cursor is a" \
- " pychrysalide.glibext.LineCursor instance.\n" \
+ " about the current rendering position.\n" \
"\n" \
- "The result has to be an integer less than, equal to, or" \
- " greater than zero if the cursor is, respectively, before," \
- " inside or after the area covered by the generator." \
+ "If set, the content is a pychrysalide.analysis.BinContent" \
+ " instance providing access to the processed binary data." \
)
- result = 0;
-
gstate = PyGILState_Ensure();
pyobj = pygobject_new(G_OBJECT(generator));
- if (has_python_method(pyobj, "_contain_cursor"))
+ if (has_python_method(pyobj, "_populate_line"))
{
args = PyTuple_New(3);
PyTuple_SetItem(args, 0, PyLong_FromSize_t(index));
PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat));
- PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(cursor)));
+ PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(line)));
+ //PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(content)));
- pyret = run_python_method(pyobj, "_contain_cursor", args);
-
- if (pyret != NULL)
- {
- ret = PyLong_Check(pyret);
+ pyret = run_python_method(pyobj, "_populate_line", args);
- if (ret)
- result = PyLong_AsLong(pyret);
-
- Py_DECREF(pyret);
-
- }
+ Py_XDECREF(pyret);
Py_DECREF(args);
@@ -339,69 +345,70 @@ static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *genera
PyGILState_Release(gstate);
- return result;
-
}
+#if 0
+
+
/******************************************************************************
* *
* Paramètres : generator = générateur à consulter. *
+* x = position géographique sur la ligne concernée. *
* index = indice de cette même ligne dans le tampon global.*
* repeat = indice d'utilisations successives du générateur. *
* *
-* Description : Renseigne sur les propriétés liées à un générateur. *
+* Description : Retrouve l'emplacement correspondant à une position donnée. *
* *
-* Retour : Propriétés particulières associées. *
+* Retour : Emplacement constitué. *
* *
* Remarques : - *
* *
******************************************************************************/
-static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator *generator, size_t index, size_t repeat)
+static void py_token_generator_compute_cursor_wrapper(const GTokenGenerator *generator, gint x, size_t index, size_t repeat, GLineCursor **cursor)
{
- BufferLineFlags result; /* Fanions à 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 LINE_GENERATOR_GET_FLAGS_WRAPPER PYTHON_WRAPPER_DEF \
+#define TOKEN_GENERATOR_COMPUTE_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \
( \
- _get_flags, "$self, index, repeat, /", \
+ _compute_cursor, "$self, x, index, repeat, /", \
METH_VARARGS, \
- "Abstract method used to provide flags for a given rendering" \
- " line.\n" \
+ "Abstract method used to create a new cursor for a given" \
+ " location inside displayed lines.\n" \
"\n" \
- "The line index and the number of repetitions (only relevant" \
- " if the generator produces several lines) give indications" \
- " about the active position.\n" \
+ "The position on the horizontal axis, the line index and the" \
+ " number of repetitions (only relevant if the generator" \
+ " produces several lines) give indications about the active" \
+ " position.\n" \
"\n" \
- "The result has to be a" \
- " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n" \
+ "The result has to be a pychrysalide.glibext.LineCursor" \
+ " instance." \
)
- result = BLF_NONE;
-
gstate = PyGILState_Ensure();
pyobj = pygobject_new(G_OBJECT(generator));
- if (has_python_method(pyobj, "_get_flags"))
+ if (has_python_method(pyobj, "_compute_cursor"))
{
- args = PyTuple_New(2);
- PyTuple_SetItem(args, 0, PyLong_FromSize_t(index));
- PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat));
+ args = PyTuple_New(3);
+ PyTuple_SetItem(args, 0, PyLong_FromSize_t(x));
+ PyTuple_SetItem(args, 1, PyLong_FromSize_t(index));
+ PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat));
- pyret = run_python_method(pyobj, "_get_flags", args);
+ pyret = run_python_method(pyobj, "_compute_cursor", args);
if (pyret != NULL)
{
- ret = convert_to_buffer_line_flags(pyret, &result);
+ ret = convert_to_line_cursor(pyret, cursor);
if (ret != 1)
- result = BLF_NONE;
+ *cursor = NULL;
Py_DECREF(pyret);
@@ -415,65 +422,75 @@ static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator
PyGILState_Release(gstate);
- return result;
-
}
/******************************************************************************
* *
-* Paramètres : generator = générateur à utiliser pour l'impression. *
-* line = ligne de rendu à compléter. *
+* Paramètres : generator = générateur à consulter. *
* index = indice de cette même ligne dans le tampon global.*
* repeat = indice d'utilisations successives du générateur. *
-* content = éventuel contenu binaire brut à imprimer. *
+* cursor = emplacement à analyser. *
* *
-* Description : Imprime dans une ligne de rendu le contenu représenté. *
+* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
* *
-* Retour : - *
+* Retour : Bilan de la détermination, utilisable en comparaisons. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content)
+static int py_token_generator_contain_cursor_wrapper(const GTokenGenerator *generator, size_t index, size_t repeat, const GLineCursor *cursor)
{
+ int result; /* Bilan d'analyse à 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 LINE_GENERATOR_PRINT_WRAPPER PYTHON_WRAPPER_DEF \
+#define TOKEN_GENERATOR_CONTAIN_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \
( \
- _print, "$self, line, index, repeat, content, /", \
+ _contain_cursor, "$self, index, repeat, cursor, /", \
METH_VARARGS, \
- "Abstract method used to generate content into a rendering" \
- " line, which is a provided pychrysalide.glibext.BufferLine" \
- " instance.\n" \
+ "Abstract method used to check the position of a cursor in" \
+ " relation to rendering lines.\n" \
"\n" \
"The line index and the number of repetitions (only relevant" \
" if the generator produces several lines) give indications" \
- " about the current rendering position.\n" \
+ " about the active position. The cursor is a" \
+ " pychrysalide.glibext.LineCursor instance.\n" \
"\n" \
- "If set, the content is a pychrysalide.analysis.BinContent" \
- " instance providing access to the processed binary data." \
+ "The result has to be an integer less than, equal to, or" \
+ " greater than zero if the cursor is, respectively, before," \
+ " inside or after the area covered by the generator." \
)
+ result = 0;
+
gstate = PyGILState_Ensure();
pyobj = pygobject_new(G_OBJECT(generator));
- if (has_python_method(pyobj, "_print"))
+ if (has_python_method(pyobj, "_contain_cursor"))
{
- args = PyTuple_New(4);
- PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line)));
- PyTuple_SetItem(args, 1, PyLong_FromSize_t(index));
- PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat));
- PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(content)));
+ args = PyTuple_New(3);
+ PyTuple_SetItem(args, 0, PyLong_FromSize_t(index));
+ PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat));
+ PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(cursor)));
- pyret = run_python_method(pyobj, "_print", args);
+ pyret = run_python_method(pyobj, "_contain_cursor", args);
- Py_XDECREF(pyret);
+ if (pyret != NULL)
+ {
+ ret = PyLong_Check(pyret);
+
+ if (ret)
+ result = PyLong_AsLong(pyret);
+
+ Py_DECREF(pyret);
+
+ }
Py_DECREF(args);
@@ -483,12 +500,16 @@ static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLi
PyGILState_Release(gstate);
+ return result;
+
}
+#endif
+
/* ---------------------------------------------------------------------------------- */
-/* CONNEXION AVEC L'API DE PYTHON */
+/* LIAISON DE FONCTIONNALITES AVEC L'API PYTHON */
/* ---------------------------------------------------------------------------------- */
@@ -497,57 +518,45 @@ static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLi
* Paramètres : self = classe représentant un générateur à manipuler. *
* args = arguments fournis à l'appel. *
* *
-* Description : Retrouve l'emplacement correspondant à une position donnée. *
+* Description : Renseigne sur les propriétés liées à un générateur. *
* *
-* Retour : Emplacement constitué. *
+* Retour : Propriétés particulières associées. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_line_generator_compute_cursor(PyObject *self, PyObject *args)
+static PyObject *py_token_generator_get_flags(PyObject *self, PyObject *args)
{
PyObject *result; /* Propriétés à retourner */
- int x; /* Position horizontale */
size_t index; /* Indice dans le tampon */
size_t repeat; /* Utilisations successives */
int ret; /* Bilan de lecture des args. */
- GLineGenerator *generator; /* Version native */
- GLineCursor *cursor; /* Curseur nouveau obtenu */
+ GTokenGenerator *generator; /* Version native */
+ BufferLineFlags flags; /* Propriétés courantes */
-#define LINE_GENERATOR_COMPUTE_CURSOR_METHOD PYTHON_METHOD_DEF \
-( \
- compute_cursor, "$self, x, index, repeat, /", \
- METH_VARARGS, py_line_generator, \
- "Create a a new cursor for a given location inside displayed" \
- " lines.\n" \
- "\n" \
- "The position on the horizontal axis, the line index and the" \
- " number of repetitions (only relevant if the generator" \
- " produces several lines) give indications about the active" \
- " position.\n" \
- "\n" \
- "The result has to be a pychrysalide.glibext.LineCursor" \
- " instance." \
+#define TOKEN_GENERATOR_GET_FLAGS_METHOD PYTHON_METHOD_DEF \
+( \
+ get_flags, "$self, index, repeat, /", \
+ METH_VARARGS, py_token_generator, \
+ "Get the flags of a given position from the generator.\n" \
+ "\n" \
+ "The line index and the number of repetitions (only relevant" \
+ " if the generator produces several lines) give indications" \
+ " about the active position.\n" \
+ "\n" \
+ "The result is a pychrysalide.glibext.BufferLine.BufferLineFlags" \
+ " value." \
)
- ret = PyArg_ParseTuple(args, "inn", &x, &index, &repeat);
+ ret = PyArg_ParseTuple(args, "nn", &index, &repeat);
if (!ret) return NULL;
- generator = G_LINE_GENERATOR(pygobject_get(self));
+ generator = G_TOKEN_GENERATOR(pygobject_get(self));
- cursor = g_line_generator_compute_cursor(generator, x, index, repeat);
+ flags = g_token_generator_get_flags(generator, index, repeat);
- if (cursor != NULL)
- {
- result = pygobject_new(G_OBJECT(cursor));
- g_object_unref(G_OBJECT(cursor));
- }
- else
- {
- result = Py_None;
- Py_INCREF(result);
- }
+ result = cast_with_constants_group_from_type(get_python_buffer_line_type(), "BufferLineFlags", flags);
return result;
@@ -559,99 +568,108 @@ static PyObject *py_line_generator_compute_cursor(PyObject *self, PyObject *args
* Paramètres : self = classe représentant un générateur à manipuler. *
* args = arguments fournis à l'appel. *
* *
-* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
+* Description : Etablit dans une ligne de rendu le contenu représenté. *
* *
-* Retour : Bilan de la détermination, utilisable en comparaisons. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_line_generator_contain_cursor(PyObject *self, PyObject *args)
+static PyObject *py_token_generator_populate_line(PyObject *self, PyObject *args)
{
- PyObject *result; /* Propriétés à retourner */
+ GBufferLine *line; /* Ligne de rendu à compléter */
size_t index; /* Indice dans le tampon */
size_t repeat; /* Utilisations successives */
- GLineCursor *cursor; /* Curseur à venir situer */
+ GTokenGenerator *generator; /* Version native */
int ret; /* Bilan de lecture des args. */
- GLineGenerator *generator; /* Version native */
- int status; /* Bilan d'une analyse */
-#define LINE_GENERATOR_CONTAIN_CURSOR_METHOD PYTHON_METHOD_DEF \
+#define TOKEN_GENERATOR_POPULATE_LINE_METHOD PYTHON_METHOD_DEF \
( \
- contain_cursor, "$self, index, repeat, cursor, /", \
- METH_VARARGS, py_line_generator, \
- "Check the position of a cursor in relation to rendering" \
- " lines.\n" \
+ populate_line, "$self, index, repeat, line, /", \
+ METH_VARARGS, py_token_generator, \
+ "Produce output into a rendering line with optional content.\n" \
"\n" \
- "The line index and the number of repetitions (only relevant" \
- " if the generator produces several lines) give indications" \
- " about the active position. The cursor is a" \
- " pychrysalide.glibext.LineCursor instance.\n" \
+ "The provided *line* is a pychrysalide.glibext.BufferLine" \
+ " instance. The *index* and the number of repetitions (only" \
+ " relevant if the generator produces several lines) give" \
+ " indications about the current rendering position.\n" \
"\n" \
- "The result has to be an integer less than, equal to, or" \
- " greater than zero if the cursor is, respectively, before," \
- " inside or after the area covered by the generator." \
+ "If set, the content is a pychrysalide.analysis.BinContent" \
+ " instance providing access to the processed binary data." \
)
- ret = PyArg_ParseTuple(args, "nnO&", &index, &repeat, convert_to_line_cursor, &cursor);
+ ret = PyArg_ParseTuple(args, "nnO&", &index, &repeat, convert_to_buffer_line, &line);
if (!ret) return NULL;
- generator = G_LINE_GENERATOR(pygobject_get(self));
+ generator = G_TOKEN_GENERATOR(pygobject_get(self));
- status = g_line_generator_contain_cursor(generator, index, repeat, cursor);
+ g_token_generator_populate_line(generator, index, repeat, line, NULL);
- result = PyLong_FromLong(status);
-
- return result;
+ Py_RETURN_NONE;
}
+
+#if 0
+
/******************************************************************************
* *
* Paramètres : self = classe représentant un générateur à manipuler. *
* args = arguments fournis à l'appel. *
* *
-* Description : Renseigne sur les propriétés liées à un générateur. *
+* Description : Retrouve l'emplacement correspondant à une position donnée. *
* *
-* Retour : Propriétés particulières associées. *
+* Retour : Emplacement constitué. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_line_generator_get_flags(PyObject *self, PyObject *args)
+static PyObject *py_token_generator_compute_cursor(PyObject *self, PyObject *args)
{
PyObject *result; /* Propriétés à retourner */
+ int x; /* Position horizontale */
size_t index; /* Indice dans le tampon */
size_t repeat; /* Utilisations successives */
int ret; /* Bilan de lecture des args. */
- GLineGenerator *generator; /* Version native */
- BufferLineFlags flags; /* Propriétés courantes */
+ GTokenGenerator *generator; /* Version native */
+ GLineCursor *cursor; /* Curseur nouveau obtenu */
-#define LINE_GENERATOR_GET_FLAGS_METHOD PYTHON_METHOD_DEF \
-( \
- get_flags, "$self, index, repeat, /", \
- METH_VARARGS, py_line_generator, \
- "Get the flags of a given position from the generator.\n" \
- "\n" \
- "The line index and the number of repetitions (only relevant" \
- " if the generator produces several lines) give indications" \
- " about the active position.\n" \
- "\n" \
- "The result is a pychrysalide.glibext.BufferLine.BufferLineFlags" \
- " value." \
+#define TOKEN_GENERATOR_COMPUTE_CURSOR_METHOD PYTHON_METHOD_DEF \
+( \
+ compute_cursor, "$self, x, index, repeat, /", \
+ METH_VARARGS, py_token_generator, \
+ "Create a a new cursor for a given location inside displayed" \
+ " lines.\n" \
+ "\n" \
+ "The position on the horizontal axis, the line index and the" \
+ " number of repetitions (only relevant if the generator" \
+ " produces several lines) give indications about the active" \
+ " position.\n" \
+ "\n" \
+ "The result has to be a pychrysalide.glibext.LineCursor" \
+ " instance." \
)
- ret = PyArg_ParseTuple(args, "nn", &index, &repeat);
+ ret = PyArg_ParseTuple(args, "inn", &x, &index, &repeat);
if (!ret) return NULL;
- generator = G_LINE_GENERATOR(pygobject_get(self));
+ generator = G_TOKEN_GENERATOR(pygobject_get(self));
- flags = g_line_generator_get_flags(generator, index, repeat);
+ cursor = g_token_generator_compute_cursor(generator, x, index, repeat);
- result = cast_with_constants_group_from_type(get_python_buffer_line_type(), "BufferLineFlags", flags);
+ if (cursor != NULL)
+ {
+ result = pygobject_new(G_OBJECT(cursor));
+ g_object_unref(G_OBJECT(cursor));
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
return result;
@@ -663,50 +681,56 @@ static PyObject *py_line_generator_get_flags(PyObject *self, PyObject *args)
* Paramètres : self = classe représentant un générateur à manipuler. *
* args = arguments fournis à l'appel. *
* *
-* Description : Imprime dans une ligne de rendu le contenu représenté. *
+* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
* *
-* Retour : - *
+* Retour : Bilan de la détermination, utilisable en comparaisons. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_line_generator_print(PyObject *self, PyObject *args)
+static PyObject *py_token_generator_contain_cursor(PyObject *self, PyObject *args)
{
- GBufferLine *line; /* Ligne de rendu à compléter */
+ PyObject *result; /* Propriétés à retourner */
size_t index; /* Indice dans le tampon */
size_t repeat; /* Utilisations successives */
- GBinContent *content; /* Contenu binaire associé */
- GLineGenerator *generator; /* Version native */
+ GLineCursor *cursor; /* Curseur à venir situer */
int ret; /* Bilan de lecture des args. */
+ GTokenGenerator *generator; /* Version native */
+ int status; /* Bilan d'une analyse */
-#define LINE_GENERATOR_PRINT_METHOD PYTHON_METHOD_DEF \
+#define TOKEN_GENERATOR_CONTAIN_CURSOR_METHOD PYTHON_METHOD_DEF \
( \
- print, "$self, line, index, repeat, content, /", \
- METH_VARARGS, py_line_generator, \
- "Produce output into a rendering line with optional content.\n" \
+ contain_cursor, "$self, index, repeat, cursor, /", \
+ METH_VARARGS, py_token_generator, \
+ "Check the position of a cursor in relation to rendering" \
+ " lines.\n" \
"\n" \
- "The provided line is a pychrysalide.glibext.BufferLine" \
- " instance. The index and the number of repetitions (only" \
- " relevant if the generator produces several lines) give" \
- " indications about the current rendering position.\n" \
+ "The line index and the number of repetitions (only relevant" \
+ " if the generator produces several lines) give indications" \
+ " about the active position. The cursor is a" \
+ " pychrysalide.glibext.LineCursor instance.\n" \
"\n" \
- "If set, the content is a pychrysalide.analysis.BinContent" \
- " instance providing access to the processed binary data." \
+ "The result has to be an integer less than, equal to, or" \
+ " greater than zero if the cursor is, respectively, before," \
+ " inside or after the area covered by the generator." \
)
- ret = PyArg_ParseTuple(args, "O&nnO&", convert_to_buffer_line, &line, &index,
- &repeat, convert_to_binary_content, &content);
+ ret = PyArg_ParseTuple(args, "nnO&", &index, &repeat, convert_to_line_cursor, &cursor);
if (!ret) return NULL;
- generator = G_LINE_GENERATOR(pygobject_get(self));
+ generator = G_TOKEN_GENERATOR(pygobject_get(self));
- g_line_generator_print(generator, line, index, repeat, content);
+ status = g_token_generator_contain_cursor(generator, index, repeat, cursor);
- Py_RETURN_NONE;
+ result = PyLong_FromLong(status);
+
+ return result;
}
+#endif
+
/******************************************************************************
* *
@@ -721,24 +745,24 @@ static PyObject *py_line_generator_print(PyObject *self, PyObject *args)
* *
******************************************************************************/
-static PyObject *py_line_generator_get_lines_count(PyObject *self, void *closure)
+static PyObject *py_token_generator_get_lines_count(PyObject *self, void *closure)
{
PyObject *result; /* Décompte à retourner */
- GLineGenerator *generator; /* Version native */
+ GTokenGenerator *generator; /* Version native */
size_t count; /* Nombre de lignes présentes */
-#define LINE_GENERATOR_LINES_COUNT_ATTRIB PYTHON_GET_DEF_FULL \
+#define TOKEN_GENERATOR_LINES_COUNT_ATTRIB PYTHON_GET_DEF_FULL \
( \
- lines_count, py_line_generator, \
+ lines_count, py_token_generator, \
"Quantity of lines produced by the generator.\n" \
"\n" \
"This number may vary between calls, if a width has changed" \
" for instance." \
)
- generator = G_LINE_GENERATOR(pygobject_get(self));
+ generator = G_TOKEN_GENERATOR(pygobject_get(self));
- count = g_line_generator_count_lines(generator);
+ count = g_token_generator_count_lines(generator);
result = PyLong_FromSize_t(count);
@@ -759,43 +783,47 @@ static PyObject *py_line_generator_get_lines_count(PyObject *self, void *closure
* *
******************************************************************************/
-PyTypeObject *get_python_line_generator_type(void)
+PyTypeObject *get_python_token_generator_type(void)
{
- static PyMethodDef py_line_generator_methods[] = {
- LINE_GENERATOR_COUNT_LINES_WRAPPER,
- LINE_GENERATOR_COMPUTE_CURSOR_WRAPPER,
- LINE_GENERATOR_CONTAIN_CURSOR_WRAPPER,
- LINE_GENERATOR_GET_FLAGS_WRAPPER,
- LINE_GENERATOR_PRINT_WRAPPER,
- LINE_GENERATOR_COMPUTE_CURSOR_METHOD,
- LINE_GENERATOR_CONTAIN_CURSOR_METHOD,
- LINE_GENERATOR_GET_FLAGS_METHOD,
- LINE_GENERATOR_PRINT_METHOD,
+ static PyMethodDef py_token_generator_methods[] = {
+ TOKEN_GENERATOR_COUNT_LINES_WRAPPER,
+ TOKEN_GENERATOR_GET_FLAGS_WRAPPER,
+ TOKEN_GENERATOR_POPULATE_LINE_WRAPPER,
+ /*
+ TOKEN_GENERATOR_COMPUTE_CURSOR_WRAPPER,
+ TOKEN_GENERATOR_CONTAIN_CURSOR_WRAPPER,
+ */
+ TOKEN_GENERATOR_GET_FLAGS_METHOD,
+ TOKEN_GENERATOR_POPULATE_LINE_METHOD,
+ /*
+ TOKEN_GENERATOR_COMPUTE_CURSOR_METHOD,
+ TOKEN_GENERATOR_CONTAIN_CURSOR_METHOD,
+ */
{ NULL }
};
- static PyGetSetDef py_line_generator_getseters[] = {
- LINE_GENERATOR_LINES_COUNT_ATTRIB,
+ static PyGetSetDef py_token_generator_getseters[] = {
+ TOKEN_GENERATOR_LINES_COUNT_ATTRIB,
{ NULL }
};
- static PyTypeObject py_line_generator_type = {
+ static PyTypeObject py_token_generator_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.glibext.LineGenerator",
+ .tp_name = "pychrysalide.glibext.TokenGenerator",
.tp_basicsize = sizeof(PyObject),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_doc = LINE_GENERATOR_DOC,
+ .tp_doc = TOKEN_GENERATOR_DOC,
- .tp_methods = py_line_generator_methods,
- .tp_getset = py_line_generator_getseters,
+ .tp_methods = py_token_generator_methods,
+ .tp_getset = py_token_generator_getseters,
};
- return &py_line_generator_type;
+ return &py_token_generator_type;
}
@@ -804,7 +832,7 @@ PyTypeObject *get_python_line_generator_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide.glibext.LineGenerator'.*
+* Description : Prend en charge l'objet 'pychrysalide.....TokenGenerator'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -812,21 +840,21 @@ PyTypeObject *get_python_line_generator_type(void)
* *
******************************************************************************/
-bool ensure_python_line_generator_is_registered(void)
+bool ensure_python_token_generator_is_registered(void)
{
- PyTypeObject *type; /* Type Python 'LineGenerator' */
+ PyTypeObject *type; /* Type Python 'TokenGenerator'*/
PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
static GInterfaceInfo info = { /* Paramètres d'inscription */
- .interface_init = (GInterfaceInitFunc)py_line_generator_interface_init,
+ .interface_init = (GInterfaceInitFunc)py_token_generator_interface_init,
.interface_finalize = NULL,
.interface_data = NULL,
};
- type = get_python_line_generator_type();
+ type = get_python_token_generator_type();
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
@@ -834,7 +862,7 @@ bool ensure_python_line_generator_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_interface_for_pygobject(dict, G_TYPE_LINE_GENERATOR, type, &info))
+ if (!register_interface_for_pygobject(dict, G_TYPE_TOKEN_GENERATOR, type, &info))
return false;
}
@@ -857,11 +885,11 @@ bool ensure_python_line_generator_is_registered(void)
* *
******************************************************************************/
-int convert_to_line_generator(PyObject *arg, void *dst)
+int convert_to_token_generator(PyObject *arg, void *dst)
{
int result; /* Bilan à retourner */
- result = PyObject_IsInstance(arg, (PyObject *)get_python_line_generator_type());
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_token_generator_type());
switch (result)
{
@@ -871,11 +899,11 @@ int convert_to_line_generator(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to line generator");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to token generator");
break;
case 1:
- *((GLineGenerator **)dst) = G_LINE_GENERATOR(pygobject_get(arg));
+ *((GTokenGenerator **)dst) = G_TOKEN_GENERATOR(pygobject_get(arg));
break;
default:
diff --git a/plugins/pychrysalide/glibext/linegen.h b/plugins/pychrysalide/glibext/generator.h
index bfad885..b2672a8 100644
--- a/plugins/pychrysalide/glibext/linegen.h
+++ b/plugins/pychrysalide/glibext/generator.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * linegen.h - prototypes pour l'équivalent Python du fichier "glibext/linegen.h"
+ * generator.h - prototypes pour l'équivalent Python du fichier "glibext/generator.h"
*
- * Copyright (C) 2018 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_LINEGEN_H
-#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_LINEGEN_H
+#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_GENERATOR_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_GENERATOR_H
#include <Python.h>
@@ -32,14 +32,14 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_line_generator_type(void);
+PyTypeObject *get_python_token_generator_type(void);
-/* Prend en charge l'objet 'pychrysalide.glibext.LineGenerator'. */
-bool ensure_python_line_generator_is_registered(void);
+/* Prend en charge l'objet 'pychrysalide.glibext.TokenGenerator'. */
+bool ensure_python_token_generator_is_registered(void);
/* Tente de convertir en générateur de lignes. */
-int convert_to_line_generator(PyObject *, void *);
+int convert_to_token_generator(PyObject *, void *);
-#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_LINEGEN_H */
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_GENERATOR_H */
diff --git a/plugins/pychrysalide/glibext/comparison.c b/plugins/pychrysalide/glibext/hashable.c
index 548f700..c870d55 100644
--- a/plugins/pychrysalide/glibext/comparison.c
+++ b/plugins/pychrysalide/glibext/hashable.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * comparison.c - équivalent Python du fichier "glibext/comparison.h"
+ * hashable.c - équivalent Python du fichier "glibext/hashable.c"
*
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,38 +22,40 @@
*/
-#include "comparison.h"
+#include "hashable.h"
+#include <assert.h>
#include <pygobject.h>
-#include <glibext/comparison-int.h>
+#include <glibext/hashable-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 *);
+/* Procède à l'initialisation de l'interface de détermination. */
+static void py_hashable_object_interface_init(GHashableObjectInterface *, 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 *);
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+static guint py_hashable_object_hash_wrapper(const GHashableObject *);
/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
-/* Effectue une comparaison avec un objet 'ComparableItem'. */
-static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
+/* Transmet l'empreinte d'un objet calculée par son parent. */
+static PyObject *py_hashable_object_parent_hash(PyObject *, PyObject *);
+
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+static Py_hash_t py_hashable_object_hash(PyObject *);
@@ -67,7 +69,7 @@ static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
* Paramètres : iface = interface GLib à initialiser. *
* unused = adresse non utilisée ici. *
* *
-* Description : Procède à l'initialisation de l'interface de comparaison. *
+* Description : Procède à l'initialisation de l'interface de détermination. *
* *
* Retour : - *
* *
@@ -75,72 +77,78 @@ static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
* *
******************************************************************************/
-static void py_comparable_item_interface_init(GComparableItemIface *iface, gpointer *unused)
+static void py_hashable_object_interface_init(GHashableObjectInterface *iface, gpointer *unused)
{
-
-#define COMPARABLE_ITEM_DOC \
- "ComparableItem provides an interface to compare objects.\n" \
+#define HASHABLE_OBJECT_DOC \
+ "The HashableObject class defines a interface ensuring that a" \
+ " customized hashing method is available for an object.\n" \
"\n" \
"A typical class declaration for a new implementation looks like:\n" \
"\n" \
- " class NewImplem(GObject.Object, ComparableItem):\n" \
+ " class NewImplem(GObject.Object, HashableObject):\n" \
" ...\n" \
- "\n"
+ "\n" \
+ "The following method has to be defined for new implementations:\n" \
+ "* pychrysalide.glibext.HashableObject._hash().\n"
- iface->cmp_rich = py_comparable_item_compare_rich;
+ iface->hash = py_hashable_object_hash_wrapper;
}
/******************************************************************************
* *
-* 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] *
+* Paramètres : object = objet dont l'instance est à consulter. *
* *
-* Description : Réalise une comparaison entre objets selon un critère précis.*
+* Description : Calcule l'empreinte sur 32 bits d'un objet. *
* *
-* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool py_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status)
+static guint py_hashable_object_hash_wrapper(const GHashableObject *object)
{
- bool result; /* Etat à retourner */
+ guint result; /* Valeur à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyitem; /* Objet Python concerné #1 */
- PyObject *pyother; /* Objet Python concerné #2 */
+ PyObject *pyobj; /* Objet Python concerné */
PyObject *pyret; /* Bilan de consultation */
- int ret; /* Bilan d'une conversion */
- result = false;
+#define HASHABLE_OBJECT_HASH_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _hash, "$self", \
+ METH_NOARGS, \
+ "Abstract method computing a hash from an object which is used" \
+ " as the default implementation of the __hash__() method.\n" \
+ "\n" \
+ "The result has to be an unsigned integer.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the return value is not" \
+ " an integer." \
+)
+
+ result = 0;
gstate = PyGILState_Ensure();
- pyitem = pygobject_new(G_OBJECT(item));
- pyother = pygobject_new(G_OBJECT(other));
+ pyobj = pygobject_new(G_OBJECT(object));
- pyret = PyObject_RichCompare(pyitem, pyother, op);
+ pyret = run_python_method(pyobj, "_hash", NULL);
if (pyret != NULL)
{
- ret = PyBool_Check(pyret);
+ if (PyLong_Check(pyret))
+ result = PyLong_AsUnsignedLong(pyret);
- if (ret)
- {
- *status = (pyret == Py_True);
- result = true;
- }
-
- Py_DECREF(pyret);
+ else
+ PyErr_SetString(PyExc_TypeError, _("computed hash value has to be an unsigned integer"));
}
- Py_DECREF(pyother);
- Py_DECREF(pyitem);
+ Py_XDECREF(pyret);
+
+ Py_DECREF(pyobj);
PyGILState_Release(gstate);
@@ -157,47 +165,97 @@ static bool py_comparable_item_compare_rich(const GComparableItem *item, const G
/******************************************************************************
* *
-* Paramètres : a = premier object Python à consulter. *
-* b = second object Python à consulter. *
-* op = type de comparaison menée. *
+* Paramètres : self = objet dont l'instance se veut unique. *
+* args = adresse non utilisée ici. *
* *
-* Description : Effectue une comparaison avec un objet 'ComparableItem'. *
+* Description : Transmet l'empreinte d'un objet calculée par son parent. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_comparable_item_richcompare(PyObject *a, PyObject *b, int op)
+static PyObject *py_hashable_object_parent_hash(PyObject *self, PyObject *args)
{
- 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)
+ PyObject *result; /* Valeur à retourner */
+ GHashableObject *object; /* Mécanismes natifs */
+ GHashableObjectInterface *iface; /* Interface utilisée */
+ GHashableObjectInterface *parent_iface; /* Interface parente */
+ guint hash; /* Valeur d'empreitne */
+
+#define HASHABLE_OBJECT_PARENT_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ parent_hash, "$self", \
+ METH_NOARGS, py_hashable_object, \
+ "Provide the hash value defined by the interface implementation"\
+ " from the object native parent.\n" \
+ "\n" \
+ "The result is an unsigned integer.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the object parent does" \
+ " not implement the pychrysalide.glibext.HashableObject" \
+ " interface.\n" \
+ "\n" \
+ "A *RuntimeError* exception is raised if the direct parent type"\
+ " of the object has not a native implementation. For Python" \
+ " implementations, the super()._hash() function has to be used" \
+ " instead." \
+)
+
+ if (!check_for_native_parent(self))
+ return NULL;
+
+ object = G_HASHABLE_OBJECT(pygobject_get(self));
+
+ iface = G_HASHABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ if (parent_iface == NULL)
{
- result = Py_NotImplemented;
- goto cmp_done;
+ PyErr_SetString(PyExc_TypeError, _("object parent does not implement the HashableObject interface"));
+
+ result = NULL;
+
}
+ else
+ {
+ hash = parent_iface->hash(object);
- item_a = G_COMPARABLE_ITEM(pygobject_get(a));
- item_b = G_COMPARABLE_ITEM(pygobject_get(b));
+ result = PyLong_FromUnsignedLong(hash);
- valid = g_comparable_item_compare_rich(item_a, item_b, op, &status);
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
+ }
+
+ return result;
+
+}
- if (valid)
- result = status ? Py_True : Py_False;
- else
- result = Py_NotImplemented;
- cmp_done:
+/******************************************************************************
+* *
+* Paramètres : self = objet manipulé ici. *
+* *
+* Description : Calcule l'empreinte sur 32 bits d'un objet. *
+* *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- Py_INCREF(result);
+static Py_hash_t py_hashable_object_hash(PyObject *self)
+{
+ Py_hash_t result; /* Empreinte à retourner */
+ GHashableObject *object; /* Mécanismes natifs */
+
+ object = G_HASHABLE_OBJECT(pygobject_get(self));
+
+ result = g_hashable_object_hash(object);
+
+ UPDATE_RESULT_IF_RAISED_EXCEPTION(-1);
return result;
@@ -216,44 +274,46 @@ static PyObject *py_comparable_item_richcompare(PyObject *a, PyObject *b, int op
* *
******************************************************************************/
-PyTypeObject *get_python_comparable_item_type(void)
+PyTypeObject *get_python_hashable_object_type(void)
{
- static PyMethodDef py_comparable_item_methods[] = {
+ static PyMethodDef py_hashable_object_methods[] = {
+ HASHABLE_OBJECT_HASH_WRAPPER,
+ HASHABLE_OBJECT_PARENT_HASH_METHOD,
{ NULL }
};
- static PyGetSetDef py_comparable_item_getseters[] = {
+ static PyGetSetDef py_hashable_object_getseters[] = {
{ NULL }
};
- static PyTypeObject py_comparable_item_type = {
+ static PyTypeObject py_hashable_object_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.glibext.ComparableItem",
+ .tp_name = "pychrysalide.glibext.HashableObject",
.tp_basicsize = sizeof(PyObject),
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_hash = py_hashable_object_hash,
- .tp_doc = COMPARABLE_ITEM_DOC,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_richcompare = py_comparable_item_richcompare,
+ .tp_doc = HASHABLE_OBJECT_DOC,
- .tp_methods = py_comparable_item_methods,
- .tp_getset = py_comparable_item_getseters,
+ .tp_methods = py_hashable_object_methods,
+ .tp_getset = py_hashable_object_getseters,
};
- return &py_comparable_item_type;
+ return &py_hashable_object_type;
}
/******************************************************************************
* *
-* Paramètres : module = module dont la définition est à compléter. *
+* Paramètres : - *
* *
-* Description : Prend en charge l'objet 'pychrysalide.....ComparableItem'. *
+* Description : Prend en charge l'objet 'pychrysalide.....HashableObject'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -261,21 +321,21 @@ PyTypeObject *get_python_comparable_item_type(void)
* *
******************************************************************************/
-bool ensure_python_comparable_item_is_registered(void)
+bool ensure_python_hashable_object_is_registered(void)
{
- PyTypeObject *type; /* Type Python 'ComparableItem' */
+ PyTypeObject *type; /* Type Python 'HashableObject'*/
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_init = (GInterfaceInitFunc)py_hashable_object_interface_init,
.interface_finalize = NULL,
.interface_data = NULL,
};
- type = get_python_comparable_item_type();
+ type = get_python_hashable_object_type();
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
@@ -283,10 +343,7 @@ bool ensure_python_comparable_item_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_interface_for_pygobject(dict, G_TYPE_COMPARABLE_ITEM, type, &info))
- return false;
-
- if (!define_comparable_item_constants(type))
+ if (!register_interface_for_pygobject(dict, G_TYPE_HASHABLE_OBJECT, type, &info))
return false;
}
@@ -301,7 +358,7 @@ bool ensure_python_comparable_item_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 élément comparable. *
+* Description : Tente de convertir en interface d'objet réductible. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
* *
@@ -309,11 +366,11 @@ bool ensure_python_comparable_item_is_registered(void)
* *
******************************************************************************/
-int convert_to_comparable_item(PyObject *arg, void *dst)
+int convert_to_hashable_object(PyObject *arg, void *dst)
{
int result; /* Bilan à retourner */
- result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_item_type());
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_hashable_object_type());
switch (result)
{
@@ -323,11 +380,11 @@ int convert_to_comparable_item(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to comparable item");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to hashable object");
break;
case 1:
- *((GComparableItem **)dst) = G_COMPARABLE_ITEM(pygobject_get(arg));
+ *((GHashableObject **)dst) = G_HASHABLE_OBJECT(pygobject_get(arg));
break;
default:
diff --git a/plugins/pychrysalide/glibext/comparison.h b/plugins/pychrysalide/glibext/hashable.h
index 79f7092..8583118 100644
--- a/plugins/pychrysalide/glibext/comparison.h
+++ b/plugins/pychrysalide/glibext/hashable.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * comparison.h - prototypes pour l'équivalent Python du fichier "glibext/comparison.h"
+ * hashable.h - prototypes pour l'équivalent Python du fichier "glibext/hashable.h"
*
- * Copyright (C) 2018 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H
-#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H
+#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_HASHABLE_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_HASHABLE_H
#include <Python.h>
@@ -32,14 +32,14 @@
/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_comparable_item_type(void);
+PyTypeObject *get_python_hashable_object_type(void);
-/* Prend en charge l'objet 'pychrysalide.glibext.ComparableItem'. */
-bool ensure_python_comparable_item_is_registered(void);
+/* Prend en charge l'objet 'pychrysalide.glibext.HashableObject'. */
+bool ensure_python_hashable_object_is_registered(void);
-/* Tente de convertir en élément comparable. */
-int convert_to_comparable_item(PyObject *, void *);
+/* Tente de convertir en interface d'objet réductible. */
+int convert_to_hashable_object(PyObject *, void *);
-#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H */
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_HASHABLE_H */
diff --git a/plugins/pychrysalide/glibext/module-ui.c b/plugins/pychrysalide/glibext/module-ui.c
new file mode 100644
index 0000000..8fa6d0e
--- /dev/null
+++ b/plugins/pychrysalide/glibext/module-ui.c
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire glibext (forme graphique) en tant que module
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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-ui.h"
+
+
+#include <assert.h>
+
+
+#include "bufferline.h"
+#include "generator.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Intègre les objets du module 'glibext' (mode UI). *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_glibext_module_ui(void)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (result) result = ensure_python_token_generator_is_registered();
+
+ if (result) result = ensure_python_buffer_line_is_registered();
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/module-ui.h b/plugins/pychrysalide/glibext/module-ui.h
new file mode 100644
index 0000000..d91a2fa
--- /dev/null
+++ b/plugins/pychrysalide/glibext/module-ui.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire glibext (forme graphique) en tant que module
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_MODULE_UI_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_MODULE_UI_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+/* Intègre les objets du module 'glibext' (mode UI). */
+bool populate_glibext_module_ui(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_MODULE_UI_H */
diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c
index 6cca246..bbe357d 100644
--- a/plugins/pychrysalide/glibext/module.c
+++ b/plugins/pychrysalide/glibext/module.c
@@ -33,16 +33,20 @@
#include "buffercache.h"
#include "bufferline.h"
#include "bufferview.h"
-#include "comparison.h"
#include "configuration.h"
#include "linecursor.h"
#include "linegen.h"
#include "loadedpanel.h"
#include "named.h"
*/
+#include "comparable.h"
+#include "hashable.h"
#include "objhole.h"
#include "portion.h"
+#include "secstorage.h"
+#include "serialize.h"
#include "singleton.h"
+#include "storage.h"
#include "strbuilder.h"
#include "work.h"
#include "workqueue.h"
@@ -112,12 +116,17 @@ bool populate_glibext_module(void)
result = true;
+ if (result) result = ensure_python_comparable_object_is_registered();
+ if (result) result = ensure_python_hashable_object_is_registered();
+ if (result) result = ensure_python_serializable_object_is_registered();
if (result) result = ensure_python_singleton_candidate_is_registered();
if (result) result = ensure_python_string_builder_is_registered();
if (result) result = ensure_python_thick_object_is_registered();
if (result) result = ensure_python_binary_portion_is_registered();
if (result) result = ensure_python_generic_work_is_registered();
+ if (result) result = ensure_python_object_storage_is_registered();
+ if (result) result = ensure_python_secret_storage_is_registered();
if (result) result = ensure_python_singleton_factory_is_registered();
if (result) result = ensure_python_work_queue_is_registered();
@@ -129,7 +138,6 @@ bool populate_glibext_module(void)
#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();
diff --git a/plugins/pychrysalide/glibext/objhole.c b/plugins/pychrysalide/glibext/objhole.c
index 2a3ad6f..6bea5d1 100644
--- a/plugins/pychrysalide/glibext/objhole.c
+++ b/plugins/pychrysalide/glibext/objhole.c
@@ -37,12 +37,25 @@
-CREATE_DYN_CONSTRUCTOR(thick_object, G_TYPE_THICK_OBJECT);
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+CREATE_DYN_CONSTRUCTOR(thick_object, G_TYPE_THICK_OBJECT);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_thick_object_init(PyObject *, PyObject *, PyObject *);
+
+
+/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */
+
+
+/* Pose un verrou à l'aide du bit dédié de GObject. */
+static PyObject *py_thick_object_lock(PyObject *, PyObject *);
+
+/* Retire un verrou via le bit dédié de GObject. */
+static PyObject *py_thick_object_unlock(PyObject *, PyObject *);
+
/* Indique le nombre de bits accaparés par la GLib. */
static PyObject *py_thick_object_get__GOBJECT_RESERVED_EXTRA_BITS(PyObject *, void *);
@@ -54,6 +67,11 @@ static int py_thick_object_set_extra(PyObject *, PyObject *, void *);
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : self = objet à initialiser (théoriquement). *
@@ -92,6 +110,86 @@ static int py_thick_object_init(PyObject *self, PyObject *args, PyObject *kwds)
}
+
+/* ---------------------------------------------------------------------------------- */
+/* LIAISON DE FONCTIONNALITES AVEC L'API PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : self = instance représentant une extension d'objet. *
+* args = arguments fournis à l'appel, non utilisé ici. *
+* *
+* Description : Pose un verrou à l'aide du bit dédié de GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_thick_object_lock(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Résultat à retourner */
+ GThickObject *obj; /* Version GLib de l'instance */
+
+#define THICK_OBJECT_LOCK_METHOD PYTHON_METHOD_DEF \
+( \
+ lock, "$self", \
+ METH_NOARGS, py_thick_object, \
+ "Lock the object using the internal GLib bit.\n" \
+)
+
+ obj = G_THICK_OBJECT(pygobject_get(self));
+
+ g_thick_object_lock(obj);
+
+ result = Py_None;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = instance représentant une extension d'objet. *
+* args = arguments fournis à l'appel, non utilisé ici. *
+* *
+* Description : Retire un verrou via le bit dédié de GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_thick_object_unlock(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Résultat à retourner */
+ GThickObject *obj; /* Version GLib de l'instance */
+
+#define THICK_OBJECT_UNLOCK_METHOD PYTHON_METHOD_DEF \
+( \
+ unlock, "$self", \
+ METH_NOARGS, py_thick_object, \
+ "Unlock the object using the internal GLib bit.\n" \
+)
+
+ obj = G_THICK_OBJECT(pygobject_get(self));
+
+ g_thick_object_unlock(obj);
+
+ result = Py_None;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
/******************************************************************************
* *
* Paramètres : self = objet Python concerné par l'appel. *
@@ -215,6 +313,8 @@ static int py_thick_object_set_extra(PyObject *self, PyObject *value, void *clos
PyTypeObject *get_python_thick_object_type(void)
{
static PyMethodDef py_thick_object_methods[] = {
+ THICK_OBJECT_LOCK_METHOD,
+ THICK_OBJECT_UNLOCK_METHOD,
{ NULL }
};
diff --git a/plugins/pychrysalide/glibext/secstorage.c b/plugins/pychrysalide/glibext/secstorage.c
new file mode 100644
index 0000000..5935d29
--- /dev/null
+++ b/plugins/pychrysalide/glibext/secstorage.c
@@ -0,0 +1,625 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * secstorage.c - équivalent Python du fichier "glibext/secstorage.c"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "secstorage.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <glibext/secstorage-int.h>
+
+
+#include "../access.h"
+#include "../convert.h"
+#include "../helpers.h"
+
+
+
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+CREATE_DYN_CONSTRUCTOR(secret_storage, G_TYPE_SECRET_STORAGE);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_secret_storage_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+
+
+/* Définit un mot de passe pour protéger une clef maître. */
+static PyObject *py_secret_storage_set_password(PyObject *, PyObject *);
+
+/* Déverrouille la clef de chiffrement maître. */
+static PyObject *py_secret_storage_unlock(PyObject *, PyObject *);
+
+/* Verrouille la clef de chiffrement maître. */
+static PyObject *py_secret_storage_lock(PyObject *, PyObject *);
+
+/* Chiffre des données avec la clef de chiffrement maître. */
+static PyObject *py_secret_storage_encrypt_data(PyObject *, PyObject *);
+
+/* Déchiffre des données avec la clef de chiffrement maître. */
+static PyObject *py_secret_storage_decrypt_data(PyObject *, PyObject *);
+
+/* Détermine si une clef de chiffrement protégée est en place. */
+static PyObject *py_secret_storage_has_key(PyObject *, void *);
+
+/* Détermine si la clef de chiffrement maître est vérouillée. */
+static PyObject *py_secret_storage_is_locked(PyObject *, void *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* 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_secret_storage_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ GSettings *settings; /* Configuration à considérer */
+ int ret; /* Bilan de lecture des args. */
+ GSecretStorage *storage; /* Stockage natif à manipuler */
+
+#define SECRET_STORAGE_DOC \
+ "SecretStorage acts as guardian for secrets using ecryption," \
+ " mainly for sensitive information stored as configuration" \
+ " parameters.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " SecretStorage(settings=None)" \
+ "\n" \
+ "The *settings* arguement may point to a GSettings instance." \
+ " This optional argument is mainly used for testing purpose;" \
+ " the main configuration settings are used by default."
+
+ settings = NULL;
+
+ ret = PyArg_ParseTuple(args, "|O&", convert_to_gsettings_or_none, &settings);
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ if (!g_secret_storage_create(storage, settings))
+ return -1;
+
+ return 0;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONNEXION AVEC L'API DE PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Définit un mot de passe pour protéger une clef maître. *
+* *
+* Retour : Bilan de la mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_secret_storage_set_password(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Conversion à retourner */
+ const char *passwd; /* Mot de passe associé */
+ int ret; /* Bilan de lecture des args. */
+ GSecretStorage *storage; /* Stockage sécurisé visé */
+ bool status; /* Bilan de situation */
+
+#define SECRET_STORAGE_SET_PASSWORD_METHOD PYTHON_METHOD_DEF \
+( \
+ set_password, "/, password=''", \
+ METH_VARARGS, py_secret_storage, \
+ "Create a master key used for protecting secrets. This key is" \
+ " itself protected by the provided password.\n" \
+ "\n" \
+ "The supplied *password* has to be a string.\n" \
+ "\n" \
+ "The result is a boolean status: *True* if the operation successed,"\
+ " *False* otherwise." \
+)
+
+ passwd = "";
+
+ ret = PyArg_ParseTuple(args, "|s", &passwd);
+ if (!ret) return NULL;
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ status = g_secret_storage_set_password(storage, passwd);
+
+ 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 : Déverrouille la clef de chiffrement maître. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_secret_storage_unlock(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Conversion à retourner */
+ const char *passwd; /* Mot de passe associé */
+ int ret; /* Bilan de lecture des args. */
+ GSecretStorage *storage; /* Stockage sécurisé visé */
+ bool status; /* Bilan de situation */
+
+#define SECRET_STORAGE_UNLOCK_METHOD PYTHON_METHOD_DEF \
+( \
+ unlock, "/, password=''", \
+ METH_VARARGS, py_secret_storage, \
+ "Decrypt in memory the master key used for protecting secrets.\n" \
+ "\n" \
+ "The supplied *password* is the primary password used to protect" \
+ " this key.\n" \
+ "\n" \
+ "The result is a boolean status: *True* if the operation successed" \
+ " or if the master key is already unlocked, *False* otherwise." \
+)
+
+ passwd = "";
+
+ ret = PyArg_ParseTuple(args, "|s", &passwd);
+ if (!ret) return NULL;
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ status = g_secret_storage_unlock(storage, passwd);
+
+ 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 : Verrouille la clef de chiffrement maître. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_secret_storage_lock(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Conversion à retourner */
+ GSecretStorage *storage; /* Stockage sécurisé visé */
+
+#define SECRET_STORAGE_LOCK_METHOD PYTHON_METHOD_DEF \
+( \
+ lock, "", \
+ METH_NOARGS, py_secret_storage, \
+ "Clear from memory the master key used for protecting secrets." \
+)
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ g_secret_storage_lock(storage);
+
+ result = Py_None;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Chiffre des données avec la clef de chiffrement maître. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_secret_storage_encrypt_data(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Conversion à retourner */
+ const char *data_in; /* Données d'entrée à chiffrer */
+ Py_ssize_t size_in; /* Quantité de ces données */
+ int ret; /* Bilan de lecture des args. */
+ sized_binary_t in; /* Données à chiffer */
+ GSecretStorage *storage; /* Stockage sécurisé visé */
+ bool status; /* Bilan de situation */
+ sized_binary_t out; /* Données chiffrées */
+
+#define SECRET_STORAGE_ENCRYPT_DATA_METHOD PYTHON_METHOD_DEF \
+( \
+ encrypt_data, "data", \
+ METH_VARARGS, py_secret_storage, \
+ "Encrypt data using an unlocked the master key.\n" \
+ "\n" \
+ "The *data* arguement points to bytes to process." \
+ "\n" \
+ "The result is either encrypted *data* as bytes in case of success,"\
+ " or *None* in case of failure." \
+)
+
+ ret = PyArg_ParseTuple(args, "s#", &data_in, &size_in);
+ if (!ret) return NULL;
+
+ in.static_data = data_in;
+ in.size = size_in;
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ status = g_secret_storage_encrypt_data(storage, &in, &out);
+
+ if (status)
+ {
+ result = PyBytes_FromStringAndSize(out.static_data, out.size);
+ exit_sized_binary(&out);
+ }
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Déchiffre des données avec la clef de chiffrement maître. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_secret_storage_decrypt_data(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Conversion à retourner */
+ const char *data_in; /* Données d'entrée à chiffrer */
+ Py_ssize_t size_in; /* Quantité de ces données */
+ int ret; /* Bilan de lecture des args. */
+ sized_binary_t in; /* Données à chiffer */
+ GSecretStorage *storage; /* Stockage sécurisé visé */
+ bool status; /* Bilan de situation */
+ sized_binary_t out; /* Données chiffrées */
+
+#define SECRET_STORAGE_DECRYPT_DATA_METHOD PYTHON_METHOD_DEF \
+( \
+ decrypt_data, "data", \
+ METH_VARARGS, py_secret_storage, \
+ "Decrypt data using an unlocked the master key.\n" \
+ "\n" \
+ "The *data* arguement points to bytes to process." \
+ "\n" \
+ "The result is either decrypted *data* as bytes in case of success,"\
+ " or *None* in case of failure." \
+)
+
+ ret = PyArg_ParseTuple(args, "s#", &data_in, &size_in);
+ if (!ret) return NULL;
+
+ in.static_data = data_in;
+ in.size = size_in;
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ status = g_secret_storage_decrypt_data(storage, &in, &out);
+
+ if (status)
+ {
+ result = PyBytes_FromStringAndSize(out.static_data, out.size);
+ exit_sized_binary(&out);
+ }
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Détermine si une clef de chiffrement protégée est en place. *
+* *
+* Retour : Bilan de l'analyse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_secret_storage_has_key(PyObject *self, void *closure)
+{
+ PyObject *result; /* Instance Python à retourner */
+ GSecretStorage *storage; /* Stockage sécurisé visé */
+ bool status; /* Bilan de consultation */
+
+#define PY_SECRET_STORAGE_HAS_KEY_ATTRIB PYTHON_HAS_DEF_FULL \
+( \
+ key, py_secret_storage, \
+ "Indicate if a master key used for protecting secrets seems to have"\
+ " been defined. Without any unlocking attempt, the test only relies"\
+ " on the length of saved master data.\n" \
+ "\n" \
+ "The returned status is a boolean status: *True* if the master key" \
+ " seems to exist, *False* otherwise." \
+)
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ status = g_secret_storage_has_key(storage);
+
+ 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 : Détermine si la clef de chiffrement maître est vérouillée. *
+* *
+* Retour : Bilan de la détermination. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_secret_storage_is_locked(PyObject *self, void *closure)
+{
+ PyObject *result; /* Instance Python à retourner */
+ GSecretStorage *storage; /* Stockage sécurisé visé */
+ bool status; /* Bilan de consultation */
+
+#define SECRET_STORAGE_IS_LOCKED_ATTRIB PYTHON_IS_DEF_FULL \
+( \
+ locked, py_secret_storage, \
+ "Indicate if the master key used for protecting secrets is" \
+ " currently decrypted in memory.\n" \
+ "\n" \
+ "The *settings* arguement must point to a GSettings intance; the" \
+ " main configuration settings are used by default.\n" \
+ "\n" \
+ "The returned status is a boolean status: *True* if the master key" \
+ " is unlocked and ready for use, *False* otherwise." \
+)
+
+ storage = G_SECRET_STORAGE(pygobject_get(self));
+
+ status = g_secret_storage_is_locked(storage);
+
+ 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_secret_storage_type(void)
+{
+ static PyMethodDef py_secret_storage_methods[] = {
+ SECRET_STORAGE_SET_PASSWORD_METHOD,
+ SECRET_STORAGE_UNLOCK_METHOD,
+ SECRET_STORAGE_LOCK_METHOD,
+ SECRET_STORAGE_ENCRYPT_DATA_METHOD,
+ SECRET_STORAGE_DECRYPT_DATA_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_secret_storage_getseters[] = {
+ PY_SECRET_STORAGE_HAS_KEY_ATTRIB,
+ SECRET_STORAGE_IS_LOCKED_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_secret_storage_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.glibext.SecretStorage",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SECRET_STORAGE_DOC,
+
+ .tp_methods = py_secret_storage_methods,
+ .tp_getset = py_secret_storage_getseters,
+
+ .tp_init = py_secret_storage_init,
+ .tp_new = py_secret_storage_new,
+
+ };
+
+ return &py_secret_storage_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.glibext.SecretStorage'.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_secret_storage_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'SecretStorage' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_secret_storage_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.glibext");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SECRET_STORAGE, 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 gardien des secrets avec stockage. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_secret_storage(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_secret_storage_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 secret storage");
+ break;
+
+ case 1:
+ *((GSecretStorage **)dst) = G_SECRET_STORAGE(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/secstorage.h b/plugins/pychrysalide/glibext/secstorage.h
new file mode 100644
index 0000000..68726c3
--- /dev/null
+++ b/plugins/pychrysalide/glibext/secstorage.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * secstorage.h - prototypes pour l'équivalent Python du fichier "glibext/secstorage.h"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_SECSTORAGE_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_SECSTORAGE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_secret_storage_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.glibext.SecretStorage'. */
+bool ensure_python_secret_storage_is_registered(void);
+
+/* Tente de convertir en gardien des secrets avec stockage. */
+int convert_to_secret_storage(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_SECSTORAGE_H */
diff --git a/plugins/pychrysalide/analysis/storage/serialize.c b/plugins/pychrysalide/glibext/serialize.c
index 40fcef7..61f359f 100644
--- a/plugins/pychrysalide/analysis/storage/serialize.c
+++ b/plugins/pychrysalide/glibext/serialize.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * serialize.c - équivalent Python du fichier "analysis/storage/serialize.h"
+ * serialize.c - équivalent Python du fichier "glibext/serialize.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -28,13 +28,12 @@
#include <pygobject.h>
-#include <analysis/storage/serialize-int.h>
+#include <glibext/serialize-int.h>
#include "storage.h"
-#include "../../access.h"
-#include "../../helpers.h"
-#include "../../common/packed.h"
+#include "../access.h"
+#include "../helpers.h"
@@ -42,23 +41,23 @@
/* Procède à l'initialisation de l'interface de génération. */
-static void py_serializable_object_interface_init(GSerializableObjectIface *, gpointer *);
+static void py_serializable_object_interface_init(GSerializableObjectInterface *, gpointer *);
-/* Charge un objet depuis une mémoire tampon. */
-static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+/* Charge un objet depuis un flux de données. */
+static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, int);
-/* Sauvegarde un objet dans une mémoire tampon. */
-static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+/* Sauvegarde un objet dans un flux de données. */
+static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, int);
/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
-/* Charge un objet depuis une mémoire tampon. */
+/* Charge un objet depuis un flux de données. */
static bool py_serializable_object_load(PyObject *, PyObject *);
-/* Sauvegarde un objet dans une mémoire tampon. */
+/* Sauvegarde un objet dans un flux de données. */
static bool py_serializable_object_store(PyObject *, PyObject *);
@@ -81,7 +80,7 @@ static bool py_serializable_object_store(PyObject *, PyObject *);
* *
******************************************************************************/
-static void py_serializable_object_interface_init(GSerializableObjectIface *iface, gpointer *unused)
+static void py_serializable_object_interface_init(GSerializableObjectInterface *iface, gpointer *unused)
{
#define SERIALIZABLE_OBJECT_DOC \
@@ -94,8 +93,8 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac
" ...\n" \
"\n" \
"The following methods have to be defined for new implementations:\n" \
- "* pychrysalide.analysis.storage.SerializableObject._load();\n" \
- "* pychrysalide.analysis.storage.SerializableObject._store();\n"
+ "* pychrysalide.glibext.SerializableObject._load();\n" \
+ "* pychrysalide.glibext.SerializableObject._store();\n"
iface->load = py_serializable_object_load_wrapper;
iface->store = py_serializable_object_store_wrapper;
@@ -106,10 +105,10 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac
/******************************************************************************
* *
* Paramètres : object = instruction d'assemblage à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en lecture. *
* *
-* Description : Charge un objet depuis une mémoire tampon. *
+* Description : Charge un objet depuis un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -117,25 +116,24 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac
* *
******************************************************************************/
-static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *storage_obj; /* Objet Python à emmployer */
PyObject *args; /* Arguments pour l'appel */
PyObject *pyobj; /* Objet Python concerné */
PyObject *pyret; /* Bilan de consultation */
#define SERIALIZABLE_OBJECT_LOAD_WRAPPER PYTHON_WRAPPER_DEF \
( \
- _load, "$self, storage, pbuf, /", \
+ _load, "$self, storage, fd, /", \
METH_VARARGS, \
- "Abstract method used to load an object definition from buffered data.\n" \
+ "Abstract method used to load an object definition from a data stream.\n" \
"\n" \
- "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \
- " provided to store inner objects, if relevant, or None. The *pbuf*" \
- " argument points to a pychrysalide.common.PackedBuffer object containing" \
- " the data to process.\n" \
+ "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \
+ " provided to store inner objects. The *fd* argument is an integer value" \
+ " provided as a file descriptor which as to be kept open after" \
+ " processing.\n" \
"\n" \
"The result is a boolean indicating the status of the operation." \
)
@@ -148,17 +146,9 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb
if (has_python_method(pyobj, "_load"))
{
- if (storage == NULL)
- {
- storage_obj = Py_None;
- Py_INCREF(storage_obj);
- }
- else
- storage_obj = pygobject_new(G_OBJECT(storage));
-
args = PyTuple_New(2);
- PyTuple_SetItem(args, 0, storage_obj);
- PyTuple_SetItem(args, 1, build_from_internal_packed_buffer(pbuf));
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(storage)));
+ PyTuple_SetItem(args, 1, PyLong_FromLong(fd));
pyret = run_python_method(pyobj, "_load", args);
@@ -182,10 +172,10 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb
/******************************************************************************
* *
* Paramètres : object = instruction d'assemblage à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Sauvegarde un objet dans une mémoire tampon. *
+* Description : Sauvegarde un objet dans un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -193,25 +183,24 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb
* *
******************************************************************************/
-static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *storage_obj; /* Objet Python à emmployer */
PyObject *args; /* Arguments pour l'appel */
PyObject *pyobj; /* Objet Python concerné */
PyObject *pyret; /* Bilan de consultation */
#define SERIALIZABLE_OBJECT_STORE_WRAPPER PYTHON_WRAPPER_DEF \
( \
- _store, "$self, storage, pbuf, /", \
+ _store, "$self, storage, fd, /", \
METH_VARARGS, \
- "Abstract method used to store an object definition into buffered data.\n" \
+ "Abstract method used to store an object definition into a data stream.\n" \
"\n" \
- "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \
- " provided to store inner objects, if relevant, or None. The *pbuf*" \
- " argument points to a pychrysalide.common.PackedBuffer object containing" \
- " the data to process.\n" \
+ "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \
+ " provided to store inner objects. The *fd* argument is an integer value" \
+ " provided as a file descriptor which as to be kept open after" \
+ " processing.\n" \
"\n" \
"The result is a boolean indicating the status of the operation." \
)
@@ -224,17 +213,9 @@ static bool py_serializable_object_store_wrapper(const GSerializableObject *obje
if (has_python_method(pyobj, "_store"))
{
- if (storage == NULL)
- {
- storage_obj = Py_None;
- Py_INCREF(storage_obj);
- }
- else
- storage_obj = pygobject_new(G_OBJECT(storage));
-
args = PyTuple_New(2);
- PyTuple_SetItem(args, 0, storage_obj);
- PyTuple_SetItem(args, 1, build_from_internal_packed_buffer(pbuf));
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(storage)));
+ PyTuple_SetItem(args, 1, PyLong_FromLong(fd));
pyret = run_python_method(pyobj, "_store", args);
@@ -266,7 +247,7 @@ static bool py_serializable_object_store_wrapper(const GSerializableObject *obje
* Paramètres : self = classe représentant un générateur à manipuler. *
* args = arguments fournis à l'appel. *
* *
-* Description : Charge un objet depuis une mémoire tampon. *
+* Description : Charge un objet depuis un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -278,32 +259,30 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args)
{
PyObject *result; /* Bilan à retourner */
GObjectStorage *storage; /* Conservateur à manipuler */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
+ int fd; /* Flux ouvert (en lecture) */
int ret; /* Bilan de lecture des args. */
GSerializableObject *object; /* Version native */
bool status; /* Bilan de l'opération */
#define SERIALIZABLE_OBJECT_LOAD_METHOD PYTHON_METHOD_DEF \
( \
- load, "$self, storage, pbuf, /", \
+ load, "$self, storage, fd, /", \
METH_VARARGS, py_serializable_object, \
- "Load an object definition from buffered data.\n" \
+ "Load an object definition from a data stream.\n" \
"\n" \
- "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \
- " provided to store inner objects, if relevant, or None. The *pbuf*" \
- " argument points to a pychrysalide.common.PackedBuffer object containing" \
- " the data to process.\n" \
+ "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \
+ " provided to store inner objects. The *fd* argument is an integer value" \
+ " used as a file descriptor for writing data\n" \
"\n" \
"The result is a boolean indicating the status of the operation." \
)
- ret = PyArg_ParseTuple(args, "O&O&", convert_to_object_storage_or_none, &storage,
- convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "O&i", convert_to_object_storage, &storage, &fd);
if (!ret) return NULL;
object = G_SERIALIZABLE_OBJECT(pygobject_get(self));
- status = g_serializable_object_load(object, storage, pbuf);
+ status = g_serializable_object_load(object, storage, fd);
result = status ? Py_True : Py_False;
Py_INCREF(result);
@@ -318,7 +297,7 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args)
* Paramètres : self = classe représentant un générateur à manipuler. *
* args = arguments fournis à l'appel. *
* *
-* Description : Sauvegarde un objet dans une mémoire tampon. *
+* Description : Sauvegarde un objet dans un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -330,32 +309,30 @@ static bool py_serializable_object_store(PyObject *self, PyObject *args)
{
PyObject *result; /* Bilan à retourner */
GObjectStorage *storage; /* Conservateur à manipuler */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
+ int fd; /* Flux ouvert (en lecture) */
int ret; /* Bilan de lecture des args. */
GSerializableObject *object; /* Version native */
bool status; /* Bilan de l'opération */
#define SERIALIZABLE_OBJECT_STORE_METHOD PYTHON_METHOD_DEF \
( \
- store, "$self, storage, pbuf, /", \
+ store, "$self, storage, fd, /", \
METH_VARARGS, py_serializable_object, \
- "Store an object definition into buffered data.\n" \
+ "Store an object definition into a data stream.\n" \
"\n" \
- "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \
- " provided to store inner objects, if relevant, or None. The *pbuf*" \
- " argument points to a pychrysalide.common.PackedBuffer object containing" \
- " the data to process.\n" \
+ "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \
+ " provided to store inner objects. The *fd* argument is an integer value" \
+ " used as a file descriptor for writing data\n" \
"\n" \
"The result is a boolean indicating the status of the operation." \
)
- ret = PyArg_ParseTuple(args, "O&O&", convert_to_object_storage_or_none, &storage,
- convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "O&i", convert_to_object_storage, &storage, &fd);
if (!ret) return NULL;
object = G_SERIALIZABLE_OBJECT(pygobject_get(self));
- status = g_serializable_object_store(object, storage, pbuf);
+ status = g_serializable_object_store(object, storage, fd);
result = status ? Py_True : Py_False;
Py_INCREF(result);
@@ -395,7 +372,7 @@ PyTypeObject *get_python_serializable_object_type(void)
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.analysis.storage.SerializableObject",
+ .tp_name = "pychrysalide.glibext.SerializableObject",
.tp_basicsize = sizeof(PyObject),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
@@ -442,7 +419,7 @@ bool ensure_python_serializable_object_is_registered(void)
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
- module = get_access_to_python_module("pychrysalide.analysis.storage");
+ module = get_access_to_python_module("pychrysalide.glibext");
dict = PyModule_GetDict(module);
diff --git a/plugins/pychrysalide/analysis/storage/serialize.h b/plugins/pychrysalide/glibext/serialize.h
index 7e831e5..90688ba 100644
--- a/plugins/pychrysalide/analysis/storage/serialize.h
+++ b/plugins/pychrysalide/glibext/serialize.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * serialize.h - prototypes pour l'équivalent Python du fichier "analysis/storage/serialize.h"
+ * serialize.h - prototypes pour l'équivalent Python du fichier "glibext/serialize.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H
-#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H
+#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H
#include <Python.h>
@@ -34,7 +34,7 @@
/* Fournit un accès à une définition de type à diffuser. */
PyTypeObject *get_python_serializable_object_type(void);
-/* Prend en charge l'objet 'pychrysalide.analysis.storage.SerializableObject'. */
+/* Prend en charge l'objet 'pychrysalide.glibext.SerializableObject'. */
bool ensure_python_serializable_object_is_registered(void);
/* Tente de convertir en objet adapté à une mise en cache. */
@@ -42,4 +42,4 @@ int convert_to_serializable_object(PyObject *, void *);
-#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H */
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H */
diff --git a/plugins/pychrysalide/glibext/singleton.c b/plugins/pychrysalide/glibext/singleton.c
index ca847de..8712506 100644
--- a/plugins/pychrysalide/glibext/singleton.c
+++ b/plugins/pychrysalide/glibext/singleton.c
@@ -49,20 +49,20 @@ static GSingletonCandidate **py_singleton_candidate_list_inner_instances_wrapper
/* Met à jour une liste de candidats embarqués par un candidat. */
static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCandidate *, GSingletonCandidate **, size_t);
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *);
+/* Marque un candidat comme figé. */
+static void py_singleton_candidate_mark_as_read_only_wrapper(GSingletonCandidate *);
-/* Détermine si deux candidats à l'unicité sont identiques. */
-static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *, const GSingletonCandidate *);
+/* Indique si le candidat est figé. */
+static bool py_singleton_candidate_is_read_only_wrapper(const GSingletonCandidate *);
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-static PyObject *py_singleton_candidate_hash(PyObject *, PyObject *);
+/* Indique si le candidat est figé. */
+static PyObject *py_singleton_candidate_is_read_only(PyObject *, void *);
-/* Fournit une liste de candidats embarqués par un candidat. */
-static PyObject *py_singleton_candidate_get_inner_instances(PyObject *, void *);
+/* Crée une copie modifiable d'un object unique. */
+static GSingletonCandidate *py_singleton_candidate_dup_wrapper(const GSingletonCandidate *);
-/* Effectue une comparaison avec un objet 'SingletonCandidate'. */
-static PyObject *py_singleton_candidate_richcompare(PyObject *, PyObject *, int);
+/* Crée une copie modifiable d'un object unique. */
+static PyObject *py_singleton_candidate_dup(PyObject *, PyObject *);
@@ -104,25 +104,37 @@ static void py_singleton_candidate_interface_init(GSingletonCandidateInterface *
" aiming at becoming singleton instances. All shared singletons are" \
" registered within a pychrysalide.glibext.SingletonFactory object.\n" \
"\n" \
+ "Implementations of the pychrysalide.glibext.HashableObject and" \
+ " pychrysalide.glibext.ComparableObject interfaces are required for" \
+ " types implementing the SingletonCandidate interface.\n" \
+ "\n" \
"The main implemantations come with types derived from" \
- " pychrysalide.analysis.DataType.\n" \
+ " pychrysalide.analysis.DataType (with possible recursivity) or from" \
+ " pychrysalide.arch.ArchOperand.\n" \
"\n" \
"A typical class declaration for a new implementation looks like:\n" \
"\n" \
- " class NewImplem(GObject.Object, SingletonCandidate):\n" \
+ " class NewImplem(GObject.Object, HashableObject, ComparableObject," \
+ " SingletonCandidate):\n" \
" ...\n" \
"\n" \
"The following methods have to be defined for new implementations:\n" \
+ "* pychrysalide.glibext.SingletonCandidate._mark_as_read_only();\n" \
+ "* pychrysalide.glibext.SingletonCandidate._is_read_only();\n" \
+ "* pychrysalide.glibext.SingletonCandidate._dup().\n" \
+ "\n" \
+ "The following methods may bbe defined for new implementations if" \
+ " inner SingletonCandidate objets are carried:\n" \
"* pychrysalide.glibext.SingletonCandidate._list_inner_instances();\n" \
- "* pychrysalide.glibext.SingletonCandidate._update_inner_instances();\n"\
- "* pychrysalide.glibext.SingletonCandidate.__hash__();\n" \
- "* pychrysalide.glibext.SingletonCandidate.__eq__().\n"
+ "* pychrysalide.glibext.SingletonCandidate._update_inner_instances().\n"
iface->update_inner = py_singleton_candidate_update_inner_instances_wrapper;
iface->list_inner = py_singleton_candidate_list_inner_instances_wrapper;
- iface->hash = py_singleton_candidate___hash__wrapper;
- iface->is_equal = py_singleton_candidate___eq__wrapper;
+ iface->mark_as_ro = py_singleton_candidate_mark_as_read_only_wrapper;
+ iface->is_ro = py_singleton_candidate_is_read_only_wrapper;
+
+ iface->dup = py_singleton_candidate_dup_wrapper;
}
@@ -297,122 +309,97 @@ static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCand
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
+* Description : Marque un candidat comme figé. *
* *
-* Retour : Empreinte de l'élément représenté. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *candidate)
+static void py_singleton_candidate_mark_as_read_only_wrapper(GSingletonCandidate *candidate)
{
- guint result; /* Empreinte à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
PyObject *pyobj; /* Objet Python concerné */
PyObject *pyret; /* Bilan de consultation */
-#define SINGLETON_CANDIDATE_HASH_WRAPPER PYTHON_WRAPPER_DEF \
-( \
- __hash__, "$self, /", \
- METH_NOARGS, \
- "Abstract method used to produce a hash of the object.\n" \
- "\n" \
- "The result must be an integer value up to 64 bits." \
- "\n" \
- "Inner instances which are listed through the" \
- " pychrysalide.glibext.SingletonCandidate._list_inner_instances()" \
- " method do not need to get processed here as they are handled" \
- " automatically by the interface core." \
+#define SINGLETON_CANDIDATE_MARK_AS_READ_ONLY_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _mark_as_read_only, "$self", \
+ METH_NOARGS, \
+ "Abstract method used to seal the object as unmodifiable.\n" \
+ "\n" \
+ "No result is expected." \
)
- result = 0;
-
gstate = PyGILState_Ensure();
pyobj = pygobject_new(G_OBJECT(candidate));
- if (has_python_method(pyobj, "__hash__"))
- {
- pyret = run_python_method(pyobj, "__hash__", NULL);
+ pyret = run_python_method(pyobj, "_mark_as_read_only", NULL);
- if (pyret != NULL)
- {
- if (PyLong_Check(pyret))
- result = PyLong_AsUnsignedLongMask(pyret);
-
- Py_DECREF(pyret);
-
- }
-
- }
+ Py_XDECREF(pyret);
Py_DECREF(pyobj);
PyGILState_Release(gstate);
- return result;
-
}
/******************************************************************************
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
-* other = second élément à analyser. *
* *
-* Description : Détermine si deux candidats à l'unicité sont identiques. *
+* Description : Indique si le candidat est figé. *
* *
-* Retour : Bilan de la comparaison. *
+* Retour : true si le contenu du candidat ne peut plus être modifié. *
* *
* Remarques : - *
* *
******************************************************************************/
-static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *candidate, const GSingletonCandidate *other)
+static bool py_singleton_candidate_is_read_only_wrapper(const GSingletonCandidate *candidate)
{
- guint result; /* Empreinte à retourner */
+ 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 */
-#define SINGLETON_CANDIDATE_EQ_WRAPPER PYTHON_WRAPPER_DEF \
-( \
- __eq__, "$self, other, /", \
- METH_NOARGS, \
- "Abstract method used to provide the *__eq__* method for" \
- " rich comparison.\n" \
- "\n" \
- "The expected result is a boolean value." \
+#define SINGLETON_CANDIDATE_IS_READ_ONLY_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _is_read_only, "$self", \
+ METH_NOARGS, \
+ "Abstract method used to provide the state of the object: are" \
+ " its properties frozen (*True*) or can it be modified" \
+ " (*False*)?\n" \
+ "\n" \
+ "The result has to be a boolean status.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the return value is not" \
+ " a boolean." \
)
- result = 0;
+ result = false;
gstate = PyGILState_Ensure();
pyobj = pygobject_new(G_OBJECT(candidate));
- if (has_python_method(pyobj, "__eq__"))
- {
- args = PyTuple_New(1);
- PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other)));
-
- pyret = run_python_method(pyobj, "__eq__", args);
-
- if (pyret != NULL)
- {
- if (PyLong_Check(pyret))
- result = PyLong_AsUnsignedLong(pyret);
+ pyret = run_python_method(pyobj, "_is_read_only", NULL);
- Py_DECREF(pyret);
+ if (pyret != NULL)
+ {
+ if (PyBool_Check(pyret))
+ result = (pyret == Py_True);
- }
-
- Py_DECREF(args);
+ else
+ PyErr_SetString(PyExc_TypeError, _("status has to be provided as a boolean value"));
}
+ Py_XDECREF(pyret);
+
Py_DECREF(pyobj);
PyGILState_Release(gstate);
@@ -424,47 +411,77 @@ static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *
/******************************************************************************
* *
-* Paramètres : self = objet dont l'instance se veut unique. *
-* args = adresse non utilisée ici. *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
+* Description : Crée une copie modifiable d'un object unique. *
* *
-* Retour : Empreinte de l'élément représenté. *
+* Retour : Nouvelle instance mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_singleton_candidate_hash(PyObject *self, PyObject *args)
+static GSingletonCandidate *py_singleton_candidate_dup_wrapper(const GSingletonCandidate *candidate)
{
- PyObject *result; /* Emplacement à retourner */
- GSingletonCandidate *candidate; /* Mécanismes natifs */
- guint hash; /* Valeur d'empreitne */
+ GSingletonCandidate *result; /* Instance à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyret; /* Bilan de consultation */
+ PyObject *state; /* Validation du mode */
-#define SINGLETON_CANDIDATE_HASH_METHOD PYTHON_METHOD_DEF \
-( \
- hash, "$self", \
- METH_NOARGS, py_singleton_candidate, \
- "Compute the hash value of the singleton candidate.\n" \
- "\n" \
- "The method relies on the interface core to include in the" \
- " process the optional embedded instances which may become" \
- " singletons.\n" \
- "\n" \
- "The result is an integer value.\n" \
- "\n" \
- "Even if the Python *hash()* method, relying on the" \
- " pychrysalide.glibext.SingletonCandidate.__hash__()" \
- " implementation, provides values up to 64 bits, the final" \
- " hashes processed by the native GLib hash methods are" \
- " limited to 32 bits values." \
+#define SINGLETON_CANDIDATE_DUP_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _dup, "$self", \
+ METH_NOARGS, \
+ "Abstract method used to create a copy of the object. This" \
+ " has to be able to get modified (ie. its" \
+ " pychrysalide.glibext.SingletonCandidate.read_only status" \
+ " has to be *False*).\n" \
+ "\n" \
+ "The result has to be a new intance of type(self).\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the type of the" \
+ " return value is different from the type of self.\n" \
+ "\n" \
+ "A *ValueError* exception is raised of the return object" \
+ " is in read-only mode." \
)
- candidate = G_SINGLETON_CANDIDATE(pygobject_get(self));
+ result = false;
- hash = g_singleton_candidate_hash(candidate);
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(candidate));
+
+ pyret = run_python_method(pyobj, "_dup", NULL);
+
+ if (pyret != NULL)
+ {
+ if (Py_TYPE(pyret) != Py_TYPE(pyobj))
+ PyErr_SetString(PyExc_TypeError, _("the result type is different from the source type"));
+
+ else
+ {
+ state = py_singleton_candidate_is_read_only(pyret, NULL);
+
+ if (state != NULL)
+ {
+ if (state != Py_False)
+ PyErr_SetString(PyExc_ValueError, _("the result type can not be in read-only mode"));
+
+ Py_DECREF(state);
+
+ }
- result = PyLong_FromUnsignedLong(hash);
+ }
+
+ }
+
+ Py_XDECREF(pyret);
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
return result;
@@ -473,48 +490,51 @@ static PyObject *py_singleton_candidate_hash(PyObject *self, PyObject *args)
/******************************************************************************
* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
+* Paramètres : self = objet manipulé ici. *
+* args = adresse non utilisée ici. *
* *
-* Description : Fournit une liste de candidats embarqués par un candidat. *
+* Description : Crée une copie modifiable d'un object unique. *
* *
-* Retour : Liste de candidats internes, vide si aucun. *
+* Retour : Nouvelle instance mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_singleton_candidate_get_inner_instances(PyObject *self, void *closure)
+static PyObject *py_singleton_candidate_dup(PyObject *self, PyObject *args)
{
- PyObject *result; /* Valeur à retourner */
+ PyObject *result; /* Emplacement à retourner */
GSingletonCandidate *candidate; /* Mécanismes natifs */
- size_t count; /* Quantité d'objets internes */
- GSingletonCandidate **instances; /* Liste des embarqués */
- size_t i; /* Boucle de parcours */
+ GSingletonCandidate *copy; /* Copie des mécanismes natifs */
-#define SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- inner_instances, py_singleton_candidate, \
- "List of optional internal singleton candidate instances.\n" \
- "\n" \
- "The result has to be a tuple containing zero or more" \
- " pychrysalide.glibext.SingletonCandidate instances." \
+#define SINGLETON_CANDIDATE_DUP_METHOD PYTHON_METHOD_DEF \
+( \
+ dup, "$self", \
+ METH_NOARGS, py_singleton_candidate, \
+ "Create a copy of the object. This has to be able to get" \
+ " modified (ie. its" \
+ " pychrysalide.glibext.SingletonCandidate.read_only status" \
+ " has to be *False*).\n" \
+ "\n" \
+ "The result has to be a new intance of type(self)." \
)
candidate = G_SINGLETON_CANDIDATE(pygobject_get(self));
- instances = g_singleton_candidate_list_inner_instances(candidate, &count);
+ copy = g_singleton_candidate_dup(candidate);
- result = PyTuple_New(count);
+ if (copy == NULL)
+ result = NULL;
- for (i = 0; i < count; i++)
+ else
{
- PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(instances[i])));
- g_object_unref(G_OBJECT(instances[i]));
+ result = pygobject_new(G_OBJECT(candidate));
+
+ unref_object(copy);
+
}
- if (instances != NULL)
- free(instances);
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
return result;
@@ -523,50 +543,39 @@ static PyObject *py_singleton_candidate_get_inner_instances(PyObject *self, void
/******************************************************************************
* *
-* Paramètres : a = premier object Python à consulter. *
-* b = second object Python à consulter. *
-* op = type de comparaison menée. *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
* *
-* Description : Effectue une comparaison avec un objet 'SingletonCandidate'. *
+* Description : Indique si le candidat est figé. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : True si le contenu du candidat ne peut plus être modifié. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_singleton_candidate_richcompare(PyObject *a, PyObject *b, int op)
+static PyObject *py_singleton_candidate_is_read_only(PyObject *self, void *closure)
{
- PyObject *result; /* Bilan à retourner */
- int ret; /* Bilan de lecture des args. */
- GSingletonCandidate *cand_a; /* Premier élément à traiter */
- GSingletonCandidate *cand_b; /* Second élément à traiter */
- gboolean status; /* Résultat d'une comparaison */
-
- if (op != Py_EQ)
- {
- result = Py_NotImplemented;
- goto cmp_done;
- }
-
- ret = PyObject_IsInstance(b, (PyObject *)get_python_singleton_candidate_type());
- if (!ret)
- {
- result = Py_NotImplemented;
- goto cmp_done;
- }
-
- cand_a = G_SINGLETON_CANDIDATE(pygobject_get(a));
- cand_b = G_SINGLETON_CANDIDATE(pygobject_get(b));
+ PyObject *result; /* Valeur à retourner */
+ GSingletonCandidate *candidate; /* Mécanismes natifs */
+ bool state; /* Etat de l'objet courant */
- status = g_singleton_candidate_is_equal(cand_a, cand_b);
+#define SINGLETON_CANDIDATE_READ_ONLY_ATTRIB PYTHON_IS_DEF_FULL \
+( \
+ read_only, py_singleton_candidate, \
+ "Boolean state of the object: *True* if all its properties are" \
+ " frozen, *False* if the object can be modified." \
+)
- result = (status ? Py_True : Py_False);
+ candidate = G_SINGLETON_CANDIDATE(pygobject_get(self));
- cmp_done:
+ state = g_singleton_candidate_is_read_only(candidate);
+ result = state ? Py_True : Py_False;
Py_INCREF(result);
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
return result;
}
@@ -589,14 +598,15 @@ PyTypeObject *get_python_singleton_candidate_type(void)
static PyMethodDef py_singleton_candidate_methods[] = {
SINGLETON_CANDIDATE_LIST_INNER_INSTANCES_WRAPPER,
SINGLETON_CANDIDATE_UPDATE_INNER_INSTANCES_WRAPPER,
- SINGLETON_CANDIDATE_HASH_WRAPPER,
- SINGLETON_CANDIDATE_EQ_WRAPPER,
- SINGLETON_CANDIDATE_HASH_METHOD,
+ SINGLETON_CANDIDATE_MARK_AS_READ_ONLY_WRAPPER,
+ SINGLETON_CANDIDATE_IS_READ_ONLY_WRAPPER,
+ SINGLETON_CANDIDATE_DUP_WRAPPER,
+ SINGLETON_CANDIDATE_DUP_METHOD,
{ NULL }
};
static PyGetSetDef py_singleton_candidate_getseters[] = {
- SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB,
+ SINGLETON_CANDIDATE_READ_ONLY_ATTRIB,
{ NULL }
};
@@ -611,8 +621,6 @@ PyTypeObject *get_python_singleton_candidate_type(void)
.tp_doc = SINGLETON_CANDIDATE_DOC,
- .tp_richcompare = py_singleton_candidate_richcompare,
-
.tp_methods = py_singleton_candidate_methods,
.tp_getset = py_singleton_candidate_getseters
diff --git a/plugins/pychrysalide/analysis/storage/storage.c b/plugins/pychrysalide/glibext/storage.c
index c54fe0f..f2962bf 100644
--- a/plugins/pychrysalide/analysis/storage/storage.c
+++ b/plugins/pychrysalide/glibext/storage.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * storage.c - équivalent Python du fichier "analysis/storage/storage.c"
+ * storage.c - équivalent Python du fichier "glibext/storage.c"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,25 +25,23 @@
#include "storage.h"
+#include <assert.h>
#include <pygobject.h>
-#include <analysis/storage/storage-int.h>
-#include <plugins/dt.h>
+#include <glibext/storage-int.h>
#include "serialize.h"
-#include "../../access.h"
-#include "../../helpers.h"
-#include "../../common/packed.h"
+#include "../access.h"
+#include "../helpers.h"
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_object_storage_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(object_storage, G_TYPE_OBJECT_STORAGE);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_object_storage_init(PyObject *, PyObject *, PyObject *);
@@ -68,9 +66,6 @@ static PyObject *py_object_storage_unpack_object(PyObject *, PyObject *);
/* Sauvegarde un object sous forme de données rassemblées. */
static PyObject *py_object_storage_store_object(PyObject *, PyObject *);
-/* Sauvegarde un object interne sous forme de données. */
-static PyObject *py_object_storage_pack_object(PyObject *, PyObject *);
-
/* ---------------------------------------------------------------------------------- */
@@ -80,66 +75,6 @@ static PyObject *py_object_storage_pack_object(PyObject *, PyObject *);
/******************************************************************************
* *
-* 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_object_storage_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_object_storage_type();
-
- if (type == base)
- goto simple_way;
-
- /* Mise en place d'un type dédié */
-
- first_time = (g_type_from_name(type->tp_name) == 0);
-
- gtype = build_dynamic_type(G_TYPE_OBJECT_STORAGE, type->tp_name, NULL, 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() */
-
- simple_way:
-
- result = PyType_GenericNew(type, args, kwds);
-
- exit:
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : self = objet à initialiser (théoriquement). *
* args = arguments fournis à l'appel. *
* kwds = arguments de type key=val fournis. *
@@ -154,7 +89,9 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj
static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- const char *hash; /* Empreinte de contenu */
+ const char *type; /* Type global de conservation */
+ unsigned char version; /* Version de ce type */
+ const char *uid; /* Identifiant de distinction */
int ret; /* Bilan de lecture des args. */
GObjectStorage *storage; /* Mécanismes natifs */
@@ -164,14 +101,15 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
- " ObjectStorage(hash)" \
+ " ObjectStorage(type, version uid)" \
"\n" \
- "Where *hash* should a string built from the checksum of the" \
- " relative binary content linked to the storage.pychrysalide."
+ "Where *type* is a short string describing the storage kind," \
+ " *version* provides a version control for this type and *uid* is" \
+ " an arbitrary unique identifier used for creating temporary files."
/* Récupération des paramètres */
- ret = PyArg_ParseTuple(args, "s", &hash);
+ ret = PyArg_ParseTuple(args, "sbs", &type, &version, &uid);
if (!ret) return -1;
/* Initialisation d'un objet GLib */
@@ -183,7 +121,8 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
storage = G_OBJECT_STORAGE(pygobject_get(self));
- storage->hash = strdup(hash);
+ if (!g_object_storage_create(storage, type, version, uid))
+ return -1;
return 0;
@@ -212,27 +151,27 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
static PyObject *py_object_storage_load(PyObject *self, PyObject *args)
{
PyObject *result; /* Emplacement à retourner */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
+ const char *filename; /* Fichier de source à traiter */
int ret; /* Bilan de lecture des args. */
GObjectStorage *storage; /* Mécanismes natifs */
-#define OBJECT_STORAGE_LOAD_METHOD PYTHON_METHOD_DEF \
-( \
- load, "pbuf, /", \
- METH_STATIC | METH_VARARGS, py_object_storage, \
- "Construct a new storage from a buffer.\n" \
- "\n" \
- "The *pbuf* has to be an instance of type" \
- " pychrysalide.common.PackedBuffer.\n" \
- "\n" \
- "The result is a new pychrysalide.analysis.storage.ObjectStorage" \
- " object on success, *None* otherwise." \
+#define OBJECT_STORAGE_LOAD_METHOD PYTHON_METHOD_DEF \
+( \
+ load, "filename, /", \
+ METH_STATIC | METH_VARARGS, py_object_storage, \
+ "Construct a new storage from a filename.\n" \
+ "\n" \
+ "The *filename* argument points to the source file to" \
+ " read.\n" \
+ "\n" \
+ "The result is a new pychrysalide.glibext.ObjectStorage" \
+ " object on success, *None* otherwise." \
)
- ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "s", &filename);
if (!ret) return NULL;
- storage = g_object_storage_load(pbuf);
+ storage = g_object_storage_load(filename);
if (storage == NULL)
{
@@ -242,7 +181,7 @@ static PyObject *py_object_storage_load(PyObject *self, PyObject *args)
else
{
result = pygobject_new(G_OBJECT(storage));
- g_object_unref(G_OBJECT(storage));
+ unref_object(storage);
}
return result;
@@ -266,29 +205,29 @@ static PyObject *py_object_storage_load(PyObject *self, PyObject *args)
static PyObject *py_object_storage_store(PyObject *self, PyObject *args)
{
PyObject *result; /* Emplacement à retourner */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
+ const char *filename; /* Fichier de destination */
int ret; /* Bilan de lecture des args. */
GObjectStorage *storage; /* Mécanismes natifs */
bool status; /* Bilan de l'opération */
#define OBJECT_STORAGE_STORE_METHOD PYTHON_METHOD_DEF \
( \
- store, "$self, pbuf, /", \
+ store, "$self, filename, /", \
METH_VARARGS, py_object_storage, \
- "Save a storage into a buffer.\n" \
+ "Save a storage into a file.\n" \
"\n" \
- "The *pbuf* has to be an instance of type" \
- " pychrysalide.common.PackedBuffer.\n" \
+ "The *filename* argument points to the destination" \
+ " file to write.\n" \
"\n" \
"The result is *True* on success, *False* otherwise." \
)
- ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "s", &filename);
if (!ret) return NULL;
storage = G_OBJECT_STORAGE(pygobject_get(self));
- status = g_object_storage_store(storage, pbuf);
+ status = g_object_storage_store(storage, filename);
result = status ? Py_True : Py_False;
Py_INCREF(result);
@@ -331,7 +270,7 @@ static PyObject *py_object_storage_load_object(PyObject *self, PyObject *args)
" the data to unserialize.\n" \
"\n" \
"The result is a pychrysalide.analysis.storage.SerializableObject" \
- " instancet in case of success, or None in case of failure." \
+ " instancet in case of success, or *None* in case of failure." \
)
ret = PyArg_ParseTuple(args, "sK", &name, &pos);
@@ -370,31 +309,34 @@ static PyObject *py_object_storage_load_object(PyObject *self, PyObject *args)
static PyObject *py_object_storage_unpack_object(PyObject *self, PyObject *args)
{
PyObject *result; /* Bilan à retourner */
+ int fd; /* Flux de fonnées courant */
const char *name; /* Désignation de groupe */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
int ret; /* Bilan de lecture des args. */
GObjectStorage *storage; /* Mécanismes natifs */
GSerializableObject *object; /* Objet reconstruit ou NULL */
#define OBJECT_STORAGE_UNPACK_OBJECT_METHOD PYTHON_METHOD_DEF \
( \
- unpack_object, "$self, name, pbuf, /", \
+ unpack_object, "$self, fd, name, /", \
METH_VARARGS, py_object_storage, \
- "Load an object from a buffer with a location pointing to data.\n" \
+ "Load an object from a reference to serialized data.\n" \
"\n" \
- "The *name* is a string label for the group of target objects and" \
- " *pbuf* has to be a pychrysalide.common.PackedBuffer instance.\n" \
+ "The *fd* argument is a file descriptor pointing to the data" \
+ " stream for a current object being restored. A reference to" \
+ " another object belonging to a group pointed by the string *name*" \
+ " should be available at the current read position for this data" \
+ " stream.\n" \
"\n" \
"The result is a pychrysalide.analysis.storage.SerializableObject" \
- " instancet in case of success, or None in case of failure." \
+ " instancet in case of success, or *None* in case of failure." \
)
- ret = PyArg_ParseTuple(args, "sO&", &name, convert_to_packed_buffer, &pbuf);
+ ret = PyArg_ParseTuple(args, "is", &fd, &name);
if (!ret) return NULL;
storage = G_OBJECT_STORAGE(pygobject_get(self));
- object = g_object_storage_unpack_object(storage, name, pbuf);
+ object = g_object_storage_unpack_object(storage, fd, name);
if (object != NULL)
result = pygobject_new(G_OBJECT(object));
@@ -443,7 +385,7 @@ static PyObject *py_object_storage_store_object(PyObject *self, PyObject *args)
" pychrysalide.analysis.storage.SerializableObject instance.\n" \
"\n" \
"The result is the position of the data for stored object," \
- " provided as an integer offset, in case of success or None" \
+ " provided as an integer offset, in case of success or *None*" \
" in case of failure." \
)
@@ -469,62 +411,6 @@ static PyObject *py_object_storage_store_object(PyObject *self, PyObject *args)
/******************************************************************************
* *
-* Paramètres : self = classe représentant une mémorisation de types. *
-* args = arguments fournis à l'appel. *
-* *
-* Description : Sauvegarde un object interne sous forme de données. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args)
-{
- PyObject *result; /* Emplacement à retourner */
- const char *name; /* Désignation de groupe */
- GSerializableObject *object; /* Objet à traiter */
- packed_buffer_t *pbuf; /* Tampon de données à employer*/
- int ret; /* Bilan de lecture des args. */
- GObjectStorage *storage; /* Mécanismes natifs */
- bool status; /* Bilan de l'opération */
-
-#define OBJECT_STORAGE_PACK_OBJECT_METHOD PYTHON_METHOD_DEF \
-( \
- pack_object, "$self, name, object, pbuf/", \
- METH_VARARGS, py_object_storage, \
- "Save an object as serialized data and store the location of" \
- " the data intro a buffer.\n" \
- "\n" \
- "The *name* is a string label for the group of target objects," \
- " the processed *object* has to be a" \
- " pychrysalide.analysis.storage.SerializableObject instance" \
- " and *pbuf* is expected to be a" \
- " pychrysalide.common.PackedBuffer instance.\n" \
- "\n" \
- "The status of the operation is returned as a boolean value:" \
- " *True* for success, *False* for failure." \
-)
-
- ret = PyArg_ParseTuple(args, "sO&O&", &name, convert_to_serializable_object, &object,
- convert_to_packed_buffer, &pbuf);
- if (!ret) return NULL;
-
- storage = G_OBJECT_STORAGE(pygobject_get(self));
-
- status = g_object_storage_pack_object(storage, name, object, pbuf);
-
- result = status ? Py_True : Py_False;
- Py_INCREF(result);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : - *
* *
* Description : Fournit un accès à une définition de type à diffuser. *
@@ -543,7 +429,6 @@ PyTypeObject *get_python_object_storage_type(void)
OBJECT_STORAGE_LOAD_OBJECT_METHOD,
OBJECT_STORAGE_UNPACK_OBJECT_METHOD,
OBJECT_STORAGE_STORE_OBJECT_METHOD,
- OBJECT_STORAGE_PACK_OBJECT_METHOD,
{ NULL }
};
@@ -555,7 +440,7 @@ PyTypeObject *get_python_object_storage_type(void)
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.analysis.storage.ObjectStorage",
+ .tp_name = "pychrysalide.glibext.ObjectStorage",
.tp_basicsize = sizeof(PyGObject),
.tp_flags = Py_TPFLAGS_DEFAULT,
@@ -579,7 +464,7 @@ PyTypeObject *get_python_object_storage_type(void)
* *
* Paramètres : module = module dont la définition est à compléter. *
* *
-* Description : Prend en charge l'objet 'pychrysalide....ObjectStorage'. *
+* Description : Prend en charge l'objet 'pychrysalide.glibext.ObjectStorage'.*
* *
* Retour : Bilan de l'opération. *
* *
@@ -597,7 +482,7 @@ bool ensure_python_object_storage_is_registered(void)
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
- module = get_access_to_python_module("pychrysalide.analysis.storage");
+ module = get_access_to_python_module("pychrysalide.glibext");
dict = PyModule_GetDict(module);
diff --git a/plugins/pychrysalide/analysis/storage/storage.h b/plugins/pychrysalide/glibext/storage.h
index a0a2c18..681f99a 100644
--- a/plugins/pychrysalide/analysis/storage/storage.h
+++ b/plugins/pychrysalide/glibext/storage.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * storage.h - prototypes pour l'équivalent Python du fichier "analysis/storage/storage.h"
+ * storage.h - prototypes pour l'équivalent Python du fichier "glibext/storage.h"
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,8 +22,8 @@
*/
-#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H
-#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H
+#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H
#include <Python.h>
@@ -34,7 +34,7 @@
/* Fournit un accès à une définition de type à diffuser. */
PyTypeObject *get_python_object_storage_type(void);
-/* Prend en charge l'objet 'pychrysalide.analysis.storage.ObjectStorage'. */
+/* Prend en charge l'objet 'pychrysalide.glibext.ObjectStorage'. */
bool ensure_python_object_storage_is_registered(void);
/* Tente de convertir en conservateur d'objets. */
@@ -45,4 +45,4 @@ int convert_to_object_storage_or_none(PyObject *, void *);
-#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H */
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H */
diff --git a/plugins/pychrysalide/glibext/strbuilder.c b/plugins/pychrysalide/glibext/strbuilder.c
index 482f7df..a6de0f0 100644
--- a/plugins/pychrysalide/glibext/strbuilder.c
+++ b/plugins/pychrysalide/glibext/strbuilder.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* strbuilder.c - équivalent Python du fichier "glibext/strbuilder.c"
*
- * Copyright (C) 2021 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -37,11 +37,22 @@
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
/* Procède à l'initialisation de l'interface d'exportation. */
static void py_string_builder_interface_init(GStringBuilderInterface *, gpointer *);
/* Exporte une chaîne de caractères à partir d'un objet. */
-bool py_string_builder_to_string_wrapper(const GStringBuilder *, unsigned int, sized_binary_t *);
+static bool py_string_builder_to_string_wrapper(const GStringBuilder *, unsigned int, sized_binary_t *);
+
+
+
+/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+
+
+/* Transmet la description d'un objet définie par son parent. */
+static PyObject *py_string_builder_parent_to_string(PyObject *, PyObject *);
/* Exporte une chaîne de caractères à partir d'un objet. */
static PyObject *py_string_builder_to_string(PyObject *, PyObject *);
@@ -51,6 +62,11 @@ static PyObject *py_string_builder_str(PyObject *);
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
@@ -98,9 +114,9 @@ static void py_string_builder_interface_init(GStringBuilderInterface *iface, gpo
* *
******************************************************************************/
-bool py_string_builder_to_string_wrapper(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)
+static bool py_string_builder_to_string_wrapper(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)
{
- bool result; /* Bilan à retourner */
+ bool result; /* Bilan à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
PyObject *pyobj; /* Objet Python concerné */
PyObject *args; /* Arguments pour l'appel */
@@ -119,7 +135,10 @@ bool py_string_builder_to_string_wrapper(const GStringBuilder *builder, unsigned
"The optional *flags* argument define hints for the operation" \
" (for instance the Intel or AT&T flavor for x86 assembly).\n" \
"\n" \
- "The result has to be a string or *None* in case of error." \
+ "The result has to be a string." \
+ "\n" \
+ "A *TypeError* exception is raised if the return value is not" \
+ " a string." \
)
result = false;
@@ -128,38 +147,37 @@ bool py_string_builder_to_string_wrapper(const GStringBuilder *builder, unsigned
pyobj = pygobject_new(G_OBJECT(builder));
- if (has_python_method(pyobj, "_to_string"))
- {
- args = PyTuple_New(1);
- PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(flags));
+ args = PyTuple_New(1);
+ PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(flags));
- pyret = run_python_method(pyobj, "_to_string", args);
+ pyret = run_python_method(pyobj, "_to_string", args);
- if (pyret != NULL && pyret != Py_None)
+ if (pyret != NULL)
+ {
+ if (PyUnicode_Check(pyret))
{
- if (PyUnicode_Check(pyret))
- {
- utf8 = PyUnicode_AsUTF8AndSize(pyret, &size);
-
- if (utf8 != NULL)
- {
- assert(size >= 0);
+ utf8 = PyUnicode_AsUTF8AndSize(pyret, &size);
- add_to_sized_binary(out, utf8, size);
- result = true;
+ if (utf8 != NULL)
+ {
+ assert(size >= 0);
- }
+ add_to_sized_binary(out, utf8, size);
+ result = true;
}
}
- Py_XDECREF(pyret);
-
- Py_DECREF(args);
+ if (!result)
+ PyErr_SetString(PyExc_TypeError, _("object description has to get provided as an UTF-8 string value"));
}
+ Py_XDECREF(pyret);
+
+ Py_DECREF(args);
+
Py_DECREF(pyobj);
PyGILState_Release(gstate);
@@ -169,6 +187,108 @@ bool py_string_builder_to_string_wrapper(const GStringBuilder *builder, unsigned
}
+
+/* ---------------------------------------------------------------------------------- */
+/* CONNEXION AVEC L'API DE PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet dont l'instance se veut unique. *
+* args = adresse non utilisée ici. *
+* *
+* Description : Transmet la description d'un objet définie par son parent. *
+* *
+* Retour : Présentation de l'élément construite. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_string_builder_parent_to_string(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ unsigned int flags; /* Eventuelles indications */
+ int ret; /* Bilan de lecture des args. */
+ GStringBuilder *builder; /* Mécanismes natifs */
+ GStringBuilderInterface *iface; /* Interface utilisée */
+ GStringBuilderInterface *parent_iface; /* Interface parente */
+ sized_binary_t out; /* Description construite */
+ bool status; /* Bilan de l'opération */
+
+#define STRING_BUILDER_PARENT_TO_STRING_METHOD PYTHON_METHOD_DEF \
+( \
+ parent_to_string, "$self, /, flags=0", \
+ METH_VARARGS, py_string_builder, \
+ "Provide a string representation defined by the interface" \
+ " implementation from the object native parent.\n" \
+ "\n" \
+ "The result is a string.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the object parent does" \
+ " not implement the pychrysalide.glibext.StringBuilder" \
+ " interface." \
+ "\n" \
+ "A *RuntimeError* exception is raised if the direct parent type"\
+ " of the object has not a native implementation. For Python" \
+ " implementations, the super()._to_string() function has to be" \
+ " used instead.\n" \
+ "\n" \
+ "A *BufferError* exception is raised if the description has" \
+ " not been able to get created." \
+)
+
+ if (!check_for_native_parent(self))
+ return NULL;
+
+ flags = 0;
+
+ ret = PyArg_ParseTuple(args, "|I", &flags);
+ if (!ret) return NULL;
+
+ builder = G_STRING_BUILDER(pygobject_get(self));
+
+ iface = G_STRING_BUILDER_GET_IFACE(builder);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ if (parent_iface == NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, _("object parent does not implement the StringBuilder interface"));
+
+ result = NULL;
+
+ }
+ else
+ {
+ init_sized_binary(&out);
+
+ status = parent_iface->to_string(builder, flags, &out);
+
+ if (status)
+ result = PyUnicode_FromStringAndSize(out.data, out.size);
+
+ else
+ {
+ result = NULL;
+
+ if (PyErr_Occurred() == NULL)
+ PyErr_SetString(PyExc_BufferError, _("unable to create a description"));
+
+ }
+
+ exit_sized_binary(&out);
+
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
+ }
+
+ return result;
+
+}
+
+
/******************************************************************************
* *
* Paramètres : self = objet manipulé ici. *
@@ -176,7 +296,7 @@ bool py_string_builder_to_string_wrapper(const GStringBuilder *builder, unsigned
* *
* Description : Exporte une chaîne de caractères à partir d'un objet. *
* *
-* Retour : Présentation de l'élément construite ou None. *
+* Retour : Présentation de l'élément construite. *
* *
* Remarques : - *
* *
@@ -198,11 +318,13 @@ static PyObject *py_string_builder_to_string(PyObject *self, PyObject *args)
"Provide a string representation for the object which is used" \
" as the default implementation of the __repr__() method.\n" \
"\n" \
- "\n" \
"The optional *flags* argument define hints for the operation" \
" (for instance the Intel or AT&T flavor for x86 assembly).\n" \
"\n" \
- "The result is a string or *None* in case of error." \
+ "The result is a string.\n" \
+ "\n" \
+ "A *BufferError* exception is raised if the description has" \
+ " not been able to get created." \
)
flags = 0;
@@ -221,12 +343,17 @@ static PyObject *py_string_builder_to_string(PyObject *self, PyObject *args)
else
{
- result = Py_None;
- Py_INCREF(result);
+ result = NULL;
+
+ if (PyErr_Occurred() == NULL)
+ PyErr_SetString(PyExc_BufferError, _("unable to create a description"));
+
}
exit_sized_binary(&out);
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
return result;
}
@@ -238,13 +365,13 @@ static PyObject *py_string_builder_to_string(PyObject *self, PyObject *args)
* *
* Description : Fournit une représentation de l'objet exportable. *
* *
-* Retour : Présentation de l'élément construite ou None. *
+* Retour : Présentation de l'élément construite. *
* *
* Remarques : - *
* *
******************************************************************************/
-PyObject *py_string_builder_str(PyObject *self)
+static PyObject *py_string_builder_str(PyObject *self)
{
PyObject *result; /* Emplacement à retourner */
GStringBuilder *builder; /* Mécanismes natifs */
@@ -262,12 +389,17 @@ PyObject *py_string_builder_str(PyObject *self)
else
{
- result = Py_None;
- Py_INCREF(result);
+ result = NULL;
+
+ if (PyErr_Occurred() == NULL)
+ PyErr_SetString(PyExc_BufferError, _("unable to create a description"));
+
}
exit_sized_binary(&out);
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
return result;
}
@@ -289,6 +421,7 @@ PyTypeObject *get_python_string_builder_type(void)
{
static PyMethodDef py_string_builder_methods[] = {
STRING_BUILDER_TO_STRING_WRAPPER,
+ STRING_BUILDER_PARENT_TO_STRING_METHOD,
STRING_BUILDER_TO_STRING_METHOD,
{ NULL }
};
diff --git a/plugins/pychrysalide/glibext/strbuilder.h b/plugins/pychrysalide/glibext/strbuilder.h
index d6aae20..1881cae 100644
--- a/plugins/pychrysalide/glibext/strbuilder.h
+++ b/plugins/pychrysalide/glibext/strbuilder.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* strbuilder.h - prototypes pour l'équivalent Python du fichier "glibext/strbuilder.h"
*
- * Copyright (C) 2021 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
diff --git a/plugins/pychrysalide/analysis/storage/tpmem.c b/plugins/pychrysalide/glibext/tpmem.c
index ae07008..ae07008 100644
--- a/plugins/pychrysalide/analysis/storage/tpmem.c
+++ b/plugins/pychrysalide/glibext/tpmem.c
diff --git a/plugins/pychrysalide/analysis/storage/tpmem.h b/plugins/pychrysalide/glibext/tpmem.h
index 1085632..1085632 100644
--- a/plugins/pychrysalide/analysis/storage/tpmem.h
+++ b/plugins/pychrysalide/glibext/tpmem.h
diff --git a/plugins/pychrysalide/glibext/workqueue.c b/plugins/pychrysalide/glibext/workqueue.c
index d8126be..ca6c73c 100644
--- a/plugins/pychrysalide/glibext/workqueue.c
+++ b/plugins/pychrysalide/glibext/workqueue.c
@@ -94,9 +94,9 @@ static int py_work_queue_init(PyObject *self, PyObject *args, PyObject *kwds)
{
int ret; /* Bilan de lecture des args. */
-#define WORK_QUEUE_DOC \
- "WorkQueue defines a basic work aimed to get processed in a" \
- " thread setup by a pychrysalide.glibext.WorkQueue instance.\n" \
+#define WORK_QUEUE_DOC \
+ "WorkQueue creates threads in order to process" \
+ " pychrysalide.glibext.Work instances.\n" \
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
diff --git a/plugins/pychrysalide/gtkext/Makefile.am b/plugins/pychrysalide/gtkext/Makefile.am
index 2e1260f..1d91751 100644
--- a/plugins/pychrysalide/gtkext/Makefile.am
+++ b/plugins/pychrysalide/gtkext/Makefile.am
@@ -1,19 +1,23 @@
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 \
+# named.h named.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 = \
- graph/libpychrysagtkextgraph.la
-
-libpychrysagtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ panel.h panel.c \
+ module.h module.c
+
+# libpychrysagtkext_la_LIBADD = \
+# graph/libpychrysagtkextgraph.la
+
+libpychrysagtkext_la_CFLAGS = $(LIBGTK4_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
@@ -22,4 +26,4 @@ devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysagtkext_la_SOURCES:%c=)
-SUBDIRS = graph
+#SUBDIRS = graph
diff --git a/plugins/pychrysalide/gtkext/module.c b/plugins/pychrysalide/gtkext/module.c
index f8264af..fa59b2b 100644
--- a/plugins/pychrysalide/gtkext/module.c
+++ b/plugins/pychrysalide/gtkext/module.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* module.c - intégration du répertoire gtkext en tant que module
*
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -28,13 +28,13 @@
#include <assert.h>
-#include "blockdisplay.h"
-#include "bufferdisplay.h"
-#include "displaypanel.h"
-#include "dockable.h"
-#include "easygtk.h"
-#include "named.h"
-#include "graph/module.h"
+//#include "blockdisplay.h"
+//#include "bufferdisplay.h"
+//#include "displaypanel.h"
+//#include "dockable.h"
+//#include "named.h"
+#include "panel.h"
+//#include "graph/module.h"
#include "../helpers.h"
@@ -71,7 +71,7 @@ bool add_gtkext_module(PyObject *super)
result = (module != NULL);
- if (result) result = add_gtkext_graph_module(module);
+ //if (result) result = add_gtkext_graph_module(module);
if (!result)
Py_XDECREF(module);
@@ -99,14 +99,16 @@ bool populate_gtkext_module(void)
result = true;
- if (result) result = ensure_python_block_display_is_registered();
- if (result) result = ensure_python_buffer_display_is_registered();
- if (result) result = ensure_python_display_panel_is_registered();
- if (result) result = ensure_python_dockable_is_registered();
- if (result) result = ensure_python_easygtk_is_registered();
- if (result) result = ensure_python_built_named_widget_is_registered();
+ if (result) result = ensure_python_tiled_panel_is_registered();
- if (result) result = populate_gtkext_graph_module();
+ //if (result) result = ensure_python_block_display_is_registered();
+ //if (result) result = ensure_python_buffer_display_is_registered();
+ //if (result) result = ensure_python_display_panel_is_registered();
+ //if (result) result = ensure_python_dockable_is_registered();
+ //if (result) result = ensure_python_easygtk_is_registered();
+ //if (result) result = ensure_python_built_named_widget_is_registered();
+
+ //if (result) result = populate_gtkext_graph_module();
assert(result);
diff --git a/plugins/pychrysalide/gtkext/panel.c b/plugins/pychrysalide/gtkext/panel.c
new file mode 100644
index 0000000..9f6589a
--- /dev/null
+++ b/plugins/pychrysalide/gtkext/panel.c
@@ -0,0 +1,130 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * panel.c - prototypes pour l'équivalent Python du fichier "gtkext/panel.c"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "panel.h"
+
+
+#include <pygobject.h>
+
+
+#include <gtkext/panel.h>
+
+
+#include "../access.h"
+#include "../helpers.h"
+#include "../helpers-ui.h"
+
+
+
+#define TILED_PANEL_DOC \
+ "The TiledPanel class defines a panel widget for the framework main" \
+ " window."
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_tiled_panel_type(void)
+{
+ static PyMethodDef py_tiled_panel_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_tiled_panel_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_tiled_panel_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.gtkext.TiledPanel",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = TILED_PANEL_DOC,
+
+ .tp_methods = py_tiled_panel_methods,
+ .tp_getset = py_tiled_panel_getseters,
+
+ };
+
+ static PyTypeObject *result = NULL;
+
+ if (result == NULL)
+ result = define_python_dynamic_type(&py_tiled_panel_type);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.gtkext.TiledPanel'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_tiled_panel_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'TiledPanel' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_tiled_panel_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.gtkext");
+
+ dict = PyModule_GetDict(module);
+
+ if (!ensure_gtk_widget_is_registered())
+ return false;
+
+ if (!register_class_for_pygobject(dict, GTK_TYPE_TILED_PANEL, type))
+ return false;
+
+ }
+
+ return true;
+
+}
diff --git a/plugins/pychrysalide/gtkext/panel.h b/plugins/pychrysalide/gtkext/panel.h
new file mode 100644
index 0000000..c5cbe86
--- /dev/null
+++ b/plugins/pychrysalide/gtkext/panel.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * panel.h - prototypes pour l'équivalent Python du fichier "gtkext/panel.h"
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_GTKEXT_PANEL_H
+#define _PLUGINS_PYCHRYSALIDE_GTKEXT_PANEL_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_tiled_panel_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.gtkext.TiledPanel'. */
+bool ensure_python_tiled_panel_is_registered(void);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GTKEXT_PANEL_H */
diff --git a/plugins/pychrysalide/helpers-ui.c b/plugins/pychrysalide/helpers-ui.c
new file mode 100644
index 0000000..982e676
--- /dev/null
+++ b/plugins/pychrysalide/helpers-ui.c
@@ -0,0 +1,141 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * helpers-ui.c - simplification des interactions UI de base avec Python
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "helpers-ui.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+#include <gtk/gtk.h>
+
+
+#include "bindings.h"
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONFORTS CIBLANT PYGOBJECT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Assure une prise en charge de l'objet Gtk.WIdget. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_gtk_widget_is_registered(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *gtk_mod; /* Module Python Gtk */
+ PyObject *widget_type; /* Module "GtkWidget" */
+
+ /**
+ * Afin d'éviter le message d'avertissement suivant, la version attendue
+ * est demandée :
+ *
+ * PyGIWarning: Gtk was imported without specifying a version first.
+ * Use gi.require_version('Gtk', '4.0') before import to ensure that the right version gets loaded.
+ *
+ */
+ result = import_namespace_from_gi_repository("Gtk", "4.0");
+
+ if (result)
+ {
+ gtk_mod = PyImport_ImportModule("gi.repository.Gtk");
+ assert(gtk_mod != NULL);
+
+ widget_type = PyObject_GetAttrString(gtk_mod, "Widget");
+
+ result = (widget_type != NULL);
+
+ Py_DECREF(gtk_mod);
+ Py_XDECREF(widget_type);
+
+ }
+
+ 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 instance de composant GTK. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_gtk_widget(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ PyObject *gtk_mod; /* Module Python Gtk */
+ PyObject *widget_type; /* Module "GtkWidget" */
+ int ret; /* Bilan d'une conversion */
+
+ result = 0;
+
+ gtk_mod = PyImport_ImportModule("gi.repository.Gtk");
+
+ if (gtk_mod == NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module");
+ goto done;
+ }
+
+ widget_type = PyObject_GetAttrString(gtk_mod, "Widget");
+
+ Py_DECREF(gtk_mod);
+
+ ret = PyObject_TypeCheck(arg, (PyTypeObject *)widget_type);
+
+ Py_DECREF(widget_type);
+
+ if (!ret)
+ {
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget");
+ goto done;
+ }
+
+ *((GtkWidget **)dst) = GTK_WIDGET(pygobject_get(arg));
+
+ result = 1;
+
+ done:
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/helpers-ui.h b/plugins/pychrysalide/helpers-ui.h
new file mode 100644
index 0000000..b575905
--- /dev/null
+++ b/plugins/pychrysalide/helpers-ui.h
@@ -0,0 +1,44 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * helpers-ui.h - prototypes pour la simplification des interactions UI de base avec Python
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYCHRYSALIDE_HELPERS_UI_H
+#define _PLUGINS_PYCHRYSALIDE_HELPERS_UI_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* --------------------------- CONFORTS CIBLANT PYGOBJECT --------------------------- */
+
+
+/* Assure une prise en charge de l'objet Gtk.WIdget. */
+bool ensure_gtk_widget_is_registered(void);
+
+/* Tente de convertir en instance de composant GTK. */
+int convert_to_gtk_widget(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_HELPERS_UI_H */
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index c31d9f1..4ff768c 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* helpers.c - simplification des interactions de base avec Python
*
- * Copyright (C) 2018-2024 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -32,9 +32,6 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#ifdef INCLUDE_GTK_SUPPORT
-# include <gtk/gtk.h>
-#endif
#include <i18n.h>
@@ -1122,6 +1119,60 @@ int forward_pygobjet_init(PyObject *self)
/******************************************************************************
* *
+* Paramètres : type = type Python à ausculter. *
+* *
+* Description : Détermine si un type Python est implémenté en C ou non. *
+* *
+* Retour : Bilan de l'analyse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool pytype_has_native_implementation(const PyTypeObject *type)
+{
+ bool result; /* Bilan à retourner */
+ GType gtype; /* Type associé à la classe */
+
+ static GQuark pygobject_custom_key = 0; /* Clef d'accès direct */
+
+ /**
+ * Dans les sources de PyGObject, la fonction pyg_type_register() de
+ * gi/gimodule.c, appelée depuis gi/types.py, contient la bribe de code
+ * suivante :
+ *
+ * // Mark this GType as a custom python type
+ * g_type_set_qdata(instance_type, pygobject_custom_key,
+ * GINT_TO_POINTER (1));
+ *
+ * La fonction pyi_object_register_types() de gi/pygobject-object.c indique
+ * la clef associée au Quark :
+ *
+ * pygobject_custom_key = g_quark_from_static_string("PyGObject::custom");
+ *
+ * Enfin, une fonction inspirante est codée dans le fichier gi/pygi-type.c :
+ *
+ * gboolean pyg_gtype_is_custom(GType gtype)
+ * {
+ * return g_type_get_qdata (gtype, pygobject_custom_key) != NULL;
+ * }
+ *
+ */
+
+ if (pygobject_custom_key == 0)
+ pygobject_custom_key = g_quark_from_static_string("PyGObject::custom");
+
+ gtype = pyg_type_from_object((PyObject *)type);
+
+ result = (g_type_get_qdata(gtype, pygobject_custom_key) == NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : arg = argument quelconque à tenter de convertir. *
* dst = destination des valeurs récupérées en cas de succès. *
* *
@@ -1206,122 +1257,6 @@ int convert_to_gobject(PyObject *arg, void *dst)
#if 0
-#ifdef INCLUDE_GTK_SUPPORT
-
-
-/******************************************************************************
-* *
-* 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 de composant GTK. *
-* *
-* Retour : Bilan de l'opération, voire indications supplémentaires. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-int convert_to_gtk_widget(PyObject *arg, void *dst)
-{
- int result; /* Bilan à retourner */
- PyObject *gtk_mod; /* Module Python Gtk */
- PyObject *widget_type; /* Module "GtkWidget" */
- int ret; /* Bilan d'une conversion */
-
- result = 0;
-
- gtk_mod = PyImport_ImportModule("gi.repository.Gtk");
-
- if (gtk_mod == NULL)
- {
- PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module");
- goto done;
- }
-
- widget_type = PyObject_GetAttrString(gtk_mod, "Widget");
-
- Py_DECREF(gtk_mod);
-
- ret = PyObject_TypeCheck(arg, (PyTypeObject *)widget_type);
-
- Py_DECREF(widget_type);
-
- if (!ret)
- {
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget");
- goto done;
- }
-
- *((GtkWidget **)dst) = GTK_WIDGET(pygobject_get(arg));
-
- result = 1;
-
- done:
-
- 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 instance de conteneur GTK. *
-* *
-* Retour : Bilan de l'opération, voire indications supplémentaires. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-int convert_to_gtk_container(PyObject *arg, void *dst)
-{
- int result; /* Bilan à retourner */
- PyObject *gtk_mod; /* Module Python Gtk */
- PyObject *container_type; /* Module "GtkContainer" */
- int ret; /* Bilan d'une conversion */
-
- result = 0;
-
- gtk_mod = PyImport_ImportModule("gi.repository.Gtk");
-
- if (gtk_mod == NULL)
- {
- PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module");
- goto done;
- }
-
- container_type = PyObject_GetAttrString(gtk_mod, "Container");
-
- Py_DECREF(gtk_mod);
-
- ret = PyObject_TypeCheck(arg, (PyTypeObject *)container_type);
-
- Py_DECREF(container_type);
-
- if (!ret)
- {
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK container");
- goto done;
- }
-
- *((GtkContainer **)dst) = GTK_CONTAINER(pygobject_get(arg));
-
- result = 1;
-
- done:
-
- return result;
-
-}
-
-
-#endif
-
-
/******************************************************************************
* *
* Paramètres : color = couleur dans sa définition native à copier. *
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index 2808bf1..f1c6337 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* helpers.h - prototypes pour la simplification des interactions de base avec Python
*
- * Copyright (C) 2018-2024 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -34,6 +34,9 @@
#endif
+#include <i18n.h>
+
+
/* ---------------------- ACCELERATEURS POUR PYTHON UNIQUEMENT ---------------------- */
@@ -129,7 +132,7 @@ bool register_python_module_object(PyObject *, PyTypeObject *);
PYTHON_GETSET_DEF("is_" #name, base ## _is_ ## name, NULL, ATTRIB_RO doc, NULL)
#define PYTHON_HAS_DEF_FULL(name, base, doc) \
- PYTHON_GETSET_DEF(#name, base ## _has_ ## name, NULL, ATTRIB_RO doc, NULL)
+ PYTHON_GETSET_DEF("has_" #name, base ## _has_ ## name, NULL, ATTRIB_RO doc, NULL)
#define PYTHON_RAWGET_DEF_FULL(name, base, doc) \
PYTHON_GETSET_DEF(#name, base ## _ ## name, NULL, ATTRIB_RO doc, NULL)
@@ -225,6 +228,41 @@ PyTypeObject *define_python_dynamic_type(const PyTypeObject *);
/**
+ * Prise en compte d'éventuelles exceptions levées dans les implémentations.
+ *
+ * Par exemple :
+ * - du code Python exécute une fonction implémentée en C ;
+ * - cette dernière fait appel à un Wrapper C qui sollicite du code
+ * d'implémentation Python.
+ *
+ * Cette seconde étape peut lever une exception (impletation manquante ou
+ * implémentation levant une exception.
+ *
+ * Les codes C des étapes 1 et 2 ne dispose pas de mécanismes pour transmettre
+ * le détail des éventuelles exceptions, mais Python le mémorise.
+ */
+
+#define UPDATE_RESULT_IF_RAISED_EXCEPTION(val) \
+ do \
+ { \
+ if (PyErr_Occurred() != NULL) \
+ result = val; \
+ } \
+ while (0)
+
+#define CLEAN_RESULT_IF_RAISED_EXCEPTION(val) \
+ do \
+ { \
+ if (PyErr_Occurred() != NULL) \
+ { \
+ Py_XDECREF(result); \
+ result = NULL; \
+ } \
+ } \
+ while (0)
+
+
+/**
* pygobject_new() prend en compte les références flottantes au moment de la
* construction d'un objet Python.
*
@@ -250,11 +288,23 @@ bool register_class_for_pygobject(PyObject *, GType, PyTypeObject *);
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 *);
+bool register_class_for_dynamic_pygobject(GType, PyTypeObject *); // REMME
/* Fait suivre à la partie GObject une initialisation nouvelle. */
int forward_pygobjet_init(PyObject *);
+/* Détermine si un type Python est implémenté en C ou non. */
+bool pytype_has_native_implementation(const PyTypeObject *);
+
+#define check_for_native_parent(obj) \
+ ({ \
+ bool __result; \
+ __result = pytype_has_native_implementation((obj)->ob_type->tp_base); \
+ if (!__result) \
+ PyErr_SetString(PyExc_RuntimeError, _("object parent is not a native type")); \
+ __result; \
+ })
+
/* Tente de convertir en valeur GType. */
int convert_to_gtype(PyObject *, void *);
@@ -263,17 +313,6 @@ int convert_to_gobject(PyObject *, void *);
#if 0
-#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
diff --git a/plugins/pynb/Makefile.am b/plugins/pynb/Makefile.am
new file mode 100644
index 0000000..50e549f
--- /dev/null
+++ b/plugins/pynb/Makefile.am
@@ -0,0 +1,77 @@
+
+BUILT_SOURCES = resources.h resources.c
+
+
+lib_LTLIBRARIES = libpynbui.la
+
+libdir = $(pluginslibdir)
+
+
+# if BUILD_PYTHON3_BINDINGS
+
+# PYTHON3_LIBADD = python/libpynbpython.la
+
+# if BUILD_DISCARD_LOCAL
+
+# PYTHON3_LDFLAGS = -Wl,-rpath,$(pluginslibdir) \
+# -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so
+
+# else
+
+# PYTHON3_LDFLAGS = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs \
+# -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so
+
+# endif
+
+# PYTHON3_SUBDIRS = python
+
+# endif
+
+
+libpynbui_la_SOURCES = \
+ core-ui-int.h \
+ core-ui.h core-ui.c \
+ panel-int.h \
+ panel.h panel.c \
+ params-int.h \
+ params.h params.c \
+ prefs-int.h \
+ prefs.h prefs.c \
+ resources.h resources.c
+
+libpynbui_la_LIBADD = \
+ $(PYTHON3_LIBADD)
+
+libpynbui_la_CFLAGS = $(LIBGTK4_CFLAGS)
+
+libpynbui_la_LDFLAGS = \
+ $(LIBGTK4_LIBS) $(PYTHON3_LDFLAGS)
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libpynbui_la_SOURCES:%c=)
+
+
+RES_FILES = \
+ panel.ui \
+ params.ui \
+ prefs.ui \
+ data/images/pynb-symbolic.svg
+
+
+resources.c: gresource.xml $(RES_FILES)
+ glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name plugins_pynb gresource.xml
+
+resources.h: gresource.xml
+ glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name plugins_pynb gresource.xml
+
+
+CLEANFILES = resources.h resources.c
+
+EXTRA_DIST = gresource.xml $(RES_FILES)
+
+
+AM_CPPFLAGS = -I$(top_srcdir)/src $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+
+SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/pynb/core-ui-int.h b/plugins/pynb/core-ui-int.h
new file mode 100644
index 0000000..caf5713
--- /dev/null
+++ b/plugins/pynb/core-ui-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-ui-int.h - prototypes internes pour le plugin présentant des notes avec code Python
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYNB_CORE_UI_INT_H
+#define _PLUGINS_PYNB_CORE_UI_INT_H
+
+
+#include <plugins/native-int.h>
+
+
+#include "core-ui.h"
+
+
+
+/* Greffon natif pour la présentation de notes avec texte et code Python (instance) */
+struct _GPythonNotebookPluginUI
+{
+ GNativePlugin parent; /* A laisser en premier */
+
+};
+
+
+/* Greffon natif pour la présentation de notes avec texte et code Python (classe) */
+struct _GPythonNotebookPluginUIClass
+{
+ GNativePluginClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un module pour un module pour présentation. */
+bool g_python_notebook_plugin_ui_create(GPythonNotebookPluginUI *, GModule *);
+
+
+
+#endif /* _PLUGINS_PYNB_CORE_UI_INT_H */
diff --git a/plugins/pynb/core-ui.c b/plugins/pynb/core-ui.c
new file mode 100644
index 0000000..dd49a83
--- /dev/null
+++ b/plugins/pynb/core-ui.c
@@ -0,0 +1,363 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-ui.c - présentation de notes sous forme de texte et de code Python
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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-ui.h"
+
+
+#include <i18n.h>
+#include <gui/core/panels.h>
+#include <plugins/self.h>
+#include <plugins/tweakable-int.h>
+
+
+#include "core-ui-int.h"
+#include "panel.h"
+#include "params.h"
+#include "prefs.h"
+
+
+
+/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */
+
+
+/* Initialise la classe des recherches et identifications. */
+static void g_python_notebook_plugin_ui_class_init(GPythonNotebookPluginUIClass *);
+
+/* Procède à l'initialisation de l'interface d'intervention. */
+static void g_python_notebook_plugin_ui_tweakable_plugin_interface_init(GTweakablePluginInterface *);
+
+/* Initialise une instance de recherches et identifications. */
+static void g_python_notebook_plugin_ui_init(GPythonNotebookPluginUI *);
+
+/* Supprime toutes les références externes. */
+static void g_python_notebook_plugin_ui_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_python_notebook_plugin_ui_finalize(GObject *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte de l'activation du greffon. */
+static bool g_python_notebook_plugin_ui_enable(GPythonNotebookPluginUI *);
+
+/* Prend acte de la désactivation du greffon. */
+static bool g_python_notebook_plugin_ui_disable(GPythonNotebookPluginUI *);
+
+
+
+/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */
+
+
+/* Fournit une liste de sections de configuration. */
+static tweak_info_t *g_python_notebook_plugin_ui_get_tweak_info(const GTweakablePlugin *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* COMPOSITION DE NOUVEAU GREFFON NATIF */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une présentation de notes texte et code Python. */
+G_DEFINE_TYPE_WITH_CODE(GPythonNotebookPluginUI, g_python_notebook_plugin_ui, G_TYPE_NATIVE_PLUGIN,
+ G_IMPLEMENT_INTERFACE(G_TYPE_TWEAKABLE_PLUGIN, g_python_notebook_plugin_ui_tweakable_plugin_interface_init));
+
+
+NATIVE_PLUGIN_ENTRYPOINT(g_python_notebook_plugin_ui_new);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à initialiser. *
+* *
+* Description : Initialise la classe des recherches et identifications. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_python_notebook_plugin_ui_class_init(GPythonNotebookPluginUIClass *class)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GPluginModuleClass *plugin; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = g_python_notebook_plugin_ui_dispose;
+ object->finalize = g_python_notebook_plugin_ui_finalize;
+
+ plugin = G_PLUGIN_MODULE_CLASS(class);
+
+ plugin->enable = (pg_management_fc)g_python_notebook_plugin_ui_enable;
+ plugin->disable = (pg_management_fc)g_python_notebook_plugin_ui_disable;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface d'intervention. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_python_notebook_plugin_ui_tweakable_plugin_interface_init(GTweakablePluginInterface *iface)
+{
+ iface->get_info = g_python_notebook_plugin_ui_get_tweak_info;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = instance à initialiser. *
+* *
+* Description : Initialise une instance de recherches et identifications. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_python_notebook_plugin_ui_init(GPythonNotebookPluginUI *plugin)
+{
+ STORE_PLUGIN_ABI(plugin);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_python_notebook_plugin_ui_dispose(GObject *object)
+{
+ G_OBJECT_CLASS(g_python_notebook_plugin_ui_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_python_notebook_plugin_ui_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(g_python_notebook_plugin_ui_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = extension vue du système. *
+* *
+* Description : Crée un module pour présentation de notes. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : Le transfert de propriétée du module est total. *
+* *
+******************************************************************************/
+
+GPluginModule *g_python_notebook_plugin_ui_new(GModule *module)
+{
+ GPythonNotebookPluginUI *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_PYTHON_NOTEBOOK_PLUGIN_UI, NULL);
+
+ if (!g_python_notebook_plugin_ui_create(result, module))
+ g_clear_object(&result);
+
+ return G_PLUGIN_MODULE(result);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = instance à initialiser pleinement. *
+* module = extension vue du système. *
+* *
+* Description : Met en place un module pour un module pour présentation. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : Le transfert de propriétée du module est total. *
+* *
+******************************************************************************/
+
+bool g_python_notebook_plugin_ui_create(GPythonNotebookPluginUI *plugin, GModule *module)
+{
+ bool result; /* Bilan à retourner */
+
+#ifdef INCLUDE_PYTHON3_BINDINGS
+# define PG_REQ REQ_LIST("PyChrysalide")
+#else
+# define PG_REQ NO_REQ
+#endif
+
+ result = g_native_plugin_create(G_NATIVE_PLUGIN(plugin),
+ "PythonNotebook",
+ "Edit notebook with text and code to support binary analysis",
+ PACKAGE_VERSION,
+ CHRYSALIDE_WEBSITE("doc/plugins/pynb"),
+ PG_REQ,
+ module);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Prend acte de l'activation du greffon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_python_notebook_plugin_ui_enable(GPythonNotebookPluginUI *plugin)
+{
+ bool result; /* Bilan à retourner */
+ panel_info_t info; /* Infos d'enregistrement */
+
+ info.category = "Main";
+
+ info.image = "pynb-symbolic";
+ info.title = _("Python notebook");
+ info.desc = _("Edit notebook with text and code to support binary analysis");
+
+ info.personality = FPP_MAIN_PANEL;
+
+ info.panel_type = GTK_TYPE_PYTHON_NOTEBOOK_PANEL;
+ info.params_type = GTK_TYPE_PYTHON_NOTEBOOK_PARAMETERS;
+
+ result = register_framework_panel_definition(&info);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Prend acte de la désactivation du greffon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_python_notebook_plugin_ui_disable(GPythonNotebookPluginUI *plugin)
+{
+ bool result; /* Bilan à retourner */
+
+
+ // TODO : unregister
+
+ result = true;
+
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTEGRATION DANS L'EDITION DES PREFERENCES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = interface à manipuler. *
+* count = taille de la liste renvoyée. [OUT] *
+* *
+* Description : Fournit une liste de sections de configuration. *
+* *
+* Retour : Définition(s) de section de configuration ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static tweak_info_t *g_python_notebook_plugin_ui_get_tweak_info(const GTweakablePlugin *plugin, size_t *count)
+{
+ tweak_info_t *result; /* Liste à renvoyer */
+
+ tweak_info_t infos[] = {
+ TWEAK_SIMPLE_DEF("root", "Basics",
+ "pynb-symbolic", "pynotebook", "Notebook", GTK_TYPE_PYTHON_NOTEBOOK_TWEAK_PANEL),
+ };
+
+ *count = 1;
+ result = malloc(*count * sizeof(tweak_info_t));
+
+ memcpy(result, infos, *count * sizeof(tweak_info_t));
+
+ return result;
+
+}
diff --git a/plugins/pynb/core-ui.h b/plugins/pynb/core-ui.h
new file mode 100644
index 0000000..8ab9dd9
--- /dev/null
+++ b/plugins/pynb/core-ui.h
@@ -0,0 +1,43 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-ui.h - prototypes pour la présentation de notes sous forme de texte et de code Python
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_FIDO_CORE_UI_H
+#define _PLUGINS_FIDO_CORE_UI_H
+
+
+#include <plugins/plugin.h>
+#include <plugins/plugin-int.h>
+
+
+
+#define G_TYPE_PYTHON_NOTEBOOK_PLUGIN_UI (g_python_notebook_plugin_ui_get_type())
+
+DECLARE_GTYPE(GPythonNotebookPluginUI, g_python_notebook_plugin_ui, G, PYTHON_NOTEBOOK_PLUGIN_UI);
+
+
+/* Crée un module pour présentation de notes. */
+GPluginModule *g_python_notebook_plugin_ui_new(GModule *);
+
+
+
+#endif /* _PLUGINS_FIDO_CORE_UI_H */
diff --git a/plugins/pynb/data/images/pynb-symbolic.svg b/plugins/pynb/data/images/pynb-symbolic.svg
new file mode 100644
index 0000000..f8cae60
--- /dev/null
+++ b/plugins/pynb/data/images/pynb-symbolic.svg
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="256"
+ height="256"
+ viewBox="0 0 67.73333 67.733333"
+ version="1.1"
+ id="svg2759"
+ sodipodi:docname="pynotebook.svg"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview2761"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="false"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="false"
+ inkscape:zoom="2.9329997"
+ inkscape:cx="126.83261"
+ inkscape:cy="128.1964"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1" />
+ <defs
+ id="defs2756">
+ <linearGradient
+ id="b"
+ x1="28.809"
+ y1="28.882"
+ x2="45.803001"
+ y2="45.162998"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(12.026515,0,0,11.963752,-37.015053,-73.520624)">
+ <stop
+ stop-color="#FFE052"
+ id="stop3586" />
+ <stop
+ offset="1"
+ stop-color="#FFC331"
+ id="stop3588" />
+ </linearGradient>
+ <linearGradient
+ id="a"
+ x1="19.075001"
+ y1="18.782"
+ x2="34.897999"
+ y2="34.658001"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(12.026515,0,0,11.963752,-37.015053,-73.520624)">
+ <stop
+ stop-color="#387EB8"
+ id="stop3581" />
+ <stop
+ offset="1"
+ stop-color="#366994"
+ id="stop3583" />
+ </linearGradient>
+ </defs>
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g3524"
+ transform="translate(2.9562937,-0.62320885)"
+ sodipodi:insensitive="true"
+ style="display:none">
+ <path
+ id="rect2966"
+ style="fill:#3a1616;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="m 49.272443,10.836031 c 0.102978,0.351405 0.158647,0.723392 0.158647,1.108976 V 57.03476 c 0,2.168007 -1.745406,3.913456 -3.913456,3.913456 H 16.30288 c -0.385538,0 -0.75709,-0.05622 -1.108459,-0.159163 0.237938,0.812336 0.730853,1.513585 1.387112,2.01175 0.65626,0.498165 1.475864,0.793246 2.367181,0.793246 h 29.214753 c 2.16805,0 3.913456,-1.745449 3.913456,-3.913456 V 14.59084 c 0,-1.782422 -1.180022,-3.278791 -2.80448,-3.754809 z"
+ sodipodi:nodetypes="csssscsssssc" />
+ <path
+ id="rect2964"
+ style="display:inline;fill:#a44040;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="m 13.657273,5.3857002 h 29.21476 c 2.168053,0 3.913452,1.7453645 3.913452,3.9133733 V 54.388991 c 0,2.168009 -1.745399,3.913373 -3.913452,3.913373 h -29.21476 c -1.084026,0 -2.062389,-0.436341 -2.769745,-1.143683 -0.707357,-0.707342 -1.1437069,-1.685685 -1.1437069,-2.76969 V 9.2990735 c 0,-2.1680088 1.7453999,-3.9133733 3.9134519,-3.9133733 z"
+ sodipodi:nodetypes="ssssssssss" />
+ <path
+ id="rect3518"
+ style="fill:#2d3a16;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="m 10.887528,57.158681 5.291742,4.9e-5 5.29299,5.29246 h -5.291667 z"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ <g
+ id="g3807"
+ transform="matrix(0.275,0,0,0.27644269,10.179141,20.324238)"
+ style="display:none;stroke-width:3.62685">
+ <path
+ d="m 76.135321,-13.223349 c -26.868437,0 -25.19164,11.6515879 -25.19164,11.6515879 l 0.03307,12.0716141 h 25.638125 v 3.621485 h -35.82789 c 0,0 -17.187994,-1.951302 -17.187994,25.161874 0,27.106562 15.005182,26.147447 15.005182,26.147447 h 8.956145 V 52.849722 c 0,0 -0.482864,-15.005182 14.767057,-15.005182 h 25.426458 c 0,0 14.287506,0.231511 14.287506,-13.807942 V 0.82271803 c 0,0 2.16958,-14.04606703 -25.906021,-14.04606703 z m -14.138672,8.1160932 c 2.549922,0 4.613672,2.0637499 4.613672,4.61367177 0,2.54992183 -2.06375,4.61367183 -4.613672,4.61367183 a 4.6070572,4.6070572 0 0 1 -4.613672,-4.61367183 c 0,-2.54992187 2.06375,-4.61367177 4.613672,-4.61367177 z"
+ fill="url(#a)"
+ id="path3577"
+ style="fill:url(#a);stroke-width:11.9951" />
+ <path
+ d="m 76.895998,92.057664 c 26.868432,0 25.191642,-11.651588 25.191642,-11.651588 l -0.0331,-12.071615 h -25.6381 v -3.621484 h 35.82458 c 0,0 17.1913,1.951302 17.1913,-25.158567 0,-27.109869 -15.00518,-26.147447 -15.00518,-26.147447 H 105.471 v 12.57763 c 0,0 0.48286,15.005182 -14.76706,15.005182 H 65.277482 c 0,0 -14.287499,-0.231511 -14.287499,13.807942 v 23.21388 c 0,0 -2.169584,14.046067 25.906015,14.046067 z m 14.138671,-8.116093 a 4.6070572,4.6070572 0 0 1 -4.613671,-4.613672 c 0,-2.546615 2.06375,-4.610365 4.613671,-4.610365 2.549922,0 4.613672,2.060443 4.613672,4.610365 0,2.553229 -2.06375,4.613672 -4.613672,4.613672 z"
+ fill="url(#b)"
+ id="path3579"
+ style="fill:url(#b);stroke-width:11.9951" />
+ </g>
+ <g
+ id="g3859"
+ style="display:none;fill:#000000;fill-opacity:1">
+ <path
+ id="path3544"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="m 52.228737,10.212822 c 0.102978,0.351405 0.158647,0.723392 0.158647,1.108976 v 45.089753 c 0,2.168007 -1.745406,3.913456 -3.913456,3.913456 H 19.259174 c -0.385538,0 -0.75709,-0.05622 -1.108459,-0.159163 0.237938,0.812336 0.730853,1.513585 1.387112,2.01175 0.65626,0.498165 1.475864,0.793246 2.367181,0.793246 h 29.214753 c 2.16805,0 3.913456,-1.745449 3.913456,-3.913456 V 13.967631 c 0,-1.782422 -1.180022,-3.278791 -2.80448,-3.754809 z"
+ sodipodi:nodetypes="csssscsssssc" />
+ <path
+ id="path3546"
+ style="display:inline;fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 16.613456,4.7624999 C 14.445408,4.7625 12.7,6.5079516 12.7,8.675956 v 45.089753 c 0,1.084003 0.436244,2.062515 1.143599,2.769857 0.707354,0.70734 1.685833,1.143599 2.769857,1.143599 h 29.214753 c 2.168049,0 3.913456,-1.745451 3.913456,-3.913456 V 8.675956 c 0,-2.1680044 -1.745407,-3.9134561 -3.913456,-3.9134561 z M 31.116446,16.66875 c 7.720775,0 7.124113,3.882967 7.124113,3.882967 v 6.417179 c 0,3.881096 -3.928959,3.817338 -3.928959,3.817338 h -6.992338 c -4.19372,0 -4.061251,4.148067 -4.061251,4.148067 v 3.477824 h -2.462898 c 0,0 -4.126363,0.264897 -4.126363,-7.2285 0,-7.495223 4.726843,-6.955647 4.726843,-6.955647 h 9.852628 v -1.000973 h -7.050215 l -0.0093,-3.337264 c 0,0 -0.461064,-3.220991 6.927742,-3.220991 z m -3.888135,2.24379 c -0.701226,0 -1.268656,0.570469 -1.268656,1.275374 a 1.2669408,1.2735872 0 0 0 1.268656,1.275375 c 0.701229,0 1.268657,-0.570467 1.268657,-1.275375 0,-0.704905 -0.567428,-1.275374 -1.268657,-1.275374 z m 14.46475,5.117 c 0.453342,-0.0018 4.079854,0.203094 4.079854,7.229016 0,7.494318 -4.727359,6.955131 -4.727359,6.955131 h -9.852112 v 1.000973 h 7.050732 l 0.0093,3.337263 c 0,0 0.461069,3.220992 -6.927742,3.220992 -7.720783,0 -7.124113,-3.882967 -7.124113,-3.882967 v -6.417179 c 0,-3.881101 3.928959,-3.817338 3.928959,-3.817338 h 6.992338 c 4.193725,0 4.060734,-4.148067 4.060734,-4.148067 v -3.47679 h 2.462898 c 0,0 0.01629,-9.15e-4 0.04651,-0.001 z M 35.21387,40.97941 c -0.701227,0 -1.269173,0.570348 -1.269173,1.27434 a 1.2669408,1.2735872 0 0 0 1.269173,1.275375 c 0.701228,0 1.268657,-0.569554 1.268657,-1.275375 0,-0.704906 -0.567429,-1.27434 -1.268657,-1.27434 z" />
+ <path
+ id="path3548"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="m 13.843822,56.535472 5.291742,4.9e-5 5.29299,5.29246 h -5.291667 z"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ <path
+ id="rect3934"
+ style="display:none;fill:#00ba2b;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 4.7624999,62.970832 20.637499,4.7624999 h 42.333333 l -15.875,58.2083321 z"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ id="path4924"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 24.551 4.7625 C 22.3829 4.7625 20.1615 6.50795 19.5702 8.67596 L 7.27299 53.7657 C 6.97735 54.8497 7.14673 55.8282 7.66117 56.5356 L 11.5111 61.8277 L 11.5147 61.8277 C 11.6056 61.9525 11.7049 62.0706 11.8167 62.1776 C 12.3371 62.6758 13.0763 62.9708 13.9676 62.9708 L 43.1824 62.9708 C 45.3504 62.9708 47.5719 61.2254 48.1631 59.0574 L 60.4603 13.9676 C 60.9465 12.1852 60.1745 10.6888 58.6799 10.2128 C 58.687 10.5642 58.6413 10.9362 58.5361 11.3218 L 46.2389 56.4115 C 45.6476 58.5795 43.4262 60.325 41.2581 60.325 L 15.7098 60.325 L 13.7851 57.6792 L 39.3339 57.6792 C 41.5019 57.6792 43.7234 55.9337 44.3147 53.7657 L 56.6119 8.67596 C 57.2031 6.50795 55.9338 4.7625 53.7657 4.7625 L 24.551 4.7625 Z M 35.8068 16.6688 C 43.5276 16.6688 41.8719 20.5517 41.8719 20.5517 L 40.1218 26.9689 C 39.0633 30.85 35.1517 30.7862 35.1517 30.7862 L 28.1594 30.7862 C 23.9657 30.7862 22.9668 34.9343 22.9668 34.9343 L 22.0183 38.4121 L 19.5554 38.4121 C 19.5554 38.4121 15.3568 38.677 17.4005 31.1836 C 19.4446 23.6884 24.0243 24.228 24.0243 24.228 L 33.877 24.228 L 34.1499 23.227 L 27.0997 23.227 L 28.0006 19.8897 C 28.0006 19.8897 28.418 16.6688 35.8068 16.6688 Z M 31.3067 18.9125 C 30.6055 18.9125 29.8825 19.483 29.6902 20.1879 C 29.5975 20.5263 29.6424 20.851 29.8152 21.0902 C 29.9879 21.3295 30.2743 21.4637 30.611 21.4633 C 31.3123 21.4633 32.0353 20.8928 32.2275 20.1879 C 32.4198 19.483 32.0079 18.9125 31.3067 18.9125 Z M 44.3759 24.0295 C 44.8297 24.0277 48.4004 24.2326 46.4842 31.2586 C 44.4403 38.7529 39.86 38.2137 39.86 38.2137 L 30.0079 38.2137 L 29.7349 39.2147 L 36.7856 39.2147 L 35.8848 42.5519 C 35.8848 42.5519 35.4674 45.7729 28.0786 45.7729 C 20.3578 45.7729 22.0135 41.8899 22.0135 41.8899 L 23.7636 35.4728 C 24.8221 31.5917 28.7336 31.6554 28.7336 31.6554 L 35.726 31.6554 C 39.9197 31.6554 40.918 27.5074 40.918 27.5074 L 41.8662 24.0306 L 44.3291 24.0306 C 44.3291 24.0306 44.3457 24.0296 44.3759 24.0295 Z M 33.274 40.9794 C 32.5728 40.9794 31.8493 41.5498 31.6573 42.2538 C 31.5645 42.5922 31.6095 42.917 31.7824 43.1563 C 31.9553 43.3956 32.2418 43.5297 32.5787 43.5291 C 33.2799 43.5291 34.0026 42.9596 34.1951 42.2538 C 34.3874 41.5488 33.9753 40.9794 33.274 40.9794 Z" />
+ <path
+ style="display:none;fill:#af00ba;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 4.7624999,62.970832 20.637499,4.7624999 h 42.333333 l -15.875,58.2083321 z"
+ id="path5158"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+</svg>
diff --git a/plugins/pynb/gresource.xml b/plugins/pynb/gresource.xml
new file mode 100644
index 0000000..71eb8ed
--- /dev/null
+++ b/plugins/pynb/gresource.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/re/chrysalide/framework/gui/panels">
+ <file compressed="true" alias="pynb-panel.ui">panel.ui</file>
+ <file compressed="true" alias="pynb-params.ui">params.ui</file>
+ <file compressed="true" alias="pynb-prefs.ui">prefs.ui</file>
+ </gresource>
+ <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions">
+ <file compressed="true" alias="pynb-symbolic.svg">data/images/pynb-symbolic.svg</file>
+ </gresource>
+</gresources>
diff --git a/plugins/pynb/panel-int.h b/plugins/pynb/panel-int.h
new file mode 100644
index 0000000..23884c7
--- /dev/null
+++ b/plugins/pynb/panel-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * panel-int.h - prototypes internes pour le panneau dédié à la présentation de notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYNB_PANEL_INT_H
+#define _PLUGINS_PYNB_PANEL_INT_H
+
+
+#include <gtkext/panel-int.h>
+
+
+#include "panel.h"
+
+
+
+/* Panneau de cartopgraphie des dispositions d'échantillons (instance) */
+struct _GtkPythonNotebookPanel
+{
+ GtkTiledPanel parent; /* A laisser en premier */
+
+};
+
+/* Panneau de cartopgraphie des dispositions d'échantillons (classe) */
+struct _GtkPythonNotebookPanelClass
+{
+ GtkTiledPanelClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place nouvelle instance de panneau de présentation. */
+bool gtk_python_notebook_panel_create(GtkPythonNotebookPanel *);
+
+
+
+#endif /* _PLUGINS_PYNB_PANEL_INT_H */
diff --git a/plugins/pynb/panel.c b/plugins/pynb/panel.c
new file mode 100644
index 0000000..8ce9cdb
--- /dev/null
+++ b/plugins/pynb/panel.c
@@ -0,0 +1,210 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * panel.c - panneau dédié à la présentation de notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "panel.h"
+
+
+#include <gtkext/helpers.h>
+
+
+#include "panel-int.h"
+
+
+
+/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */
+
+
+/* Initialise la classe des panneaux pour binaires. */
+static void gtk_python_notebook_panel_class_init(GtkPythonNotebookPanelClass *);
+
+/* Initialise une instance de panneau pour binaire. */
+static void gtk_python_notebook_panel_init(GtkPythonNotebookPanel *);
+
+/* Supprime toutes les références externes. */
+static void gtk_python_notebook_panel_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_python_notebook_panel_finalize(GObject *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit les composants adaptés pour la barre de titre. */
+//static GListStore *gtk_python_notebook_panel_get_title_widgets(GtkTiledPanel *, bool);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* COEUR D'UN PANNEAU D'AFFICHAGE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un panneau de présentation de notes. */
+G_DEFINE_TYPE(GtkPythonNotebookPanel, gtk_python_notebook_panel, GTK_TYPE_TILED_PANEL);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à initialiser. *
+* *
+* Description : Initialise la classe des panneaux pour binaires. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_panel_class_init(GtkPythonNotebookPanelClass *class)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+ GtkTiledPanelClass *panel; /* Version parente de classe */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_python_notebook_panel_dispose;
+ object->finalize = gtk_python_notebook_panel_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/pynb-panel.ui");
+
+ //gtk_widget_class_bind_template_child(widget, GtkPythonNotebookPanel, summary);
+
+ panel = GTK_TILED_PANEL_CLASS(class);
+
+ //panel->get_widgets = (get_tiled_panel_widgets_cb)gtk_python_notebook_panel_get_title_widgets;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance à initialiser. *
+* *
+* Description : Initialise une instance de panneau pour binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_panel_init(GtkPythonNotebookPanel *panel)
+{
+ gtk_widget_init_template(GTK_WIDGET(panel));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_panel_dispose(GObject *object)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PYTHON_NOTEBOOK_PANEL);
+
+ G_OBJECT_CLASS(gtk_python_notebook_panel_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_panel_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_python_notebook_panel_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une nouvelle instance de panneau de présentation. *
+* *
+* Retour : Composant GTK mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkTiledPanel *gtk_python_notebook_panel_new(void)
+{
+ GtkTiledPanel *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_PYTHON_NOTEBOOK_PANEL, NULL);
+
+ if (!gtk_python_notebook_panel_create(GTK_PYTHON_NOTEBOOK_PANEL(result)))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau de recherche et récupération à remplir. *
+* *
+* Description : Met en place nouvelle instance de panneau de présentation. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_python_notebook_panel_create(GtkPythonNotebookPanel *panel)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ return result;
+
+}
diff --git a/plugins/pynb/panel.h b/plugins/pynb/panel.h
new file mode 100644
index 0000000..f9f8016
--- /dev/null
+++ b/plugins/pynb/panel.h
@@ -0,0 +1,47 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * panel.h - prototypes pour le panneau dédié à la présentation de notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYNB_PANEL_H
+#define _PLUGINS_PYNB_PANEL_H
+
+
+#include <gtk/gtk.h>
+
+
+#include <glibext/helpers.h>
+#include <gtkext/panel.h>
+
+
+
+#define GTK_TYPE_PYTHON_NOTEBOOK_PANEL (gtk_python_notebook_panel_get_type())
+
+DECLARE_GTYPE(GtkPythonNotebookPanel, gtk_python_notebook_panel, GTK, PYTHON_NOTEBOOK_PANEL);
+
+
+/* Crée une nouvelle instance de panneau de présentation. */
+GtkTiledPanel *gtk_python_notebook_panel_new(void);
+
+
+
+#endif /* _PLUGINS_PYNB_PANEL_H */
diff --git a/plugins/pynb/panel.ui b/plugins/pynb/panel.ui
new file mode 100644
index 0000000..d16af80
--- /dev/null
+++ b/plugins/pynb/panel.ui
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <template class="GtkPythonNotebookPanel" parent="GtkTiledPanel">
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">automatic</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <property name="has-frame">true</property>
+ <property name="margin-start">8</property>
+ <property name="margin-top">8</property>
+ <property name="margin-end">8</property>
+ <property name="margin-bottom">8</property>
+
+ </object>
+ </child>
+ </template>
+
+</interface>
diff --git a/plugins/pynb/params-int.h b/plugins/pynb/params-int.h
new file mode 100644
index 0000000..7f3bc8b
--- /dev/null
+++ b/plugins/pynb/params-int.h
@@ -0,0 +1,50 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * params-int.h - définitions internes pour l'édition des paramètres initiaux d'une présentation de notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYNB_PARAMS_INT_H
+#define _PLUGINS_PYNB_PARAMS_INT_H
+
+
+#include "params.h"
+
+
+
+/* Composant pour les paramètres de chargement d'un binaire (instance) */
+struct _GtkPythonNotebookParameters
+{
+ GtkGrid parent; /* A laisser en premier */
+
+ //GtkEntry *filename; /* CHemin d'un binaire */
+
+};
+
+/* Composant pour les paramètres de chargement d'un binaire (classe) */
+struct _GtkPythonNotebookParametersClass
+{
+ GtkGridClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _PLUGINS_PYNB_PARAMS_INT_H */
diff --git a/plugins/pynb/params.c b/plugins/pynb/params.c
new file mode 100644
index 0000000..690ff95
--- /dev/null
+++ b/plugins/pynb/params.c
@@ -0,0 +1,171 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * params.c - édition des paramètres initiaux d'une présentation de notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "params.h"
+
+
+#include "panel.h"
+#include "params-int.h"
+#include <gtkext/helpers.h>
+#include <gui/window.h>
+
+
+
+/* Initialise la classe des composants d'édition de paramètres. */
+static void gtk_python_notebook_parameters_class_init(GtkPythonNotebookParametersClass *);
+
+/* Initialise une instance de composant d'édition de paramètres. */
+static void gtk_python_notebook_parameters_init(GtkPythonNotebookParameters *);
+
+/* Supprime toutes les références externes. */
+static void gtk_python_notebook_parameters_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_python_notebook_parameters_finalize(GObject *);
+
+/* Réagit à une demande de création de notes. */
+static void gtk_python_notebook_parameters_on_create_clicked(GtkButton *, GtkPythonNotebookParameters *);
+
+
+
+/* Indique le type du composant d'édition des paramètres de chargement. */
+G_DEFINE_TYPE(GtkPythonNotebookParameters, gtk_python_notebook_parameters, GTK_TYPE_GRID);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Initialise la classe des composants d'édition de paramètres. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_parameters_class_init(GtkPythonNotebookParametersClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_python_notebook_parameters_dispose;
+ object->finalize = gtk_python_notebook_parameters_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/pynb-params.ui");
+
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_python_notebook_parameters_on_create_clicked));
+
+ //gtk_widget_class_bind_template_child(widget, GtkPythonNotebookParameters, filename);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : params = composant GTK à initialiser. *
+* *
+* Description : Initialise une instance de composant d'édition de paramètres.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_parameters_init(GtkPythonNotebookParameters *params)
+{
+ gtk_widget_init_template(GTK_WIDGET(params));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_parameters_dispose(GObject *object)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PYTHON_NOTEBOOK_PARAMETERS);
+
+ G_OBJECT_CLASS(gtk_python_notebook_parameters_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_parameters_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_python_notebook_parameters_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton GTK concerné par l'appel. *
+* params = paramètres du panneau à mettre en place. *
+* *
+* Description : Réagit à une demande de création de notes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_parameters_on_create_clicked(GtkButton *button, GtkPythonNotebookParameters *params)
+{
+ GtkRoot *root; /* Racine du composant */
+ GtkTiledPanel *tiled; /* Panneau d'affichage complet */
+
+ root = gtk_widget_get_root(GTK_WIDGET(button));
+
+ tiled = gtk_python_notebook_panel_new();
+
+ gtk_framework_window_add(GTK_FRAMEWORK_WINDOW(root), tiled);
+
+}
diff --git a/plugins/pynb/params.h b/plugins/pynb/params.h
new file mode 100644
index 0000000..2d4b39b
--- /dev/null
+++ b/plugins/pynb/params.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * params.h - prototypes pour l'édition des paramètres initiaux d'une présentation de notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYNB_PARAMS_H
+#define _PLUGINS_PYNB_PARAMS_H
+
+
+#include <gtk/gtk.h>
+
+
+#include <glibext/helpers.h>
+
+
+
+#define GTK_TYPE_PYTHON_NOTEBOOK_PARAMETERS (gtk_python_notebook_parameters_get_type())
+
+DECLARE_GTYPE(GtkPythonNotebookParameters, gtk_python_notebook_parameters, GTK, PYTHON_NOTEBOOK_PARAMETERS);
+
+
+
+#endif /* _PLUGINS_PYNB_PARAMS_H */
diff --git a/plugins/pynb/params.ui b/plugins/pynb/params.ui
new file mode 100644
index 0000000..21a4788
--- /dev/null
+++ b/plugins/pynb/params.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <template class="GtkPythonNotebookParameters" parent="GtkGrid">
+ <property name="margin-bottom">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">12</property>
+ <property name="column-spacing">12</property>
+ <property name="row-spacing">8</property>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="label">Load and analyze a new notebook file:</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkEntry" id="filename">
+ <property name="secondary-icon-name">document-open-symbolic</property>
+ <property name="placeholder-text">File location</property>
+ <property name="hexpand">TRUE</property>
+ <property name="hexpand-set">TRUE</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">1</property>
+ </layout>
+ <style>
+ <class name="background"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="create">
+ <property name="label">Create</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">2</property>
+ </layout>
+ <signal name="clicked" handler="gtk_python_notebook_parameters_on_create_clicked"/>
+ </object>
+ </child>
+
+ </template>
+
+</interface>
diff --git a/plugins/pynb/prefs-int.h b/plugins/pynb/prefs-int.h
new file mode 100644
index 0000000..9c44c68
--- /dev/null
+++ b/plugins/pynb/prefs-int.h
@@ -0,0 +1,48 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * prefs-int.h - définitions internes pour la configuration des paramètres liés aux notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYNB_PREFS_INT_H
+#define _PLUGINS_PYNB_PREFS_INT_H
+
+
+#include "prefs.h"
+
+
+
+/* Composant d'édition des paramètres liés aux notes (instance) */
+struct _GtkPythonNotebookTweakPanel
+{
+ GtkBox parent; /* A laisser en premier */
+
+};
+
+/* Composant d'édition des paramètres liés aux notes (classe) */
+struct _GtkPythonNotebookTweakPanelClass
+{
+ GtkBoxClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _PLUGINS_PYNB_PREFS_INT_H */
diff --git a/plugins/pynb/prefs.c b/plugins/pynb/prefs.c
new file mode 100644
index 0000000..9363e9b
--- /dev/null
+++ b/plugins/pynb/prefs.c
@@ -0,0 +1,143 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * prefs.c - configuration des paramètres liés aux notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "prefs.h"
+
+
+#include <gtkext/helpers.h>
+
+
+#include "prefs-int.h"
+
+
+
+/* Procède à l'initialisation de classe des configurations. */
+static void gtk_python_notebook_tweak_panel_class_init(GtkPythonNotebookTweakPanelClass *);
+
+/* Procède à l'initialisation des configurations de sécurité. */
+static void gtk_python_notebook_tweak_panel_init(GtkPythonNotebookTweakPanel *);
+
+/* Supprime toutes les références externes. */
+static void gtk_python_notebook_tweak_panel_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_python_notebook_tweak_panel_finalize(GObject *);
+
+
+
+/* Indique le type du composant de configuration des notes. */
+G_DEFINE_TYPE(GtkPythonNotebookTweakPanel, gtk_python_notebook_tweak_panel, GTK_TYPE_BOX);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de classe des configurations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_tweak_panel_class_init(GtkPythonNotebookTweakPanelClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_python_notebook_tweak_panel_dispose;
+ object->finalize = gtk_python_notebook_tweak_panel_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/pynb-prefs.ui");
+
+ /* Stockage sécurisé */
+
+ //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_python_notebook_tweak_panel_on_new_passwords_changed));
+
+ //gtk_widget_class_bind_template_child(widget, GtkPythonNotebookTweakPanel, current_primary_passwd);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = composant GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation des configurations de sécurité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_tweak_panel_init(GtkPythonNotebookTweakPanel *panel)
+{
+ gtk_widget_init_template(GTK_WIDGET(panel));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_tweak_panel_dispose(GObject *object)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PYTHON_NOTEBOOK_TWEAK_PANEL);
+
+ G_OBJECT_CLASS(gtk_python_notebook_tweak_panel_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_python_notebook_tweak_panel_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_python_notebook_tweak_panel_parent_class)->finalize(object);
+
+}
diff --git a/plugins/pynb/prefs.h b/plugins/pynb/prefs.h
new file mode 100644
index 0000000..6551983
--- /dev/null
+++ b/plugins/pynb/prefs.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * prefs.h - prototypes pour la configuration des paramètres liés aux notes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_PYNB_PREFS_H
+#define _PLUGINS_PYNB_PREFS_H
+
+
+#include <gtk/gtk.h>
+
+
+#include <glibext/helpers.h>
+
+
+
+#define GTK_TYPE_PYTHON_NOTEBOOK_TWEAK_PANEL (gtk_python_notebook_tweak_panel_get_type())
+
+DECLARE_GTYPE(GtkPythonNotebookTweakPanel, gtk_python_notebook_tweak_panel, GTK, PYTHON_NOTEBOOK_TWEAK_PANEL);
+
+
+
+#endif /* _PLUGINS_PYNB_PREFS_H */
diff --git a/plugins/pynb/prefs.ui b/plugins/pynb/prefs.ui
new file mode 100644
index 0000000..b8a6962
--- /dev/null
+++ b/plugins/pynb/prefs.ui
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <template class="GtkPythonNotebookTweakPanel" parent="GtkBox">
+
+ <property name="orientation">vertical</property>
+
+ <!-- Conservation de paramètres sécurisée -->
+ <child>
+ <object class="GtkGrid">
+ <property name="margin-start">20</property>
+ <property name="margin-end">20</property>
+ <property name="margin-top">20</property>
+ <property name="margin-bottom">20</property>
+ <property name="row-spacing">10</property>
+ <property name="column-spacing">10</property>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="label">Notes config</property>
+ <property name="use-markup">true</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="column-span">2</property>
+ </layout>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index c50af8f..7411287 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -59,7 +59,7 @@ libchrysacore_la_LDFLAGS = \
-avoid-version -ldl -lm \
$(TOOLKIT_LIBS) $(LIBXML_LIBS) \
$(LIBSQLITE_LIBS) $(LIBARCHIVE_LIBS) \
- $(LIBSSL_LIBS) $(LIBHS_LIBS)
+ $(LIBSSL_LIBS)
if BUILD_CURL_SUPPORT
@@ -73,12 +73,18 @@ libchrysacore_la_LDFLAGS += $(LIBMAGIC_LIBS)
endif
+if BUILD_HS_SUPPORT
+
+libchrysacore_la_LDFLAGS += $(LIBHS_LIBS)
+
+endif
+
libchrysacore4_la_SOURCES =
libchrysacore4_la_LIBADD = \
analysis/libanalysis4.la \
- arch/libarch4.la \
+ arch/libarch.la \
common/libcommon4.la \
core/libcore4.la \
format/libformat.la \
@@ -86,7 +92,7 @@ libchrysacore4_la_LIBADD = \
plugins/libplugins.la
libchrysacore4_la_LDFLAGS = \
- $(TOOLKIT_LIBS) $(LIBSSL_LIBS) $(LIBJSONGLIB_LIBS)
+ $(TOOLKIT_LIBS) $(LIBSSL_LIBS) $(LIBJSONGLIB_LIBS) $(LIBZIP_LIBS)
if BUILD_CURL_SUPPORT
@@ -102,13 +108,15 @@ EXTRA_libchrysacoreui_la_DEPENDENCIES = libchrysacore4.la
libchrysacoreui_la_SOURCES =
libchrysacoreui_la_LIBADD = \
+ arch/libarchui.la \
+ data/images/libdataimages.la \
glibext/libglibextui.la \
gtkext/libgtkext4.la \
gui/libgui4.la
# -lm: log()
libchrysacoreui_la_LDFLAGS = \
- $(LIBGTK4_CFLAGS) -L.libs -lchrysacore4 \
+ $(LIBGTK4_LIBS) -L.libs -lchrysacore4 \
-lm
@@ -188,4 +196,4 @@ rost_LDFLAGS = $(LIBGOBJ_LIBS) -L.libs -lchrysacore
#SUBDIRS = core glibext $(GTKEXT_SUBDIR) analysis arch format common debug $(GUI_SUBDIR) mangling plugins schemas
-SUBDIRS = analysis arch common core format glibext gtkext gui plugins
+SUBDIRS = analysis arch common core data format glibext gtkext gui plugins schemas
diff --git a/src/analysis/contents/encapsulated.c b/src/analysis/contents/encapsulated.c
index 451c340..22b61c0 100644
--- a/src/analysis/contents/encapsulated.c
+++ b/src/analysis/contents/encapsulated.c
@@ -30,8 +30,8 @@
#include "encapsulated-int.h"
#include "../db/misc/rlestr.h"
-#include "../storage/serialize-int.h"
#include "../../common/extstr.h"
+#include "../../glibext/serialize-int.h"
diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c
index 791f8b6..125016c 100644
--- a/src/analysis/contents/file.c
+++ b/src/analysis/contents/file.c
@@ -35,8 +35,8 @@
#include "file-int.h"
#include "../db/misc/rlestr.h"
-#include "../storage/serialize-int.h"
#include "../../core/logs.h"
+#include "../../glibext/serialize-int.h"
diff --git a/src/analysis/contents/memory.c b/src/analysis/contents/memory.c
index a3acc3b..c6ccb5b 100644
--- a/src/analysis/contents/memory.c
+++ b/src/analysis/contents/memory.c
@@ -35,9 +35,9 @@
#include "memory-int.h"
#include "../db/misc/rlestr.h"
-#include "../storage/serialize-int.h"
#include "../../common/extstr.h"
#include "../../core/logs.h"
+#include "../../glibext/serialize-int.h"
diff --git a/src/analysis/contents/restricted.c b/src/analysis/contents/restricted.c
index 95f513b..6f091ae 100644
--- a/src/analysis/contents/restricted.c
+++ b/src/analysis/contents/restricted.c
@@ -30,9 +30,9 @@
#include "restricted-int.h"
#include "../db/misc/rlestr.h"
-#include "../storage/serialize-int.h"
#include "../../common/extstr.h"
#include "../../core/logs.h"
+#include "../../glibext/serialize-int.h"
diff --git a/src/analysis/scan/patterns/backends/Makefile.am b/src/analysis/scan/patterns/backends/Makefile.am
index 23b0163..84711a7 100644
--- a/src/analysis/scan/patterns/backends/Makefile.am
+++ b/src/analysis/scan/patterns/backends/Makefile.am
@@ -6,10 +6,16 @@ libanalysisscanpatternsbackends_la_SOURCES = \
acism-int.h \
acism.h acism.c \
bitap-int.h \
- bitap.h bitap.c \
+ bitap.h bitap.c
+
+if BUILD_HS_SUPPORT
+
+libanalysisscanpatternsbackends_la_SOURCES += \
hyperscan-int.h \
hyperscan.h hyperscan.c
+endif
+
# Cf. https://www.gnu.org/software/automake/manual/html_node/Per_002dObject-Flags.html
AM_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBHS_CFLAGS)
diff --git a/src/analysis/storage/Makefile.am b/src/analysis/storage/Makefile.am
index 3eb287b..dad7411 100644
--- a/src/analysis/storage/Makefile.am
+++ b/src/analysis/storage/Makefile.am
@@ -6,12 +6,7 @@ libanalysisstorage_la_SOURCES = \
cache-int.h \
cache.h cache.c \
container-int.h \
- container.h container.c \
- serialize-int.h \
- serialize.h serialize.c \
- storage-int.h \
- storage.h storage.c \
- tpmem.h tpmem.c
+ container.h container.c
libanalysisstorage_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
diff --git a/src/analysis/storage/serialize.h b/src/analysis/storage/serialize.h
deleted file mode 100644
index 93a4496..0000000
--- a/src/analysis/storage/serialize.h
+++ /dev/null
@@ -1,64 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * serialize.h - prototypes pour les objets entreposables dans un cache
- *
- * 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/>.
- */
-
-
-#ifndef _ANALYSIS_STORAGE_SERIALIZE_H
-#define _ANALYSIS_STORAGE_SERIALIZE_H
-
-
-#include <glib-object.h>
-
-
-#include "../../common/packed.h"
-
-
-
-#define G_TYPE_SERIALIZABLE_OBJECT g_serializable_object_get_type()
-#define G_SERIALIZABLE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObject))
-#define G_SERIALIZABLE_OBJECT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObjectIface))
-#define G_IS_SERIALIZABLE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SERIALIZABLE_OBJECT))
-#define G_IS_SERIALIZABLE_OBJECT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE((vtable), G_TYPE_SERIALIZABLE_OBJECT))
-#define G_SERIALIZABLE_OBJECT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObjectIface))
-
-
-/* Intermédiaire pour la mise en cache d'objet (coquille vide) */
-typedef struct _GSerializableObject GSerializableObject;
-
-/* Intermédiaire pour la mise en cache d'objet (interface) */
-typedef struct _GSerializableObjectIface GSerializableObjectIface;
-
-
-/* Détermine le type d'une interface pour la mise en cache d'objet. */
-GType g_serializable_object_get_type(void) G_GNUC_CONST;
-
-/* storage.h : définition d'une conservation d'objets construits */
-typedef struct _GObjectStorage GObjectStorage;
-
-/* Charge un objet depuis une mémoire tampon. */
-bool g_serializable_object_load(GSerializableObject *, GObjectStorage *, packed_buffer_t *);
-
-/* Sauvegarde un objet dans une mémoire tampon. */
-bool g_serializable_object_store(const GSerializableObject *, GObjectStorage *, packed_buffer_t *);
-
-
-
-#endif /* _ANALYSIS_STORAGE_SERIALIZE_H */
diff --git a/src/analysis/storage/tpmem.h b/src/analysis/storage/tpmem.h
deleted file mode 100644
index 34cbde6..0000000
--- a/src/analysis/storage/tpmem.h
+++ /dev/null
@@ -1,70 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * tpmem.h - prototypes pour la mémorisation des types d'objets mis en cache
- *
- * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef _ANALYSIS_STORAGE_TPMEM_H
-#define _ANALYSIS_STORAGE_TPMEM_H
-
-
-#include <glib-object.h>
-
-
-#include "../../common/packed.h"
-
-
-
-#define G_TYPE_TYPE_MEMORY g_type_memory_get_type()
-#define G_TYPE_MEMORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_TYPE_MEMORY, GTypeMemory))
-#define G_IS_TYPE_MEMORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_TYPE_MEMORY))
-#define G_TYPE_MEMORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_TYPE_MEMORY, GTypeMemoryClass))
-#define G_IS_TYPE_MEMORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_TYPE_MEMORY))
-#define G_TYPE_MEMORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_TYPE_MEMORY, GTypeMemoryClass))
-
-
-/* Définition d'une mémoire de types d'objets (instance) */
-typedef struct _GTypeMemory GTypeMemory;
-
-/* Définition d'une mémoire de types d'objets (classe) */
-typedef struct _GTypeMemoryClass GTypeMemoryClass;
-
-
-/* Indique le type défini pour une mémoire de types d'objets. */
-GType g_type_memory_get_type(void);
-
-/* Crée une mémoire pour types d'objets. */
-GTypeMemory *g_type_memory_new(void);
-
-/* Apprend tous les types mémorisés dans un tampon. */
-bool g_type_memory_load_types(GTypeMemory *, packed_buffer_t *);
-
-/* Crée une nouvelle instance d'objet à partir de son type. */
-GObject *g_type_memory_create_object(GTypeMemory *, packed_buffer_t *);
-
-/* Sauvegarde le type d'un objet instancié. */
-bool g_type_memory_store_object_gtype(GTypeMemory *, GObject *, packed_buffer_t *);
-
-/* Enregistre tous les types mémorisés dans un tampon. */
-bool g_type_memory_store_types(GTypeMemory *, packed_buffer_t *);
-
-
-
-#endif /* _ANALYSIS_STORAGE_TPMEM_H */
diff --git a/src/app.c b/src/app.c
index 2e0d4fa..ef62135 100644
--- a/src/app.c
+++ b/src/app.c
@@ -399,7 +399,7 @@ static void ensure_wm_icon_and_name(void)
filename = get_xdg_data_dir("icons/hicolor/scalable/apps/chrysalide-logo.svg", true);
- fd = open(filename, O_WRONLY | O_CREAT);
+ fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1)
LOG_ERROR_N("open");
@@ -505,6 +505,32 @@ int main(int argc, char **argv)
set_log_verbosity(verbosity);
+ /**
+ * Même s'il est dit que l'usage de GtkApplication permet de s'affranchir
+ * d'un appel à gtk_init(), il se trouve que la journalisation en mode
+ * graphique peut solliciter le panneau en GTK pour afficher des messages
+ * avant la mise en place de l'applicatif GTK principal :
+ *
+ * #2 0x00007ffff7b33403 in gtk_css_lookup_resolve (lookup=lookup@entry=0x7fffffff88a0, provider=provider@entry=0x0, sstyle=sstyle@entry=0x7fffe800a730, parent_style=parent_style@entry=0x0) at ../gtk/gtkcssstaticstyle.c:911
+ * #3 0x00007ffff7b3389f in gtk_css_static_style_new_compute (provider=0x0, filter=filter@entry=0x7fffffff8ea0, node=node@entry=0x0, change=<optimized out>, change@entry=0) at ../gtk/gtkcssstaticstyle.c:1026
+ * #4 0x00007ffff7b3392c in gtk_css_static_style_get_default () at ../gtk/gtkcssstaticstyle.c:711
+ * #5 0x00007ffff7b24b09 in gtk_css_node_init (cssnode=0x7fffe800a5b0) at ../gtk/gtkcssnode.c:641
+ * #6 0x00007ffff75d8dab in g_type_create_instance () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
+ * [...]
+ * #10 0x00007ffff7b3b8fa in gtk_css_widget_node_new (widget=widget@entry=0x5555555bf1b0) at ../gtk/gtkcsswidgetnode.c:160
+ * #11 0x00007ffff7ae4576 in gtk_widget_init (instance=<optimized out>, g_class=0x5555555be380) at ../gtk/gtkwidget.c:2345
+ * [...]
+ * #16 0x00007ffff73fd3f4 in get_framework_panel_singleton (...) at panels.c:329
+ * #17 0x00007ffff73fce35 in do_log_message_alt (...) at logs.c:56
+ * [...]
+ * #23 0x00007ffff74566db in init_all_plugins (load=true) at pglist.c:103
+ * #24 0x0000555555556d44 in main (argc=2, argv=0x7fffffffb568) at app.c:514
+ *
+ * L'initialisation permettant un retour de gtk_settings_get_default() non
+ * nul est ainsi forcée au plus tôt avec un appel à gtk_init() manuel.
+ */
+ gtk_init();
+
if (!load_core_components(ACC_GLOBAL_VARS))
goto exit;
diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am
index 6ee2690..6683854 100644
--- a/src/arch/Makefile.am
+++ b/src/arch/Makefile.am
@@ -1,43 +1,57 @@
-noinst_LTLIBRARIES = libarch4.la # libarch.la
+noinst_LTLIBRARIES = libarch.la libarchui.la
+
+# libarch_la_SOURCES = \
+# archbase.h archbase.c \
+# context-int.h \
+# context.h context.c \
+# instriter.h instriter.c \
+# link.h link.c \
+# post.h post.c \
+# storage.h storage.c
+
+# libarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+
+# libarch_la_LIBADD = \
+# operands/libarchoperands.la
+
+
+#
+# processor-int.h \
+# processor.h processor.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-int.h \
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_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+libarch_la_CFLAGS = $(LIBGOBJ_CFLAGS)
libarch_la_LIBADD = \
instructions/libarchinstructions.la \
operands/libarchoperands.la
-libarch4_la_SOURCES = \
- vmpa.h vmpa.c
+libarchui_la_SOURCES = \
+ instruction-ui-int.h \
+ instruction-ui.h instruction-ui.c \
+ operand-ui-int.h \
+ operand-ui.h operand-ui.c
-libarch4_la_CFLAGS = $(TOOLKIT_CFLAGS)
+libarchui_la_CFLAGS = $(LIBGTK_CFLAGS)
-libarch4_la_LIBADD =
+libarchui_la_LIBADD = \
+ operands/libarchoperandsui.la
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
-dev_HEADERS = $(libarch_la_SOURCES:%c=)
-
+dev_HEADERS = $(libarch_la_SOURCES:%c=) $(libarchui_la_SOURCES:%c=)
-#SUBDIRS = instructions operands
+SUBDIRS = instructions operands
diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h
index 7dbbe27..d426cea 100644
--- a/src/arch/instruction-int.h
+++ b/src/arch/instruction-int.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* instruction-int.h - prototypes pour la définition générique interne des instructions
*
- * Copyright (C) 2008-2020 Cyrille Bagard
+ * Copyright (C) 2008-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,18 +25,29 @@
#define _ARCH_INSTRUCTION_INT_H
+#include <stdint.h>
+
+
#include "instruction.h"
-#include "../analysis/storage/storage.h"
#include "../common/array.h"
-#include "../glibext/objhole.h"
+#include "../glibext/objhole-int.h"
/* Indique l'encodage d'une instruction de façon détaillée. */
-typedef const char * (* get_instruction_encoding_fc) (const GArchInstruction *);
+typedef char * (* get_instruction_encoding_fc) (const GArchInstruction *);
/* Fournit le nom humain de l'instruction manipulée. */
-typedef const char * (* get_instruction_keyword_fc) (GArchInstruction * );
+typedef char * (* get_instruction_keyword_fc) (const GArchInstruction *);
+
+
+
+#if 0
+
+#include "../analysis/storage/storage.h"
+
+
+
/* Complète un désassemblage accompli pour une instruction. */
typedef void (* call_instruction_hook_fc) (GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *);
@@ -67,80 +78,45 @@ typedef bool (* store_instruction_fc) (GArchInstruction *, GObjectStorage *, pac
-/* Informations glissées dans la structure GObject de GArchOperand */
-typedef struct _instr_extra_data_t
-{
- itid_t uid; /* Identifiant unique du type */
-
- ArchInstrFlag flags; /* Informations complémentaires*/
-
-} instr_extra_data_t;
+#endif
-/* Informations glissées dans la structure GObject de GArchInstruction */
-typedef union _instr_obj_extra_t
-{
- instr_extra_data_t data; /* Données embarquées */
- lockable_obj_extra_t lockable; /* Gestion d'accès aux fanions */
-} instr_obj_extra_t;
+/* Conservation d'une adresse et de propriétées */
+typedef unsigned long compact_ins_link_t;
/* Définition générique d'une instruction d'architecture (instance) */
struct _GArchInstruction
{
- GObject parent; /* A laisser en premier */
+ GThickObject parent; /* A laisser en premier */
-#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__
+ GBinaryPortion *rel_area; /* Zone de référence */
+ rel_mrange_t rel_range; /* Emplacement compressé */
/**
- * L'inclusion des informations suivantes dépend de l'architecture.
- *
- * Si la structure GObject possède un trou, on remplit de préférence
- * ce dernier.
+ * A laisser à la suite de la localisation précédente pour éviter
+ * les espaces vide dans la structure.
*/
+ uint16_t link_count; /* Quantité de liens établis */
- instr_obj_extra_t extra; /* Externalisation embarquée */
-
-#endif
-
- mrange_t range; /* Emplacement en mémoire */
+ compact_ins_link_t *links; /* Liste de ces liens */
flat_array_t *operands; /* Liste des opérandes */
- /**
- * Il existe le besoin indéniable d'un verrou pour les accès aux instructions
- * liées. Il faut par ailleurs un verrou distinct pour les sources et les
- * destinations car une même instruction peut boucler sur elle même et la
- * fonction g_arch_instruction_change_link() pose des verrous sur les
- * deux extrémités.
- *
- * La GLib propose les fonctions g_bit_lock() / g_bit_unlock(), légères mais
- * sans distinction entre lectures et écritures. Tant pis : la réduction de
- * l'empreinte mémoire prime !
- *
- * Par contre la documentation indique :
- *
- * """
- * Attempting to lock on two different bits within the same integer is not supported.
- * """
- *
- * Donc on doit bien conserver un compteur distinct pour chaque extrémité.
- * Cela correspond de toute façon à la définition optimisée des tableaux
- * suivante.
- */
-
- flat_array_t *from; /* Origines des références */
- flat_array_t *to; /* Instructions visées */
-
};
/* Définition générique d'une instruction d'architecture (classe) */
struct _GArchInstructionClass
{
- GObjectClass parent; /* A laisser en premier */
+ GThickObjectClass parent; /* A laisser en premier */
get_instruction_encoding_fc get_encoding; /* Obtention de l'encodage */
get_instruction_keyword_fc get_keyword; /* Texte humain équivalent */
+
+#if 0
+
+ //get_instruction_encoding_fc get_encoding; /* Obtention de l'encodage */
+ //get_instruction_keyword_fc get_keyword; /* Texte humain équivalent */
call_instruction_hook_fc call_hook; /* Décrochages éventuels */
build_instruction_tooltip_fc build_tooltip; /* Construction d'une bulle*/
get_instruction_desc_fc get_desc; /* Description assez complète */
@@ -155,22 +131,50 @@ struct _GArchInstructionClass
//get_instruction_rw_regs_fc get_rw_regs; /* Liste des registres liés */
+#endif
+
};
+/* Met en place une instruction d'architecture. */
+bool g_arch_instruction_create(GArchInstruction *, itid_t);
+
+
+
/**
* Accès aux informations éventuellement déportées.
*/
-#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__
-# define GET_ARCH_INSTR_EXTRA(ins) (instr_extra_data_t *)&ins->extra
+#define ARCH_INSTRUCTION_EXTRA_DATA \
+ \
+ unsigned int reserved : GOBJECT_RESERVED_EXTRA_BITS; \
+ \
+ /** \
+ * itid_t \
+ */ \
+ unsigned int tid : 16; \
+ \
+ /** \
+ * ArchOperandFlag \
+ */ \
+ unsigned int flags : 8;
-#else
-# define GET_ARCH_INSTR_EXTRA(ins) GET_GOBJECT_EXTRA(G_OBJECT(ins), instr_extra_data_t)
+/* Informations glissées dans la structure GObject de GArchOperand */
+typedef struct _instruction_extra_data_t
+{
+ ARCH_INSTRUCTION_EXTRA_DATA; /* Socle commun */
+
+} instruction_extra_data_t;
+
+
+#define GET_ARCH_INSTR_EXTRA(op) \
+ GET_GOBJECT_EXTRA(op, instruction_extra_data_t)
+
+#define SET_ARCH_INSTR_EXTRA(op, data) \
+ SET_GOBJECT_EXTRA(op, instruction_extra_data_t, data)
-#endif
/**
diff --git a/src/arch/instruction-ui-int.h b/src/arch/instruction-ui-int.h
new file mode 100644
index 0000000..b07f40c
--- /dev/null
+++ b/src/arch/instruction-ui-int.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instruction-ui-int.h - prototypes pour la définition générique interne des instructions sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_INSTRUCTION_UI_INT_H
+#define _ARCH_INSTRUCTION_UI_INT_H
+
+
+#include "instruction-ui.h"
+
+
+
+#if 0
+
+/* Traduit un opérande en version humainement lisible. */
+typedef void (* print_operand_ui_fc) (const GArchOperandUI *, GBufferLine *);
+
+/* Construit un petit résumé concis de l'opérande. */
+typedef char * (* build_operand_ui_tooltip_fc) (const GArchOperandUI *, const GLoadedBinary *);
+
+
+
+/* Définition générique d'un opérande d'architecture (interface) */
+struct _GArchOperandUIInterface
+{
+ GTypeInterface base_iface; /* A laisser en premier */
+
+ print_operand_ui_fc print; /* Texte humain équivalent */
+ build_operand_ui_tooltip_fc build_tooltip; /* Définition de description*/
+
+};
+
+#endif
+
+
+#endif /* _ARCH_INSTRUCTION_UI_INT_H */
diff --git a/src/arch/instruction-ui.c b/src/arch/instruction-ui.c
new file mode 100644
index 0000000..7f923d8
--- /dev/null
+++ b/src/arch/instruction-ui.c
@@ -0,0 +1,254 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instruction-ui.c - gestion générique des instructions sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "instruction-ui.h"
+
+
+#include "instruction-int.h"
+#include "operand-ui.h"
+#include "../analysis/content.h"
+#include "../common/cpp.h"
+#include "../glibext/generator-int.h"
+#include "../glibext/options/asm.h"
+
+
+
+/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+
+
+/* Renseigne sur les propriétés liées à un générateur. */
+static BufferLineFlags g_arch_instruction_ui_get_flags(const GTokenGenerator *, size_t, size_t);
+
+/* Etablit dans une ligne de rendu le contenu représenté. */
+static void g_arch_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *);
+
+#if 0
+
+/* Retrouve l'emplacement correspondant à une position donnée. */
+static void g_arch_instruction_ui_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_ui_contain_cursor(const GArchInstruction *, size_t, size_t, const GLineCursor *);
+
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* OFFRE DE CAPACITES DE GENERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de génération. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_arch_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface)
+{
+ /**
+ * La procédure par défaut de iface->count() ne doit pas être retouchée !
+ */
+
+ iface->get_flags = g_arch_instruction_ui_get_flags;
+ iface->populate = g_arch_instruction_ui_populate_line;
+
+#if 0
+ iface->compute = (linegen_compute_fc)g_arch_instruction_ui_compute_cursor;
+ iface->contain = (linegen_contain_fc)g_arch_instruction_ui_contain_cursor;
+#endif
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : generator = générateur à consulter. *
+* index = indice de cette même ligne dans le tampon global.*
+* repeat = indice d'utilisations successives du générateur. *
+* *
+* Description : Renseigne sur les propriétés liées à un générateur. *
+* *
+* Retour : Propriétés particulières associées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static BufferLineFlags g_arch_instruction_ui_get_flags(const GTokenGenerator *generator, size_t index, size_t repeat)
+{
+ BufferLineFlags result; /* Fanions à retourner */
+
+ result = BLF_HAS_CODE;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : generator = générateur à utiliser pour l'impression. *
+* index = indice de cette même ligne dans le tampon global.*
+* repeat = indice d'utilisations successives du générateur. *
+* line = ligne de rendu à compléter. *
+* data = éventuelle donnée complémentaire fournie. *
+* *
+* Description : Etablit dans une ligne de rendu le contenu représenté. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_arch_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data)
+{
+ GArchInstruction *instr; /* Version spécialisée */
+ GBinContent *content; /* Contenu brut d'origine */
+ mrange_t range; /* Emplacement couvert */
+ char *key; /* Mot clef principal */
+ size_t count; /* Nombre d'opérandes en place */
+ size_t i; /* Boucle de parcours */
+ GArchOperand *op; /* Opérande à manipuler */
+
+ instr = G_ARCH_INSTRUCTION(generator);
+ content = G_BIN_CONTENT(data);
+
+ /* Prologue */
+
+ if (g_arch_instruction_get_range(instr, &range))
+ {
+ g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range));
+
+ g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range));
+
+ g_buffer_line_fill_content(line, ACO_BINARY, content, &range, VMPA_NO_PHYSICAL);
+
+ }
+
+ /* Instruction proprement dite */
+
+ key = g_arch_instruction_get_keyword(instr);
+
+ g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_INSTRUCTION, SL(key), NULL, G_OBJECT(instr));
+
+ free(key);
+
+ /* Liste des opérandes */
+
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+
+ count = g_arch_instruction_count_operands(instr);
+
+ if (count > 0)
+ {
+ op = g_arch_instruction_get_operand(instr, 0);
+ g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line);
+ unref_object(op);
+
+ for (i = 1; i < count; i++)
+ {
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL);
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_NONE, STCSL(" "), NULL, NULL);
+
+ op = g_arch_instruction_get_operand(instr, i);
+ g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line);
+ unref_object(op);
+
+ }
+
+ }
+
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
+
+}
+
+
+#if 0
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = générateur à consulter. *
+* x = position géographique sur la ligne concernée. *
+* index = indice de cette même ligne dans le tampon global. *
+* repeat = indice d'utilisations successives du générateur. *
+* cursor = emplacement à constituer. [OUT] *
+* *
+* Description : Retrouve l'emplacement correspondant à une position donnée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_arch_instruction_ui_compute_cursor(const GArchInstruction *instr, gint x, size_t index, size_t repeat, GLineCursor **cursor)
+{
+ *cursor = g_binary_cursor_new();
+
+ g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&instr->range));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = générateur à consulter. *
+* index = indice de cette même ligne dans le tampon global. *
+* repeat = indice d'utilisations successives du générateur. *
+* cursor = emplacement à analyser. *
+* *
+* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
+* *
+* Retour : Bilan de la détermination, utilisable en comparaisons. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int g_arch_instruction_ui_contain_cursor(const GArchInstruction *instr, size_t index, size_t repeat, const GLineCursor *cursor)
+{
+ int result; /* Conclusion à retourner */
+ vmpa2t addr; /* Autre emplacement à comparer*/
+
+ assert(G_IS_BINARY_CURSOR(cursor));
+
+ g_binary_cursor_retrieve(G_BINARY_CURSOR(cursor), &addr);
+
+ result = cmp_mrange_with_vmpa(&instr->range, &addr);
+
+ return result;
+
+}
+
+
+#endif
diff --git a/src/arch/instruction-ui.h b/src/arch/instruction-ui.h
new file mode 100644
index 0000000..62a52f2
--- /dev/null
+++ b/src/arch/instruction-ui.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instruction-ui.h - prototypes pour la gestion générique des instructions sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_INSTRUCTION_UI_H
+#define _ARCH_INSTRUCTION_UI_H
+
+
+#include "../glibext/generator.h"
+#include "../glibext/helpers.h"
+
+
+
+/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+
+
+/* Procède à l'initialisation de l'interface de génération. */
+void g_arch_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *);
+
+
+
+#endif /* _ARCH_INSTRUCTION_UI_H */
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index cd1e9c7..36bdecb 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* instruction.c - gestion générique des instructions
*
- * Copyright (C) 2008-2020 Cyrille Bagard
+ * Copyright (C) 2008-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,102 +26,93 @@
#include <assert.h>
#include <malloc.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <limits.h>
#include <string.h>
#include "instruction-int.h"
-#include "storage.h"
-#include "../analysis/storage/serialize-int.h"
-#include "../core/columns.h"
+#include "../common/leb128.h"
#include "../core/logs.h"
#include "../core/processors.h"
-#include "../glibext/gbinarycursor.h"
-#include "../glibext/linegen-int.h"
+#include "../glibext/serialize-int.h"
-/* Initialise la classe générique des instructions. */
-static void g_arch_instruction_class_init(GArchInstructionClass *);
-
-/* Initialise une instance d'opérande d'architecture. */
-static void g_arch_instruction_init(GArchInstruction *);
-/* Procède à l'initialisation de l'interface de génération. */
-static void g_arch_instruction_generator_init(GLineGeneratorInterface *);
-/* Procède à l'initialisation de l'interface de sérialisation. */
-static void g_arch_instruction_serializable_init(GSerializableObjectInterface *);
-
-/* Supprime toutes les références externes. */
-static void g_arch_instruction_dispose(GArchInstruction *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_arch_instruction_finalize(GArchInstruction *);
+/* ----------------------- DEFINITION GENERIQUE D'INSTRUCTION ----------------------- */
+/* Initialise la classe générique des instructions. */
+static void g_arch_instruction_class_init(GArchInstructionClass *);
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_arch_instruction_serializable_object_iface_init(GSerializableObjectInterface *);
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_arch_instruction_load_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
+/* Initialise une instance d'opérande d'architecture. */
+static void g_arch_instruction_init(GArchInstruction *);
-/* Sauvegarde toutes les destinations d'une instruction. */
-bool g_arch_instruction_store_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
+/* Supprime toutes les références externes. */
+static void g_arch_instruction_dispose(GObject *);
+/* Procède à la libération totale de la mémoire. */
+static void g_arch_instruction_finalize(GObject *);
+/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */
-/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+#define COMPACT_INS_LINK_MASK_DIR (1ul << (__WORDSIZE - 1))
+#define COMPACT_INS_LINK_MASK_TYPE 0xf
+#define COMPACT_INS_LINK_MASK (COMPACT_INS_LINK_MASK_DIR | COMPACT_INS_LINK_MASK_TYPE)
-/* Indique le nombre de ligne prêtes à être générées. */
-static size_t g_arch_instruction_count_lines(const GArchInstruction *);
+#define COMPACT_INS_LINK_FROM (0ul << (__WORDSIZE - 1))
+#define COMPACT_INS_LINK_TO (1ul << (__WORDSIZE - 1))
-#ifdef INCLUDE_GTK_SUPPORT
+#define COMPACT_INS_LINK_DIR(cl) (cl & COMPACT_INS_LINK_MASK_DIR)
+#define COMPACT_INS_LINK_PTR(cl) ((GArchInstruction *)(cl & ~COMPACT_INS_LINK_MASK))
+#define COMPACT_INS_LINK_TYPE(cl) (cl & COMPACT_INS_LINK_MASK_TYPE)
-/* Retrouve l'emplacement correspondant à une position donnée. */
-static void g_arch_instruction_compute_cursor(const GArchInstruction *, gint, size_t, size_t, GLineCursor **);
+#define MAKE_COMPACT_INS_LINK(d, i, t) \
+ (compact_ins_link_t)(d | (unsigned long)i | t)
-/* 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 *);
+/* Détermine si un type de lien existe dans une instruction. */
+static bool _g_arch_instruction_has_link(const GArchInstruction *, compact_ins_link_t, InstructionLinkType);
-#endif
+/* Détermine si un lien existe entre deux instructions. */
+static bool _g_arch_instruction_has_link_with(const GArchInstruction *, compact_ins_link_t, const GArchInstruction *);
-/* 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);
+/* Fournit la quantité d'instructions pointant vers une autre. */
+static size_t _g_arch_instruction_count_links(const GArchInstruction *, compact_ins_link_t);
-/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
-static void _g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
+/* Fournit les détails d'un lien donné avec une instruction. */
+static GArchInstruction *_g_arch_instruction_get_linked_instruction(const GArchInstruction *, size_t, compact_ins_link_t, InstructionLinkType *);
-/* Imprime dans une ligne de rendu le contenu représenté. */
-static void g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
-/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
+/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */
-/* Charge un contenu depuis une mémoire tampon. */
-static bool _g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
+/* Charge un objet depuis un flux de données. */
+static bool g_arch_instruction_load(GSerializableObject *, GObjectStorage *, int);
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
+/* Sauvegarde un objet dans un flux de données. */
+static bool g_arch_instruction_store(const GSerializableObject *, GObjectStorage *, int);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool _g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION GENERIQUE D'INSTRUCTION */
+/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour une instruction d'architecture. */
-G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_arch_instruction_generator_init)
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_instruction_serializable_init));
+G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_THICK_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_instruction_serializable_object_iface_init)
+ G_IMPLEMENT_INTERFACE_IF_SYM(g_token_generator_get_type, g_arch_instruction_ui_token_generator_iface_init));
+
/******************************************************************************
@@ -139,28 +130,20 @@ G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT,
static void g_arch_instruction_class_init(GArchInstructionClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
- GArchInstructionClass *instr; /* Encore une autre vision... */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_instruction_dispose;
- object->finalize = (GObjectFinalizeFunc)g_arch_instruction_finalize;
-
- instr = G_ARCH_INSTRUCTION_CLASS(klass);
-
- instr->print = (print_instruction_fc)_g_arch_instruction_print;
-
- instr->load = (load_instruction_fc)_g_arch_instruction_load;
- instr->store = (store_instruction_fc)_g_arch_instruction_store;
+ object->dispose = g_arch_instruction_dispose;
+ object->finalize = g_arch_instruction_finalize;
}
/******************************************************************************
* *
-* Paramètres : instr = instance à initialiser. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Initialise une instance d'instruction d'architecture. *
+* Description : Procède à l'initialisation de l'interface de sérialisation. *
* *
* Retour : - *
* *
@@ -168,27 +151,19 @@ static void g_arch_instruction_class_init(GArchInstructionClass *klass)
* *
******************************************************************************/
-static void g_arch_instruction_init(GArchInstruction *instr)
+static void g_arch_instruction_serializable_object_iface_init(GSerializableObjectInterface *iface)
{
- instr_extra_data_t *extra; /* Données insérées à modifier */
-
- extra = GET_ARCH_INSTR_EXTRA(instr);
-
- INIT_GOBJECT_EXTRA_LOCK(extra);
-
- instr->operands = NULL;
-
- instr->from = NULL;
- instr->to = NULL;
+ iface->load = g_arch_instruction_load;
+ iface->store = g_arch_instruction_store;
}
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
+* Paramètres : instr = instance à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de génération. *
+* Description : Initialise une instance d'instruction d'architecture. *
* *
* Retour : - *
* *
@@ -196,42 +171,22 @@ static void g_arch_instruction_init(GArchInstruction *instr)
* *
******************************************************************************/
-static void g_arch_instruction_generator_init(GLineGeneratorInterface *iface)
+static void g_arch_instruction_init(GArchInstruction *instr)
{
- 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;
-
-}
+ instr->rel_area = NULL;
+ instr->link_count = 0;
-/******************************************************************************
-* *
-* Paramètres : iface = interface GLib à initialiser. *
-* *
-* Description : Procède à l'initialisation de l'interface de sérialisation. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ instr->links = NULL;
-static void g_arch_instruction_serializable_init(GSerializableObjectInterface *iface)
-{
- iface->load = (load_serializable_object_cb)g_arch_instruction_load;
- iface->store = (store_serializable_object_cb)g_arch_instruction_store;
+ instr->operands = NULL;
}
/******************************************************************************
* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -241,43 +196,38 @@ static void g_arch_instruction_serializable_init(GSerializableObjectInterface *i
* *
******************************************************************************/
-static void g_arch_instruction_dispose(GArchInstruction *instr)
+static void g_arch_instruction_dispose(GObject *object)
{
+ GArchInstruction *instr; /* Version spécialisée */
size_t count; /* Nombre d'opérandes en place */
size_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à manipuler */
- g_arch_instruction_lock_operands(instr);
+ instr = G_ARCH_INSTRUCTION(object);
+
+ g_clear_object(&instr->rel_area);
+
+ g_arch_instruction_delete_all_links(instr);
- count = _g_arch_instruction_count_operands(instr);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+
+ count = g_arch_instruction_count_operands(instr);
for (i = 0; i < count; i++)
{
- op = _g_arch_instruction_get_operand(instr, 0);
+ op = g_arch_instruction_get_operand(instr, 0);
rem_item_from_flat_array(&instr->operands, 0, sizeof(GArchOperand *));
/**
* Une fois pour l'obtention, une autre pour la libération !
*/
- g_object_unref(G_OBJECT(op));
- g_object_unref(G_OBJECT(op));
+ unref_object(op);
+ unref_object(op);
}
- g_arch_instruction_unlock_operands(instr);
-
-#ifndef NDEBUG
- g_arch_instruction_lock_src(instr);
- assert(count_flat_array_items(instr->from) == 0);
- g_arch_instruction_unlock_src(instr);
-#endif
-
-#ifndef NDEBUG
- g_arch_instruction_lock_dest(instr);
- assert(count_flat_array_items(instr->to) == 0);
- g_arch_instruction_unlock_dest(instr);
-#endif
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
G_OBJECT_CLASS(g_arch_instruction_parent_class)->dispose(G_OBJECT(instr));
@@ -286,7 +236,7 @@ static void g_arch_instruction_dispose(GArchInstruction *instr)
/******************************************************************************
* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -296,38 +246,26 @@ static void g_arch_instruction_dispose(GArchInstruction *instr)
* *
******************************************************************************/
-static void g_arch_instruction_finalize(GArchInstruction *instr)
+static void g_arch_instruction_finalize(GObject *object)
{
- G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr));
+ GArchInstruction *instr; /* Version spécialisée */
-}
+ instr = G_ARCH_INSTRUCTION(object);
+ if (instr->links != NULL)
+ free(instr->links);
-/******************************************************************************
-* *
-* Paramètres : instr = instruction quelconque à consulter. *
-* *
-* Description : Indique l'encodage d'une instruction de façon détaillée. *
-* *
-* Retour : Description humaine de l'encodage utilisé. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-const char *g_arch_instruction_get_encoding(const GArchInstruction *instr)
-{
- return G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_encoding(instr);
+ G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr));
}
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à modifier. *
-* flag = drapeau d'information complémentaire à planter. *
+* Paramètres : instr = instance à initialiser pleinement. *
+* tid = identifiant associé au type d'instructions ciblé. *
* *
-* Description : Ajoute une information complémentaire à une instruction. *
+* Description : Met en place une instruction d'architecture. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -335,22 +273,18 @@ const char *g_arch_instruction_get_encoding(const GArchInstruction *instr)
* *
******************************************************************************/
-bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag)
+bool g_arch_instruction_create(GArchInstruction *instr, itid_t tid)
{
bool result; /* Bilan à retourner */
- instr_extra_data_t *extra; /* Données insérées à modifier */
+ instruction_extra_data_t extra; /* Données insérées à modifier */
- assert(flag <= AIF_HIGH_USER);
+ result = true;
extra = GET_ARCH_INSTR_EXTRA(instr);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = !(extra->flags & flag);
+ extra.tid = tid;
- extra->flags |= flag;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ SET_ARCH_INSTR_EXTRA(instr, &extra);
return result;
@@ -359,33 +293,24 @@ bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag)
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à modifier. *
-* flag = drapeau d'information complémentaire à planter. *
+* Paramètres : instr = instruction quelconque à consulter. *
* *
-* Description : Retire une information complémentaire à une instruction. *
+* Description : Fournit l'identifiant correspondant à un type d'instructions.*
* *
-* Retour : Bilan de l'opération. *
+* Retour : Identifiant unique par type d'instruction et architecture. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstrFlag flag)
+itid_t g_arch_instruction_get_type_id(const GArchInstruction *instr)
{
- bool result; /* Bilan à retourner */
- instr_extra_data_t *extra; /* Données insérées à modifier */
-
- assert(flag <= AIF_HIGH_USER);
+ itid_t result; /* Numéro à retourner */
+ instruction_extra_data_t extra; /* Données insérées à modifier */
extra = GET_ARCH_INSTR_EXTRA(instr);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = (extra->flags & flag);
-
- extra->flags &= ~flag;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = extra.tid;
return result;
@@ -395,30 +320,23 @@ bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstrFlag flag)
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à consulter. *
-* flag = drapeau d'information à rechercher. *
* *
-* Description : Détermine si une instruction possède un fanion particulier. *
+* Description : Indique l'encodage d'une instruction de façon détaillée. *
* *
-* Retour : Bilan de la détection. *
+* Retour : Description humaine de l'encodage utilisé. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag flag)
+char *g_arch_instruction_get_encoding(const GArchInstruction *instr)
{
- bool result; /* Bilan à retourner */
- instr_extra_data_t *extra; /* Données insérées à modifier */
-
- assert(flag <= AIF_HIGH_USER);
-
- extra = GET_ARCH_INSTR_EXTRA(instr);
-
- LOCK_GOBJECT_EXTRA(extra);
+ char *result; /* Encodage à retourner */
+ GArchInstructionClass *class; /* Classe des instructions */
- result = (extra->flags & flag);
+ class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = class->get_encoding(instr);
return result;
@@ -427,28 +345,24 @@ bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag fl
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à modifier. *
+* Paramètres : instr = instruction d'assemblage à consulter. *
* *
-* Description : Fournit les informations complémentaires d'une instruction. *
+* Description : Fournit le nom humain de l'instruction manipulée. *
* *
-* Retour : Eventuels drapeaux d'information complémentaire à plantés. *
+* Retour : Mot clef de bas niveau. *
* *
* Remarques : - *
* *
******************************************************************************/
-ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)
+char *g_arch_instruction_get_keyword(const GArchInstruction *instr)
{
- ArchInstrFlag result; /* Fanions à retourner */
- instr_extra_data_t *extra; /* Données insérées à modifier */
-
- extra = GET_ARCH_INSTR_EXTRA(instr);
-
- LOCK_GOBJECT_EXTRA(extra);
+ char *result; /* Etiquette à retourner */
+ GArchInstructionClass *class; /* Classe des instructions */
- result = extra->flags;
+ class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = class->get_keyword(instr);
return result;
@@ -457,10 +371,12 @@ ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à consulter. *
-* uid = identifiant unique par type d'instruction. *
+* Paramètres : instr = instruction quelconque à compléter. *
+* area = portion de binaire incluant l'instruction. *
+* start = adresse virtuelle et/ou position physique. *
+* length = taille de l'instruction. *
* *
-* Description : Définit l'identifiant unique pour un ensemble d'instructions.*
+* Description : Calcule la localisation d'une instruction. *
* *
* Retour : - *
* *
@@ -468,358 +384,214 @@ ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)
* *
******************************************************************************/
-void g_arch_instruction_set_unique_id(GArchInstruction *instr, itid_t uid)
+void g_arch_instruction_compute_range(GArchInstruction *instr, GBinaryPortion *area, const vmpa2t *start, phys_t length)
{
- instr_extra_data_t *extra; /* Données insérées à modifier */
+ const mrange_t *a_range; /* Couverture de la portion */
+ phys_t diff; /* Décalage à appliquer */
- extra = GET_ARCH_INSTR_EXTRA(instr);
-
- LOCK_GOBJECT_EXTRA(extra);
+ a_range = g_binary_portion_get_range(area);
- extra->uid = uid;
+ assert(mrange_contains_addr(a_range, start));
- UNLOCK_GOBJECT_EXTRA(extra);
+ diff = compute_vmpa_diff(get_mrange_addr(a_range), start);
-}
+ instr->rel_area = area;
+ ref_object(area);
-
-/******************************************************************************
-* *
-* Paramètres : instr = instruction quelconque à consulter. *
-* *
-* Description : Fournit l'identifiant unique pour un ensemble d'instructions.*
-* *
-* Retour : Identifiant unique par type d'instruction et architecture. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-itid_t g_arch_instruction_get_unique_id(const GArchInstruction *instr)
-{
- itid_t result; /* Numéro à retourner */
- instr_extra_data_t *extra; /* Données insérées à consulter*/
-
- extra = GET_ARCH_INSTR_EXTRA(instr);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = extra->uid;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- return result;
+ init_rel_mrange(&instr->rel_range, diff, length);
}
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à traiter. *
-* type = type de procédure à utiliser. *
-* proc = représentation de l'architecture utilisée. *
-* context = contexte associé à la phase de désassemblage. *
-* format = accès aux données du binaire d'origine. *
+* Paramètres : instr = instruction quelconque à consulter. *
+* range = localisation de l'instruction. [OUT] *
* *
-* Description : Complète un désassemblage accompli pour une instruction. *
+* Description : Fournit la place mémoire d'une instruction. *
* *
-* Retour : - *
+* Retour : Validité de la localisation : existence d'une définition ? *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_arch_instruction_call_hook(GArchInstruction *instr, InstrProcessHook type, GArchProcessor *proc, GProcContext *context, GExeFormat *format)
+bool g_arch_instruction_get_range(const GArchInstruction *instr, mrange_t *range)
{
- GArchInstructionClass *class; /* Classe des instructions */
+ bool result; /* Statut à retourner */
+ const mrange_t *a_range; /* Couverture de la portion */
+ vmpa2t start; /* Position de départ complète */
- class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
+ result = (instr->rel_area != NULL);
- if (class->call_hook != NULL)
- class->call_hook(instr, type, proc, context, format);
+ if (result)
+ {
+ a_range = g_binary_portion_get_range(instr->rel_area);
-}
+ copy_vmpa(&start, get_mrange_addr(a_range));
+ advance_vmpa(&start, get_rel_mrange_offset(&instr->rel_range));
+ init_mrange(range, &start, get_rel_mrange_length(&instr->rel_range));
-/******************************************************************************
-* *
-* Paramètres : instr = instruction quelconque à modifier. *
-* address = adresse virtuelle et/ou position physique. *
-* length = taille de l'instruction. *
-* *
-* Description : Définit la localisation d'une instruction. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ }
-void g_arch_instruction_set_range(GArchInstruction *instr, const mrange_t *range)
-{
- copy_mrange(&instr->range, range);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à consulter. *
+* Paramètres : instr = instruction à venir modifier. *
+* flag = drapeau d'information complémentaire à planter. *
* *
-* Description : Fournit la place mémoire d'une instruction. *
+* Description : Ajoute une information complémentaire à une instruction. *
* *
-* Retour : Zone mémoire couverte par l'instruction. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-const mrange_t *g_arch_instruction_get_range(const GArchInstruction *instr)
+bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstructionFlag flag)
{
- return &instr->range;
+ bool result; /* Bilan à retourner */
+ instruction_extra_data_t extra; /* Données insérées à modifier */
-}
+ assert(flag <= AIF_HIGH_USER);
+ extra = GET_ARCH_INSTR_EXTRA(instr);
+ result = !(extra.flags & flag);
-/******************************************************************************
-* *
-* Paramètres : instr = instruction quelconque à consulter. *
-* offset = position physique dans le code binaire/NULL. [OUT] *
-* length = taille de l'instruction ou NULL. [OUT] *
-* address = adresse virtuelle ou position physique/NULL. [OUT] *
-* *
-* Description : Fournit la localisation d'une instruction. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ extra.flags |= flag;
-void g_arch_instruction_get_location(const GArchInstruction *instr, off_t *offset, off_t *length, vmpa_t *address)
-{
- //if (offset != NULL) *offset = instr->offset;
- //if (length != NULL) *length = instr->length;
+ SET_ARCH_INSTR_EXTRA(instr, &extra);
- //if (address != NULL) *address = instr->address;
+ return result;
}
-
/******************************************************************************
* *
-* Paramètres : instr = instruction à consulter. *
-* rregs = liste des rgistres lus. [OUT] *
-* rcount = nombre de registres lus. [OUT] *
-* wregs = liste des rgistres écrits. [OUT] *
-* wcount = nombre de registres écrits. [OUT] *
+* Paramètres : instr = instruction à venir modifier. *
+* flag = drapeau d'information complémentaire à planter. *
* *
-* Description : Liste les registres lus et écrits par l'instruction. *
+* Description : Retire une information complémentaire à une instruction. *
* *
-* Retour : - *
+* Retour : Bilan de l'opération. *
* *
-* Remarques : Les compteurs de références sont à décrémenter après usage ! *
+* Remarques : - *
* *
******************************************************************************/
-void g_arch_instruction_get_rw_registers(const GArchInstruction *instr, GArchRegister ***rregs, size_t *rcount, GArchRegister ***wregs, size_t *wcount)
+bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstructionFlag flag)
{
-#if 0
+ bool result; /* Bilan à retourner */
+ instruction_extra_data_t extra; /* Données insérées à modifier */
- size_t i; /* Boucle de parcours */
+ assert(flag <= AIF_HIGH_USER);
- *rregs = NULL;
- *rcount = 0;
- *wregs = NULL;
- *wcount = 0;
+ extra = GET_ARCH_INSTR_EXTRA(instr);
- instr->get_rw_regs(instr, rregs, rcount, wregs, wcount);
+ result = (extra.flags & flag);
- for (i = 0; i < *rcount; i++)
- g_object_ref(G_OBJECT((*rregs)[i]));
+ extra.flags &= ~flag;
- for (i = 0; i < *wcount; i++)
- g_object_ref(G_OBJECT((*wregs)[i]));
+ SET_ARCH_INSTR_EXTRA(instr, &extra);
-#endif
+ return result;
}
-
-/* ---------------------------------------------------------------------------------- */
-/* MANIPULATION DES OPERANDES */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : instr = instruction à mettre à jour. *
+* Paramètres : instr = instruction à venir consulter. *
+* flag = drapeau d'information à rechercher. *
* *
-* Description : Verrouille les accès à la liste des opérandes. *
+* Description : Détermine si une instruction possède un fanion particulier. *
* *
-* Retour : - *
+* Retour : Bilan de la détection. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_arch_instruction_lock_operands(GArchInstruction *instr)
+bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstructionFlag flag)
{
- lock_flat_array(&instr->operands);
+ bool result; /* Bilan à retourner */
+ instruction_extra_data_t extra; /* Données insérées à modifier */
-}
+ assert(flag <= AIF_HIGH_USER);
+ extra = GET_ARCH_INSTR_EXTRA(instr);
-/******************************************************************************
-* *
-* Paramètres : instr = instruction à mettre à jour. *
-* *
-* Description : Déverrouille les accès à la liste des opérandes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ result = (extra.flags & flag);
-void g_arch_instruction_unlock_operands(GArchInstruction *instr)
-{
- unlock_flat_array(&instr->operands);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : instr = instance à mettre à jour. *
-* operand = instruction à venir associer. *
+* Paramètres : instr = instruction à venir consulter. *
* *
-* Description : Attache un opérande supplémentaire à une instruction. *
+* Description : Fournit les particularités de l'instruction. *
* *
-* Retour : - *
+* Retour : Somme de tous les fanions associés à l'opérande. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_arch_instruction_attach_extra_operand(GArchInstruction *instr, GArchOperand *operand)
+ArchInstructionFlag g_arch_instruction_get_flags(const GArchInstruction *instr)
{
- GSingletonFactory *factory; /* Unise à instances uniques */
- GArchOperand *singleton; /* Instance retenue */
-
- factory = get_operands_factory();
-
- singleton = G_ARCH_OPERAND(g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(operand)));
-
- g_object_unref(G_OBJECT(operand));
- g_object_unref(G_OBJECT(factory));
-
- g_arch_instruction_lock_operands(instr);
-
- add_item_to_flat_array(&instr->operands, &singleton, sizeof(GArchOperand *));
-
- g_arch_instruction_unlock_operands(instr);
+ ArchInstructionFlag result; /* Fanions à retourner */
+ instruction_extra_data_t extra; /* Données insérées à modifier */
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : instr = instance à consulter. *
-* *
-* Description : Indique la quantité d'opérandes présents dans l'instruction. *
-* *
-* Retour : Nombre d'opérandes attachés. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ extra = GET_ARCH_INSTR_EXTRA(instr);
-size_t _g_arch_instruction_count_operands(const GArchInstruction *instr)
-{
- size_t result; /* Décompte à retourner */
-
- result = count_flat_array_items(instr->operands);
+ result = extra.flags;
return result;
}
-/******************************************************************************
-* *
-* Paramètres : instr = instance à consulter. *
-* index = indice de l'opérande concerné. *
-* *
-* Description : Fournit un opérande donné d'une instruction. *
-* *
-* Retour : Opérande trouvée. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GArchOperand *_g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index)
-{
- GArchOperand *result; /* Opérande à retourner */
- GArchOperand **ptr; /* Adresse dans le tableau */
-
- ptr = get_flat_array_item(instr->operands, index, sizeof(GArchOperand *));
-
- result = *ptr;
-
- g_object_ref(G_OBJECT(result));
-
- return result;
-}
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : instr = instance à mettre à jour. *
-* old = ancienne opérande à détacher. *
-* new = nouvelle opérande à attacher. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* dir = direction du lien recherché. *
+* type = type de lien à détecter. *
* *
-* Description : Remplace un opérande d'une instruction par un autre. *
+* Description : Détermine si un type de lien existe dans une instruction. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Bilan du statut courant de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *old, GArchOperand *new)
+static bool _g_arch_instruction_has_link(const GArchInstruction *instr, compact_ins_link_t dir, InstructionLinkType type)
{
bool result; /* Bilan à retourner */
- size_t count; /* Nombre d'opérandes en place */
- size_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à manipuler */
-
- result = false;
-
- count = _g_arch_instruction_count_operands(instr);
-
- for (i = 0; i < count && !result; i++)
- {
- op = _g_arch_instruction_get_operand(instr, i);
+ uint16_t i; /* Boucle de parcours */
- result = (op == old);
-
- g_object_unref(G_OBJECT(op));
-
- }
-
- if (result)
- {
- rpl_item_in_flat_array(instr->operands, i - 1, &new, sizeof(GArchOperand *));
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- g_object_unref(G_OBJECT(old));
+ result = false;
- }
+ for (i = 0; i < instr->link_count && !result; i++)
+ result = COMPACT_INS_LINK_DIR(instr->links[i]) == dir;
return result;
@@ -828,45 +600,22 @@ bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *
/******************************************************************************
* *
-* Paramètres : instr = instance à mettre à jour. *
-* target = instruction à venir dissocier. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* type = type de lien à détecter. *
* *
-* Description : Détache un opérande liée d'une instruction. *
+* Description : Détermine si un type de lien amène à une instruction. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Bilan du statut courant de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *target)
+bool g_arch_instruction_has_src_link(const GArchInstruction *instr, InstructionLinkType type)
{
bool result; /* Bilan à retourner */
- size_t count; /* Nombre d'opérandes en place */
- size_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à manipuler */
-
- result = false;
-
- count = _g_arch_instruction_count_operands(instr);
- for (i = 0; i < count && !result; i++)
- {
- op = _g_arch_instruction_get_operand(instr, i);
-
- result = (op == target);
-
- g_object_unref(G_OBJECT(op));
-
- }
-
- if (result)
- {
- rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *));
-
- g_object_unref(G_OBJECT(target));
-
- }
+ result = _g_arch_instruction_has_link(instr, COMPACT_INS_LINK_FROM, type);
return result;
@@ -875,78 +624,22 @@ bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *t
/******************************************************************************
* *
-* Paramètres : instr = instance à consulter. *
-* target = instruction à venir retrouver. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* type = type de lien à détecter. *
* *
-* Description : Détermine le chemin conduisant à un opérande. *
+* Description : Détermine si un type de lien émerge d'une instruction. *
* *
-* Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. *
+* Retour : Bilan du statut courant de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
-char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target)
+bool g_arch_instruction_has_dest_link(const GArchInstruction *instr, InstructionLinkType type)
{
- char *result; /* Chemin à retourner */
- size_t count; /* Nombre d'opérandes en place */
- size_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à manipuler */
- int ret; /* Bilan d'une construction */
- char *sub_path; /* Sous-chemin emprunté */
-
- result = NULL;
-
- g_arch_instruction_lock_operands(instr);
-
- count = _g_arch_instruction_count_operands(instr);
-
- /* Première passe : accès direct */
-
- for (i = 0; i < count && result == NULL; i++)
- {
- op = _g_arch_instruction_get_operand(instr, i);
-
- if (op == target)
- {
- ret = asprintf(&result, "%zu", i);
- if (ret == -1)
- {
- LOG_ERROR_N("asprintf");
- result = NULL;
- }
- }
-
- g_object_unref(G_OBJECT(op));
-
- }
-
- /* Seconde passe : accès profond */
-
- for (i = 0; i < count && result == NULL; i++)
- {
- op = _g_arch_instruction_get_operand(instr, i);
-
- sub_path = g_arch_operand_find_inner_operand_path(op, target);
-
- if (sub_path != NULL)
- {
- ret = asprintf(&result, "%zu:%s", i, sub_path);
- if (ret == -1)
- {
- LOG_ERROR_N("asprintf");
- result = NULL;
- }
-
- free(sub_path);
-
- }
-
- g_object_unref(G_OBJECT(op));
-
- }
+ bool result; /* Bilan à retourner */
- g_arch_instruction_unlock_operands(instr);
+ result = _g_arch_instruction_has_link(instr, COMPACT_INS_LINK_TO, type);
return result;
@@ -955,104 +648,65 @@ char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchO
/******************************************************************************
* *
-* Paramètres : instr = instance à consulter. *
-* path = chemin d'accès à un opérande à retrouver. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* dir = direction du lien recherché. *
+* linked = seconde instruction à considérer. *
* *
-* Description : Obtient l'opérande correspondant à un chemin donné. *
+* Description : Détermine si un lien existe entre deux instructions. *
* *
-* Retour : Opérande trouvé ou NULL en cas d'échec. *
+* Retour : Bilan du statut courant de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
-GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path)
+static bool _g_arch_instruction_has_link_with(const GArchInstruction *instr, compact_ins_link_t dir, const GArchInstruction *linked)
{
- GArchOperand *result; /* Opérande trouvée à renvoyer */
- size_t index; /* Indice de l'opérande visé */
- char *end; /* Poursuite du parcours ? */
- GArchOperand *found; /* Opérande trouvé */
-
- result = NULL;
-
- g_arch_instruction_lock_operands(instr);
-
- /* Recherche au premier niveau */
-
- index = strtoul(path, &end, 10);
-
- if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL))
- {
- LOG_ERROR_N("strtoul");
- goto done;
- }
-
- found = _g_arch_instruction_get_operand(instr, index);
- if (found == NULL) goto done;
-
- if (*end == '\0')
- {
- result = found;
- goto done;
- }
-
- /* Recherche en profondeur */
-
- assert(*end == ':');
-
- result = g_arch_operand_get_inner_operand_from_path(found, end + 1);
+ bool result; /* Bilan à retourner */
+ uint16_t i; /* Boucle de parcours */
- g_object_unref(G_OBJECT(found));
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- done:
+ result = false;
- g_arch_instruction_unlock_operands(instr);
+ for (i = 0; i < instr->link_count && !result; i++)
+ result = COMPACT_INS_LINK_PTR(instr->links[i]) == linked;
return result;
}
-
-/* ---------------------------------------------------------------------------------- */
-/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : instr = instruction à mettre à jour. *
-* src = sélection de l'extrémité à traiter. *
-* lock = indique le sens du verrouillage à mener. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* src = seconde instruction à considérer. *
* *
-* Description : Met à disposition un encadrement des accès aux liens. *
+* Description : Détermine si une instruction est source d'une autre. *
* *
-* Retour : - *
+* Retour : Bilan du statut courant de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_arch_instruction_lock_unlock_links(GArchInstruction *instr, bool src, bool lock)
+bool g_arch_instruction_has_src_link_with(const GArchInstruction *instr, const GArchInstruction *src)
{
- flat_array_t **array; /* Choix du tableau ciblé */
+ bool result; /* Bilan à retourner */
- array = (src ? &instr->from : &instr->to);
+ result = _g_arch_instruction_has_link_with(instr, COMPACT_INS_LINK_FROM, src);
- if (lock)
- lock_flat_array(array);
- else
- unlock_flat_array(array);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
-* type = type de lien à détecter. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* dest = seconde instruction à considérer. *
* *
-* Description : Détermine si un type de lien existe dans une instruction. *
+* Description : Détermine si une instruction est destination d'une autre. *
* *
* Retour : Bilan du statut courant de l'instruction. *
* *
@@ -1060,30 +714,11 @@ void g_arch_instruction_lock_unlock_links(GArchInstruction *instr, bool src, boo
* *
******************************************************************************/
-bool g_arch_instruction_has_link(GArchInstruction *instr, InstructionLinkType type)
+bool g_arch_instruction_has_dest_link_with(const GArchInstruction *instr, const GArchInstruction *dest)
{
bool result; /* Bilan à retourner */
- size_t count; /* Nombre de liens à parcourir */
- size_t i; /* Boucle de parcours */
- const instr_link_t *dlink; /* Définition de destination */
-
- result = false;
-
- g_arch_instruction_lock_dest(instr);
- count = g_arch_instruction_count_destinations(instr);
-
- for (i = 0; i < count && !result; i++)
- {
- dlink = g_arch_instruction_get_destination(instr, i);
-
- result = (dlink->type == type);
-
- unref_instr_link(dlink);
-
- }
-
- g_arch_instruction_unlock_dest(instr);
+ result = _g_arch_instruction_has_link_with(instr, COMPACT_INS_LINK_TO, dest);
return result;
@@ -1092,54 +727,53 @@ bool g_arch_instruction_has_link(GArchInstruction *instr, InstructionLinkType ty
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
+* Paramètres : instr = instruction dont les informations sont à manipuler. *
* dest = ligne visée par la liaison (côté destination). *
+* type = type de lien à construire. *
* *
-* Description : Détermine si un lien est déjà établi entre deux instructions.*
+* Description : Etablit un lien entre deux instructions. *
* *
-* Retour : Bilan de l'état actuel des liaisons. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_arch_instruction_has_link_to(GArchInstruction *instr, const GArchInstruction *dest)
+void g_arch_instruction_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type)
{
- bool result; /* Bilan à retourner */
- size_t count; /* Nombre de liens à parcourir */
- size_t i; /* Boucle de parcours */
- const instr_link_t *dlink; /* Définition de destination */
+ compact_ins_link_t new_from; /* Nouvel enregistrement #1 */
+ compact_ins_link_t new_to; /* Nouvel enregistrement #2 */
- result = false;
+ new_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, type);
+ ref_object(instr);
- g_arch_instruction_lock_dest(instr);
+ new_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, type);
+ ref_object(dest);
- count = g_arch_instruction_count_destinations(instr);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+ g_thick_object_lock(G_THICK_OBJECT(dest));
- for (i = 0; i < count && !result; i++)
- {
- dlink = g_arch_instruction_get_destination(instr, i);
-
- result = (dlink->linked == dest);
+ dest->links = realloc(dest->links, ++dest->link_count * sizeof(compact_ins_link_t));
- unref_instr_link(dlink);
+ dest->links[dest->link_count - 1] = new_from;
- }
+ instr->links = realloc(instr->links, ++instr->link_count * sizeof(compact_ins_link_t));
- g_arch_instruction_unlock_dest(instr);
+ instr->links[instr->link_count - 1] = new_to;
- return result;
+ g_thick_object_unlock(G_THICK_OBJECT(dest));
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
}
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
+* Paramètres : instr = instruction dont les informations sont à manipuler. *
* dest = ligne visée par la liaison (côté destination). *
* type = type de lien à construire. *
* *
-* Description : Etablit un lien entre deux instructions. *
+* Description : Supprime un lien entre deux instructions. *
* *
* Retour : - *
* *
@@ -1147,43 +781,59 @@ bool g_arch_instruction_has_link_to(GArchInstruction *instr, const GArchInstruct
* *
******************************************************************************/
-void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type)
+void g_arch_instruction_unlink(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type)
{
- instr_link_t new_src; /* Nouveau lien à définir #1 */
- instr_link_t new_dst; /* Nouveau lien à définir #2 */
+ compact_ins_link_t old_from; /* Ancien enregistrement #1 */
+ compact_ins_link_t old_to; /* Ancien enregistrement #2 */
+ uint16_t i_from; /* Boucle de parcours #1 */
+ uint16_t i_to; /* Boucle de parcours #2 */
+ bool status; /* Bilan des recherches */
+
+ old_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, type);
+
+ old_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, type);
- /* Côté destination */
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+ g_thick_object_lock(G_THICK_OBJECT(dest));
- new_src.linked = instr;
- new_src.type = type;
+ for (i_from = 0; i_from < dest->link_count; i_from++)
+ if (dest->links[i_from] == old_from)
+ break;
- ref_instr_link((&new_src));
+ for (i_to = 0; i_to < instr->link_count; i_to++)
+ if (instr->links[i_to] == old_to)
+ break;
- /* Côté point de départ */
+ assert((i_from < dest->link_count && i_to < instr->link_count)
+ || (i_from == dest->link_count && i_to == instr->link_count));
- new_dst.linked = dest;
- new_dst.type = type;
+ status = (i_from < dest->link_count && i_to < instr->link_count);
- ref_instr_link((&new_dst));
+ if (status)
+ {
+ if ((i_from + 1) < dest->link_count)
+ memmove(&dest->links[i_from], &dest->links[i_from + 1],
+ (dest->link_count - i_from - 1) * sizeof(compact_ins_link_t));
- /* Ajout dans le respect d'une cohérence globale */
+ dest->links = realloc(dest->links, --dest->link_count * sizeof(compact_ins_link_t));
- g_arch_instruction_lock_src(dest);
- g_arch_instruction_lock_dest(instr);
+ if ((i_to + 1) < instr->link_count)
+ memmove(&instr->links[i_to], &instr->links[i_to + 1],
+ (instr->link_count - i_to - 1) * sizeof(compact_ins_link_t));
- add_item_to_flat_array(&dest->from, &new_src, sizeof(instr_link_t));
+ instr->links = realloc(instr->links, --instr->link_count * sizeof(compact_ins_link_t));
- add_item_to_flat_array(&instr->to, &new_dst, sizeof(instr_link_t));
+ }
- g_arch_instruction_unlock_dest(instr);
- g_arch_instruction_unlock_src(dest);
+ g_thick_object_unlock(G_THICK_OBJECT(dest));
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
}
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
+* Paramètres : instr = instruction dont les informations sont à manipuler. *
* dest = ligne visée par la liaison (côté destination). *
* old = ancien type de lien construit. *
* new = nouveau type de lien à construire. *
@@ -1199,67 +849,43 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des
bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType old, InstructionLinkType new)
{
bool result; /* Bilan à retourner */
- size_t count; /* Raccourci pour la lecture */
- size_t i; /* Boucle de parcours */
- instr_link_t *slink; /* Définition de source */
- instr_link_t *dlink; /* Définition de destination */
-
- result = false;
+ compact_ins_link_t old_from; /* Ancien enregistrement #1 */
+ compact_ins_link_t new_from; /* Nouvel enregistrement #1 */
+ compact_ins_link_t old_to; /* Ancien enregistrement #2 */
+ compact_ins_link_t new_to; /* Nouvel enregistrement #2 */
+ uint16_t i_from; /* Boucle de parcours #1 */
+ uint16_t i_to; /* Boucle de parcours #2 */
- /**
- * Note : pour la récupération des liens de sources et de destinations,
- * on n'utilise pas les fonctions g_arch_instruction_get_(source|destination)(),
- * qui renvoient un pointeur non modifiable.
- *
- * On a en effet besoin de modifier le type de lien.
- */
+ old_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, old);
+ new_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, new);
+ old_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, old);
+ new_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, new);
- g_arch_instruction_lock_src(dest);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+ g_thick_object_lock(G_THICK_OBJECT(dest));
- /* Côté destination */
-
- count = g_arch_instruction_count_sources(dest);
-
- for (i = 0; i < count; i++)
- {
- slink = get_flat_array_item(dest->from, i, sizeof(instr_link_t));
-
- if (slink->linked == instr && slink->type == old)
+ for (i_from = 0; i_from < dest->link_count; i_from++)
+ if (dest->links[i_from] == old_from)
break;
- }
-
- if (i == count)
- goto gaicl_exit;
+ for (i_to = 0; i_to < instr->link_count; i_to++)
+ if (instr->links[i_to] == old_to)
+ break;
- /* Côté point de départ */
+ assert((i_from < dest->link_count && i_to < instr->link_count)
+ || (i_from == dest->link_count && i_to == instr->link_count));
- count = g_arch_instruction_count_destinations(instr);
+ result = (i_from < dest->link_count && i_to < instr->link_count);
- for (i = 0; i < count; i++)
+ if (result)
{
- dlink = get_flat_array_item(instr->to, i, sizeof(instr_link_t));
-
- if (dlink->linked == dest && dlink->type == old)
- break;
-
+ dest->links[i_from] = new_from;
+ instr->links[i_to] = new_to;
}
- if (i == count)
- goto gaicl_exit;
-
- /* Si les deux extrémités sont raccord... */
-
- slink->type = new;
-
- dlink->type = new;
-
- result = true;
-
- gaicl_exit:
-
- g_arch_instruction_unlock_src(dest);
+ g_thick_object_unlock(G_THICK_OBJECT(dest));
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
return result;
@@ -1280,116 +906,92 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d
void g_arch_instruction_delete_all_links(GArchInstruction *instr)
{
- instr_link_t *link_src; /* Lien à supprimer #2 */
- GArchInstruction *other; /* Instruction de l'autre bout */
- size_t count; /* Quantié de liens présents */
- size_t i; /* Boucle de parcours */
- instr_link_t *link_dst; /* Lien à supprimer #1 */
+ GArchInstruction *linked; /* Autre instruction liée */
+ InstructionLinkType type; /* Type de liaison */
- /* Coté sources */
+ g_thick_object_lock(G_THICK_OBJECT(instr));
- g_arch_instruction_lock_src(instr);
-
- while (count_flat_array_items(instr->from) > 0)
+ while (g_arch_instruction_count_src_links(instr) > 0)
{
- link_src = get_flat_array_item(instr->from, 0, sizeof(instr_link_t));
-
- other = link_src->linked;
+ linked = g_arch_instruction_get_linked_source(instr, 0, &type);
- g_arch_instruction_lock_dest(other);
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
- count = count_flat_array_items(other->to);
+ g_arch_instruction_unlink(linked, instr, type);
- for (i = 0; i < count; i++)
- {
- link_dst = get_flat_array_item(other->to, i, sizeof(instr_link_t));
+ g_thick_object_lock(G_THICK_OBJECT(instr));
- if (link_dst->linked == instr && link_dst->type == link_src->type)
- {
- unref_instr_link(link_dst);
-
- rem_item_from_flat_array(&other->to, i, sizeof(instr_link_t));
-
- break;
-
- }
-
- }
-
- assert(i < count);
-
- g_arch_instruction_unlock_dest(other);
-
- unref_instr_link(link_src);
-
- rem_item_from_flat_array(&instr->from, 0, sizeof(instr_link_t));
+ unref_object(linked);
}
- g_arch_instruction_unlock_src(instr);
-
- /* Coté destinations */
-
- g_arch_instruction_lock_dest(instr);
-
- while (count_flat_array_items(instr->to) > 0)
+ while (g_arch_instruction_count_dest_links(instr) > 0)
{
- link_dst = get_flat_array_item(instr->to, 0, sizeof(instr_link_t));
+ linked = g_arch_instruction_get_linked_destination(instr, 0, &type);
- other = link_dst->linked;
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
- g_arch_instruction_lock_src(other);
+ g_arch_instruction_unlink(instr, linked, type);
- count = count_flat_array_items(other->from);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
- for (i = 0; i < count; i++)
- {
- link_src = get_flat_array_item(other->from, i, sizeof(instr_link_t));
+ unref_object(linked);
- if (link_src->linked == instr && link_src->type == link_dst->type)
- {
- unref_instr_link(link_src);
-
- rem_item_from_flat_array(&other->from, i, sizeof(instr_link_t));
+ }
- break;
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
- }
+}
- }
- assert(i < count);
+/******************************************************************************
+* *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* dir = direction des liens à considérer. *
+* *
+* Description : Fournit la quantité d'instructions pointant vers une autre. *
+* *
+* Retour : Nombre de ces liens. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- g_arch_instruction_unlock_src(other);
+static size_t _g_arch_instruction_count_links(const GArchInstruction *instr, compact_ins_link_t dir)
+{
+ size_t result; /* Nombre de liens à renvoyer */
+ uint16_t i; /* Boucle de parcours */
- unref_instr_link(link_dst);
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- rem_item_from_flat_array(&instr->to, 0, sizeof(instr_link_t));
+ result = 0;
- }
+ for (i = 0; i < instr->link_count; i++)
+ if (COMPACT_INS_LINK_DIR(instr->links[i]) == dir)
+ result++;
- g_arch_instruction_unlock_dest(instr);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
* *
-* Description : Fournit la quantité d'instructions pointant vers une autre. *
+* Description : Fournit la quantité d'instructions placées en source. *
* *
-* Retour : Nombre de ces origines. *
+* Retour : Nombre de ces liens. *
* *
* Remarques : - *
* *
******************************************************************************/
-size_t g_arch_instruction_count_sources(const GArchInstruction *instr)
+size_t g_arch_instruction_count_src_links(const GArchInstruction *instr)
{
size_t result; /* Nombre de liens à renvoyer */
- result = count_flat_array_items(instr->from);
+ result = _g_arch_instruction_count_links(instr, COMPACT_INS_LINK_FROM);
return result;
@@ -1398,24 +1000,21 @@ size_t g_arch_instruction_count_sources(const GArchInstruction *instr)
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
-* index = indice de l'élément à retrouver. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
* *
-* Description : Fournit les détails d'une origine d'une instruction donnée. *
+* Description : Fournit la quantité d'instructions placées en destination. *
* *
-* Retour : Lien déterminé vers une instruction d'origine. *
+* Retour : Nombre de ces liens. *
* *
* Remarques : - *
* *
******************************************************************************/
-const instr_link_t *g_arch_instruction_get_source(GArchInstruction *instr, size_t index)
+size_t g_arch_instruction_count_dest_links(const GArchInstruction *instr)
{
- instr_link_t *result; /* Détails présents à renvoyer */
-
- result = get_flat_array_item(instr->from, index, sizeof(instr_link_t));
+ size_t result; /* Nombre de liens à renvoyer */
- ref_instr_link(result);
+ result = _g_arch_instruction_count_links(instr, COMPACT_INS_LINK_TO);
return result;
@@ -1424,43 +1023,47 @@ const instr_link_t *g_arch_instruction_get_source(GArchInstruction *instr, size_
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
-* count = quantié de liens présents. [OUT] *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* index = indice de l'élément à retrouver. *
+* dir = direction des liens à considérer. *
+* type = type de lien enregistré. [OUT] *
* *
-* Description : Fournit tous les détails d'origine d'une instruction donnée. *
+* Description : Fournit les détails d'un lien donné avec une instruction. *
* *
-* Retour : Liens vers des instructions d'origine à libérer. *
+* Retour : Autre instruction pointée par l'instruction, voire NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-instr_link_t *g_arch_instruction_get_sources(GArchInstruction *instr, size_t *count)
+static GArchInstruction *_g_arch_instruction_get_linked_instruction(const GArchInstruction *instr, size_t index, compact_ins_link_t dir, InstructionLinkType *type)
{
- instr_link_t *result; /* Détails présents à renvoyer */
- size_t i; /* Boucle de parcours */
- const instr_link_t *link; /* Lien à fournir */
-
- g_arch_instruction_lock_src(instr);
+ GArchInstruction *result; /* Instance ciblée à renvoyer */
+ uint16_t i; /* Boucle de parcours */
- *count = g_arch_instruction_count_sources(instr);
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- if (*count == 0)
- result = NULL;
+ result = NULL;
+ *type = ILT_COUNT;
- else
+ for (i = 0; i < instr->link_count; i++)
{
- result = (instr_link_t *)malloc(*count * sizeof(instr_link_t));
+ if (COMPACT_INS_LINK_DIR(instr->links[i]) != dir)
+ continue;
- for (i = 0; i < *count; i++)
+ if (index == 0)
{
- link = g_arch_instruction_get_source(instr, i);
- memcpy(&result[i], link, sizeof(instr_link_t));
+ result = COMPACT_INS_LINK_PTR(instr->links[i]);
+ *type = COMPACT_INS_LINK_TYPE(instr->links[i]);
}
+ else
+ index--;
+
}
- g_arch_instruction_unlock_src(instr);
+ if (result != NULL)
+ ref_object(result);
return result;
@@ -1469,21 +1072,23 @@ instr_link_t *g_arch_instruction_get_sources(GArchInstruction *instr, size_t *co
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
+* index = indice de l'élément à retrouver. *
+* type = type de lien enregistré. [OUT] *
* *
-* Description : Donne le nombre d'instructions non naturellement suivantes. *
+* Description : Fournit les détails d'une source donnée d'une instruction. *
* *
-* Retour : Nombre de ces destinations. *
+* Retour : Autre instruction pointée par l'instruction, voire NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-size_t g_arch_instruction_count_destinations(const GArchInstruction *instr)
+GArchInstruction *g_arch_instruction_get_linked_source(const GArchInstruction *instr, size_t index, InstructionLinkType *type)
{
- size_t result; /* Nombre de liens à renvoyer */
+ GArchInstruction *result; /* Instance ciblée à renvoyer */
- result = count_flat_array_items(instr->to);
+ result = _g_arch_instruction_get_linked_instruction(instr, index, COMPACT_INS_LINK_FROM, type);
return result;
@@ -1492,71 +1097,54 @@ size_t g_arch_instruction_count_destinations(const GArchInstruction *instr)
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
+* Paramètres : instr = instruction dont les liens sont à consulter. *
* index = indice de l'élément à retrouver. *
+* type = type de lien enregistré. [OUT] *
* *
-* Description : Fournit les détails d'une destination d'une instruction. *
+* Description : Fournit les détails d'une destination donnée d'une instruct. *
* *
-* Retour : Lien déterminé vers une instruction de destination. *
+* Retour : Autre instruction pointée par l'instruction, voire NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-const instr_link_t *g_arch_instruction_get_destination(GArchInstruction *instr, size_t index)
+GArchInstruction *g_arch_instruction_get_linked_destination(const GArchInstruction *instr, size_t index, InstructionLinkType *type)
{
- instr_link_t *result; /* Détails présents à renvoyer */
-
- result = get_flat_array_item(instr->to, index, sizeof(instr_link_t));
+ GArchInstruction *result; /* Instance ciblée à renvoyer */
- ref_instr_link(result);
+ result = _g_arch_instruction_get_linked_instruction(instr, index, COMPACT_INS_LINK_TO, type);
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION DES OPERANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
-* type = type de lien recherché. *
+* Paramètres : instr = instance à consulter. *
* *
-* Description : Fournit la destination d'une instruction et d'un type donné. *
+* Description : Indique la quantité d'opérandes présents dans l'instruction. *
* *
-* Retour : Instruction de destination trouvée ou NULL. *
+* Retour : Nombre d'opérandes attachés. *
* *
* Remarques : - *
* *
******************************************************************************/
-GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *instr, InstructionLinkType type)
+size_t g_arch_instruction_count_operands(const GArchInstruction *instr)
{
- GArchInstruction *result; /* Résultat à remonter */
- size_t count; /* Nombre de liens à parcourir */
- size_t i; /* Boucle de parcours */
- const instr_link_t *dest; /* Destination à étudier */
-
- result = NULL;
-
- g_arch_instruction_lock_dest(instr);
-
- count = g_arch_instruction_count_destinations(instr);
-
- for (i = 0; i < count && result == NULL; i++)
- {
- dest = g_arch_instruction_get_destination(instr, i);
-
- if (dest->type == type)
- {
- result = dest->linked;
- g_object_ref(G_OBJECT(result));
- }
+ size_t result; /* Décompte à retourner */
- unref_instr_link(dest);
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- }
-
- g_arch_instruction_unlock_dest(instr);
+ result = count_flat_array_items(instr->operands);
return result;
@@ -1565,56 +1153,45 @@ GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *ins
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter. *
-* count = quantié de liens présents. [OUT] *
+* Paramètres : instr = instance à mettre à jour. *
+* operand = instruction à venir associer. *
* *
-* Description : Fournit tous les détails de destination d'une instruction. *
+* Description : Attache un opérande supplémentaire à une instruction. *
* *
-* Retour : Liens vers des instructions de destination à libérer. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *instr, size_t *count)
+void g_arch_instruction_attach_operand(GArchInstruction *instr, GArchOperand *operand)
{
- instr_link_t *result; /* Détails présents à renvoyer */
- size_t i; /* Boucle de parcours */
- const instr_link_t *link; /* Lien à fournir */
-
- g_arch_instruction_lock_dest(instr);
-
- *count = g_arch_instruction_count_destinations(instr);
+ GSingletonFactory *factory; /* Unise à instances uniques */
+ GSingletonCandidate *singleton; /* Instance retenue */
+ GArchOperand *stored; /* Forme d'opérande conservée */
- if (*count == 0)
- result = NULL;
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- else
- {
- result = (instr_link_t *)malloc(*count * sizeof(instr_link_t));
+ factory = get_operands_factory();
- for (i = 0; i < *count; i++)
- {
- link = g_arch_instruction_get_destination(instr, i);
- memcpy(&result[i], link, sizeof(instr_link_t));
- }
+ singleton = g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(operand));
- }
+ unref_object(factory);
- g_arch_instruction_unlock_dest(instr);
+ stored = G_ARCH_OPERAND(singleton);
- return result;
+ add_item_to_flat_array(&instr->operands, &stored, sizeof(GArchOperand *));
}
/******************************************************************************
* *
-* Paramètres : instr = élément GLib à constuire. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à lire. *
+* Paramètres : instr = instance à mettre à jour. *
+* old = ancienne opérande à détacher. *
+* new = nouvelle opérande à attacher. *
* *
-* Description : Charge un contenu depuis une mémoire tampon. *
+* Description : Remplace un opérande d'une instruction par un autre. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -1622,40 +1199,47 @@ instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *instr, size_
* *
******************************************************************************/
-static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
+bool g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *old, GArchOperand *new)
{
bool result; /* Bilan à retourner */
- uleb128_t count; /* Nombre de liens à charger */
- uleb128_t i; /* Boucle de parcours */
- GArchInstruction *linked; /* Lien vers une instruction */
- uleb128_t type; /* Valeur ULEB128 à charger */
+ size_t count; /* Nombre d'opérandes en place */
+ size_t i; /* Boucle de parcours */
+ GArchOperand *op; /* Opérande à manipuler */
+ GSingletonFactory *factory; /* Unise à instances uniques */
+ GSingletonCandidate *singleton; /* Instance retenue */
+ GArchOperand *stored; /* Forme d'opérande conservée */
- g_arch_instruction_lock_dest(instr);
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- result = unpack_uleb128(&count, pbuf);
+ result = false;
- for (i = 0; i < count && result; i++)
+ count = g_arch_instruction_count_operands(instr);
+
+ for (i = 0; i < count && !result; i++)
{
- linked = G_ARCH_INSTRUCTION(g_object_storage_unpack_object(storage, "instructions", pbuf));
- if (linked == NULL)
- {
- result = false;
- break;
- }
+ op = g_arch_instruction_get_operand(instr, i);
- result = unpack_uleb128(&type, pbuf);
- if (!result)
- {
- g_object_unref(G_OBJECT(linked));
- break;
- }
+ result = (op == old);
- g_arch_instruction_link_with(instr, linked, type);
- g_object_unref(G_OBJECT(linked));
+ unref_object(op);
}
- g_arch_instruction_unlock_dest(instr);
+ if (result)
+ {
+ factory = get_operands_factory();
+
+ singleton = g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(new));
+
+ unref_object(factory);
+
+ stored = G_ARCH_OPERAND(singleton);
+
+ rpl_item_in_flat_array(instr->operands, i - 1, &stored, sizeof(GArchOperand *));
+
+ unref_object(old);
+
+ }
return result;
@@ -1664,11 +1248,10 @@ static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjec
/******************************************************************************
* *
-* Paramètres : instr = instruction dont les informations sont à consulter.*
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : instr = instance à mettre à jour. *
+* target = instruction à venir dissocier. *
* *
-* Description : Sauvegarde toutes les destinations d'une instruction. *
+* Description : Détache un opérande liée d'une instruction. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -1676,87 +1259,67 @@ static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjec
* *
******************************************************************************/
-bool g_arch_instruction_store_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
+bool g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *target)
{
bool result; /* Bilan à retourner */
- size_t count; /* Nombre d'éléments à traiter */
- size_t kept; /* Nombre de liens conservés */
+ size_t count; /* Nombre d'opérandes en place */
size_t i; /* Boucle de parcours */
- const instr_link_t *link; /* Lien vers une instruction */
-
- g_arch_instruction_lock_dest(instr);
+ GArchOperand *op; /* Opérande à manipuler */
- count = g_arch_instruction_count_destinations(instr);
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- /**
- * Le type de lien ILT_REF n'est mis en place que lors de la création
- * d'opérandes de type G_TYPE_TARGET_OPERAND, et sera donc remis en place
- * dynamiquement lors de la restauration de ces derniers.
- */
+ result = false;
- kept = 0;
+ count = g_arch_instruction_count_operands(instr);
- for (i = 0; i < count; i++)
+ for (i = 0; i < count && !result; i++)
{
- link = g_arch_instruction_get_destination(instr, i);
+ op = g_arch_instruction_get_operand(instr, i);
- if (link->type != ILT_REF)
- kept++;
+ result = (op == target);
- unref_instr_link(link);
+ unref_object(op);
}
- result = pack_uleb128((uleb128_t []){ kept }, pbuf);
-
- for (i = 0; i < count && result; i++)
+ if (result)
{
- link = g_arch_instruction_get_destination(instr, i);
-
- if (link->type != ILT_REF)
- {
- result = g_object_storage_pack_object(storage, "instructions",
- G_SERIALIZABLE_OBJECT(link->linked), pbuf);
-
- if (result)
- result = pack_uleb128((uleb128_t []){ link->type }, pbuf);
-
- }
+ rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *));
- unref_instr_link(link);
+ unref_object(target);
}
- g_arch_instruction_unlock_dest(instr);
-
return result;
}
-
-/* ---------------------------------------------------------------------------------- */
-/* CONVERSIONS DU FORMAT DES INSTRUCTIONS */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
+* Paramètres : instr = instance à consulter. *
+* index = indice de l'opérande concerné. *
* *
-* Description : Fournit le nom humain de l'instruction manipulée. *
+* Description : Fournit un opérande donné d'une instruction. *
* *
-* Retour : Mot clef de bas niveau. *
+* Retour : Opérande trouvée. *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *g_arch_instruction_get_keyword(GArchInstruction *instr)
+GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index)
{
- const char *result; /* Désignation à retourner */
+ GArchOperand *result; /* Opérande à retourner */
+ GArchOperand **ptr; /* Adresse dans le tableau */
+
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(instr)));
- result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_keyword(instr);
+ ptr = get_flat_array_item(instr->operands, index, sizeof(GArchOperand *));
+
+ result = *ptr;
+
+ ref_object(result);
return result;
@@ -1765,450 +1328,396 @@ const char *g_arch_instruction_get_keyword(GArchInstruction *instr)
/******************************************************************************
* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
+* Paramètres : instr = instance à consulter. *
+* target = instruction à venir retrouver. *
* *
-* Description : Construit un petit résumé concis de l'instruction. *
+* Description : Détermine le chemin conduisant à un opérande. *
* *
-* Retour : Chaîne de caractères à libérer après usage ou NULL. *
+* Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. *
* *
* Remarques : - *
* *
******************************************************************************/
-char *g_arch_instruction_build_tooltip(const GArchInstruction *instr)
+char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target)
{
- char *result; /* Description à retourner */
- GArchInstructionClass *class; /* Classe des instructions */
+ char *result; /* Chemin à retourner */
+ size_t count; /* Nombre d'opérandes en place */
+ size_t i; /* Boucle de parcours */
+ GArchOperand *op; /* Opérande à manipuler */
+ int ret; /* Bilan d'une construction */
+ char *sub_path; /* Sous-chemin emprunté */
- class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
+ result = NULL;
- if (class->build_tooltip != NULL)
- result = class->build_tooltip(instr);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
- else
- result = NULL;
+ count = g_arch_instruction_count_operands(instr);
- return result;
+ /* Première passe : accès direct */
-}
+ for (i = 0; i < count && result == NULL; i++)
+ {
+ op = g_arch_instruction_get_operand(instr, i);
+ if (op == target)
+ {
+ ret = asprintf(&result, "%zu", i);
+ if (ret == -1)
+ {
+ LOG_ERROR_N("asprintf");
+ result = NULL;
+ }
+ }
-/******************************************************************************
-* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
-* *
-* Description : Fournit une description pour l'instruction manipulée. *
-* *
-* Retour : Chaîne de caractères avec balises éventuelles. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ unref_object(op);
-const char *g_arch_instruction_get_description(const GArchInstruction *instr)
-{
- const char *result; /* Description à retourner */
+ }
- result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_desc(instr);
+ /* Seconde passe : accès profond */
- return result;
-
-}
+ for (i = 0; i < count && result == NULL; i++)
+ {
+ op = g_arch_instruction_get_operand(instr, i);
+ sub_path = NULL;//g_arch_operand_find_inner_operand_path(op, target);
+ if (sub_path != NULL)
+ {
+ ret = asprintf(&result, "%zu:%s", i, sub_path);
+ if (ret == -1)
+ {
+ LOG_ERROR_N("asprintf");
+ result = NULL;
+ }
-/* ---------------------------------------------------------------------------------- */
-/* OFFRE DE CAPACITES DE GENERATION */
-/* ---------------------------------------------------------------------------------- */
+ free(sub_path);
+ }
-/******************************************************************************
-* *
-* Paramètres : instr = générateur à consulter. *
-* *
-* Description : Indique le nombre de ligne prêtes à être générées. *
-* *
-* Retour : Nombre de lignes devant apparaître au final. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ unref_object(op);
-static size_t g_arch_instruction_count_lines(const GArchInstruction *instr)
-{
- return 1;
+ }
-}
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
+ return result;
-#ifdef INCLUDE_GTK_SUPPORT
+}
/******************************************************************************
* *
-* Paramètres : instr = générateur à consulter. *
-* x = position géographique sur la ligne concernée. *
-* index = indice de cette même ligne dans le tampon global. *
-* repeat = indice d'utilisations successives du générateur. *
-* cursor = emplacement à constituer. [OUT] *
+* Paramètres : instr = instance à consulter. *
+* path = chemin d'accès à un opérande à retrouver. *
* *
-* Description : Retrouve l'emplacement correspondant à une position donnée. *
+* Description : Obtient l'opérande correspondant à un chemin donné. *
* *
-* Retour : - *
+* Retour : Opérande trouvé ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_arch_instruction_compute_cursor(const GArchInstruction *instr, gint x, size_t index, size_t repeat, GLineCursor **cursor)
+GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path)
{
- *cursor = g_binary_cursor_new();
+ GArchOperand *result; /* Opérande trouvée à renvoyer */
+ size_t index; /* Indice de l'opérande visé */
+ char *end; /* Poursuite du parcours ? */
+ GArchOperand *found; /* Opérande trouvé */
- g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&instr->range));
+ result = NULL;
-}
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+ /* Recherche au premier niveau */
-/******************************************************************************
-* *
-* Paramètres : instr = générateur à consulter. *
-* index = indice de cette même ligne dans le tampon global. *
-* repeat = indice d'utilisations successives du générateur. *
-* cursor = emplacement à analyser. *
-* *
-* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
-* *
-* Retour : Bilan de la détermination, utilisable en comparaisons. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ index = strtoul(path, &end, 10);
-static int g_arch_instruction_contain_cursor(const GArchInstruction *instr, size_t index, size_t repeat, const GLineCursor *cursor)
-{
- int result; /* Conclusion à retourner */
- vmpa2t addr; /* Autre emplacement à comparer*/
+ if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL))
+ {
+ LOG_ERROR_N("strtoul");
+ goto done;
+ }
+
+ found = g_arch_instruction_get_operand(instr, index);
+ if (found == NULL) goto done;
+
+ if (*end == '\0')
+ {
+ result = found;
+ goto done;
+ }
+
+ /* Recherche en profondeur */
+
+ assert(*end == ':');
+
+ result = NULL;//g_arch_operand_get_inner_operand_from_path(found, end + 1);
- assert(G_IS_BINARY_CURSOR(cursor));
+ unref_object(found);
- g_binary_cursor_retrieve(G_BINARY_CURSOR(cursor), &addr);
+ done:
- result = cmp_mrange_with_vmpa(&instr->range, &addr);
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
return result;
}
-#endif
+
+/* ---------------------------------------------------------------------------------- */
+/* MECANISMES DE CONSERVATION ET RESTAURATION */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : instr = générateur à consulter. *
-* index = indice de cette même ligne dans le tampon global. *
-* repeat = indice d'utilisations successives du générateur. *
+* Paramètres : object = élément GLib à constuire. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en lecture. *
* *
-* Description : Renseigne sur les propriétés liées à un générateur. *
+* Description : Charge un objet depuis un flux de données. *
* *
-* Retour : Propriétés particulières associées. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *instr, size_t index, size_t repeat)
+static bool g_arch_instruction_load(GSerializableObject *object, GObjectStorage *storage, int fd)
{
- return BLF_HAS_CODE;
+ bool result; /* Bilan à retourner */
+ uleb128_t extra; /* Données embarquées */
+
+ /* Propriétés internes */
+
+ result = load_uleb128(&extra, fd);
+
+ if (result)
+ g_thick_object_set_extra(G_THICK_OBJECT(object), extra);
+
+ /* Liaisons avec d'autres instructions */
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : instr = instruction d'assemblage à représenter. *
-* line = ligne de rendu à compléter. *
-* index = indice de cette même ligne dans le tampon global. *
-* repeat = indice d'utilisations successives du générateur. *
-* content = éventuel contenu binaire brut à imprimer. *
+* Paramètres : object = élément GLib à consulter. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. *
+* Description : Sauvegarde un objet dans un flux de données. *
* *
-* Retour : - *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void _g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content)
+static bool g_arch_instruction_store(const GSerializableObject *object, GObjectStorage *storage, int fd)
{
- const char *key; /* Mot clef principal */
- size_t klen; /* Taille de ce mot clef */
- size_t count; /* Nombre d'opérandes en place */
+ bool result; /* Bilan à retourner */
+ GArchInstruction *instr; /* Version spécialisée */
+ size_t src_count; /* Quantité de sources */
+ size_t dest_count; /* Quantité de destinations */
+ off64_t *ins_offsets; /* Emplacements d'instructions */
size_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à manipuler */
+ GArchInstruction *linked; /* Instruction liée */
+ size_t op_count; /* Quantité d'opérandes */
+ off64_t *op_offsets; /* Emplacements d'opérandes */
+ GArchOperand *op; /* Opérande à traiter */
+ guint extra; /* Données embarquées */
+ InstructionLinkType type; /* Type de lien */
- g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range));
+ assert(g_thick_object_check_lock(G_THICK_OBJECT(object)));
- g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range));
+ /* Préparation des références aux instructions liées */
- g_buffer_line_fill_content(line, DLC_BINARY, content, &instr->range, VMPA_NO_PHYSICAL);
+ instr = G_ARCH_INSTRUCTION(object);
- /* Instruction proprement dite */
+ src_count = g_arch_instruction_count_src_links(instr);
+ dest_count = g_arch_instruction_count_dest_links(instr);
- key = g_arch_instruction_get_keyword(instr);
- klen = strlen(key);
+ ins_offsets = malloc((src_count + dest_count) * sizeof(off64_t));
- g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION, G_OBJECT(instr));
+ for (i = 0; i < src_count && result; i++)
+ {
+ linked = g_arch_instruction_get_linked_source(instr, i, (InstructionLinkType []) { 0 });
- /* Liste des opérandes */
+ result = g_object_storage_store_object(storage, "instructions",
+ G_SERIALIZABLE_OBJECT(linked), &ins_offsets[i]);
- g_arch_instruction_lock_operands(instr);
+ unref_object(linked);
- count = _g_arch_instruction_count_operands(instr);
+ }
- if (count > 0)
+ for (i = 0; i < dest_count && result; i++)
{
- op = _g_arch_instruction_get_operand(instr, 0);
- g_arch_operand_print(op, line);
- g_object_unref(G_OBJECT(op));
+ linked = g_arch_instruction_get_linked_destination(instr, i, (InstructionLinkType []) { 0 });
- for (i = 1; i < count; i++)
- {
- g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL);
- g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL);
+ result = g_object_storage_store_object(storage, "instructions",
+ G_SERIALIZABLE_OBJECT(linked), &ins_offsets[src_count + i]);
- op = _g_arch_instruction_get_operand(instr, i);
+ unref_object(linked);
- g_arch_operand_print(op, line);
+ }
- g_object_unref(G_OBJECT(op));
+ if (!result)
+ goto exit_with_ins_off;
- }
+ /* Préparation des références aux opérandes embarqués */
- }
+ op_count = g_arch_instruction_count_operands(instr);
- g_arch_instruction_unlock_operands(instr);
+ op_offsets = malloc(op_count * sizeof(off64_t));
-}
+ for (i = 0; i < op_count && result; i++)
+ {
+ op = g_arch_instruction_get_operand(instr, i);
+ result = g_object_storage_store_object(storage, "operandss",
+ G_SERIALIZABLE_OBJECT(op), &op_offsets[i]);
-/******************************************************************************
-* *
-* Paramètres : instr = générateur à utiliser pour l'impression. *
-* line = ligne de rendu à compléter. *
-* index = indice de cette même ligne dans le tampon global. *
-* repeat = indice d'utilisations successives du générateur. *
-* content = éventuel contenu binaire brut à imprimer. *
-* *
-* Description : Imprime dans une ligne de rendu le contenu représenté. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ unref_object(op);
-static void g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content)
-{
- G_ARCH_INSTRUCTION_GET_CLASS(instr)->print(instr, line, index, repeat, content);
+ }
-}
+ if (!result)
+ goto exit_with_op_off;
+ /* Propriétés internes */
+ extra = g_thick_object_get_extra(G_THICK_OBJECT(object));
-/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION ET RECHARGEMENT DES DONNEES */
-/* ---------------------------------------------------------------------------------- */
+ result = store_uleb128((uleb128_t []) { extra }, fd);
+ if (!result) goto exit;
+ /* Liaisons avec d'autres instructions */
-/******************************************************************************
-* *
-* Paramètres : instr = é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 : - *
-* *
-******************************************************************************/
+ instr = G_ARCH_INSTRUCTION(object);
-static bool _g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- instr_extra_data_t *extra; /* Données insérées à consulter*/
- uleb128_t value; /* Valeur ULEB128 à charger */
- uleb128_t count; /* Nombre d'éléments à traiter */
- uleb128_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à traiter */
+ src_count = g_arch_instruction_count_src_links(instr);
+ dest_count = g_arch_instruction_count_dest_links(instr);
- extra = GET_ARCH_INSTR_EXTRA(instr);
+ result = store_uleb128((uleb128_t []) { src_count }, fd);
+ if (!result) goto exit;
- LOCK_GOBJECT_EXTRA(extra);
+ result = store_uleb128((uleb128_t []) { dest_count }, fd);
+ if (!result) goto exit;
- result = unpack_uleb128(&value, pbuf);
+ for (i = 0; i < src_count && result; i++)
+ {
+ linked = g_arch_instruction_get_linked_source(instr, i, &type);
- if (result)
- extra->uid = value;
+ result = store_uleb128((uleb128_t []) { type }, fd);
- if (result)
- {
- result = unpack_uleb128(&value, pbuf);
+ unref_object(linked);
if (result)
- extra->flags = value;
+ result = store_uleb128((uleb128_t []) { ins_offsets[i] }, fd);
}
- UNLOCK_GOBJECT_EXTRA(extra);
-
- if (result)
- result = unpack_mrange(&instr->range, pbuf);
-
- if (result)
+ for (i = 0; i < dest_count && result; i++)
{
- result = unpack_uleb128(&count, pbuf);
+ linked = g_arch_instruction_get_linked_destination(instr, i, &type);
- for (i = 0; i < count && result; i++)
- {
- op = G_ARCH_OPERAND(g_object_storage_unpack_object(storage, "operands", pbuf));
- result = (op != NULL);
+ result = store_uleb128((uleb128_t []) { type }, fd);
- if (result)
- g_arch_instruction_attach_extra_operand(instr, op);
+ unref_object(linked);
- }
+ if (result)
+ result = store_uleb128((uleb128_t []) { ins_offsets[src_count + i] }, fd);
}
- if (result)
- result = g_arch_instruction_load_destinations(instr, storage, pbuf);
-
- return result;
+ /* Opérandes embarqués */
-}
+ result = store_uleb128((uleb128_t []) { op_count }, fd);
+ if (!result) goto exit;
+ for (i = 0; i < op_count && result; i++)
+ result = store_uleb128((uleb128_t []) { op_offsets[i] }, fd);
-/******************************************************************************
-* *
-* Paramètres : instr = é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 : - *
-* *
-******************************************************************************/
+ exit:
+ exit_with_op_off:
-static bool g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- GArchInstructionClass *class; /* Classe à activer */
+ free(op_offsets);
- class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
+ exit_with_ins_off:
- result = class->load(instr, storage, pbuf);
+ free(ins_offsets);
return result;
}
-/******************************************************************************
-* *
-* Paramètres : instr = é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_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- instr_extra_data_t *extra; /* Données insérées à consulter*/
- size_t count; /* Nombre d'éléments à traiter */
- size_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à traiter */
-
- extra = GET_ARCH_INSTR_EXTRA(instr);
- LOCK_GOBJECT_EXTRA(extra);
- result = pack_uleb128((uleb128_t []){ extra->uid }, pbuf);
- if (result)
- result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf);
- UNLOCK_GOBJECT_EXTRA(extra);
- if (result)
- result = pack_mrange(&instr->range, pbuf);
- if (result)
- {
- g_arch_instruction_lock_operands(instr);
- count = _g_arch_instruction_count_operands(instr);
- result = pack_uleb128((uleb128_t []){ count }, pbuf);
- for (i = 0; i < count && result; i++)
- {
- op = _g_arch_instruction_get_operand(instr, i);
- result = g_object_storage_pack_object(storage, "operands", G_SERIALIZABLE_OBJECT(op), pbuf);
- g_object_unref(G_OBJECT(op));
- }
- g_arch_instruction_unlock_operands(instr);
- }
- if (result)
- result = g_arch_instruction_store_destinations(instr, storage, pbuf);
+#if 0
- return result;
-}
/******************************************************************************
* *
-* Paramètres : instr = élément GLib à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : instr = instruction quelconque à traiter. *
+* type = type de procédure à utiliser. *
+* proc = représentation de l'architecture utilisée. *
+* context = contexte associé à la phase de désassemblage. *
+* format = accès aux données du binaire d'origine. *
* *
-* Description : Sauvegarde un contenu dans une mémoire tampon. *
+* Description : Complète un désassemblage accompli pour une instruction. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
+void g_arch_instruction_call_hook(GArchInstruction *instr, InstrProcessHook type, GArchProcessor *proc, GProcContext *context, GExeFormat *format)
{
- bool result; /* Bilan à retourner */
- GArchInstructionClass *class; /* Classe à activer */
+ GArchInstructionClass *class; /* Classe des instructions */
class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
- result = class->store(instr, storage, pbuf);
-
- return result;
+ if (class->call_hook != NULL)
+ class->call_hook(instr, type, proc, context, format);
}
+
+
+
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index 3c9c149..98bc73e 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* instruction.h - prototypes pour la gestion générique des instructions
*
- * Copyright (C) 2008-2020 Cyrille Bagard
+ * Copyright (C) 2008-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,194 +25,118 @@
#define _ARCH_INSTRUCTION_H
-#include <sys/types.h>
+#include <stdbool.h>
+#include <stdint.h>
-#include "context.h"
#include "operand.h"
-#include "register.h"
#include "vmpa.h"
-#include "../analysis/type.h"
-#include "../common/packed.h"
-#include "../format/executable.h"
+#include "../glibext/helpers.h"
+#include "../glibext/portion.h"
-#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))
+/* ----------------------- DEFINITION GENERIQUE D'INSTRUCTION ----------------------- */
-/* Définition générique d'une instruction d'architecture (instance) */
-typedef struct _GArchInstruction GArchInstruction;
+#define G_TYPE_ARCH_INSTRUCTION (g_arch_instruction_get_type())
-/* Définition générique d'une instruction d'architecture (classe) */
-typedef struct _GArchInstructionClass GArchInstructionClass;
+DECLARE_GTYPE(GArchInstruction, g_arch_instruction, G, ARCH_INSTRUCTION);
-/* Drapeaux pour informations complémentaires */
-
-#define AIF_USER_BIT 4
-
-typedef enum _ArchInstrFlag
-{
- AIF_NONE = (0 << 0), /* Aucune information */
- AIF_ROUTINE_START = (1 << 0), /* Début de routine */
- AIF_RETURN_POINT = (1 << 1), /* Retour de fonction appelée */
- AIF_COND_RETURN_POINT = (1 << 2), /* Retour éventuel de fonction */
- AIF_CALL = (1 << 3), /* Instruction d'appel */
-
- AIF_LOW_USER = (1 << AIF_USER_BIT), /* Premier bit disponible */
- AIF_HIGH_USER = (1 << 7), /* Dernier bit disponible */
-
-} ArchInstrFlag;
-
/* Type pour les types d'instructions */
typedef uint16_t itid_t;
-/* Types de crochet de traitement */
-typedef enum _InstrProcessHook
-{
- IPH_FETCH, /* Itinéraire de désassemblage */
- IPH_LINK, /* Edition des liens */
- IPH_POST, /* Résolution des symboles */
-
- IPH_COUNT
-
-} InstrProcessHook;
-
-
-/* Indique le type défini pour une instruction d'architecture. */
-GType g_arch_instruction_get_type(void);
+/* Fournit l'identifiant correspondant à un type d'instructions. */
+itid_t g_arch_instruction_get_type_id(const GArchInstruction *);
/* Indique l'encodage d'une instruction de façon détaillée. */
-const char *g_arch_instruction_get_encoding(const GArchInstruction *);
-
-/* Ajoute une information complémentaire à une instruction. */
-bool g_arch_instruction_set_flag(GArchInstruction *, ArchInstrFlag);
+char *g_arch_instruction_get_encoding(const GArchInstruction *);
-/* Retire une information complémentaire à une instruction. */
-bool g_arch_instruction_unset_flag(GArchInstruction *, ArchInstrFlag);
-
-/* Détermine si une instruction possède un fanion particulier. */
-bool g_arch_instruction_has_flag(const GArchInstruction *, ArchInstrFlag);
+/* Fournit le nom humain de l'instruction manipulée. */
+char *g_arch_instruction_get_keyword(const GArchInstruction *);
-/* Fournit les informations complémentaires d'une instruction. */
-ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *);
-/* Définit l'identifiant unique pour un ensemble d'instructions. */
-void g_arch_instruction_set_unique_id(GArchInstruction *, itid_t);
+ /* Type de masques pour les encodages d'instructions */
+typedef enum _InstructionBytesMask
+{
+ /**
+ * Correspond aux bits fixes : pas de valeurs de registre ni de valeur entière.
+ */
+ IBM_LOOSE,
-/* Fournit l'identifiant unique pour un ensemble d'instructions. */
-itid_t g_arch_instruction_get_unique_id(const GArchInstruction *);
+ /**
+ * Dissimulation des références à des éléments externes pouvant varier avec
+ * entre compilations : adresses de saut ou d'appel, références vers des tables,
+ * etc.
+ */
+ IBM_LOCAL,
+ /**
+ * Dissimulation des déplacements à partir d'une base.
+ */
+ IBM_STRICT,
-/**
- * La définition de "GArchProcessor", utile aux traitements complémentaires, ne peut
- * se faire en incluant le fichier d'en-tête "processor.h", pour cause de références
- * circulaires.
- *
- * On procède donc à une seconde déclaration, en attendant éventuellement mieux.
- */
+ /**
+ * Conservation de toutes les valeurs immédiates et dissimulation des registres.
+ */
+ IBM_LARGE,
-/* Depuis "processeur.h" : définition générique d'un processeur d'architecture (instance) */
-typedef struct _GArchProcessor GArchProcessor;
+ IBM_COUNT
+} InstructionBytesMask;
-/* Complète un désassemblage accompli pour une instruction. */
-typedef void (* instr_hook_fc) (GArchInstruction *, GArchProcessor *, GProcContext *, GExeFormat *);
-
-/* Complète un désassemblage accompli pour une instruction. */
-void g_arch_instruction_call_hook(GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *);
-/* Définit la localisation d'une instruction. */
-void g_arch_instruction_set_range(GArchInstruction *, const mrange_t *);
+/* Calcule la localisation d'une instruction. */
+void g_arch_instruction_compute_range(GArchInstruction *, GBinaryPortion *, const vmpa2t *, phys_t);
/* Fournit la place mémoire d'une instruction. */
-const mrange_t *g_arch_instruction_get_range(const GArchInstruction *);
-
-
-
-/* Fournit la localisation d'une instruction. */
-void g_arch_instruction_get_location(const GArchInstruction *, off_t *, off_t *, vmpa_t *) __attribute__ ((deprecated));
+bool g_arch_instruction_get_range(const GArchInstruction *, mrange_t *);
+#define AIF_USER_BIT 4
-/* Liste les registres lus et écrits par l'instruction. */
-void g_arch_instruction_get_rw_registers(const GArchInstruction *, GArchRegister ***, size_t *, GArchRegister ***, size_t *) __attribute__ ((deprecated));
+typedef enum _ArchInstructionFlag
+{
+ AIF_NONE = (0 << 0), /* Aucune information */
+ AIF_ROUTINE_START = (1 << 0), /* Début de routine */
+ AIF_RETURN_POINT = (1 << 1), /* Retour de fonction appelée */
+ AIF_COND_RETURN_POINT = (1 << 2), /* Retour éventuel de fonction */
+ AIF_CALL = (1 << 3), /* Instruction d'appel */
+ AIF_LOW_USER = (1 << AIF_USER_BIT), /* Premier bit disponible */
+ AIF_HIGH_USER = (1 << 7), /* Dernier bit disponible */
+} ArchInstructionFlag;
-/* --------------------------- MANIPULATION DES OPERANDES --------------------------- */
+#define AIF_USER_FLAG(n) (1 << (AIF_USER_BIT + n))
-/* Verrouille les accès à la liste des opérandes. */
-void g_arch_instruction_lock_operands(GArchInstruction *);
+/* Ajoute une information complémentaire à une instruction. */
+bool g_arch_instruction_set_flag(GArchInstruction *, ArchInstructionFlag);
-/* Déverrouille les accès à la liste des opérandes. */
-void g_arch_instruction_unlock_operands(GArchInstruction *);
+/* Retire une information complémentaire à une instruction. */
+bool g_arch_instruction_unset_flag(GArchInstruction *, ArchInstructionFlag);
-/* Attache un opérande supplémentaire à une instruction. */
-void g_arch_instruction_attach_extra_operand(GArchInstruction *, GArchOperand *);
+/* Détermine si une instruction possède un fanion particulier. */
+bool g_arch_instruction_has_flag(const GArchInstruction *, ArchInstructionFlag);
-/* Indique la quantité d'opérandes présents dans l'instruction. */
-size_t _g_arch_instruction_count_operands(const GArchInstruction *);
+/* Fournit les particularités de l'instruction. */
+ArchInstructionFlag g_arch_instruction_get_flags(const GArchInstruction *);
-/* Fournit un opérande donné d'une instruction. */
-GArchOperand *_g_arch_instruction_get_operand(const GArchInstruction *, size_t);
-/* Remplace un opérande d'une instruction par un autre. */
-bool _g_arch_instruction_replace_operand(GArchInstruction *, GArchOperand *, GArchOperand *);
+/* Types de crochet de traitement */
+typedef enum _InstrProcessHook
+{
+ IPH_FETCH, /* Itinéraire de désassemblage */
+ IPH_LINK, /* Edition des liens */
+ IPH_POST, /* Résolution des symboles */
-/* Détache un opérande liée d'une instruction. */
-bool _g_arch_instruction_detach_operand(GArchInstruction *, GArchOperand *);
-
-
-#define g_arch_instruction_count_operands(ins) \
- ({ \
- size_t __result; \
- g_arch_instruction_lock_operands(ins); \
- __result = _g_arch_instruction_count_operands(ins); \
- g_arch_instruction_unlock_operands(ins); \
- __result; \
- })
-
-#define g_arch_instruction_get_operand(ins, idx) \
- ({ \
- GArchOperand *__result; \
- g_arch_instruction_lock_operands(ins); \
- __result = _g_arch_instruction_get_operand(ins, idx); \
- g_arch_instruction_unlock_operands(ins); \
- __result; \
- })
-
-#define g_arch_instruction_replace_operand(ins, o, n) \
- ({ \
- bool __result; \
- g_arch_instruction_lock_operands(ins); \
- __result = _g_arch_instruction_replace_operand(ins, o, n); \
- g_arch_instruction_unlock_operands(ins); \
- __result; \
- })
-
-#define g_arch_instruction_detach_operand(ins, o) \
- ({ \
- bool __result; \
- g_arch_instruction_lock_operands(ins); \
- __result = _g_arch_instruction_detach_operand(ins, o); \
- g_arch_instruction_unlock_operands(ins); \
- __result; \
- })
+ IPH_COUNT
+} InstrProcessHook;
-/* Détermine le chemin conduisant à un opérande. */
-char *g_arch_instruction_find_operand_path(GArchInstruction *, const GArchOperand *);
-/* Obtient l'opérande correspondant à un chemin donné. */
-GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *, const char *);
@@ -236,30 +160,24 @@ typedef enum _InstructionLinkType
} InstructionLinkType;
-/* Déscription d'une liaison entre deux instructions */
-typedef struct _instr_link_t
-{
- GArchInstruction *linked; /* Autre instruction liée */
- InstructionLinkType type; /* Type de liaison */
-
-} instr_link_t;
-
-#define ref_instr_link(l) g_object_ref(G_OBJECT(l->linked));
-#define unref_instr_link(l) g_object_unref(G_OBJECT(l->linked));
+/* Détermine si un type de lien amène à une instruction. */
+bool g_arch_instruction_has_src_link(const GArchInstruction *, InstructionLinkType);
+/* Détermine si un type de lien émerge d'une instruction. */
+bool g_arch_instruction_has_dest_link(const GArchInstruction *, InstructionLinkType);
-/* Met à disposition un encadrement des accès aux liens. */
-void g_arch_instruction_lock_unlock_links(GArchInstruction *, bool, bool);
+/* Détermine si une instruction est source d'une autre. */
+bool g_arch_instruction_has_src_link_with(const GArchInstruction *, const GArchInstruction *);
-/* Détermine si un type de lien existe dans une instruction. */
-bool g_arch_instruction_has_link(GArchInstruction *, InstructionLinkType);
-
-/* Détermine si un lien est déjà établi entre deux instructions. */
-bool g_arch_instruction_has_link_to(GArchInstruction *, const GArchInstruction *);
+/* Détermine si une instruction est destination d'une autre. */
+bool g_arch_instruction_has_dest_link_with(const GArchInstruction *, const GArchInstruction *);
/* Etablit un lien entre deux instructions. */
-void g_arch_instruction_link_with(GArchInstruction *, GArchInstruction *, InstructionLinkType);
+void g_arch_instruction_link(GArchInstruction *, GArchInstruction *, InstructionLinkType);
+
+/* Supprime un lien entre deux instructions. */
+void g_arch_instruction_unlink(GArchInstruction *, GArchInstruction *, InstructionLinkType);
/* Change la nature d'un lien entre deux instructions. */
bool g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, InstructionLinkType, InstructionLinkType);
@@ -267,46 +185,72 @@ bool g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, Inst
/* Supprime tous les liens établis avec d'autres instructions. */
void g_arch_instruction_delete_all_links(GArchInstruction *);
-#define g_arch_instruction_lock_src(ins) g_arch_instruction_lock_unlock_links(ins, true, true)
-#define g_arch_instruction_unlock_src(ins) g_arch_instruction_lock_unlock_links(ins, true, false)
+/* Fournit la quantité d'instructions placées en source. */
+size_t g_arch_instruction_count_src_links(const GArchInstruction *);
-/* Fournit la quantité d'instructions pointant vers une autre. */
-size_t g_arch_instruction_count_sources(const GArchInstruction *);
+/* Fournit la quantité d'instructions placées en destination. */
+size_t g_arch_instruction_count_dest_links(const GArchInstruction *);
-/* Fournit les détails d'une origine d'une instruction donnée. */
-const instr_link_t *g_arch_instruction_get_source(GArchInstruction *, size_t);
+/* Fournit les détails d'une source donnée d'une instruction. */
+GArchInstruction *g_arch_instruction_get_linked_source(const GArchInstruction *, size_t, InstructionLinkType *);
-/* Fournit tous les détails d'origine d'une instruction donnée. */
-instr_link_t *g_arch_instruction_get_sources(GArchInstruction *, size_t *);
+/* Fournit les détails d'une destination donnée d'une instruction. */
+GArchInstruction *g_arch_instruction_get_linked_destination(const GArchInstruction *, size_t, InstructionLinkType *);
-#define g_arch_instruction_lock_dest(ins) g_arch_instruction_lock_unlock_links(ins, false, true)
-#define g_arch_instruction_unlock_dest(ins) g_arch_instruction_lock_unlock_links(ins, false, false)
-/* Donne le nombre d'instructions non naturellement suivantes. */
-size_t g_arch_instruction_count_destinations(const GArchInstruction *);
-/* Fournit les détails d'une destination d'une instruction. */
-const instr_link_t *g_arch_instruction_get_destination(GArchInstruction *, size_t);
+/* --------------------------- MANIPULATION DES OPERANDES --------------------------- */
-/* Fournit la destination d'une instruction et d'un type donné. */
-GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *, InstructionLinkType);
-/* Fournit tous les détails de destination d'une instruction. */
-instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *, size_t *);
+/* Indique la quantité d'opérandes présents dans l'instruction. */
+size_t g_arch_instruction_count_operands(const GArchInstruction *);
+/* Attache un opérande supplémentaire à une instruction. */
+void g_arch_instruction_attach_operand(GArchInstruction *, GArchOperand *);
+/* Remplace un opérande d'une instruction par un autre. */
+bool g_arch_instruction_replace_operand(GArchInstruction *, GArchOperand *, GArchOperand *);
-/* --------------------- CONVERSIONS DU FORMAT DES INSTRUCTIONS --------------------- */
+/* Détache un opérande liée d'une instruction. */
+bool g_arch_instruction_detach_operand(GArchInstruction *, GArchOperand *);
+/* Fournit un opérande donné d'une instruction. */
+GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *, size_t);
+
+/* Détermine le chemin conduisant à un opérande. */
+char *g_arch_instruction_find_operand_path(GArchInstruction *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *, const char *);
+
+
+
+
+#if 0
+
+
+
+/**
+ * La définition de "GArchProcessor", utile aux traitements complémentaires, ne peut
+ * se faire en incluant le fichier d'en-tête "processor.h", pour cause de références
+ * circulaires.
+ *
+ * On procède donc à une seconde déclaration, en attendant éventuellement mieux.
+ */
+
+/* Depuis "processeur.h" : définition générique d'un processeur d'architecture (instance) */
+typedef struct _GArchProcessor GArchProcessor;
+
+
+/* Complète un désassemblage accompli pour une instruction. */
+typedef void (* instr_hook_fc) (GArchInstruction *, GArchProcessor *, GProcContext *, GExeFormat *);
+
+/* Complète un désassemblage accompli pour une instruction. */
+void g_arch_instruction_call_hook(GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *);
-/* Fournit le nom humain de l'instruction manipulée. */
-const char *g_arch_instruction_get_keyword(GArchInstruction *);
-/* Construit un petit résumé concis de l'instruction. */
-char *g_arch_instruction_build_tooltip(const GArchInstruction *);
-/* Fournit une description pour l'instruction manipulée. */
-const char *g_arch_instruction_get_description(const GArchInstruction *);
+#endif
diff --git a/src/arch/instructions/Makefile.am b/src/arch/instructions/Makefile.am
index 28cf90f..d6fc4bd 100644
--- a/src/arch/instructions/Makefile.am
+++ b/src/arch/instructions/Makefile.am
@@ -1,12 +1,19 @@
-noinst_LTLIBRARIES = libarchinstructions.la
+noinst_LTLIBRARIES = libarchinstructions.la libarchinstructionsui.la
libarchinstructions_la_SOURCES = \
+ raw-int.h \
raw.h raw.c \
undefined-int.h \
undefined.h undefined.c
-libarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+libarchinstructions_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+libarchinstructionsui_la_SOURCES = \
+ raw-ui.h raw-ui.c \
+ undefined-ui.h undefined-ui.c
+
+libarchinstructionsui_la_CFLAGS = $(LIBGTK4_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
diff --git a/src/arch/instructions/raw-int.h b/src/arch/instructions/raw-int.h
new file mode 100644
index 0000000..4a5e64b
--- /dev/null
+++ b/src/arch/instructions/raw-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * raw-int.h - prototypes pour la définition interne des instructions de données brutes
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_INSTRUCTIONS_RAW_INT_H
+#define _ARCH_INSTRUCTIONS_RAW_INT_H
+
+
+#include "raw.h"
+#include "../instruction-int.h"
+
+
+
+/* Définition générique d'une instruction brute d'architecture (instance) */
+struct _GRawInstruction
+{
+ GArchInstruction parent; /* A laisser en premier */
+
+};
+
+/* Définition générique d'une instruction brute d'architecture (instance) */
+struct _GRawInstructionClass
+{
+ GArchInstructionClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une instruction de type 'db/dw/etc' simple. */
+bool g_raw_instruction_create_value(GRawInstruction *, GBinaryPortion *, const vmpa2t *, MemoryDataSize, uint64_t);
+
+/* Met en place une instruction de type 'db/dw/etc' étendue. */
+bool g_raw_instruction_create_array(GRawInstruction *, GBinaryPortion *, vmpa2t *, MemoryDataSize, const GBinContent *, size_t, SourceEndian);
+
+
+
+#endif /* _ARCH_INSTRUCTIONS_RAW_INT_H */
diff --git a/src/arch/instructions/raw-ui.c b/src/arch/instructions/raw-ui.c
new file mode 100644
index 0000000..1026dfb
--- /dev/null
+++ b/src/arch/instructions/raw-ui.c
@@ -0,0 +1,261 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * raw-ui.c - opérandes représentant des instructions de données brutes sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "raw-ui.h"
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+
+
+#include "raw.h"
+#include "../operand-ui.h"
+#include "../operands/immediate.h"
+#include "../../glibext/objhole.h"
+#include "../../glibext/options/asm.h"
+
+
+
+/* Etablit dans une ligne de rendu le contenu représenté. */
+static void g_raw_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de génération. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_raw_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface)
+{
+ iface->populate = g_raw_instruction_ui_populate_line;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : generator = générateur à utiliser pour l'impression. *
+* index = indice de cette même ligne dans le tampon global.*
+* repeat = indice d'utilisations successives du générateur. *
+* line = ligne de rendu à compléter. *
+* data = éventuelle donnée complémentaire fournie. *
+* *
+* Description : Etablit dans une ligne de rendu le contenu représenté. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_raw_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data)
+{
+ GArchInstruction *instr; /* Version spécialisée #1 */
+ GRawInstruction *raw; /* Version spécialisée #2 */
+ GBinContent *content; /* Contenu brut d'origine */
+ mrange_t range; /* Emplacement couvert */
+ phys_t max_displayed_len; /* Quantité de code affichée */
+ char *key; /* Mot clef principal */
+ char *string; /* Chaîne reconstituée */
+ size_t iter; /* Tête d'écriture */
+ bool first; /* Mémorise une énumération */
+ size_t count; /* Nombre d'opérandes en place */
+ size_t i; /* Boucle de parcours */
+ GArchOperand *op; /* Opérande à manipuler */
+ GImmediateOperand *imm; /* Version opérande de valeur */
+ char byte; /* Octet à afficher (ou pas) */
+#ifndef NDEBUG
+ bool status; /* Bilan d'une récupération */
+#endif
+
+ instr = G_ARCH_INSTRUCTION(generator);
+ raw = G_RAW_INSTRUCTION(instr);
+ content = G_BIN_CONTENT(data);
+
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+
+ /* Prologue */
+
+ if (g_arch_instruction_get_range(instr, &range))
+ {
+ /* Localisation */
+
+ g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range));
+
+ g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range));
+
+ /* Contenu */
+
+ if (g_raw_instruction_is_padding(raw))
+ max_displayed_len = 0;
+
+ else if (g_raw_instruction_is_string(raw))
+ max_displayed_len = 1;
+
+ else
+ {
+ max_displayed_len = get_mrange_length(&range);
+ max_displayed_len /= g_arch_instruction_count_operands(instr);
+ }
+
+ g_buffer_line_fill_content(line, ACO_BINARY, content, &range, max_displayed_len);
+
+ }
+
+ /* Instruction proprement dite */
+
+ key = g_arch_instruction_get_keyword(instr);
+
+ g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_INSTRUCTION, SL(key), NULL, G_OBJECT(instr));
+
+ free(key);
+
+ /* Contenu sous forme d'opérandes */
+
+ if (g_raw_instruction_is_padding(raw))
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL("..."), NULL, NULL);
+
+ else
+ {
+ string = NULL;
+ iter = 0;
+
+ first = true;
+
+ count = g_arch_instruction_count_operands(instr);
+
+ for (i = 0; i < count; i++)
+ {
+ op = g_arch_instruction_get_operand(instr, i);
+
+ if (!G_IS_IMMEDIATE_OPERAND(op))
+ goto fallback;
+
+ imm = G_IMMEDIATE_OPERAND(op);
+
+ if (g_immediate_operand_get_size(imm) != MDS_8_BITS)
+ goto fallback;
+
+ if (!g_raw_instruction_is_string(raw) && g_immediate_operand_get_display(imm) != IOD_CHAR)
+ goto fallback;
+
+#ifndef NDEBUG
+ status = g_immediate_operand_get_value(imm, MDS_8_BITS, &byte);
+ assert(status);
+#else
+ g_immediate_operand_get_value(imm, MDS_8_BITS, &byte);
+#endif
+
+ /* Si le caractère doit apparaître en hexadécimal... */
+
+ if (!isprint(byte))
+ goto fallback;
+
+ /* Impression de l'octet */
+
+ if (string == NULL)
+ {
+ string = calloc(count + 3, sizeof(char));
+
+ strcpy(string, "\"");
+ iter = 1;
+
+ }
+
+ string[iter++] = byte;
+
+ unref_object(op);
+
+ continue;
+
+ fallback:
+
+ /* Si une chaîne précède */
+
+ if (string != NULL && iter > 1)
+ {
+ if (!first)
+ {
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL);
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL);
+ }
+ else
+ first = false;
+
+ string[iter++] = '"';
+
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_STRING, string, iter, NULL, NULL);
+
+ iter = 1;
+
+ }
+
+ /* Intégration en tant qu'opérande classique */
+
+ if (!first)
+ {
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL);
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL);
+ }
+ else
+ first = false;
+
+ g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line);
+
+ unref_object(op);
+
+ }
+
+ /* Si au final une chaîne traine encore */
+
+ if (string != NULL && iter > 1)
+ {
+ if (!first)
+ {
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL);
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL);
+ }
+
+ string[iter++] = '"';
+
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_STRING, string, iter, NULL, NULL);
+
+ }
+
+ if (string != NULL)
+ free(string);
+
+ }
+
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
+
+}
diff --git a/src/arch/instructions/raw-ui.h b/src/arch/instructions/raw-ui.h
new file mode 100644
index 0000000..cd604e6
--- /dev/null
+++ b/src/arch/instructions/raw-ui.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * raw-ui.h - prototypes pour les opérandes représentant des instructions de données brutes sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_OPERANDS_RAW_UI_H
+#define _ARCH_OPERANDS_RAW_UI_H
+
+
+#include "../../glibext/generator-int.h"
+
+
+
+/* Procède à l'initialisation de l'interface de génération. */
+void g_raw_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *);
+
+
+
+#endif /* _ARCH_OPERANDS_RAW_UI_H */
diff --git a/src/arch/instructions/raw.c b/src/arch/instructions/raw.c
index 26282fa..87297f1 100644
--- a/src/arch/instructions/raw.c
+++ b/src/arch/instructions/raw.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* raw.c - instructions pures vues de l'esprit
*
- * Copyright (C) 2014-2020 Cyrille Bagard
+ * Copyright (C) 2014-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,36 +25,19 @@
#include <assert.h>
-#include <ctype.h>
#include <string.h>
#include <i18n.h>
-#include "../instruction-int.h"
+#include "raw-int.h"
#include "../operands/immediate.h"
-#include "../operands/target.h"
-#include "../../core/columns.h"
+//#include "../operands/target.h" // FIXME
-/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */
-
-
-/* Définition générique d'une instruction brute d'architecture (instance) */
-struct _GRawInstruction
-{
- GArchInstruction parent; /* A laisser en premier */
-
-};
-
-/* Définition générique d'une instruction brute d'architecture (classe) */
-struct _GRawInstructionClass
-{
- GArchInstructionClass parent; /* A laisser en premier */
-
-};
+/* --------------------- INSTRUCTION AVEC JEU DE DONNEES BRUTES --------------------- */
/* Initialise la classe des instructions brutes d'architecture. */
@@ -64,40 +47,26 @@ static void g_raw_instruction_class_init(GRawInstructionClass *);
static void g_raw_instruction_init(GRawInstruction *);
/* Supprime toutes les références externes. */
-static void g_raw_instruction_dispose(GRawInstruction *);
+static void g_raw_instruction_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_raw_instruction_finalize(GRawInstruction *);
-
-/* Indique l'encodage d'une instruction de façon détaillée. */
-static const char *g_raw_instruction_get_encoding(const GRawInstruction *);
-
-/* Fournit le nom humain de l'instruction manipulée. */
-static const char *g_raw_instruction_get_keyword(const GRawInstruction *);
+static void g_raw_instruction_finalize(GObject *);
-/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-/* Charge une instruction depuis une mémoire tampon. */
-static bool g_raw_instruction_unserialize(GRawInstruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *);
-
-/* Sauvegarde une instruction dans une mémoire tampon. */
-static bool g_raw_instruction_serialize(GRawInstruction *, GAsmStorage *, packed_buffer_t *);
-
-
-
-/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
-
+/* Indique l'encodage d'une instruction de façon détaillée. */
+static char *g_raw_instruction_get_encoding(const GArchInstruction *);
-/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
-static void g_raw_instruction_print(GRawInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
+/* Fournit le nom humain de l'instruction manipulée. */
+static char *g_raw_instruction_get_keyword(const GArchInstruction *);
/* ---------------------------------------------------------------------------------- */
-/* INSTRUCTION INCONNUE / DONNEES */
+/* INSTRUCTION AVEC JEU DE DONNEES BRUTES */
/* ---------------------------------------------------------------------------------- */
@@ -124,18 +93,13 @@ static void g_raw_instruction_class_init(GRawInstructionClass *klass)
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_raw_instruction_dispose;
- object->finalize = (GObjectFinalizeFunc)g_raw_instruction_finalize;
+ object->dispose = g_raw_instruction_dispose;
+ object->finalize = g_raw_instruction_finalize;
instr = G_ARCH_INSTRUCTION_CLASS(klass);
- instr->get_encoding = (get_instruction_encoding_fc)g_raw_instruction_get_encoding;
- instr->get_keyword = (get_instruction_keyword_fc)g_raw_instruction_get_keyword;
-
- instr->unserialize = (unserialize_instruction_fc)g_raw_instruction_unserialize;
- instr->serialize = (serialize_instruction_fc)g_raw_instruction_serialize;
-
- instr->print = (print_instruction_fc)g_raw_instruction_print;
+ instr->get_encoding = g_raw_instruction_get_encoding;
+ instr->get_keyword = g_raw_instruction_get_keyword;
}
@@ -160,7 +124,7 @@ static void g_raw_instruction_init(GRawInstruction *instr)
/******************************************************************************
* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -170,16 +134,16 @@ static void g_raw_instruction_init(GRawInstruction *instr)
* *
******************************************************************************/
-static void g_raw_instruction_dispose(GRawInstruction *instr)
+static void g_raw_instruction_dispose(GObject *object)
{
- G_OBJECT_CLASS(g_raw_instruction_parent_class)->dispose(G_OBJECT(instr));
+ G_OBJECT_CLASS(g_raw_instruction_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -189,16 +153,17 @@ static void g_raw_instruction_dispose(GRawInstruction *instr)
* *
******************************************************************************/
-static void g_raw_instruction_finalize(GRawInstruction *instr)
+static void g_raw_instruction_finalize(GObject *object)
{
- G_OBJECT_CLASS(g_raw_instruction_parent_class)->finalize(G_OBJECT(instr));
+ G_OBJECT_CLASS(g_raw_instruction_parent_class)->finalize(object);
}
/******************************************************************************
* *
-* Paramètres : addr = position à associer à l'instruction. *
+* Paramètres : area = portion de binaire incluant l'instruction. *
+* addr = adresse virtuelle et/ou position physique. *
* size = taille de l'opérande souhaitée. *
* value = valeur sur x bits à venir récupérer. *
* *
@@ -210,127 +175,106 @@ static void g_raw_instruction_finalize(GRawInstruction *instr)
* *
******************************************************************************/
-GArchInstruction *g_raw_instruction_new_from_value(const vmpa2t *addr, MemoryDataSize size, uint64_t value)
+GArchInstruction *g_raw_instruction_new_from_value(GBinaryPortion *area, const vmpa2t *addr, MemoryDataSize size, uint64_t value)
{
GArchInstruction *result; /* Instruction à retourner */
- GArchOperand *operand; /* Octet non décodé à afficher */
- mrange_t range; /* Couverture de l'instruction */
result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL);
- operand = g_imm_operand_new_from_value(size, value);
- if (operand == NULL) goto error;
+ if (!g_raw_instruction_create_value(G_RAW_INSTRUCTION(result), area, addr, size, value))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instance à initialiser pleinement. *
+* area = portion de binaire incluant l'instruction. *
+* addr = adresse virtuelle et/ou position physique. *
+* size = taille de chacun des éléments à représenter. *
+* value = valeur sur x bits à venir récupérer. *
+* *
+* Description : Met en place une instruction de type 'db/dw/etc' simple. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_raw_instruction_create_value(GRawInstruction *instr, GBinaryPortion *area, const vmpa2t *addr, MemoryDataSize size, uint64_t value)
+{
+ bool result; /* Bilan à retourner */
+ GArchOperand *operand; /* Octet non décodé à afficher */
+ uint16_t length; /* Taille de l'instruction */
+
+ result = false;
+
+ operand = g_immediate_operand_new_from_value(size, value);
+ if (operand == NULL) goto exit;
g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING);
- g_arch_instruction_attach_extra_operand(result, operand);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
+
+ g_arch_instruction_attach_operand(G_ARCH_INSTRUCTION(instr), operand);
+ unref_object(operand);
+
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
switch (size)
{
case MDS_8_BITS_UNSIGNED:
case MDS_8_BITS_SIGNED:
- init_mrange(&range, addr, 1);
+ length = 1;
break;
case MDS_16_BITS_UNSIGNED:
case MDS_16_BITS_SIGNED:
- init_mrange(&range, addr, 2);
+ length = 2;
break;
case MDS_32_BITS_UNSIGNED:
case MDS_32_BITS_SIGNED:
- init_mrange(&range, addr, 4);
+ length = 4;
break;
case MDS_64_BITS_UNSIGNED:
case MDS_64_BITS_SIGNED:
- init_mrange(&range, addr, 8);
+ length = 8;
break;
default:
assert(false);
- goto error;
+ goto exit;
break;
}
- g_arch_instruction_set_range(result, &range);
+ g_arch_instruction_compute_range(G_ARCH_INSTRUCTION(instr), area, addr, length);
- return result;
-
- error:
-
- g_object_unref(G_OBJECT(result));
-
- return NULL;
-
-}
+ result = true;
-
-/******************************************************************************
-* *
-* Paramètres : content = flux de données à analyser. *
-* addr = position courante dans ce flux. [OUT] *
-* *
-* Description : Crée une instruction de type 'db/dw/etc' pour un uleb128. *
-* *
-* Retour : Instruction mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa2t *addr)
-{
- GArchInstruction *result; /* Instruction à retourner */
- vmpa2t start; /* Départ original de lecture */
- uleb128_t value; /* Valeur uleb128 à représenter*/
- phys_t diff; /* Couverture de la lecture */
- MemoryDataSize leb_size; /* Taille de la valeur */
- GArchOperand *operand; /* Octet non décodé à afficher */
- mrange_t range; /* Couverture de l'instruction */
-
- result = NULL;
-
- copy_vmpa(&start, addr);
-
- if (!g_binary_content_read_uleb128(content, addr, &value))
- goto error;
-
- diff = compute_vmpa_diff(&start, addr);
-
- leb_size = MDS_FROM_BYTES(diff);
- assert(leb_size != MDS_UNDEFINED);
-
- result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL);
-
- init_mrange(&range, &start, diff);
- g_arch_instruction_set_range(result, &range);
-
- operand = g_imm_operand_new_from_value(leb_size, (uint64_t)value);
- if (operand == NULL) goto error;
-
- g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING);
-
- g_arch_instruction_attach_extra_operand(result, operand);
+ exit:
return result;
- error:
-
- g_clear_object(&result);
-
- return NULL;
-
}
/******************************************************************************
* *
-* Paramètres : content = flux de données à analyser. *
-* addr = position courante dans ce flux. [OUT] *
+* Paramètres : area = portion de binaire incluant l'instruction. *
+* addr = adresse virtuelle et/ou position physique. *
+* size = taille de chacun des éléments à représenter. *
+* content = flux de données à analyser. *
+* count = nombre de ces éléments. *
+* endian = ordre des bits dans la source. *
* *
-* Description : Crée une instruction de type 'db/dw/etc' pour un sleb128. *
+* Description : Crée une instruction de type 'db/dw/etc' étendue. *
* *
* Retour : Instruction mise en place. *
* *
@@ -338,256 +282,174 @@ GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa
* *
******************************************************************************/
-GArchInstruction *g_raw_instruction_new_sleb128(const GBinContent *content, vmpa2t *addr)
+GArchInstruction *g_raw_instruction_new_array(GBinaryPortion *area, vmpa2t *addr, MemoryDataSize size, const GBinContent *content, size_t count, SourceEndian endian)
{
GArchInstruction *result; /* Instruction à retourner */
- vmpa2t start; /* Départ original de lecture */
- uleb128_t value; /* Valeur uleb128 à représenter*/
- phys_t diff; /* Couverture de la lecture */
- MemoryDataSize leb_size; /* Taille de la valeur */
- GArchOperand *operand; /* Octet non décodé à afficher */
- mrange_t range; /* Couverture de l'instruction */
-
- result = NULL;
-
- copy_vmpa(&start, addr);
-
- if (!g_binary_content_read_uleb128(content, addr, &value))
- goto error;
-
- diff = compute_vmpa_diff(&start, addr);
-
- leb_size = MDS_FROM_BYTES(diff) | MDS_SIGN;
- assert(leb_size != MDS_SIGN);
result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL);
- init_mrange(&range, &start, diff);
- g_arch_instruction_set_range(result, &range);
-
- operand = g_imm_operand_new_from_value(leb_size, (uint64_t)value);
- if (operand == NULL) goto error;
-
- g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING);
-
- g_arch_instruction_attach_extra_operand(result, operand);
+ if (!g_raw_instruction_create_array(G_RAW_INSTRUCTION(result), area, addr, size, content, count, endian))
+ g_clear_object(&result);
return result;
- error:
-
- g_clear_object(&result);
-
- return NULL;
-
}
/******************************************************************************
* *
-* Paramètres : content = flux de données à analyser. *
+* Paramètres : instr = instance à initialiser pleinement. *
+* area = portion de binaire incluant l'instruction. *
+* addr = adresse virtuelle et/ou position physique. *
* size = taille de chacun des éléments à représenter. *
+* content = flux de données à analyser. *
* count = nombre de ces éléments. *
-* addr = position courante dans ce flux. [OUT] *
* endian = ordre des bits dans la source. *
* *
-* Description : Crée une instruction de type 'db/dw/etc' étendue. *
+* Description : Met en place une instruction de type 'db/dw/etc' étendue. *
* *
-* Retour : Instruction mise en place. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GArchInstruction *g_raw_instruction_new_array(const GBinContent *content, MemoryDataSize size, size_t count, vmpa2t *addr, SourceEndian endian)
+bool g_raw_instruction_create_array(GRawInstruction *instr, GBinaryPortion *area, vmpa2t *addr, MemoryDataSize size, const GBinContent *content, size_t count, SourceEndian endian)
{
- GArchInstruction *result; /* Instruction à retourner */
- vmpa2t old; /* Sauvegarde de la position */
+ bool result; /* Bilan à retourner */
+ vmpa2t start; /* Sauvegarde de la position */
size_t i; /* Boucle de parcours */
GArchOperand *operand; /* Octet non décodé à afficher */
- mrange_t range; /* Couverture de l'instruction */
+ phys_t diff; /* Décalage à appliquer */
+
+ result = false;
/* Par soucis de cohérence */
- if (count == 0) return NULL;
+ if (count == 0)
+ goto exit;
- result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL);
+ copy_vmpa(&start, addr);
- copy_vmpa(&old, addr);
+ g_thick_object_lock(G_THICK_OBJECT(instr));
for (i = 0; i < count; i++)
{
- operand = g_imm_operand_new_from_data(size, content, addr, endian);
- if (operand == NULL) goto error;
+ operand = g_immediate_operand_new_from_data(size, content, addr, (bool []){ false /* unused */ }, endian);
+ if (operand == NULL) break;
g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING);
- g_arch_instruction_attach_extra_operand(result, operand);
+ g_arch_instruction_attach_operand(G_ARCH_INSTRUCTION(instr), operand);
+ unref_object(operand);
}
- init_mrange(&range, &old, compute_vmpa_diff(addr, &old));
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
- g_arch_instruction_set_range(result, &range);
+ if (i < count)
+ goto exit;
- return result;
+ diff = compute_vmpa_diff(addr, &start);
+
+ g_arch_instruction_compute_range(G_ARCH_INSTRUCTION(instr), area, &start, diff);
- error:
+ result = true;
- g_object_unref(G_OBJECT(result));
+ exit:
- return NULL;
+ return result;
}
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à consulter. *
+* Paramètres : instr = instruction à traiter. *
+* is_padding = nouveau statut à associer au contenu. *
* *
-* Description : Indique l'encodage d'une instruction de façon détaillée. *
+* Description : Marque l'instruction comme ne contenant que du bourrage. *
* *
-* Retour : Description humaine de l'encodage utilisé. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static const char *g_raw_instruction_get_encoding(const GRawInstruction *instr)
+void g_raw_instruction_mark_as_padding(GRawInstruction *instr, bool is_padding)
{
- const char *result; /* Description à retourner */
-
- if (g_raw_instruction_is_string(instr))
- result = _("String");
+ if (is_padding)
+ g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);
else
- result = _("Raw");
-
- return result;
+ g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);
}
/******************************************************************************
* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
+* Paramètres : instr = instruction à traiter. *
+* is_padding = nouveau statut à associer au contenu. *
* *
-* Description : Fournit le nom humain de l'instruction manipulée. *
+* Description : Indique si le contenu de l'instruction est du bourrage. *
* *
-* Retour : Mot clef de bas niveau. *
+* Retour : Statut du contenu de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
-static const char *g_raw_instruction_get_keyword(const GRawInstruction *instr)
+bool g_raw_instruction_is_padding(const GRawInstruction *instr)
{
- GArchOperand *operand; /* Octet décodé à afficher */
- MemoryDataSize size; /* Taille de valeur associée */
-
- static char *defines[] = { "dn", "db", "dw", "dd", "dq" };
-
- operand = g_arch_instruction_get_operand(G_ARCH_INSTRUCTION(instr), 0);
-
- if (G_IS_TARGET_OPERAND(operand))
- size = g_target_operand_get_size(G_TARGET_OPERAND(operand));
- else
- size = g_imm_operand_get_size(G_IMM_OPERAND(operand));
+ bool result; /* Indication à retourner */
- g_object_unref(G_OBJECT(operand));
+ result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);
- return defines[MDS_RANGE(size)];
+ return result;
}
-
-/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION SUR DISQUE DES INSTRUCTIONS */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
-* storage = mécanisme de sauvegarde à manipuler. *
-* format = format binaire chargé associé à l'architecture. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : instr = instruction à traiter. *
+* is_string = nouveau statut à associer au contenu. *
* *
-* Description : Charge une instruction depuis une mémoire tampon. *
+* Description : Marque l'instruction comme contenant une chaîne de texte. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_raw_instruction_unserialize(GRawInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf)
+void g_raw_instruction_mark_as_string(GRawInstruction *instr, bool is_string)
{
- bool result; /* Bilan à retourner */
- GArchInstructionClass *parent; /* Classe parente à consulter */
- uint8_t boolean; /* Valeur booléenne */
-
- parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class);
-
- result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf);
-
- if (result)
- {
- result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
-
- if (result)
- g_raw_instruction_mark_as_padding(instr, (boolean == 1));
-
- }
-
- if (result)
- {
- result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
-
- if (result)
- g_raw_instruction_mark_as_string(instr, (boolean == 1));
-
- }
-
- return result;
+ if (is_string)
+ g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);
+ else
+ g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);
}
/******************************************************************************
* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
-* storage = mécanisme de sauvegarde à manipuler. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : instr = instruction à traiter. *
+* is_string = nouveau statut à associer au contenu. *
* *
-* Description : Sauvegarde une instruction dans une mémoire tampon. *
+* Description : Indique si le contenu de l'instruction est un texte. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Statut du contenu de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_raw_instruction_serialize(GRawInstruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf)
+bool g_raw_instruction_is_string(const GRawInstruction *instr)
{
- bool result; /* Bilan à retourner */
- GArchInstructionClass *parent; /* Classe parente à consulter */
- uint8_t boolean; /* Valeur booléenne */
-
- parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class);
-
- result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf);
-
- if (result)
- {
- boolean = (g_raw_instruction_is_padding(instr) ? 1 : 0);
- result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
- }
+ bool result; /* Indication à retourner */
- if (result)
- {
- boolean = (g_raw_instruction_is_string(instr) ? 1 : 0);
- result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
- }
+ result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);
return result;
@@ -596,285 +458,73 @@ static bool g_raw_instruction_serialize(GRawInstruction *instr, GAsmStorage *sto
/* ---------------------------------------------------------------------------------- */
-/* OFFRE DE CAPACITES DE GENERATION */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : instr = instruction d'assemblage à représenter. *
-* line = ligne de rendu à compléter. *
-* index = indice de cette même ligne dans le tampon global. *
-* repeat = indice d'utilisations successives du générateur. *
-* content = éventuel contenu binaire brut à imprimer. *
+* Paramètres : instr = instruction quelconque à consulter. *
* *
-* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. *
+* Description : Indique l'encodage d'une instruction de façon détaillée. *
* *
-* Retour : - *
+* Retour : Description humaine de l'encodage utilisé. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_raw_instruction_print(GRawInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content)
+static char *g_raw_instruction_get_encoding(const GArchInstruction *instr)
{
- GArchInstruction *base; /* Autre version de l'instance */
- phys_t max_displayed_len; /* Quantité de code affichée */
- const char *key; /* Mot clef principal */
- size_t klen; /* Taille de ce mot clef */
- char *string; /* Chaîne reconstituée */
- size_t iter; /* Tête d'écriture */
- bool first; /* Mémorise une énumération */
- size_t count; /* Nombre d'opérandes en place */
- size_t i; /* Boucle de parcours */
- GArchOperand *op; /* Opérande à manipuler */
- GImmOperand *imm; /* Version opérande de valeur */
- char byte; /* Octet à afficher (ou pas) */
-#ifndef NDEBUG
- bool status; /* Bilan d'une récupération */
-#endif
-
- base = G_ARCH_INSTRUCTION(instr);
-
- /* Localisation */
-
- g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range));
-
- g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range));
-
- /* Contenu */
-
- if (g_raw_instruction_is_padding(instr))
- max_displayed_len = 0;
-
- else if (g_raw_instruction_is_string(instr))
- max_displayed_len = 1;
-
- else
- {
- max_displayed_len = get_mrange_length(&base->range);
- max_displayed_len /= g_arch_instruction_count_operands(base);
- }
-
- g_buffer_line_fill_content(line, DLC_BINARY, content, &base->range, max_displayed_len);
-
- /* Zone du code d'assemblage */
+ char *result; /* Description à retourner */
+ GRawInstruction *raw; /* Version spécialisée */
- key = g_arch_instruction_get_keyword(base);
- klen = strlen(key);
-
- g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION, NULL);
-
- if (g_raw_instruction_is_padding(instr))
- g_buffer_line_append_text(line, DLC_ASSEMBLY, "...", 3, RTT_RAW, NULL);
+ raw = G_RAW_INSTRUCTION(instr);
+ if (g_raw_instruction_is_string(raw))
+ result = strdup(_("String"));
else
- {
- string = NULL;
- iter = 0;
-
- first = true;
-
- g_arch_instruction_lock_operands(base);
-
- count = _g_arch_instruction_count_operands(base);
-
- for (i = 0; i < count; i++)
- {
- op = _g_arch_instruction_get_operand(base, i);
-
- if (!G_IS_IMM_OPERAND(op))
- goto grip_fallback;
-
- imm = G_IMM_OPERAND(op);
-
- if (g_imm_operand_get_size(imm) != MDS_8_BITS)
- goto grip_fallback;
-
- if (!g_raw_instruction_is_string(instr) && g_imm_operand_get_display(imm) != IOD_CHAR)
- goto grip_fallback;
-
-#ifndef NDEBUG
- status = g_imm_operand_get_value(imm, MDS_8_BITS, &byte);
- assert(status);
-#else
- g_imm_operand_get_value(imm, MDS_8_BITS, &byte);
-#endif
-
- /* Si le caractère doit apparaître en hexadécimal... */
-
- if (!isprint(byte))
- goto grip_fallback;
-
- /* Impression de l'octet */
-
- if (string == NULL)
- {
- string = (char *)calloc(count + 3, sizeof(char));
-
- strcpy(string, "\"");
- iter = 1;
-
- }
-
- string[iter++] = byte;
-
- g_object_unref(G_OBJECT(op));
-
- continue;
-
- grip_fallback:
-
- /* Si une chaîne précède */
-
- if (string != NULL && iter > 1)
- {
- if (!first)
- {
- g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL);
- g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL);
- }
- else
- first = false;
-
- string[iter++] = '"';
-
- g_buffer_line_append_text(line, DLC_ASSEMBLY, string, iter, RTT_STRING, NULL);
-
- iter = 1;
-
- }
-
- /* Intégration en tant qu'opérande classique */
-
- if (!first)
- {
- g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL);
- g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL);
- }
- else
- first = false;
-
- g_arch_operand_print(op, line);
-
- g_object_unref(G_OBJECT(op));
-
- }
-
- /* Si au final une chaîne traine encore */
-
- if (string != NULL && iter > 1)
- {
- if (!first)
- {
- g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL);
- g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL);
- }
-
- string[iter++] = '"';
-
- g_buffer_line_append_text(line, DLC_ASSEMBLY, string, iter, RTT_STRING, NULL);
-
- }
+ result = strdup(_("Raw"));
- g_arch_instruction_unlock_operands(base);
-
- if (string != NULL)
- free(string);
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : instr = instruction à traiter. *
-* is_padding = nouveau statut à associer au contenu. *
-* *
-* Description : Marque l'instruction comme ne contenant que du bourrage. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_raw_instruction_mark_as_padding(GRawInstruction *instr, bool is_padding)
-{
- if (is_padding)
- g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);
- else
- g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : instr = instruction à traiter. *
-* is_padding = nouveau statut à associer au contenu. *
+* Paramètres : instr = instruction d'assemblage à consulter. *
* *
-* Description : Indique si le contenu de l'instruction est du bourrage. *
+* Description : Fournit le nom humain de l'instruction manipulée. *
* *
-* Retour : Statut du contenu de l'instruction. *
+* Retour : Mot clef de bas niveau. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_raw_instruction_is_padding(const GRawInstruction *instr)
+static char *g_raw_instruction_get_keyword(const GArchInstruction *instr)
{
- bool result; /* Indication à retourner */
-
- result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);
-
- return result;
-
-}
+ char *result; /* Désignation à retourner */
+ GArchOperand *operand; /* Octet décodé à afficher */
+ MemoryDataSize size; /* Taille de valeur associée */
+ static char *defines[] = { "dn", "db", "dw", "dd", "dq" };
-/******************************************************************************
-* *
-* Paramètres : instr = instruction à traiter. *
-* is_string = nouveau statut à associer au contenu. *
-* *
-* Description : Marque l'instruction comme contenant une chaîne de texte. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ g_thick_object_lock(G_THICK_OBJECT(instr));
-void g_raw_instruction_mark_as_string(GRawInstruction *instr, bool is_string)
-{
- if (is_string)
- g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);
- else
- g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);
-
-}
+ operand = g_arch_instruction_get_operand(instr, 0);
+ /*if (G_IS_TARGET_OPERAND(operand)) FIXME
+ size = g_target_operand_get_size(G_TARGET_OPERAND(operand));
+ else*/
+ size = g_immediate_operand_get_size(G_IMMEDIATE_OPERAND(operand));
-/******************************************************************************
-* *
-* Paramètres : instr = instruction à traiter. *
-* is_string = nouveau statut à associer au contenu. *
-* *
-* Description : Indique si le contenu de l'instruction est un texte. *
-* *
-* Retour : Statut du contenu de l'instruction. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ unref_object(operand);
-bool g_raw_instruction_is_string(const GRawInstruction *instr)
-{
- bool result; /* Indication à retourner */
+ g_thick_object_unlock(G_THICK_OBJECT(instr));
- result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);
+ result = strdup(defines[MDS_RANGE(size)]);
return result;
diff --git a/src/arch/instructions/raw.h b/src/arch/instructions/raw.h
index 4e92cd4..712f877 100644
--- a/src/arch/instructions/raw.h
+++ b/src/arch/instructions/raw.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * raw.h - prototypes pour les instructions pures vues de l'esprit
+ * raw.h - prototypes pour les instructions de données brutes
*
- * Copyright (C) 2014-2020 Cyrille Bagard
+ * Copyright (C) 2014-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,46 +25,24 @@
#define _ARCH_INSTRUCTIONS_RAW_H
-#include <glib-object.h>
-
-
#include "../instruction.h"
#include "../vmpa.h"
+#include "../../analysis/content.h"
+#include "../../glibext/helpers.h"
-/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */
-
-
-#define G_TYPE_RAW_INSTRUCTION g_raw_instruction_get_type()
-#define G_RAW_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RAW_INSTRUCTION, GRawInstruction))
-#define G_IS_RAW_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RAW_INSTRUCTION))
-#define G_RAW_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RAW_INSTRUCTION, GRawInstructionClass))
-#define G_IS_RAW_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RAW_INSTRUCTION))
-#define G_RAW_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RAW_INSTRUCTION, GRawInstructionClass))
-
+#define G_TYPE_RAW_INSTRUCTION (g_raw_instruction_get_type())
-/* Définition générique d'une instruction brute d'architecture (instance) */
-typedef struct _GRawInstruction GRawInstruction;
+DECLARE_GTYPE(GRawInstruction, g_raw_instruction, G, RAW_INSTRUCTION);
-/* Définition générique d'une instruction brute d'architecture (classe) */
-typedef struct _GRawInstructionClass GRawInstructionClass;
-
-
-/* Indique le type défini pour une instruction inconnue d'architecture. */
-GType g_raw_instruction_get_type(void);
/* Crée une instruction de type 'db/dw/etc' simple. */
-GArchInstruction *g_raw_instruction_new_from_value(const vmpa2t *, MemoryDataSize, uint64_t);
+GArchInstruction *g_raw_instruction_new_from_value(GBinaryPortion *, const vmpa2t *, MemoryDataSize, uint64_t);
-/* Crée une instruction de type 'db/dw/etc' pour un uleb128. */
-GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa2t *);
+/* Crée une instruction de type 'db/dw/etc' étendue. */
+GArchInstruction *g_raw_instruction_new_array(GBinaryPortion *, vmpa2t *, MemoryDataSize, const GBinContent *, size_t, SourceEndian);
-/* Crée une instruction de type 'db/dw/etc' pour un sleb128. */
-GArchInstruction *g_raw_instruction_new_sleb128(const GBinContent *content, vmpa2t *);
-
-/* Crée une instruction de type 'db/dw/etc' étendue. */
-GArchInstruction *g_raw_instruction_new_array(const GBinContent *, MemoryDataSize, size_t, vmpa2t *, SourceEndian);
/* Drapeaux pour informations complémentaires */
typedef enum _RawInstrFlag
@@ -74,6 +52,7 @@ typedef enum _RawInstrFlag
} RawInstrFlag;
+
/* Marque l'instruction comme ne contenant que du bourrage. */
void g_raw_instruction_mark_as_padding(GRawInstruction *, bool);
diff --git a/src/arch/instructions/undefined-int.h b/src/arch/instructions/undefined-int.h
index a9b7627..faf0b4b 100644
--- a/src/arch/instructions/undefined-int.h
+++ b/src/arch/instructions/undefined-int.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * undefined-int.h - prototypes pour la définition générique interne des instructions au comportement non défini
+ * undefined-int.h - prototypes pour la définition interne des instructions au comportement non défini
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -27,42 +27,18 @@
#include "undefined.h"
#include "../instruction-int.h"
-#include "../../glibext/objhole.h"
-/* Informations glissées dans la structure GObject de GArchInstruction */
-typedef struct _undef_extra_data_t
-{
- /**
- * Le champ uid de la structure parente attendue conduit à une taille
- * alignée sur 2 octets, donc à une taille totale de 4 octets ce qui
- * représente la limite maximale de taille supportée.
- *
- * Pour 3 octets à la base, qui devraient laisser 8 - 1 octets disponbibles
- * en incluant le bit de verrouillage.
- *
- * On reproduit donc la structure instr_extra_data_t ici, en basculant
- * l'énumération InstrExpectedBehavior en champ de bits.
- */
-
- itid_t uid; /* Identifiant unique du type */
- ArchInstrFlag flags; /* Informations complémentaires*/
-
- unsigned int behavior : 2; /* Conséquences réelles */
-
-} undef_extra_data_t;
-
-
/* Définition générique d'une instruction au comportement non défini (instance) */
-struct _GUndefInstruction
+struct _GUndefinedInstruction
{
GArchInstruction parent; /* A laisser en premier */
};
/* Définition générique d'une instruction au comportement non défini (classe) */
-struct _GUndefInstructionClass
+struct _GUndefinedInstructionClass
{
GArchInstructionClass parent; /* A laisser en premier */
@@ -73,15 +49,25 @@ struct _GUndefInstructionClass
* Accès aux informations éventuellement déportées.
*/
-#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__
+/* Informations glissées dans la structure GObject de GArchInstruction */
+typedef struct _undef_extra_data_t
+{
+ ARCH_INSTRUCTION_EXTRA_DATA
+
+ unsigned int behavior : 2; /* Conséquences réelles */
+
+} undef_extra_data_t;
+
-# define GET_UNDEF_INSTR_EXTRA(ins) ((undef_extra_data_t *)&((GArchInstruction *)ins)->extra)
+#define GET_UNDEF_INSTR_EXTRA(op) \
+ GET_GOBJECT_EXTRA(op, undef_extra_data_t)
-#else
+#define SET_UNDEF_INSTR_EXTRA(op, data) \
+ SET_GOBJECT_EXTRA(op, undef_extra_data_t, data)
-# define GET_UNDEF_INSTR_EXTRA(ins) GET_GOBJECT_EXTRA(G_OBJECT(ins), undef_extra_data_t)
-#endif
+/* Met en place une instruction au comportement indéfini. */
+bool g_undefined_instruction_create(GUndefinedInstruction *, InstrExpectedBehavior);
diff --git a/src/arch/instructions/undefined-ui.c b/src/arch/instructions/undefined-ui.c
new file mode 100644
index 0000000..fbc0452
--- /dev/null
+++ b/src/arch/instructions/undefined-ui.c
@@ -0,0 +1,102 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * undefined-ui.c - opérandes représentant des instructions indéfinies sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "undefined-ui.h"
+
+
+#include "../instruction.h"
+#include "../../glibext/options/asm.h"
+
+
+
+/* Etablit dans une ligne de rendu le contenu représenté. */
+static void g_undefined_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de génération. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_undefined_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface)
+{
+ iface->populate = g_undefined_instruction_ui_populate_line;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : generator = générateur à utiliser pour l'impression. *
+* index = indice de cette même ligne dans le tampon global.*
+* repeat = indice d'utilisations successives du générateur. *
+* line = ligne de rendu à compléter. *
+* data = éventuelle donnée complémentaire fournie. *
+* *
+* Description : Etablit dans une ligne de rendu le contenu représenté. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_undefined_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data)
+{
+ GArchInstruction *instr; /* Version spécialisée */
+ GBinContent *content; /* Contenu brut d'origine */
+ mrange_t range; /* Emplacement couvert */
+ char *key; /* Mot clef principal */
+
+ instr = G_ARCH_INSTRUCTION(generator);
+ content = G_BIN_CONTENT(data);
+
+ /* Prologue */
+
+ if (g_arch_instruction_get_range(instr, &range))
+ {
+ g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range));
+
+ g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range));
+
+ g_buffer_line_fill_content(line, ACO_BINARY, content, &range, VMPA_NO_PHYSICAL);
+
+ }
+
+ /* Instruction proprement dite */
+
+ key = g_arch_instruction_get_keyword(instr);
+
+ g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_ERROR, SL(key), NULL, G_OBJECT(instr));
+
+ free(key);
+
+}
diff --git a/src/arch/instructions/undefined-ui.h b/src/arch/instructions/undefined-ui.h
new file mode 100644
index 0000000..8bc2d67
--- /dev/null
+++ b/src/arch/instructions/undefined-ui.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * undefined-ui.h - prototypes pour les opérandes représentant des instructions indéfinies sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_OPERANDS_UNDEFINED_UI_H
+#define _ARCH_OPERANDS_UNDEFINED_UI_H
+
+
+#include "../../glibext/generator-int.h"
+
+
+
+/* Procède à l'initialisation de l'interface de génération. */
+void g_undefined_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *);
+
+
+
+#endif /* _ARCH_OPERANDS_UNDEFINED_UI_H */
diff --git a/src/arch/instructions/undefined.c b/src/arch/instructions/undefined.c
index 15c63e7..75df493 100644
--- a/src/arch/instructions/undefined.c
+++ b/src/arch/instructions/undefined.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* undefined.c - instructions au comportement non défini
*
- * Copyright (C) 2016-2019 Cyrille Bagard
+ * Copyright (C) 2016-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,63 +25,42 @@
#include <assert.h>
+#include <string.h>
#include <i18n.h>
#include "undefined-int.h"
-#include "../../core/columns.h"
+#include "../../glibext/serialize-int.h"
+/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */
+
+
/* Initialise la classe des instructions non définies. */
-static void g_undef_instruction_class_init(GUndefInstructionClass *);
+static void g_undefined_instruction_class_init(GUndefinedInstructionClass *);
/* Initialise une instance d'instruction non définie. */
-static void g_undef_instruction_init(GUndefInstruction *);
+static void g_undefined_instruction_init(GUndefinedInstruction *);
/* Supprime toutes les références externes. */
-static void g_undef_instruction_dispose(GUndefInstruction *);
+static void g_undefined_instruction_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_undef_instruction_finalize(GUndefInstruction *);
-
-/* Indique l'encodage d'une instruction de façon détaillée. */
-static const char *g_undef_instruction_get_encoding(const GUndefInstruction *);
-
-/* Fournit le nom humain de l'instruction manipulée. */
-static const char *g_undef_instruction_get_keyword(const GUndefInstruction *);
-
-
-
-/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */
-
-
-/* Charge une instruction depuis une mémoire tampon. */
-static bool g_undef_instruction_unserialize(GUndefInstruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *);
-
-/* Sauvegarde une instruction dans une mémoire tampon. */
-static bool g_undef_instruction_serialize(GUndefInstruction *, GAsmStorage *, packed_buffer_t *);
-
-
-
-/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
-
-
-/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
-static void g_undef_instruction_print(GUndefInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
+static void g_undefined_instruction_finalize(GObject *);
/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_undef_instruction_load(GUndefInstruction *, GObjectStorage *, packed_buffer_t *);
+/* Indique l'encodage d'une instruction de façon détaillée. */
+static char *g_undefined_instruction_get_encoding(const GArchInstruction *);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_undef_instruction_store(GUndefInstruction *, GObjectStorage *, packed_buffer_t *);
+/* Fournit le nom humain de l'instruction manipulée. */
+static char *g_undefined_instruction_get_keyword(const GArchInstruction *);
@@ -91,7 +70,9 @@ static bool g_undef_instruction_store(GUndefInstruction *, GObjectStorage *, pac
/* Indique le type défini pour une instruction au comportement non défini. */
-G_DEFINE_TYPE(GUndefInstruction, g_undef_instruction, G_TYPE_ARCH_INSTRUCTION);
+G_DEFINE_TYPE_WITH_CODE(GUndefinedInstruction, g_undefined_instruction, G_TYPE_ARCH_INSTRUCTION,
+ G_IMPLEMENT_INTERFACE_IF_SYM(g_token_generator_get_type, g_undefined_instruction_ui_token_generator_iface_init));
+
/******************************************************************************
@@ -106,28 +87,20 @@ G_DEFINE_TYPE(GUndefInstruction, g_undef_instruction, G_TYPE_ARCH_INSTRUCTION);
* *
******************************************************************************/
-static void g_undef_instruction_class_init(GUndefInstructionClass *klass)
+static void g_undefined_instruction_class_init(GUndefinedInstructionClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GArchInstructionClass *instr; /* Encore une autre vision... */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_undef_instruction_dispose;
- object->finalize = (GObjectFinalizeFunc)g_undef_instruction_finalize;
+ object->dispose = g_undefined_instruction_dispose;
+ object->finalize = g_undefined_instruction_finalize;
instr = G_ARCH_INSTRUCTION_CLASS(klass);
- instr->get_encoding = (get_instruction_encoding_fc)g_undef_instruction_get_encoding;
- instr->get_keyword = (get_instruction_keyword_fc)g_undef_instruction_get_keyword;
-
- instr->unserialize = (unserialize_instruction_fc)g_undef_instruction_unserialize;
- instr->serialize = (serialize_instruction_fc)g_undef_instruction_serialize;
-
- instr->print = (print_instruction_fc)g_undef_instruction_print;
-
- instr->load = (load_instruction_fc)g_undef_instruction_load;
- instr->store = (store_instruction_fc)g_undef_instruction_store;
+ instr->get_encoding = g_undefined_instruction_get_encoding;
+ instr->get_keyword = g_undefined_instruction_get_keyword;
}
@@ -144,16 +117,22 @@ static void g_undef_instruction_class_init(GUndefInstructionClass *klass)
* *
******************************************************************************/
-static void g_undef_instruction_init(GUndefInstruction *instr)
+static void g_undefined_instruction_init(GUndefinedInstruction *instr)
{
- GET_UNDEF_INSTR_EXTRA(instr)->behavior = IEB_UNDEFINED;
+ undef_extra_data_t extra; /* Données insérées à consulter*/
+
+ extra = GET_UNDEF_INSTR_EXTRA(instr);
+
+ extra.behavior = IEB_UNDEFINED;
+
+ SET_UNDEF_INSTR_EXTRA(instr, &extra);
}
/******************************************************************************
* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -163,16 +142,16 @@ static void g_undef_instruction_init(GUndefInstruction *instr)
* *
******************************************************************************/
-static void g_undef_instruction_dispose(GUndefInstruction *instr)
+static void g_undefined_instruction_dispose(GObject *object)
{
- G_OBJECT_CLASS(g_undef_instruction_parent_class)->dispose(G_OBJECT(instr));
+ G_OBJECT_CLASS(g_undefined_instruction_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : instr = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -182,9 +161,9 @@ static void g_undef_instruction_dispose(GUndefInstruction *instr)
* *
******************************************************************************/
-static void g_undef_instruction_finalize(GUndefInstruction *instr)
+static void g_undefined_instruction_finalize(GObject *object)
{
- G_OBJECT_CLASS(g_undef_instruction_parent_class)->finalize(G_OBJECT(instr));
+ G_OBJECT_CLASS(g_undefined_instruction_parent_class)->finalize(object);
}
@@ -201,16 +180,14 @@ static void g_undef_instruction_finalize(GUndefInstruction *instr)
* *
******************************************************************************/
-GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior behavior)
+GArchInstruction *g_undefined_instruction_new(InstrExpectedBehavior behavior)
{
GArchInstruction *result; /* Instruction à retourner */
- undef_extra_data_t *extra; /* Données insérées à modifier */
- result = g_object_new(G_TYPE_UNDEF_INSTRUCTION, NULL);
+ result = g_object_new(G_TYPE_UNDEFINED_INSTRUCTION, NULL);
- extra = GET_UNDEF_INSTR_EXTRA(result);
-
- extra->behavior = behavior;
+ if (!g_undefined_instruction_create(G_UNDEFINED_INSTRUCTION(result), behavior))
+ g_clear_object(&result);
return result;
@@ -219,90 +196,10 @@ GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior behavior)
/******************************************************************************
* *
-* Paramètres : instr = instruction quelconque à consulter. *
-* *
-* Description : Indique l'encodage d'une instruction de façon détaillée. *
-* *
-* Retour : Description humaine de l'encodage utilisé. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static const char *g_undef_instruction_get_encoding(const GUndefInstruction *instr)
-{
- const char *result; /* Description à retourner */
-
- result = _("Undefined");
-
- return result;
-
-}
-
-
-/******************************************************************************
+* Paramètres : instr = instance à initialiser pleinement. *
+* behavior = état réel du CPU après une passe de l'instruction.*
* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
-* *
-* Description : Fournit le nom humain de l'instruction manipulée. *
-* *
-* Retour : Mot clef de bas niveau. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-const char *g_undef_instruction_get_keyword(const GUndefInstruction *instr)
-{
- const char *result; /* Désignation à retourner */
- undef_extra_data_t *extra; /* Données insérées à consulter*/
-
- extra = GET_UNDEF_INSTR_EXTRA(instr);
-
- switch (extra->behavior)
- {
- case IEB_NOP:
- result = "nop";
- break;
-
- case IEB_UNDEFINED:
- result = "undefined";
- break;
-
- case IEB_UNPREDICTABLE:
- result = "unpredictable";
- break;
-
- case IEB_RESERVED:
- result = "reserved";
- break;
-
- default:
- assert(false);
- result = NULL;
- break;
-
- }
-
- return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION SUR DISQUE DES INSTRUCTIONS */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
-* storage = mécanisme de sauvegarde à manipuler. *
-* format = format binaire chargé associé à l'architecture. *
-* pbuf = zone tampon à remplir. *
-* *
-* Description : Charge une instruction depuis une mémoire tampon. *
+* Description : Met en place une instruction au comportement indéfini. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -310,122 +207,24 @@ const char *g_undef_instruction_get_keyword(const GUndefInstruction *instr)
* *
******************************************************************************/
-static bool g_undef_instruction_unserialize(GUndefInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf)
+bool g_undefined_instruction_create(GUndefinedInstruction *instr, InstrExpectedBehavior behavior)
{
bool result; /* Bilan à retourner */
- GArchInstructionClass *parent; /* Classe parente à consulter */
- undef_extra_data_t *extra; /* Données insérées à consulter*/
- uint8_t val; /* Champ de bits manipulé */
-
- parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class);
+ undef_extra_data_t extra; /* Données insérées à modifier */
- result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf);
+ result = true;
- if (result)
- {
- extra = GET_UNDEF_INSTR_EXTRA(instr);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false);
- extra->behavior = val;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : instr = instruction d'assemblage à consulter. *
-* storage = mécanisme de sauvegarde à manipuler. *
-* pbuf = zone tampon à remplir. *
-* *
-* Description : Sauvegarde une instruction dans une mémoire tampon. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool g_undef_instruction_serialize(GUndefInstruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- GArchInstructionClass *parent; /* Classe parente à consulter */
- undef_extra_data_t *extra; /* Données insérées à consulter*/
-
- parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class);
-
- result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf);
-
- if (result)
- {
- extra = GET_UNDEF_INSTR_EXTRA(instr);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = extend_packed_buffer(pbuf, (uint8_t []){ extra->behavior }, sizeof(uint8_t), false);
+ extra = GET_UNDEF_INSTR_EXTRA(instr);
- UNLOCK_GOBJECT_EXTRA(extra);
+ extra.behavior = behavior;
- }
+ SET_UNDEF_INSTR_EXTRA(instr, &extra);
return result;
}
-
-/* ---------------------------------------------------------------------------------- */
-/* OFFRE DE CAPACITES DE GENERATION */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : instr = instruction d'assemblage à représenter. *
-* line = ligne de rendu à compléter. *
-* index = indice de cette même ligne dans le tampon global. *
-* repeat = indice d'utilisations successives du générateur. *
-* content = éventuel contenu binaire brut à imprimer. *
-* *
-* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_undef_instruction_print(GUndefInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content)
-{
- GArchInstruction *base; /* Version de base */
- const char *key; /* Mot clef principal */
- size_t klen; /* Taille de ce mot clef */
-
- base = G_ARCH_INSTRUCTION(instr);
-
- g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range));
-
- g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range));
-
- g_buffer_line_fill_content(line, DLC_BINARY, content, &base->range, VMPA_NO_PHYSICAL);
-
- /* Instruction proprement dite */
-
- key = g_arch_instruction_get_keyword(base);
- klen = strlen(key);
-
- g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_ERROR, NULL);
-
-}
-
-
/******************************************************************************
* *
* Paramètres : instr = instruction à consulter. *
@@ -438,18 +237,14 @@ static void g_undef_instruction_print(GUndefInstruction *instr, GBufferLine *lin
* *
******************************************************************************/
-InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *instr)
+InstrExpectedBehavior g_undefined_instruction_get_behavior(const GUndefinedInstruction *instr)
{
InstrExpectedBehavior result; /* Comportement à retourner */
- undef_extra_data_t *extra; /* Données insérées à consulter*/
+ undef_extra_data_t extra; /* Données insérées à consulter*/
extra = GET_UNDEF_INSTR_EXTRA(instr);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = extra->behavior;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = extra.behavior;
return result;
@@ -464,41 +259,21 @@ InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *
/******************************************************************************
* *
-* Paramètres : instr = élément GLib à constuire. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à lire. *
+* Paramètres : instr = instruction quelconque à consulter. *
* *
-* Description : Charge un contenu depuis une mémoire tampon. *
+* Description : Indique l'encodage d'une instruction de façon détaillée. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Description humaine de l'encodage utilisé. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_undef_instruction_load(GUndefInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
+static char *g_undefined_instruction_get_encoding(const GArchInstruction *instr)
{
- bool result; /* Bilan à retourner */
- GArchInstructionClass *parent; /* Classe parente à consulter */
- undef_extra_data_t *extra; /* Données insérées à consulter*/
- uint8_t val; /* Champ de bits manipulé */
-
- parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class);
-
- result = parent->load(G_ARCH_INSTRUCTION(instr), storage, pbuf);
-
- if (result)
- {
- extra = GET_UNDEF_INSTR_EXTRA(instr);
-
- LOCK_GOBJECT_EXTRA(extra);
+ char *result; /* Description à retourner */
- result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false);
- extra->behavior = val;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- }
+ result = strdup(_("Undefined"));
return result;
@@ -507,37 +282,45 @@ static bool g_undef_instruction_load(GUndefInstruction *instr, GObjectStorage *s
/******************************************************************************
* *
-* Paramètres : instr = élément GLib à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : instr = instruction d'assemblage à consulter. *
* *
-* Description : Sauvegarde un contenu dans une mémoire tampon. *
+* Description : Fournit le nom humain de l'instruction manipulée. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Mot clef de bas niveau. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_undef_instruction_store(GUndefInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
+static char *g_undefined_instruction_get_keyword(const GArchInstruction *instr)
{
- bool result; /* Bilan à retourner */
- GArchInstructionClass *parent; /* Classe parente à consulter */
- undef_extra_data_t *extra; /* Données insérées à consulter*/
-
- parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class);
+ char *result; /* Désignation à retourner */
+ undef_extra_data_t extra; /* Données insérées à consulter*/
- result = parent->store(G_ARCH_INSTRUCTION(instr), storage, pbuf);
+ extra = GET_UNDEF_INSTR_EXTRA(instr);
- if (result)
+ switch (extra.behavior)
{
- extra = GET_UNDEF_INSTR_EXTRA(instr);
+ case IEB_NOP:
+ result = strdup("nop");
+ break;
- LOCK_GOBJECT_EXTRA(extra);
+ case IEB_UNDEFINED:
+ result = strdup("undefined");
+ break;
- result = extend_packed_buffer(pbuf, (uint8_t []){ extra->behavior }, sizeof(uint8_t), false);
+ case IEB_UNPREDICTABLE:
+ result = strdup("unpredictable");
+ break;
- UNLOCK_GOBJECT_EXTRA(extra);
+ case IEB_RESERVED:
+ result = strdup("reserved");
+ break;
+
+ default:
+ assert(false);
+ result = NULL;
+ break;
}
diff --git a/src/arch/instructions/undefined.h b/src/arch/instructions/undefined.h
index 8f35f35..d4b35f4 100644
--- a/src/arch/instructions/undefined.h
+++ b/src/arch/instructions/undefined.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* undefined.h - prototypes pour les instructions au comportement non défini
*
- * Copyright (C) 2016-2019 Cyrille Bagard
+ * Copyright (C) 2016-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,27 +25,14 @@
#define _ARCH_INSTRUCTIONS_UNDEFINED_H
-#include <glib-object.h>
-
-
#include "../instruction.h"
-#include "../vmpa.h"
-
+#include "../../glibext/helpers.h"
-#define G_TYPE_UNDEF_INSTRUCTION g_undef_instruction_get_type()
-#define G_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstruction))
-#define G_IS_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UNDEF_INSTRUCTION))
-#define G_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass))
-#define G_IS_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UNDEF_INSTRUCTION))
-#define G_UNDEF_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass))
+#define G_TYPE_UNDEFINED_INSTRUCTION (g_undefined_instruction_get_type())
-/* Définition générique d'une instruction au comportement non défini (instance) */
-typedef struct _GUndefInstruction GUndefInstruction;
-
-/* Définition générique d'une instruction au comportement non défini (classe) */
-typedef struct _GUndefInstructionClass GUndefInstructionClass;
+DECLARE_GTYPE(GUndefinedInstruction, g_undefined_instruction, G, UNDEFINED_INSTRUCTION);
/* Etat précis de l'instruction */
@@ -59,14 +46,11 @@ typedef enum _InstrExpectedBehavior
} InstrExpectedBehavior;
-/* Indique le type défini pour une instruction au comportement non défini. */
-GType g_undef_instruction_get_type(void);
-
/* Crée une instruction au comportement nominalement indéfini. */
-GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior);
+GArchInstruction *g_undefined_instruction_new(InstrExpectedBehavior);
/* Indique le type de conséquences réél de l'instruction. */
-InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *);
+InstrExpectedBehavior g_undefined_instruction_get_behavior(const GUndefinedInstruction *);
diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h
index e6c1232..10c079b 100644
--- a/src/arch/operand-int.h
+++ b/src/arch/operand-int.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* operand-int.h - prototypes pour la définition générique interne des opérandes
*
- * Copyright (C) 2008-2020 Cyrille Bagard
+ * Copyright (C) 2008-2024 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,13 +26,23 @@
#include "operand.h"
+#include "../common/szbin.h"
+#include "../glibext/objhole-int.h"
+
+
+
+/* Exporte une chaîne de caractères à partir d'un objet. */
+//typedef bool (* arch_operand_to_string_fc) (const GArchOperand *operand, unsigned int flags, sized_binary_t *);
+
+
+
+#if 0
#include <stdbool.h>
#include "../analysis/storage/storage.h"
-#include "../glibext/objhole.h"
@@ -71,46 +81,29 @@ typedef bool (* load_operand_fc) (GArchOperand *, GObjectStorage *, packed_buffe
typedef bool (* store_operand_fc) (GArchOperand *, GObjectStorage *, packed_buffer_t *);
-/* Informations glissées dans la structure GObject de GArchOperand */
-typedef struct _operand_extra_data_t
-{
- ArchOperandFlag flags; /* Informations diverses */
-} operand_extra_data_t;
-/* Encapsulation avec un verrou d'accès */
-typedef union _operand_obj_extra_t
-{
- operand_extra_data_t data; /* Données embarquées */
- lockable_obj_extra_t lockable; /* Gestion d'accès aux fanions */
+#endif
-} operand_obj_extra_t;
/* Définition générique d'un opérande d'architecture (instance) */
struct _GArchOperand
{
- GObject parent; /* A laisser en premier */
-
-#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__
-
- /**
- * L'inclusion des informations suivantes dépend de l'architecture.
- *
- * Si la structure GObject possède un trou, on remplit de préférence
- * ce dernier.
- */
-
- operand_obj_extra_t extra; /* Externalisation embarquée */
-
-#endif
+ GThickObject parent; /* A laisser en premier */
};
/* Définition générique d'un opérande d'architecture (classe) */
struct _GArchOperandClass
{
- GObjectClass parent; /* A laisser en premier */
+ GThickObjectClass parent; /* A laisser en premier */
+
+
+
+
+
+#if 0
operand_compare_fc compare; /* Comparaison d'opérandes */
find_inner_operand_fc find_inner; /* Définition d'un chemin */
@@ -128,29 +121,57 @@ struct _GArchOperandClass
load_operand_fc load; /* Chargement depuis un tampon */
store_operand_fc store; /* Conservation dans un tampon */
+#endif
+
};
+
/**
* Accès aux informations éventuellement déportées.
*/
-#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__
-# define GET_ARCH_OP_EXTRA(op) (operand_extra_data_t *)&op->extra
+#define ARCH_OPERAND_EXTRA_DATA(mx) \
+ \
+ unsigned int reserved : GOBJECT_RESERVED_EXTRA_BITS; \
+ \
+ /** \
+ * ArchOperandFlag \
+ */ \
+ unsigned int flags : mx;
-#else
-# define GET_ARCH_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), operand_extra_data_t)
+/* Informations glissées dans la structure GObject de GArchOperand */
+typedef struct _operand_extra_data_t
+{
+ ARCH_OPERAND_EXTRA_DATA(3); /* Informations pour l'opérande*/
+
+} operand_extra_data_t;
+
+
+#define GET_ARCH_OP_EXTRA(op) \
+ GET_GOBJECT_EXTRA(op, operand_extra_data_t)
+
+#define SET_ARCH_OP_EXTRA(op, data) \
+ SET_GOBJECT_EXTRA(op, operand_extra_data_t, data)
+
+
+
+
+
+
+
+
+#if 0
-#endif
/* Ajoute une information complémentaire à un opérande. */
-bool _g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag, bool);
+//bool _g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag, bool);
/* Retire une information complémentaire à un opérande. */
-bool _g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag, bool);
+//bool _g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag, bool);
@@ -190,5 +211,7 @@ bool g_arch_operand_store_generic_fixed(GArchOperand *, GObjectStorage *, packed
bool g_arch_operand_store_generic_variadic(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+#endif
+
#endif /* _ARCH_OPERAND_INT_H */
diff --git a/src/arch/operand-ui-int.h b/src/arch/operand-ui-int.h
new file mode 100644
index 0000000..c1173f3
--- /dev/null
+++ b/src/arch/operand-ui-int.h
@@ -0,0 +1,52 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * operand-ui-int.h - prototypes pour la définition générique interne des opérandes sous forme graphique
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ARCH_OPERAND_UI_INT_H
+#define _ARCH_OPERAND_UI_INT_H
+
+
+#include "operand-ui.h"
+
+
+
+/* Traduit un opérande en version humainement lisible. */
+typedef void (* print_operand_ui_fc) (const GArchOperandUI *, GBufferLine *);
+
+/* Construit un petit résumé concis de l'opérande. */
+typedef char * (* build_operand_ui_tooltip_fc) (const GArchOperandUI *, const GLoadedBinary *);
+
+
+
+/* Définition générique d'un opérande d'architecture (interface) */
+struct _GArchOperandUIInterface
+{
+ GTypeInterface base_iface; /* A laisser en premier */
+
+ print_operand_ui_fc print; /* Texte humain équivalent */
+ build_operand_ui_tooltip_fc build_tooltip; /* Définition de description*/
+
+};
+
+
+
+#endif /* _ARCH_OPERAND_UI_INT_H */
diff --git a/src/arch/operand-ui.c b/src/arch/operand-ui.c
new file mode 100644
index 0000000..ff7ad1b
--- /dev/null
+++ b/src/arch/operand-ui.c
@@ -0,0 +1,111 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * operand-ui.c - gestion générique des opérandes sous forme graphique
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "operand-ui.h"
+
+
+#include "operand-ui-int.h"
+
+
+
+/* Procède à l'initialisation de l'interface d'opérande UI. */
+static void g_arch_operand_ui_default_init(GArchOperandUIInterface *);
+
+
+
+/* Indique le type défini pour un opérande d'architecture avec représentation graphique. */
+G_DEFINE_INTERFACE(GArchOperandUI, g_arch_operand_ui, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface d'opérande UI. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_arch_operand_ui_default_init(GArchOperandUIInterface *iface)
+{
+ iface->print = NULL;
+ iface->build_tooltip = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande à traiter. *
+* line = ligne tampon où imprimer l'opérande donné. *
+* *
+* Description : Traduit un opérande en version humainement lisible. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_arch_operand_ui_print(const GArchOperandUI *operand, GBufferLine *line)
+{
+ GArchOperandUIInterface *iface; /* Interface utilisée */
+
+ iface = G_ARCH_OPERAND_UI_GET_IFACE(operand);
+
+ iface->print(operand, line);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande à consulter. *
+* binary = informations relatives au binaire chargé. *
+* *
+* Description : Construit un petit résumé concis de l'opérande. *
+* *
+* Retour : Chaîne de caractères à libérer après usage ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_arch_operand_ui_build_tooltip(const GArchOperandUI *operand, const GLoadedBinary *binary)
+{
+ char *result; /* Description à retourner */
+ GArchOperandUIInterface *iface; /* Interface utilisée */
+
+ iface = G_ARCH_OPERAND_UI_GET_IFACE(operand);
+
+ if (iface->build_tooltip != NULL)
+ result = iface->build_tooltip(operand, binary);
+ else
+ result = NULL;
+
+ return result;
+
+}
diff --git a/src/arch/operand-ui.h b/src/arch/operand-ui.h
new file mode 100644
index 0000000..b197645
--- /dev/null
+++ b/src/arch/operand-ui.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * operand-ui.h - prototypes pour la gestion générique des opérandes sous forme graphique
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ARCH_OPERAND_UI_H
+#define _ARCH_OPERAND_UI_H
+
+
+#include "../glibext/bufferline.h"
+#include "../glibext/helpers.h"
+
+
+
+#define G_TYPE_ARCH_OPERAND_UI (g_arch_operand_ui_get_type())
+
+DECLARE_INTERFACE(GArchOperandUI, g_arch_operand_ui, G, ARCH_OPERAND_UI);
+
+
+
+// TODO : REMME
+//typedef void *GBufferLine;
+typedef void *GLoadedBinary;
+/////
+
+
+
+/* Traduit un opérande en version humainement lisible. */
+void g_arch_operand_ui_print(const GArchOperandUI *, GBufferLine *);
+
+/* Construit un petit résumé concis de l'opérande. */
+char *g_arch_operand_ui_build_tooltip(const GArchOperandUI *, const GLoadedBinary *);
+
+
+
+#endif /* _ARCH_OPERAND_UI_H */
diff --git a/src/arch/operand.c b/src/arch/operand.c
index 0f5ffd5..d3e837c 100644
--- a/src/arch/operand.c
+++ b/src/arch/operand.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* operand.c - gestion générique des opérandes
*
- * Copyright (C) 2008-2020 Cyrille Bagard
+ * Copyright (C) 2008-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,17 +25,16 @@
#include <assert.h>
-#include <malloc.h>
-#include <string.h>
#include "operand-int.h"
-#include "storage.h"
-#include "../analysis/storage/serialize-int.h"
#include "../common/fnv1a.h"
#include "../common/sort.h"
-#include "../core/logs.h"
+#include "../glibext/comparable-int.h"
+#include "../glibext/hashable-int.h"
+#include "../glibext/serialize-int.h"
#include "../glibext/singleton-int.h"
+#include "../glibext/strbuilder-int.h"
@@ -45,66 +44,67 @@
/* Initialise la classe générique des opérandes. */
static void g_arch_operand_class_init(GArchOperandClass *);
-/* Initialise une instance d'opérande d'architecture. */
-static void g_arch_operand_init(GArchOperand *);
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_arch_operand_comparable_object_iface_init(GComparableObjectInterface *);
-/* Procède à l'initialisation de l'interface de singleton. */
-static void g_arch_operand_singleton_init(GSingletonCandidateInterface *);
+/* Procède à l'initialisation de l'interface de détermination. */
+static void g_arch_operand_hashable_object_iface_init(GHashableObjectInterface *);
/* Procède à l'initialisation de l'interface de sérialisation. */
-static void g_arch_operand_serializable_init(GSerializableObjectInterface *);
+static void g_arch_operand_serializable_object_iface_init(GSerializableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface de rassemblement. */
+static void g_arch_operand_singleton_candidate_iface_init(GSingletonCandidateInterface *);
+
+/* Procède à l'initialisation de l'interface d'exportation. */
+static void g_arch_operand_string_builder_iface_init(GStringBuilderInterface *);
+
+/* Initialise une instance d'opérande d'architecture. */
+static void g_arch_operand_init(GArchOperand *);
/* Supprime toutes les références externes. */
-static void g_arch_operand_dispose(GArchOperand *);
+static void g_arch_operand_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_arch_operand_finalize(GArchOperand *);
+static void g_arch_operand_finalize(GObject *);
-/* Compare un opérande avec un autre. */
-static int _g_arch_operand_compare(const GArchOperand *, const GArchOperand *, bool);
+/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */
-/* ------------------------ CONTROLE DU VOLUME DES INSTANCES ------------------------ */
+/* Réalise une comparaison étendue entre objets. */
+static int g_arch_operand_compare(const GComparableObject *, const GComparableObject *);
-/* Fournit une liste de candidats embarqués par un candidat. */
-GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *, size_t *);
-/* Met à jour une liste de candidats embarqués par un candidat. */
-void g_arch_operand_update_inner_instances(GArchOperand *, GArchOperand **, size_t);
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-static guint _g_arch_operand_hash(const GArchOperand *, bool);
+/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-static guint g_arch_operand_hash(const GArchOperand *);
-/* Détermine si deux candidats à l'unicité sont identiques. */
-static gboolean g_arch_operand_is_equal(const GArchOperand *, const GArchOperand *);
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+static guint g_arch_operand_hash(const GHashableObject *);
-/* Marque un candidat comme figé. */
-static void g_arch_operand_set_read_only(GArchOperand *);
-/* Indique si le candidat est figé. */
-static bool g_arch_operand_is_read_only(GArchOperand *);
+/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */
-/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
+/* Charge un objet depuis un flux de données. */
+static bool g_arch_operand_load(GSerializableObject *, GObjectStorage *, int);
+/* Sauvegarde un objet dans un flux de données. */
+static bool g_arch_operand_store(const GSerializableObject *, GObjectStorage *, int);
-/* Charge un contenu depuis une mémoire tampon. */
-static bool _g_arch_operand_load(GArchOperand *, GObjectStorage *, packed_buffer_t *);
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_arch_operand_load(GArchOperand *, GObjectStorage *, packed_buffer_t *);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool _g_arch_operand_store(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+/* ------------------------ CONTROLE DU VOLUME DES INSTANCES ------------------------ */
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_arch_operand_store(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+
+/* Marque un candidat comme figé. */
+static void g_arch_operand_mark_as_read_only(GSingletonCandidate *);
+
+/* Indique si le candidat est figé. */
+static bool g_arch_operand_is_read_only(const GSingletonCandidate *);
@@ -114,9 +114,12 @@ static bool g_arch_operand_store(GArchOperand *, GObjectStorage *, packed_buffer
/* Indique le type défini pour un opérande d'architecture. */
-G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(G_TYPE_SINGLETON_CANDIDATE, g_arch_operand_singleton_init)
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_operand_serializable_init));
+G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_THICK_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_arch_operand_comparable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_arch_operand_hashable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_operand_serializable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_SINGLETON_CANDIDATE, g_arch_operand_singleton_candidate_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_arch_operand_string_builder_iface_init));
/******************************************************************************
@@ -134,30 +137,20 @@ G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_OBJECT,
static void g_arch_operand_class_init(GArchOperandClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
- GArchOperandClass *operand; /* Encore une autre vision... */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_operand_dispose;
- object->finalize = (GObjectFinalizeFunc)g_arch_operand_finalize;
-
- operand = G_ARCH_OPERAND_CLASS(klass);
-
- operand->compare = (operand_compare_fc)_g_arch_operand_compare;
-
- operand->hash = _g_arch_operand_hash;
-
- operand->load = (load_operand_fc)_g_arch_operand_load;
- operand->store = (store_operand_fc)_g_arch_operand_store;
+ object->dispose = g_arch_operand_dispose;
+ object->finalize = g_arch_operand_finalize;
}
/******************************************************************************
* *
-* Paramètres : operand = instance à initialiser. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Initialise une instance d'opérande d'architecture. *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
* *
* Retour : - *
* *
@@ -165,13 +158,9 @@ static void g_arch_operand_class_init(GArchOperandClass *klass)
* *
******************************************************************************/
-static void g_arch_operand_init(GArchOperand *operand)
+static void g_arch_operand_comparable_object_iface_init(GComparableObjectInterface *iface)
{
- operand_extra_data_t *extra; /* Données insérées à modifier */
-
- extra = GET_ARCH_OP_EXTRA(operand);
-
- INIT_GOBJECT_EXTRA_LOCK(extra);
+ iface->compare = g_arch_operand_compare;
}
@@ -180,7 +169,7 @@ static void g_arch_operand_init(GArchOperand *operand)
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de singleton. *
+* Description : Procède à l'initialisation de l'interface de détermination. *
* *
* Retour : - *
* *
@@ -188,16 +177,9 @@ static void g_arch_operand_init(GArchOperand *operand)
* *
******************************************************************************/
-static void g_arch_operand_singleton_init(GSingletonCandidateInterface *iface)
+static void g_arch_operand_hashable_object_iface_init(GHashableObjectInterface *iface)
{
- iface->list_inner = (list_inner_instances_fc)g_arch_operand_list_inner_instances;
- iface->update_inner = (update_inner_instances_fc)g_arch_operand_update_inner_instances;
-
- iface->hash = (hash_candidate_fc)g_arch_operand_hash;
- iface->is_equal = (is_candidate_equal_fc)g_arch_operand_is_equal;
-
- iface->set_ro = (set_candidate_ro_fc)g_arch_operand_set_read_only;
- iface->is_ro = (is_candidate_ro_fc)g_arch_operand_is_read_only;
+ iface->hash = g_arch_operand_hash;
}
@@ -214,38 +196,19 @@ static void g_arch_operand_singleton_init(GSingletonCandidateInterface *iface)
* *
******************************************************************************/
-static void g_arch_operand_serializable_init(GSerializableObjectInterface *iface)
+static void g_arch_operand_serializable_object_iface_init(GSerializableObjectInterface *iface)
{
- iface->load = (load_serializable_object_cb)g_arch_operand_load;
- iface->store = (store_serializable_object_cb)g_arch_operand_store;
+ iface->load = g_arch_operand_load;
+ iface->store = g_arch_operand_store;
}
/******************************************************************************
* *
-* Paramètres : operand = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_arch_operand_dispose(GArchOperand *operand)
-{
- G_OBJECT_CLASS(g_arch_operand_parent_class)->dispose(G_OBJECT(operand));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = instance d'objet GLib à traiter. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Procède à la libération totale de la mémoire. *
+* Description : Procède à l'initialisation de l'interface de rassemblement. *
* *
* Retour : - *
* *
@@ -253,147 +216,59 @@ static void g_arch_operand_dispose(GArchOperand *operand)
* *
******************************************************************************/
-static void g_arch_operand_finalize(GArchOperand *operand)
+static void g_arch_operand_singleton_candidate_iface_init(GSingletonCandidateInterface *iface)
{
- G_OBJECT_CLASS(g_arch_operand_parent_class)->finalize(G_OBJECT(operand));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : a = premier opérande à consulter. *
-* b = second opérande à consulter. *
-* lock = précise le besoin en verrouillage. *
-* *
-* Description : Compare un opérande avec un autre. *
-* *
-* Retour : Bilan de la comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int _g_arch_operand_compare(const GArchOperand *a, const GArchOperand *b, bool lock)
-{
- int result; /* Bilan à faire remonter */
- operand_extra_data_t *ea; /* Données insérées à consulter*/
- operand_extra_data_t *eb; /* Données insérées à consulter*/
-
- assert(!lock);
-
- ea = GET_ARCH_OP_EXTRA(a);
- eb = GET_ARCH_OP_EXTRA(b);
+ iface->list_inner = NULL;
+ iface->update_inner = NULL;
- result = sort_unsigned_long(ea->flags, eb->flags);
-
- return result;
+ iface->mark_as_ro = g_arch_operand_mark_as_read_only;
+ iface->is_ro = g_arch_operand_is_read_only;
}
/******************************************************************************
* *
-* Paramètres : a = premier opérande à consulter. *
-* b = second opérande à consulter. *
-* *
-* Description : Compare un opérande avec un autre. *
-* *
-* Retour : Bilan de la comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-int g_arch_operand_compare(const GArchOperand *a, const GArchOperand *b)
-{
- int result; /* Bilan à faire remonter */
- GType type_a; /* Type de l'object A */
- GType type_b; /* Type de l'object B */
-
- type_a = G_OBJECT_TYPE(G_OBJECT(a));
- type_b = G_OBJECT_TYPE(G_OBJECT(b));
-
- assert(sizeof(GType) <= sizeof(unsigned long));
-
- result = sort_unsigned_long(type_a, type_b);
-
- if (result == 0)
- result = G_ARCH_OPERAND_GET_CLASS(a)->compare(a, b, true);
-
- return result;
-
-}
-
-
-/******************************************************************************
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Paramètres : operand = opérande à consulter. *
-* target = instruction à venir retrouver. *
+* Description : Procède à l'initialisation de l'interface d'exportation. *
* *
-* Description : Détermine le chemin conduisant à un opérande interne. *
-* *
-* Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-char *g_arch_operand_find_inner_operand_path(const GArchOperand *operand, const GArchOperand *target)
+static void g_arch_operand_string_builder_iface_init(GStringBuilderInterface *iface)
{
- char *result; /* Chemin à retourner */
- GArchOperandClass *class; /* Classe associée à l'objet */
-
- class = G_ARCH_OPERAND_GET_CLASS(operand);
-
- if (class->find_inner != NULL)
- result = class->find_inner(operand, target);
-
- else
- result = NULL;
-
- return result;
+ iface->to_string = NULL;
}
/******************************************************************************
* *
-* Paramètres : operand = opérande à consulter. *
-* path = chemin d'accès à un opérande à retrouver. *
+* Paramètres : operand = instance à initialiser. *
* *
-* Description : Obtient l'opérande correspondant à un chemin donné. *
+* Description : Initialise une instance d'opérande d'architecture. *
* *
-* Retour : Opérande trouvé ou NULL en cas d'échec. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *operand, const char *path)
+static void g_arch_operand_init(GArchOperand *operand)
{
- GArchOperand *result; /* Opérande trouvée à renvoyer */
- GArchOperandClass *class; /* Classe associée à l'objet */
-
- class = G_ARCH_OPERAND_GET_CLASS(operand);
-
- if (class->get_inner != NULL)
- result = class->get_inner(operand, path);
-
- else
- result = NULL;
-
- return result;
}
/******************************************************************************
* *
-* Paramètres : operand = opérande à traiter. *
-* line = ligne tampon où imprimer l'opérande donné. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Traduit un opérande en version humainement lisible. *
+* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
@@ -401,54 +276,36 @@ GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *ope
* *
******************************************************************************/
-void g_arch_operand_print(const GArchOperand *operand, GBufferLine *line)
+static void g_arch_operand_dispose(GObject *object)
{
- G_ARCH_OPERAND_GET_CLASS(operand)->print(operand, line);
+ G_OBJECT_CLASS(g_arch_operand_parent_class)->dispose(object);
}
-#ifdef INCLUDE_GTK_SUPPORT
-
-
/******************************************************************************
* *
-* Paramètres : operand = opérande à consulter. *
-* binary = informations relatives au binaire chargé. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Construit un petit résumé concis de l'opérande. *
+* Description : Procède à la libération totale de la mémoire. *
* *
-* Retour : Chaîne de caractères à libérer après usage ou NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-char *g_arch_operand_build_tooltip(const GArchOperand *operand, const GLoadedBinary *binary)
+static void g_arch_operand_finalize(GObject *object)
{
- char *result; /* Description à retourner */
- GArchOperandClass *class; /* Classe associée à l'objet */
-
- class = G_ARCH_OPERAND_GET_CLASS(operand);
-
- if (class->build_tooltip != NULL)
- result = class->build_tooltip(operand, binary);
- else
- result = NULL;
-
- return result;
+ G_OBJECT_CLASS(g_arch_operand_parent_class)->finalize(object);
}
-#endif
-
-
/******************************************************************************
* *
* Paramètres : operand = opérande à venir modifier. *
* flag = drapeau d'information complémentaire à planter. *
-* lock = indique un besoin de verrouillage des données. *
* *
* Description : Ajoute une information complémentaire à un opérande. *
* *
@@ -458,48 +315,20 @@ char *g_arch_operand_build_tooltip(const GArchOperand *operand, const GLoadedBin
* *
******************************************************************************/
-bool _g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag, bool lock)
+bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag)
{
bool result; /* Bilan à retourner */
- operand_extra_data_t *extra; /* Données insérées à modifier */
+ operand_extra_data_t extra; /* Données insérées à modifier */
assert(flag <= AOF_HIGH_USER);
extra = GET_ARCH_OP_EXTRA(operand);
- if (lock)
- LOCK_GOBJECT_EXTRA(extra);
-
- result = !(extra->flags & flag);
-
- extra->flags |= flag;
-
- if (lock)
- UNLOCK_GOBJECT_EXTRA(extra);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à venir modifier. *
-* flag = drapeau d'information complémentaire à planter. *
-* *
-* Description : Ajoute une information complémentaire à un opérande. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ result = !(extra.flags & flag);
-bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag)
-{
- bool result; /* Bilan à retourner */
+ extra.flags |= flag;
- result = _g_arch_operand_set_flag(operand, flag, true);
+ SET_ARCH_OP_EXTRA(operand, &extra);
return result;
@@ -510,7 +339,6 @@ bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag)
* *
* Paramètres : operand = opérande à venir modifier. *
* flag = drapeau d'information complémentaire à planter. *
-* lock = indique un besoin de verrouillage des données. *
* *
* Description : Retire une information complémentaire à un opérande. *
* *
@@ -520,46 +348,20 @@ bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag)
* *
******************************************************************************/
-bool _g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag, bool lock)
+bool g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag)
{
bool result; /* Bilan à retourner */
- operand_extra_data_t *extra; /* Données insérées à modifier */
+ operand_extra_data_t extra; /* Données insérées à modifier */
assert(flag <= AOF_HIGH_USER);
extra = GET_ARCH_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = (extra->flags & flag);
-
- extra->flags &= ~flag;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à venir modifier. *
-* flag = drapeau d'information complémentaire à planter. *
-* *
-* Description : Retire une information complémentaire à un opérande. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ result = (extra.flags & flag);
-bool g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag)
-{
- bool result; /* Bilan à retourner */
+ extra.flags &= ~flag;
- result = _g_arch_operand_unset_flag(operand, flag, true);
+ SET_ARCH_OP_EXTRA(operand, &extra);
return result;
@@ -582,17 +384,13 @@ bool g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag)
bool g_arch_operand_has_flag(const GArchOperand *operand, ArchOperandFlag flag)
{
bool result; /* Bilan à retourner */
- operand_extra_data_t *extra; /* Données insérées à modifier */
+ operand_extra_data_t extra; /* Données insérées à modifier */
assert(flag <= AOF_HIGH_USER);
extra = GET_ARCH_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = (extra->flags & flag);
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = (extra.flags & flag);
return result;
@@ -614,15 +412,11 @@ bool g_arch_operand_has_flag(const GArchOperand *operand, ArchOperandFlag flag)
ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *operand)
{
ArchOperandFlag result; /* Fanions à retourner */
- operand_extra_data_t *extra; /* Données insérées à modifier */
+ operand_extra_data_t extra; /* Données insérées à modifier */
extra = GET_ARCH_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = extra->flags;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = extra.flags;
return result;
@@ -630,39 +424,40 @@ ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *operand)
-/* ---------------------------------------------------------------------------------- */
-/* CONTROLE DU VOLUME DES INSTANCES */
-/* ---------------------------------------------------------------------------------- */
+
+
+
+
+#if 0
+
+
/******************************************************************************
* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* count = quantité d'instances à l'unicité internes. *
+* Paramètres : operand = opérande à consulter. *
+* target = instruction à venir retrouver. *
* *
-* Description : Fournit une liste de candidats embarqués par un candidat. *
+* Description : Détermine le chemin conduisant à un opérande interne. *
* *
-* Retour : Liste de candidats internes ou NULL si aucun. *
+* Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. *
* *
* Remarques : - *
* *
******************************************************************************/
-GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *operand, size_t *count)
+char *g_arch_operand_find_inner_operand_path(const GArchOperand *operand, const GArchOperand *target)
{
- GArchOperand **result; /* Instances à retourner */
+ char *result; /* Chemin à retourner */
GArchOperandClass *class; /* Classe associée à l'objet */
class = G_ARCH_OPERAND_GET_CLASS(operand);
- if (class->list_inner == NULL)
- {
- *count = 0;
- result = NULL;
- }
+ if (class->find_inner != NULL)
+ result = class->find_inner(operand, target);
else
- result = class->list_inner(operand, count);
+ result = NULL;
return result;
@@ -671,105 +466,59 @@ GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *operand,
/******************************************************************************
* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* instances = liste de candidats internes devenus singletons. *
-* count = quantité d'instances à l'unicité internes. *
+* Paramètres : operand = opérande à consulter. *
+* path = chemin d'accès à un opérande à retrouver. *
* *
-* Description : Met à jour une liste de candidats embarqués par un candidat. *
+* Description : Obtient l'opérande correspondant à un chemin donné. *
* *
-* Retour : - *
+* Retour : Opérande trouvé ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_arch_operand_update_inner_instances(GArchOperand *operand, GArchOperand **instances, size_t count)
+GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *operand, const char *path)
{
+ GArchOperand *result; /* Opérande trouvée à renvoyer */
GArchOperandClass *class; /* Classe associée à l'objet */
class = G_ARCH_OPERAND_GET_CLASS(operand);
- if (class->update_inner == NULL)
- assert(class->list_inner == NULL);
+ if (class->get_inner != NULL)
+ result = class->get_inner(operand, path);
else
- {
- assert(class->list_inner != NULL);
- class->update_inner(operand, instances, count);
- }
+ result = NULL;
+
+ return result;
}
-/******************************************************************************
-* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* lock = précise le besoin en verrouillage. *
-* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
-* *
-* Retour : Empreinte de l'élément représenté. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+#endif
-static guint _g_arch_operand_hash(const GArchOperand *operand, bool lock)
-{
- guint result; /* Valeur à retourner */
- const char *name; /* Désignation du type d'object*/
- fnv64_t name_hash; /* Empreinte du nom */
- operand_extra_data_t *extra; /* Données insérées à modifier */
- assert(!lock);
- name = G_OBJECT_TYPE_NAME(G_OBJECT(operand));
- name_hash = fnv_64a_hash(name);
- result = (name_hash & 0xffffffff);
- result ^= (name_hash >> 32);
- extra = GET_ARCH_OP_EXTRA(operand);
- result ^= extra->flags;
- return result;
-}
-/******************************************************************************
-* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
-* *
-* Retour : Empreinte de l'élément représenté. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-static guint g_arch_operand_hash(const GArchOperand *operand)
-{
- guint result; /* Valeur à retourner */
- GArchOperandClass *class; /* Classe associée à l'objet */
-
- class = G_ARCH_OPERAND_GET_CLASS(operand);
-
- result = class->hash(operand, true);
- return result;
-
-}
+/* ---------------------------------------------------------------------------------- */
+/* COMPARAISON DETAILLEE DE DEUX OBJETS */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* other = second élément à analyser. *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
* *
-* Description : Détermine si deux candidats à l'unicité sont identiques. *
+* Description : Réalise une comparaison étendue entre objets. *
* *
* Retour : Bilan de la comparaison. *
* *
@@ -777,56 +526,56 @@ static guint g_arch_operand_hash(const GArchOperand *operand)
* *
******************************************************************************/
-static gboolean g_arch_operand_is_equal(const GArchOperand *operand, const GArchOperand *other)
+static int g_arch_operand_compare(const GComparableObject *object, const GComparableObject *other)
{
- gboolean result; /* Bilan à renvoyer */
- int ret; /* Bilan d'une comparaison */
+ int result; /* Bilan à retourner */
+ operand_extra_data_t extra_op; /* Données insérées à consulter*/
+ operand_extra_data_t extra_other; /* Données insérées à consulter*/
- ret = g_arch_operand_compare(operand, other);
+ extra_op = GET_ARCH_OP_EXTRA(object);
+ extra_other = GET_ARCH_OP_EXTRA(other);
- result = (ret == 0);
+ result = sort_unsigned_long(extra_op.flags, extra_other.flags);
return result;
}
-/******************************************************************************
-* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* *
-* Description : Marque un candidat comme figé. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_arch_operand_set_read_only(GArchOperand *operand)
-{
- g_arch_operand_set_flag(operand, AOF_READ_ONLY);
-}
+/* ---------------------------------------------------------------------------------- */
+/* CALCUL D'UNE EMPREINTE DE L'INSTANCE */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
+* Paramètres : object = objet dont l'instance est à consulter. *
* *
-* Description : Indique si le candidat est figé. *
+* Description : Calcule l'empreinte sur 32 bits d'un objet. *
* *
-* Retour : true si le contenu du candidat ne peut plus être modifié. *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_arch_operand_is_read_only(GArchOperand *operand)
+static guint g_arch_operand_hash(const GHashableObject *object)
{
- bool result; /* Etat à retourner */
+ guint result; /* Valeur à retourner */
+ const char *name; /* Désignation du type d'object*/
+ fnv64_t name_hash; /* Empreinte du nom */
+ operand_extra_data_t extra; /* Données insérées à consulter*/
- result = g_arch_operand_has_flag(operand, AOF_READ_ONLY);
+ name = G_OBJECT_TYPE_NAME(G_OBJECT(object));
+ name_hash = fnv_64a_hash(name);
+
+ result = (name_hash & 0xffffffff);
+ result ^= (name_hash >> 32);
+
+ extra = GET_ARCH_OP_EXTRA(object);
+
+ result ^= extra.flags;
return result;
@@ -835,17 +584,17 @@ static bool g_arch_operand_is_read_only(GArchOperand *operand)
/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION ET RECHARGEMENT DES DONNEES */
+/* MECANISMES DE CONSERVATION ET RESTAURATION */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à constuire. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à lire. *
+* Paramètres : object = élément GLib à constuire. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en lecture. *
* *
-* Description : Charge un contenu depuis une mémoire tampon. *
+* Description : Charge un objet depuis un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -853,22 +602,15 @@ static bool g_arch_operand_is_read_only(GArchOperand *operand)
* *
******************************************************************************/
-static bool _g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_arch_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
- operand_extra_data_t *extra; /* Données insérées à consulter*/
- uleb128_t value; /* Valeur ULEB128 à charger */
-
- extra = GET_ARCH_OP_EXTRA(operand);
+ uleb128_t extra; /* Données embarquées */
- LOCK_GOBJECT_EXTRA(extra);
-
- result = unpack_uleb128(&value, pbuf);
+ result = load_uleb128(&extra, fd);
if (result)
- extra->flags = value;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ g_thick_object_set_extra(G_THICK_OBJECT(object), extra);
return result;
@@ -877,11 +619,11 @@ static bool _g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage,
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à constuire. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à lire. *
+* Paramètres : object = élément GLib à consulter. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Charge un contenu depuis une mémoire tampon. *
+* Description : Sauvegarde un objet dans un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -889,74 +631,69 @@ static bool _g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage,
* *
******************************************************************************/
-static bool g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_arch_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
- GArchOperandClass *class; /* Classe à activer */
+ guint extra; /* Données embarquées */
- class = G_ARCH_OPERAND_GET_CLASS(operand);
+ extra = g_thick_object_get_extra(G_THICK_OBJECT(object));
- result = class->load(operand, storage, pbuf);
+ result = store_uleb128((uleb128_t []) { extra }, fd);
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* CONTROLE DU VOLUME DES INSTANCES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
* *
-* Description : Sauvegarde un contenu dans une mémoire tampon. *
+* Description : Marque un candidat comme figé. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool _g_arch_operand_store(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static void g_arch_operand_mark_as_read_only(GSingletonCandidate *candidate)
{
- bool result; /* Bilan à retourner */
- operand_extra_data_t *extra; /* Données insérées à consulter*/
-
- extra = GET_ARCH_OP_EXTRA(operand);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf);
+ GArchOperand *operand; /* Version spécialisée */
- UNLOCK_GOBJECT_EXTRA(extra);
+ operand = G_ARCH_OPERAND(candidate);
- return result;
+ g_arch_operand_set_flag(operand, AOF_READ_ONLY);
}
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : operand = objet dont l'instance se veut unique. *
* *
-* Description : Sauvegarde un contenu dans une mémoire tampon. *
+* Description : Indique si le candidat est figé. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : true si le contenu du candidat ne peut plus être modifié. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_arch_operand_store(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_arch_operand_is_read_only(const GSingletonCandidate *candidate)
{
- bool result; /* Bilan à retourner */
- GArchOperandClass *class; /* Classe à activer */
+ bool result; /* Etat à retourner */
+ GArchOperand *operand; /* Version spécialisée */
- class = G_ARCH_OPERAND_GET_CLASS(operand);
+ operand = G_ARCH_OPERAND(candidate);
- result = class->store(operand, storage, pbuf);
+ result = g_arch_operand_has_flag(operand, AOF_READ_ONLY);
return result;
diff --git a/src/arch/operand.h b/src/arch/operand.h
index 234ee64..72a1b56 100644
--- a/src/arch/operand.h
+++ b/src/arch/operand.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* operand.h - prototypes pour la gestion générique des opérandes
*
- * Copyright (C) 2008-2020 Cyrille Bagard
+ * Copyright (C) 2008-2024 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,20 +25,16 @@
#define _ARCH_OPERAND_H
-#include <glib-object.h>
-
+#include <stdbool.h>
-#include "../common/packed.h"
-#include "../format/format.h"
-#include "../glibext/bufferline.h"
+#include "../glibext/helpers.h"
-/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
+#define G_TYPE_ARCH_OPERAND (g_arch_operand_get_type())
-/* Depuis "../analysis/binary.h" : description de fichier binaire */
-typedef struct _GLoadedBinary GLoadedBinary;
+DECLARE_GTYPE(GArchOperand, g_arch_operand, G, ARCH_OPERAND);
/* Indications supplémentaires liées aux opérandes */
@@ -58,6 +54,41 @@ typedef enum _ArchOperandFlag
#define AOF_USER_FLAG(n) (1 << (AOF_USER_BIT + n))
+/* Ajoute une information complémentaire à un opérande. */
+bool g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag);
+
+/* Retire une information complémentaire à un opérande. */
+bool g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag);
+
+/* Détermine si un opérande possède un fanion particulier. */
+bool g_arch_operand_has_flag(const GArchOperand *, ArchOperandFlag);
+
+/* Fournit les particularités de l'opérande. */
+ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *);
+
+
+
+
+#if 0
+
+
+#include <glib-object.h>
+
+
+#include "../common/packed.h"
+#include "../format/format.h"
+#include "../glibext/bufferline.h"
+
+
+
+/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
+
+
+/* Depuis "../analysis/binary.h" : description de fichier binaire */
+typedef struct _GLoadedBinary GLoadedBinary;
+
+
+
#define G_TYPE_ARCH_OPERAND g_arch_operand_get_type()
#define G_ARCH_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARCH_OPERAND, GArchOperand))
#define G_IS_ARCH_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARCH_OPERAND))
@@ -95,18 +126,6 @@ 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);
-
-/* Retire une information complémentaire à un opérande. */
-bool g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag);
-
-/* Détermine si un opérande possède un fanion particulier. */
-bool g_arch_operand_has_flag(const GArchOperand *, ArchOperandFlag);
-
-/* Fournit les particularités de l'opérande. */
-ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *);
-
/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */
@@ -116,5 +135,8 @@ ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *);
typedef struct _GAsmStorage GAsmStorage;
+#endif
+
+
#endif /* _ARCH_OPERAND_H */
diff --git a/src/arch/operands/Makefile.am b/src/arch/operands/Makefile.am
index f2a8767..3d9cbde 100644
--- a/src/arch/operands/Makefile.am
+++ b/src/arch/operands/Makefile.am
@@ -1,26 +1,36 @@
-noinst_LTLIBRARIES = libarchoperands.la
+noinst_LTLIBRARIES = libarchoperands.la libarchoperandsui.la
+
+# libarchoperands_la_SOURCES = \
+# feeder-int.h \
+# feeder.h feeder.c \
+# proxy-int.h \
+# proxy.h proxy.c \
+# rename-int.h \
+# rename.h rename.c \
+# target-int.h \
+# target.h target.c \
+# targetable-int.h \
+# targetable.h targetable.c
libarchoperands_la_SOURCES = \
- feeder-int.h \
- feeder.h feeder.c \
immediate-int.h \
immediate.h immediate.c \
+ known-int.h \
known.h known.c \
register-int.h \
- register.h register.c \
- proxy-int.h \
- proxy.h proxy.c \
- rename-int.h \
- rename.h rename.c \
- target-int.h \
- target.h target.c \
- targetable-int.h \
- targetable.h targetable.c
+ register.h register.c
+
+libarchoperands_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+libarchoperandsui_la_SOURCES = \
+ immediate-ui.h immediate-ui.c \
+ known-ui.h known-ui.c \
+ register-ui.h register-ui.c
-libarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
+libarchoperandsui_la_CFLAGS = $(LIBGTK4_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
-dev_HEADERS = $(libarchoperands_la_SOURCES:%c=)
+dev_HEADERS = $(libarchoperands_la_SOURCES:%c=) $(libarchoperandsui_la_SOURCES:%c=)
diff --git a/src/arch/operands/immediate-int.h b/src/arch/operands/immediate-int.h
index d2313f5..3d60c7d 100644
--- a/src/arch/operands/immediate-int.h
+++ b/src/arch/operands/immediate-int.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* immediate-int.h - définitions internes propres aux opérandes représentant des valeurs numériques
*
- * Copyright (C) 2021 Cyrille Bagard
+ * Copyright (C) 2021-2024 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -30,27 +30,8 @@
-/* Informations glissées dans la structure GObject de GArchOperand */
-typedef struct _immop_extra_data_t
-{
- operand_extra_data_t parent; /* A laisser en premier */
-
- MemoryDataSize size; /* Taille de l'opérande */
-
- /**
- * Les deux éléments suivants sont de type ImmOperandDisplay ;
- * leur espace de conservation est réduit au maximum afin d'éviter
- * un recouvrement .
- */
-
- unsigned int def_display : 3; /* Type par défaut d'affichage */
- unsigned int display : 3; /* Format général d'affichage */
-
-} immop_extra_data_t;
-
-
/* Définition d'un opérande de valeur numérique (instance) */
-struct _GImmOperand
+struct _GImmediateOperand
{
GArchOperand parent; /* Instance parente */
@@ -59,7 +40,7 @@ struct _GImmOperand
};
/* Définition d'un opérande de valeur numérique (classe) */
-struct _GImmOperandClass
+struct _GImmediateOperandClass
{
GArchOperandClass parent; /* Classe parente */
@@ -70,15 +51,46 @@ struct _GImmOperandClass
* Accès aux informations éventuellement déportées.
*/
-#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__
+/* Informations glissées dans la structure GObject de GArchOperand */
+typedef struct _immop_extra_data_t
+{
+ ARCH_OPERAND_EXTRA_DATA(3); /* Informations pour l'opérande*/
-# define GET_IMM_OP_EXTRA(op) ((immop_extra_data_t *)&((GArchOperand *)op)->extra)
+ /**
+ * MemoryDataSize
+ */
+ unsigned int size : 4; /* Taille de l'opérande */
+
+ /**
+ * ImmOperandDisplay x 2
+ */
+ unsigned int def_display : 3; /* Type par défaut d'affichage */
+ unsigned int display : 3; /* Format général d'affichage */
+
+} immop_extra_data_t;
+
+
+#define GET_IMM_OP_EXTRA(op) \
+ GET_GOBJECT_EXTRA(op, immop_extra_data_t)
+
+#define SET_IMM_OP_EXTRA(op, data) \
+ SET_GOBJECT_EXTRA(op, immop_extra_data_t, data)
-#else
-# define GET_IMM_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), immop_extra_data_t)
+/* Met en place un opérande réprésentant une valeur numérique. */
+bool g_immediate_operand_create_from_value(GImmediateOperand *, MemoryDataSize, uint64_t);
+
+/* Crée un opérande réprésentant une valeur numérique. */
+bool g_immediate_operand_create_from_data(GImmediateOperand *, MemoryDataSize, const GBinContent *, vmpa2t *, bool *, SourceEndian);
+
+/**
+ * La taille d'impression d'un opérande n'est pas VMPA_MAX_SIZE,
+ * mais 1 + 64 caractères + octet nul final en cas d'impression en binaire.
+ */
+#define IMM_MAX_SIZE 66
-#endif
+/* Construit la chaîne de caractères correspondant à l'opérande. */
+size_t _g_immediate_operand_to_string(const GImmediateOperand *, ImmOperandDisplay, char [IMM_MAX_SIZE]);
diff --git a/src/arch/operands/immediate-ui.c b/src/arch/operands/immediate-ui.c
new file mode 100644
index 0000000..62058b3
--- /dev/null
+++ b/src/arch/operands/immediate-ui.c
@@ -0,0 +1,184 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * immediate-ui.c - opérandes représentant des valeurs numériques sous forme graphique
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "immediate-ui.h"
+
+
+#include <i18n.h>
+
+
+#include "immediate-int.h"
+#include "../../common/extstr.h"
+#include "../../glibext/tokenstyle.h"
+#include "../../glibext/options/asm.h"
+
+
+
+/* Traduit un opérande en version humainement lisible. */
+static void g_immediate_operand_ui_print(const GImmediateOperand *, GBufferLine *);
+
+/* Construit un petit résumé concis de l'opérande. */
+static char *g_immediate_operand_ui_build_tooltip(const GImmediateOperand *, const GLoadedBinary *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface d'opérande UI. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *iface)
+{
+ iface->print = (print_operand_ui_fc)g_immediate_operand_ui_print;
+ iface->build_tooltip = (build_operand_ui_tooltip_fc)g_immediate_operand_ui_build_tooltip;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande à traiter. *
+* line = ligne tampon où imprimer l'opérande donné. *
+* *
+* Description : Traduit un opérande en version humainement lisible. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_immediate_operand_ui_print(const GImmediateOperand *operand, GBufferLine *line)
+{
+ GImmediateOperand *base; /* Version d'instance basique */
+ ImmOperandDisplay display; /* Type d'affichage courant */
+ char value[IMM_MAX_SIZE]; /* Chaîne à imprimer */
+ size_t len; /* Taille de l'élément inséré */
+
+ base = G_IMMEDIATE_OPERAND(operand);
+
+ display = g_immediate_operand_get_display(base);
+
+ len = _g_immediate_operand_to_string(base, display, value);
+
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_IMMEDIATE, value, len, NULL, G_OBJECT(operand));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande à consulter. *
+* binary = informations relatives au binaire chargé. *
+* *
+* Description : Construit un petit résumé concis de l'opérande. *
+* *
+* Retour : Chaîne de caractères à libérer après usage ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_immediate_operand_ui_build_tooltip(const GImmediateOperand *operand, const GLoadedBinary *binary)
+{
+ char *result; /* Description à retourner */
+ GImmediateOperand *base; /* Version d'instance basique */
+ char value[IMM_MAX_SIZE]; /* Conversion artificielle */
+ char *conv; /* Affichage de la Conversion */
+
+ base = G_IMMEDIATE_OPERAND(operand);
+
+ if (base->raw <= UCHAR_MAX && isprint(base->raw))
+ switch (base->raw)
+ {
+ case '&':
+ asprintf(&result, _("Character: '&amp;'"));
+ break;
+ case '<':
+ asprintf(&result, _("Character: '&lt;'"));
+ break;
+ case '>':
+ asprintf(&result, _("Character: '&gt;'"));
+ break;
+ default:
+ asprintf(&result, _("Character: '%c'"), (char)base->raw);
+ break;
+ }
+
+ else
+ asprintf(&result, _("Character: &lt;not printable&gt;"));
+
+ /* Binaire */
+
+ _g_immediate_operand_to_string(base, IOD_BIN, value);
+
+ asprintf(&conv, _("Binary: %s"), value);
+
+ result = stradd(result, "\n");
+ result = stradd(result, conv);
+
+ free(conv);
+
+ /* Octal */
+
+ _g_immediate_operand_to_string(base, IOD_OCT, value);
+
+ asprintf(&conv, _("Octal: %s"), value);
+
+ result = stradd(result, "\n");
+ result = stradd(result, conv);
+
+ free(conv);
+
+ /* Décimal */
+
+ _g_immediate_operand_to_string(base, IOD_DEC, value);
+
+ asprintf(&conv, _("Decimal: %s"), value);
+
+ result = stradd(result, "\n");
+ result = stradd(result, conv);
+
+ free(conv);
+
+ /* Hexadécimal */
+
+ _g_immediate_operand_to_string(base, IOD_HEX, value);
+
+ asprintf(&conv, _("Hexadecimal: %s"), value);
+
+ result = stradd(result, "\n");
+ result = stradd(result, conv);
+
+ free(conv);
+
+ return result;
+
+}
diff --git a/src/arch/operands/immediate-ui.h b/src/arch/operands/immediate-ui.h
new file mode 100644
index 0000000..4dbddae
--- /dev/null
+++ b/src/arch/operands/immediate-ui.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * immediate-ui.h - prototypes pour les opérandes représentant des valeurs numériques sous forme graphique
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ARCH_OPERANDS_IMMEDIATE_UI_H
+#define _ARCH_OPERANDS_IMMEDIATE_UI_H
+
+
+#include "../operand-ui-int.h"
+
+
+
+/* Procède à l'initialisation de l'interface d'opérande UI. */
+void g_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *);
+
+
+
+#endif /* _ARCH_OPERANDS_IMMEDIATE_UI_H */
diff --git a/src/arch/operands/immediate.c b/src/arch/operands/immediate.c
index f40c645..f99b421 100644
--- a/src/arch/operands/immediate.c
+++ b/src/arch/operands/immediate.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* immediate.c - opérandes représentant des valeurs numériques
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2024 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,25 +25,32 @@
#include <assert.h>
+#include <stdarg.h>
+
+
+
+#if 0
+
#include <ctype.h>
#include <inttypes.h>
#include <limits.h>
#include <malloc.h>
-#include <stdarg.h>
#include <stdio.h>
#include <i18n.h>
+#endif
+
+
#include "immediate-int.h"
-#include "known.h"
-#include "rename-int.h"
-#include "targetable-int.h"
#include "../../common/asm.h"
-#include "../../common/extstr.h"
#include "../../common/sort.h"
-#include "../../core/columns.h"
+#include "../../glibext/comparable-int.h"
+#include "../../glibext/hashable-int.h"
+#include "../../glibext/serialize-int.h"
+#include "../../glibext/strbuilder-int.h"
@@ -51,68 +58,75 @@
/* Initialise la classe des opérandes de valeur immédiate. */
-static void g_imm_operand_class_init(GImmOperandClass *);
+static void g_immediate_operand_class_init(GImmediateOperandClass *);
-/* Initialise un opérande de valeur immédiate. */
-static void g_imm_operand_init(GImmOperand *);
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface de détermination. */
+static void g_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface d'exportation. */
+static void g_immediate_operand_string_builder_iface_init(GStringBuilderInterface *, gpointer);
+
+#if 0
/* Procède à l'initialisation de l'interface de ciblage. */
-static void g_imm_operand_targetable_interface_init(GTargetableOperandInterface *);
+static void g_immediate_operand_targetable_interface_init(GTargetableOperandInterface *);
/* Procède à l'initialisation de l'interface de renommage. */
-static void g_imm_operand_renameable_interface_init(GRenameableOperandInterface *);
+static void g_immediate_operand_renameable_interface_init(GRenameableOperandInterface *);
+
+#endif
+
+/* Initialise un opérande de valeur immédiate. */
+static void g_immediate_operand_init(GImmediateOperand *);
/* Supprime toutes les références externes. */
-static void g_imm_operand_dispose(GImmOperand *);
+static void g_immediate_operand_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_imm_operand_finalize(GImmOperand *);
+static void g_immediate_operand_finalize(GObject *);
-/* Construit la chaîne de caractères correspondant à l'opérande. */
-static size_t _g_imm_operand_to_string(const GImmOperand *, ImmOperandDisplay, char [IMM_MAX_SIZE]);
-/* Traduit un opérande en version humainement lisible. */
-static void g_imm_operand_print(const GImmOperand *, GBufferLine *);
+/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+/* Réalise une comparaison étendue entre objets. */
+static int g_immediate_operand_compare(const GComparableObject *, const GComparableObject *);
-/* Compare un opérande avec un autre. */
-static int g_imm_operand_compare(const GImmOperand *, const GImmOperand *, bool);
-#ifdef INCLUDE_GTK_SUPPORT
+/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */
-/* Construit un petit résumé concis de l'opérande. */
-static char *g_imm_operand_build_tooltip(const GImmOperand *, const GLoadedBinary *);
-#endif
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+static guint g_immediate_operand_hash(const GHashableObject *);
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-static guint g_imm_operand_hash(const GImmOperand *, bool);
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_imm_operand_load(GImmOperand *, GObjectStorage *, packed_buffer_t *);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_imm_operand_store(GImmOperand *, GObjectStorage *, packed_buffer_t *);
+/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */
+/* Charge un objet depuis un flux de données. */
+static bool g_immediate_operand_load(GSerializableObject *, GObjectStorage *, int);
-/* ---------------------- COMMUNICATION D'UN CIBLAGE POTENTIEL ---------------------- */
+/* Sauvegarde un objet dans un flux de données. */
+static bool g_immediate_operand_store(const GSerializableObject *, GObjectStorage *, int);
-/* Obtient l'adresse de la cible visée par un opérande. */
-static bool g_imm_operand_get_addr(const GImmOperand *, const vmpa2t *, GBinFormat *, GArchProcessor *, vmpa2t *);
+/* ----------------- EXPORTATION SOUS FORME DE CHAINE DE CARACTERES ----------------- */
-/* ---------------------- CONSTRUCTION D'UN CONTENU ALTERNATIF ---------------------- */
+/* Exporte une chaîne de caractères à partir d'un objet. */
+static bool g_immediate_operand_to_string(const GStringBuilder *, unsigned int, sized_binary_t *);
-/* Construit un opérande de représentation alternative. */
-static GRenamedOperand *g_imm_operand_build(const GImmOperand *, const char *);
@@ -122,9 +136,12 @@ static GRenamedOperand *g_imm_operand_build(const GImmOperand *, const char *);
/* Indique le type défini pour un opérande de valeur numérique. */
-G_DEFINE_TYPE_WITH_CODE(GImmOperand, g_imm_operand, G_TYPE_ARCH_OPERAND,
- G_IMPLEMENT_INTERFACE(G_TYPE_TARGETABLE_OPERAND, g_imm_operand_targetable_interface_init)
- G_IMPLEMENT_INTERFACE(G_TYPE_RENAMEABLE_OPERAND, g_imm_operand_renameable_interface_init));
+G_DEFINE_TYPE_WITH_CODE(GImmediateOperand, g_immediate_operand, G_TYPE_ARCH_OPERAND,
+ G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_immediate_operand_comparable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_immediate_operand_hashable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_immediate_operand_serializable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_immediate_operand_string_builder_iface_init)
+ G_IMPLEMENT_INTERFACE_IF_SYM(g_arch_operand_ui_get_type, g_immediate_operand_ui_arch_operand_ui_iface_init));
/******************************************************************************
@@ -139,36 +156,42 @@ G_DEFINE_TYPE_WITH_CODE(GImmOperand, g_imm_operand, G_TYPE_ARCH_OPERAND,
* *
******************************************************************************/
-static void g_imm_operand_class_init(GImmOperandClass *klass)
+static void g_immediate_operand_class_init(GImmediateOperandClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
- GArchOperandClass *operand; /* Version de classe parente */
object = G_OBJECT_CLASS(klass);
- operand = G_ARCH_OPERAND_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_imm_operand_dispose;
- object->finalize = (GObjectFinalizeFunc)g_imm_operand_finalize;
+ object->dispose = g_immediate_operand_dispose;
+ object->finalize = g_immediate_operand_finalize;
- 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;
- operand->load = (load_operand_fc)g_imm_operand_load;
- operand->store = (store_operand_fc)g_imm_operand_store;
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *iface)
+{
+ iface->compare = g_immediate_operand_compare;
}
/******************************************************************************
* *
-* Paramètres : operand = instance à initialiser. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Initialise un opérande de valeur immédiate. *
+* Description : Procède à l'initialisation de l'interface de détermination. *
* *
* Retour : - *
* *
@@ -176,23 +199,39 @@ static void g_imm_operand_class_init(GImmOperandClass *klass)
* *
******************************************************************************/
-static void g_imm_operand_init(GImmOperand *operand)
+static void g_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *iface)
{
- GET_IMM_OP_EXTRA(operand)->size = MDS_UNDEFINED;
+ iface->hash = g_immediate_operand_hash;
- GET_IMM_OP_EXTRA(operand)->def_display = IOD_HEX;
- GET_IMM_OP_EXTRA(operand)->display = IOD_COUNT;
+}
- operand->raw = 0;
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de sérialisation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *iface)
+{
+ iface->load = g_immediate_operand_load;
+ iface->store = g_immediate_operand_store;
}
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
+* Paramètres : iface = interface GLib à initialiser. *
+* unused = pointeur non utilisé ici. *
* *
-* Description : Procède à l'initialisation de l'interface de ciblage. *
+* Description : Procède à l'initialisation de l'interface d'exportation. *
* *
* Retour : - *
* *
@@ -200,18 +239,18 @@ static void g_imm_operand_init(GImmOperand *operand)
* *
******************************************************************************/
-static void g_imm_operand_targetable_interface_init(GTargetableOperandInterface *iface)
+static void g_immediate_operand_string_builder_iface_init(GStringBuilderInterface *iface, gpointer unused)
{
- iface->get_addr = (get_targetable_addr_fc)g_imm_operand_get_addr;
+ iface->to_string = g_immediate_operand_to_string;
}
/******************************************************************************
* *
-* Paramètres : iface = interface GLib à initialiser. *
+* Paramètres : operand = instance à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de renommage. *
+* Description : Initialise un opérande de valeur immédiate. *
* *
* Retour : - *
* *
@@ -219,16 +258,27 @@ static void g_imm_operand_targetable_interface_init(GTargetableOperandInterface
* *
******************************************************************************/
-static void g_imm_operand_renameable_interface_init(GRenameableOperandInterface *iface)
+static void g_immediate_operand_init(GImmediateOperand *operand)
{
- iface->build = (build_renameable_fc)g_imm_operand_build;
+ immop_extra_data_t extra; /* Données insérées à consulter*/
+
+ extra = GET_IMM_OP_EXTRA(operand);
+
+ extra.size = MDS_UNDEFINED;
+
+ extra.def_display = IOD_HEX;
+ extra.display = IOD_COUNT;
+
+ SET_IMM_OP_EXTRA(operand, &extra);
+
+ operand->raw = 0;
}
/******************************************************************************
* *
-* Paramètres : operand = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -238,16 +288,16 @@ static void g_imm_operand_renameable_interface_init(GRenameableOperandInterface
* *
******************************************************************************/
-static void g_imm_operand_dispose(GImmOperand *operand)
+static void g_immediate_operand_dispose(GObject *object)
{
- G_OBJECT_CLASS(g_imm_operand_parent_class)->dispose(G_OBJECT(operand));
+ G_OBJECT_CLASS(g_immediate_operand_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : operand = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -257,9 +307,74 @@ static void g_imm_operand_dispose(GImmOperand *operand)
* *
******************************************************************************/
-static void g_imm_operand_finalize(GImmOperand *operand)
+static void g_immediate_operand_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(g_immediate_operand_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : size = taille de l'opérande souhaitée. *
+* value = valeur sur x bits à venir récupérer. *
+* *
+* Description : Crée un opérande réprésentant une valeur numérique. *
+* *
+* Retour : Instruction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GArchOperand *g_immediate_operand_new_from_value(MemoryDataSize size, uint64_t value)
{
- G_OBJECT_CLASS(g_imm_operand_parent_class)->finalize(G_OBJECT(operand));
+ GImmediateOperand *result; /* Opérande à retourner */
+
+ result = g_object_new(G_TYPE_IMMEDIATE_OPERAND, NULL);
+
+ if (!g_immediate_operand_create_from_value(result, size, value))
+ g_clear_object(&result);
+
+ return G_ARCH_OPERAND(result);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = instance à initialiser pleinement. *
+* size = taille de l'opérande souhaitée. *
+* value = valeur sur x bits à venir récupérer. *
+* *
+* Description : Met en place un opérande réprésentant une valeur numérique. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_immediate_operand_create_from_value(GImmediateOperand *operand, MemoryDataSize size, uint64_t value)
+{
+ bool result; /* Bilan à retourner */
+ immop_extra_data_t extra; /* Données insérées à consulter*/
+
+ result = (size != MDS_UNDEFINED);
+
+ if (result)
+ {
+ extra = GET_IMM_OP_EXTRA(operand);
+
+ extra.size = size;
+
+ operand->raw = value;
+
+ SET_IMM_OP_EXTRA(operand, &extra);
+
+ }
+
+ return result;
}
@@ -280,10 +395,41 @@ static void g_imm_operand_finalize(GImmOperand *operand)
* *
******************************************************************************/
-GArchOperand *_g_imm_operand_new_from_data(MemoryDataSize size, const GBinContent *content, vmpa2t *addr, bool *low, SourceEndian endian)
+GArchOperand *g_immediate_operand_new_from_data(MemoryDataSize size, const GBinContent *content, vmpa2t *addr, bool *low, SourceEndian endian)
{
- GImmOperand *result; /* Opérande à retourner */
- immop_extra_data_t *extra; /* Données insérées à modifier */
+ GImmediateOperand *result; /* Opérande à retourner */
+
+ result = g_object_new(G_TYPE_IMMEDIATE_OPERAND, NULL);
+
+ if (!g_immediate_operand_create_from_data(result, size, content, addr, low, endian))
+ g_clear_object(&result);
+
+ return G_ARCH_OPERAND(result);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = instance à initialiser pleinement. *
+* size = taille de l'opérande souhaitée. *
+* content = flux de données à analyser. *
+* addr = position courante dans ce flux. [OUT] *
+* low = position éventuelle des 4 bits visés. [OUT] *
+* endian = ordre des bits dans la source. *
+* *
+* Description : Crée un opérande réprésentant une valeur numérique. *
+* *
+* Retour : Instruction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_immediate_operand_create_from_data(GImmediateOperand *operand, MemoryDataSize size, const GBinContent *content, vmpa2t *addr, bool *low, SourceEndian endian)
+{
+ bool result; /* Bilan à retourner */
+ uint64_t raw; /* Valeur brute lue */
uint8_t uval8; /* Valeur sur 8 bits */
uint16_t uval16; /* Valeur sur 16 bits */
uint32_t uval32; /* Valeur sur 32 bits */
@@ -293,125 +439,78 @@ GArchOperand *_g_imm_operand_new_from_data(MemoryDataSize size, const GBinConten
int32_t sval32; /* Valeur sur 32 bits */
int64_t sval64; /* Valeur sur 64 bits */
- result = g_object_new(G_TYPE_IMM_OPERAND, NULL);
-
- extra = GET_IMM_OP_EXTRA(result);
-
- extra->size = size;
-
switch (size)
{
case MDS_4_BITS_UNSIGNED:
- if (!g_binary_content_read_u4(content, addr, low, &uval8))
- goto gionfd_error;
- result->raw = uval8;
+ result = g_binary_content_read_u4(content, addr, low, &uval8);
+ if (result)
+ raw = uval8;
break;
case MDS_8_BITS_UNSIGNED:
- if (!g_binary_content_read_u8(content, addr, &uval8))
- goto gionfd_error;
- result->raw = uval8;
+ result = g_binary_content_read_u8(content, addr, &uval8);
+ if (result)
+ raw = uval8;
break;
case MDS_16_BITS_UNSIGNED:
- if (!g_binary_content_read_u16(content, addr, endian, &uval16))
- goto gionfd_error;
- result->raw = uval16;
+ result = g_binary_content_read_u16(content, addr, endian, &uval16);
+ if (result)
+ raw = uval16;
break;
case MDS_32_BITS_UNSIGNED:
- if (!g_binary_content_read_u32(content, addr, endian, &uval32))
- goto gionfd_error;
- result->raw = uval32;
+ result = g_binary_content_read_u32(content, addr, endian, &uval32);
+ if (result)
+ raw = uval32;
break;
case MDS_64_BITS_UNSIGNED:
- if (!g_binary_content_read_u64(content, addr, endian, &uval64))
- goto gionfd_error;
- result->raw = uval64;
+ result = g_binary_content_read_u64(content, addr, endian, &uval64);
+ if (result)
+ raw = uval64;
break;
case MDS_4_BITS_SIGNED:
- if (!g_binary_content_read_s4(content, addr, low, &sval8))
- goto gionfd_error;
- result->raw = sval8;
+ result = g_binary_content_read_s4(content, addr, low, &sval8);
+ if (result)
+ raw = sval8;
break;
case MDS_8_BITS_SIGNED:
- if (!g_binary_content_read_s8(content, addr, &sval8))
- goto gionfd_error;
- result->raw = sval8;
+ result = g_binary_content_read_s8(content, addr, &sval8);
+ if (result)
+ raw = sval8;
break;
case MDS_16_BITS_SIGNED:
- if (!g_binary_content_read_s16(content, addr, endian, &sval16))
- goto gionfd_error;
- result->raw = sval16;
+ result = g_binary_content_read_s16(content, addr, endian, &sval16);
+ if (result)
+ raw = sval16;
break;
case MDS_32_BITS_SIGNED:
- if (!g_binary_content_read_s32(content, addr, endian, &sval32))
- goto gionfd_error;
- result->raw = sval32;
+ result = g_binary_content_read_s32(content, addr, endian, &sval32);
+ if (result)
+ raw = sval32;
break;
case MDS_64_BITS_SIGNED:
- if (!g_binary_content_read_s64(content, addr, endian, &sval64))
- goto gionfd_error;
- result->raw = sval64;
+ result = g_binary_content_read_s64(content, addr, endian, &sval64);
+ if (result)
+ raw = sval64;
break;
case MDS_UNDEFINED:
- goto gionfd_error;
+ result = false;
break;
}
- return G_ARCH_OPERAND(result);
-
- gionfd_error:
-
- g_object_unref(G_OBJECT(result));
-
- return NULL;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : size = taille de l'opérande souhaitée. *
-* value = valeur sur x bits à venir récupérer. *
-* *
-* Description : Crée un opérande réprésentant une valeur numérique. *
-* *
-* Retour : Instruction mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GArchOperand *g_imm_operand_new_from_value(MemoryDataSize size, uint64_t value)
-{
- GImmOperand *result; /* Opérande à retourner */
- immop_extra_data_t *extra; /* Données insérées à modifier */
-
- if (size == MDS_UNDEFINED)
- result = NULL;
-
- else
- {
- result = g_object_new(G_TYPE_IMM_OPERAND, NULL);
-
- extra = GET_IMM_OP_EXTRA(result);
-
- extra->size = size;
-
- result->raw = value;
-
- }
+ if (result)
+ result = g_immediate_operand_create_from_value(operand, size, raw);
- return (result != NULL ? G_ARCH_OPERAND(result) : NULL);
+ return result;
}
@@ -428,18 +527,14 @@ GArchOperand *g_imm_operand_new_from_value(MemoryDataSize size, uint64_t value)
* *
******************************************************************************/
-MemoryDataSize g_imm_operand_get_size(const GImmOperand *operand)
+MemoryDataSize g_immediate_operand_get_size(const GImmediateOperand *operand)
{
MemoryDataSize result; /* Taille à retourner */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ immop_extra_data_t extra; /* Données insérées à consulter*/
extra = GET_IMM_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = extra->size;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = extra.size;
return result;
@@ -460,10 +555,10 @@ MemoryDataSize g_imm_operand_get_size(const GImmOperand *operand)
* *
******************************************************************************/
-bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ...)
+bool g_immediate_operand_get_value(const GImmediateOperand *operand, MemoryDataSize size, ...)
{
bool result; /* Bilan à retourner */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ immop_extra_data_t extra; /* Données insérées à consulter*/
va_list ap; /* Liste des compléments */
uint8_t *uval8; /* Valeur sur 8 bits */
uint16_t *uval16; /* Valeur sur 16 bits */
@@ -478,9 +573,7 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..
extra = GET_IMM_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- if (extra->size != size)
+ if (extra.size != size)
goto exit;
va_start(ap, size);
@@ -533,8 +626,6 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..
exit:
- UNLOCK_GOBJECT_EXTRA(extra);
-
return result;
}
@@ -542,6 +633,37 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..
/******************************************************************************
* *
+* Paramètres : operand = structure dont le contenu est à actualiser. [OUT] *
+* size = taille de l'opérande souhaitée. *
+* value = valeur sur x bits à venir récupérer. *
+* *
+* Description : Définit la nouvelle valeur de l'opérande à une valeur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_immediate_operand_set_value(GImmediateOperand *operand, MemoryDataSize size, uint64_t value)
+{
+ immop_extra_data_t extra; /* Données insérées à consulter*/
+
+ assert(size != MDS_UNDEFINED);
+
+ extra = GET_IMM_OP_EXTRA(operand);
+
+ extra.size = size;
+
+ operand->raw = value;
+
+ SET_IMM_OP_EXTRA(operand, &extra);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : operand = opérande à consulter. *
* *
* Description : Fournit la valeur brute représentée par l'opérande. *
@@ -552,42 +674,55 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..
* *
******************************************************************************/
-uint64_t g_imm_operand_get_raw_value(const GImmOperand *operand)
+uint64_t g_immediate_operand_get_raw_value(const GImmediateOperand *operand)
{
- return operand->raw;
+ uint64_t result; /* Valeur brute à retourner */
+
+ result = operand->raw;
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : operand = structure dont le contenu est à actualiser. [OUT] *
-* size = taille de l'opérande souhaitée. *
-* value = valeur sur x bits à venir récupérer. *
+* Paramètres : operand = structure dont le contenu est à consulter. *
* *
-* Description : Définit la nouvelle valeur de l'opérande à une valeur. *
+* Description : Indique le signe d'une valeur immédiate. *
* *
-* Retour : - *
+* Retour : true si la valeur est strictement négative, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_imm_operand_set_value(GImmOperand *operand, MemoryDataSize size, uint64_t value)
+bool g_immediate_operand_is_negative(const GImmediateOperand *operand)
{
- immop_extra_data_t *extra; /* Données insérées à consulter*/
-
- assert(size != MDS_UNDEFINED);
+ bool result; /* Bilan à renvoyer */
+ immop_extra_data_t extra; /* Données insérées à consulter*/
extra = GET_IMM_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- extra->size = size;
-
- operand->raw = value;
+ switch (extra.size)
+ {
+ case MDS_4_BITS_SIGNED:
+ case MDS_8_BITS_SIGNED:
+ case MDS_16_BITS_SIGNED:
+ case MDS_32_BITS_SIGNED:
+ case MDS_64_BITS_SIGNED:
+ /**
+ * Pour les valeurs plus petites que 64 bits, le compilateur
+ * réalise une extension de signe lors du transtypage.
+ */
+ result = (operand->raw & 0x8000000000000000ll);
+ break;
+ default:
+ result = false;
+ break;
+ }
- UNLOCK_GOBJECT_EXTRA(extra);
+ return result;
}
@@ -605,17 +740,15 @@ void g_imm_operand_set_value(GImmOperand *operand, MemoryDataSize size, uint64_t
* *
******************************************************************************/
-void g_imm_operand_set_default_display(GImmOperand *operand, ImmOperandDisplay display)
+void g_immediate_operand_set_default_display(GImmediateOperand *operand, ImmOperandDisplay display)
{
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ immop_extra_data_t extra; /* Données insérées à consulter*/
extra = GET_IMM_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
+ extra.def_display = display;
- extra->def_display = display;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ SET_IMM_OP_EXTRA(operand, &extra);
}
@@ -632,18 +765,14 @@ void g_imm_operand_set_default_display(GImmOperand *operand, ImmOperandDisplay d
* *
******************************************************************************/
-ImmOperandDisplay g_imm_operand_get_default_display(const GImmOperand *operand)
+ImmOperandDisplay g_immediate_operand_get_default_display(const GImmediateOperand *operand)
{
ImmOperandDisplay result; /* Affichage à retourner */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ immop_extra_data_t extra; /* Données insérées à consulter*/
extra = GET_IMM_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- result = extra->def_display;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = extra.def_display;
return result;
@@ -663,17 +792,15 @@ ImmOperandDisplay g_imm_operand_get_default_display(const GImmOperand *operand)
* *
******************************************************************************/
-void g_imm_operand_set_display(GImmOperand *operand, ImmOperandDisplay display)
+void g_immediate_operand_set_display(GImmediateOperand *operand, ImmOperandDisplay display)
{
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ immop_extra_data_t extra; /* Données insérées à consulter*/
extra = GET_IMM_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
+ extra.display = display;
- extra->display = display;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ SET_IMM_OP_EXTRA(operand, &extra);
}
@@ -690,94 +817,225 @@ void g_imm_operand_set_display(GImmOperand *operand, ImmOperandDisplay display)
* *
******************************************************************************/
-ImmOperandDisplay g_imm_operand_get_display(const GImmOperand *operand)
+ImmOperandDisplay g_immediate_operand_get_display(const GImmediateOperand *operand)
{
ImmOperandDisplay result; /* Affichage à retourner */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ immop_extra_data_t extra; /* Données insérées à consulter*/
extra = GET_IMM_OP_EXTRA(operand);
- LOCK_GOBJECT_EXTRA(extra);
-
- if (extra->display != IOD_COUNT)
- result = extra->display;
+ if (extra.display != IOD_COUNT)
+ result = extra.display;
else
- result = extra->def_display;
-
- UNLOCK_GOBJECT_EXTRA(extra);
+ result = extra.def_display;
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* COMPARAISON DETAILLEE DE DEUX OBJETS */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = structure dont le contenu est à consulter. *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
* *
-* Description : Indique le signe d'une valeur immédiate. *
+* Description : Réalise une comparaison étendue entre objets. *
* *
-* Retour : true si la valeur est strictement négative, false sinon. *
+* Retour : Bilan de la comparaison. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_imm_operand_is_negative(const GImmOperand *operand)
+static int g_immediate_operand_compare(const GComparableObject *object, const GComparableObject *other)
{
- bool result; /* Bilan à renvoyer */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ int result; /* Bilan à retourner */
+ GComparableObjectInterface *iface; /* Interface utilisée */
+ GComparableObjectInterface *parent_iface; /* Interface parente */
+ GImmediateOperand *operand_a; /* Version spécialisée #0 */
+ GImmediateOperand *operand_b; /* Version spécialisée #1 */
+ immop_extra_data_t extra_a; /* Données insérées à consulter*/
+ immop_extra_data_t extra_b; /* Données insérées à consulter*/
- extra = GET_IMM_OP_EXTRA(operand);
+ iface = G_COMPARABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
- LOCK_GOBJECT_EXTRA(extra);
+ result = parent_iface->compare(object, other);
- switch (extra->size)
+ if (result == 0)
{
- case MDS_4_BITS_SIGNED:
- case MDS_8_BITS_SIGNED:
- case MDS_16_BITS_SIGNED:
- case MDS_32_BITS_SIGNED:
- case MDS_64_BITS_SIGNED:
- /**
- * Pour les valeurs plus petites que 64 bits, le compilateur
- * réalise une extension de signe lors du transtypage.
- */
- result = (operand->raw & 0x8000000000000000ll);
- break;
- default:
- result = false;
- break;
+ operand_a = G_IMMEDIATE_OPERAND(object);
+
+ extra_a = GET_IMM_OP_EXTRA(operand_a);
+
+ operand_b = G_IMMEDIATE_OPERAND(other);
+
+ extra_b = GET_IMM_OP_EXTRA(operand_b);
+
+ result = sort_unsigned_long(extra_a.size, extra_b.size);
+
+ if (result == 0)
+ sort_uint64_t(operand_a->raw, operand_b->raw);
+
+ if (result == 0)
+ result = sort_unsigned_long(extra_a.def_display, extra_b.def_display);
+
+ if (result == 0)
+ result = sort_unsigned_long(extra_a.display, extra_b.display);
+
}
- UNLOCK_GOBJECT_EXTRA(extra);
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CALCUL D'UNE EMPREINTE DE L'INSTANCE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : object = objet dont l'instance est à consulter. *
+* *
+* Description : Calcule l'empreinte sur 32 bits d'un objet. *
+* *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static guint g_immediate_operand_hash(const GHashableObject *object)
+{
+ guint result; /* Valeur à retourner */
+ GHashableObjectInterface *iface; /* Interface utilisée */
+ GHashableObjectInterface *parent_iface; /* Interface parente */
+ GImmediateOperand *operand; /* Version spécialisée */
+
+ iface = G_HASHABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ result = parent_iface->hash(object);
+
+ operand = G_IMMEDIATE_OPERAND(object);
+
+ result ^= (operand->raw & 0xffffffff);
+ result ^= (operand->raw >> 32);
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* MECANISMES DE CONSERVATION ET RESTAURATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = structure dont le contenu est à consulter. *
+* Paramètres : object = élément GLib à constuire. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en lecture. *
* *
-* Description : Indique si une valeur immédiate est nulle ou non. *
+* Description : Charge un objet depuis un flux de données. *
* *
-* Retour : true si la valeur est nulle, false sinon. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_imm_operand_is_null(const GImmOperand *operand)
+static bool g_immediate_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)
{
- return (operand->raw == 0ll);
+ bool result; /* Bilan à retourner */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *parent_iface; /* Interface parente */
+ uleb128_t val; /* Valeur sauvegardée */
+ GImmediateOperand *operand; /* Version spécialisée */
+
+ iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ result = parent_iface->load(object, storage, fd);
+
+ if (result)
+ {
+ result = load_uleb128(&val, fd);
+
+ if (result)
+ {
+ operand = G_IMMEDIATE_OPERAND(object);
+ operand->raw = val;
+ }
+
+ }
+
+ return result;
}
/******************************************************************************
* *
+* Paramètres : object = élément GLib à consulter. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en écriture. *
+* *
+* Description : Sauvegarde un objet dans un flux de données. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_immediate_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd)
+{
+ bool result; /* Bilan à retourner */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *parent_iface; /* Interface parente */
+ GImmediateOperand *operand; /* Version spécialisée */
+
+ iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ result = parent_iface->store(object, storage, fd);
+ if (!result) goto exit;
+
+ operand = G_IMMEDIATE_OPERAND(object);
+
+ result = store_uleb128((uleb128_t []) { operand->raw }, fd);
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* EXPORTATION SOUS FORME DE CHAINE DE CARACTERES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
* Paramètres : operand = opérande à transcrire. *
* display = type d'affichage demandé. *
* value = valeur portée par l'opérande transcrite. [OUT] *
@@ -790,10 +1048,10 @@ bool g_imm_operand_is_null(const GImmOperand *operand)
* *
******************************************************************************/
-static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDisplay display, char value[IMM_MAX_SIZE])
+size_t _g_immediate_operand_to_string(const GImmediateOperand *operand, ImmOperandDisplay display, char value[IMM_MAX_SIZE])
{
size_t result; /* Longueur à retourner */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
+ immop_extra_data_t extra; /* Données insérées à consulter*/
unsigned int range; /* Catégorie de la taille */
const char *prefix; /* Entrée en matière */
const char *suffix; /* Sortie de matière */
@@ -813,13 +1071,11 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis
static const char *conv_si_defs[] = { "", "o", "d", "x", "c" };
static const char *conv_us_defs[] = { "", "o", "u", "x", "c" };
- assert(display <= IOD_LAST_VALID);
+ assert(display < IOD_COUNT);
extra = GET_IMM_OP_EXTRA(operand);
- //LOCK_GOBJECT_EXTRA(extra);
-
- range = MDS_RANGE(extra->size);
+ range = MDS_RANGE(extra.size);
/* Encadrement pour les caractères */
if (display == IOD_CHAR)
@@ -862,10 +1118,10 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis
if (do_padding)
{
- if (extra->display != IOD_COUNT)
- do_padding = (extra->display != IOD_BIN && extra->display != IOD_HEX);
+ if (extra.display != IOD_COUNT)
+ do_padding = (extra.display == IOD_BIN || extra.display == IOD_HEX);
else
- do_padding = (extra->def_display != IOD_BIN && extra->def_display != IOD_HEX);
+ do_padding = (extra.def_display == IOD_BIN || extra.def_display == IOD_HEX);
}
switch (display)
@@ -892,7 +1148,7 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis
if (display != IOD_BIN)
{
- if (MDS_IS_SIGNED(extra->size))
+ if (MDS_IS_SIGNED(extra.size))
conv = conv_si_defs[display];
else
conv = conv_us_defs[display];
@@ -929,7 +1185,7 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis
snprintf(format, sizeof(format), "%s%s%s%s%s%s%s", prefix, alternate, intro, zpad, lmod, conv, suffix);
- switch (extra->size)
+ switch (extra.size)
{
case MDS_UNDEFINED:
result = snprintf(value, IMM_MAX_SIZE, "<? undef value ?>");
@@ -982,8 +1238,6 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis
}
- //UNLOCK_GOBJECT_EXTRA(extra);
-
assert(result > 0);
return result;
@@ -993,555 +1247,37 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis
/******************************************************************************
* *
-* Paramètres : operand = opérande à transcrire. *
-* syntax = type de représentation demandée. *
-* value = valeur portée par l'opérande transcrite. [OUT] *
+* Paramètres : builder = objet dont l'instance est exportable. *
+* flags = éventuelles indications pour l'opération. *
+* out = chaîne de caractères mise en place. [OUT] *
* *
-* Description : Construit la chaîne de caractères correspondant à l'opérande.*
+* Description : Exporte une chaîne de caractères à partir d'un objet. *
* *
-* Retour : Nombre de caractères utilisés. *
+* Retour : Bilan de l'opération. *
* *
-* Remarques : - *
+* Remarques : La sortie out est à nettoyer avec exit_sized_binary() après *
+* usage. *
* *
******************************************************************************/
-size_t g_imm_operand_to_string(const GImmOperand *operand, char value[IMM_MAX_SIZE])
+static bool g_immediate_operand_to_string(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)
{
- size_t result; /* Longueur à retourner */
+ bool result; /* Bilan à retourner */
+ const GImmediateOperand *operand; /* Version spécialisée */
ImmOperandDisplay display; /* Type d'affichage courant */
-
- display = g_imm_operand_get_display(operand);
-
- result = _g_imm_operand_to_string(operand, display, value);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à traiter. *
-* line = ligne tampon où imprimer l'opérande donné. *
-* *
-* Description : Traduit un opérande en version humainement lisible. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_imm_operand_print(const GImmOperand *operand, GBufferLine *line)
-{
char value[IMM_MAX_SIZE]; /* Chaîne à imprimer */
size_t len; /* Taille de l'élément inséré */
- len = g_imm_operand_to_string(operand, value);
-
- g_buffer_line_append_text(line, DLC_ASSEMBLY, value, len, RTT_IMMEDIATE, G_OBJECT(operand));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à traiter. *
-* pos = valeur résultante. [OUT] *
-* *
-* Description : Convertit une valeur immédiate en position de type phys_t. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_imm_operand_to_phys_t(const GImmOperand *operand, phys_t *pos)
-{
- bool result; /* Bilan à renvoyer */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
-
- extra = GET_IMM_OP_EXTRA(operand);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = !MDS_IS_SIGNED(extra->size);
-
- if (result)
- *pos = operand->raw;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à traiter. *
-* addr = valeur résultante. [OUT] *
-* *
-* Description : Convertit une valeur immédiate en adresse de type virt_t. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_imm_operand_to_virt_t(const GImmOperand *operand, virt_t *addr)
-{
- bool result; /* Bilan à renvoyer */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
-
- extra = GET_IMM_OP_EXTRA(operand);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = !MDS_IS_SIGNED(extra->size);
-
- if (result)
- *addr = operand->raw;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à traiter. *
-* val = valeur résultante. [OUT] *
-* *
-* Description : Convertit une valeur immédiate en valeur de type leb128_t. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_imm_operand_as_leb128(const GImmOperand *operand, leb128_t *val)
-{
- immop_extra_data_t *extra; /* Données insérées à consulter*/
-
- extra = GET_IMM_OP_EXTRA(operand);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- *val = operand->raw;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à traiter. *
-* val = valeur résultante. [OUT] *
-* *
-* Description : Convertit une valeur immédiate en valeur de type uleb128_t. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_imm_operand_as_uleb128(const GImmOperand *operand, uleb128_t *val)
-{
- immop_extra_data_t *extra; /* Données insérées à consulter*/
-
- extra = GET_IMM_OP_EXTRA(operand);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- *val = operand->raw;
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : a = premier opérande à consulter. *
-* b = second opérande à consulter. *
-* lock = précise le besoin en verrouillage. *
-* *
-* Description : Compare un opérande avec un autre. *
-* *
-* Retour : Bilan de la comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int g_imm_operand_compare(const GImmOperand *a, const GImmOperand *b, bool lock)
-{
- int result; /* Bilan à retourner */
- immop_extra_data_t *ea; /* Données insérées à modifier */
- immop_extra_data_t *eb; /* Données insérées à modifier */
- GArchOperandClass *class; /* Classe parente normalisée */
-
- ea = GET_IMM_OP_EXTRA(a);
- eb = GET_IMM_OP_EXTRA(b);
-
- if (lock)
- {
- LOCK_GOBJECT_EXTRA(ea);
- LOCK_GOBJECT_EXTRA(eb);
- }
-
- result = sort_unsigned_long(ea->size, eb->size);
-
- if (result == 0)
- sort_uint64_t(a->raw, b->raw);
-
- if (result == 0)
- result = sort_unsigned_long(ea->def_display, eb->def_display);
-
- if (result == 0)
- result = sort_unsigned_long(ea->display, eb->display);
-
- if (result == 0)
- {
- class = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class);
- result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false);
- }
-
- if (lock)
- {
- UNLOCK_GOBJECT_EXTRA(eb);
- UNLOCK_GOBJECT_EXTRA(ea);
- }
-
- return result;
-
-}
-
-
-#ifdef INCLUDE_GTK_SUPPORT
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = opérande à consulter. *
-* binary = informations relatives au binaire chargé. *
-* *
-* Description : Construit un petit résumé concis de l'opérande. *
-* *
-* Retour : Chaîne de caractères à libérer après usage ou NULL. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *g_imm_operand_build_tooltip(const GImmOperand *operand, const GLoadedBinary *binary)
-{
- char *result; /* Description à retourner */
- char value[IMM_MAX_SIZE]; /* Conversion artificielle */
- char *conv; /* Affichage de la Conversion */
-
- if (operand->raw <= UCHAR_MAX && isprint(operand->raw))
- switch (operand->raw)
- {
- case '&':
- asprintf(&result, _("Character: '&amp;'"));
- break;
- case '<':
- asprintf(&result, _("Character: '&lt;'"));
- break;
- case '>':
- asprintf(&result, _("Character: '&gt;'"));
- break;
- default:
- asprintf(&result, _("Character: '%c'"), (char)operand->raw);
- break;
- }
-
- else
- asprintf(&result, _("Character: &lt;not printable&gt;"));
-
- /* Binaire */
-
- _g_imm_operand_to_string(operand, IOD_BIN, value);
-
- asprintf(&conv, _("Binary: %s"), value);
-
- result = stradd(result, "\n");
- result = stradd(result, conv);
-
- free(conv);
-
- /* Octal */
-
- _g_imm_operand_to_string(operand, IOD_OCT, value);
-
- asprintf(&conv, _("Octal: %s"), value);
-
- result = stradd(result, "\n");
- result = stradd(result, conv);
-
- free(conv);
-
- /* Décimal */
-
- _g_imm_operand_to_string(operand, IOD_DEC, value);
-
- asprintf(&conv, _("Decimal: %s"), value);
-
- result = stradd(result, "\n");
- result = stradd(result, conv);
-
- free(conv);
-
- /* Hexadécimal */
-
- _g_imm_operand_to_string(operand, IOD_HEX, value);
-
- asprintf(&conv, _("Hexadecimal: %s"), value);
-
- result = stradd(result, "\n");
- result = stradd(result, conv);
-
- free(conv);
-
- return result;
-
-}
-
-
-#endif
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* lock = précise le besoin en verrouillage. *
-* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
-* *
-* Retour : Empreinte de l'élément représenté. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static guint g_imm_operand_hash(const GImmOperand *operand, bool lock)
-{
- guint result; /* Valeur à retourner */
- immop_extra_data_t *extra; /* Données insérées à modifier */
- GArchOperandClass *class; /* Classe parente normalisée */
-
- extra = GET_IMM_OP_EXTRA(operand);
-
- if (lock)
- LOCK_GOBJECT_EXTRA(extra);
-
- class = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class);
- result = class->hash(G_ARCH_OPERAND(operand), false);
-
- result ^= (operand->raw & 0xffffffff);
- result ^= (operand->raw >> 32);
-
- if (lock)
- UNLOCK_GOBJECT_EXTRA(extra);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = é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_imm_operand_load(GImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- GArchOperandClass *parent; /* Classe parente à consulter */
- immop_extra_data_t *extra; /* Données insérées à modifier */
- uleb128_t value; /* Valeur ULEB128 à charger */
- uint8_t val; /* Champ de bits manipulé */
-
- parent = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class);
-
- result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
-
- if (result)
- {
- extra = GET_IMM_OP_EXTRA(operand);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = unpack_uleb128(&value, pbuf);
-
- if (result)
- extra->size = value;
-
- if (result)
- {
- result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false);
-
- if (result)
- extra->def_display = val;
-
- }
-
- if (result)
- {
- result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false);
-
- if (result)
- extra->display = val;
-
- }
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- }
-
- if (result)
- result = extract_packed_buffer(pbuf, &operand->raw, sizeof(uint64_t), true);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = é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_imm_operand_store(GImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- GArchOperandClass *parent; /* Classe parente à consulter */
- immop_extra_data_t *extra; /* Données insérées à modifier */
+ operand = G_IMMEDIATE_OPERAND(builder);
- parent = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class);
+ display = g_immediate_operand_get_display(operand);
- result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
+ len = _g_immediate_operand_to_string(operand, display, value);
- if (result)
- {
- extra = GET_IMM_OP_EXTRA(operand);
-
- LOCK_GOBJECT_EXTRA(extra);
-
- result = pack_uleb128((uleb128_t []){ extra->size }, pbuf);
-
- if (result)
- result = extend_packed_buffer(pbuf, (uint8_t []) { extra->def_display }, sizeof(uint8_t), false);
-
- if (result)
- result = extend_packed_buffer(pbuf, (uint8_t []) { extra->display }, sizeof(uint8_t), false);
-
- UNLOCK_GOBJECT_EXTRA(extra);
-
- }
+ result = (len > 0);
if (result)
- result = extend_packed_buffer(pbuf, &operand->raw, sizeof(uint64_t), true);
-
- return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* COMMUNICATION D'UN CIBLAGE POTENTIEL */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = operande à consulter. *
-* src = localisation de l'instruction mère. *
-* format = format reconnu pour le binaire chargé. *
-* proc = architecture associée à ce même binaire. *
-* addr = localisation de la cible. [OUT] *
-* *
-* Description : Obtient l'adresse de la cible visée par un opérande. *
-* *
-* Retour : true si la cible est valide, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool g_imm_operand_get_addr(const GImmOperand *operand, const vmpa2t *src, GBinFormat *format, GArchProcessor *proc, vmpa2t *addr)
-{
- bool result; /* Bilan à retourner */
- virt_t virt; /* Adresse virtuelle */
-
- result = g_imm_operand_to_virt_t(operand, &virt);
-
- if (result)
- result = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, addr);
-
- return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* CONSTRUCTION D'UN CONTENU ALTERNATIF */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : operand = operande à consulter. *
-* text = texte alternatif de représentation. *
-* *
-* Description : Construit un opérande de représentation alternative. *
-* *
-* Retour : Nouvel opérande, en version renommée. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GRenamedOperand *g_imm_operand_build(const GImmOperand *operand, const char *text)
-{
- GRenamedOperand *result; /* Instance à retourner */
-
- result = G_RENAMED_OPERAND(g_known_imm_operand_new(operand, text));
+ add_to_sized_binary(out, value, len);
return result;
diff --git a/src/arch/operands/immediate.h b/src/arch/operands/immediate.h
index 7c1ff03..d66349a 100644
--- a/src/arch/operands/immediate.h
+++ b/src/arch/operands/immediate.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* immediate.h - prototypes pour les opérandes représentant des valeurs numériques
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2024 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,17 +25,22 @@
#define _ARCH_OPERANDS_IMMEDIATE_H
-#include <glib-object.h>
#include <stdbool.h>
#include <stdint.h>
-#include "../archbase.h"
#include "../operand.h"
#include "../../analysis/content.h"
+#include "../../common/datatypes.h"
+#include "../../glibext/helpers.h"
+#define G_TYPE_IMMEDIATE_OPERAND (g_immediate_operand_get_type())
+
+DECLARE_GTYPE(GImmediateOperand, g_immediate_operand, G, IMMEDIATE_OPERAND);
+
+
/* Etats particuliers d'un opérande de valeur immédiate */
typedef enum _ImmOpFlag
{
@@ -57,86 +62,39 @@ typedef enum _ImmOperandDisplay
} ImmOperandDisplay;
-#define IOD_LAST_VALID IOD_CHAR
-
-
-#define G_TYPE_IMM_OPERAND g_imm_operand_get_type()
-#define G_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_IMM_OPERAND, GImmOperand))
-#define G_IS_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_IMM_OPERAND))
-#define G_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_IMM_OPERAND, GImmOperandClass))
-#define G_IS_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_IMM_OPERAND))
-#define G_IMM_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_IMM_OPERAND, GImmOperandClass))
-
-
-/* Définition d'un opérande de valeur numérique (instance) */
-typedef struct _GImmOperand GImmOperand;
-
-/* Définition d'un opérande de valeur numérique (classe) */
-typedef struct _GImmOperandClass GImmOperandClass;
-
-
-/* Indique le type défini pour un opérande d'architecture. */
-GType g_imm_operand_get_type(void);
/* Crée un opérande réprésentant une valeur numérique. */
-GArchOperand *_g_imm_operand_new_from_data(MemoryDataSize, const GBinContent *, vmpa2t *, bool *, SourceEndian);
-
-#define g_imm_operand_new_from_data(size, content, addr, endian) \
- _g_imm_operand_new_from_data(size, content, addr, NULL, endian)
+GArchOperand *g_immediate_operand_new_from_value(MemoryDataSize, uint64_t);
/* Crée un opérande réprésentant une valeur numérique. */
-GArchOperand *g_imm_operand_new_from_value(MemoryDataSize, uint64_t);
+GArchOperand *g_immediate_operand_new_from_data(MemoryDataSize, const GBinContent *, vmpa2t *, bool *, SourceEndian);
/* Renseigne la taille de la valeur indiquée à la construction. */
-MemoryDataSize g_imm_operand_get_size(const GImmOperand *);
+MemoryDataSize g_immediate_operand_get_size(const GImmediateOperand *);
/* Fournit la valeur portée par une opérande numérique. */
-bool g_imm_operand_get_value(const GImmOperand *, MemoryDataSize, ...);
+bool g_immediate_operand_get_value(const GImmediateOperand *, MemoryDataSize, ...);
+
+/* Définit la nouvelle valeur de l'opérande à une valeur. */
+void g_immediate_operand_set_value(GImmediateOperand *, MemoryDataSize, uint64_t);
/* Fournit la valeur brute représentée par l'opérande. */
-uint64_t g_imm_operand_get_raw_value(const GImmOperand *);
+uint64_t g_immediate_operand_get_raw_value(const GImmediateOperand *);
-/* Définit la nouvelle valeur de l'opérande à une valeur. */
-void g_imm_operand_set_value(GImmOperand *, MemoryDataSize, uint64_t);
+/* Indique le signe d'une valeur immédiate. */
+bool g_immediate_operand_is_negative(const GImmediateOperand *);
/* Définit le format textuel par défaut de la valeur. */
-void g_imm_operand_set_default_display(GImmOperand *, ImmOperandDisplay);
+void g_immediate_operand_set_default_display(GImmediateOperand *, ImmOperandDisplay);
/* Indique le format textuel par défaut de la valeur. */
-ImmOperandDisplay g_imm_operand_get_default_display(const GImmOperand *);
+ImmOperandDisplay g_immediate_operand_get_default_display(const GImmediateOperand *);
/* Définit la grande ligne du format textuel de la valeur. */
-void g_imm_operand_set_display(GImmOperand *, ImmOperandDisplay);
+void g_immediate_operand_set_display(GImmediateOperand *, ImmOperandDisplay);
/* Indique la grande ligne du format textuel de la valeur. */
-ImmOperandDisplay g_imm_operand_get_display(const GImmOperand *);
-
-/* Indique le signe d'une valeur immédiate. */
-bool g_imm_operand_is_negative(const GImmOperand *);
-
-/* Indique si une valeur immédiate est nulle ou non. */
-bool g_imm_operand_is_null(const GImmOperand *);
-
-/**
- * La taille d'impression d'un opérande n'est pas VMPA_MAX_SIZE,
- * mais 1 + 64 caractères + octet nul final en cas d'impression en binaire.
- */
-#define IMM_MAX_SIZE 66
-
-/* Construit la chaîne de caractères correspondant à l'opérande. */
-size_t g_imm_operand_to_string(const GImmOperand *, char [IMM_MAX_SIZE]);
-
-/* Convertit une valeur immédiate en position de type phys_t. */
-bool g_imm_operand_to_phys_t(const GImmOperand *, phys_t *);
-
-/* Convertit une valeur immédiate en adresse de type virt_t. */
-bool g_imm_operand_to_virt_t(const GImmOperand *, virt_t *);
-
-/* Convertit une valeur immédiate en valeur de type leb128_t. */
-void g_imm_operand_as_leb128(const GImmOperand *, leb128_t *);
-
-/* Convertit une valeur immédiate en valeur de type uleb128_t. */
-void g_imm_operand_as_uleb128(const GImmOperand *, uleb128_t *);
+ImmOperandDisplay g_immediate_operand_get_display(const GImmediateOperand *);
diff --git a/src/arch/operands/known-int.h b/src/arch/operands/known-int.h
new file mode 100644
index 0000000..021fbf2
--- /dev/null
+++ b/src/arch/operands/known-int.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * known-int.h - définitions internes pour les opérandes représentant des valeurs numériques avec sémantique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_OPERANDS_KNOWN_INT_H
+#define _ARCH_OPERANDS_KNOWN_INT_H
+
+
+#include "immediate-int.h"
+#include "known.h"
+
+
+
+/* Définition d'un remplacement d'opérande de valeur numérique (instance) */
+struct _GKnownImmediateOperand
+{
+ GImmediateOperand parent; /* Instance parente */
+
+ char *alt_text; /* Alternative humaine */
+
+};
+
+/* Définition d'un remplacement d'opérande de valeur numérique (classe) */
+struct _GKnownImmediateOperandClass
+{
+ GImmediateOperandClass parent; /* Classe parente */
+
+};
+
+
+/* Met en place un opérande remplaçant visuellement une valeur. */
+bool g_known_immediate_operand_create(GKnownImmediateOperand *, const GImmediateOperand *, const char *);
+
+
+
+#endif /* _ARCH_OPERANDS_KNOWN_INT_H */
diff --git a/src/arch/operands/known-ui.c b/src/arch/operands/known-ui.c
new file mode 100644
index 0000000..9b7507a
--- /dev/null
+++ b/src/arch/operands/known-ui.c
@@ -0,0 +1,79 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * known-ui.c - opérandes représentant des valeurs numériques avec sémantique sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "known-ui.h"
+
+
+#include "known-int.h"
+#include "../../common/cpp.h"
+#include "../../glibext/options/asm.h"
+
+
+
+/* Traduit un opérande en version humainement lisible. */
+static void g_known_immediate_operand_ui_print(const GArchOperandUI *, GBufferLine *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface d'opérande UI. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_known_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *iface)
+{
+ iface->print = g_known_immediate_operand_ui_print;
+ iface->build_tooltip = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande à traiter. *
+* line = ligne tampon où imprimer l'opérande donné. *
+* *
+* Description : Traduit un opérande en version humainement lisible. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_known_immediate_operand_ui_print(const GArchOperandUI *operand, GBufferLine *line)
+{
+ GKnownImmediateOperand *known; /* Version de base */
+
+ known = G_KNOWN_IMMEDIATE_OPERAND(operand);
+
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_IMMEDIATE, SL(known->alt_text), NULL, G_OBJECT(operand));
+
+}
diff --git a/src/arch/operands/known-ui.h b/src/arch/operands/known-ui.h
new file mode 100644
index 0000000..fa2dc62
--- /dev/null
+++ b/src/arch/operands/known-ui.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * known-ui.h - prototypes pour les opérandes représentant des valeurs numériques avec sémantique sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_OPERANDS_KNOWN_UI_H
+#define _ARCH_OPERANDS_KNOWN_UI_H
+
+
+#include "../operand-ui-int.h"
+
+
+
+/* Procède à l'initialisation de l'interface d'opérande UI. */
+void g_known_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *);
+
+
+
+#endif /* _ARCH_OPERANDS_KNOWN_UI_H */
diff --git a/src/arch/operands/known.c b/src/arch/operands/known.c
index 5402879..c9e177f 100644
--- a/src/arch/operands/known.c
+++ b/src/arch/operands/known.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* known.c - opérandes représentant des valeurs numériques avec sémantique
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -24,81 +24,80 @@
#include "known.h"
-#include <assert.h>
#include <malloc.h>
#include <string.h>
-#include "immediate-int.h"
-#include "rename-int.h"
-#include "../../analysis/db/misc/rlestr.h"
-#include "../../core/columns.h"
-#include "../../core/logs.h"
+#include "known-int.h"
+#include "../../common/cpp.h"
+#include "../../glibext/comparable-int.h"
+#include "../../glibext/hashable-int.h"
+#include "../../glibext/serialize-int.h"
+#include "../../glibext/strbuilder-int.h"
/* ----------------------- REMPLACEMENT DE VALEURS IMMEDIATES ----------------------- */
-/* Définition d'un remplacement d'opérande de valeur numérique (instance) */
-struct _GKnownImmOperand
-{
- GImmOperand parent; /* Instance parente */
+/* Initialise la classe des remplacements d'opérandes. */
+static void g_known_immediate_operand_class_init(GKnownImmediateOperandClass *);
- char *alt_text; /* Alternative humaine */
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_known_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *);
-};
+/* Procède à l'initialisation de l'interface de détermination. */
+static void g_known_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *);
-/* Définition d'un remplacement d'opérande de valeur numérique (classe) */
-struct _GKnownImmOperandClass
-{
- GImmOperandClass parent; /* Classe parente */
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_known_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *);
-};
-
-
-/* Initialise la classe des remplacements d'opérandes. */
-static void g_known_imm_operand_class_init(GKnownImmOperandClass *);
+/* Procède à l'initialisation de l'interface d'exportation. */
+static void g_known_immediate_operand_string_builder_iface_init(GStringBuilderInterface *);
/* Initialise un remplacement d'opérande de valeur immédiate. */
-static void g_known_imm_operand_init(GKnownImmOperand *);
-
-/* Procède à l'initialisation de l'interface de renommage. */
-static void g_known_imm_operand_renamed_interface_init(GRenamedOperandInterface *);
+static void g_known_immediate_operand_init(GKnownImmediateOperand *);
/* Supprime toutes les références externes. */
-static void g_known_imm_operand_dispose(GKnownImmOperand *);
+static void g_known_immediate_operand_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_known_imm_operand_finalize(GKnownImmOperand *);
+static void g_known_immediate_operand_finalize(GObject *);
+
+
+/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+/* Réalise une comparaison étendue entre objets. */
+static int g_known_immediate_operand_compare(const GComparableObject *, const GComparableObject *);
-/* Compare un opérande avec un autre. */
-static int g_known_imm_operand_compare(const GKnownImmOperand *, const GKnownImmOperand *, bool);
-/* Traduit un opérande en version humainement lisible. */
-static void g_known_imm_operand_print(const GKnownImmOperand *, GBufferLine *);
+/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-static guint g_known_imm_operand_hash(const GKnownImmOperand *, bool);
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_known_imm_operand_load(GKnownImmOperand *, GObjectStorage *, packed_buffer_t *);
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+static guint g_known_immediate_operand_hash(const GHashableObject *);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_known_imm_operand_store(GKnownImmOperand *, GObjectStorage *, packed_buffer_t *);
+/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */
-/* ------------------------- AFFICHAGE D'UN CONTENU RENOMME ------------------------- */
+/* Charge un objet depuis un flux de données. */
+static bool g_known_immediate_operand_load(GSerializableObject *, GObjectStorage *, int);
-/* Fournit un texte comme représentation alternative d'opérande. */
-static const char *g_known_imm_operand_get_text(const GKnownImmOperand *);
+/* Sauvegarde un objet dans un flux de données. */
+static bool g_known_immediate_operand_store(const GSerializableObject *, GObjectStorage *, int);
+
+
+
+/* ----------------- EXPORTATION SOUS FORME DE CHAINE DE CARACTERES ----------------- */
+
+
+/* Exporte une chaîne de caractères à partir d'un objet. */
+static bool g_known_immediate_operand_to_string(const GStringBuilder *, unsigned int, sized_binary_t *);
@@ -108,8 +107,12 @@ static const char *g_known_imm_operand_get_text(const GKnownImmOperand *);
/* Indique le type défini pour un remplacemet d'opérande de valeur numérique. */
-G_DEFINE_TYPE_WITH_CODE(GKnownImmOperand, g_known_imm_operand, G_TYPE_IMM_OPERAND,
- G_IMPLEMENT_INTERFACE(G_TYPE_RENAMED_OPERAND, g_known_imm_operand_renamed_interface_init));
+G_DEFINE_TYPE_WITH_CODE(GKnownImmediateOperand, g_known_immediate_operand, G_TYPE_IMMEDIATE_OPERAND,
+ G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_known_immediate_operand_comparable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_known_immediate_operand_hashable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_known_immediate_operand_serializable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_known_immediate_operand_string_builder_iface_init)
+ G_IMPLEMENT_INTERFACE_IF_SYM(g_arch_operand_ui_get_type, g_known_immediate_operand_ui_arch_operand_ui_iface_init));
/******************************************************************************
@@ -124,33 +127,42 @@ G_DEFINE_TYPE_WITH_CODE(GKnownImmOperand, g_known_imm_operand, G_TYPE_IMM_OPERAN
* *
******************************************************************************/
-static void g_known_imm_operand_class_init(GKnownImmOperandClass *klass)
+static void g_known_immediate_operand_class_init(GKnownImmediateOperandClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
- GArchOperandClass *operand; /* Version de classe parente */
object = G_OBJECT_CLASS(klass);
- operand = G_ARCH_OPERAND_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_known_imm_operand_dispose;
- object->finalize = (GObjectFinalizeFunc)g_known_imm_operand_finalize;
+ object->dispose = g_known_immediate_operand_dispose;
+ object->finalize = g_known_immediate_operand_finalize;
+
+}
- operand->compare = (operand_compare_fc)g_known_imm_operand_compare;
- operand->print = (operand_print_fc)g_known_imm_operand_print;
- operand->hash = (operand_hash_fc)g_known_imm_operand_hash;
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- operand->load = (load_operand_fc)g_known_imm_operand_load;
- operand->store = (store_operand_fc)g_known_imm_operand_store;
+static void g_known_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *iface)
+{
+ iface->compare = g_known_immediate_operand_compare;
}
/******************************************************************************
* *
-* Paramètres : operand = instance à initialiser. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Initialise un remplacement d'opérande de valeur immédiate. *
+* Description : Procède à l'initialisation de l'interface de détermination. *
* *
* Retour : - *
* *
@@ -158,9 +170,9 @@ static void g_known_imm_operand_class_init(GKnownImmOperandClass *klass)
* *
******************************************************************************/
-static void g_known_imm_operand_init(GKnownImmOperand *operand)
+static void g_known_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *iface)
{
- operand->alt_text = NULL;
+ iface->hash = g_known_immediate_operand_hash;
}
@@ -169,7 +181,7 @@ static void g_known_imm_operand_init(GKnownImmOperand *operand)
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de renommage. *
+* Description : Procède à l'initialisation de l'interface de sérialisation. *
* *
* Retour : - *
* *
@@ -177,18 +189,19 @@ static void g_known_imm_operand_init(GKnownImmOperand *operand)
* *
******************************************************************************/
-static void g_known_imm_operand_renamed_interface_init(GRenamedOperandInterface *iface)
+static void g_known_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *iface)
{
- iface->get_text = (get_renamed_text_fc)g_known_imm_operand_get_text;
+ iface->load = g_known_immediate_operand_load;
+ iface->store = g_known_immediate_operand_store;
}
/******************************************************************************
* *
-* Paramètres : operand = instance d'objet GLib à traiter. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Supprime toutes les références externes. *
+* Description : Procède à l'initialisation de l'interface d'exportation. *
* *
* Retour : - *
* *
@@ -196,12 +209,28 @@ static void g_known_imm_operand_renamed_interface_init(GRenamedOperandInterface
* *
******************************************************************************/
-static void g_known_imm_operand_dispose(GKnownImmOperand *operand)
+static void g_known_immediate_operand_string_builder_iface_init(GStringBuilderInterface *iface)
{
- if (operand->alt_text != NULL)
- free(operand->alt_text);
+ iface->to_string = g_known_immediate_operand_to_string;
- G_OBJECT_CLASS(g_known_imm_operand_parent_class)->dispose(G_OBJECT(operand));
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = instance à initialiser. *
+* *
+* Description : Initialise un remplacement d'opérande de valeur immédiate. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_known_immediate_operand_init(GKnownImmediateOperand *operand)
+{
+ operand->alt_text = NULL;
}
@@ -210,7 +239,7 @@ static void g_known_imm_operand_dispose(GKnownImmOperand *operand)
* *
* Paramètres : operand = instance d'objet GLib à traiter. *
* *
-* Description : Procède à la libération totale de la mémoire. *
+* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
@@ -218,180 +247,199 @@ static void g_known_imm_operand_dispose(GKnownImmOperand *operand)
* *
******************************************************************************/
-static void g_known_imm_operand_finalize(GKnownImmOperand *operand)
+static void g_known_immediate_operand_dispose(GObject *object)
{
- G_OBJECT_CLASS(g_known_imm_operand_parent_class)->finalize(G_OBJECT(operand));
+ G_OBJECT_CLASS(g_known_immediate_operand_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : old = opérande à venir copier avant son remplacement. *
-* alt = texte alternatif à présenter pour l'impression. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Crée un opérande remplaçant visuellement une valeur. *
+* Description : Procède à la libération totale de la mémoire. *
* *
-* Retour : Instruction mise en place. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GArchOperand *g_known_imm_operand_new(const GImmOperand *old, const char *alt)
+static void g_known_immediate_operand_finalize(GObject *object)
{
- GKnownImmOperand *result; /* Remplacement à retourner */
- immop_extra_data_t *src; /* Données insérées à consulter*/
- immop_extra_data_t *dest; /* Données insérées à modifier */
+ GKnownImmediateOperand *operand; /* Version spécialisée */
- result = g_object_new(G_TYPE_KNOWN_IMM_OPERAND, NULL);
+ operand = G_KNOWN_IMMEDIATE_OPERAND(object);
- result->parent.raw = old->raw;
+ if (operand->alt_text != NULL)
+ free(operand->alt_text);
- src = GET_IMM_OP_EXTRA(old);
- dest = GET_IMM_OP_EXTRA(&result->parent);
+ G_OBJECT_CLASS(g_known_immediate_operand_parent_class)->finalize(object);
- LOCK_GOBJECT_EXTRA(src);
+}
- *(&dest->parent) = *(&src->parent);
- dest->size = src->size;
+/******************************************************************************
+* *
+* Paramètres : old = opérande à venir copier avant son remplacement. *
+* alt = texte alternatif à présenter pour l'impression. *
+* *
+* Description : Crée un opérande remplaçant visuellement une valeur. *
+* *
+* Retour : Instruction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- dest->def_display = src->def_display;
- dest->display = src->display;
+GArchOperand *g_known_immediate_operand_new(const GImmediateOperand *old, const char *alt)
+{
+ GKnownImmediateOperand *result; /* Remplacement à retourner */
- UNLOCK_GOBJECT_EXTRA(src);
+ result = g_object_new(G_TYPE_KNOWN_IMMEDIATE_OPERAND, NULL);
- result->alt_text = strdup(alt);
+ if (!g_known_immediate_operand_create(result, old, alt))
+ g_clear_object(&result);
return G_ARCH_OPERAND(result);
}
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : a = premier opérande à consulter. *
-* b = second opérande à consulter. *
-* lock = précise le besoin en verrouillage. *
+* Paramètres : operand = instance à initialiser pleinement. *
+* old = opérande à venir copier avant son remplacement. *
+* alt = texte alternatif à présenter pour l'impression. *
* *
-* Description : Compare un opérande avec un autre. *
+* Description : Met en place un opérande remplaçant visuellement une valeur. *
* *
-* Retour : Bilan de la comparaison. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static int g_known_imm_operand_compare(const GKnownImmOperand *a, const GKnownImmOperand *b, bool lock)
+bool g_known_immediate_operand_create(GKnownImmediateOperand *operand, const GImmediateOperand *old, const char *alt)
{
- int result; /* Bilan à retourner */
- immop_extra_data_t *ea; /* Données insérées à consulter*/
- immop_extra_data_t *eb; /* Données insérées à consulter*/
- GArchOperandClass *class; /* Classe parente normalisée */
+ bool result; /* Bilan à retourner */
+ immop_extra_data_t extra; /* Données insérées à consulter*/
- ea = GET_IMM_OP_EXTRA(G_IMM_OPERAND(a));
- eb = GET_IMM_OP_EXTRA(G_IMM_OPERAND(b));
+ result = true;
- if (lock)
- {
- LOCK_GOBJECT_EXTRA(ea);
- LOCK_GOBJECT_EXTRA(eb);
- }
+ extra = GET_IMM_OP_EXTRA(old);
- result = strcmp(a->alt_text, b->alt_text);
+ SET_IMM_OP_EXTRA(operand, &extra);
- if (result == 0)
- {
- class = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class);
- result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false);
- }
+ G_IMMEDIATE_OPERAND(operand)->raw = G_IMMEDIATE_OPERAND(old)->raw;
- if (lock)
- {
- UNLOCK_GOBJECT_EXTRA(eb);
- UNLOCK_GOBJECT_EXTRA(ea);
- }
+ operand->alt_text = strdup(alt);
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* COMPARAISON DETAILLEE DE DEUX OBJETS */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = opérande à traiter. *
-* line = ligne tampon où imprimer l'opérande donné. *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
* *
-* Description : Traduit un opérande en version humainement lisible. *
+* Description : Réalise une comparaison étendue entre objets. *
* *
-* Retour : - *
+* Retour : Bilan de la comparaison. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_known_imm_operand_print(const GKnownImmOperand *operand, GBufferLine *line)
+static int g_known_immediate_operand_compare(const GComparableObject *object, const GComparableObject *other)
{
- size_t len; /* Taille de l'élément inséré */
+ int result; /* Bilan à retourner */
+ GComparableObjectInterface *iface; /* Interface utilisée */
+ GComparableObjectInterface *parent_iface; /* Interface parente */
+ GKnownImmediateOperand *operand_a; /* Version spécialisée #0 */
+ GKnownImmediateOperand *operand_b; /* Version spécialisée #1 */
+
+ iface = G_COMPARABLE_OBJECT_GET_IFACE(object);
- len = strlen(operand->alt_text);
+ parent_iface = g_type_interface_peek_parent(iface);
- g_buffer_line_append_text(line, DLC_ASSEMBLY, operand->alt_text, len, RTT_IMMEDIATE, G_OBJECT(operand));
+ result = parent_iface->compare(object, other);
+
+ if (result == 0)
+ {
+ operand_a = G_KNOWN_IMMEDIATE_OPERAND(object);
+ operand_b = G_KNOWN_IMMEDIATE_OPERAND(other);
+
+ result = strcmp(operand_a->alt_text, operand_b->alt_text);
+
+ }
+
+ return result;
}
+/* ---------------------------------------------------------------------------------- */
+/* CALCUL D'UNE EMPREINTE DE L'INSTANCE */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* lock = précise le besoin en verrouillage. *
+* Paramètres : object = objet dont l'instance est à consulter. *
* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
+* Description : Calcule l'empreinte sur 32 bits d'un objet. *
* *
-* Retour : Empreinte de l'élément représenté. *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
* *
* Remarques : - *
* *
******************************************************************************/
-static guint g_known_imm_operand_hash(const GKnownImmOperand *operand, bool lock)
+static guint g_known_immediate_operand_hash(const GHashableObject *object)
{
guint result; /* Valeur à retourner */
- immop_extra_data_t *extra; /* Données insérées à consulter*/
- GArchOperandClass *class; /* Classe parente normalisée */
+ GHashableObjectInterface *iface; /* Interface utilisée */
+ GHashableObjectInterface *parent_iface; /* Interface parente */
+ GKnownImmediateOperand *operand; /* Version spécialisée */
- extra = GET_IMM_OP_EXTRA(G_IMM_OPERAND(operand));
+ iface = G_HASHABLE_OBJECT_GET_IFACE(object);
- if (lock)
- LOCK_GOBJECT_EXTRA(extra);
+ parent_iface = g_type_interface_peek_parent(iface);
- class = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class);
- result = class->hash(G_ARCH_OPERAND(operand), false);
+ result = parent_iface->hash(object);
- result ^= g_str_hash(operand->alt_text);
+ operand = G_KNOWN_IMMEDIATE_OPERAND(object);
- if (lock)
- UNLOCK_GOBJECT_EXTRA(extra);
+ result ^= g_str_hash(operand->alt_text);
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* MECANISMES DE CONSERVATION ET RESTAURATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à constuire. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à lire. *
+* Paramètres : object = élément GLib à constuire. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en lecture. *
* *
-* Description : Charge un contenu depuis une mémoire tampon. *
+* Description : Charge un objet depuis un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -399,30 +447,31 @@ static guint g_known_imm_operand_hash(const GKnownImmOperand *operand, bool lock
* *
******************************************************************************/
-static bool g_known_imm_operand_load(GKnownImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_known_immediate_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
- GArchOperandClass *parent; /* Classe parente à consulter */
- rle_string str; /* Chaîne à charger */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *parent_iface; /* Interface parente */
+ sized_binary_t str; /* Texte alternatif rechargé */
+ GKnownImmediateOperand *operand; /* Version spécialisée */
+
+ iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
- parent = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class);
+ parent_iface = g_type_interface_peek_parent(iface);
- result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
+ result = parent_iface->load(object, storage, fd);
if (result)
{
- setup_empty_rle_string(&str);
+ init_sized_binary(&str);
- result = unpack_rle_string(&str, pbuf);
+ load_sized_binary_as_string(&str, fd);
- if (result)
- {
- if (get_rle_string(&str) != NULL)
- operand->alt_text = strdup(get_rle_string(&str));
+ operand = G_KNOWN_IMMEDIATE_OPERAND(object);
- exit_rle_string(&str);
+ operand->alt_text = strdup(str.static_data);
- }
+ exit_sized_binary(&str);
}
@@ -433,11 +482,11 @@ static bool g_known_imm_operand_load(GKnownImmOperand *operand, GObjectStorage *
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : object = élément GLib à consulter. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Sauvegarde un contenu dans une mémoire tampon. *
+* Description : Sauvegarde un objet dans un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -445,54 +494,64 @@ static bool g_known_imm_operand_load(GKnownImmOperand *operand, GObjectStorage *
* *
******************************************************************************/
-static bool g_known_imm_operand_store(GKnownImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_known_immediate_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
- GArchOperandClass *parent; /* Classe parente à consulter */
- rle_string str; /* Chaîne à conserver */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *parent_iface; /* Interface parente */
+ GKnownImmediateOperand *operand; /* Version spécialisée */
+ sized_binary_t str; /* Texte alternatif à conserver*/
- parent = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class);
+ iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
- result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
+ parent_iface = g_type_interface_peek_parent(iface);
- if (result)
- {
- init_static_rle_string(&str, operand->alt_text);
+ result = parent_iface->store(object, storage, fd);
+ if (!result) goto exit;
- result = pack_rle_string(&str, pbuf);
+ operand = G_KNOWN_IMMEDIATE_OPERAND(object);
- exit_rle_string(&str);
+ setup_sized_binary_from_static_string(&str, operand->alt_text);
- }
+ result = store_sized_binary_as_string(&str, fd);
+
+ exit:
return result;
}
-
/* ---------------------------------------------------------------------------------- */
-/* AFFICHAGE D'UN CONTENU RENOMME */
+/* EXPORTATION SOUS FORME DE CHAINE DE CARACTERES */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : operand = operande à consulter. *
+* Paramètres : builder = objet dont l'instance est exportable. *
+* flags = éventuelles indications pour l'opération. *
+* out = chaîne de caractères mise en place. [OUT] *
* *
-* Description : Fournit un texte comme représentation alternative d'opérande.*
+* Description : Exporte une chaîne de caractères à partir d'un objet. *
* *
-* Retour : Chaîne de caractère de représentation alternative. *
+* Retour : Bilan de l'opération. *
* *
-* Remarques : - *
+* Remarques : La sortie out est à nettoyer avec exit_sized_binary() après *
+* usage. *
* *
******************************************************************************/
-static const char *g_known_imm_operand_get_text(const GKnownImmOperand *operand)
+static bool g_known_immediate_operand_to_string(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)
{
- const char *result; /* Texte à retourner */
+ bool result; /* Bilan à retourner */
+ const GKnownImmediateOperand *operand; /* Version spécialisée */
+
+ result = true;
+
+ operand = G_KNOWN_IMMEDIATE_OPERAND(builder);
- result = operand->alt_text;
+ add_to_sized_binary(out, operand->alt_text, strlen(operand->alt_text));
return result;
diff --git a/src/arch/operands/known.h b/src/arch/operands/known.h
index eb84d3b..a8b563f 100644
--- a/src/arch/operands/known.h
+++ b/src/arch/operands/known.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* known.h - prototypes pour les opérandes représentant des valeurs numériques avec sémantique
*
- * Copyright (C) 2021 Cyrille Bagard
+ * Copyright (C) 2021-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,34 +25,18 @@
#define _ARCH_OPERANDS_KNOWN_H
-#include <glib-object.h>
-
-
#include "immediate.h"
-#include "../operand.h"
-
-
-
-#define G_TYPE_KNOWN_IMM_OPERAND g_known_imm_operand_get_type()
-#define G_KNOWN_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KNOWN_IMM_OPERAND, GKnownImmOperand))
-#define G_IS_KNOWN_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KNOWN_IMM_OPERAND))
-#define G_KNOWN_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KNOWN_IMM_OPERAND, GKnownImmOperandClass))
-#define G_IS_KNOWN_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KNOWN_IMM_OPERAND))
-#define G_KNOWN_IMM_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KNOWN_IMM_OPERAND, GKnownImmOperandClass))
+#include "../../glibext/helpers.h"
-/* Définition d'un remplacement d'opérande de valeur numérique (instance) */
-typedef struct _GKnownImmOperand GKnownImmOperand;
-/* Définition d'un remplacement d'opérande de valeur numérique (classe) */
-typedef struct _GKnownImmOperandClass GKnownImmOperandClass;
+#define G_TYPE_KNOWN_IMMEDIATE_OPERAND (g_known_immediate_operand_get_type())
+DECLARE_GTYPE(GKnownImmediateOperand, g_known_immediate_operand, G, KNOWN_IMMEDIATE_OPERAND);
-/* Indique le type défini pour un remplacemet d'opérande de valeur numérique. */
-GType g_known_imm_operand_get_type(void);
/* Crée un opérande remplaçant visuellement une valeur. */
-GArchOperand *g_known_imm_operand_new(const GImmOperand *, const char *);
+GArchOperand *g_known_immediate_operand_new(const GImmediateOperand *, const char *);
diff --git a/src/arch/operands/register-int.h b/src/arch/operands/register-int.h
index a887567..93cf025 100644
--- a/src/arch/operands/register-int.h
+++ b/src/arch/operands/register-int.h
@@ -26,8 +26,6 @@
#include "register.h"
-
-
#include "../operand-int.h"
@@ -49,5 +47,9 @@ struct _GRegisterOperandClass
};
+/* Met en place un opérande réprésentant une valeur numérique. */
+bool g_register_operand_create(GRegisterOperand *, GArchRegister *);
+
+
#endif /* _ARCH_OPERANDS_REGISTER_INT_H */
diff --git a/src/arch/operands/register-ui.c b/src/arch/operands/register-ui.c
new file mode 100644
index 0000000..513a24f
--- /dev/null
+++ b/src/arch/operands/register-ui.c
@@ -0,0 +1,93 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * register-ui.c - opérandes représentant des registres sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "register-ui.h"
+
+
+#include "register.h"
+#include "../../glibext/strbuilder.h"
+#include "../../glibext/options/asm.h"
+
+
+
+/* Traduit un opérande en version humainement lisible. */
+static void g_register_operand_ui_print(const GArchOperandUI *, GBufferLine *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface d'opérande UI. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_register_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *iface)
+{
+ iface->print = g_register_operand_ui_print;
+ iface->build_tooltip = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande à traiter. *
+* line = ligne tampon où imprimer l'opérande donné. *
+* *
+* Description : Traduit un opérande en version humainement lisible. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_register_operand_ui_print(const GArchOperandUI *operand, GBufferLine *line)
+{
+ GStringBuilder *builder; /* Autre version de l'opérande */
+ sized_binary_t str; /* Chaîne équivalente produite */
+ bool status; /* Bilan d'une conversion */
+
+ builder = G_STRING_BUILDER(operand);
+
+ init_sized_binary(&str);
+
+ status = g_string_builder_to_string(builder, 0 /* flags */, &str);
+
+ if (status)
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_REGISTER,
+ str.static_data, str.size, NULL, G_OBJECT(operand));
+
+ else
+ g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_REGISTER,
+ "??", 2, NULL, G_OBJECT(operand));
+
+ exit_sized_binary(&str);
+
+}
diff --git a/src/arch/operands/register-ui.h b/src/arch/operands/register-ui.h
new file mode 100644
index 0000000..16be67b
--- /dev/null
+++ b/src/arch/operands/register-ui.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * register-ui.h - prototypes pour les opérandes représentant des registres sous forme graphique
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _ARCH_OPERANDS_REGISTER_UI_H
+#define _ARCH_OPERANDS_REGISTER_UI_H
+
+
+#include "../operand-ui-int.h" // FIXME ??
+
+
+
+/* Procède à l'initialisation de l'interface d'opérande UI. */
+void g_register_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *);
+
+
+
+#endif /* _ARCH_OPERANDS_REGISTER_UI_H */
diff --git a/src/arch/operands/register.c b/src/arch/operands/register.c
index 4615a99..cad2c4e 100644
--- a/src/arch/operands/register.c
+++ b/src/arch/operands/register.c
@@ -28,7 +28,10 @@
#include "register-int.h"
-#include "../storage.h"
+#include "../../glibext/comparable-int.h"
+#include "../../glibext/hashable-int.h"
+#include "../../glibext/serialize-int.h"
+#include "../../glibext/strbuilder-int.h"
@@ -38,34 +41,61 @@
/* Initialise la classe des opérandes de registre. */
static void g_register_operand_class_init(GRegisterOperandClass *);
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_register_operand_comparable_object_iface_init(GComparableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface de détermination. */
+static void g_register_operand_hashable_object_iface_init(GHashableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_register_operand_serializable_object_iface_init(GSerializableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface d'exportation. */
+static void g_register_operand_string_builder_iface_init(GStringBuilderInterface *);
+
/* Initialise une instance d'opérande de registre. */
static void g_register_operand_init(GRegisterOperand *);
/* Supprime toutes les références externes. */
-static void g_register_operand_dispose(GRegisterOperand *);
+static void g_register_operand_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_register_operand_finalize(GRegisterOperand *);
+static void g_register_operand_finalize(GObject *);
+
+
+
+/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */
+
+
+/* Réalise une comparaison étendue entre objets. */
+static int g_register_operand_compare(const GComparableObject *, const GComparableObject *);
+
+/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+static guint g_register_operand_hash(const GHashableObject *);
-/* Compare un opérande avec un autre. */
-static int g_register_operand_compare(const GRegisterOperand *, const GRegisterOperand *, bool);
-/* Traduit un opérande en version humainement lisible. */
-static void g_register_operand_print(const GRegisterOperand *, GBufferLine *);
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-static guint g_register_operand_hash(const GRegisterOperand *, bool);
+/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_register_operand_load(GRegisterOperand *, GObjectStorage *, packed_buffer_t *);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_register_operand_store(GRegisterOperand *, GObjectStorage *, packed_buffer_t *);
+/* Charge un objet depuis un flux de données. */
+static bool g_register_operand_load(GSerializableObject *, GObjectStorage *, int);
+
+/* Sauvegarde un objet dans un flux de données. */
+static bool g_register_operand_store(const GSerializableObject *, GObjectStorage *, int);
+
+
+
+/* ----------------- EXPORTATION SOUS FORME DE CHAINE DE CARACTERES ----------------- */
+
+
+/* Exporte une chaîne de caractères à partir d'un objet. */
+static bool g_register_operand_to_string(const GStringBuilder *, unsigned int, sized_binary_t *);
@@ -75,7 +105,12 @@ static bool g_register_operand_store(GRegisterOperand *, GObjectStorage *, packe
/* Indique le type défini par la GLib pour un opérande de registre Dalvik. */
-G_DEFINE_TYPE(GRegisterOperand, g_register_operand, G_TYPE_ARCH_OPERAND);
+G_DEFINE_TYPE_WITH_CODE(GRegisterOperand, g_register_operand, G_TYPE_ARCH_OPERAND,
+ G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_register_operand_comparable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_register_operand_hashable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_register_operand_serializable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_register_operand_string_builder_iface_init)
+ G_IMPLEMENT_INTERFACE_IF_SYM(g_arch_operand_ui_get_type, g_register_operand_ui_arch_operand_ui_iface_init));
/******************************************************************************
@@ -93,23 +128,88 @@ G_DEFINE_TYPE(GRegisterOperand, g_register_operand, G_TYPE_ARCH_OPERAND);
static void g_register_operand_class_init(GRegisterOperandClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
- GArchOperandClass *operand; /* Version de classe parente */
object = G_OBJECT_CLASS(klass);
- operand = G_ARCH_OPERAND_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_register_operand_dispose;
- object->finalize = (GObjectFinalizeFunc)g_register_operand_finalize;
+ object->dispose = g_register_operand_dispose;
+ object->finalize = g_register_operand_finalize;
- operand = G_ARCH_OPERAND_CLASS(klass);
+}
- operand->compare = (operand_compare_fc)g_register_operand_compare;
- operand->print = (operand_print_fc)g_register_operand_print;
- operand->hash = (operand_hash_fc)g_register_operand_hash;
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- operand->load = (load_operand_fc)g_register_operand_load;
- operand->store = (store_operand_fc)g_register_operand_store;
+static void g_register_operand_comparable_object_iface_init(GComparableObjectInterface *iface)
+{
+ iface->compare = g_register_operand_compare;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de détermination. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_register_operand_hashable_object_iface_init(GHashableObjectInterface *iface)
+{
+ iface->hash = g_register_operand_hash;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de sérialisation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_register_operand_serializable_object_iface_init(GSerializableObjectInterface *iface)
+{
+ iface->load = g_register_operand_load;
+ iface->store = g_register_operand_store;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface d'exportation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_register_operand_string_builder_iface_init(GStringBuilderInterface *iface)
+{
+ iface->to_string = g_register_operand_to_string;
}
@@ -135,7 +235,7 @@ static void g_register_operand_init(GRegisterOperand *operand)
/******************************************************************************
* *
-* Paramètres : binary = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -145,18 +245,22 @@ static void g_register_operand_init(GRegisterOperand *operand)
* *
******************************************************************************/
-static void g_register_operand_dispose(GRegisterOperand *operand)
+static void g_register_operand_dispose(GObject *object)
{
+ GRegisterOperand *operand; /* Version spécialisée */
+
+ operand = G_REGISTER_OPERAND(object);
+
g_clear_object(&operand->reg);
- G_OBJECT_CLASS(g_register_operand_parent_class)->dispose(G_OBJECT(operand));
+ G_OBJECT_CLASS(g_register_operand_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : binary = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -166,9 +270,36 @@ static void g_register_operand_dispose(GRegisterOperand *operand)
* *
******************************************************************************/
-static void g_register_operand_finalize(GRegisterOperand *operand)
+static void g_register_operand_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(g_register_operand_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = instance à initialiser pleinement. *
+* reg = registre matériel à représenter. *
+* *
+* Description : Met en place un opérande réprésentant une valeur numérique. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_register_operand_create(GRegisterOperand *operand, GArchRegister *reg)
{
- G_OBJECT_CLASS(g_register_operand_parent_class)->finalize(G_OBJECT(operand));
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ operand->reg = reg;
+ ref_object(reg);
+
+ return result;
}
@@ -190,8 +321,7 @@ GArchRegister *g_register_operand_get_register(const GRegisterOperand *operand)
GArchRegister *result; /* Instance à retourner */
result = operand->reg;
-
- g_object_ref(G_OBJECT(result));
+ ref_object(result);
return result;
@@ -200,17 +330,16 @@ GArchRegister *g_register_operand_get_register(const GRegisterOperand *operand)
/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* COMPARAISON DETAILLEE DE DEUX OBJETS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : a = premier opérande à consulter. *
-* b = second opérande à consulter. *
-* lock = précise le besoin en verrouillage. *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
* *
-* Description : Compare un opérande avec un autre. *
+* Description : Réalise une comparaison étendue entre objets. *
* *
* Retour : Bilan de la comparaison. *
* *
@@ -218,17 +347,25 @@ GArchRegister *g_register_operand_get_register(const GRegisterOperand *operand)
* *
******************************************************************************/
-static int g_register_operand_compare(const GRegisterOperand *a, const GRegisterOperand *b, bool lock)
+static int g_register_operand_compare(const GComparableObject *object, const GComparableObject *other)
{
int result; /* Bilan à retourner */
- GArchOperandClass *class; /* Classe parente normalisée */
+ GComparableObjectInterface *iface; /* Interface utilisée */
+ GComparableObjectInterface *parent_iface; /* Interface parente */
+ GRegisterOperand *operand; /* Version spécialisée */
+
+ iface = G_COMPARABLE_OBJECT_GET_IFACE(object);
- result = g_arch_register_compare(a->reg, b->reg);
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ result = parent_iface->compare(object, other);
if (result == 0)
{
- class = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class);
- result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false);
+ operand = G_REGISTER_OPERAND(object);
+
+ result = g_comparable_object_compare(G_COMPARABLE_OBJECT(operand->reg), other);
+
}
return result;
@@ -236,53 +373,96 @@ static int g_register_operand_compare(const GRegisterOperand *a, const GRegister
}
+
+/* ---------------------------------------------------------------------------------- */
+/* CALCUL D'UNE EMPREINTE DE L'INSTANCE */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = opérande à traiter. *
-* line = ligne tampon où imprimer l'opérande donné. *
+* Paramètres : object = objet dont l'instance est à consulter. *
* *
-* Description : Traduit un opérande en version humainement lisible. *
+* Description : Calcule l'empreinte sur 32 bits d'un objet. *
* *
-* Retour : - *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_register_operand_print(const GRegisterOperand *operand, GBufferLine *line)
+static guint g_register_operand_hash(const GHashableObject *object)
{
- g_arch_register_print(operand->reg, line);
+ guint result; /* Valeur à retourner */
+ GHashableObjectInterface *iface; /* Interface utilisée */
+ GHashableObjectInterface *parent_iface; /* Interface parente */
+ GRegisterOperand *operand; /* Version spécialisée */
+
+ iface = G_HASHABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ result = parent_iface->hash(object);
+
+ operand = G_REGISTER_OPERAND(object);
+
+ result ^= g_hashable_object_hash(G_HASHABLE_OBJECT(operand->reg));
+
+ return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* MECANISMES DE CONSERVATION ET RESTAURATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = objet dont l'instance se veut unique. *
-* lock = précise le besoin en verrouillage. *
+* Paramètres : object = élément GLib à constuire. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en lecture. *
* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
+* Description : Charge un objet depuis un flux de données. *
* *
-* Retour : Empreinte de l'élément représenté. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static guint g_register_operand_hash(const GRegisterOperand *operand, bool lock)
+static bool g_register_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)
{
- guint result; /* Valeur à retourner */
- GArchOperandClass *class; /* Classe parente normalisée */
- GArchRegister *reg; /* Registre visé par l'opérande*/
+ bool result; /* Bilan à retourner */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *parent_iface; /* Interface parente */
+ GSerializableObject *reg; /* Registre récupéré */
+ GRegisterOperand *operand; /* Version spécialisée */
+
+ iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ result = parent_iface->load(object, storage, fd);
+
+ if (result)
+ {
+ reg = g_object_storage_unpack_object(storage, fd, "registers");
- class = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class);
- result = class->hash(G_ARCH_OPERAND(operand), false);
+ if (reg == NULL)
+ result = false;
- reg = g_register_operand_get_register(operand);
+ else
+ {
+ operand = G_REGISTER_OPERAND(object);
- result ^= g_arch_register_hash(reg);
+ operand->reg = G_ARCH_REGISTER(reg);
+
+ }
- g_object_unref(G_OBJECT(reg));
+ }
return result;
@@ -291,11 +471,11 @@ static guint g_register_operand_hash(const GRegisterOperand *operand, bool lock)
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à constuire. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à lire. *
+* Paramètres : object = élément GLib à consulter. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Charge un contenu depuis une mémoire tampon. *
+* Description : Sauvegarde un objet dans un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -303,61 +483,64 @@ static guint g_register_operand_hash(const GRegisterOperand *operand, bool lock)
* *
******************************************************************************/
-static bool g_register_operand_load(GRegisterOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_register_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
- GArchOperandClass *parent; /* Classe parente à consulter */
- GSerializableObject *reg; /* Registre manipulé */
+ GRegisterOperand *operand; /* Version spécialisée */
+ off64_t reg_pos; /* Position renvoyant au reg. */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *parent_iface; /* Interface parente */
- parent = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class);
+ operand = G_REGISTER_OPERAND(object);
- result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
+ result = g_object_storage_store_object(storage, "registers", G_SERIALIZABLE_OBJECT(operand->reg), &reg_pos);
+ if (!result) goto exit;
- if (result)
- {
- reg = g_object_storage_unpack_object(storage, "registers", pbuf);
+ iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
- result = (reg != NULL);
+ parent_iface = g_type_interface_peek_parent(iface);
- if (result)
- operand->reg = G_ARCH_REGISTER(reg);
+ result = parent_iface->store(object, storage, fd);
+ if (!result) goto exit;
- }
+ result = store_uleb128((uleb128_t []) { reg_pos }, fd);
+
+ exit:
return result;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* EXPORTATION SOUS FORME DE CHAINE DE CARACTERES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : operand = élément GLib à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* Paramètres : builder = objet dont l'instance est exportable. *
+* flags = éventuelles indications pour l'opération. *
+* out = chaîne de caractères mise en place. [OUT] *
* *
-* Description : Sauvegarde un contenu dans une mémoire tampon. *
+* Description : Exporte une chaîne de caractères à partir d'un objet. *
* *
* Retour : Bilan de l'opération. *
* *
-* Remarques : - *
+* Remarques : La sortie out est à nettoyer avec exit_sized_binary() après *
+* usage. *
* *
******************************************************************************/
-static bool g_register_operand_store(GRegisterOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_register_operand_to_string(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)
{
bool result; /* Bilan à retourner */
- GArchOperandClass *parent; /* Classe parente à consulter */
- GSerializableObject *reg; /* Registre manipulé */
+ const GRegisterOperand *operand; /* Version spécialisée */
- parent = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class);
+ operand = G_REGISTER_OPERAND(builder);
- result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
-
- if (result)
- {
- reg = G_SERIALIZABLE_OBJECT(operand->reg);
- result = g_object_storage_pack_object(storage, "registers", reg, pbuf);
- }
+ result = g_string_builder_to_string(G_STRING_BUILDER(operand->reg), flags, out);
return result;
diff --git a/src/arch/register-int.h b/src/arch/register-int.h
index f0b9af9..22ef2cc 100644
--- a/src/arch/register-int.h
+++ b/src/arch/register-int.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* register-int.h - définitions internes pour la représentation générique d'un registre
*
- * Copyright (C) 2012-2018 Cyrille Bagard
+ * Copyright (C) 2012-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,31 +26,15 @@
#include "register.h"
-#include "../analysis/storage/serialize-int.h"
-/* Produit une empreinte à partir d'un registre. */
-typedef guint (* reg_hash_fc) (const GArchRegister *);
-
-/* Compare un registre avec un autre. */
-typedef int (* reg_compare_fc) (const GArchRegister *, const GArchRegister *);
-
-/* Traduit un registre en version humainement lisible. */
-typedef void (* reg_print_fc) (const GArchRegister *, GBufferLine *);
-
/* Indique si le registre correspond à ebp ou similaire. */
typedef bool (* reg_is_base_pointer_fc) (const GArchRegister *);
/* Indique si le registre correspond à esp ou similaire. */
typedef bool (* reg_is_stack_pointer_fc) (const GArchRegister *);
-/* Charge un contenu depuis une mémoire tampon. */
-typedef bool (* load_register_fc) (GArchRegister *, GObjectStorage *, packed_buffer_t *);
-
-/* Sauvegarde un contenu dans une mémoire tampon. */
-typedef bool (* store_register_fc) (GArchRegister *, GObjectStorage *, packed_buffer_t *);
-
/* Représentation d'un registre (instance) */
struct _GArchRegister
@@ -64,15 +48,9 @@ struct _GArchRegisterClass
{
GObjectClass parent; /* A laisser en premier */
- reg_hash_fc hash; /* Production d'empreinte */
- reg_compare_fc compare; /* Comparaison de registres */
- reg_print_fc print; /* Impression du registre */
reg_is_base_pointer_fc is_bp; /* Correspondance avec ebp */
reg_is_stack_pointer_fc is_sp; /* Correspondance avec esp */
- load_register_fc load; /* Chargement depuis un tampon */
- store_register_fc store; /* Conservation dans un tampon */
-
};
diff --git a/src/arch/register.c b/src/arch/register.c
index f487419..6017373 100644
--- a/src/arch/register.c
+++ b/src/arch/register.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* registers.c - aides auxiliaires relatives aux registres Dalvik
*
- * Copyright (C) 2012-2018 Cyrille Bagard
+ * Copyright (C) 2012-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,6 +25,10 @@
#include "register-int.h"
+#include "../glibext/comparable-int.h"
+#include "../glibext/hashable-int.h"
+#include "../glibext/serialize-int.h"
+#include "../glibext/strbuilder-int.h"
@@ -34,34 +38,26 @@
/* Initialise la classe des registres. */
static void g_arch_register_class_init(GArchRegisterClass *);
-/* Initialise une instance de registre. */
-static void g_arch_register_init(GArchRegister *);
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_arch_register_comparable_object_iface_init(GComparableObjectInterface *);
+
+/* Procède à l'initialisation de l'interface de détermination. */
+static void g_arch_register_hashable_object_iface_init(GHashableObjectInterface *);
/* Procède à l'initialisation de l'interface de sérialisation. */
static void g_arch_register_serializable_init(GSerializableObjectInterface *);
-/* Supprime toutes les références externes. */
-static void g_arch_register_dispose(GArchRegister *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_arch_register_finalize(GArchRegister *);
-
+/* Procède à l'initialisation de l'interface d'exportation. */
+static void g_arch_register_string_builder_iface_init(GStringBuilderInterface *);
+/* Initialise une instance de registre. */
+static void g_arch_register_init(GArchRegister *);
-/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
-
-
-/* Charge un contenu depuis une mémoire tampon. */
-static bool _g_arch_register_load(GArchRegister *, GObjectStorage *, packed_buffer_t *);
-
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_arch_register_load(GArchRegister *, GObjectStorage *, packed_buffer_t *);
-
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool _g_arch_register_store(GArchRegister *, GObjectStorage *, packed_buffer_t *);
+/* Supprime toutes les références externes. */
+static void g_arch_register_dispose(GObject *);
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_arch_register_store(GArchRegister *, GObjectStorage *, packed_buffer_t *);
+/* Procède à la libération totale de la mémoire. */
+static void g_arch_register_finalize(GObject *);
@@ -72,7 +68,10 @@ static bool g_arch_register_store(GArchRegister *, GObjectStorage *, packed_buff
/* Indique le type défini pour une représentation d'un registre. */
G_DEFINE_TYPE_WITH_CODE(GArchRegister, g_arch_register, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_register_serializable_init));
+ G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_arch_register_comparable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_arch_register_hashable_object_iface_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_register_serializable_init)
+ G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_arch_register_string_builder_iface_init));
/******************************************************************************
@@ -93,20 +92,18 @@ static void g_arch_register_class_init(GArchRegisterClass *klass)
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_register_dispose;
- object->finalize = (GObjectFinalizeFunc)g_arch_register_finalize;
-
- klass->load = (load_register_fc)_g_arch_register_load;
- klass->store = (store_register_fc)_g_arch_register_store;
+ object->dispose = g_arch_register_dispose;
+ object->finalize = g_arch_register_finalize;
}
+
/******************************************************************************
* *
-* Paramètres : reg = instance à initialiser. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Initialise une instance de registre. *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
* *
* Retour : - *
* *
@@ -114,8 +111,9 @@ static void g_arch_register_class_init(GArchRegisterClass *klass)
* *
******************************************************************************/
-static void g_arch_register_init(GArchRegister *reg)
+static void g_arch_register_comparable_object_iface_init(GComparableObjectInterface *iface)
{
+ iface->compare = NULL;
}
@@ -124,7 +122,7 @@ static void g_arch_register_init(GArchRegister *reg)
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Procède à l'initialisation de l'interface de sérialisation. *
+* Description : Procède à l'initialisation de l'interface de détermination. *
* *
* Retour : - *
* *
@@ -132,19 +130,18 @@ static void g_arch_register_init(GArchRegister *reg)
* *
******************************************************************************/
-static void g_arch_register_serializable_init(GSerializableObjectInterface *iface)
+static void g_arch_register_hashable_object_iface_init(GHashableObjectInterface *iface)
{
- iface->load = (load_serializable_object_cb)g_arch_register_load;
- iface->store = (store_serializable_object_cb)g_arch_register_store;
+ iface->hash = NULL;
}
/******************************************************************************
* *
-* Paramètres : reg = instance d'objet GLib à traiter. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Supprime toutes les références externes. *
+* Description : Procède à l'initialisation de l'interface de sérialisation. *
* *
* Retour : - *
* *
@@ -152,18 +149,19 @@ static void g_arch_register_serializable_init(GSerializableObjectInterface *ifac
* *
******************************************************************************/
-static void g_arch_register_dispose(GArchRegister *reg)
+static void g_arch_register_serializable_init(GSerializableObjectInterface *iface)
{
- G_OBJECT_CLASS(g_arch_register_parent_class)->dispose(G_OBJECT(reg));
+ iface->load = NULL;
+ iface->store = NULL;
}
/******************************************************************************
* *
-* Paramètres : reg = instance d'objet GLib à traiter. *
+* Paramètres : iface = interface GLib à initialiser. *
* *
-* Description : Procède à la libération totale de la mémoire. *
+* Description : Procède à l'initialisation de l'interface d'exportation. *
* *
* Retour : - *
* *
@@ -171,58 +169,55 @@ static void g_arch_register_dispose(GArchRegister *reg)
* *
******************************************************************************/
-static void g_arch_register_finalize(GArchRegister *reg)
+static void g_arch_register_string_builder_iface_init(GStringBuilderInterface *iface)
{
- G_OBJECT_CLASS(g_arch_register_parent_class)->finalize(G_OBJECT(reg));
+ iface->to_string = NULL;
}
/******************************************************************************
* *
-* Paramètres : reg = opérande à consulter pour le calcul. *
+* Paramètres : reg = instance à initialiser. *
* *
-* Description : Produit une empreinte à partir d'un registre. *
+* Description : Initialise une instance de registre. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-guint g_arch_register_hash(const GArchRegister *reg)
+static void g_arch_register_init(GArchRegister *reg)
{
- return G_ARCH_REGISTER_GET_CLASS(reg)->hash(reg);
}
/******************************************************************************
* *
-* Paramètres : a = premier registre à consulter. *
-* b = second registre à consulter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Compare un registre avec un autre. *
+* Description : Supprime toutes les références externes. *
* *
-* Retour : Bilan de la comparaison. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-int g_arch_register_compare(const GArchRegister *a, const GArchRegister *b)
+static void g_arch_register_dispose(GObject *object)
{
- return G_ARCH_REGISTER_GET_CLASS(a)->compare(a, b);
+ G_OBJECT_CLASS(g_arch_register_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : reg = registre à transcrire. *
-* line = ligne tampon où imprimer l'opérande donné. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Traduit un registre en version humainement lisible. *
+* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
@@ -230,9 +225,9 @@ int g_arch_register_compare(const GArchRegister *a, const GArchRegister *b)
* *
******************************************************************************/
-void g_arch_register_print(const GArchRegister *reg, GBufferLine *line)
+static void g_arch_register_finalize(GObject *object)
{
- G_ARCH_REGISTER_GET_CLASS(reg)->print(reg, line);
+ G_OBJECT_CLASS(g_arch_register_parent_class)->finalize(object);
}
@@ -287,115 +282,3 @@ bool g_arch_register_is_stack_pointer(const GArchRegister *reg)
return result;
}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* CONSERVATION ET RECHARGEMENT DES DONNEES */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : reg = é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_arch_register_load(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
-
- result = true;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : reg = é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_arch_register_load(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- GArchRegisterClass *class; /* Classe à activer */
-
- class = G_ARCH_REGISTER_GET_CLASS(reg);
-
- result = class->load(reg, storage, pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : reg = é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_arch_register_store(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
-
- result = true;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : reg = é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_arch_register_store(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- GArchRegisterClass *class; /* Classe à activer */
-
- class = G_ARCH_REGISTER_GET_CLASS(reg);
-
- result = class->store(reg, storage, pbuf);
-
- return result;
-
-}
diff --git a/src/arch/register.h b/src/arch/register.h
index 0265a73..16275e0 100644
--- a/src/arch/register.h
+++ b/src/arch/register.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* register.h - prototypes pour les aides auxiliaires relatives aux registres Dalvik
*
- * Copyright (C) 2012-2018 Cyrille Bagard
+ * Copyright (C) 2012-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,44 +25,19 @@
#define _ARCH_REGISTER_H
-#include <glib-object.h>
#include <stdbool.h>
-#include "../glibext/bufferline.h"
+#include "../glibext/helpers.h"
-/* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */
+#define G_TYPE_ARCH_REGISTER (g_arch_register_get_type())
+DECLARE_GTYPE(GArchRegister, g_arch_register, G, ARCH_REGISTER);
-#define G_TYPE_ARCH_REGISTER g_arch_register_get_type()
-#define G_ARCH_REGISTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARCH_REGISTER, GArchRegister))
-#define G_IS_ARCH_REGISTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARCH_REGISTER))
-#define G_ARCH_REGISTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_REGISTER, GArchRegisterClass))
-#define G_IS_ARCH_REGISTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_REGISTER))
-#define G_ARCH_REGISTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_REGISTER, GArchRegisterClass))
-/* Représentation d'un registre (instance) */
-typedef struct _GArchRegister GArchRegister;
-
-/* Représentation d'un registre (classe) */
-typedef struct _GArchRegisterClass GArchRegisterClass;
-
-
-/* Indique le type défini pour une représentation d'un registre. */
-GType g_arch_register_get_type(void);
-
-/* Produit une empreinte à partir d'un registre. */
-guint g_arch_register_hash(const GArchRegister *);
-
-/* Compare un registre avec un autre. */
-int g_arch_register_compare(const GArchRegister *, const GArchRegister *);
-
-/* Traduit un registre en version humainement lisible. */
-void g_arch_register_print(const GArchRegister *, GBufferLine *);
-
/* Indique si le registre correspond à ebp ou similaire. */
bool g_arch_register_is_base_pointer(const GArchRegister *);
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index 8a9b961..7a11deb 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -296,4 +296,33 @@ char *mrange_length_to_string(const mrange_t *, MemoryDataSize, char [VMPA_MAX_L
+/* ------------------- DEFINITION D'UN ESPACE RELATIVE EN MEMOIRE ------------------- */
+
+
+/* Couverture mémoire */
+typedef struct _rel_mrange_t
+{
+ uint32_t offset; /* Décalage depuis une ref. */
+ uint16_t length; /* Taille de la couverture */
+
+} rel_mrange_t;
+
+
+#define init_rel_mrange(rr, o, l) \
+ do \
+ { \
+ (rr)->offset = o; \
+ (rr)->length = l; \
+ } \
+ while (0);
+
+
+#define get_rel_mrange_offset(rr) \
+ (rr)->offset
+
+#define get_rel_mrange_length(rr) \
+ (rr)->length
+
+
+
#endif /* _ARCH_VMPA_H */
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index d09b661..1056cb2 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -47,6 +47,7 @@ endif
libcommon4_la_SOURCES = \
+ array.h array.c \
asm.h asm.c \
bits.h bits.c \
compiler.h \
diff --git a/src/common/bits.c b/src/common/bits.c
index 26f570f..27296f2 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -31,6 +31,7 @@
#include "asm.h"
+#include "io.h"
#include "leb128.h"
diff --git a/src/common/cpp.h b/src/common/cpp.h
index 2644281..4ebad82 100644
--- a/src/common/cpp.h
+++ b/src/common/cpp.h
@@ -43,6 +43,15 @@
/**
+ * Facilite la transmission d'arguement pour des fonctions
+ * comme strncmp() et Cie.
+ */
+#define SL(str) str, strlen(str)
+
+#define STCSL(str) str, STATIC_STR_SIZE(str)
+
+
+/**
* Détermine la taille de la plus longue chaîne de caractères
* correspondant à un type donné.
*/
diff --git a/src/common/datatypes.h b/src/common/datatypes.h
index 681e232..248f4a1 100644
--- a/src/common/datatypes.h
+++ b/src/common/datatypes.h
@@ -71,6 +71,10 @@ typedef enum _MemoryDataSize
} MemoryDataSize;
+#define MDS_RANGE(mds) ((mds & 0x7) - 1)
+#define MDS_SIGN 0x8
+#define MDS_IS_SIGNED(mds) (mds & MDS_SIGN)
+
#define MDS_4_BITS MDS_4_BITS_UNSIGNED
#define MDS_8_BITS MDS_8_BITS_UNSIGNED
#define MDS_16_BITS MDS_16_BITS_UNSIGNED
diff --git a/src/common/leb128.c b/src/common/leb128.c
index 009aff6..7fae4d0 100644
--- a/src/common/leb128.c
+++ b/src/common/leb128.c
@@ -24,9 +24,20 @@
#include "leb128.h"
+#include <malloc.h>
+
+
#include "io.h"
+/**
+ * Quantité maximale d'octets de représentation.
+ *
+ * sizeof([u]leb128_t) / 7 = 9.142857142857142
+ *
+ */
+#define MAX_LEB128_BYTES 9
+
/******************************************************************************
* *
@@ -133,7 +144,7 @@ bool load_uleb128(uleb128_t *value, int fd)
unsigned int shift; /* Décalage à appliquer */
uint8_t byte; /* Octet à transposer */
- result = true;
+ result = false;
*value = 0;
@@ -142,7 +153,7 @@ bool load_uleb128(uleb128_t *value, int fd)
while (true)
{
/* Encodage sur trop d'octets ? */
- if (shift > (7 * sizeof(uleb128_t)))
+ if (shift > (7 * MAX_LEB128_BYTES))
{
result = false;
break;
@@ -153,6 +164,8 @@ bool load_uleb128(uleb128_t *value, int fd)
*value |= ((byte & 0x7f) << shift);
+ result = true;
+
if ((byte & 0x80) == 0x00)
break;
@@ -207,7 +220,7 @@ bool store_uleb128(const uleb128_t *value, int fd)
/******************************************************************************
* *
* Paramètres : value = valeur à consigner. *
-* pbuf = tampon de données à constituer. [OUT] *
+* len = taille du tampon de données à constitué. [OUT] *
* *
* Description : Encode un nombre non signé encodé au format LEB128. *
* *
@@ -217,26 +230,44 @@ bool store_uleb128(const uleb128_t *value, int fd)
* *
******************************************************************************/
-bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf)
+void *pack_uleb128(const uleb128_t *value, size_t *len)
{
- bool result; /* Bilan à retourner */
+ uint8_t *result; /* Données à retourner */
uleb128_t tmp; /* Valeur modifiable */
- uint8_t byte; /* Octet à transposer */
+ uint8_t *byte; /* Octet à transposer */
+
+ /* Calcul de la quantité d'octets nécessaires */
+
+ *len = 0;
tmp = *value;
do
{
- byte = (tmp & 0x7f);
+ tmp >>= 7;
+ (*len)++;
+ }
+ while (tmp != 0);
+
+ /* Exportation */
+
+ result = malloc(*len * sizeof(uint8_t));
+ byte = result;
+
+ tmp = *value;
+
+ do
+ {
+ *byte = (tmp & 0x7f);
tmp >>= 7;
if (tmp != 0)
- byte |= 0x80;
+ *byte |= 0x80;
- result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
+ byte++;
}
- while (result && tmp != 0);
+ while (tmp != 0);
return result;
@@ -246,7 +277,7 @@ bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf)
/******************************************************************************
* *
* Paramètres : value = valeur à consigner. *
-* pbuf = tampon de données à constituer. [OUT] *
+* len = taille du tampon de données à constitué. [OUT] *
* *
* Description : Encode un nombre signé encodé au format LEB128. *
* *
@@ -256,19 +287,24 @@ bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf)
* *
******************************************************************************/
-bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)
+void *pack_leb128(const leb128_t *value, size_t *len)
{
-
- bool result; /* Bilan à retourner */
+ uint8_t *result; /* Données à retourner */
+ bool negative; /* Nature de la valeur */
uleb128_t tmp; /* Valeur modifiable */
bool more; /* Poursuite des traitements */
- bool negative; /* Nature de la valeur */
uint8_t byte; /* Octet à transposer */
+ uint8_t *iter; /* Boucle de parcours */
+
+ negative = (*value < 0);
+
+ /* Calcul de la quantité d'octets nécessaires */
+
+ *len = 0;
tmp = *value;
more = true;
- negative = (*value < 0);
while (more)
{
@@ -291,10 +327,44 @@ bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)
if ((tmp == 0 && (byte & 0x40) == 0x00) || (tmp == -1 && (byte & 0x40) == 0x40))
more = false;
+ (*len)++;
+
+ }
+
+ /* Exportation */
+
+ result = malloc(*len * sizeof(uint8_t));
+ iter = result;
+
+ tmp = *value;
+
+ more = true;
+
+ while (more)
+ {
+ *iter = (tmp & 0x7f);
+ tmp >>= 7;
+
+ /**
+ * Propagation forcée du bit de signe pour les implémentations de
+ * décalage basées sur une opération logique et non arithmétique.
+ */
+
+ if (negative)
+ tmp |= (~0llu << (LEB128_BITS_COUNT - 7));
+
+ /**
+ * Le bit de signe n'est pas le bit de poids fort ici :
+ * On travaille sur 7 bits, donc le masque est 0x40 !
+ */
+
+ if ((tmp == 0 && (*iter & 0x40) == 0x00) || (tmp == -1 && (*iter & 0x40) == 0x40))
+ more = false;
+
else
- byte |= 0x80;
+ *iter |= 0x80;
- result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
+ iter++;
}
@@ -306,7 +376,8 @@ bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)
/******************************************************************************
* *
* Paramètres : value = valeur à constituer. [OUT] *
-* pbuf = tampon de données à consulter. *
+* pos = tête de lecture à faire évoluer. [OUT] *
+* max = position maximale liée à la fin des données. *
* *
* Description : Décode un nombre non signé encodé au format LEB128. *
* *
@@ -316,38 +387,45 @@ bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)
* *
******************************************************************************/
-bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf)
+bool unpack_uleb128(uleb128_t *value, const void **pos, const void *max)
{
bool result; /* Bilan à retourner */
unsigned int shift; /* Décalage à appliquer */
- uint8_t byte; /* Octet à transposer */
+ uint8_t *byte; /* Octet à transposer */
- result = true;
+ result = false;
*value = 0;
shift = 0;
+ byte = *(uint8_t **)pos;
- while (true)
+ do
{
/* Encodage sur trop d'octets ? */
- if (shift > (7 * sizeof(uleb128_t)))
+ if (shift > (7 * MAX_LEB128_BYTES))
{
result = false;
break;
}
- result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
- if (!result) break;
+ /* Atteinte de la fin des données ? */
+ if ((void *)byte >= max)
+ {
+ result = false;
+ break;
+ }
- *value |= ((byte & 0x7f) << shift);
+ *value |= ((*byte & 0x7f) << shift);
- if ((byte & 0x80) == 0x00)
- break;
+ result = true;
shift += 7;
}
+ while ((*byte++ & 0x80) == 0x80);
+
+ *pos = byte;
return result;
@@ -357,7 +435,8 @@ bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf)
/******************************************************************************
* *
* Paramètres : value = valeur à constituer. [OUT] *
-* pbuf = tampon de données à consulter. *
+* pos = tête de lecture à faire évoluer. [OUT] *
+* max = position maximale liée à la fin des données. *
* *
* Description : Décode un nombre signé encodé au format LEB128. *
* *
@@ -367,44 +446,56 @@ bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf)
* *
******************************************************************************/
-bool unpack_leb128(leb128_t *value, packed_buffer_t *pbuf)
+bool unpack_leb128(leb128_t *value, const void **pos, const void *max)
{
bool result; /* Bilan à retourner */
unsigned int shift; /* Décalage à appliquer */
- uint8_t byte; /* Octet à transposer */
+ uint8_t *byte; /* Octet à transposer */
- result = true;
+ result = false;
*value = 0;
shift = 0;
+ byte = *(uint8_t **)pos;
do
{
/* Encodage sur trop d'octets ? */
- if (shift > (7 * sizeof(leb128_t)))
+ if (shift > (7 * MAX_LEB128_BYTES))
{
result = false;
break;
}
- result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
- if (!result) break;
+ /* Atteinte de la fin des données ? */
+ if ((void *)byte >= max)
+ {
+ result = false;
+ break;
+ }
- *value |= ((byte & 0x7f) << shift);
+ *value |= ((*byte & 0x7f) << shift);
+
+ result = true;
shift += 7;
}
- while ((byte & 0x80) == 0x80);
+ while ((*byte++ & 0x80) == 0x80);
/**
* Le bit de signe n'est pas le bit de poids fort ici :
* On travaille sur 7 bits, donc le masque est 0x40 !
*/
- if (shift < LEB128_BITS_COUNT && (byte & 0x40) == 0x40)
- *value |= (~0llu << shift);
+ if (result)
+ {
+ if (shift < LEB128_BITS_COUNT && (byte[-1] & 0x40) == 0x40)
+ *value |= (~0llu << shift);
+ }
+
+ *pos = byte;
return result;
diff --git a/src/common/leb128.h b/src/common/leb128.h
index 0313f5c..cb712a3 100644
--- a/src/common/leb128.h
+++ b/src/common/leb128.h
@@ -30,7 +30,6 @@
#include "datatypes.h"
-#include "packed.h"
@@ -65,16 +64,16 @@ bool load_uleb128(uleb128_t *, int);
bool store_uleb128(const uleb128_t *, int);
/* Encode un nombre non signé encodé au format LEB128. */
-bool pack_uleb128(const uleb128_t *, packed_buffer_t *);
+void *pack_uleb128(const uleb128_t *, size_t *);
/* Encode un nombre signé encodé au format LEB128. */
-bool pack_leb128(const leb128_t *, packed_buffer_t *);
+void *pack_leb128(const leb128_t *, size_t *);
-/* Décode un nombre non signé encodé au format LEB128. */
-bool unpack_uleb128(uleb128_t *, packed_buffer_t *);
+/* Encode un nombre non signé encodé au format LEB128. */
+bool unpack_uleb128(uleb128_t *, const void **, const void *);
/* Décode un nombre signé encodé au format LEB128. */
-bool unpack_leb128(leb128_t *, packed_buffer_t *);
+bool unpack_leb128(leb128_t *, const void **, const void *);
diff --git a/src/common/pathname.c b/src/common/pathname.c
index dd3ec9e..81dc1e3 100644
--- a/src/common/pathname.c
+++ b/src/common/pathname.c
@@ -33,13 +33,13 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <gio/gio.h>
#include <sys/stat.h>
#include "extstr.h"
#include "io.h"
#include "../core/logs.h"
-//#include "../core/params.h" // TODO : config
@@ -316,16 +316,19 @@ int ensure_path_exists(const char *path)
* Remarques : - *
* *
******************************************************************************/
-#if 0 // TODO
+
int make_tmp_file(const char *prefix, const char *suffix, char **filename)
{
int result; /* Flux ou code à retourner */
- const char *tmpdir; /* Répertoire d'accueil */
- bool status; /* Bilan d'un consultation */
+ GSettings *settings; /* Configuration sollicitée */
+ gchar *tmpdir; /* Répertoire d'accueil */
size_t slen; /* Taille du suffixe */
- status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir);
- if (!status) return -1;
+ /* Récupération d'un répertoire de travail temporaire */
+
+ settings = g_settings_new("re.chrysalide.framework.paths");
+
+ tmpdir = g_settings_get_string(settings, "tmp-work-dir");
slen = strlen(suffix);
@@ -334,6 +337,12 @@ int make_tmp_file(const char *prefix, const char *suffix, char **filename)
else
asprintf(filename, "%s" G_DIR_SEPARATOR_S "%s-%d.XXXXXX", tmpdir, prefix, getpid());
+ g_free(tmpdir);
+
+ g_clear_object(&settings);
+
+ /* Mise en place d'un fichier temporaire */
+
result = ensure_path_exists(*filename);
if (result == 0)
@@ -356,7 +365,7 @@ int make_tmp_file(const char *prefix, const char *suffix, char **filename)
return result;
}
-#endif
+
/******************************************************************************
* *
diff --git a/src/common/pathname.h b/src/common/pathname.h
index 1b6624c..104833b 100644
--- a/src/common/pathname.h
+++ b/src/common/pathname.h
@@ -42,9 +42,7 @@ bool mkpath(const char *);
int ensure_path_exists(const char *);
/* Met en place un fichier temporaire. */
-#if 0 // TODO
int make_tmp_file(const char *, const char *, char **);
-#endif
/* Copie un fichier. */
bool copy_file(const char *, const char *);
diff --git a/src/common/sort.h b/src/common/sort.h
index 39a6f33..27e3739 100644
--- a/src/common/sort.h
+++ b/src/common/sort.h
@@ -37,6 +37,9 @@ int sort_boolean(bool, bool);
/* Compare une valeur avec une autre. */
int sort_unsigned_long(unsigned long, unsigned long);
+#define sort_size(v1, v2) \
+ sort_unsigned_long(v1, v2)
+
/* Compare une valeur avec une autre. */
int sort_signed_long_long(signed long long, signed long long);
diff --git a/src/common/szbin.h b/src/common/szbin.h
index 5891449..8524ae3 100644
--- a/src/common/szbin.h
+++ b/src/common/szbin.h
@@ -25,6 +25,7 @@
#define _COMMON_SZBIN_H
+#include <assert.h>
#include <malloc.h>
#include <string.h>
@@ -72,11 +73,22 @@ typedef struct _sized_binary_t
while (0)
+#define setup_sized_binary_from_static_string(sb, s) \
+ do \
+ { \
+ (sb)->static_data = s; \
+ (sb)->size = strlen(s) + 1; \
+ } \
+ while (0)
+
+
#define dup_into_sized_binary(sb, d, s) \
do \
{ \
- setup_sized_binary(sb, s); \
- memcpy((sb)->data, d, s); \
+ size_t __size_once; \
+ __size_once = s; \
+ setup_sized_binary(sb, __size_once);\
+ memcpy((sb)->data, d, __size_once); \
} \
while (0)
@@ -97,6 +109,16 @@ typedef struct _sized_binary_t
while (0)
+#define resize_sized_binary(sb, s) \
+ do \
+ { \
+ (sb)->size = s; \
+ (sb)->data = realloc((sb)->data, \
+ (sb)->size); \
+ } \
+ while (0)
+
+
#define add_to_sized_binary(sb, d, s) \
do \
{ \
@@ -121,18 +143,21 @@ typedef struct _sized_binary_t
while (0)
-#define memcmp_sized_binary(s1, s2) \
- ({ \
- int __ret; \
- size_t __n; \
- __n = (s1)->size < (s2)->size ? (s1)->size : (s2)->size; \
- __ret = memcmp((s1)->data, (s2)->data, __n); \
- if (__ret == 0) \
- __ret = sort_unsigned_long_long((s1)->size, (s2)->size);\
- __ret; \
+#define memcmp_sized_binary(s1, s2) \
+ ({ \
+ int __ret; \
+ __ret = sort_size((s1)->size, (s2)->size); \
+ if (__ret == 0) \
+ __ret = memcmp((s1)->data, (s2)->data, (s1)->size); \
+ __ret; \
})
+
+/**
+ * Conservations et rechargements.
+ */
+
#define load_sized_binary(sb, f) \
({ \
uleb128_t __sz; \
@@ -149,6 +174,23 @@ typedef struct _sized_binary_t
})
+#define load_sized_binary_as_string(sb, f) \
+ ({ \
+ uleb128_t __sz; \
+ bool __ret; \
+ __ret = load_uleb128(&__sz, f); \
+ if (__ret) \
+ { \
+ setup_sized_binary(sb, __sz + 1); \
+ __ret = safe_read(f, (sb)->data, __sz); \
+ if (!__ret) \
+ exit_sized_binary(sb); \
+ (sb)->data[__sz] = '\0'; \
+ } \
+ __ret; \
+ })
+
+
#define store_sized_binary(sb, f) \
({ \
bool __ret; \
@@ -159,5 +201,82 @@ typedef struct _sized_binary_t
})
+#define store_sized_binary_as_string(sb, f) \
+ ({ \
+ bool __ret; \
+ size_t __length; \
+ assert((sb)->size >= 1); \
+ __length = (sb)->size - 1; \
+ assert((sb)->static_data[__length] == '\0'); \
+ __ret = store_uleb128((const uleb128_t []){ __length }, f); \
+ if (__ret) \
+ __ret = safe_write(f, (sb)->static_data, __length); \
+ __ret; \
+ })
+
+
+#define unpack_sized_binary(sb, p, m) \
+ ({ \
+ uleb128_t __sz; \
+ bool __ret; \
+ __ret = unpack_uleb128(&__sz, p, m); \
+ if (__ret) \
+ { \
+ setup_sized_binary(sb, __sz); \
+ memcpy((sb)->data, *p, (sb)->size); \
+ *((uint8_t **)p) += __sz; \
+ } \
+ __ret; \
+ })
+
+
+#define unpack_sized_binary_as_string(sb, p, m) \
+ ({ \
+ uleb128_t __sz; \
+ bool __ret; \
+ __ret = unpack_uleb128(&__sz, p, m); \
+ if (__ret) \
+ { \
+ setup_sized_binary(sb, __sz + 1); \
+ memcpy((sb)->data, *p, __sz); \
+ (sb)->data[__sz] = '\0'; \
+ *((uint8_t **)p) += __sz; \
+ } \
+ __ret; \
+ })
+
+
+#define pack_sized_binary(sb, l) \
+ ({ \
+ uint8_t *__result; \
+ size_t __pos; \
+ __result = pack_uleb128((const uleb128_t []){ (sb)->size }, l); \
+ __pos = *(l); \
+ *(l) += (sb)->size; \
+ __result = realloc(__result, *(l) * sizeof(uint8_t)); \
+ memcpy(&__result[__pos], (sb)->static_data, \
+ ((sb)->size * sizeof(uint8_t))); \
+ __result; \
+ })
+
+
+#define pack_sized_binary_as_string(sb, l) \
+ ({ \
+ uint8_t *__result; \
+ size_t __length; \
+ size_t __pos; \
+ assert((sb)->size >= 1); \
+ __length = (sb)->size - 1; \
+ assert((sb)->static_data[__length] == '\0'); \
+ __result = pack_uleb128((const uleb128_t []){ __length }, l); \
+ __pos = *(l); \
+ *(l) += __length; \
+ __result = realloc(__result, *(l) * sizeof(uint8_t)); \
+ memcpy(&__result[__pos], (sb)->static_data, \
+ (__length * sizeof(uint8_t))); \
+ __result; \
+ })
+
+
#endif /* _COMMON_SZBIN_H */
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index e1e3c4e..15ed866 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -20,9 +20,10 @@ libcore4_la_SOURCES = \
logs.h logs.c \
nox.h nox.c \
nproc.h nproc.c \
- paths.h paths.c
+ paths.h paths.c \
+ processors.h processors.c
-libcore4_la_CFLAGS = $(TOOLKIT_CFLAGS)
+libcore4_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBSSL_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
diff --git a/src/core/core.c b/src/core/core.c
index 9514ee1..c730fad 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -25,6 +25,7 @@
#include "global.h"
+#include "processors.h"
@@ -53,12 +54,22 @@ bool load_core_components(AvailableCoreComponent flags)
if ((flags & ACC_GLOBAL_VARS) != 0 && (__loaded & ACC_GLOBAL_VARS) == 0)
{
+ set_secret_storage(g_secret_storage_new(NULL));
+
set_work_queue(g_work_queue_new());
__loaded |= ACC_GLOBAL_VARS;
}
+ if ((flags & ACC_CODE_ANALYSIS) != 0 && (__loaded & ACC_CODE_ANALYSIS) == 0)
+ {
+ register_arch_gtypes();
+
+ init_operands_factory();
+
+ }
+
return result;
}
@@ -78,10 +89,18 @@ bool load_core_components(AvailableCoreComponent flags)
void unload_core_components(AvailableCoreComponent flags)
{
+ if ((flags & ACC_CODE_ANALYSIS) != 0 && (__loaded & ACC_CODE_ANALYSIS) == 0)
+ {
+ exit_operands_factory();
+
+ }
+
if ((flags & ACC_GLOBAL_VARS) != 0 && (__loaded & ACC_GLOBAL_VARS) == 0)
{
set_work_queue(NULL);
+ set_secret_storage(NULL);
+
__loaded &= ~ACC_GLOBAL_VARS;
}
@@ -107,7 +126,6 @@ void unload_core_components(AvailableCoreComponent flags)
#include "demanglers.h"
#include "global.h"
#include "params.h"
-#include "processors.h"
#include "queue.h"
#include "../analysis/scan/core.h"
#ifdef INCLUDE_MAGIC_SUPPORT
@@ -191,9 +209,6 @@ bool load_all_core_components(bool cs)
if (result) result = init_segment_content_hash_table();
- register_arch_gtypes();
- init_operands_factory();
-
}
}
@@ -219,8 +234,6 @@ void unload_all_core_components(bool cs)
{
if (cs)
{
- exit_operands_factory();
-
exit_segment_content_hash_table();
unload_demanglers_definitions();
diff --git a/src/core/core.h b/src/core/core.h
index 7c50f6c..640476a 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -32,9 +32,12 @@
/* Eléments à (dé)charger disponibles */
typedef enum _AvailableCoreComponent
{
- ACC_NONE = (0 << 0), /* Statut initial */
- ACC_GLOBAL_VARS = (1 << 0), /* Singletons globaux */
- ACC_SCAN_FEATURES = (1 << 0), /* Espace de noms pour scan */
+ ACC_NONE = (0 << 0), /* Statut initial */
+ ACC_GLOBAL_VARS = (1 << 0), /* Singletons globaux */
+ ACC_CODE_ANALYSIS = (1 << 1), /* Désassemblage de code */
+ ACC_SCAN_FEATURES = (1 << 2), /* Espace de noms pour scan */
+
+ ACC_ALL_COMPONENTS = (1 << 3) - 1
} AvailableCoreComponent;
diff --git a/src/core/global.c b/src/core/global.c
index d38656b..0275e09 100644
--- a/src/core/global.c
+++ b/src/core/global.c
@@ -36,6 +36,9 @@ static size_t _bytes_sent = 0;
/* Gestionnaire de tâches parallèles */
static GWorkQueue *_queue = NULL;
+/* Gardien des secrets avec support des stockages */
+static GSecretStorage *_storage = NULL;
+
/******************************************************************************
@@ -131,6 +134,49 @@ GWorkQueue *get_work_queue(void)
}
+/******************************************************************************
+* *
+* Paramètres : queue = nouveau stockage sécurisé à mémoriser ou NULL. *
+* *
+* Description : Définit le stockage sécurisé principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void set_secret_storage(/* __steal */GSecretStorage *storage)
+{
+ if (_storage != NULL)
+ unref_object(_storage);
+
+ _storage = storage;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit le stockage sécurisé principal. *
+* *
+* Retour : Gestionnaire de traitements parallèles courant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GSecretStorage *get_secret_storage(void)
+{
+ ref_object(_storage);
+
+ return _storage;
+
+}
+
+
diff --git a/src/core/global.h b/src/core/global.h
index b861ad8..f5d8a62 100644
--- a/src/core/global.h
+++ b/src/core/global.h
@@ -25,6 +25,7 @@
#define _CORE_GLOBAL_H
+#include "../glibext/secstorage.h"
#include "../glibext/workqueue.h"
@@ -41,6 +42,12 @@ void set_work_queue(/* __steal */GWorkQueue *);
/* Fournit le gestionnaire de traitements parallèles courant. */
GWorkQueue *get_work_queue(void);
+/* Définit le stockage sécurisé principal. */
+void set_secret_storage(/* __steal */GSecretStorage *);
+
+/* Fournit le stockage sécurisé principal. */
+GSecretStorage *get_secret_storage(void);
+
diff --git a/src/core/logs.h b/src/core/logs.h
index e8df8bd..3719c6b 100644
--- a/src/core/logs.h
+++ b/src/core/logs.h
@@ -162,6 +162,15 @@ void log_variadic_message(LogMessageType, const char *, ...);
} \
while (0)
+#define LOG_ERROR_ZIP(func, err) \
+ do \
+ { \
+ const char *__msg; \
+ __msg = zip_error_strerror(err); \
+ log_variadic_message(LMT_EXT_ERROR, "[%s:%u] %s: %s", __FUNCTION__, __LINE__, func, __msg); \
+ } \
+ while (0)
+
#endif /* _CORE_LOGS_H */
diff --git a/src/core/processors.c b/src/core/processors.c
index e4a558f..056fc23 100644
--- a/src/core/processors.c
+++ b/src/core/processors.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* processors.c - enregistrement et fourniture des architectures supportées
*
- * Copyright (C) 2015-2020 Cyrille Bagard
+ * Copyright (C) 2015-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -29,13 +29,13 @@
#include <pthread.h>
#include <string.h>
-
+#if 0
#include "../arch/instructions/raw.h"
#include "../arch/instructions/undefined.h"
#include "../arch/operands/immediate.h"
#include "../arch/operands/register.h"
#include "../arch/operands/target.h"
-
+#endif
/* Cache des singletons d'opérandes */
@@ -77,12 +77,12 @@ static proc_t *find_processor_by_key(const char *);
void register_arch_gtypes(void)
{
- g_type_ensure(G_TYPE_RAW_INSTRUCTION);
- g_type_ensure(G_TYPE_UNDEF_INSTRUCTION);
+ //g_type_ensure(G_TYPE_RAW_INSTRUCTION);
+ //g_type_ensure(G_TYPE_UNDEF_INSTRUCTION);
- g_type_ensure(G_TYPE_IMM_OPERAND);
- g_type_ensure(G_TYPE_REGISTER_OPERAND);
- g_type_ensure(G_TYPE_TARGET_OPERAND);
+ //g_type_ensure(G_TYPE_IMM_OPERAND);
+ //g_type_ensure(G_TYPE_REGISTER_OPERAND);
+ //g_type_ensure(G_TYPE_TARGET_OPERAND);
}
@@ -126,7 +126,7 @@ GSingletonFactory *get_operands_factory(void)
result = __operands_factory;
- g_object_ref(G_OBJECT(result));
+ ref_object(result);
return result;
@@ -154,7 +154,7 @@ void exit_operands_factory(void)
}
-
+#if 0
/******************************************************************************
* *
* Paramètres : type = type GLib représentant le type à instancier. *
@@ -206,7 +206,7 @@ bool register_processor_type(GType type)
done:
- g_object_unref(G_OBJECT(proc));
+ unref_object(proc);
return result;
@@ -341,3 +341,4 @@ GArchProcessor *get_arch_processor_for_key(const char *key)
return result;
}
+#endif
diff --git a/src/core/processors.h b/src/core/processors.h
index 6aa2d1e..b622305 100644
--- a/src/core/processors.h
+++ b/src/core/processors.h
@@ -29,7 +29,7 @@
#include <stdbool.h>
-#include "../arch/processor.h"
+//#include "../arch/processor.h"
#include "../glibext/singleton.h"
@@ -45,7 +45,7 @@ GSingletonFactory *get_operands_factory(void);
/* Supprime le fournisseur d'instances uniques d'opérandes. */
void exit_operands_factory(void);
-
+#if 0
/* Enregistre un processeur pour une architecture donnée. */
bool register_processor_type(GType);
@@ -57,7 +57,7 @@ char **get_all_processor_keys(size_t *);
/* Fournit le processeur d'architecture correspondant à un nom. */
GArchProcessor *get_arch_processor_for_key(const char *);
-
+#endif
#endif /* _CORE_PROCESSORS_H */
diff --git a/src/data/Makefile.am b/src/data/Makefile.am
new file mode 100644
index 0000000..8cbe67a
--- /dev/null
+++ b/src/data/Makefile.am
@@ -0,0 +1,2 @@
+
+SUBDIRS = images
diff --git a/src/data/images/Makefile.am b/src/data/images/Makefile.am
new file mode 100644
index 0000000..d5ec84f
--- /dev/null
+++ b/src/data/images/Makefile.am
@@ -0,0 +1,33 @@
+
+BUILT_SOURCES = resources.h resources.c
+
+noinst_LTLIBRARIES = libdataimages.la
+
+RES_FILES = \
+ about-bg.png \
+ dock-station-left-symbolic.svg \
+ dock-station-right-symbolic.svg \
+ dock-station-bottom-symbolic.svg \
+ logs-symbolic.svg
+
+libdataimages_la_SOURCES = \
+ resources.h resources.c
+
+libdataimages_la_CFLAGS = $(LIBGIOUNIX_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libdataimages_la_SOURCES:%c=)
+
+
+resources.c: gresource.xml $(RES_FILES)
+ glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name data_images gresource.xml
+
+resources.h: gresource.xml
+ glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name data_images gresource.xml
+
+
+CLEANFILES = resources.h resources.c
+
+EXTRA_DIST = gresource.xml $(RES_FILES)
diff --git a/src/data/images/dock-station-bottom-symbolic.svg b/src/data/images/dock-station-bottom-symbolic.svg
new file mode 100644
index 0000000..37084ac
--- /dev/null
+++ b/src/data/images/dock-station-bottom-symbolic.svg
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="180"
+ height="180"
+ viewBox="0 0 180 180"
+ version="1.1"
+ id="svg5"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ sodipodi:docname="dock-station-bottom-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="true"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="false"
+ inkscape:zoom="4.2708118"
+ inkscape:cx="87.219952"
+ inkscape:cy="89.444353"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g3929" />
+ <defs
+ id="defs2">
+ <clipPath
+ id="k">
+ <path
+ d="M 0,0 H 800 V 800 H 0 Z"
+ id="path1320" />
+ </clipPath>
+ <mask
+ id="j">
+ <g
+ filter="url(#a)"
+ id="g1317">
+ <path
+ d="M 0,0 H 16 V 16 H 0 Z"
+ fill-opacity="0.35"
+ id="path1315" />
+ </g>
+ </mask>
+ <filter
+ id="a"
+ height="1"
+ width="1"
+ x="0"
+ y="0">
+ <feColorMatrix
+ in="SourceGraphic"
+ type="matrix"
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
+ id="feColorMatrix1280" />
+ </filter>
+ <clipPath
+ id="i">
+ <path
+ d="M 0,0 H 800 V 800 H 0 Z"
+ id="path1312" />
+ </clipPath>
+ <mask
+ id="h">
+ <g
+ filter="url(#a)"
+ id="g1309">
+ <path
+ d="M 0,0 H 16 V 16 H 0 Z"
+ fill-opacity="0.35"
+ id="path1307" />
+ </g>
+ </mask>
+ <filter
+ id="filter3652"
+ height="1"
+ width="1"
+ x="0"
+ y="0">
+ <feColorMatrix
+ in="SourceGraphic"
+ type="matrix"
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
+ id="feColorMatrix3650" />
+ </filter>
+ <clipPath
+ id="g">
+ <path
+ d="M 0,0 H 800 V 800 H 0 Z"
+ id="path1304" />
+ </clipPath>
+ <mask
+ id="f">
+ <g
+ filter="url(#a)"
+ id="g1301">
+ <path
+ d="M 0,0 H 16 V 16 H 0 Z"
+ fill-opacity="0.35"
+ id="path1299" />
+ </g>
+ </mask>
+ <filter
+ id="filter3661"
+ height="1"
+ width="1"
+ x="0"
+ y="0">
+ <feColorMatrix
+ in="SourceGraphic"
+ type="matrix"
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
+ id="feColorMatrix3659" />
+ </filter>
+ <clipPath
+ id="e">
+ <path
+ d="M 0,0 H 800 V 800 H 0 Z"
+ id="path1296" />
+ </clipPath>
+ <mask
+ id="d">
+ <g
+ filter="url(#a)"
+ id="g1293">
+ <path
+ d="M 0,0 H 16 V 16 H 0 Z"
+ fill-opacity="0.35"
+ id="path1291" />
+ </g>
+ </mask>
+ <filter
+ id="filter3670"
+ height="1"
+ width="1"
+ x="0"
+ y="0">
+ <feColorMatrix
+ in="SourceGraphic"
+ type="matrix"
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
+ id="feColorMatrix3668" />
+ </filter>
+ <clipPath
+ id="c">
+ <path
+ d="M 0,0 H 800 V 800 H 0 Z"
+ id="path1288" />
+ </clipPath>
+ <mask
+ id="b">
+ <g
+ filter="url(#a)"
+ id="g1285">
+ <path
+ d="M 0,0 H 16 V 16 H 0 Z"
+ fill-opacity="0.3"
+ id="path1283" />
+ </g>
+ </mask>
+ <filter
+ id="filter3679"
+ height="1"
+ width="1"
+ x="0"
+ y="0">
+ <feColorMatrix
+ in="SourceGraphic"
+ type="matrix"
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
+ id="feColorMatrix3677" />
+ </filter>
+ </defs>
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="g3929">
+ <path
+ id="rect3921"
+ style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1"
+ d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 100 L 0 110 L 0 135 C 0 151.61996 13.380034 165 30 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 110 L 180 100 L 180 45 C 180 28.380034 166.61996 15 150 15 L 30 15 z M 35 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 100 L 20 100 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 20 110 L 160 110 L 160 130 C 160 138.30998 153.30998 145 145 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 110 z " />
+ <path
+ id="rect3923"
+ style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 20 110 L 20 130 C 20 138.30999 26.690008 145 35 145 L 145 145 C 153.30999 145 160 138.30999 160 130 L 160 110 L 20 110 z " />
+ </g>
+</svg>
diff --git a/src/data/images/dock-station-left-symbolic.svg b/src/data/images/dock-station-left-symbolic.svg
new file mode 100644
index 0000000..0f90e8f
--- /dev/null
+++ b/src/data/images/dock-station-left-symbolic.svg
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="180"
+ height="180"
+ viewBox="0 0 180 180"
+ version="1.1"
+ id="svg5"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ sodipodi:docname="dock-station-left-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="true"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="false"
+ inkscape:zoom="4.4555556"
+ inkscape:cx="88.541146"
+ inkscape:cy="89.999999"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1" />
+ <defs
+ id="defs2" />
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ id="rect254"
+ style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1"
+ d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 135 C 0 151.61996 13.380034 165 30 165 L 65 165 L 75 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 45 C 180 28.380034 166.61996 15 150 15 L 75 15 L 65 15 L 30 15 z M 35 35 L 65 35 L 65 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 75 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 130 C 160 138.30998 153.30998 145 145 145 L 75 145 L 75 35 z " />
+ <path
+ id="rect390"
+ style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 35 35 C 26.690008 35 20 41.690008 20 50 L 20 130 C 20 138.30999 26.690008 145 35 145 L 65 145 L 65 35 L 35 35 z " />
+ </g>
+</svg>
diff --git a/src/data/images/dock-station-right-symbolic.svg b/src/data/images/dock-station-right-symbolic.svg
new file mode 100644
index 0000000..774476a
--- /dev/null
+++ b/src/data/images/dock-station-right-symbolic.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="180"
+ height="180"
+ viewBox="0 0 180 180"
+ version="1.1"
+ id="svg5"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ sodipodi:docname="dock-station-right-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="true"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="false"
+ inkscape:zoom="4.4555556"
+ inkscape:cx="86.408977"
+ inkscape:cy="89.999999"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1" />
+ <defs
+ id="defs2" />
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ id="rect254"
+ style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1"
+ d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 135 C 0 151.61996 13.380034 165 30 165 L 105 165 L 115 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 45 C 180 28.380034 166.61996 15 150 15 L 115 15 L 105 15 L 30 15 z M 35 35 L 105 35 L 105 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 115 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 130 C 160 138.30998 153.30998 145 145 145 L 115 145 L 115 35 z " />
+ <path
+ id="rect390"
+ style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 115 35 L 115 145 L 145 145 C 153.30999 145 160 138.30999 160 130 L 160 50 C 160 41.690008 153.30999 35 145 35 L 115 35 z " />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Calque 2"
+ style="display:none;opacity:0.700936">
+ <g
+ fill="#2e3436"
+ id="g182"
+ transform="matrix(11.328515,0,0,10.683311,-1.25624,4.6587097)"
+ style="stroke-width:0.0908993">
+ <path
+ d="m 6.5,13.988281 v -12 h -5 v 12 z m 0,0"
+ fill-opacity="0.35"
+ id="path176"
+ style="stroke-width:0.00826268" />
+ <path
+ d="m 3,0.988281 c -1.644531,0 -3,1.355469 -3,3 v 8 c 0,1.644531 1.355469,3 3,3 h 10 c 1.644531,0 3,-1.355469 3,-3 v -8 c 0,-1.644531 -1.355469,-3 -3,-3 z m 0,2 h 10 c 0.570312,0 1,0.429688 1,1 v 8 c 0,0.570313 -0.429688,1 -1,1 H 3 c -0.570312,0 -1,-0.429687 -1,-1 v -8 c 0,-0.570312 0.429688,-1 1,-1 z m 0,0"
+ id="path178"
+ style="stroke-width:0.0908993" />
+ <path
+ d="m 6,1.988281 h 1 v 12 H 6 Z m 0,0"
+ id="path180"
+ style="stroke-width:0.0908993" />
+ </g>
+ </g>
+</svg>
diff --git a/src/data/images/gresource.xml b/src/data/images/gresource.xml
new file mode 100644
index 0000000..25c8274
--- /dev/null
+++ b/src/data/images/gresource.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/re/chrysalide/framework/gui/dialogs/about">
+ <file compressed="true" alias="bg.png">about-bg.png</file>
+ </gresource>
+ <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions">
+ <file compressed="true">dock-station-left-symbolic.svg</file>
+ <file compressed="true">dock-station-right-symbolic.svg</file>
+ <file compressed="true">dock-station-bottom-symbolic.svg</file>
+ <file compressed="true">logs-symbolic.svg</file>
+ </gresource>
+</gresources>
diff --git a/src/data/images/logs-symbolic.svg b/src/data/images/logs-symbolic.svg
new file mode 100644
index 0000000..f541607
--- /dev/null
+++ b/src/data/images/logs-symbolic.svg
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="180"
+ height="180"
+ viewBox="0 0 180 180"
+ version="1.1"
+ id="svg5"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ sodipodi:docname="logs-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="px"
+ showgrid="false"
+ inkscape:zoom="3.9657403"
+ inkscape:cx="110.44596"
+ inkscape:cy="77.413036"
+ inkscape:window-width="1920"
+ inkscape:window-height="1011"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1" />
+ <defs
+ id="defs2" />
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="fill:#25ff4c;fill-opacity:1">
+ <path
+ id="rect495"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:1.99999;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ d="M 45 0 C 31.150014 0 20 11.150014 20 25 L 20 155 C 20 168.84999 31.150014 180 45 180 L 155 180 C 168.84999 180 180 168.84999 180 155 L 180 25 C 180 11.150014 168.84999 0 155 0 L 45 0 z M 55 10 L 145 10 C 158.84999 10 170 21.150014 170 35 L 170 145 C 170 158.84999 158.84999 170 145 170 L 55 170 C 41.150014 170 30 158.84999 30 145 L 30 35 C 30 21.150014 41.150014 10 55 10 z " />
+ <rect
+ style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ id="rect3619"
+ width="75"
+ height="12"
+ x="62.5"
+ y="84"
+ rx="6"
+ ry="6" />
+ <rect
+ style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ id="rect5029"
+ width="75"
+ height="12"
+ x="62.5"
+ y="127"
+ rx="6"
+ ry="6" />
+ <rect
+ style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ id="rect5031"
+ width="75"
+ height="12"
+ x="62.5"
+ y="41"
+ rx="6"
+ ry="6" />
+ <rect
+ style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ id="rect5049"
+ width="34"
+ height="12"
+ x="8.2744884"
+ y="41"
+ rx="6"
+ ry="6" />
+ <rect
+ style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
+ id="rect5051"
+ width="34"
+ height="12"
+ x="8.2744884"
+ y="127"
+ rx="6"
+ ry="6" />
+ </g>
+</svg>
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index 738f5b3..b0a7c31 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -4,8 +4,6 @@ BUILT_SOURCES = chrysamarshal.h chrysamarshal.c resources.h resources.c
noinst_LTLIBRARIES = libglibext.la libglibextui.la
# libglibext_la_SOURCES = \
-# comparison-int.h \
-# comparison.h comparison.c \
# configuration-int.h \
# configuration.h configuration.c \
# gbinarycursor.h gbinarycursor.c \
@@ -16,7 +14,6 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la
# \
# proto.h \
# seq.h seq.c \
-# _signal.h signal.c \
# singleton.h singleton.c \
# linetoken.h linetoken.c \
# umemslice-int.h \
@@ -40,15 +37,30 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la
libglibext_la_SOURCES = \
chrysamarshal.h chrysamarshal.c \
+ comparable-int.h \
+ comparable.h comparable.c \
+ hashable-int.h \
+ hashable.h hashable.c \
helpers.h \
+ log-int.h \
+ log.h log.c \
objhole-int.h \
objhole.h objhole.c \
portion-int.h \
portion.h portion.c \
+ secstorage-int.h \
+ secstorage.h secstorage.c \
+ serialize-int.h \
+ serialize.h serialize.c \
+ sigredir.h sigredir.c \
singleton-int.h \
singleton.h singleton.c \
+ storage-int.h \
+ storage.h storage.c \
strbuilder-int.h \
strbuilder.h strbuilder.c \
+ tpmem-int.h \
+ tpmem.h tpmem.c \
work-int.h \
work.h work.c \
workgroup-int.h \
@@ -56,7 +68,7 @@ libglibext_la_SOURCES = \
workqueue-int.h \
workqueue.h workqueue.c
-libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS)
+libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBZIP_CFLAGS)
RES_FILES = \
diff --git a/src/glibext/bufferline.c b/src/glibext/bufferline.c
index 4862e9f..e3fb27b 100644
--- a/src/glibext/bufferline.c
+++ b/src/glibext/bufferline.c
@@ -24,14 +24,16 @@
#include "bufferline.h"
+#include <assert.h>
+#include <malloc.h>
+
+
#include "bufferline-int.h"
#if 0
-#include <assert.h>
-#include <malloc.h>
#include <string.h>
@@ -273,158 +275,12 @@ bool g_buffer_line_create(GBufferLine *line, size_t col_count)
}
-
-
-
-
-
-
-
-/******************************************************************************
-* *
-* Paramètres : line = ligne à venir compléter. *
-* column = colonne de la ligne visée par l'insertion. *
-* tag = type de décorateur à utiliser. *
-* text = texte à insérer dans l'existant. *
-* length = taille du texte à traiter. *
-* style = gestionnaire de paramètres de rendu à consulter. *
-* creator = instance GLib quelconque à associer. *
-* *
-* Description : Ajoute du texte à formater dans une ligne donnée. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_buffer_line_append_text(GBufferLine *line, size_t column, TokenRenderingTag tag, const char *text, size_t length, const GTokenStyle *style, GObject *creator)
-{
- size_t index; /* Indice d'insertion */
- //content_origin *origin; /* Définition d'une origine */
-
- assert(column < line->col_count);
- assert(length > 0);
-
- index = append_text_to_line_column(&line->columns[column], tag, text, length, style);
-
- /*
- if (creator != NULL)
- {
- line->origins = realloc(line->origins, ++line->ocount * sizeof(content_origin));
-
- origin = &line->origins[line->ocount - 1];
-
- origin->coord.column = column;
- origin->coord.index = index;
-
- origin->creator = creator;
- g_object_ref(G_OBJECT(creator));
-
- }
- */
-
-}
-
-
-
-
-
-
-
-
-
-
-
-/******************************************************************************
-* *
-* Paramètres : line = ligne de texte à manipuler. *
-* cr = contexte graphique dédié à la procédure. *
-* column = (première) colonne à traiter. *
-* y = ordonnée du point d'impression. *
-* style = style de rendu pour les bribes de texte. *
-* *
-* Description : Imprime la ligne de texte représentée. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int y, const GTokenStyle *style)
-{
-#if 0
- GBufferLineClass *class; /* Stockage de briques de base */
- bool has_src_surface; /* Note une présence définie */
-#endif
- size_t max_column; /* Borne de fin des colonnes */
- int x; /* Point de départ d'impression*/
- size_t i; /* Boucle de parcours */
-
- /*
- if (line->flags != BLF_NONE)
- {
- class = G_BUFFER_LINE_GET_CLASS(line);
-
- if (line->flags & BLF_ENTRYPOINT)
- {
- cairo_set_source_surface(cairo, class->entrypoint_img, 5, y);
- has_src_surface = true;
- }
- else if (line->flags & BLF_BOOKMARK)
- {
- cairo_set_source_surface(cairo, class->bookmark_img, 5, y);
- has_src_surface = true;
- }
- else
- has_src_surface = false;
-
- if (has_src_surface)
- cairo_paint(cairo);
-
- }
- */
-
-
- /* Détermination de l'éventail des colonnes à traiter */
-
- if (column == line->merge_start)
- max_column = line->col_count;
-
- else if (column > line->merge_start)
- max_column = 0;
-
- else
- max_column = column + 1;
-
- /* Dessin du contenu de ces colonnes */
-
- x = 0;
-
- for (i = column; i < max_column; i++)
- draw_line_column(&line->columns[i], cr, &x, y, style);
-
-}
-
-
-
-
-
-
-
-
-
-
-#if 0
-
-
/******************************************************************************
* *
-* Paramètres : line = ligne à venir compléter. *
-* col = indice de la colonne à constituer. *
-* size = taille souhaitée de l'impression des positions. *
-* addr = localisation physique à venir représenter. *
+* Paramètres : line = ligne à venir compléter. *
+* column = indice de la colonne visée par l'insertion. *
+* size = taille souhaitée de l'impression des positions. *
+* addr = localisation physique à venir représenter. *
* *
* Description : Construit le tronc commun d'une ligne autour de sa position. *
* *
@@ -434,7 +290,7 @@ void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int
* *
******************************************************************************/
-void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size, const vmpa2t *addr)
+void g_buffer_line_fill_physical(GBufferLine *line, size_t column, MemoryDataSize size, const vmpa2t *addr)
{
VMPA_BUFFER(position); /* Emplacement au format texte */
size_t len; /* Taille de l'élément inséré */
@@ -448,20 +304,22 @@ void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size,
if (i == len)
i = len - 1;
+ assert(column < line->col_count);
+
if (i > 0)
- g_buffer_line_append_text(line, col, position, i, RTT_PHYS_ADDR_PAD, NULL);
+ g_buffer_line_append_text(line, column, TRT_PHYS_ADDR_PAD, position, i, NULL, NULL);
- g_buffer_line_append_text(line, col, &position[i], len - i, RTT_PHYS_ADDR, NULL);
+ g_buffer_line_append_text(line, column, TRT_PHYS_ADDR, &position[i], len - i, NULL, NULL);
}
/******************************************************************************
* *
-* Paramètres : line = ligne à venir compléter. *
-* col = indice de la colonne à constituer. *
-* size = taille souhaitée de l'impression des positions. *
-* addr = localisation virtuelle à venir représenter. *
+* Paramètres : line = ligne à venir compléter. *
+* column = indice de la colonne visée par l'insertion. *
+* size = taille souhaitée de l'impression des positions. *
+* addr = localisation virtuelle à venir représenter. *
* *
* Description : Construit le tronc commun d'une ligne autour de sa position. *
* *
@@ -471,7 +329,7 @@ void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size,
* *
******************************************************************************/
-void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, const vmpa2t *addr)
+void g_buffer_line_fill_virtual(GBufferLine *line, size_t column, MemoryDataSize size, const vmpa2t *addr)
{
VMPA_BUFFER(position); /* Emplacement au format texte */
size_t len; /* Taille de l'élément inséré */
@@ -479,6 +337,8 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size,
vmpa2_virt_to_string(addr, size, position, &len);
+ assert(column < line->col_count);
+
if (has_virt_addr(addr))
{
for (i = 2; i < len; i++)
@@ -488,14 +348,14 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size,
i = len - 1;
if (i > 0)
- g_buffer_line_append_text(line, col, position, i, RTT_VIRT_ADDR_PAD, NULL);
+ g_buffer_line_append_text(line, column, TRT_VIRT_ADDR_PAD, position, i, NULL, NULL);
- g_buffer_line_append_text(line, col, &position[i], len - i, RTT_VIRT_ADDR, NULL);
+ g_buffer_line_append_text(line, column, TRT_VIRT_ADDR, &position[i], len - i, NULL, NULL);
}
else
- g_buffer_line_append_text(line, col, position, len, RTT_VIRT_ADDR_PAD, NULL);
+ g_buffer_line_append_text(line, column, TRT_VIRT_ADDR_PAD, position, len, NULL, NULL);
}
@@ -503,7 +363,7 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size,
/******************************************************************************
* *
* Paramètres : line = ligne à venir compléter. *
-* col = indice de la colonne à constituer. *
+* column = indice de la colonne visée par l'insertion. *
* content = contenu binaire global à venir lire. *
* range = localisation des données à venir lire et présenter.*
* max = taille maximale de la portion binaire en octets. *
@@ -516,7 +376,7 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size,
* *
******************************************************************************/
-void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent *content, const mrange_t *range, phys_t max)
+void g_buffer_line_fill_content(GBufferLine *line, size_t column, const GBinContent *content, const mrange_t *range, phys_t max)
{
phys_t length; /* Taille de la couverture */
bool truncated; /* Indique si le code est coupé*/
@@ -548,7 +408,7 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent
if (required <= sizeof(static_buffer))
bin_code = static_buffer;
else
- bin_code = (char *)calloc(required, sizeof(char));
+ bin_code = calloc(required, sizeof(char));
/* Code brut */
@@ -589,7 +449,7 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent
/* Conclusion */
- g_buffer_line_append_text(line, col, bin_code, iter - bin_code, RTT_RAW_CODE, NULL);
+ g_buffer_line_append_text(line, column, TRT_RAW_CODE, bin_code, iter - bin_code, NULL, NULL);
if (bin_code != static_buffer)
free(bin_code);
@@ -599,6 +459,146 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent
/******************************************************************************
* *
+* Paramètres : line = ligne à venir compléter. *
+* column = colonne de la ligne visée par l'insertion. *
+* tag = type de décorateur à utiliser. *
+* text = texte à insérer dans l'existant. *
+* length = taille du texte à traiter. *
+* style = gestionnaire de paramètres de rendu à consulter. *
+* creator = instance GLib quelconque à associer. *
+* *
+* Description : Ajoute du texte à formater dans une ligne donnée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_buffer_line_append_text(GBufferLine *line, size_t column, TokenRenderingTag tag, const char *text, size_t length, const GTokenStyle *style, GObject *creator)
+{
+ size_t index; /* Indice d'insertion */
+ //content_origin *origin; /* Définition d'une origine */
+
+ assert(column < line->col_count);
+ assert(length > 0);
+
+ index = append_text_to_line_column(&line->columns[column], tag, text, length, style);
+
+ /*
+ if (creator != NULL)
+ {
+ line->origins = realloc(line->origins, ++line->ocount * sizeof(content_origin));
+
+ origin = &line->origins[line->ocount - 1];
+
+ origin->coord.column = column;
+ origin->coord.index = index;
+
+ origin->creator = creator;
+ g_object_ref(G_OBJECT(creator));
+
+ }
+ */
+
+}
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : line = ligne de texte à manipuler. *
+* cr = contexte graphique dédié à la procédure. *
+* column = (première) colonne à traiter. *
+* y = ordonnée du point d'impression. *
+* style = style de rendu pour les bribes de texte. *
+* *
+* Description : Imprime la ligne de texte représentée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int y, const GTokenStyle *style)
+{
+#if 0
+ GBufferLineClass *class; /* Stockage de briques de base */
+ bool has_src_surface; /* Note une présence définie */
+#endif
+ size_t max_column; /* Borne de fin des colonnes */
+ int x; /* Point de départ d'impression*/
+ size_t i; /* Boucle de parcours */
+
+ /*
+ if (line->flags != BLF_NONE)
+ {
+ class = G_BUFFER_LINE_GET_CLASS(line);
+
+ if (line->flags & BLF_ENTRYPOINT)
+ {
+ cairo_set_source_surface(cairo, class->entrypoint_img, 5, y);
+ has_src_surface = true;
+ }
+ else if (line->flags & BLF_BOOKMARK)
+ {
+ cairo_set_source_surface(cairo, class->bookmark_img, 5, y);
+ has_src_surface = true;
+ }
+ else
+ has_src_surface = false;
+
+ if (has_src_surface)
+ cairo_paint(cairo);
+
+ }
+ */
+
+
+ /* Détermination de l'éventail des colonnes à traiter */
+
+ if (column == line->merge_start)
+ max_column = line->col_count;
+
+ else if (column > line->merge_start)
+ max_column = 0;
+
+ else
+ max_column = column + 1;
+
+ /* Dessin du contenu de ces colonnes */
+
+ x = 0;
+
+ for (i = column; i < max_column; i++)
+ draw_line_column(&line->columns[i], cr, &x, y, style);
+
+}
+
+
+
+
+
+
+
+
+
+
+#if 0
+
+
+
+/******************************************************************************
+* *
* Paramètres : line = ligne à venir consulter. *
* column = indice de la colonne visée par les recherches. *
* *
diff --git a/src/glibext/bufferline.h b/src/glibext/bufferline.h
index d6a2e2d..e95ee2b 100644
--- a/src/glibext/bufferline.h
+++ b/src/glibext/bufferline.h
@@ -30,6 +30,8 @@
#include "helpers.h"
#include "tokenstyle.h"
+#include "../arch/vmpa.h"
+#include "../analysis/content.h"
@@ -45,8 +47,6 @@
#ifdef INCLUDE_GTK_SUPPORT
# include "widthtracker.h"
#endif
-#include "../analysis/content.h"
-#include "../arch/vmpa.h"
@@ -75,6 +75,9 @@ typedef struct _GBufferLineClass GBufferLineClass;
+
+
+
#define G_TYPE_BUFFER_LINE (g_buffer_line_get_type())
DECLARE_GTYPE(GBufferLine, g_buffer_line, G, BUFFER_LINE);
@@ -98,7 +101,14 @@ typedef enum _BufferLineFlags
/* Crée une nouvelle représentation de fragments de texte. */
GBufferLine *g_buffer_line_new(size_t);
+/* Construit le tronc commun d'une ligne autour de sa position. */
+void g_buffer_line_fill_physical(GBufferLine *, size_t, MemoryDataSize, const vmpa2t *);
+
+/* Construit le tronc commun d'une ligne autour de sa position. */
+void g_buffer_line_fill_virtual(GBufferLine *, size_t, MemoryDataSize, const vmpa2t *);
+/* Construit le tronc commun d'une ligne autour de son contenu. */
+void g_buffer_line_fill_content(GBufferLine *, size_t, const GBinContent *, const mrange_t *, phys_t);
/* Ajoute du texte à formater dans une ligne donnée. */
void g_buffer_line_append_text(GBufferLine *, size_t, TokenRenderingTag, const char *, size_t, const GTokenStyle *, GObject *);
diff --git a/src/glibext/comparable-int.h b/src/glibext/comparable-int.h
new file mode 100644
index 0000000..18972c2
--- /dev/null
+++ b/src/glibext/comparable-int.h
@@ -0,0 +1,47 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparable-int.h - définitions internes propres aux opérations de comparaison d'objets
+ *
+ * Copyright (C) 2022-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_COMPARABLE_INT_H
+#define _GLIBEXT_COMPARABLE_INT_H
+
+
+#include "comparable.h"
+
+
+
+/* Réalise une comparaison étendue entre objets. */
+typedef int (* compare_object_fc) (const GComparableObject *, const GComparableObject *);
+
+
+/* Instance d'objet comparable (interface) */
+struct _GComparableObjectInterface
+{
+ GTypeInterface base_iface; /* A laisser en premier */
+
+ compare_object_fc compare; /* Comparaison étendue */
+
+};
+
+
+
+#endif /* _GLIBEXT_COMPARABLE_INT_H */
diff --git a/src/glibext/comparable.c b/src/glibext/comparable.c
new file mode 100644
index 0000000..40fd110
--- /dev/null
+++ b/src/glibext/comparable.c
@@ -0,0 +1,124 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparable.c - opérations de comparaison d'objets
+ *
+ * Copyright (C) 2022-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "comparable.h"
+
+
+#include "comparable-int.h"
+#include "../common/sort.h"
+
+
+
+/* Procède à l'initialisation de l'interface de comparaison. */
+static void g_comparable_object_default_init(GComparableObjectInterface *);
+
+
+
+/* Détermine le type d'une interface pour un objet comparable. */
+G_DEFINE_INTERFACE(GComparableObject, g_comparable_object, 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_object_default_init(GComparableObjectInterface *iface)
+{
+ iface->compare = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* *
+* Description : Réalise une comparaison étendue entre objets. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int g_comparable_object_compare(const GComparableObject *object, const GComparableObject *other)
+{
+ int result; /* Bilan à retourner */
+ GType type_a; /* Type de l'object A */
+ GType type_b; /* Type de l'object B */
+ GComparableObjectInterface *iface; /* Interface utilisée */
+
+ type_a = G_OBJECT_TYPE(G_OBJECT(object));
+ type_b = G_OBJECT_TYPE(G_OBJECT(other));
+
+ assert(sizeof(GType) <= sizeof(unsigned long));
+
+ result = sort_unsigned_long(type_a, type_b);
+
+ if (result == 0)
+ {
+ iface = G_COMPARABLE_OBJECT_GET_IFACE(object);
+
+ result = iface->compare(object, other);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
+* *
+* Description : Détermine si deux objets sont fonctionnellement identiques. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gboolean g_comparable_object_is_equal(const GComparableObject *object, const GComparableObject *other)
+{
+ gboolean result; /* Bilan à renvoyer */
+ int ret; /* Bilan d'une comparaison */
+
+ ret = g_comparable_object_compare(object, other);
+
+ result = (ret == 0);
+
+ return result;
+
+}
diff --git a/src/glibext/comparable.h b/src/glibext/comparable.h
new file mode 100644
index 0000000..7a652ff
--- /dev/null
+++ b/src/glibext/comparable.h
@@ -0,0 +1,46 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparable.h - prototypes pour les opérations de comparaison d'objets
+ *
+ * Copyright (C) 2022-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_COMPARABLE_H
+#define _GLIBEXT_COMPARABLE_H
+
+
+#include "helpers.h"
+
+
+
+#define G_TYPE_COMPARABLE_OBJECT (g_comparable_object_get_type())
+
+DECLARE_INTERFACE(GComparableObject, g_comparable_object, G, COMPARABLE_OBJECT);
+
+
+
+/* Réalise une comparaison étendue entre objets. */
+int g_comparable_object_compare(const GComparableObject *, const GComparableObject *);
+
+/* Détermine si deux objets sont fonctionnellement identiques. */
+gboolean g_comparable_object_is_equal(const GComparableObject *, const GComparableObject *);
+
+
+
+#endif /* _GLIBEXT_COMPARABLE_H */
diff --git a/src/glibext/comparison-int.h b/src/glibext/comparison-int.h
deleted file mode 100644
index 446f25d..0000000
--- a/src/glibext/comparison-int.h
+++ /dev/null
@@ -1,58 +0,0 @@
-
-/* 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
deleted file mode 100644
index 8ce6941..0000000
--- a/src/glibext/comparison.c
+++ /dev/null
@@ -1,199 +0,0 @@
-
-/* 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
deleted file mode 100644
index 8d43210..0000000
--- a/src/glibext/comparison.h
+++ /dev/null
@@ -1,80 +0,0 @@
-
-/* 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/hashable-int.h b/src/glibext/hashable-int.h
new file mode 100644
index 0000000..f8a85e1
--- /dev/null
+++ b/src/glibext/hashable-int.h
@@ -0,0 +1,47 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hashable-int.h - définitions internes propres aux calculs de l'empreinte d'un objet
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_HASHABLE_INT_H
+#define _GLIBEXT_HASHABLE_INT_H
+
+
+#include "hashable.h"
+
+
+
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+typedef guint (* hash_object_fc) (const GHashableObject *);
+
+
+/* Instance d'objet visant à être unique (interface) */
+struct _GHashableObjectInterface
+{
+ GTypeInterface base_iface; /* A laisser en premier */
+
+ hash_object_fc hash; /* Réduction en valeur */
+
+};
+
+
+
+#endif /* _GLIBEXT_HASHABLE_INT_H */
diff --git a/src/glibext/hashable.c b/src/glibext/hashable.c
new file mode 100644
index 0000000..f988a90
--- /dev/null
+++ b/src/glibext/hashable.c
@@ -0,0 +1,82 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hashable.c - calculs de l'empreinte d'un objet
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "hashable.h"
+
+
+#include "hashable-int.h"
+
+
+
+/* Procède à l'initialisation de l'interface de détermination. */
+static void g_hashable_object_default_init(GHashableObjectInterface *);
+
+
+
+/* Détermine le type d'une interface pour la réduction d'un objet à une valeur. */
+G_DEFINE_INTERFACE(GHashableObject, g_hashable_object, G_TYPE_OBJECT)
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface de détermination. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hashable_object_default_init(GHashableObjectInterface *iface)
+{
+ iface->hash = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = objet dont l'instance est à consulter. *
+* *
+* Description : Calcule l'empreinte sur 32 bits d'un objet. *
+* *
+* Retour : Valeur de représentation, unique pour l'objet ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+guint g_hashable_object_hash(const GHashableObject *object)
+{
+ guint result; /* Valeur à retourner */
+ GHashableObjectInterface *iface; /* Interface utilisée */
+
+ iface = G_HASHABLE_OBJECT_GET_IFACE(object);
+
+ result = iface->hash(object);
+
+ return result;
+
+}
diff --git a/src/glibext/hashable.h b/src/glibext/hashable.h
new file mode 100644
index 0000000..165c744
--- /dev/null
+++ b/src/glibext/hashable.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hashable.h - prototypes pour les calculs de l'empreinte d'un objet
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_HASHABLE_H
+#define _GLIBEXT_HASHABLE_H
+
+
+#include "helpers.h"
+
+
+
+#define G_TYPE_HASHABLE_OBJECT (g_hashable_object_get_type())
+
+DECLARE_INTERFACE(GHashableObject, g_hashable_object, G, HASHABLE_OBJECT);
+
+
+/* Calcule l'empreinte sur 32 bits d'un objet. */
+guint g_hashable_object_hash(const GHashableObject *);
+
+
+
+#endif /* _GLIBEXT_HASHABLE_H */
diff --git a/src/glibext/helpers.h b/src/glibext/helpers.h
index cfcc85b..6176245 100644
--- a/src/glibext/helpers.h
+++ b/src/glibext/helpers.h
@@ -29,6 +29,9 @@
#include <glib-object.h>
+#include "../common/compiler.h"
+
+
/**
* Les définitions issues de <glib-2.80>/gobject/gtype.h fournissent des macros
@@ -118,6 +121,31 @@
}
+/**
+ * Définition sous condition d'une inclusion d'interface. Cette inclusion se réalise
+ * lorsque la fonction d'initialisation renseignée est définie.
+ *
+ * Cette version étendue de la macro G_IMPLEMENT_INTERFACE d'origine est principalement
+ * pour les raffinements d'objets en forme graphique.
+ */
+
+#define G_IMPLEMENT_INTERFACE_IF_SYM(iface_tp_getter, iface_init) \
+ do \
+ { \
+ extern GType iface_tp_getter(void) __weak; \
+ extern void iface_init(GTypeInterface *, gpointer) __weak; \
+ if (&iface_tp_getter != NULL && &iface_init != NULL) \
+ { \
+ GType iface_type = iface_tp_getter(); \
+ const GInterfaceInfo implementation_info = { \
+ (GInterfaceInitFunc)(void (*)(void))iface_init, NULL, NULL \
+ }; \
+ g_type_add_interface_static(g_define_type_id, iface_type, &implementation_info);\
+ } \
+ } \
+ while (0);
+
+
/**
* Les principales fonctions incrémentant ou réduisant le nombre de références
diff --git a/src/glibext/log-int.h b/src/glibext/log-int.h
new file mode 100644
index 0000000..3b3208a
--- /dev/null
+++ b/src/glibext/log-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * log-int.h - prototypes internes pour la conservation à destination graphique des éléments de journalisation
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_LOG_INT_H
+#define _GLIBEXT_LOG_INT_H
+
+
+#include <stdbool.h>
+
+
+#include "log.h"
+
+
+
+/* Définition d'une conservation d'objets construits (instance) */
+struct _GLogEntry
+{
+ GObject parent; /* A laisser en premier */
+
+ LogMessageType type; /* Type de message porté */
+ char *msg; /* Contenu du message diffusé */
+
+};
+
+/* Définition d'une conservation d'objets construits (classe) */
+struct _GLogEntryClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une conservation pour élément de journalisation. */
+bool g_log_entry_create(GLogEntry *, LogMessageType, const char *);
+
+
+
+#endif /* _GLIBEXT_LOG_INT_H */
diff --git a/src/glibext/log.c b/src/glibext/log.c
new file mode 100644
index 0000000..039172c
--- /dev/null
+++ b/src/glibext/log.c
@@ -0,0 +1,306 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * log.c - conservation hors mémoire d'objets choisis
+ *
+ * Copyright (C) 2020-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 <malloc.h>
+#include <string.h>
+
+
+#include "log-int.h"
+
+
+
+/* ---------------------------- ENTREE DE JOURNALISATION ---------------------------- */
+
+
+/* Liste des propriétés */
+
+typedef enum _LogEntryProperty {
+
+ PROP_0, /* Réservé */
+
+ PROP_ICON_NAME, /* Nom d'image de représentat° */
+ PROP_MESSAGE, /* Contenu du message diffusé */
+
+ N_PROPERTIES
+
+} LogEntryProperty;
+
+static GParamSpec *_log_entry_properties[N_PROPERTIES] = { NULL, };
+
+
+/* Initialise la classe des conservations d'objets en place. */
+static void g_log_entry_class_init(GLogEntryClass *);
+
+/* Initialise une instance de conservation d'objets en place. */
+static void g_log_entry_init(GLogEntry *);
+
+/* Supprime toutes les références externes. */
+static void g_log_entry_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_log_entry_finalize(GObject *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_log_entry_get_property(GObject *, guint, GValue *, GParamSpec *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ENTREE DE JOURNALISATION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conservation d'objets construits. */
+G_DEFINE_TYPE(GLogEntry, g_log_entry, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des conservations d'objets en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_log_entry_class_init(GLogEntryClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = g_log_entry_dispose;
+ object->finalize = g_log_entry_finalize;
+ object->get_property = gtk_log_entry_get_property;
+
+ _log_entry_properties[PROP_ICON_NAME] =
+ g_param_spec_string("icon-name", NULL, NULL,
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ _log_entry_properties[PROP_MESSAGE] =
+ g_param_spec_string("message", NULL, NULL,
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _log_entry_properties);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : entry = instance à initialiser. *
+* *
+* Description : Initialise une instance de conservation d'objets en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_log_entry_init(GLogEntry *entry)
+{
+ entry->type = LMT_COUNT;
+ entry->msg = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_log_entry_dispose(GObject *object)
+{
+ G_OBJECT_CLASS(g_log_entry_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_log_entry_finalize(GObject *object)
+{
+ GLogEntry *entry; /* Version spécialisée */
+
+ entry = G_LOG_ENTRY(object);
+
+ if (entry->msg != NULL)
+ free(entry->msg);
+
+ G_OBJECT_CLASS(g_log_entry_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = espèce du message à représenter. *
+* msg = message à faire apparaître à l'écran. *
+* *
+* Description : Crée une conservation pour un élément de journalisation. *
+* *
+* Retour : Conservation mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GLogEntry *g_log_entry_new(LogMessageType type, const char *msg)
+{
+ GLogEntry *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_LOG_ENTRY, NULL);
+
+ if (!g_log_entry_create(result, type, msg))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : entry = instance de conservation à initialiser pleinement. *
+* type = espèce du message à représenter. *
+* msg = message à faire apparaître à l'écran. *
+* *
+* Description : Met en place une conservation pour élément de journalisation.*
+* *
+* Retour : Conservation mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_log_entry_create(GLogEntry *entry, LogMessageType type, const char *msg)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ entry->type = type;
+ entry->msg = strdup(msg);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_log_entry_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GLogEntry *entry; /* Version spécialisée */
+
+ entry = G_LOG_ENTRY(object);
+
+ switch (prop_id)
+ {
+ case PROP_ICON_NAME:
+ switch (entry->type)
+ {
+ case LMT_INFO:
+ g_value_set_string(value, "dialog-information-symbolic");
+ break;
+
+ case LMT_PROCESS:
+ g_value_set_string(value, "system-run-symbolic");
+ break;
+
+ case LMT_WARNING:
+ case LMT_BAD_BINARY:
+ g_value_set_string(value, "dialog-warning-symbolic");
+ break;
+
+ case LMT_ERROR:
+ case LMT_EXT_ERROR:
+ g_value_set_string(value, "computer-fail-symbolic");
+ break;
+
+
+ case LMT_COUNT:
+ g_value_set_string(value, "dialog-question-symbolic");
+ break;
+
+ }
+ break;
+
+ case PROP_MESSAGE:
+ g_value_set_string(value, entry->msg);
+ break;
+
+ }
+
+}
diff --git a/src/glibext/log.h b/src/glibext/log.h
new file mode 100644
index 0000000..472773c
--- /dev/null
+++ b/src/glibext/log.h
@@ -0,0 +1,43 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * log.h - prototypes pour la conservation à destination graphique des éléments de journalisation
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_LOG_H
+#define _GLIBEXT_LOG_H
+
+
+#include "helpers.h"
+#include "../core/logs.h"
+
+
+
+#define G_TYPE_LOG_ENTRY (g_log_entry_get_type())
+
+DECLARE_GTYPE(GLogEntry, g_log_entry, G, LOG_ENTRY);
+
+
+/* Crée une conservation pour un élément de journalisation. */
+GLogEntry *g_log_entry_new(LogMessageType, const char *);
+
+
+
+#endif /* _GLIBEXT_LOG_H */
diff --git a/src/glibext/objhole-int.h b/src/glibext/objhole-int.h
index b4abf6f..dbfb412 100644
--- a/src/glibext/objhole-int.h
+++ b/src/glibext/objhole-int.h
@@ -105,6 +105,9 @@
#endif
+#define GOBJECT_LOCK_BIT 3
+
+
/* Nouvelle version dense des objets (instance) */
typedef struct _GThickObject
{
@@ -142,23 +145,23 @@ struct _GThickObjectClass
/* GLib 2.83.0 - cfa36f5e9 */
#define GOBJECT_RESERVED_EXTRA_BITS 5
-#define GET_GOBJECT_EXTRA(obj, tp) \
- ({ \
- BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \
- tp *___result; \
- guint __val; \
- __val = g_thick_object_get_extra(obj); \
- ___result = (tp *)(guint []){ __val }; \
- ___result; \
+#define GET_GOBJECT_EXTRA(obj, tp) \
+ ({ \
+ BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \
+ tp ___result; \
+ guint __val; \
+ __val = g_thick_object_get_extra(G_THICK_OBJECT(obj)); \
+ ___result = *(tp *)(guint []){ __val }; \
+ ___result; \
})
-#define SET_GOBJECT_EXTRA(obj, tp, data) \
- ({ \
- BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \
- BUILD_BUG_ON(sizeof(data) > sizeof(guint *)); \
- guint __val; \
- __val = *(guint *)data; \
- g_thick_object_set_extra(obj, __val); \
+#define SET_GOBJECT_EXTRA(obj, tp, data) \
+ ({ \
+ BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \
+ BUILD_BUG_ON(sizeof(data) > sizeof(guint *)); \
+ guint __val; \
+ __val = *(guint *)data; \
+ g_thick_object_set_extra(G_THICK_OBJECT(obj), __val); \
})
diff --git a/src/glibext/objhole.c b/src/glibext/objhole.c
index 20bb2a8..fd6fbc9 100644
--- a/src/glibext/objhole.c
+++ b/src/glibext/objhole.c
@@ -38,10 +38,10 @@ static void g_thick_object_class_init(GThickObjectClass *);
static void g_thick_object_init(GThickObject *);
/* Supprime toutes les références externes. */
-static void g_thick_object_dispose(GThickObject *);
+static void g_thick_object_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_thick_object_finalize(GThickObject *);
+static void g_thick_object_finalize(GObject *);
@@ -66,8 +66,8 @@ static void g_thick_object_class_init(GThickObjectClass *klass)
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_thick_object_dispose;
- object->finalize = (GObjectFinalizeFunc)g_thick_object_finalize;
+ object->dispose = g_thick_object_dispose;
+ object->finalize = g_thick_object_finalize;
}
@@ -93,7 +93,7 @@ static void g_thick_object_init(GThickObject *obj)
/******************************************************************************
* *
-* Paramètres : obj = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -103,16 +103,16 @@ static void g_thick_object_init(GThickObject *obj)
* *
******************************************************************************/
-static void g_thick_object_dispose(GThickObject *obj)
+static void g_thick_object_dispose(GObject *object)
{
- G_OBJECT_CLASS(g_thick_object_parent_class)->dispose(G_OBJECT(obj));
+ G_OBJECT_CLASS(g_thick_object_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : obj = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -122,15 +122,80 @@ static void g_thick_object_dispose(GThickObject *obj)
* *
******************************************************************************/
-static void g_thick_object_finalize(GThickObject *obj)
+static void g_thick_object_finalize(GObject *object)
{
- G_OBJECT_CLASS(g_thick_object_parent_class)->finalize(G_OBJECT(obj));
+ G_OBJECT_CLASS(g_thick_object_parent_class)->finalize(object);
}
/******************************************************************************
* *
+* Paramètres : obj = instance d'objet GLib à manipuler. *
+* *
+* Description : Pose un verrou à l'aide du bit dédié de GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_thick_object_lock(GThickObject *obj)
+{
+ g_bit_lock((gint *)&obj->extra, GOBJECT_LOCK_BIT);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : obj = instance d'objet GLib à manipuler. *
+* *
+* Description : Retire un verrou via le bit dédié de GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_thick_object_unlock(GThickObject *obj)
+{
+ g_bit_unlock((gint *)&obj->extra, GOBJECT_LOCK_BIT);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : obj = instance d'objet GLib à manipuler. *
+* *
+* Description : Vérifie qu'un verrou est appliqué à l'aide du bit de GObject.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+#ifndef NDEBUG
+bool g_thick_object_check_lock(GThickObject *obj)
+{
+ bool result; /* Bilan à retourner */
+ gboolean status; /* Bilan d'une tentative */
+
+ status = g_bit_trylock((gint *)&obj->extra, GOBJECT_LOCK_BIT);
+
+ result = (status == FALSE);
+
+ return result;
+
+}
+#endif
+
+
+/******************************************************************************
+* *
* Paramètres : obj = instance d'objet GLib à consulter. *
* *
* Description : Fournit la valeur courante de la zone de stockage d'un objet.*
diff --git a/src/glibext/objhole.h b/src/glibext/objhole.h
index c1e8cf1..461c37a 100644
--- a/src/glibext/objhole.h
+++ b/src/glibext/objhole.h
@@ -25,6 +25,11 @@
#define _GLIBEXT_OBJHOLE_H
+#ifndef NDEBUG
+# include <stdbool.h>
+#endif
+
+
#include "../glibext/helpers.h"
@@ -34,6 +39,17 @@
DECLARE_GTYPE(GThickObject, g_thick_object, G, THICK_OBJECT);
+/* Pose un verrou à l'aide du bit dédié de GObject. */
+void g_thick_object_lock(GThickObject *);
+
+/* Retire un verrou via le bit dédié de GObject. */
+void g_thick_object_unlock(GThickObject *);
+
+/* Vérifie qu'un verrou est appliqué à l'aide du bit de GObject. */
+#ifndef NDEBUG
+bool g_thick_object_check_lock(GThickObject *obj);
+#endif
+
/* Fournit la valeur courante de la zone de stockage d'un objet. */
guint g_thick_object_get_extra(const GThickObject *);
diff --git a/src/glibext/options/Makefile.am b/src/glibext/options/Makefile.am
index 448de7b..3f400c6 100644
--- a/src/glibext/options/Makefile.am
+++ b/src/glibext/options/Makefile.am
@@ -2,7 +2,8 @@
noinst_LTLIBRARIES = libglibextoptions.la
-libglibextoptions_la_SOURCES = \
+libglibextoptions_la_SOURCES = \
+ asm.h \
hex.h hex.c
libglibextoptions_la_CFLAGS = $(TOOLKIT_CFLAGS)
diff --git a/src/glibext/options/asm.h b/src/glibext/options/asm.h
new file mode 100644
index 0000000..d7a2c86
--- /dev/null
+++ b/src/glibext/options/asm.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * asm.h - prototypes pour les options de rendus de code désassemblé
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_OPTIONS_ASM_H
+#define _GLIBEXT_OPTIONS_ASM_H
+
+
+#include "../helpers.h"
+
+
+
+/* Liste des colonnes en options */
+typedef enum _DisassColumnOptions
+{
+ ACO_PHYSICAL, /* Position physique */
+ ACO_VIRTUAL, /* Adresse virtuelle */
+ ACO_BINARY, /* Contenu sous forme binaire */
+
+ ACO_COUNT
+
+} DisassColumnOptions;
+
+
+#define ACO_ASSEMBLY_LABEL (ACO_COUNT + 0) /* Etiquette dans les données */
+#define ACO_ASSEMBLY_HEAD (ACO_COUNT + 1) /* Instruction pour assembleur */
+#define ACO_ASSEMBLY (ACO_COUNT + 2) /* Code pour assembleur */
+#define ACO_COMMENTS (ACO_COUNT + 3) /* Commentaires éventuels */
+
+
+
+
+
+
+#if 0
+#define G_TYPE_HEX_OPTIONS (g_hex_options_get_type())
+
+DECLARE_GTYPE(GHexOptions, g_hex_options, G, HEX_OPTIONS);
+
+
+/* Crée un groupe d'options pour le rendu d'hexadécimal. */
+GHexOptions *g_hex_options_new(void);
+#endif
+
+
+#endif /* _GLIBEXT_OPTIONS_HEX_H */
diff --git a/src/glibext/secstorage-int.h b/src/glibext/secstorage-int.h
new file mode 100644
index 0000000..bbac133
--- /dev/null
+++ b/src/glibext/secstorage-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * secstorage-int.h - définitions internes pour la conservation sécurisée d'éléments de configuration
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_SECSTORAGE_INT_H
+#define _GLIBEXT_SECSTORAGE_INT_H
+
+
+#include "secstorage.h"
+
+
+
+/* Gardien des secrets avec support des stockages (instance) */
+struct _GSecretStorage
+{
+ GObject parent; /* A laisser en premier */
+
+ GSettings *settings; /* Configuration sollicitée */
+
+ void *master_key; /* Clef déverrouillée */
+
+};
+
+/* Gardien des secrets avec support des stockages (classe) */
+struct _GSecretStorageClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ /* Signaux */
+
+ void (* lock_update) (GSecretStorage *);
+
+};
+
+
+/* Met en place un gardien des secrets avec support de stockage. */
+bool g_secret_storage_create(GSecretStorage *, GSettings *);
+
+
+
+#endif /* _GLIBEXT_SECSTORAGE_INT_H */
diff --git a/src/glibext/secstorage.c b/src/glibext/secstorage.c
new file mode 100644
index 0000000..161214c
--- /dev/null
+++ b/src/glibext/secstorage.c
@@ -0,0 +1,950 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * secstorage.c - conservation sécurisée d'éléments de configuration
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "secstorage.h"
+
+
+#include <assert.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+
+#include "secstorage-int.h"
+#include "../core/logs.h"
+
+
+
+/**
+ * Les mécanismes de hachage de mot de passe doivent être utilisés avec un sel,
+ * et la longueur du sel doit être d’au moins 128 bits.
+ *
+ * Cette note concerne le hachage de mots de passe et non la dérivation de secrets
+ * cependant.
+ *
+ * Source : https://cyber.gouv.fr/sites/default/files/2021/03/anssi-guide-selection_crypto-1.0.pdf
+ */
+
+#define SECRET_STORAGE_SALT_SIZE (256 / 8)
+
+
+/**
+ * Nombre d'itérations pour PBKDF2 : en 2023, OWASP recommande 600000 itérations
+ * pour PBKDF2-HMAC-SHA256 (et 210000 pour PBKDF2-HMAC-SHA512).
+ *
+ * Source : https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
+ */
+
+#define PBKDF2_HMAC_SHA256_ITERATIONS (2 << 20)
+
+
+/**
+ * AES 256 : clef de 256 bits, IV de 128 bits
+ */
+
+#define SECRET_STORAGE_KEK_SIZE (256 / 8)
+
+#define SECRET_STORAGE_KEY_SIZE (256 / 8)
+
+#define SECRET_STORAGE_BLOCK_SIZE (128 / 8)
+
+#define SECRET_STORAGE_IV_SIZE SECRET_STORAGE_BLOCK_SIZE
+
+
+
+/* Initialise la classe des stockages de secrets. */
+static void g_secret_storage_class_init(GSecretStorageClass *);
+
+/* Initialise une instance de stockage de secrets. */
+static void g_secret_storage_init(GSecretStorage *);
+
+/* Supprime toutes les références externes. */
+static void g_secret_storage_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_secret_storage_finalize(GObject *);
+
+/* Teste un mot de passe par Déverrouillage de clef maître. */
+static bool g_secret_storage_check_primary_password(GSecretStorage *, const char *, void **);
+
+
+
+/* Indique le type défini pour un gardien des secrets avec support des stockages. */
+G_DEFINE_TYPE(GSecretStorage, g_secret_storage, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des stockages de secrets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_secret_storage_class_init(GSecretStorageClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = g_secret_storage_dispose;
+ object->finalize = g_secret_storage_finalize;
+
+ g_signal_new("lock-update",
+ G_TYPE_SECRET_STORAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GSecretStorageClass, lock_update),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = instance à initialiser. *
+* *
+* Description : Initialise une instance de stockage de secrets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_secret_storage_init(GSecretStorage *storage)
+{
+ storage->settings = NULL;
+
+ storage->master_key = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_secret_storage_dispose(GObject *object)
+{
+ GSecretStorage *storage; /* Version spécialisée */
+
+ storage = G_SECRET_STORAGE(object);
+
+ g_clear_object(&storage->settings);
+
+ G_OBJECT_CLASS(g_secret_storage_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_secret_storage_finalize(GObject *object)
+{
+ GSecretStorage *storage; /* Version spécialisée */
+
+ storage = G_SECRET_STORAGE(object);
+
+ if (storage->master_key != NULL)
+ free(storage->master_key);
+
+ G_OBJECT_CLASS(g_secret_storage_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : settings = éventuel espace de configuration à utiliser. *
+* *
+* Description : Créé un nouveau gardien des secrets avec support de stockage.*
+* *
+* Retour : Gestionnaire de stockage sécurisé mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GSecretStorage *g_secret_storage_new(GSettings *settings)
+{
+ GSecretStorage *result; /* Instance à retourner */
+
+ result = g_object_new(G_TYPE_SECRET_STORAGE, NULL);
+
+ if (!g_secret_storage_create(result, settings))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = stockage sécurisé à initialiser. *
+* settings = éventuel espace de configuration à utiliser. *
+* *
+* Description : Met en place un gardien des secrets avec support de stockage.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_create(GSecretStorage *storage, GSettings *settings)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (settings != NULL)
+ {
+ ref_object(settings);
+ storage->settings = settings;
+ }
+ else
+ storage->settings = g_settings_new("re.chrysalide.framework.secstorage");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à consulter. *
+* *
+* Description : Détermine si une clef de chiffrement protégée est en place. *
+* *
+* Retour : Bilan de l'analyse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_has_key(const GSecretStorage *storage)
+{
+ bool result; /* Bilan à retourner */
+ GVariant *value; /* Valeur de configuration */
+ gsize length; /* Taille d'une valeur donnée */
+
+ result = false;
+
+ value = g_settings_get_value(storage->settings, "master");
+
+ g_variant_get_fixed_array(value, &length, 1);
+
+ result = (length > SECRET_STORAGE_IV_SIZE);
+
+ g_variant_unref(value);
+
+ return result;;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à consulter. *
+* password = mot de passe principal à appliquer. *
+* *
+* Description : Définit un mot de passe pour protéger une clef maître. *
+* *
+* Retour : Bilan de la mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_set_password(GSecretStorage *storage, const char *passwd)
+{
+ bool result; /* Bilan à retourner */
+ unsigned char salt[SECRET_STORAGE_SALT_SIZE]; /* Sel pour la dérivation*/
+ int ret; /* Bilan à d'un appel */
+ GVariant *value; /* Valeur de configuration */
+ unsigned char kek[SECRET_STORAGE_KEK_SIZE]; /* Clef de protection */
+ unsigned char key[SECRET_STORAGE_KEY_SIZE]; /* Clef maître */
+ unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
+ EVP_CIPHER_CTX *ctx; /* Contexte pour le chiffrement*/
+ unsigned char encrypted[64]; /* Partie chiffrée à conserver */
+ unsigned char *iter; /* Tête d'écriture */
+ int outlen; /* Taille des données utiles */
+
+ result = false;
+
+ if (g_secret_storage_has_key(storage))
+ goto exit;
+
+ /* Création d'un sel pour la dérivation du mot de passe */
+
+ ret = RAND_bytes(salt, sizeof(salt));
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ /**
+ * La fonction g_variant_new_fixed_array() retourne un variant
+ * avec un décompte de référence flottant.
+ */
+
+ value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+ salt, SECRET_STORAGE_SALT_SIZE, sizeof(unsigned char));
+
+ /**
+ * Comme le variant à une référence flottante, la fonction
+ * g_settings_set_value() consomme cette référence.
+ *
+ * Il n'y a donc pas lieu d'appeler g_variant_unref().
+ */
+
+ g_settings_set_value(storage->settings, "salt", value);
+
+ /* Dérivation du mot de passe */
+
+ ret = PKCS5_PBKDF2_HMAC(passwd, strlen(passwd),
+ salt, SECRET_STORAGE_SALT_SIZE,
+ PBKDF2_HMAC_SHA256_ITERATIONS, EVP_sha256(),
+ SECRET_STORAGE_KEK_SIZE, kek);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ /* Définition de la clef maître et de son IV de chiffrement */
+
+ ret = RAND_bytes(key, sizeof(key));
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ ret = RAND_bytes(iv, sizeof(iv));
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ /* Chiffrement de la clef maître */
+
+ ctx = EVP_CIPHER_CTX_new();
+
+ if (ctx == NULL)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
+
+ ret = EVP_EncryptInit_ex2(ctx, EVP_aes_256_wrap_pad(), kek, iv, NULL);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ memcpy(encrypted, iv, SECRET_STORAGE_IV_SIZE);
+
+ iter = encrypted + SECRET_STORAGE_IV_SIZE;
+
+ ret = EVP_EncryptUpdate(ctx, iter, &outlen, key, SECRET_STORAGE_KEY_SIZE);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter += outlen;
+
+ ret = EVP_EncryptFinal_ex(ctx, iter, &outlen);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter += outlen;
+
+ assert((iter - encrypted) < 64);
+
+ /* Conservation de la clef protégée */
+
+ value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+ encrypted, iter - encrypted, sizeof(unsigned char));
+
+ g_settings_set_value(storage->settings, "master", value);
+
+ g_signal_emit_by_name(storage, "lock-update");
+
+ result = true;
+
+ exit_with_ctx:
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à consulter. *
+* old = ancien mot de passe principal à vérifier. *
+* new = nouveau mot de passe principal à appliquer. *
+* *
+* Description : Modifie le mot de passe protégeant une clef maître. *
+* *
+* Retour : Bilan de la mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_change_password(GSecretStorage *storage, const char *old, const char *new)
+{
+ bool result; /* Bilan à retourner */
+
+ result = false;
+
+ if (!g_secret_storage_has_key(storage))
+ goto exit;
+
+ if (!g_secret_storage_check_primary_password(storage, old, NULL))
+ goto exit;
+
+ if (!g_secret_storage_is_locked(storage))
+ g_secret_storage_lock(storage);
+
+ g_settings_reset(storage->settings, "salt");
+ g_settings_reset(storage->settings, "master");
+
+ result = g_secret_storage_set_password(storage, new);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à consulter. *
+* password = mot de passe principal à appliquer. *
+* *
+* Description : Supprime le mot de passe protégeant une clef maître. *
+* *
+* Retour : Bilan de la mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_remove_password(GSecretStorage *storage, const char *passwd)
+{
+ bool result; /* Bilan à retourner */
+
+ result = false;
+
+ if (!g_secret_storage_has_key(storage))
+ goto exit;
+
+ if (!g_secret_storage_check_primary_password(storage, passwd, NULL))
+ goto exit;
+
+ if (!g_secret_storage_is_locked(storage))
+ g_secret_storage_lock(storage);
+
+ g_settings_reset(storage->settings, "salt");
+ g_settings_reset(storage->settings, "master");
+
+ g_signal_emit_by_name(storage, "lock-update");
+
+ result = true;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à consulter. *
+* *
+* Description : Détermine si la clef de chiffrement maître est vérouillée. *
+* *
+* Retour : Bilan de la détermination. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_is_locked(const GSecretStorage *storage)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (storage->master_key == NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à manipuler. *
+* password = mot de passe principal à utiliser. *
+* master = éventuelle adresse pour un stockage de clef. [OUT]*
+* *
+* Description : Teste un mot de passe par Déverrouillage de clef maître. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_secret_storage_check_primary_password(GSecretStorage *storage, const char *passwd, void **master)
+{
+ bool result; /* Bilan à retourner */
+ GVariant *salt_value; /* Valeur du sel configuré */
+ gsize salt_length; /* Taille du sel conservé */
+ gconstpointer salt; /* Données associées #1 */
+ unsigned char kek[SECRET_STORAGE_KEK_SIZE]; /* Clef de protection */
+ int ret; /* Bilan à d'un appel */
+ GVariant *enc_value; /* Paramètres de chiffrement */
+ gsize enc_length; /* Taille de ces paramètrs */
+ gconstpointer encrypted; /* Données associées #2 */
+ EVP_CIPHER_CTX *ctx; /* Contexte de déchiffrement */
+ unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
+ unsigned char key[SECRET_STORAGE_KEY_SIZE]; /* Clef maître */
+ unsigned char *iter; /* Tête d'écriture */
+ int outlen; /* Taille des données utiles */
+
+ result = false;
+
+ if (!g_secret_storage_is_locked(storage))
+ {
+ result = true;
+ goto quick_exit;
+ }
+
+ /* Récupération du sel mis en place */
+
+ salt_value = g_settings_get_value(storage->settings, "salt");
+
+ salt = g_variant_get_fixed_array(salt_value, &salt_length, sizeof(bin_t));
+
+ if (salt_length != SECRET_STORAGE_SALT_SIZE)
+ goto exit_with_salt;
+
+ /* Dérivation du mot de passe */
+
+ ret = PKCS5_PBKDF2_HMAC(passwd, strlen(passwd),
+ salt, SECRET_STORAGE_SALT_SIZE,
+ PBKDF2_HMAC_SHA256_ITERATIONS, EVP_sha256(),
+ SECRET_STORAGE_KEK_SIZE, kek);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_salt;
+ }
+
+ /* Récupération des paramètres chiffrés */
+
+ enc_value = g_settings_get_value(storage->settings, "master");
+
+ encrypted = g_variant_get_fixed_array(enc_value, &enc_length, sizeof(bin_t));
+
+ if (enc_length <= SECRET_STORAGE_IV_SIZE)
+ goto exit_with_enc;
+
+ /* Déhiffrement de la clef maître */
+
+ ctx = EVP_CIPHER_CTX_new();
+
+ if (ctx == NULL)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_enc;
+ }
+
+ EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
+
+ memcpy(iv, encrypted, SECRET_STORAGE_IV_SIZE);
+
+ ret = EVP_DecryptInit_ex2(ctx, EVP_aes_256_wrap_pad(), kek, iv, NULL);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter = key;
+
+ ret = EVP_DecryptUpdate(ctx, iter, &outlen,
+ ((unsigned char *)encrypted) + SECRET_STORAGE_IV_SIZE,
+ enc_length - SECRET_STORAGE_IV_SIZE);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter += outlen;
+
+ ret = EVP_DecryptFinal_ex(ctx, iter, &outlen);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ assert((iter - key) == SECRET_STORAGE_KEY_SIZE);
+
+ /* Stockage de la clef maître en mémoire */
+
+ if (master != NULL)
+ {
+ *master = malloc(SECRET_STORAGE_KEY_SIZE);
+ memcpy(*master, key, SECRET_STORAGE_KEY_SIZE);
+ }
+
+ result = true;
+
+ /* Sortie */
+
+ exit_with_ctx:
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ exit_with_enc:
+
+ g_variant_unref(enc_value);
+
+ exit_with_salt:
+
+ g_variant_unref(salt_value);
+
+ quick_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à manipuler. *
+* password = mot de passe principal à utiliser. *
+* *
+* Description : Déverrouille la clef de chiffrement maître. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_unlock(GSecretStorage *storage, const char *passwd)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_secret_storage_check_primary_password(storage, passwd, &storage->master_key);
+
+ if (result)
+ g_signal_emit_by_name(storage, "lock-update");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à manipuler. *
+* *
+* Description : Verrouille la clef de chiffrement maître. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_secret_storage_lock(GSecretStorage *storage)
+{
+ if (storage->master_key != NULL)
+ {
+ free(storage->master_key);
+ storage->master_key = NULL;
+
+ g_signal_emit_by_name(storage, "lock-update");
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à consulter. *
+* in = séquence d'octets à traiter. *
+* out = séquence d'octets résultantes. [OUT] *
+* *
+* Description : Chiffre des données avec la clef de chiffrement maître. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_encrypt_data(const GSecretStorage *storage, const sized_binary_t *in, sized_binary_t *out)
+{
+ bool result; /* Bilan à retourner */
+ unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
+ int ret; /* Bilan à d'un appel */
+ EVP_CIPHER_CTX *ctx; /* Contexte pour le chiffrement*/
+ size_t needed; /* Taille de la sortie */
+ unsigned char *iter; /* Tête d'écriture */
+ int outlen; /* Taille des données utiles */
+
+ result = false;
+
+ if (g_secret_storage_is_locked(storage))
+ goto quick_exit;
+
+ /* Récupération de la clef maître et d'un IV de chiffrement */
+
+ ret = RAND_bytes(iv, sizeof(iv));
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ /* Préparation de la zone de réception */
+
+ needed = SECRET_STORAGE_IV_SIZE + ((in->size / SECRET_STORAGE_BLOCK_SIZE) + 1) * SECRET_STORAGE_BLOCK_SIZE;
+
+ setup_sized_binary(out, needed);
+
+ /* Chiffrement des données */
+
+ ctx = EVP_CIPHER_CTX_new();
+
+ if (ctx == NULL)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ ret = EVP_EncryptInit_ex2(ctx, EVP_aes_256_cbc(), storage->master_key, iv, NULL);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ memcpy(out->data, iv, SECRET_STORAGE_IV_SIZE);
+
+ iter = out->bin_data + SECRET_STORAGE_IV_SIZE;
+
+ ret = EVP_EncryptUpdate(ctx, iter, &outlen, in->bin_data, in->size);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter += outlen;
+
+ ret = EVP_EncryptFinal_ex(ctx, iter, &outlen);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter += outlen;
+
+ assert((iter - out->bin_data) == out->size);
+
+ result = true;
+
+ /* Sortie */
+
+ exit_with_ctx:
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ if (!result)
+ exit_sized_binary(out);
+
+ exit:
+ quick_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = espace de stockage sécurisé à consulter. *
+* in = séquence d'octets à traiter. *
+* out = séquence d'octets résultantes. [OUT] *
+* *
+* Description : Déchiffre des données avec la clef de chiffrement maître. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_secret_storage_decrypt_data(const GSecretStorage *storage, const sized_binary_t *in, sized_binary_t *out)
+{
+ bool result; /* Bilan à retourner */
+ unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
+ int ret; /* Bilan à d'un appel */
+ EVP_CIPHER_CTX *ctx; /* Contexte pour le chiffrement*/
+ size_t needed; /* Taille de la sortie */
+ unsigned char *iter; /* Tête d'écriture */
+ int outlen; /* Taille des données utiles */
+
+ result = false;
+
+ if (g_secret_storage_is_locked(storage))
+ goto quick_exit;
+
+ /* Récupération d'un IV de déchiffrement */
+
+ if (in->size < SECRET_STORAGE_IV_SIZE)
+ goto exit;
+
+ memcpy(iv, in->data, SECRET_STORAGE_IV_SIZE);
+
+ /* Préparation de la zone de réception */
+
+ needed = in->size - SECRET_STORAGE_IV_SIZE;
+
+ setup_sized_binary(out, needed);
+
+ /* Chiffrement des données */
+
+ ctx = EVP_CIPHER_CTX_new();
+
+ if (ctx == NULL)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit;
+ }
+
+ ret = EVP_DecryptInit_ex2(ctx, EVP_aes_256_cbc(), storage->master_key, iv, NULL);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter = out->bin_data;
+
+ ret = EVP_DecryptUpdate(ctx, iter, &outlen,
+ in->bin_data + SECRET_STORAGE_IV_SIZE, in->size - SECRET_STORAGE_IV_SIZE);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter += outlen;
+
+ ret = EVP_DecryptFinal_ex(ctx, iter, &outlen);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto exit_with_ctx;
+ }
+
+ iter += outlen;
+
+ assert((iter - out->bin_data) <= out->size);
+
+ resize_sized_binary(out, iter - out->bin_data);
+
+ result = true;
+
+ /* Sortie */
+
+ exit_with_ctx:
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ if (!result)
+ exit_sized_binary(out);
+
+ exit:
+ quick_exit:
+
+ return result;
+
+}
diff --git a/src/glibext/secstorage.h b/src/glibext/secstorage.h
new file mode 100644
index 0000000..ed3f79c
--- /dev/null
+++ b/src/glibext/secstorage.h
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * secstorage.h - prototypes pour la conservation sécurisée d'éléments de configuration
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_SECSTORAGE_H
+#define _GLIBEXT_SECSTORAGE_H
+
+
+#include <stdbool.h>
+#include <gio/gio.h>
+
+
+#include "helpers.h"
+#include "../common/szbin.h"
+
+
+
+#define G_TYPE_SECRET_STORAGE (g_secret_storage_get_type())
+
+DECLARE_GTYPE(GSecretStorage, g_secret_storage, G, SECRET_STORAGE);
+
+
+/* Créé un nouveau gardien des secrets avec support de stockage. */
+GSecretStorage *g_secret_storage_new(GSettings *);
+
+/* Détermine si une clef de chiffrement protégée est en place. */
+bool g_secret_storage_has_key(const GSecretStorage *);
+
+/* Définit un mot de passe pour protéger une clef maître. */
+bool g_secret_storage_set_password(GSecretStorage *, const char *);
+
+/* Modifie le mot de passe protégeant une clef maître. */
+bool g_secret_storage_change_password(GSecretStorage *, const char *, const char *);
+
+/* Supprime le mot de passe protégeant une clef maître. */
+bool g_secret_storage_remove_password(GSecretStorage *, const char *);
+
+/* Détermine si la clef de chiffrement maître est vérouillée. */
+bool g_secret_storage_is_locked(const GSecretStorage *);
+
+/* Déverrouille la clef de chiffrement maître. */
+bool g_secret_storage_unlock(GSecretStorage *, const char *);
+
+/* Verrouille la clef de chiffrement maître. */
+void g_secret_storage_lock(GSecretStorage *);
+
+/* Chiffre des données avec la clef de chiffrement maître. */
+bool g_secret_storage_encrypt_data(const GSecretStorage *, const sized_binary_t *, sized_binary_t *);
+
+/* Déchiffre des données avec la clef de chiffrement maître. */
+bool g_secret_storage_decrypt_data(const GSecretStorage *, const sized_binary_t *, sized_binary_t *);
+
+
+
+#endif /* _GLIBEXT_SECSTORAGE_H */
diff --git a/src/analysis/storage/serialize-int.h b/src/glibext/serialize-int.h
index de8d3e3..df9c597 100644
--- a/src/analysis/storage/serialize-int.h
+++ b/src/glibext/serialize-int.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* serialize-int.h - définitions internes propres aux objets entreposables dans un cache
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,8 +21,8 @@
*/
-#ifndef _ANALYSIS_STORAGE_SERIALIZE_INT_H
-#define _ANALYSIS_STORAGE_SERIALIZE_INT_H
+#ifndef _GLIBEXT_SERIALIZE_INT_H
+#define _GLIBEXT_SERIALIZE_INT_H
#include "serialize.h"
@@ -33,14 +33,14 @@
/* Charge un objet depuis une mémoire tampon. */
-typedef bool (* load_serializable_object_cb) (GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+typedef bool (* load_serializable_object_cb) (GSerializableObject *, GObjectStorage *, int);
/* Sauvegarde un objet dans une mémoire tampon. */
-typedef bool (* store_serializable_object_cb) (const GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+typedef bool (* store_serializable_object_cb) (const GSerializableObject *, GObjectStorage *, int);
/* Intermédiaire pour la mise en cache d'objet (interface) */
-struct _GSerializableObjectIface
+struct _GSerializableObjectInterface
{
GTypeInterface base_iface; /* A laisser en premier */
@@ -50,9 +50,5 @@ struct _GSerializableObjectIface
};
-/* Redéfinition */
-typedef GSerializableObjectIface GSerializableObjectInterface;
-
-
-#endif /* _ANALYSIS_STORAGE_SERIALIZE_INT_H */
+#endif /* _GLIBEXT_SERIALIZE_INT_H */
diff --git a/src/analysis/storage/serialize.c b/src/glibext/serialize.c
index d1b0502..b43f0c2 100644
--- a/src/analysis/storage/serialize.c
+++ b/src/glibext/serialize.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* serialize.h - objets entreposables dans un cache
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -51,6 +51,8 @@ G_DEFINE_INTERFACE(GSerializableObject, g_serializable_object, G_TYPE_OBJECT)
static void g_serializable_object_default_init(GSerializableObjectInterface *iface)
{
+ iface->load = NULL;
+ iface->store = NULL;
}
@@ -58,10 +60,10 @@ static void g_serializable_object_default_init(GSerializableObjectInterface *ifa
/******************************************************************************
* *
* Paramètres : object = élément GLib à constuire. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à lire. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en lecture. *
* *
-* Description : Charge un objet depuis une mémoire tampon. *
+* Description : Charge un objet depuis un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -69,14 +71,14 @@ static void g_serializable_object_default_init(GSerializableObjectInterface *ifa
* *
******************************************************************************/
-bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
- GSerializableObjectIface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
- result = iface->load(object, storage, pbuf);
+ result = iface->load(object, storage, fd);
return result;
@@ -86,10 +88,10 @@ bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *sto
/******************************************************************************
* *
* Paramètres : object = élément GLib à consulter. *
-* storage = conservateur de données à manipuler ou NULL. *
-* pbuf = zone tampon à remplir. *
+* storage = conservateur de données à manipuler. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Sauvegarde un objet dans une mémoire tampon. *
+* Description : Sauvegarde un objet dans un flux de données. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -97,14 +99,14 @@ bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *sto
* *
******************************************************************************/
-bool g_serializable_object_store(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+bool g_serializable_object_store(const GSerializableObject *object, GObjectStorage *storage, int fd)
{
bool result; /* Bilan à retourner */
- GSerializableObjectIface *iface; /* Interface utilisée */
+ GSerializableObjectInterface *iface; /* Interface utilisée */
iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
- result = iface->store(object, storage, pbuf);
+ result = iface->store(object, storage, fd);
return result;
diff --git a/src/glibext/serialize.h b/src/glibext/serialize.h
new file mode 100644
index 0000000..c95ac30
--- /dev/null
+++ b/src/glibext/serialize.h
@@ -0,0 +1,52 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * serialize.h - prototypes pour les objets entreposables dans un cache
+ *
+ * Copyright (C) 2020-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_SERIALIZE_H
+#define _GLIBEXT_SERIALIZE_H
+
+
+#include <stdbool.h>
+
+
+#include "helpers.h"
+
+
+
+#define G_TYPE_SERIALIZABLE_OBJECT (g_serializable_object_get_type())
+
+DECLARE_INTERFACE(GSerializableObject, g_serializable_object, G, SERIALIZABLE_OBJECT);
+
+
+/* storage.h : définition d'une conservation d'objets construits */
+typedef struct _GObjectStorage GObjectStorage;
+
+
+/* Charge un objet depuis un flux de données. */
+bool g_serializable_object_load(GSerializableObject *, GObjectStorage *, int);
+
+/* Sauvegarde un objet dans un flux de données. */
+bool g_serializable_object_store(const GSerializableObject *, GObjectStorage *, int);
+
+
+
+#endif /* _GLIBEXT_SERIALIZE_H */
diff --git a/src/glibext/signal.c b/src/glibext/sigredir.c
index 33290fb..67e8563 100644
--- a/src/glibext/signal.c
+++ b/src/glibext/sigredir.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * signal.c - encadrement des signaux supplémentaire par rapport à celui de la GLib
+ * sigredir.c - encadrement des signaux supplémentaire par rapport à celui de la GLib
*
- * Copyright (C) 2014-2018 Cyrille Bagard
+ * Copyright (C) 2014-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,49 +21,55 @@
*/
-#include "signal.h"
+#include "sigredir.h"
#include <assert.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdbool.h>
+#include <gobject/gclosure.h>
#include <gobject/gvaluecollector.h>
-/* Prototype pour le transfert d'exécution. */
-typedef void (* GSignalCallback) (gpointer, ...);
+/* Informations utiles à l'appel final */
+typedef struct _gsignal_wrapper_params_t
+{
+ GClosure *closure; /* Glue pour les appels */
+
+ guint n_params; /* Nombre de paramètres */
+ GValue instance_and_params[0]; /* Instance & paramètres */
+
+} gsignal_wrapper_params_t;
+
+/* Transmet un signal dans le contexte principal. */
+static gboolean to_main_wrapper(gpointer);
+/* Supprime de la mémoire le transporteur d'informations. */
+static void destroy_wrapper_params(gpointer);
/* Informations concernant une diffusion de signal */
-typedef struct _gsignal_wrapper_info
+typedef struct _gsignal_wrapper_info_t
{
gpointer instance; /* Instance GLib initiatrice */
+ gulong id; /* Identifiant de connexion */
GClosure *closure; /* Glue pour les appels */
- GType return_type; /* Type de la valeur retournée */
guint n_params; /* Nombre de paramètres */
- const GType *param_types; /* Type des paramètres associés*/
+ GType param_types[0]; /* Type des paramètres associés*/
- GValue return_value; /* Valeur de retour */
- GValue instance_and_params[0]; /* Instance & paramètres */
-
-} gsignal_wrapper_info;
-
-
-/* Transmet un signal dans le contexte principal. */
-static gboolean to_main_wrapper(gsignal_wrapper_info *);
+} gsignal_wrapper_info_t;
/* Réceptionne un signal et redirige son exécution. */
-static void carry_signal_to_main_thread(gsignal_wrapper_info *, ...);
+static void carry_signal_to_main_thread(gsignal_wrapper_info_t *, ...);
/******************************************************************************
* *
-* Paramètres : info = collecteur d'informations sur la diffusion. *
+* Paramètres : data = collecteur d'informations sur la diffusion. *
* *
* Description : Transmet un signal dans le contexte principal. *
* *
@@ -73,11 +79,17 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *, ...);
* *
******************************************************************************/
-static gboolean to_main_wrapper(gsignal_wrapper_info *info)
+static gboolean to_main_wrapper(gpointer data)
{
- g_closure_invoke(info->closure, NULL/*&info->return_value*/,
- info->n_params + 1, info->instance_and_params,
- NULL);
+ gsignal_wrapper_params_t *params; /* Informations d'appel */
+
+ params = (gsignal_wrapper_params_t *)data;
+
+ g_closure_invoke(params->closure,
+ NULL /* return_value */,
+ params->n_params + 1,
+ params->instance_and_params,
+ NULL /* invocation_hint */);
return G_SOURCE_REMOVE;
@@ -86,6 +98,35 @@ static gboolean to_main_wrapper(gsignal_wrapper_info *info)
/******************************************************************************
* *
+* Paramètres : data = collecteur d'informations à supprimer. *
+* *
+* Description : Supprime de la mémoire le transporteur d'informations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void destroy_wrapper_params(gpointer data)
+{
+ gsignal_wrapper_params_t *params; /* Informations d'appel */
+ guint i; /* Boucle de parcours */
+
+ params = (gsignal_wrapper_params_t *)data;
+
+ g_closure_unref(params->closure);
+
+ for (i = 0; i < (params->n_params + 1); i++)
+ g_value_unset(params->instance_and_params + i);
+
+ free(params);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : info = collecteur d'informations sur la diffusion. *
* ... = arguments poussés par la GLib sur la pile. *
* *
@@ -97,23 +138,26 @@ static gboolean to_main_wrapper(gsignal_wrapper_info *info)
* *
******************************************************************************/
-static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...)
+static void carry_signal_to_main_thread(gsignal_wrapper_info_t *info, ...)
{
+ gsignal_wrapper_params_t *params; /* Informations d'appel */
GValue *param_values; /* Paramètres d'appel */
va_list ap; /* Liste d'arguments sur pile */
guint i; /* Boucle de parcours */
bool static_scope; /* Portée des arguments */
gchar *error; /* Eventuelle erreur inattendue*/
- //g_value_init(&info->return_value, info->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
+ params = calloc(1, sizeof(gsignal_wrapper_params_t) + sizeof(GValue) * (info->n_params + 1));
+
+ params->closure = info->closure;
+ g_closure_ref(info->closure);
- if (G_IS_VALUE(info->instance_and_params))
- g_value_unset(info->instance_and_params);
+ params->n_params = info->n_params;
- g_value_init(info->instance_and_params, G_TYPE_FROM_INSTANCE(info->instance));
- g_value_set_instance(info->instance_and_params, info->instance);
+ g_value_init(params->instance_and_params, G_TYPE_FROM_INSTANCE(info->instance));
+ g_value_set_instance(params->instance_and_params, info->instance);
- param_values = info->instance_and_params + 1;
+ param_values = params->instance_and_params + 1;
va_start(ap, info);
@@ -121,9 +165,6 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...)
for (i = 0; i < info->n_params; i++)
{
- if (G_IS_VALUE(param_values + i))
- g_value_unset(param_values + i);
-
static_scope = info->param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE;
G_VALUE_COLLECT_INIT(param_values + i,
@@ -143,7 +184,28 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...)
va_end(ap);
if (error == NULL)
- g_idle_add_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)to_main_wrapper, info, NULL);
+ g_idle_add_full(G_PRIORITY_HIGH_IDLE, to_main_wrapper, params, destroy_wrapper_params);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = collecteur d'informations à supprimer. *
+* *
+* Description : Déconnecte un signal redirigé vers le contexte principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_signal_disconnect_from_main(gsignal_wrapper_info_t *info)
+{
+ g_signal_handler_disconnect(info->instance, info->id);
+
+ free(info);
}
@@ -165,41 +227,44 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...)
* *
******************************************************************************/
-gulong _g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data, GClosureMarshal marshal, GConnectFlags flags)
+gsignal_wrapper_info_t *_g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data, GClosureMarshal marshal, GConnectFlags flags)
{
+ gsignal_wrapper_info_t *result; /* Structure à renvoyer */
guint signal_id; /* Identifiant du signal visé */
GSignalQuery query; /* Information sur le signal */
- gsignal_wrapper_info *info; /* Encapsulation des données */
/* Collection d'informations */
signal_id = g_signal_lookup(signal, G_TYPE_FROM_INSTANCE(instance));
g_signal_query(signal_id, &query);
+
assert(query.signal_id != 0);
+ assert(query.return_type == G_TYPE_NONE);
/* Allocation adaptée */
- info = calloc(1, sizeof(gsignal_wrapper_info) + sizeof(GValue) * (query.n_params + 1));
+ result = malloc(sizeof(gsignal_wrapper_info_t) + sizeof(GType) * query.n_params);
- info->instance = instance;
+ result->instance = instance;
if (flags & G_CONNECT_SWAPPED)
- info->closure = g_cclosure_new_swap(handler, data, NULL);
+ result->closure = g_cclosure_new_swap(handler, data, NULL);
else
- info->closure = g_cclosure_new(handler, data, NULL);
+ result->closure = g_cclosure_new(handler, data, NULL);
- g_closure_ref(info->closure);
- g_closure_sink(info->closure);
+ g_closure_ref(result->closure);
+ g_closure_sink(result->closure);
- g_closure_set_marshal(info->closure, marshal);
+ g_closure_set_marshal(result->closure, marshal);
- info->return_type = query.return_type;
- info->n_params = query.n_params;
- info->param_types = query.param_types;
+ result->n_params = query.n_params;
+ memcpy(result->param_types, query.param_types, sizeof(GType) * query.n_params);
- assert(query.return_type == G_TYPE_NONE);
+ /* Connexion au signal */
+
+ result->id = g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), result);
- return g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), info);
+ return result;
}
diff --git a/src/glibext/_signal.h b/src/glibext/sigredir.h
index 4f0ab4b..f394d77 100644
--- a/src/glibext/_signal.h
+++ b/src/glibext/sigredir.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * signal.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib
+ * sigredir.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib
*
- * Copyright (C) 2014-2018 Cyrille Bagard
+ * Copyright (C) 2014-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,20 +21,23 @@
*/
-#ifndef _GLIBEXT_SIGNAL_H
-#define _GLIBEXT_SIGNAL_H
+#ifndef _GLIBEXT_SIGREDIR_H
+#define _GLIBEXT_SIGREDIR_H
#include <glib-object.h>
-#include <gobject/gclosure.h>
-#include <glib/gdataset.h>
-#include <glib/glist.h>
#include <gobject/gsignal.h>
+/* Informations concernant une diffusion de signal */
+typedef struct _gsignal_wrapper_info_t gsignal_wrapper_info_t;
+
/* Reproduit le comportement de la fonction g_signal_connect(). */
-gulong _g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, GClosureMarshal, GConnectFlags);
+gsignal_wrapper_info_t *_g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, GClosureMarshal, GConnectFlags);
+
+/* Déconnecte un signal redirigé vers le contexte principal. */
+void g_signal_disconnect_from_main(gsignal_wrapper_info_t *);
#define g_signal_connect_to_main(instance, signal, handler, data, marshal) \
@@ -45,4 +48,4 @@ gulong _g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, G
-#endif /* _GLIBEXT_SIGNAL_H */
+#endif /* _GLIBEXT_SIGREDIR_H */
diff --git a/src/glibext/singleton-int.h b/src/glibext/singleton-int.h
index 9212e2e..747e64a 100644
--- a/src/glibext/singleton-int.h
+++ b/src/glibext/singleton-int.h
@@ -38,11 +38,14 @@ typedef GSingletonCandidate ** (* list_inner_instances_fc) (const GSingletonCand
/* Met à jour une liste de candidats embarqués par un candidat. */
typedef void (* update_inner_instances_fc) (GSingletonCandidate *, GSingletonCandidate **, size_t);
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-typedef guint (* hash_candidate_fc) (const GSingletonCandidate *);
+/* Marque un candidat comme figé. */
+typedef void (* mark_candidate_as_ro_fc) (GSingletonCandidate *);
-/* Détermine si deux candidats à l'unicité sont identiques. */
-typedef gboolean (* is_candidate_equal_fc) (const GSingletonCandidate *, const GSingletonCandidate *);
+/* Indique si le candidat est figé. */
+typedef bool (* is_candidate_ro_fc) (const GSingletonCandidate *);
+
+/* Crée une copie modifiable d'un object unique. */
+typedef GSingletonCandidate * (* dup_candidate_fc) (const GSingletonCandidate *);
/* Instance d'objet visant à être unique (interface) */
@@ -53,8 +56,10 @@ struct _GSingletonCandidateInterface
list_inner_instances_fc list_inner; /* Récupération d'internes */
update_inner_instances_fc update_inner; /* Mise à jour des éléments */
- hash_candidate_fc hash; /* Prise d'empreinte */
- is_candidate_equal_fc is_equal; /* Comparaison */
+ mark_candidate_as_ro_fc mark_as_ro; /* Bascule en mode figé */
+ is_candidate_ro_fc is_ro; /* Consultation de l'état */
+
+ dup_candidate_fc dup; /* Création de copie modifiable*/
};
diff --git a/src/glibext/singleton.c b/src/glibext/singleton.c
index 65b83e7..ed49934 100644
--- a/src/glibext/singleton.c
+++ b/src/glibext/singleton.c
@@ -26,9 +26,10 @@
#include <assert.h>
#include <malloc.h>
-#include <stdbool.h>
+#include "comparable.h"
+#include "hashable.h"
#include "singleton-int.h"
@@ -39,11 +40,14 @@
/* Procède à l'initialisation de l'interface de rassemblement. */
static void g_singleton_candidate_default_init(GSingletonCandidateInterface *);
+/* Fournit une liste de candidats embarqués par un candidat. */
+static GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *, size_t *);
+
/* Met à jour une liste de candidats embarqués par un candidat. */
static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *, GSingletonCandidate **, size_t);
-/* Détermine si deux candidats à l'unicité sont identiques. */
-static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *, GSingletonCandidate *, GList **);
+/* Marque un candidat comme figé. */
+static void g_singleton_candidate_mark_as_read_only(GSingletonCandidate *);
@@ -70,7 +74,9 @@ static void g_singleton_factory_finalize(GSingletonFactory *);
/* Détermine le type d'une interface pour la constitution d'objets uniques. */
-G_DEFINE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT)
+G_DEFINE_INTERFACE_WITH_CODE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT,;
+ g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_COMPARABLE_OBJECT);
+ g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_HASHABLE_OBJECT))
/******************************************************************************
@@ -87,6 +93,13 @@ G_DEFINE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT)
static void g_singleton_candidate_default_init(GSingletonCandidateInterface *iface)
{
+ iface->list_inner = NULL;
+ iface->update_inner = NULL;
+
+ iface->mark_as_ro = NULL;
+ iface->is_ro = NULL;
+
+ iface->dup = NULL;
}
@@ -113,8 +126,11 @@ GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingleto
if (iface->list_inner == NULL)
{
+ assert(iface->update_inner == NULL);
+
*count = 0;
result = NULL;
+
}
else
@@ -161,17 +177,16 @@ static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *ca
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
* *
-* Description : Fournit l'empreinte d'un candidat à une centralisation. *
+* Description : Marque un candidat comme figé. *
* *
-* Retour : Empreinte de l'élément représenté. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-guint g_singleton_candidate_hash(GSingletonCandidate *candidate)
+static void g_singleton_candidate_mark_as_read_only(GSingletonCandidate *candidate)
{
- guint result; /* Valeur à retourner */
GSingletonCandidateInterface *iface; /* Interface utilisée */
GSingletonCandidate **children; /* Instances internes */
size_t count; /* Quantité de ces instances */
@@ -179,103 +194,62 @@ guint g_singleton_candidate_hash(GSingletonCandidate *candidate)
iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
- result = iface->hash(candidate);
+ iface->mark_as_ro(candidate);
children = g_singleton_candidate_list_inner_instances(candidate, &count);
for (i = 0; i < count; i++)
{
- result ^= g_singleton_candidate_hash(children[i]);
- unref_object(children[i]);
+ g_singleton_candidate_mark_as_read_only(children[i]);
+ unref_object(G_OBJECT(children[i]));
}
if (children != NULL)
free(children);
- return result;
-
}
/******************************************************************************
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
-* other = second élément à analyser. *
-* processed = liste de candidats déjà traités. *
* *
-* Description : Détermine si deux candidats à l'unicité sont identiques. *
+* Description : Indique si le candidat est figé. *
* *
-* Retour : Bilan de la comparaison. *
+* Retour : true si le contenu du candidat ne peut plus être modifié. *
* *
* Remarques : - *
* *
******************************************************************************/
-static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other, GList **processed)
+bool g_singleton_candidate_is_read_only(const GSingletonCandidate *candidate)
{
- gboolean result; /* Bilan à renvoyer */
- GList *skip; /* Détection de boucle */
+ bool result; /* Etat à retourner */
GSingletonCandidateInterface *iface; /* Interface utilisée */
- GSingletonCandidate **children[2]; /* Instances internes */
- size_t count[2]; /* Quantité de ces instances */
+#ifndef NDEBUG
+ GSingletonCandidate **children; /* Instances internes */
+ size_t count; /* Quantité de ces instances */
size_t i; /* Boucle de parcours */
+#endif
- skip = g_list_find(processed[0], candidate);
-
- if (skip != NULL)
- result = (g_list_find(processed[1], other) != NULL);
-
- else
- {
- iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
-
- result = iface->is_equal(candidate, other);
-
- processed[0] = g_list_append(processed[0], candidate);
- processed[1] = g_list_append(processed[1], other);
-
- if (!result)
- goto done;
-
- children[0] = g_singleton_candidate_list_inner_instances(candidate, &count[0]);
- children[1] = g_singleton_candidate_list_inner_instances(other, &count[1]);
-
- if (count[0] != count[1])
- {
- for (i = 0; i < count[0]; i++)
- g_object_unref(G_OBJECT(children[0][i]));
-
- for (i = 0; i < count[1]; i++)
- g_object_unref(G_OBJECT(children[1][i]));
-
- }
-
- else
- {
- for (i = 0; i < count[0] && result; i++)
- {
- result = _g_singleton_candidate_is_equal(children[0][i], children[1][i], processed);
- g_object_unref(G_OBJECT(children[0][i]));
- g_object_unref(G_OBJECT(children[1][i]));
- }
-
- for (; i < count[0]; i++)
- {
- g_object_unref(G_OBJECT(children[0][i]));
- g_object_unref(G_OBJECT(children[1][i]));
- }
+ iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
- if (children[0] != NULL)
- free(children[0]);
+ result = iface->is_ro(candidate);
- if (children[1] != NULL)
- free(children[1]);
+#ifndef NDEBUG
- }
+ children = g_singleton_candidate_list_inner_instances(candidate, &count);
+ for (i = 0; i < count; i++)
+ {
+ assert(result == g_singleton_candidate_is_read_only(children[i]));
+ unref_object(G_OBJECT(children[i]));
}
- done:
+ if (children != NULL)
+ free(children);
+
+#endif
return result;
@@ -285,31 +259,60 @@ static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *candidate,
/******************************************************************************
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
-* other = second élément à analyser. *
* *
-* Description : Détermine si deux candidats à l'unicité sont identiques. *
+* Description : Crée une copie modifiable d'un object unique. *
* *
-* Retour : Bilan de la comparaison. *
+* Retour : Nouvelle instance mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
-gboolean g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other)
+GSingletonCandidate *g_singleton_candidate_dup(const GSingletonCandidate *candidate)
{
- gboolean result; /* Bilan à renvoyer */
- GList *processed[2]; /* Suivi des traitements */
+ GSingletonCandidate *result; /* Instance à retourner */
+ GSingletonCandidateInterface *iface; /* Interface utilisée */
+ size_t count; /* Quantité d'objets internes */
+ GSingletonCandidate **children; /* Liste d'instances internes */
+ size_t i; /* Boucle de parcours */
+ GSingletonCandidate **new_children; /* Nouvelle liste d'instances */
+
+ iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+
+ result = iface->dup(candidate);
+
+ assert(!g_singleton_candidate_is_read_only(result));
+
+ children = g_singleton_candidate_list_inner_instances(candidate, &count);
+
+ if (count > 0)
+ {
+ new_children = malloc(count * sizeof(GSingletonCandidate *));
+
+ for (i = 0; i < count; i++)
+ {
+ new_children[i] = g_singleton_candidate_dup(children[i]);
+
+ assert(!g_singleton_candidate_is_read_only(new_children[i]));
+
+ }
+
+ g_singleton_candidate_update_inner_instances(result, new_children, count);
- processed[0] = NULL;
- processed[1] = NULL;
+ for (i = 0; i < count; i++)
+ {
+ unref_object(G_OBJECT(new_children[i]));
+ unref_object(G_OBJECT(children[i]));
+ }
+
+ free(new_children);
- result = _g_singleton_candidate_is_equal(candidate, other, processed);
+ }
- assert(processed[0] != NULL);
- assert(processed[1] != NULL);
+ if (children != NULL)
+ free(children);
- g_list_free(processed[0]);
- g_list_free(processed[1]);
+ assert(G_OBJECT_TYPE(result) == G_OBJECT_TYPE(candidate));
return result;
@@ -364,8 +367,8 @@ static void g_singleton_factory_class_init(GSingletonFactoryClass *klass)
static void g_singleton_factory_init(GSingletonFactory *factory)
{
- factory->table = g_hash_table_new_full((GHashFunc)g_singleton_candidate_hash,
- (GEqualFunc)g_singleton_candidate_is_equal,
+ factory->table = g_hash_table_new_full((GHashFunc)g_hashable_object_hash,
+ (GEqualFunc)g_comparable_object_is_equal,
g_object_unref, NULL);
g_mutex_init(&factory->access);
@@ -524,6 +527,8 @@ GSingletonCandidate *g_singleton_factory_get_instance(GSingletonFactory *factory
g_hash_table_add(factory->table, candidate);
#endif
+ g_singleton_candidate_mark_as_read_only(candidate);
+
result = candidate;
}
diff --git a/src/glibext/singleton.h b/src/glibext/singleton.h
index 36714fa..11afffd 100644
--- a/src/glibext/singleton.h
+++ b/src/glibext/singleton.h
@@ -25,6 +25,9 @@
#define _GLIBEXT_SINGLETON_H
+#include <stdbool.h>
+
+
#include "helpers.h"
@@ -37,14 +40,11 @@
DECLARE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G, SINGLETON_CANDIDATE);
-/* Fournit une liste de candidats embarqués par un candidat. */
-GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *, size_t *);
-
-/* Fournit l'empreinte d'un candidat à une centralisation. */
-guint g_singleton_candidate_hash(GSingletonCandidate *);
+/* Indique si le candidat est figé. */
+bool g_singleton_candidate_is_read_only(const GSingletonCandidate *);
-/* Détermine si deux candidats à l'unicité sont identiques. */
-gboolean g_singleton_candidate_is_equal(GSingletonCandidate *, GSingletonCandidate *);
+/* Crée une copie modifiable d'un object unique. */
+GSingletonCandidate *g_singleton_candidate_dup(const GSingletonCandidate *);
diff --git a/src/analysis/storage/storage-int.h b/src/glibext/storage-int.h
index 4883aa8..d89e1c8 100644
--- a/src/analysis/storage/storage-int.h
+++ b/src/glibext/storage-int.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * storage.h - prototypes internes pour la conservation sur disque d'objets construits
+ * storage-int.h - prototypes internes pour la conservation sur disque d'objets construits
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,11 +21,13 @@
*/
-#ifndef _ANALYSIS_STORAGE_STORAGE_INT_H
-#define _ANALYSIS_STORAGE_STORAGE_INT_H
+#ifndef _GLIBEXT_STORAGE_INT_H
+#define _GLIBEXT_STORAGE_INT_H
#include "storage.h"
+#include "tpmem.h"
+#include "../common/szbin.h"
@@ -44,9 +46,12 @@ struct _GObjectStorage
{
GObject parent; /* A laisser en premier */
- GTypeMemory *tpmem; /* Mémorisation de types */
+ sized_binary_t type; /* Type de conservation */
+ uint8_t version; /* Version correspondante */
+
+ sized_binary_t uid; /* Identifiant de distinction */
- char *hash; /* Empreinte du contenu */
+ GTypeMemory *tpmem; /* Mémorisation de types */
storage_backend_t *backends; /* Gestionnaires existants */
size_t count; /* Quantité de gestionnaires */
@@ -62,5 +67,9 @@ struct _GObjectStorageClass
};
+/* Met en place un support d'une conservation d'objets en place. */
+bool g_object_storage_create(GObjectStorage *, const char *, uint8_t, const char *);
+
+
-#endif /* _ANALYSIS_STORAGE_STORAGE_INT_H */
+#endif /* _GLIBEXT_STORAGE_INT_H */
diff --git a/src/analysis/storage/storage.c b/src/glibext/storage.c
index 610a0f6..0a3c4e7 100644
--- a/src/analysis/storage/storage.c
+++ b/src/glibext/storage.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* storage.c - conservation hors mémoire d'objets choisis
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -28,20 +28,23 @@
#include <malloc.h>
#include <string.h>
#include <unistd.h>
-#include <stdarg.h>
+#include <zip.h>
#include "storage-int.h"
-#include "../db/misc/rlestr.h"
-#include "../../common/io.h"
-#include "../../common/leb128.h"
-#include "../../common/pathname.h"
-#include "../../core/logs.h"
+#include "../common/cpp.h"
+#include "../common/pathname.h"
+#include "../core/logs.h"
-
-#define STORAGE_MAGIC "CSTR"
-#define STORAGE_NUMBER "\x00\x01"
+/**
+ * Historique du format :
+ *
+ * - 09/03/25 : 1.0 (version initiale)
+ *
+ */
+#define STORAGE_MAGIC "COBSTR"
+#define STORAGE_NUMBER "\x01\x00"
/* Initialise la classe des conservations d'objets en place. */
@@ -51,10 +54,13 @@ static void g_object_storage_class_init(GObjectStorageClass *);
static void g_object_storage_init(GObjectStorage *);
/* Supprime toutes les références externes. */
-static void g_object_storage_dispose(GObjectStorage *);
+static void g_object_storage_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_object_storage_finalize(GObjectStorage *);
+static void g_object_storage_finalize(GObject *);
+
+/* Assure l'inexistence d'un groupe avec un nom donné. */
+static bool g_object_storage_has_no_backend_named(GObjectStorage *, const char *);
/* Retrouve l'encadrement pour un nouveau groupe d'objets. */
static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const char *);
@@ -62,11 +68,8 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const
/* Ajoute le support d'un nouveau groupe d'objets construits. */
static bool g_object_storage_add_backend(GObjectStorage *, const char *, storage_backend_t **);
-/* Extrait d'un tampon des enregistrements spécifiques. */
-static bool g_object_storage_load_backend(GObjectStorage *, packed_buffer_t *);
-
-/* Place dans un tampon les données liées à des enregistrements. */
-static bool pack_storage_backend(const storage_backend_t *, packed_buffer_t *);
+/* Charge un objet à partir de données rassemblées. */
+static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *, const char *, off64_t);
@@ -92,8 +95,8 @@ static void g_object_storage_class_init(GObjectStorageClass *klass)
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_object_storage_dispose;
- object->finalize = (GObjectFinalizeFunc)g_object_storage_finalize;
+ object->dispose = g_object_storage_dispose;
+ object->finalize = g_object_storage_finalize;
}
@@ -112,9 +115,12 @@ static void g_object_storage_class_init(GObjectStorageClass *klass)
static void g_object_storage_init(GObjectStorage *storage)
{
- storage->tpmem = g_type_memory_new();
+ init_sized_binary(&storage->type);
+ storage->version = 0;
- storage->hash = NULL;
+ init_sized_binary(&storage->uid);
+
+ storage->tpmem = g_type_memory_new();
storage->backends = NULL;
storage->count = 0;
@@ -125,7 +131,7 @@ static void g_object_storage_init(GObjectStorage *storage)
/******************************************************************************
* *
-* Paramètres : storage = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -135,18 +141,22 @@ static void g_object_storage_init(GObjectStorage *storage)
* *
******************************************************************************/
-static void g_object_storage_dispose(GObjectStorage *storage)
+static void g_object_storage_dispose(GObject *object)
{
+ GObjectStorage *storage; /* Version spécialisée */
+
+ storage = G_OBJECT_STORAGE(object);
+
g_clear_object(&storage->tpmem);
- G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(G_OBJECT(storage));
+ G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : storage = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -156,18 +166,27 @@ static void g_object_storage_dispose(GObjectStorage *storage)
* *
******************************************************************************/
-static void g_object_storage_finalize(GObjectStorage *storage)
+static void g_object_storage_finalize(GObject *object)
{
+ GObjectStorage *storage; /* Version spécialisée */
size_t i; /* Boucle de parcours */
storage_backend_t *backend; /* Gestionnaire à manipuler */
int ret; /* Bilan d'un appel */
+ storage = G_OBJECT_STORAGE(object);
+
g_mutex_lock(&storage->mutex);
for (i = 0; i < storage->count; i++)
{
backend = &storage->backends[i];
+ /**
+ * Chargement incomplet depuis g_object_storage_load().
+ */
+ if (backend->name == NULL)
+ break;
+
if (backend->fd != -1)
close(backend->fd);
else
@@ -193,17 +212,20 @@ static void g_object_storage_finalize(GObjectStorage *storage)
g_mutex_clear(&storage->mutex);
- if (storage->hash != NULL)
- free(storage->hash);
+ exit_sized_binary(&storage->type);
+
+ exit_sized_binary(&storage->uid);
- G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(G_OBJECT(storage));
+ G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(object);
}
/******************************************************************************
* *
-* Paramètres : loaded = contenu binaire à associer. *
+* Paramètres : type = type global à indiquer dans une conservation. *
+* version = numéro de version associé. *
+* uid = identifiant arbitraire mais unique pour distinguer.*
* *
* Description : Crée le support d'une conservation d'objets en place. *
* *
@@ -213,13 +235,14 @@ static void g_object_storage_finalize(GObjectStorage *storage)
* *
******************************************************************************/
-GObjectStorage *g_object_storage_new(const char *hash)
+GObjectStorage *g_object_storage_new(const char *type, uint8_t version, const char *uid)
{
GObjectStorage *result; /* Structure à retourner */
result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
- result->hash = strdup(hash);
+ if (!g_object_storage_create(result, type, version, uid))
+ g_clear_object(&result);
return result;
@@ -228,7 +251,39 @@ GObjectStorage *g_object_storage_new(const char *hash)
/******************************************************************************
* *
-* Paramètres : pbuf = zone tampon à lire. *
+* Paramètres : storage = stockage d'objets à initialiser. *
+* type = type global à indiquer dans une conservation. *
+* version = numéro de version associé. *
+* uid = identifiant arbitraire mais unique pour distinguer.*
+* *
+* Description : Met en place un support d'une conservation d'objets en place.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_object_storage_create(GObjectStorage *storage, const char *type, uint8_t version, const char *uid)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ dup_into_sized_binary(&storage->type, type, strlen(type));
+
+ storage->version = version;
+
+ dup_into_sized_binary(&storage->uid, uid, strlen(uid) + 1);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : filename = fichier de source à traiter. *
* *
* Description : Charge le support d'une conservation d'objets en place. *
* *
@@ -238,140 +293,297 @@ GObjectStorage *g_object_storage_new(const char *hash)
* *
******************************************************************************/
-GObjectStorage *g_object_storage_load(packed_buffer_t *pbuf)
+GObjectStorage *g_object_storage_load(const char *filename)
{
GObjectStorage *result; /* Structure à retourner */
- char header[6]; /* Entête attendue des données */
+ GObjectStorage *storage; /* Structure en construction */
+ int err; /* Eventuel code d'erreur */
+ zip_t *archive; /* Archive ZIP à manipuler */
+ zip_error_t error; /* Suivi des erreurs obtenues */
+ char *tpmem_filename; /* Chemin d'accès pour types */
+ zip_int64_t entries_count; /* Nombre d'éléments ZIP */
+ void *data; /* Données (décompressées) */
+ zip_stat_t stats; /* Information sur les données */
+ zip_file_t *file; /* Echantillon à extraire */
+ zip_int64_t got; /* Nombre d'octets lus */
+ int ret; /* Bilan d'un appel */
+ const void *pos; /* Tête de lecture */
+ const void *max; /* Fin des données lisibles */
bool status; /* Bilan d'une extraction */
- rle_string str; /* Chaîne à conserver */
- uleb128_t count; /* Nombre de groupes à charger */
- uleb128_t i; /* Boucle de parcours */
+ char *prefix; /* Début de nom de fichier */
+ int fd; /* Descripteur de flux ouvert */
+ off_t moved; /* Nouvelle position établie */
+ zip_int64_t i; /* Boucle de parcours */
+ storage_backend_t *backend; /* Informations à intégrer */
+ const char *slash; /* Pointeur vers un caractère /*/
result = NULL;
- status = extract_packed_buffer(pbuf, header, 6, false);
- if (!status) goto quick_exit;
+ storage = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
- if (strncmp(header, STORAGE_MAGIC STORAGE_NUMBER, 6) != 0)
- goto quick_exit;
+ archive = zip_open(filename, ZIP_RDONLY, &err);
+ if (archive == NULL)
+ {
+ zip_error_init_with_code(&error, err);
+ LOG_ERROR_ZIP("zip_open", &error);
+ goto exit;
+ }
+
+ zip_error_init(&error);
+
+ tpmem_filename = NULL;
+
+ /* Validation du nombre d'entrées */
+
+ entries_count = zip_get_num_entries(archive, ZIP_FL_UNCHANGED);
- setup_empty_rle_string(&str);
+ if (entries_count < 2)
+ goto exit_with_archive;
- status = unpack_rle_string(&str, pbuf);
- if (!status) goto quick_exit;
+ data = NULL;
- if (get_rle_string(&str) == NULL)
+ /* Extraction de la partie de contrôle */
+
+ ret = zip_stat_index(archive, 0, ZIP_FL_UNCHANGED, &stats);
+ if (ret != 0)
{
- exit_rle_string(&str);
- goto quick_exit;
+ LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive));
+ goto exit_with_archive;
}
- result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
-
- result->hash = strdup(get_rle_string(&str));
+ if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE))
+ goto exit_with_archive;
- exit_rle_string(&str);
+ if (strcmp(stats.name, "control") != 0)
+ goto exit_with_archive;
- status = g_type_memory_load_types(result->tpmem, pbuf);
- if (!status) goto exit_while_loading;
+ if (stats.size < (6 + 2 + 1 + 1 + 1))
+ goto exit_with_archive;
- status = unpack_uleb128(&count, pbuf);
+ file = zip_fopen_index(archive, 0, ZIP_FL_UNCHANGED);
+ if (file == NULL)
+ {
+ LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive));
+ goto exit_with_archive;
+ }
- for (i = 0; i < count && status; i++)
- status = g_object_storage_load_backend(result, pbuf);
+ data = malloc(stats.size);
- exit_while_loading:
+ got = zip_fread(file, data, stats.size);
- if (!status)
+ ret = zip_fclose(file);
+ if (ret != 0)
{
- g_object_unref(G_OBJECT(result));
- result = NULL;
+ zip_error_set(&error, ret, 0);
+ LOG_ERROR_ZIP("zip_fclose", &error);
+ goto exit_with_data;
}
- quick_exit:
+ if (got != stats.size)
+ goto exit_with_data;
- return result;
+ if (memcmp(data, STORAGE_MAGIC, 6) != 0)
+ goto exit_with_data;
-}
+ if (memcmp(((uint8_t *)data) + 6, STORAGE_NUMBER, 2) != 0)
+ goto exit_with_data;
+ pos = (uint8_t *)data + 8;
+ max = (uint8_t *)data + got;
-/******************************************************************************
-* *
-* Paramètres : storage = gestionnaire de conservations à manipuler. *
-* pbuf = zone tampon à remplir. [OUT] *
-* *
-* Description : Sauvegarde le support d'une conservation d'objets en place. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ status = unpack_sized_binary(&storage->type, &pos, max);
+ if (!status) goto exit_with_data;
-bool g_object_storage_store(GObjectStorage *storage, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- rle_string str; /* Chaîne à conserver */
- size_t i; /* Boucle de parcours */
+ if (pos >= max)
+ goto exit_with_data;
- result = extend_packed_buffer(pbuf, STORAGE_MAGIC STORAGE_NUMBER, 6, false);
+ storage->version = *(uint8_t *)pos;
+ pos = (uint8_t *)pos + 1;
- if (result)
+ unpack_sized_binary_as_string(&storage->uid, &pos, max);
+ if (!status) goto exit_with_data;
+
+ if (pos != max)
+ goto exit_with_data;
+
+ free(data);
+ data = NULL;
+
+ /* Extraction de la conservation des types */
+
+ ret = zip_stat_index(archive, 1, ZIP_FL_UNCHANGED, &stats);
+ if (ret != 0)
{
- init_static_rle_string(&str, storage->hash);
+ LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive));
+ goto exit_with_archive;
+ }
- result = pack_rle_string(&str, pbuf);
+ if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE))
+ goto exit_with_archive;
- exit_rle_string(&str);
+ if (strcmp(stats.name, "types") != 0)
+ goto exit_with_archive;
+ file = zip_fopen_index(archive, 1, ZIP_FL_UNCHANGED);
+ if (file == NULL)
+ {
+ LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive));
+ goto exit_with_archive;
}
- g_mutex_lock(&storage->mutex);
+ data = malloc(stats.size);
- if (result)
- result = g_type_memory_store_types(storage->tpmem, pbuf);
+ got = zip_fread(file, data, stats.size);
- if (result)
- result = pack_uleb128((uleb128_t []){ storage->count }, pbuf);
+ ret = zip_fclose(file);
+ if (ret != 0)
+ {
+ zip_error_set(&error, ret, 0);
+ LOG_ERROR_ZIP("zip_fclose", &error);
+ goto exit_with_data;
+ }
- for (i = 0; i < storage->count && result; i++)
- result = pack_storage_backend(&storage->backends[i], pbuf);
+ asprintf(&prefix, "%s-types", storage->uid.static_data);
- g_mutex_unlock(&storage->mutex);
+ fd = make_tmp_file(prefix, "cache", &tpmem_filename);
- return result;
+ free(prefix);
-}
+ if (fd == -1)
+ goto exit_with_data;
+ status = safe_write(fd, data, stats.size);
+ if (!status)
+ {
+ close(fd);
+ goto exit_with_data;
+ }
-/******************************************************************************
-* *
-* Paramètres : storage = gestionnaire de conservations à compléter. *
-* name = désignation d'un nouveau groupe d'objets. *
-* *
-* Description : Retrouve l'encadrement pour un nouveau groupe d'objets. *
-* *
-* Retour : Informations liées à un groupe ou NULL en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ moved = lseek(fd, 0, SEEK_SET);
+ if (moved == ((off_t)-1))
+ {
+ LOG_ERROR_N("lseek");
+ close(fd);
+ goto exit_with_data;
+ }
-static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage, const char *name)
-{
- storage_backend_t *result; /* Encadrement à retourner */
- size_t i; /* Boucle de parcours */
+ status = g_type_memory_load(storage->tpmem, fd);
- assert(!g_mutex_trylock(&storage->mutex));
+ close(fd);
- for (i = 0; i < storage->count; i++)
- if (strcmp(storage->backends[i].name, name) == 0)
- break;
+ if (!status)
+ goto exit_with_data;
- if (i == storage->count)
- result = NULL;
- else
- result = &storage->backends[i];
+ free(data);
+ data = NULL;
+
+ /* Extraction des différents objects restants */
+
+ if (entries_count > 2)
+ {
+ storage->count = entries_count - 2;
+ storage->backends = calloc(storage->count, sizeof(storage_backend_t));
+
+ for (i = 2; i < entries_count; i++)
+ {
+ backend = &storage->backends[i - 2];
+
+ ret = zip_stat_index(archive, i, ZIP_FL_UNCHANGED, &stats);
+ if (ret != 0)
+ {
+ LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive));
+ goto exit_with_archive;
+ }
+
+ if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE))
+ goto exit_with_archive;
+
+ if (strncmp(stats.name, SL("backends/")) != 0)
+ goto exit_with_archive;
+
+ slash = strchr(stats.name, '/');
+
+ if (slash == NULL)
+ goto exit_with_archive;
+
+ if (strchr(slash + 1, '/') != NULL)
+ goto exit_with_archive;
+
+ if (!g_object_storage_has_no_backend_named(storage, slash + 1))
+ goto exit_with_archive;
+
+ file = zip_fopen_index(archive, i, ZIP_FL_UNCHANGED);
+ if (file == NULL)
+ {
+ LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive));
+ goto exit_with_archive;
+ }
+
+ data = malloc(stats.size);
+
+ got = zip_fread(file, data, stats.size);
+
+ ret = zip_fclose(file);
+ if (ret != 0)
+ {
+ zip_error_set(&error, ret, 0);
+ LOG_ERROR_ZIP("zip_fclose", &error);
+ goto exit_with_data;
+ }
+
+ backend->name = strdup(slash + 1);
+
+ asprintf(&prefix, "%s-%s", storage->uid.static_data, backend->name);
+
+ backend->fd = make_tmp_file(prefix, "cache", &backend->filename);
+
+ free(prefix);
+
+ if (backend->fd == -1)
+ goto exit_with_data;
+
+ status = safe_write(backend->fd, data, stats.size);
+ if (!status) goto exit_with_data;
+
+ moved = lseek(backend->fd, 0, SEEK_SET);
+ if (moved == ((off_t)-1))
+ {
+ LOG_ERROR_N("lseek");
+ goto exit_with_data;
+ }
+
+ free(data);
+ data = NULL;
+
+ }
+
+ }
+
+ /* Clôture des opérations */
+
+ result = storage;
+ ref_object(storage);
+
+ exit_with_data:
+
+ if (data != NULL)
+ free(data);
+
+ exit_with_archive:
+
+ ret = zip_close(archive);
+
+ if (ret != 0)
+ LOG_ERROR_ZIP("zip_close", zip_get_error(archive));
+
+ if (tpmem_filename != NULL)
+ unlink(tpmem_filename);
+
+ zip_error_fini(&error);
+
+ exit:
+
+ unref_object(storage);
return result;
@@ -380,11 +592,10 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,
/******************************************************************************
* *
-* Paramètres : storage = gestionnaire de conservations à compléter. *
-* name = désignation d'un nouveau groupe d'objets. *
-* backend = support mis en place pour les enregistrements. *
+* Paramètres : storage = gestionnaire de conservations à manipuler. *
+* filename = fichier de destination à constituer. *
* *
-* Description : Ajoute le support d'un nouveau groupe d'objets construits. *
+* Description : Sauvegarde le support d'une conservation d'objets en place. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -392,46 +603,199 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,
* *
******************************************************************************/
-static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend)
+bool g_object_storage_store(GObjectStorage *storage, const char *filename)
{
bool result; /* Bilan à retourner */
+ int err; /* Eventuel code d'erreur */
+ zip_t *archive; /* Archive ZIP à manipuler */
+ zip_error_t error; /* Suivi des erreurs obtenues */
+ char *tpmem_filename; /* Chemin d'accès pour types */
+ void *type_buf; /* Données pour le type */
+ size_t type_buflen; /* Quantité de ces données */
+ void *uid_buf; /* Données pour l'identifiant */
+ size_t uid_buflen; /* Quantité de ces données */
+ size_t control_len; /* Taille des premières données*/
+ uint8_t *control; /* Premières données du fichier*/
+ zip_source_t *zip_data; /* Données ZIP à intégrer */
+ zip_int64_t index; /* Nouvel index du contenu */
+ int ret; /* Bilan d'un appel */
char *prefix; /* Début de nom de fichier */
- char *filename; /* Chemin d'accès aux données */
int fd; /* Descripteur de flux ouvert */
+ bool status; /* Bilan d'une écriture */
+ size_t i; /* Boucle de parcours */
+ char *zip_name; /* Destination pour l'archive */
result = false;
- *backend = NULL;
+ archive = zip_open(filename, ZIP_CREATE | ZIP_TRUNCATE, &err);
+ if (archive == NULL)
+ {
+ zip_error_init_with_code(&error, err);
+ LOG_ERROR_ZIP("zip_open", &error);
+ goto exit;
+ }
- assert(!g_mutex_trylock(&storage->mutex));
+ zip_error_init(&error);
- if (g_object_storage_find_backend(storage, name) != NULL)
- goto exit;
+ tpmem_filename = NULL;
- /* Préparatifs */
+ /* Fichier de contrôle */
- asprintf(&prefix, "%s-%s", storage->hash, name);
+ type_buf = pack_sized_binary(&storage->type, &type_buflen);
- fd = make_tmp_file(prefix, "cache", &filename);
+ uid_buf = pack_sized_binary_as_string(&storage->uid, &uid_buflen);
+
+ assert((sizeof(STORAGE_MAGIC) - 1 + sizeof(STORAGE_NUMBER) - 1) == 8);
+
+ control_len = 8 + type_buflen + 1 + uid_buflen;
+ control = malloc(control_len * sizeof(uint8_t));
+
+ memcpy(control, STORAGE_MAGIC, 6);
+ memcpy(control + 6, STORAGE_NUMBER, 2);
+
+ memcpy(control + 8, type_buf, type_buflen);
+
+ control[8 + type_buflen] = storage->version;
+
+ memcpy(control + 8 + type_buflen + 1, uid_buf, uid_buflen);
+
+ zip_data = zip_source_buffer_create(control, control_len, 0, &error);
+ if (zip_data == NULL)
+ {
+ LOG_ERROR_ZIP("zip_source_buffer_create", &error);
+ goto exit_with_control;
+ }
+
+ index = zip_file_add(archive, "control", zip_data, ZIP_FL_ENC_UTF_8);
+ if (index == -1)
+ {
+ zip_source_free(zip_data);
+ LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive));
+ goto exit_with_control;
+ }
+
+ ret = zip_set_file_compression(archive, index, ZIP_CM_STORE, 0 /* comp_flags */);
+ if (ret == -1)
+ {
+ LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive));
+ goto exit_with_control;
+ }
+
+ /* Composants de la conservation */
+
+ g_mutex_lock(&storage->mutex);
+
+ /* Conservation des types */
+
+ asprintf(&prefix, "%s-types", storage->uid.static_data);
+
+ fd = make_tmp_file(prefix, "cache", &tpmem_filename);
free(prefix);
if (fd == -1)
- goto exit;
+ goto exit_with_lock;
- /* Inscription en bonne et due forme */
+ status = g_type_memory_store(storage->tpmem, fd);
- storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t));
+ close(fd);
- *backend = &storage->backends[storage->count - 1];
+ if (!status)
+ goto exit_with_lock;
- (*backend)->name = strdup(name);
+ zip_data = zip_source_file_create(tpmem_filename, 0, -1 /* ZIP_LENGTH_TO_END */, &error);
+ if (zip_data == NULL)
+ {
+ LOG_ERROR_ZIP("zip_source_file_create", &error);
+ goto exit_with_lock;
+ }
- (*backend)->filename = filename;
- (*backend)->fd = fd;
+ index = zip_file_add(archive, "types", zip_data, ZIP_FL_ENC_UTF_8);
+ if (index == -1)
+ {
+ zip_source_free(zip_data);
+ LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive));
+ goto exit_with_lock;
+ }
+
+ ret = zip_set_file_compression(archive, index, ZIP_CM_DEFLATE, 9 /* comp_flags */);
+ if (ret == -1)
+ {
+ LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive));
+ goto exit_with_lock;
+ }
+
+ /* Conservation des objets */
+
+ for (i = 0; i < storage->count; i++)
+ {
+ zip_data = zip_source_file_create(storage->backends[i].filename, 0, -1 /* ZIP_LENGTH_TO_END */, &error);
+ if (zip_data == NULL)
+ {
+ LOG_ERROR_ZIP("zip_source_file_create", &error);
+ goto exit_with_lock;
+ }
+
+ /**
+ * Pas besoin de distinguer les chemins UNIX et Windows ici.
+ *
+ * Cf. https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT :
+ *
+ * 4.4.17 file name: (Variable)
+ *
+ * The path stored MUST NOT contain a drive or
+ * device letter, or a leading slash. All slashes
+ * MUST be forward slashes '/' as opposed to
+ * backwards slashes '\' for compatibility with Amiga
+ * and UNIX file systems etc. If input came from standard
+ * input, there is no file name field.
+ *
+ */
+
+ asprintf(&zip_name, "backends/%s", storage->backends[i].name);
+
+ index = zip_file_add(archive, zip_name, zip_data, ZIP_FL_ENC_UTF_8);
+
+ free(zip_name);
+
+ if (index == -1)
+ {
+ zip_source_free(zip_data);
+ LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive));
+ goto exit_with_lock;
+ }
+
+ ret = zip_set_file_compression(archive, index, ZIP_CM_DEFLATE, 9 /* comp_flags */);
+ if (ret == -1)
+ {
+ LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive));
+ goto exit_with_lock;
+ }
+
+ }
result = true;
+ /* Clôture des opérations */
+
+ exit_with_lock:
+
+ g_mutex_unlock(&storage->mutex);
+
+ exit_with_control:
+
+ ret = zip_close(archive);
+
+ if (ret != 0)
+ LOG_ERROR_ZIP("zip_close", zip_get_error(archive));
+
+ free(control);
+
+ if (tpmem_filename != NULL)
+ unlink(tpmem_filename);
+
+ zip_error_fini(&error);
+
exit:
return result;
@@ -441,71 +805,67 @@ static bool g_object_storage_add_backend(GObjectStorage *storage, const char *na
/******************************************************************************
* *
-* Paramètres : storage = gestionnaire de conservations à compléter. *
-* pbuf = zone tampon à lire. *
+* Paramètres : storage = gestionnaire de conservations à consulter. *
+* name = désignation d'un nouveau groupe d'objets. *
* *
-* Description : Extrait d'un tampon des enregistrements spécifiques. *
+* Description : Assure l'inexistence d'un groupe avec un nom donné. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Bilan des recherches. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_object_storage_has_no_backend_named(GObjectStorage *storage, const char *name)
{
bool result; /* Bilan à retourner */
- rle_string str; /* Chaîne à conserver */
- bool status; /* Bilan de lecture de contenu */
- storage_backend_t *backend; /* Informations à intégrer */
- uleb128_t length; /* Taille des données à charger*/
- off_t moved; /* Nouvelle position établie */
-
- result = false;
-
- g_mutex_lock(&storage->mutex);
-
- /* Récupération du nom et création du support */
-
- setup_empty_rle_string(&str);
+ size_t i; /* Boucle de parcours */
- status = unpack_rle_string(&str, pbuf);
- if (!status) goto exit;
+ result = true;
- if (get_rle_string(&str) == NULL)
+ for (i = 0; i < storage->count && result; i++)
{
- exit_rle_string(&str);
- goto exit;
- }
-
- status = g_object_storage_add_backend(storage, get_rle_string(&str), &backend);
+ if (storage->backends[i].name == NULL)
+ break;
- exit_rle_string(&str);
+ if (strcmp(storage->backends[i].name, name) == 0)
+ result = false;
- if (!status) goto exit;
+ }
- /* Récupération du contenu */
+ return result;
- status = unpack_uleb128(&length, pbuf);
- if (!status) goto exit;
+}
- status = safe_write(backend->fd, pbuf->data + pbuf->pos, length);
- if (!status) goto exit;
- advance_packed_buffer(pbuf, length);
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire de conservations à compléter. *
+* name = désignation d'un nouveau groupe d'objets. *
+* *
+* Description : Retrouve l'encadrement pour un nouveau groupe d'objets. *
+* *
+* Retour : Informations liées à un groupe ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- moved = lseek(backend->fd, 0, SEEK_SET);
- if (moved == ((off_t)-1))
- {
- LOG_ERROR_N("lseek");
- goto exit;
- }
+static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage, const char *name)
+{
+ storage_backend_t *result; /* Encadrement à retourner */
+ size_t i; /* Boucle de parcours */
- result = true;
+ assert(!g_mutex_trylock(&storage->mutex));
- exit:
+ for (i = 0; i < storage->count; i++)
+ if (strcmp(storage->backends[i].name, name) == 0)
+ break;
- g_mutex_unlock(&storage->mutex);
+ if (i == storage->count)
+ result = NULL;
+ else
+ result = &storage->backends[i];
return result;
@@ -514,10 +874,11 @@ static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer
/******************************************************************************
* *
-* Paramètres : backend = stockage des enregistrements spécifiques. *
-* pbuf = zone tampon à remplir. [OUT] *
+* Paramètres : storage = gestionnaire de conservations à compléter. *
+* name = désignation d'un nouveau groupe d'objets. *
+* backend = support mis en place pour les enregistrements. *
* *
-* Description : Place dans un tampon les données liées à des enregistrements.*
+* Description : Ajoute le support d'un nouveau groupe d'objets construits. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -525,72 +886,45 @@ static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer
* *
******************************************************************************/
-static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer_t *pbuf)
+static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend)
{
bool result; /* Bilan à retourner */
- rle_string str; /* Chaîne à conserver */
- bool status; /* Bilan de lecture de contenu */
- off_t current; /* Position courante */
- off_t moved; /* Nouvelle position établie */
- void *data; /* Données à transférer */
+ char *prefix; /* Début de nom de fichier */
+ char *filename; /* Chemin d'accès aux données */
+ int fd; /* Descripteur de flux ouvert */
result = false;
- /* Inscription du nom */
+ *backend = NULL;
- init_static_rle_string(&str, backend->name);
+ assert(!g_mutex_trylock(&storage->mutex));
- status = pack_rle_string(&str, pbuf);
+ if (g_object_storage_find_backend(storage, name) != NULL)
+ goto exit;
- exit_rle_string(&str);
+ /* Préparatifs */
- if (!status) goto exit;
+ asprintf(&prefix, "%s-%s", storage->uid.static_data, name);
- /* Inscription du contenu */
+ fd = make_tmp_file(prefix, "cache", &filename);
- current = lseek(backend->fd, 0, SEEK_CUR);
- if (current == ((off_t)-1))
- {
- LOG_ERROR_N("lseek");
- goto exit;
- }
+ free(prefix);
- moved = lseek(backend->fd, 0, SEEK_SET);
- if (moved == ((off_t)-1))
- {
- LOG_ERROR_N("lseek");
+ if (fd == -1)
goto exit;
- }
- data = malloc(current);
- if (data == NULL)
- {
- LOG_ERROR_N("malloc");
- goto restore;
- }
-
- status = safe_read(backend->fd, data, current);
- if (!status) goto free_mem;
-
- status = pack_uleb128((uleb128_t []){ current }, pbuf);
- if (!status) goto free_mem;
-
- status = extend_packed_buffer(pbuf, data, current, false);
+ /* Inscription en bonne et due forme */
- free_mem:
+ storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t));
- free(data);
+ *backend = &storage->backends[storage->count - 1];
- restore:
+ (*backend)->name = strdup(name);
- moved = lseek(backend->fd, current, SEEK_SET);
- if (moved == ((off_t)-1))
- {
- LOG_ERROR_N("lseek");
- goto exit;
- }
+ (*backend)->filename = filename;
+ (*backend)->fd = fd;
- result = status;
+ result = true;
exit:
@@ -602,7 +936,7 @@ static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer
/******************************************************************************
* *
* Paramètres : storage = gestionnaire à manipuler. *
-* name = désignation d'un nouveau groupe d'objets. *
+* name = désignation d'un groupe d'objets à consulter. *
* pos = tête de lecture avant écriture. *
* *
* Description : Charge un objet à partir de données rassemblées. *
@@ -613,56 +947,44 @@ static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer
* *
******************************************************************************/
-GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const char *name, off64_t pos)
+static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *storage, const char *name, off64_t pos)
{
GSerializableObject *result; /* Instance à retourner */
- bool status; /* Bilan d'une opération */
storage_backend_t *backend; /* Informations à consulter */
- packed_buffer_t pbuf; /* Tampon des données à lire */
off64_t new; /* Nouvelle position de lecture*/
+ bool status; /* Bilan d'une opération */
result = NULL;
- /* Chargement */
-
- status = false;
+ assert(!g_mutex_trylock(&storage->mutex));
- g_mutex_lock(&storage->mutex);
+ /* Chargement */
backend = g_object_storage_find_backend(storage, name);
+ if (backend == NULL) goto exit;
- if (backend != NULL)
+ new = lseek64(backend->fd, pos, SEEK_SET);
+ if (new == (off_t)-1)
{
- new = lseek64(backend->fd, pos, SEEK_SET);
-
- if (new == pos)
- {
- init_packed_buffer(&pbuf);
- status = read_packed_buffer(&pbuf, backend->fd);
- }
-
+ LOG_ERROR_N("lseek64");
+ goto exit;
}
- g_mutex_unlock(&storage->mutex);
-
- if (!status)
- goto exit;
+ assert (new == pos);
/* Phase de conversion */
- result = G_SERIALIZABLE_OBJECT(g_type_memory_create_object(storage->tpmem, &pbuf));
+ result = G_SERIALIZABLE_OBJECT(g_type_memory_create_object_from_gtype(storage->tpmem, backend->fd));
if (result)
{
- status = g_serializable_object_load(result, storage, &pbuf);
+ status = g_serializable_object_load(result, storage, backend->fd);
if (!status)
g_clear_object(&result);
}
- exit_packed_buffer(&pbuf);
-
exit:
return result;
@@ -673,10 +995,10 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const
/******************************************************************************
* *
* Paramètres : storage = gestionnaire à manipuler. *
-* name = désignation d'un nouveau groupe d'objets. *
-* pbuf = zone tampon à parcourir. *
+* name = désignation d'un groupe d'objets à consulter. *
+* pos = tête de lecture avant écriture. *
* *
-* Description : Charge un objet interne à partir de données rassemblées. *
+* Description : Charge un objet à partir de données rassemblées. *
* *
* Retour : Objet restauré en mémoire ou NULL en cas d'échec. *
* *
@@ -684,18 +1006,15 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const
* *
******************************************************************************/
-GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf)
+GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const char *name, off64_t pos)
{
GSerializableObject *result; /* Instance à retourner */
- uint64_t pos; /* Localisation des données */
- bool status; /* Bilan d'une opération */
- result = NULL;
+ g_mutex_lock(&storage->mutex);
- status = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true);
+ result = g_object_storage_load_object_unlocked(storage, name, pos);
- if (status)
- result = g_object_storage_load_object(storage, name, pos);
+ g_mutex_unlock(&storage->mutex);
return result;
@@ -704,60 +1023,70 @@ GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, con
/******************************************************************************
* *
-* Paramètres : storage = gestionnaire à manipuler. *
-* name = désignation d'un nouveau groupe d'objets. *
-* pbuf = zone tampon à parcourir. *
-* expected = type d'objet attendu. *
-* ... = élément restauré ou NULL en cas d'échec. [OUT] *
+* Paramètres : storage = gestionnaire à manipuler. *
+* fd = flux de données de l'objet courant. *
+* name = désignation du groupe de l'objets à extraire. *
* *
-* Description : Charge un objet interne à partir de données rassemblées. *
+* Description : Charge un objet interne à partir d'une référence embarquée. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Objet restauré en mémoire ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf, GType expected, ...)
+GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, int fd, const char *name)
{
- bool result; /* Bilan d'une opération */
- uint64_t pos; /* Localisation des données */
- GSerializableObject *instance; /* Objet rechargé à valider */
- va_list ap; /* Liste d'arguments variables */
- void **object; /* Lieu d'enregistrement final */
+ GSerializableObject *result; /* Instance à retourner */
+ storage_backend_t *backend; /* Informations à consulter */
+ uleb128_t pos; /* Localisation des données */
+ bool status; /* Bilan d'une opération */
+ off64_t saved; /* Sauvegarde de position */
+ off64_t new; /* Nouvelle position de lecture*/
- result = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true);
+ result = NULL;
- if (result)
- {
- if (pos == 0)
- *object = NULL;
+ g_mutex_lock(&storage->mutex);
- else
- {
- instance = g_object_storage_load_object(storage, name, pos);
+ /* Récupération de la position */
- result = G_TYPE_CHECK_INSTANCE_TYPE(instance, expected);
+ backend = g_object_storage_find_backend(storage, name);
+ if (backend == NULL) goto exit;
- if (result)
- {
- va_start(ap, expected);
+ status = load_uleb128(&pos, backend->fd);
+ if (!status) goto exit;
- object = va_arg(ap, void **);
+ saved = lseek64(backend->fd, 0, SEEK_CUR);
+ if (saved == (off_t)-1)
+ {
+ LOG_ERROR_N("lseek64");
+ goto exit;
+ }
- *object = instance;
+ /* Chargement */
- va_end(ap);
+ result = g_object_storage_load_object_unlocked(storage, name, pos);
- }
+ if (result == NULL) goto exit;
- else
- g_clear_object(&instance);
+ /* Restauration de la position courante */
- }
+ new = lseek64(backend->fd, saved, SEEK_SET);
+ if (new == (off_t)-1)
+ {
+ LOG_ERROR_N("lseek64");
+
+ g_clear_object(&result);
+ goto exit;
}
+ assert (new == saved);
+
+ exit:
+
+ g_mutex_unlock(&storage->mutex);
+
return result;
}
@@ -766,7 +1095,7 @@ bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name,
/******************************************************************************
* *
* Paramètres : storage = gestionnaire à manipuler. *
-* name = désignation d'un nouveau groupe d'objets. *
+* name = désignation d'un groupe d'objets, nouveau ou non. *
* object = objet sérialisable à traiter. *
* pos = tête de lecture avant écriture. [OUT] *
* *
@@ -781,22 +1110,9 @@ bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name,
bool g_object_storage_store_object(GObjectStorage *storage, const char *name, const GSerializableObject *object, off64_t *pos)
{
bool result; /* Bilan à retourner */
- packed_buffer_t pbuf; /* Tampon des données à écrire */
storage_backend_t *backend; /* Informations à consulter */
off64_t tmp; /* Conservation éphémère */
- /* Phase de conversion */
-
- init_packed_buffer(&pbuf);
-
- result = g_type_memory_store_object_gtype(storage->tpmem, G_OBJECT(object), &pbuf);
- if (!result) goto exit;
-
- result = g_serializable_object_store(object, storage, &pbuf);
- if (!result) goto exit;
-
- /* Enregistrement */
-
result = false;
g_mutex_lock(&storage->mutex);
@@ -814,54 +1130,18 @@ bool g_object_storage_store_object(GObjectStorage *storage, const char *name, co
*pos = lseek64(backend->fd, 0, SEEK_CUR);
if (*pos != (off64_t)-1)
- result = write_packed_buffer(&pbuf, backend->fd);
-
- }
-
- g_mutex_unlock(&storage->mutex);
-
- /* Sortie propre */
-
- exit:
-
- exit_packed_buffer(&pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : storage = gestionnaire à manipuler. *
-* name = désignation d'un nouveau groupe d'objets. *
-* pbuf = zone tampon à remplir. *
-* *
-* Description : Sauvegarde un object interne sous forme de données. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_object_storage_pack_object(GObjectStorage *storage, const char *name, const GSerializableObject *object, packed_buffer_t *pbuf)
-{
- bool result; /* Bilan à retourner */
- off64_t pos; /* Localisation des données */
-
- if (object == NULL)
- result = extend_packed_buffer(pbuf, (uint64_t []){ 0 }, sizeof(uint64_t), true);
+ {
+ result = g_type_memory_store_object_gtype(storage->tpmem, G_OBJECT(object), backend->fd);
- else
- {
- result = g_object_storage_store_object(storage, name, object, &pos);
+ if (result)
+ result = g_serializable_object_store(object, storage, backend->fd);
- if (result)
- result = extend_packed_buffer(pbuf, (uint64_t []){ pos }, sizeof(uint64_t), true);
+ }
}
+ g_mutex_unlock(&storage->mutex);
+
return result;
}
diff --git a/src/analysis/storage/storage.h b/src/glibext/storage.h
index cc0caad..ea06ed4 100644
--- a/src/analysis/storage/storage.h
+++ b/src/glibext/storage.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* storage.h - prototypes pour la conservation sur disque d'objets construits
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,69 +21,61 @@
*/
-#ifndef _ANALYSIS_STORAGE_STORAGE_H
-#define _ANALYSIS_STORAGE_STORAGE_H
+#ifndef _GLIBEXT_STORAGE_H
+#define _GLIBEXT_STORAGE_H
-#include <glib-object.h>
-#include <stdbool.h>
+#include <stdint.h>
+#include "helpers.h"
#include "serialize.h"
-#include "tpmem.h"
-#define G_TYPE_OBJECT_STORAGE g_object_storage_get_type()
-#define G_OBJECT_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_OBJECT_STORAGE, GObjectStorage))
-#define G_IS_OBJECT_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_OBJECT_STORAGE))
-#define G_OBJECT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_OBJECT_STORAGE, GObjectStorageClass))
-#define G_IS_OBJECT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_OBJECT_STORAGE))
-#define G_OBJECT_STORAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_OBJECT_STORAGE, GObjectStorageClass))
+#define G_TYPE_OBJECT_STORAGE (g_object_storage_get_type())
+DECLARE_GTYPE(GObjectStorage, g_object_storage, G, OBJECT_STORAGE);
-/* Définition d'une conservation d'objets construits (instance) */
-typedef struct _GObjectStorage GObjectStorage;
-
-/* Définition d'une conservation d'objets construits (classe) */
-typedef struct _GObjectStorageClass GObjectStorageClass;
-
-
-/* Indique le type défini pour une conservation d'objets construits. */
-GType g_object_storage_get_type(void);
/* Crée le support d'une conservation d'objets en place. */
-GObjectStorage *g_object_storage_new(const char *);
-
-#define get_storage_linked_format(s) \
- ({ \
- void*__result; \
- __result = g_object_get_data(G_OBJECT(s), "format"); \
- g_object_ref(G_OBJECT(__result)); \
- __result; \
- })
+GObjectStorage *g_object_storage_new(const char *, uint8_t, const char *);
/* Charge le support d'une conservation d'objets en place. */
-GObjectStorage *g_object_storage_load(packed_buffer_t *);
+GObjectStorage *g_object_storage_load(const char *);
/* Sauvegarde le support d'une conservation d'objets en place. */
-bool g_object_storage_store(GObjectStorage *, packed_buffer_t *);
+bool g_object_storage_store(GObjectStorage *, const char *);
/* Charge un objet à partir de données rassemblées. */
GSerializableObject *g_object_storage_load_object(GObjectStorage *, const char *, off64_t);
-/* Charge un objet interne à partir de données rassemblées. */
-GSerializableObject *g_object_storage_unpack_object(GObjectStorage *, const char *, packed_buffer_t *);
+/* Charge un objet interne à partir d'une référence embarquée. */
+GSerializableObject *g_object_storage_unpack_object(GObjectStorage *, int, const char *);
/* Sauvegarde un object sous forme de données rassemblées. */
bool g_object_storage_store_object(GObjectStorage *, const char *, const GSerializableObject *, off64_t *);
-/* Charge un objet interne à partir de données rassemblées. */
-bool g_object_storage_unpack_object_2(GObjectStorage *, const char *, packed_buffer_t *, GType, ...);
-/* Sauvegarde un object interne sous forme de données. */
-bool g_object_storage_pack_object(GObjectStorage *, const char *, const GSerializableObject *, packed_buffer_t *);
+
+
+#if 0
+
+/**
+ * TODO : REMME ?
+ */
+
+#define get_storage_linked_format(s) \
+ ({ \
+ void*__result; \
+ __result = g_object_get_data(G_OBJECT(s), "format"); \
+ g_object_ref(G_OBJECT(__result)); \
+ __result; \
+ })
+
+#endif
+
-#endif /* _ANALYSIS_STORAGE_STORAGE_H */
+#endif /* _GLIBEXT_STORAGE_H */
diff --git a/src/glibext/strbuilder-int.h b/src/glibext/strbuilder-int.h
index 97e0f4e..d74e65c 100644
--- a/src/glibext/strbuilder-int.h
+++ b/src/glibext/strbuilder-int.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* strbuilder-int.h - définitions internes propres aux éléments exportant une chaîne de caractères
*
- * Copyright (C) 2024 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
diff --git a/src/glibext/strbuilder.c b/src/glibext/strbuilder.c
index 54a102b..e48674c 100644
--- a/src/glibext/strbuilder.c
+++ b/src/glibext/strbuilder.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* strbuilder.c - exportation d'une chaîne de caractères depuis un élément
*
- * Copyright (C) 2024 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -51,6 +51,7 @@ G_DEFINE_INTERFACE(GStringBuilder, g_string_builder, G_TYPE_OBJECT)
static void g_string_builder_default_init(GStringBuilderInterface *iface)
{
+ iface->to_string = NULL;
}
@@ -77,7 +78,11 @@ bool g_string_builder_to_string(const GStringBuilder *builder, unsigned int flag
iface = G_STRING_BUILDER_GET_IFACE(builder);
- result = iface->to_string(builder, flags, out);
+ if (iface->to_string == NULL)
+ result = false;
+
+ else
+ result = iface->to_string(builder, flags, out);
return result;
diff --git a/src/glibext/strbuilder.h b/src/glibext/strbuilder.h
index d8d0eaa..b6422f7 100644
--- a/src/glibext/strbuilder.h
+++ b/src/glibext/strbuilder.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* strbuilder.h - prototypes pour l'exportation d'une chaîne de caractères depuis un élément
*
- * Copyright (C) 2024 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
diff --git a/src/glibext/tpmem-int.h b/src/glibext/tpmem-int.h
new file mode 100644
index 0000000..b1b7eec
--- /dev/null
+++ b/src/glibext/tpmem-int.h
@@ -0,0 +1,78 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tpmem-int.h - définitions internes propres à la mémorisation des types d'objets mis en cache
+ *
+ * Copyright (C) 2020-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_TPMEM_INT_H
+#define _GLIBEXT_TPMEM_INT_H
+
+
+#include "tpmem.h"
+
+
+/* Conservation d'une référence sur un type */
+typedef struct _gtype_ref_info_t
+{
+ GType gtype; /* Type pour la GLib */
+ gpointer gclass; /* Lien vers sa classe */
+
+ /**
+ * La GLib n'est pas très claire sur la taille de GType comme le montre le
+ * code issu de <sources>/gobject/gtype.h :
+ *
+ * #if GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus
+ * typedef gsize GType;
+ * #else // for historic reasons, C++ links against gulong GTypes
+ * typedef gulong GType;
+ * #endif
+ *
+ * Et :
+ *
+ * typedef unsigned $glib_size_type_define gsize;
+ *
+ * On prend donc le parti de conserver ces types sous forme de valeurs 64 bits
+ * lors des enregistrements.
+ */
+
+} gtype_ref_info_t;
+
+
+/* Définition d'une mémoire de types d'objets (instance) */
+struct _GTypeMemory
+{
+ GObject parent; /* A laisser en premier */
+
+ gtype_ref_info_t *gtypes; /* Types des objets reconnus */
+ size_t count; /* Quantité de ces objets */
+ GMutex mutex; /* Contrôle d'accès à la liste */
+
+};
+
+/* Définition d'une mémoire de types d'objets (classe) */
+struct _GTypeMemoryClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _GLIBEXT_TPMEM_INT_H */
diff --git a/src/analysis/storage/tpmem.c b/src/glibext/tpmem.c
index 0703aeb..14b5e33 100644
--- a/src/analysis/storage/tpmem.c
+++ b/src/glibext/tpmem.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* tpmem.c - mémorisation des types d'objets mis en cache
*
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,59 +25,14 @@
#include <assert.h>
-#include <stdint.h>
-#include "../db/misc/rlestr.h"
-#include "../../arch/operands/target.h"
-#include "../../core/logs.h"
+#include "tpmem-int.h"
+#include "../common/szbin.h"
+#include "../core/logs.h"
-/* Conservation d'une référence sur un type */
-typedef struct _gtype_ref_info_t
-{
- GType gtype; /* Type pour la GLib */
- gpointer gclass; /* Lien vers sa classe */
-
- /**
- * La GLib n'est pas très claire sur la taille de GType :
- *
- * #if GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus
- * typedef gsize GType;
- * #else // for historic reasons, C++ links against gulong GTypes
- * typedef gulong GType;
- * #endif
- *
- * Et :
- *
- * typedef unsigned $glib_size_type_define gsize;
- *
- * On prend donc le parti de conserver ces types sous forme de valeurs 64 bits
- * lors des enregistrements.
- */
-
-} gtype_ref_info_t;
-
-/* Définition d'une mémoire de types d'objets (instance) */
-struct _GTypeMemory
-{
- GObject parent; /* A laisser en premier */
-
- gtype_ref_info_t *gtypes; /* Types des objets reconnus */
- size_t count; /* Quantité de ces objets */
- GMutex mutex; /* Contrôle d'accès à la liste */
-
-};
-
-/* Définition d'une mémoire de types d'objets (classe) */
-struct _GTypeMemoryClass
-{
- GObjectClass parent; /* A laisser en premier */
-
-};
-
-
/* Initialise la classe des mémoires de types d'objets. */
static void g_type_memory_class_init(GTypeMemoryClass *);
@@ -85,10 +40,10 @@ static void g_type_memory_class_init(GTypeMemoryClass *);
static void g_type_memory_init(GTypeMemory *);
/* Supprime toutes les références externes. */
-static void g_type_memory_dispose(GTypeMemory *);
+static void g_type_memory_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void g_type_memory_finalize(GTypeMemory *);
+static void g_type_memory_finalize(GObject *);
@@ -114,8 +69,8 @@ static void g_type_memory_class_init(GTypeMemoryClass *klass)
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_type_memory_dispose;
- object->finalize = (GObjectFinalizeFunc)g_type_memory_finalize;
+ object->dispose = g_type_memory_dispose;
+ object->finalize = g_type_memory_finalize;
}
@@ -143,7 +98,7 @@ static void g_type_memory_init(GTypeMemory *tpmem)
/******************************************************************************
* *
-* Paramètres : tpmem = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -153,10 +108,13 @@ static void g_type_memory_init(GTypeMemory *tpmem)
* *
******************************************************************************/
-static void g_type_memory_dispose(GTypeMemory *tpmem)
+static void g_type_memory_dispose(GObject *object)
{
+ GTypeMemory *tpmem; /* Version spécialisée */
uint64_t i; /* Boucle de parcours */
+ tpmem = G_TYPE_MEMORY(object);
+
g_mutex_lock(&tpmem->mutex);
for (i = 0; i < tpmem->count; i++)
@@ -167,14 +125,14 @@ static void g_type_memory_dispose(GTypeMemory *tpmem)
g_mutex_clear(&tpmem->mutex);
- G_OBJECT_CLASS(g_type_memory_parent_class)->dispose(G_OBJECT(tpmem));
+ G_OBJECT_CLASS(g_type_memory_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : tpmem = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -184,12 +142,16 @@ static void g_type_memory_dispose(GTypeMemory *tpmem)
* *
******************************************************************************/
-static void g_type_memory_finalize(GTypeMemory *tpmem)
+static void g_type_memory_finalize(GObject *object)
{
+ GTypeMemory *tpmem; /* Version spécialisée */
+
+ tpmem = G_TYPE_MEMORY(object);
+
if (tpmem->gtypes != NULL)
free(tpmem->gtypes);
- G_OBJECT_CLASS(g_type_memory_parent_class)->finalize(G_OBJECT(tpmem));
+ G_OBJECT_CLASS(g_type_memory_parent_class)->finalize(object);
}
@@ -220,7 +182,7 @@ GTypeMemory *g_type_memory_new(void)
/******************************************************************************
* *
* Paramètres : tpmem = mémoire à compléter. *
-* pbuf = zone tampon à lire. *
+* fd = flux ouvert en lecture. *
* *
* Description : Apprend tous les types mémorisés dans un tampon. *
* *
@@ -230,14 +192,14 @@ GTypeMemory *g_type_memory_new(void)
* *
******************************************************************************/
-bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
+bool g_type_memory_load(GTypeMemory *tpmem, int fd)
{
bool result; /* Bilan à enregistrer */
uleb128_t count; /* Nombre d'éléments détectés */
uleb128_t i; /* Boucle de parcours */
- rle_string str; /* Chaîne à charger */
+ sized_binary_t str; /* Chaîne à charger */
- result = unpack_uleb128(&count, pbuf);
+ result = load_uleb128(&count, fd);
if (result)
{
@@ -248,35 +210,27 @@ bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
assert(tpmem->gtypes == NULL);
tpmem->gtypes = calloc(count, sizeof(gtype_ref_info_t));
- setup_empty_rle_string(&str);
-
for (i = 0; i < tpmem->count && result; i++)
{
- result = unpack_rle_string(&str, pbuf);
+ result = load_sized_binary_as_string(&str, fd);
if (!result) break;
- if (get_rle_string(&str) == NULL)
- {
- exit_rle_string(&str);
- break;
- }
-
- tpmem->gtypes[i].gtype = g_type_from_name(get_rle_string(&str));
+ tpmem->gtypes[i].gtype = g_type_from_name(str.data);
result = (tpmem->gtypes[i].gtype != 0);
if (!result)
- log_variadic_message(LMT_ERROR, "Unknown type: '%s'", get_rle_string(&str));
+ log_variadic_message(LMT_ERROR, "Unknown type: '%s'", str.data);
else
tpmem->gtypes[i].gclass = g_type_class_ref(tpmem->gtypes[i].gtype);
- exit_rle_string(&str);
+ exit_sized_binary(&str);
}
- }
+ g_mutex_unlock(&tpmem->mutex);
- g_mutex_unlock(&tpmem->mutex);
+ }
return result;
@@ -285,38 +239,40 @@ bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
/******************************************************************************
* *
-* Paramètres : tpmem = mémoire à manipuler. *
-* pbuf = zone tampon à venir lire. *
+* Paramètres : tpmem = mémoire à consulter. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Crée une nouvelle instance d'objet à partir de son type. *
+* Description : Enregistre tous les types mémorisés dans un tampon. *
* *
-* Retour : Instance issue de l'opération ou NULL. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-GObject *g_type_memory_create_object(GTypeMemory *tpmem, packed_buffer_t *pbuf)
+bool g_type_memory_store(GTypeMemory *tpmem, int fd)
{
- GObject *result; /* Nouvelle instance à renvoyer*/
- uleb128_t index; /* Indice du point d'insertion */
- bool status; /* Bilan d'une récupération */
+ bool result; /* Bilan à enregistrer */
+ uint64_t i; /* Boucle de parcours */
+ const gchar *name; /* Désignation d'un type */
+ sized_binary_t str; /* Chaîne à conserver */
- result = NULL;
+ g_mutex_lock(&tpmem->mutex);
- status = unpack_uleb128(&index, pbuf);
+ result = store_uleb128((uleb128_t []){ tpmem->count }, fd);
- if (status)
+ for (i = 0; i < tpmem->count && result; i++)
{
- g_mutex_lock(&tpmem->mutex);
+ name = g_type_name(tpmem->gtypes[i].gtype);
- if (index < tpmem->count)
- result = g_object_new(tpmem->gtypes[index].gtype, NULL);
+ setup_sized_binary_from_static_string(&str, name);
- g_mutex_unlock(&tpmem->mutex);
+ store_sized_binary_as_string(&str, fd);
}
+ g_mutex_unlock(&tpmem->mutex);
+
return result;
}
@@ -325,60 +281,35 @@ GObject *g_type_memory_create_object(GTypeMemory *tpmem, packed_buffer_t *pbuf)
/******************************************************************************
* *
* Paramètres : tpmem = mémoire à manipuler. *
-* obj = instance dont le type est à mémoriser. *
-* pbuf = zone tampon à remplir. [OUT] *
+* fd = flux ouvert en lecture. *
* *
-* Description : Sauvegarde le type d'un objet instancié. *
+* Description : Crée une nouvelle instance d'objet à partir de son type. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Instance issue de l'opération ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_buffer_t *pbuf)
+GObject *g_type_memory_create_object_from_gtype(GTypeMemory *tpmem, int fd)
{
- bool result; /* Bilan à retourner */
- GType gtype; /* Type à enregistrer */
- size_t index; /* Indice du point d'insertion */
-
- gtype = G_TYPE_FROM_INSTANCE(obj);
+ GObject *result; /* Nouvelle instance à renvoyer*/
+ uleb128_t index; /* Indice du point d'insertion */
+ bool status; /* Bilan d'une récupération */
- /**
- * Pour quelques explications sur l'esquive suivante, se rapporter aux
- * commentaires de g_target_operand_unserialize().
- *
- * Dans la situation présente, on ne doit pas enregistrer le type dans le tampon,
- * car l'opérande va relancer l'opération entière (avec un opérande temporaire),
- * ce qui conduirait à l'enregistrement de deux types successifs dans les données.
- */
+ result = NULL;
- if (gtype == G_TYPE_TARGET_OPERAND)
- result = true;
+ status = load_uleb128(&index, fd);
- else
+ if (status)
{
g_mutex_lock(&tpmem->mutex);
- for (index = 0; index < tpmem->count; index++)
- if (tpmem->gtypes[index].gtype == gtype)
- break;
-
- if (index == tpmem->count)
- {
- tpmem->gtypes = realloc(tpmem->gtypes, ++tpmem->count * sizeof(gtype_ref_info_t));
-
- assert(tpmem->count > 0);
-
- tpmem->gtypes[index].gtype = gtype;
- tpmem->gtypes[index].gclass = g_type_class_ref(gtype);
-
- }
+ if (index < tpmem->count)
+ result = g_object_new(tpmem->gtypes[index].gtype, NULL);
g_mutex_unlock(&tpmem->mutex);
- result = pack_uleb128((uleb128_t []){ index }, pbuf);
-
}
return result;
@@ -388,10 +319,11 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b
/******************************************************************************
* *
-* Paramètres : tpmem = mémoire à consulter. *
-* pbuf = zone tampon à remplir. [OUT] *
+* Paramètres : tpmem = mémoire à manipuler. *
+* obj = instance dont le type est à mémoriser. *
+* fd = flux ouvert en écriture. *
* *
-* Description : Enregistre tous les types mémorisés dans un tampon. *
+* Description : Sauvegarde le type d'un objet instancié. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -399,31 +331,33 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b
* *
******************************************************************************/
-bool g_type_memory_store_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
+bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, int fd)
{
- bool result; /* Bilan à enregistrer */
- uint64_t i; /* Boucle de parcours */
- const gchar *name; /* Désignation d'un type */
- rle_string str; /* Chaîne à conserver */
+ bool result; /* Bilan à retourner */
+ GType gtype; /* Type à enregistrer */
+ size_t index; /* Indice du point d'insertion */
+
+ gtype = G_TYPE_FROM_INSTANCE(obj);
g_mutex_lock(&tpmem->mutex);
- result = pack_uleb128((uleb128_t []){ tpmem->count }, pbuf);
+ for (index = 0; index < tpmem->count; index++)
+ if (tpmem->gtypes[index].gtype == gtype)
+ break;
- for (i = 0; i < tpmem->count && result; i++)
+ if (index == tpmem->count)
{
- name = g_type_name(tpmem->gtypes[i].gtype);
-
- init_static_rle_string(&str, name);
+ tpmem->gtypes = realloc(tpmem->gtypes, ++tpmem->count * sizeof(gtype_ref_info_t));
- result = pack_rle_string(&str, pbuf);
-
- exit_rle_string(&str);
+ tpmem->gtypes[index].gtype = gtype;
+ tpmem->gtypes[index].gclass = g_type_class_ref(gtype);
}
g_mutex_unlock(&tpmem->mutex);
+ result = store_uleb128((uleb128_t []){ index }, fd);
+
return result;
}
diff --git a/src/glibext/tpmem.h b/src/glibext/tpmem.h
new file mode 100644
index 0000000..ccb8323
--- /dev/null
+++ b/src/glibext/tpmem.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tpmem.h - prototypes pour la mémorisation des types d'objets mis en cache
+ *
+ * Copyright (C) 2020-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_TPMEM_H
+#define _GLIBEXT_TPMEM_H
+
+
+#include <stdbool.h>
+
+
+#include "helpers.h"
+
+
+
+#define G_TYPE_TYPE_MEMORY (g_type_memory_get_type())
+
+DECLARE_GTYPE(GTypeMemory, g_type_memory, G, TYPE_MEMORY);
+
+
+/* Crée une mémoire pour types d'objets. */
+GTypeMemory *g_type_memory_new(void);
+
+/* Apprend tous les types mémorisés dans un tampon. */
+bool g_type_memory_load(GTypeMemory *, int);
+
+/* Enregistre tous les types mémorisés dans un tampon. */
+bool g_type_memory_store(GTypeMemory *, int);
+
+/* Crée une nouvelle instance d'objet à partir de son type. */
+GObject *g_type_memory_create_object_from_gtype(GTypeMemory *, int);
+
+/* Sauvegarde le type d'un objet instancié. */
+bool g_type_memory_store_object_gtype(GTypeMemory *, GObject *, int);
+
+
+
+#endif /* _GLIBEXT_TPMEM_H */
diff --git a/src/glibext/widthtracker.c b/src/glibext/widthtracker.c
index 7e06578..0a3dbe6 100644
--- a/src/glibext/widthtracker.c
+++ b/src/glibext/widthtracker.c
@@ -330,13 +330,17 @@ void g_width_tracker_set_column_min_width(GWidthTracker *tracker, size_t col, in
void g_width_tracker_compute_width(const GWidthTracker *tracker, int *width)
{
+ size_t col_count; /* Nombre maximum de colonnes */
size_t i; /* Boucle de parcours */
*width = 0;
- // FIX access to col_count
- for (i = 0; i < tracker->col_count; i++)
+
+ col_count = tracker->opt_count + tracker->reg_count;
+
+
+ for (i = 0; i < col_count; i++)
*width += tracker->min_widths[i];
}
diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am
index fd6c575..c6908dd 100644
--- a/src/gtkext/Makefile.am
+++ b/src/gtkext/Makefile.am
@@ -26,10 +26,19 @@ libgtkext_la_LIBADD = \
libgtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
+IMG_PATH = ../../data/images
+
RES_FILES = \
+ grid.ui \
+ dockstation.ui \
hexview.css \
hexview.ui \
- statusstack.ui
+ launcher.ui \
+ statusstack.ui \
+ $(IMG_PATH)/nolock-symbolic.svg \
+ $(IMG_PATH)/locked-symbolic.svg \
+ $(IMG_PATH)/unlocked-symbolic.svg \
+ tweak.ui
libgtkext4_la_SOURCES = \
area-int.h \
@@ -45,13 +54,21 @@ libgtkext4_la_SOURCES = \
helpers.h \
hexview-int.h \
hexview.h hexview.c \
+ launcher-int.h \
+ launcher.h launcher.c \
panel-int.h \
panel.h panel.c \
resources.h resources.c \
- statusstack.h statusstack.c
+ statusstack-int.h \
+ statusstack.h statusstack.c \
+ tweak-int.h \
+ tweak.h tweak.c
libgtkext4_la_CFLAGS = $(LIBGTK4_CFLAGS)
+libgtkext4_la_LIBADD = \
+ bindings/libgtkextbindings.la
+
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -59,6 +76,7 @@ dev_HEADERS = $(libgtkext4_la_SOURCES:%c=)
#SUBDIRS = graph
+SUBDIRS = bindings
resources.c: gresource.xml $(RES_FILES)
diff --git a/src/gtkext/area.c b/src/gtkext/area.c
index 3c59a59..3c573b2 100644
--- a/src/gtkext/area.c
+++ b/src/gtkext/area.c
@@ -85,6 +85,8 @@ static void gtk_composing_area_class_init(GtkComposingAreaClass *class)
widget = GTK_WIDGET_CLASS(class);
+ gtk_widget_class_set_css_name(widget, "comparea");
+
widget->snapshot = gtk_composing_area_snapshot;
}
diff --git a/src/gtkext/bindings/Makefile.am b/src/gtkext/bindings/Makefile.am
new file mode 100644
index 0000000..71e770d
--- /dev/null
+++ b/src/gtkext/bindings/Makefile.am
@@ -0,0 +1,42 @@
+
+EXTRA_DIST = \
+ generated-enums.c.template \
+ generated-enums.h.template
+
+
+noinst_LTLIBRARIES = libgtkextbindings.la
+
+
+nodist_libgtkextbindings_la_SOURCES = \
+ grid-enums.h grid-enums.c
+
+libgtkextbindings_la_CFLAGS = $(LIBGTK4_CFLAGS)
+
+
+BUILT_SOURCES = $(nodist_libgtkextbindings_la_SOURCES)
+CLEANFILES = $(nodist_libgtkextbindings_la_SOURCES)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(nodist_libgtkextbindings_la_SOURCES:%c=)
+
+
+grid-enums.c: ../../gtkext/grid.h generated-enums.c.template
+ $(AM_V_GEN)$(GLIB_MKENUMS) \
+ --fhead "#include \"$(subst .c,.h,$@)\"\n" \
+ --template=$(srcdir)/generated-enums.c.template \
+ --output=$(srcdir)/$@ \
+ $<
+
+grid-enums.h: ../../gtkext/grid.h generated-enums.h.template
+ $(AM_V_GEN)$(GLIB_MKENUMS) \
+ --fhead "#ifndef _GTKEXT_BINDINGS_GRID_ENUM_H\n" \
+ --fhead "#define _GTKEXT_BINDINGS_GRID_ENUM_H\n" \
+ --fhead "\n" \
+ --fhead "#include \"$<\"\n" \
+ --fhead "\n" \
+ --ftail "#endif /* _GTKEXT_BINDINGS_GRID_ENUM_H */\n" \
+ --template=$(srcdir)/generated-enums.h.template \
+ --output=$(srcdir)/$@ \
+ $<
diff --git a/src/gtkext/bindings/generated-enums.c.template b/src/gtkext/bindings/generated-enums.c.template
new file mode 100644
index 0000000..8f54149
--- /dev/null
+++ b/src/gtkext/bindings/generated-enums.c.template
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/*** BEGIN file-header ***/
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* Enumerations de "@filename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+
+GType @enum_name@_get_type(void)
+{
+ static gsize static_g_@type@_type_id;
+
+ if (g_once_init_enter(&static_g_@type@_type_id)) {
+ static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ {@VALUENAME@, "@VALUENAME@", "@valuenick@"},
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+
+ GType g_@type@_type_id = g_@type@_register_static(
+ g_intern_static_string("@EnumName@"), values);
+
+ g_once_init_leave (&static_g_@type@_type_id, g_@type@_type_id);
+ }
+
+ return static_g_@type@_type_id;
+}
+
+/*** END value-tail ***/
diff --git a/src/gtkext/bindings/generated-enums.h.template b/src/gtkext/bindings/generated-enums.h.template
new file mode 100644
index 0000000..58c772d
--- /dev/null
+++ b/src/gtkext/bindings/generated-enums.h.template
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2023-2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/*** BEGIN file-header ***/
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type(void) G_GNUC_CONST;
+#define @ENUMPREFIX@_@ENUMSHORT@_TYPE (@enum_name@_get_type())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+
+G_END_DECLS
+
+/*** END file-tail ***/
diff --git a/src/gtkext/bufferview.c b/src/gtkext/bufferview.c
index 6b8f17c..13c2632 100644
--- a/src/gtkext/bufferview.c
+++ b/src/gtkext/bufferview.c
@@ -279,9 +279,9 @@ GBufferView *gtk_buffer_view_get_view(const GtkBufferView *view)
/******************************************************************************
* *
-* Paramètres : widget = composant GTK à examiner. *
-* width = largeur affectée au composant graphique. *
-* height = hauteur affectée au composant graphique. *
+* Paramètres : widget = composant GTK à examiner. *
+* width = largeur affectée au composant graphique. *
+* height = hauteur affectée au composant graphique. *
* baseline = ligne de base affectée au composant graphique. *
* *
* Description : Prend acte de la taille allouée au composant d'affichage. *
diff --git a/src/gtkext/dockstation-int.h b/src/gtkext/dockstation-int.h
index a44371a..17ed828 100644
--- a/src/gtkext/dockstation-int.h
+++ b/src/gtkext/dockstation-int.h
@@ -32,19 +32,29 @@
/* Station de réception pour concentration d'éléments (instance) */
struct _GtkDockStation
{
- GtkWidget parent; /* A laisser en premier */
+ GtkBox parent; /* A laisser en premier */
+
+ GtkOrientation orientation; /* Spécification d'orientation */
+
+ GtkWidget *tabs; /* Bascule entre panneaux */
+ GtkWidget *toolbar; /* Boutons d'action */
+ GtkWidget *sep1; /* Séparateur #1 */
+ GtkStack *stack; /* Pile de panneaux affichés */
+ GtkWidget *sep2; /* Séparateur #2 */
+
+ GtkTiledPanel *def_panel; /* Eventuel panneau à maintenir*/
};
/* Station de réception pour concentration d'éléments (classe) */
struct _GtkDockStationClass
{
- GtkWidgetClass parent; /* A laisser en premier */
+ GtkBoxClass parent; /* A laisser en premier */
/* Signaux */
- void (* dock_widget) (GtkDockStation *, GtkWidget *);
- void (* undock_widget) (GtkDockStation *, GtkWidget *);
+ void (* panel_docked) (GtkDockStation *, GtkTiledPanel *);
+ void (* panel_undocked) (GtkDockStation *, GtkTiledPanel *);
void (* switch_widget) (GtkDockStation *, GtkWidget *);
diff --git a/src/gtkext/dockstation.c b/src/gtkext/dockstation.c
index 093f120..80bae75 100644
--- a/src/gtkext/dockstation.c
+++ b/src/gtkext/dockstation.c
@@ -28,6 +28,25 @@
+/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
+
+
+/* Liste des propriétés */
+
+typedef enum _DockStationProperty {
+
+ PROP_0, /* Réservé */
+
+ /* Interface GtkOrientable */
+ PROP_ORIENTATION,
+
+ N_PROPERTIES = PROP_ORIENTATION
+
+} DockStationProperty;
+
+//static GParamSpec *_dock_station_properties[N_PROPERTIES] = { NULL, };
+
+
/* Procède à l'initialisation de l'afficheur concentré. */
static void gtk_dock_station_class_init(GtkDockStationClass *);
@@ -35,16 +54,31 @@ static void gtk_dock_station_class_init(GtkDockStationClass *);
static void gtk_dock_station_init(GtkDockStation *);
/* Supprime toutes les références externes. */
-static void gtk_dock_station_dispose(GtkDockStation *);
+static void gtk_dock_station_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_dock_station_finalize(GtkDockStation *);
+static void gtk_dock_station_finalize(GObject *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_dock_station_set_property(GObject *, guint, const GValue *, GParamSpec *);
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_dock_station_get_property(GObject *, guint, GValue *, GParamSpec *);
+/* ---------------------------------------------------------------------------------- */
+/* INTERFACE DU COMPOSANT GTK */
+/* ---------------------------------------------------------------------------------- */
+
+
/* Détermine le type du composant d'affichage concentré. */
-G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_WIDGET)
+G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_GRID)
/******************************************************************************
@@ -62,28 +96,47 @@ G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_WIDGET)
static void gtk_dock_station_class_init(GtkDockStationClass *class)
{
GObjectClass *object; /* Autre version de la classe */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_dock_station_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_dock_station_finalize;
+ object->dispose = gtk_dock_station_dispose;
+ object->finalize = gtk_dock_station_finalize;
+ object->set_property = gtk_dock_station_set_property;
+ object->get_property = gtk_dock_station_get_property;
- g_signal_new("dock-widget",
+ //g_object_class_install_properties(object, N_PROPERTIES, _dock_station_properties);
+ g_object_class_override_property(object, PROP_ORIENTATION, "orientation");
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/dockstation.ui");
+
+ //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_status_stack_on_zoom_icon_press));
+
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, tabs);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, toolbar);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, sep1);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, stack);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, sep2);
+
+ g_signal_new("panel-docked",
GTK_TYPE_DOCK_STATION,
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GtkDockStationClass, dock_widget),
+ G_STRUCT_OFFSET(GtkDockStationClass, panel_docked),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
- g_signal_new("undock-widget",
+ g_signal_new("panel-undocked",
GTK_TYPE_DOCK_STATION,
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GtkDockStationClass, undock_widget),
+ G_STRUCT_OFFSET(GtkDockStationClass, panel_undocked),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
+ /*
g_signal_new("switch-widget",
GTK_TYPE_DOCK_STATION,
G_SIGNAL_RUN_LAST,
@@ -107,6 +160,7 @@ static void gtk_dock_station_class_init(GtkDockStationClass *class)
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
+ */
}
@@ -125,57 +179,66 @@ static void gtk_dock_station_class_init(GtkDockStationClass *class)
static void gtk_dock_station_init(GtkDockStation *station)
{
-#if 0
+ gtk_widget_init_template(GTK_WIDGET(station));
- GtkNotebook *notebook; /* Autre version du composant */
- GtkWidget *hbox; /* Division supérieure */
- GtkWidget *button; /* Bouton de contrôle */
+ station->orientation = GTK_ORIENTATION_HORIZONTAL;
- notebook = GTK_NOTEBOOK(station);
+ station->def_panel = NULL;
- gtk_notebook_set_show_border(notebook, FALSE);
- gtk_notebook_set_scrollable(notebook, TRUE);
+}
- /* Définition de la zone de contrôle */
- hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_widget_set_valign(hbox, GTK_ALIGN_CENTER);
- gtk_widget_set_margin_end(hbox, 8);
- gtk_widget_show(hbox);
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- button = qck_create_toggle_button_with_named_img(G_OBJECT(station), "search",
- "edit-find-symbolic", GTK_ICON_SIZE_MENU, NULL,
- G_CALLBACK(on_toggle_revealer), station);
- gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+static void gtk_dock_station_dispose(GObject *object)
+{
+ GtkDockStation *station; /* Version spécialisée */
- button = qck_create_button_with_named_img(G_OBJECT(station), "menu",
- "go-down-symbolic", GTK_ICON_SIZE_MENU, NULL,
- G_CALLBACK(on_click_for_menu), station);
- gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ station = GTK_DOCK_STATION(object);
- button = qck_create_button_with_named_img(G_OBJECT(station), "close",
- "window-close-symbolic", GTK_ICON_SIZE_MENU, NULL,
- G_CALLBACK(on_click_for_close), station);
- gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION);
- gtk_notebook_set_action_widget(notebook, hbox, GTK_PACK_END);
+ g_clear_object(&station->def_panel);
- g_signal_connect(notebook, "switch-page",
- G_CALLBACK(gtk_dock_station_switch_panel), station);
+ G_OBJECT_CLASS(gtk_dock_station_parent_class)->dispose(object);
-#endif
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_dock_station_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_dock_station_parent_class)->finalize(object);
}
/******************************************************************************
* *
-* Paramètres : station = instance d'objet GLib à traiter. *
+* Paramètres : - *
* *
-* Description : Supprime toutes les références externes. *
+* Description : Crée un nouveau composant pour support d'affichage concentré.*
* *
* Retour : - *
* *
@@ -183,18 +246,23 @@ static void gtk_dock_station_init(GtkDockStation *station)
* *
******************************************************************************/
-static void gtk_dock_station_dispose(GtkDockStation *station)
+GtkWidget *gtk_dock_station_new(void)
{
- G_OBJECT_CLASS(gtk_dock_station_parent_class)->dispose(G_OBJECT(station));
+ GtkWidget *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_DOCK_STATION, NULL);
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : station = instance d'objet GLib à traiter. *
+* Paramètres : station = station d'accueil pour panneaux à compléter. *
+* panel = nouveau panneau à afficher. *
* *
-* Description : Procède à la libération totale de la mémoire. *
+* Description : Ajoute un panneau à un groupe de tuiles. *
* *
* Retour : - *
* *
@@ -202,18 +270,33 @@ static void gtk_dock_station_dispose(GtkDockStation *station)
* *
******************************************************************************/
-static void gtk_dock_station_finalize(GtkDockStation *station)
+void gtk_dock_station_add_panel(GtkDockStation *station, GtkTiledPanel *panel)
{
- G_OBJECT_CLASS(gtk_dock_station_parent_class)->finalize(G_OBJECT(station));
+ GtkStackPage *page; /* Nouvelle page insérée */
+
+ page = gtk_stack_add_child(station->stack, GTK_WIDGET(panel));
+
+ if (0) // TODO
+ gtk_stack_page_set_title(page, "settings");
+
+ else
+ gtk_stack_page_set_icon_name(page, "logs-symbolic");
+
+ gtk_stack_set_visible_child(station->stack, GTK_WIDGET(panel));
+
+
+ g_signal_emit_by_name(station, "panel-docked", panel);
+
}
/******************************************************************************
* *
-* Paramètres : - *
+* Paramètres : station = station d'accueil pour panneaux à compléter. *
+* panel = nouveau panneau à afficher. *
* *
-* Description : Crée un nouveau composant pour support d'affichage concentré.*
+* Description : Ajoute un panneau à conserver à un groupe de tuiles. *
* *
* Retour : - *
* *
@@ -221,17 +304,300 @@ static void gtk_dock_station_finalize(GtkDockStation *station)
* *
******************************************************************************/
-GtkWidget *gtk_dock_station_new(void)
+void gtk_dock_station_keep_panel(GtkDockStation *station, GtkTiledPanel *panel)
{
- GtkWidget *result; /* Instance à retourner */
+ bool visible; /* Visibilité des barres */
- result = g_object_new(GTK_TYPE_DOCK_STATION, NULL);
+ g_clear_object(&station->def_panel);
+
+ if (panel != NULL)
+ {
+ station->def_panel = panel;
+ ref_object(panel);
+
+ if (gtk_stack_get_page(station->stack, GTK_WIDGET(panel)) == NULL)
+ gtk_dock_station_add_panel(station, panel);
+
+ }
+
+ visible = (station->def_panel == NULL);
+
+ gtk_widget_set_visible(station->tabs, visible);
+ gtk_widget_set_visible(station->toolbar, visible);
+ gtk_widget_set_visible(station->sep1, visible);
+ gtk_widget_set_visible(station->sep2, visible && station->orientation == GTK_ORIENTATION_HORIZONTAL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : station = station d'accueil pour panneaux à consulter. *
+* *
+* Description : Indique si la station d'accueil contient au moins un panneau.*
+* *
+* Retour : true si aucun panneau n'est intégré, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_dock_station_is_empty(const GtkDockStation *station)
+{
+ bool result; /* Bilan à retourner */
+ GtkSelectionModel *model; /* Modèle pour la pile */
+ guint count; /* Nombre de panneaux présents */
+
+ model = gtk_stack_get_pages(station->stack);
+
+ count = g_list_model_get_n_items(G_LIST_MODEL(model));
+
+ result = (count == 0);
+
+ unref_object(model);
return result;
}
+/******************************************************************************
+* *
+* Paramètres : station = station d'accueil pour panneaux à manipuler. *
+* main = panneau principal visé par l'opération. *
+* activated = nature du changement de statut : ajout, retrait ?*
+* *
+* Description : Note un ajout ou un retrait de panneau principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *station, GtkTiledPanel *main, bool activated)
+{
+ GListModel *list; /* Liste de pages à parcourir */
+ guint count; /* Nombre de pages */
+ guint i; /* Boucle de parcours */
+ GtkStackPage *page; /* Page à consulter */
+ GtkWidget *panel; /* Panneau intégré */
+
+ list = G_LIST_MODEL(gtk_stack_get_pages(station->stack));
+
+ count = g_list_model_get_n_items(list);
+
+ for (i = 0; i < count; i++)
+ {
+ page = GTK_STACK_PAGE(g_list_model_get_object(list, i));
+ if (page == NULL) continue;
+
+ panel = gtk_stack_page_get_child(page);
+
+ gtk_tiled_panel_notify_new_main_panel_state(GTK_TILED_PANEL(panel), main, activated);
+
+ unref_object(page);
+
+ }
+
+ unref_object(list);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
+* *
+* Description : Met à jour une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_dock_station_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GtkDockStation *station; /* Version spécialisée */
+ GtkOrientation orientation; /* Spécification d'orientation */
+ GtkLayoutManager *layout; /* Gestionnaire de disposition */
+ GtkLayoutChild *child_layout; /* Disposition de composant */
+
+ station = GTK_DOCK_STATION(object);
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+
+ orientation = g_value_get_enum(value);
+
+ if (station->orientation != orientation)
+ {
+ station->orientation = orientation;
+
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(station->tabs), orientation);
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(station->toolbar), orientation);
+
+ layout = gtk_widget_get_layout_manager(GTK_WIDGET(object));
+
+ if (orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ g_object_set(G_OBJECT(station->tabs),
+ "halign", GTK_ALIGN_START,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+
+ g_object_set(G_OBJECT(station->toolbar),
+ "halign", GTK_ALIGN_END,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 1,
+ "row", 0,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 0,
+ "row", 1,
+ "column-span", 2,
+ NULL);
+
+ gtk_widget_set_visible(station->sep2, FALSE);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack));
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 0,
+ "row", 2,
+ "column-span", 2,
+ NULL);
+
+ }
+ else
+ {
+ g_object_set(G_OBJECT(station->tabs),
+ "halign", GTK_ALIGN_START,
+ "valign", GTK_ALIGN_START,
+ NULL);
+
+ g_object_set(G_OBJECT(station->toolbar),
+ "halign", GTK_ALIGN_END,
+ "valign", GTK_ALIGN_START,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 1,
+ "row", 0,
+ "column-span", 1,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack));
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 2,
+ "row", 0,
+ "column-span", 1,
+ NULL);
+
+ gtk_widget_set_visible(station->sep2, TRUE);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->sep2);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 3,
+ "row", 0,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 4,
+ "row", 0,
+ NULL);
+
+ }
+
+ g_object_notify_by_pspec(object, pspec);
+
+ }
+
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_dock_station_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GtkDockStation *station; /* Version spécialisée */
+
+ station = GTK_DOCK_STATION(object);
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+ g_value_set_enum(value, station->orientation);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/gtkext/dockstation.h b/src/gtkext/dockstation.h
index a857626..e4c849f 100644
--- a/src/gtkext/dockstation.h
+++ b/src/gtkext/dockstation.h
@@ -28,6 +28,7 @@
#include <gtk/gtk.h>
+#include "panel.h"
#include "../glibext/helpers.h"
@@ -40,7 +41,17 @@ DECLARE_GTYPE(GtkDockStation, gtk_dock_station, GTK, DOCK_STATION);
/* Crée un nouveau composant pour support d'affichage concentré. */
GtkWidget *gtk_dock_station_new(void);
+/* Ajoute un panneau à un groupe de tuiles. */
+void gtk_dock_station_add_panel(GtkDockStation *, GtkTiledPanel *);
+/* Ajoute un panneau à conserver à un groupe de tuiles. */
+void gtk_dock_station_keep_panel(GtkDockStation *, GtkTiledPanel *);
+
+/* Indique si la station d'accueil contient au moins un panneau. */
+bool gtk_dock_station_is_empty(const GtkDockStation *);
+
+/* Note un ajout ou un retrait de panneau principal. */
+void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *, GtkTiledPanel *, bool);
diff --git a/src/gtkext/dockstation.ui b/src/gtkext/dockstation.ui
new file mode 100644
index 0000000..4d25134
--- /dev/null
+++ b/src/gtkext/dockstation.ui
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkDockStation" parent="GtkGrid">
+ <property name="orientation">horizontal</property>
+
+ <child>
+ <object class="GtkStackSwitcher" id="tabs">
+ <property name="orientation">horizontal</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="margin-start">2</property>
+ <property name="margin-top">2</property>
+ <property name="margin-end">2</property>
+ <property name="margin-bottom">2</property>
+ <property name="stack">stack</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="toolbar">
+ <property name="orientation">horizontal</property>
+ <property name="halign">end</property>
+ <property name="valign">start</property>
+
+ <child>
+ <object class="GtkButton">
+ <property name="icon-name">window-close-symbolic</property>
+ <style>
+ <class name="circular"/>
+ <class name="flat"/>
+ <class name="control-button"/>
+ </style>
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">4</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="sep1">
+ <property name="orientation">horizontal</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">0</property>
+ <property name="column-span">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="hexpand">true</property>
+ <layout>
+ <property name="column">2</property>
+ <property name="row">0</property>
+ <property name="column-span">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="sep2">
+ <property name="orientation">horizontal</property>
+ <layout>
+ <property name="column">3</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/gtkext/gresource.xml b/src/gtkext/gresource.xml
index 3bfd8c5..26943a6 100644
--- a/src/gtkext/gresource.xml
+++ b/src/gtkext/gresource.xml
@@ -1,8 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/re/chrysalide/framework/gtkext">
+ <file compressed="true">dockstation.ui</file>
+ <file compressed="true">grid.ui</file>
<file compressed="true">hexview.css</file>
<file compressed="true">hexview.ui</file>
+ <file compressed="true">launcher.ui</file>
<file compressed="true">statusstack.ui</file>
+ <file compressed="true">tweak.ui</file>
+ </gresource>
+ <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions">
+ <file compressed="true" alias="nolock-symbolic.svg">../../data/images/nolock-symbolic.svg</file>
+ <file compressed="true" alias="locked-symbolic.svg">../../data/images/locked-symbolic.svg</file>
+ <file compressed="true" alias="unlocked-symbolic.svg">../../data/images/unlocked-symbolic.svg</file>
</gresource>
</gresources>
diff --git a/src/gtkext/grid-int.h b/src/gtkext/grid-int.h
index 5ae48ad..8a2702b 100644
--- a/src/gtkext/grid-int.h
+++ b/src/gtkext/grid-int.h
@@ -25,46 +25,50 @@
#define _GTKEXT_GRID_INT_H
+#include "dockstation.h"
#include "grid.h"
-/* -------------------------- GESTION DES TUILES AFFICHEES -------------------------- */
-
-
-/* Informations concernant une tuile */
-typedef struct _grid_tile_t
+/* Conteneur pour un affichage en tuiles nommées (instance) */
+struct _GtkTilingGrid
{
- struct _grid_tile_t *parent; /* Tuile parente */
+ GtkGrid parent; /* A laisser en premier */
- GtkWidget *widget; /* Support d'affichage */
+ GSettings *settings; /* Configuration du conteneur */
- char *path; /* Chemin d'accès */
+ LayoutReachOptions layout; /* Disposition générale */
- struct _grid_tile_t *children[2]; /* Tuiles encastrées ou 2xNULL */
+ bool visible[TGB_COUNT]; /* Visibilités souhaitées */
-} grid_tile_t;
+ GtkRevealer *top; /* Zone d'accueil #1 */
+ GtkWidget *top_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *top_station; /* Station entière */
+ GtkRevealer *left; /* Zone d'accueil #2 */
+ GtkWidget *left_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *left_station; /* Station entière */
+ GtkDockStation *main_station; /* Zone d'accueil #3 */
-/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
+ GtkRevealer *right; /* Zone d'accueil #4 */
+ GtkWidget *right_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *right_station; /* Station entière */
+ GtkRevealer *bottom; /* Zone d'accueil #5 */
+ GtkWidget *bottom_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *bottom_station; /* Station entière */
-/* Conteneur pour un affichage en tuiles nommées (instance) */
-struct _GtkTilingGrid
-{
- GtkWidget parent; /* A laisser en premier */
-
- grid_tile_t *tiles; /* Tuiles représentées */
+ GtkGesture *tpad_gesture[TGB_COUNT]; /* Gestionnaires du touchpad */
- GtkTiledPanel *def_panel; /* Panneau principal par défaut*/
+ bool panning; /* Redimensionnement en cours */
};
/* Conteneur pour un affichage en tuiles nommées (classe) */
struct _GtkTilingGridClass
{
- GtkWidgetClass parent; /* A laisser en premier */
+ GtkGridClass parent; /* A laisser en premier */
/* Signaux */
diff --git a/src/gtkext/grid.c b/src/gtkext/grid.c
index 1b9c909..eb3cdf9 100644
--- a/src/gtkext/grid.c
+++ b/src/gtkext/grid.c
@@ -24,29 +24,43 @@
#include "grid.h"
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
#include "grid-int.h"
+#include "helpers.h"
+#include "bindings/grid-enums.h"
+
+/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
-/* -------------------------- GESTION DES TUILES AFFICHEES -------------------------- */
+/* Liste des propriétés */
+typedef enum _TilingGridProperty {
-#define IS_LEAF_TILE(t) \
- ({ \
- bool __result; \
- __result = GTK_IS_DOCK_STATION((t)->widget); \
- assert(__result || GTK_IS_PANED((t)->widget)); \
- __result; \
- })
+ PROP_0, /* Réservé */
+ PROP_LAYOUT, /* Disposition générale */
-/* Supprime une tuile de la mémoire. */
-static void delete_tile(grid_tile_t *);
+ PROP_EMPTY_TOP, /* Vide de la zone supérieure */
+ PROP_EMPTY_LEFT, /* Vide de la zone de gauche */
+ PROP_EMPTY_RIGHT, /* Vide de la zone de droite */
+ PROP_EMPTY_BOTTOM, /* Vide de la zone inférieure */
+ PROP_VISIBLE_TOP, /* Visibilité de zone sup. */
+ PROP_VISIBLE_LEFT, /* Visibilité de zone de gauche*/
+ PROP_VISIBLE_RIGHT, /* Visibilité de zone de droite*/
+ PROP_VISIBLE_BOTTOM, /* Visibilité de zone inf. */
+ N_PROPERTIES
-/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
+} TilingGridProperty;
+
+static GParamSpec *_tiling_grid_properties[N_PROPERTIES] = { NULL, };
/* Initialise la classe des conteneurs d'affichage en tuiles. */
@@ -56,48 +70,50 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *);
static void gtk_tiling_grid_init(GtkTilingGrid *);
/* Supprime toutes les références externes. */
-static void gtk_tiling_grid_dispose(GtkTilingGrid *);
+static void gtk_tiling_grid_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_tiling_grid_finalize(GtkTilingGrid *);
+static void gtk_tiling_grid_finalize(GObject *);
+/* Réagit à une intégration ou à un retrait de panneau. */
+static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *, GtkTiledPanel *, GtkTilingGrid *);
+/* -------------------- REDIMENSIONNEMENT DE ZONES POUR PANNEAUX -------------------- */
-/* ---------------------------------------------------------------------------------- */
-/* GESTION DES TUILES AFFICHEES */
-/* ---------------------------------------------------------------------------------- */
+/* Initie un redimensionnement par drag-and-drop. */
+static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *, double, double, GtkTilingGrid *);
-/******************************************************************************
-* *
-* Paramètres : tile = tuile à supprimer. *
-* *
-* Description : Supprime une tuile de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+/* Applique l'effet d'un redimensionnement drag-and-drop donné. */
+static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *, TilingGridBorder, double, double);
-static void delete_tile(grid_tile_t *tile)
-{
- if (!IS_LEAF_TILE(tile))
- {
- delete_tile(tile->children[0]);
- delete_tile(tile->children[1]);
- }
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
- else
- free(tile->path);
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
- unref_object(tile->widget);
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
- free(tile);
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
-}
+/* Clôture un drag-and-drop de redimensionnement. */
+static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *, double, double, GtkTilingGrid *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_tiling_grid_set_property(GObject *, guint, const GValue *, GParamSpec *);
+
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_tiling_grid_get_property(GObject *, guint, GValue *, GParamSpec *);
@@ -107,12 +123,12 @@ static void delete_tile(grid_tile_t *tile)
/* Détermine le type du conteneur d'affichage en tuiles nommées. */
-G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_WIDGET)
+G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_GRID)
/******************************************************************************
* *
-* Paramètres : klass = classe GTK à initialiser. *
+* Paramètres : class = classe GTK à initialiser. *
* *
* Description : Initialise la classe des conteneurs d'affichage en tuiles. *
* *
@@ -122,14 +138,101 @@ G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_WIDGET)
* *
******************************************************************************/
-static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass)
+static void gtk_tiling_grid_class_init(GtkTilingGridClass *class)
{
GObjectClass *object; /* Autre version de la classe */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_tiling_grid_dispose;
+ object->finalize = gtk_tiling_grid_finalize;
+ object->set_property = gtk_tiling_grid_set_property;
+ object->get_property = gtk_tiling_grid_get_property;
+
+ _tiling_grid_properties[PROP_LAYOUT] =
+ g_param_spec_flags("layout", NULL, NULL,
+ LAYOUT_REACH_OPTIONS_TYPE,
+ LRO_NONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_TOP] =
+ g_param_spec_boolean("empty-top", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_LEFT] =
+ g_param_spec_boolean("empty-left", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_RIGHT] =
+ g_param_spec_boolean("empty-right", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_BOTTOM] =
+ g_param_spec_boolean("empty-bottom", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * La valeur initiale des champs suivants est à maintenir synchronisée avec
+ * les initialisations de gtk_tiling_grid_init().
+ */
+
+ _tiling_grid_properties[PROP_VISIBLE_TOP] =
+ g_param_spec_boolean("visible-top", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_VISIBLE_LEFT] =
+ g_param_spec_boolean("visible-left", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_VISIBLE_RIGHT] =
+ g_param_spec_boolean("visible-right", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_VISIBLE_BOTTOM] =
+ g_param_spec_boolean("visible-bottom", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _tiling_grid_properties);
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ g_type_ensure(GTK_TYPE_DOCK_STATION);
- object = G_OBJECT_CLASS(klass);
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/grid.ui");
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tiling_grid_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_tiling_grid_finalize;
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_panel_un_docked));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_begin));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_top_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_left_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_right_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_bottom_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_end));
+
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, main_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_station);
+
+
+ /////////////
g_signal_new("station-created",
GTK_TYPE_TILING_GRID,
@@ -144,7 +247,7 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass)
/******************************************************************************
* *
-* Paramètres : tgrid = instance GTK à initialiser. *
+* Paramètres : grid = instance GTK à initialiser. *
* *
* Description : Initialise une instance de conteneur d'affichage en tuiles. *
* *
@@ -154,18 +257,70 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass)
* *
******************************************************************************/
-static void gtk_tiling_grid_init(GtkTilingGrid *tgrid)
+static void gtk_tiling_grid_init(GtkTilingGrid *grid)
{
- tgrid->tiles = NULL;
+ gtk_widget_init_template(GTK_WIDGET(grid));
+
+ grid->settings = g_settings_new_with_path("re.chrysalide.framework.tiledgrid",
+ "/re/chrysalide/framework/gui/tiles/");
+
+ g_settings_bind(grid->settings, "layout",
+ grid, "layout",
+ G_SETTINGS_BIND_DEFAULT);
+
+ /**
+ * L'initialisation des champs suivants est à maintenir synchronisée avec
+ * les valeurs initiales de gtk_tiling_grid_class_init().
+ */
+
+ grid->visible[TGB_TOP] = true;
+ grid->visible[TGB_LEFT] = true;
+ grid->visible[TGB_RIGHT] = true;
+ grid->visible[TGB_BOTTOM] = true;
+
+ g_settings_bind(grid->settings, "top-request",
+ grid->top_station, "height-request",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "top-visibility",
+ grid, "visible-top",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "left-request",
+ grid->left_station, "width-request",
+ G_SETTINGS_BIND_DEFAULT);
- tgrid->def_panel = NULL;
+ g_settings_bind(grid->settings, "left-visibility",
+ grid, "visible-left",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "right-request",
+ grid->right_station, "width-request",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "right-visibility",
+ grid, "visible-right",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "bottom-request",
+ grid->bottom_station, "height-request",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "bottom-visibility",
+ grid, "visible-bottom",
+ G_SETTINGS_BIND_DEFAULT);
+
+ gtk_widget_set_cursor_from_name(grid->top_handle, "row-resize");
+ gtk_widget_set_cursor_from_name(grid->left_handle, "col-resize");
+ gtk_widget_set_cursor_from_name(grid->right_handle, "col-resize");
+ gtk_widget_set_cursor_from_name(grid->bottom_handle, "row-resize");
}
/******************************************************************************
* *
-* Paramètres : grid = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -175,24 +330,24 @@ static void gtk_tiling_grid_init(GtkTilingGrid *tgrid)
* *
******************************************************************************/
-static void gtk_tiling_grid_dispose(GtkTilingGrid *grid)
+static void gtk_tiling_grid_dispose(GObject *object)
{
- if (grid->tiles != NULL)
- {
- delete_tile(grid->tiles);
- grid->tiles = NULL;
- }
+ GtkTilingGrid *grid; /* Version spécialisée */
+
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION);
+
+ grid = GTK_TILING_GRID(object);
- g_clear_object(&grid->def_panel);
+ g_clear_object(&grid->settings);
- G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->dispose(G_OBJECT(grid));
+ G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : grid = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -202,9 +357,9 @@ static void gtk_tiling_grid_dispose(GtkTilingGrid *grid)
* *
******************************************************************************/
-static void gtk_tiling_grid_finalize(GtkTilingGrid *grid)
+static void gtk_tiling_grid_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->finalize(G_OBJECT(grid));
+ G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->finalize(object);
}
@@ -232,142 +387,80 @@ GtkWidget *gtk_tiling_grid_new(void)
}
-
-
-
-
-#if 0
-
-
-#include <assert.h>
-#include <ctype.h>
-#include <malloc.h>
-#include <string.h>
-
-
-#include "../core/logs.h"
-
-
-
-/* Valide un chemin d'accès à une tuile. */
-static bool is_valid_tile_path(const char *);
-
-/* Crée une tuile finale d'affichage de panneaux. */
-static grid_tile_t *create_leaf_tile(const char *, GtkTiledGrid *);
-
-/* Crée une tuile intermédiaire d'affichage de panneaux. */
-static grid_tile_t *create_inter_tile(grid_tile_t *, bool, grid_tile_t *, grid_tile_t *);
-
-/* Supprime une tuile de la mémoire. */
-//static void delete_tile(grid_tile_t *);
-
-/* Calcule la taille comme entre un chemin et celui d'une tuile. */
-static size_t compute_tile_score(const grid_tile_t *, const char *);
-
-/* Indique la tuile adaptée pour un chemin donné. */
-static grid_tile_t *find_suitable_tile(grid_tile_t **, const char *, GtkTiledGrid *);
-
-/* Découpe une tuile pour y insérer une zone. */
-static grid_tile_t *split_tile(grid_tile_t **, const char *, char, GtkTiledGrid *);
-
-/* Tente de mettre la main sur une station d'accueil. */
-static grid_tile_t *find_tile_for_widget(grid_tile_t *, GtkWidget *);
-
-/* Retire une moitié de tuile vide au plein profit de l'autre. */
-static void collapse_tile(grid_tile_t *, grid_tile_t *);
-
-
-
-/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* GESTION DES TUILES AFFICHEES */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : path = chemin destiné à sélectionner une tuile. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* border = sélection de la zone à considérer. *
+* visible = nouveau statut de visibilité à appliquer. *
* *
-* Description : Valide un chemin d'accès à une tuile. *
+* Description : Affiche ou masque une zone du conteneur en tuiles. *
* *
-* Retour : true si le chemin est utilisable, false sinon. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool is_valid_tile_path(const char *path)
+void gtk_tiling_grid_set_visible(GtkTilingGrid *grid, TilingGridBorder border, bool visible)
{
- bool result; /* Bilan à retourner */
- size_t len; /* Taille du chemin */
- size_t i; /* Boucle de parcours */
- char c; /* Caractère de chemin analysé */
-
- /**
- * M[NESWnesw]*
- */
-
- len = strlen(path);
+ GtkRevealer *revealer; /* Cible visée par l'opération */
+ GtkDockStation *station; /* Apport d'une contrainte */
- result = (len >= 1);
+ if (grid->visible[border] != visible)
+ {
+ grid->visible[border] = visible;
- if (result)
- result = (path[0] == 'M');
+ switch (border)
+ {
+ case TGB_TOP:
+ revealer = grid->top;
+ station = grid->top_station;
+ break;
+
+ case TGB_LEFT:
+ revealer = grid->left;
+ station = grid->left_station;
+ break;
+
+ case TGB_RIGHT:
+ revealer = grid->right;
+ station = grid->right_station;
+ break;
+
+ case TGB_BOTTOM:
+ revealer = grid->bottom;
+ station = grid->bottom_station;
+ break;
- for (i = 1; i < len && result; i++)
- {
- c = path[i];
+ }
- if (c == '\0')
- break;
+ gtk_revealer_set_reveal_child(revealer, visible && !gtk_dock_station_is_empty(station));
- result = (c == 'N' || c == 'n'
- || c == 'E' || c == 'e'
- || c == 'S' || c == 's'
- || c == 'W' || c == 'w');
+ g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_VISIBLE_TOP + border]);
}
- return result;
-
}
/******************************************************************************
* *
-* Paramètres : path = chemin d'accès à la future tuile. *
-* tgrid = conteneur d'affichage en tuiles à manipuler. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* border = sélection de la zone à considérer. *
* *
-* Description : Crée une tuile finale d'affichage de panneaux. *
+* Description : Fournit la visibilité d'une zone du conteneur en tuiles. *
* *
-* Retour : Structure mise en place. *
+* Retour : Visibilité de la zone considérée. *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *create_leaf_tile(const char *path, GtkTiledGrid *tgrid)
+bool gtk_tiling_grid_get_visible(GtkTilingGrid *grid, TilingGridBorder border)
{
- grid_tile_t *result; /* Structure à retourner */
-
- result = (grid_tile_t *)malloc(sizeof(grid_tile_t));
-
- result->parent = NULL;
-
- result->widget = gtk_dock_station_new();
- gtk_widget_show(result->widget);
+ bool result; /* Statut à retourner */
- result->path = strdup(path);
-
- result->children[0] = NULL;
- result->children[1] = NULL;
-
- g_signal_emit_by_name(tgrid, "station-created", result->widget);
+ result = grid->visible[border];
return result;
@@ -376,333 +469,307 @@ static grid_tile_t *create_leaf_tile(const char *path, GtkTiledGrid *tgrid)
/******************************************************************************
* *
-* Paramètres : parent = tuile parente ou NULL si aucune. *
-* horiz = indique le type d'orientation désiré. *
-* first = première tuile à intégrer. *
-* second = seconde tuile à intégrer. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* panel = nouveau panneau à afficher. *
+* keep = indique si le panneau est à conserver présent. *
* *
-* Description : Crée une tuile intermédiaire d'affichage de panneaux. *
+* Description : Ajoute un panneau à un conteneur en tuiles. *
* *
-* Retour : Structure mise en place. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *create_inter_tile(grid_tile_t *parent, bool horiz, grid_tile_t *first, grid_tile_t *second)
+void gtk_tiling_grid_add_panel(GtkTilingGrid *grid, GtkTiledPanel *panel, bool keep)
{
- grid_tile_t *result; /* Structure à retourner */
- GtkWidget *container; /* Conteneur à vider */
-
- result = (grid_tile_t *)malloc(sizeof(grid_tile_t));
-
- result->parent = parent;
-
- if (horiz)
- result->widget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
- else
- result->widget = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+ char *path; /* Chemin visé par le panneau */
+ bool static_path; /* Nature du chemin à traiter */
- gtk_widget_show(result->widget);
+ path = gtk_tiled_panel_get_path(panel);
- result->path = NULL;
+ static_path = (path == NULL);
- result->children[0] = first;
- result->children[1] = second;
+ if (static_path)
+ path = "";
- /* Changement de propriétaire */
+ switch (path[0])
+ {
+ case 'N':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->top_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->top_station, panel);
+ break;
- container = gtk_widget_get_parent(first->widget);
+ case 'W':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->left_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->left_station, panel);
+ break;
- if (container != NULL)
- gtk_container_remove(GTK_CONTAINER(container), first->widget);
+ case '\0':
+ case 'M':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->main_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->main_station, panel);
+ break;
- g_object_ref(G_OBJECT(first->widget));
- gtk_paned_pack1(GTK_PANED(result->widget), first->widget, TRUE, FALSE);
+ case 'E':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->right_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->right_station, panel);
+ break;
- container = gtk_widget_get_parent(second->widget);
+ case 'S':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->bottom_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->bottom_station, panel);
+ break;
- if (container != NULL)
- gtk_container_remove(GTK_CONTAINER(container), second->widget);
+ default:
+ break;
- g_object_ref(G_OBJECT(second->widget));
- gtk_paned_pack2(GTK_PANED(result->widget), second->widget, TRUE, FALSE);
+ }
- return result;
+ if (!static_path)
+ free(path);
}
-
/******************************************************************************
* *
-* Paramètres : tile = tuile à analyser. *
-* path = chemin final complet recherché. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* main = panneau principal visé par l'opération. *
+* activated = nature du changement de statut : ajout, retrait ?*
* *
-* Description : Calcule la taille comme entre un chemin et celui d'une tuile.*
+* Description : Note un ajout ou un retrait de panneau principal. *
* *
-* Retour : Quantité de caractères communs. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static size_t compute_tile_score(const grid_tile_t *tile, const char *path)
+void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *grid, GtkTiledPanel *main, bool activated)
{
- size_t result; /* Nombre de points à renvoyer */
- size_t max; /* Taille du chemin de la tuile*/
- size_t i; /* Boucle de parcours */
- size_t score_0; /* Score du sous-élément #1 */
- size_t score_1; /* Score du sous-élément #2 */
-
- if (IS_LEAF_TILE(tile))
- {
- max = strlen(tile->path);
-
- if (strlen(path) < max)
- result = 0;
-
- else
- {
- result = 0;
-
- for (i = 0; i < max; i++)
- {
- if (tolower((unsigned char)tile->path[i]) == tolower((unsigned char)path[i]))
- result++;
- else
- break;
- }
+ gtk_dock_station_notify_new_main_panel_state(grid->top_station, main, activated);
- }
-
- }
- else
- {
- score_0 = compute_tile_score(tile->children[0], path);
- score_1 = compute_tile_score(tile->children[1], path);
+ gtk_dock_station_notify_new_main_panel_state(grid->left_station, main, activated);
- result = score_0 > score_1 ? score_0 : score_1;
+ gtk_dock_station_notify_new_main_panel_state(grid->main_station, main, activated);
- }
+ gtk_dock_station_notify_new_main_panel_state(grid->right_station, main, activated);
- return result;
+ gtk_dock_station_notify_new_main_panel_state(grid->bottom_station, main, activated);
}
/******************************************************************************
* *
-* Paramètres : tile = tuile ou NULL si aucune. [OUT] *
-* path = chemin d'accès à la tuile visée. *
-* tgrid = conteneur d'affichage en tuiles à manipuler. *
+* Paramètres : station = plateforme GTK ayant connu un changement. *
+* widget = nouvel élément à intégrer. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Indique la tuile adaptée pour un chemin donné. *
+* Description : Réagit à une intégration ou à un retrait de panneau. *
* *
-* Retour : Structure d'acceuil à disposition. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *find_suitable_tile(grid_tile_t **tile, const char *path, GtkTiledGrid *tgrid)
+static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *station, GtkTiledPanel *panel, GtkTilingGrid *grid)
{
- grid_tile_t *result; /* Structure à renvoyer */
- size_t best_len; /* Taille du chemin associé */
- size_t score_0; /* Score du sous-élément #1 */
- size_t score_1; /* Score du sous-élément #2 */
- char *sub_path; /* Nouvelle tentative d'accès */
- grid_tile_t **best; /* Direction à prendre */
- unsigned char next; /* Prochaine étape */
-
- /* Cas d'école : appel initial */
- if (*tile == NULL)
- {
- assert(path[0] == 'M' && path[1] == '\0');
-
- result = create_leaf_tile("M", tgrid);
- *tile = result;
+ TilingGridBorder border; /* Aire concernée par l'action */
+ GtkRevealer *revealer; /* Cible visée par l'opération */
+ bool new_state; /* Nouveau statut d'affichage */
+ if (station == grid->top_station)
+ {
+ border = TGB_TOP;
+ revealer = grid->top;
}
- else
+ else if (station == grid->left_station)
{
- if (IS_LEAF_TILE(*tile))
- {
- best_len = compute_tile_score(*tile, path);
-
- assert(best_len > 0);
+ border = TGB_LEFT;
+ revealer = grid->left;
+ }
- if (path[best_len] == '\0')
- result = *tile;
+ else if (station == grid->right_station)
+ {
+ border = TGB_RIGHT;
+ revealer = grid->right;
+ }
- else
- result = split_tile(tile, path, path[best_len], tgrid);
+ else if (station == grid->bottom_station)
+ {
+ border = TGB_BOTTOM;
+ revealer = grid->bottom;
+ }
- }
+ else
+ assert(false);
- else
- {
- score_0 = compute_tile_score((*tile)->children[0], path);
- score_1 = compute_tile_score((*tile)->children[1], path);
+ new_state = grid->visible[border] && !gtk_dock_station_is_empty(station);
- assert(score_0 > 0 || score_0 > 0);
+ if (gtk_revealer_get_reveal_child(revealer) != new_state)
+ gtk_revealer_set_reveal_child(revealer, new_state);
- if (score_0 == score_1)
- {
- sub_path = strndup(path, score_0);
+ /**
+ * On ne sait pas si l'état a réellement changé, mais on avertit
+ * d'une mise à jour quand même, au cas où.
+ */
- score_0 = compute_tile_score((*tile)->children[0], sub_path);
- score_1 = compute_tile_score((*tile)->children[1], sub_path);
+ g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_EMPTY_TOP + border]);
- free(sub_path);
+}
- }
- if (score_0 == score_1)
- result = split_tile(tile, path, path[score_0], tgrid);
- else
- {
- if (score_0 > score_1)
- {
- best = &(*tile)->children[0];
- best_len = score_0;
- }
- else
- {
- best = &(*tile)->children[1];
- best_len = score_1;
- }
-
- /**
- * Si on vient de tomber une feuille, trois cas de figure :
- * - soit c'est elle qui est visée.
- * - soit on veut la diviser.
- * - soit on veut la diviser en englobant ses voisines.
- */
-
- if (IS_LEAF_TILE(*best))
- {
- assert(best_len <= strlen(path));
-
- next = path[best_len];
-
- /* Premier cas */
- if (next == '\0')
- result = *best;
-
- else
- {
- /* Second cas */
- if (islower(next))
- result = find_suitable_tile(best, path, tgrid);
-
- /* Troisième cas */
- else
- result = split_tile(tile, path, next, tgrid);
-
- }
-
- }
-
- else
- result = find_suitable_tile(best, path, tgrid);
-
- }
+/* ---------------------------------------------------------------------------------- */
+/* REDIMENSIONNEMENT DE ZONES POUR PANNEAUX */
+/* ---------------------------------------------------------------------------------- */
- }
- }
+/******************************************************************************
+* *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* start_x = pointe de départ sur l'axe des abscisses. *
+* start_y = pointe de départ sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
+* *
+* Description : Initie un redimensionnement par drag-and-drop. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- assert(IS_LEAF_TILE(result));
+static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *gesture, double start_x, double start_y, GtkTilingGrid *grid)
+{
+ gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_CLAIMED);
- return result;
+ grid->panning = true;
}
/******************************************************************************
* *
-* Paramètres : tile = tuile à découper en deux. [OUT] *
-* path = chemin d'accès à la future tuile. *
-* endpoint = désignation de la zone représentée. *
-* tgrid = conteneur d'affichage en tuiles à manipuler. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* border = sélection de la zone à considérer. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
* *
-* Description : Découpe une tuile pour y insérer une zone. *
+* Description : Applique l'effet d'un redimensionnement drag-and-drop donné. *
* *
-* Retour : Structure fille mise en place. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *split_tile(grid_tile_t **tile, const char *path, char endpoint, GtkTiledGrid *tgrid)
+static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *grid, TilingGridBorder border, double offset_x, double offset_y)
{
- grid_tile_t *result; /* Création à retourner */
- GtkWidget *container; /* Conteneur à vider */
- grid_tile_t *new; /* Nouvelle tuile intermédiaire*/
+ GtkDockStation *station; /* Station entière */
+ int request; /* Taille requise */
+
+ /* Sélection de la poignée adaptée */
+
+ switch (border)
+ {
+ case TGB_TOP:
+ station = grid->top_station;
+ break;
+
+ case TGB_LEFT:
+ station = grid->left_station;
+ break;
- container = gtk_widget_get_parent((*tile)->widget);
+ case TGB_RIGHT:
+ station = grid->right_station;
+ break;
- /* Création */
+ case TGB_BOTTOM:
+ station = grid->bottom_station;
+ break;
- result = create_leaf_tile(path, tgrid);
+ }
- /* Encapsulation */
+ /* Détermination d'une nouvelle position et application */
- switch (endpoint)
+ switch (border)
{
- case 'N':
- case 'n':
- new = create_inter_tile((*tile)->parent, false, result, *tile);
+ case TGB_TOP:
+ case TGB_BOTTOM:
+ g_object_get(G_OBJECT(station), "height-request", &request, NULL);
break;
- case 'E':
- case 'e':
- new = create_inter_tile((*tile)->parent, true, *tile, result);
+ case TGB_LEFT:
+ case TGB_RIGHT:
+ g_object_get(G_OBJECT(station), "width-request", &request, NULL);
break;
- case 'S':
- case 's':
- new = create_inter_tile((*tile)->parent, false, *tile, result);
+ }
+
+ switch (border)
+ {
+ case TGB_TOP:
+ request += offset_y;
break;
- case 'W':
- case 'w':
- new = create_inter_tile((*tile)->parent, true, result, *tile);
+ case TGB_LEFT:
+ request += offset_x;
break;
- default:
- assert(false);
- new = NULL;
+ case TGB_RIGHT:
+ request += -offset_x;
+ break;
+
+ case TGB_BOTTOM:
+ request += -offset_y;
break;
}
- /* Connexions */
+ if (request > 0)
+ {
+ switch (border)
+ {
+ case TGB_TOP:
+ case TGB_BOTTOM:
+ g_object_set(G_OBJECT(station), "height-request", request, NULL);
+ break;
- *tile = new;
+ case TGB_LEFT:
+ case TGB_RIGHT:
+ g_object_set(G_OBJECT(station), "width-request", request, NULL);
+ break;
- result->parent = new;
+ }
- if (container != NULL)
- {
- g_object_ref(G_OBJECT(new->widget));
- gtk_container_add(GTK_CONTAINER(container), new->widget);
}
- return result;
-
}
/******************************************************************************
* *
-* Paramètres : tile = tuile parente, prochaine victime de promotion. *
-* side = côté de tuile amené à disparaître. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Retire une moitié de tuile vide au plein profit de l'autre. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
* Retour : - *
* *
@@ -710,114 +777,65 @@ static grid_tile_t *split_tile(grid_tile_t **tile, const char *path, char endpoi
* *
******************************************************************************/
-static void collapse_tile(grid_tile_t *tile, grid_tile_t *side)
+static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- grid_tile_t *promoted; /* Tuile à faire remonter */
- GtkWidget *container; /* Conteneur à vider */
-
- assert(!IS_LEAF_TILE(tile));
-
- /* Sélection du remplaçant */
-
- if (side == tile->children[0])
- promoted = tile->children[1];
- else
- promoted = tile->children[0];
-
- /* Etablissement d'une place nette */
-
- gtk_container_remove(GTK_CONTAINER(tile->widget), promoted->widget);
-
- container = gtk_widget_get_parent(tile->widget);
- gtk_container_remove(GTK_CONTAINER(container), tile->widget);
-
- delete_tile(side);
-
- /* Promotion effective */
-
- tile->widget = promoted->widget;
-
- tile->path = promoted->path;
-
- tile->children[0] = promoted->children[0];
- tile->children[1] = promoted->children[1];
-
- g_object_ref(G_OBJECT(promoted->widget));
- gtk_container_add(GTK_CONTAINER(container), tile->widget);
-
- free(promoted);
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_TOP, offset_x, offset_y);
}
/******************************************************************************
* *
-* Paramètres : tile = point de départ des recherches locales. *
-* widget = composant graphique à retrouver. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Tente de mettre la main sur une station d'accueil. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
-* Retour : Eventuelle tuile trouvée ou NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *find_tile_for_widget(grid_tile_t *tile, GtkWidget *widget)
+static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- grid_tile_t *result; /* Tuile à retourner */
-
- if (IS_LEAF_TILE(tile))
- result = tile->widget == widget ? tile : NULL;
-
- else
- {
- result = find_tile_for_widget(tile->children[0], widget);
-
- if (result == NULL)
- result = find_tile_for_widget(tile->children[1], widget);
-
- }
-
- return result;
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_LEFT, offset_x, offset_y);
}
-
-
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Donne le panneau fourni par défaut pour la zone principale. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
-* Retour : Panneau d'affichage par défault ou NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GPanelItem *gtk_tiled_grid_get_default_main_panel(const GtkTiledGrid *tgrid)
+static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- GPanelItem *result; /* Panneau à retourner */
-
- result = tgrid->def_panel;
-
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
-
- return result;
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_RIGHT, offset_x, offset_y);
}
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. *
-* panel = panneau d'affichage par défault ou NULL. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Fournit le panneau par défaut pour la zone principale. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
* Retour : - *
* *
@@ -825,56 +843,21 @@ GPanelItem *gtk_tiled_grid_get_default_main_panel(const GtkTiledGrid *tgrid)
* *
******************************************************************************/
-void gtk_tiled_grid_set_default_main_panel(GtkTiledGrid *tgrid, GPanelItem *panel)
+static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- GtkWidget *widget; /* Composant GTK à retirer */
- GtkWidget *parent; /* Conteneur à vider */
- grid_tile_t *tile; /* Première tuile d'accueil */
-
- if (tgrid->def_panel != NULL)
- {
- widget = gtk_dockable_build_widget(GTK_DOCKABLE(tgrid->def_panel));
-
- parent = gtk_widget_get_parent(widget);
-
- if (parent != NULL)
- gtk_container_remove(GTK_CONTAINER(parent), widget);
-
- g_object_unref(G_OBJECT(widget));
-
- g_object_unref(G_OBJECT(tgrid->def_panel));
-
- }
-
- tgrid->def_panel = panel;
-
- if (panel != NULL)
- {
- g_object_ref(G_OBJECT(panel));
-
- if (tgrid->tiles == NULL)
- gtk_tiled_grid_add(tgrid, panel);
-
- else
- {
- tile = find_suitable_tile(&tgrid->tiles, "M", tgrid);
-
- if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(tile->widget)) == 0)
- gtk_tiled_grid_add(tgrid, panel);
-
- }
-
- }
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_BOTTOM, offset_x, offset_y);
}
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. *
-* panel = panneau d'affichage à intégrer. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement final sur l'axe des abscisses. *
+* offset_y = déplacement final sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Incorpore un nouveau panneau dans le conteneur en tuiles. *
+* Description : Clôture un drag-and-drop de redimensionnement. *
* *
* Retour : - *
* *
@@ -882,66 +865,30 @@ void gtk_tiled_grid_set_default_main_panel(GtkTiledGrid *tgrid, GPanelItem *pane
* *
******************************************************************************/
-void gtk_tiled_grid_add(GtkTiledGrid *tgrid, GPanelItem *panel)
+static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- char *path; /* Chemin d'accès */
- char *name; /* Nom à donner à l'onglet */
- grid_tile_t *tile; /* Tuile d'accueil */
-
- path = gtk_panel_item_class_get_path(G_PANEL_ITEM_GET_CLASS(panel));
-
- if (!is_valid_tile_path(path))
- {
- name = gtk_dockable_get_name(GTK_DOCKABLE(panel));
- log_variadic_message(LMT_ERROR, _("Invalid path '%s' for panel '%s'"), path, name);
- free(name);
- }
-
+ if (!grid->panning)
+ gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_DENIED);
else
- {
- tile = find_suitable_tile(&tgrid->tiles, path, tgrid);
- assert(tile != NULL);
-
- gtk_dock_station_add_dockable(GTK_DOCK_STATION(tile->widget), GTK_DOCKABLE(panel));
+ grid->panning = false;
- g_panel_item_set_dock_at_startup(panel, true);
-
- /* Si c'est la toute première fois... */
- if (gtk_widget_get_parent(tile->widget) == NULL)
- {
- assert(tile == tgrid->tiles);
- assert(tile->path[0] == 'M' && tile->path[1] == '\0');
- g_object_ref(G_OBJECT(tile->widget));
- gtk_container_add(GTK_CONTAINER(tgrid), tile->widget);
- }
-
- /* Si on n'a plus besoin du panneau par défaut */
- if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0')
- {
- /* Si ce n'est pas le panneau qu'on vient de rajouter...*/
- if (panel != tgrid->def_panel)
- {
- /* Enfin : si ce panneau par défaut est réellement en place */
- if (g_panel_item_is_docked(tgrid->def_panel))
- gtk_tiled_grid_remove(tgrid, tgrid->def_panel);
-
- }
-
- }
+}
- }
- free(path);
-}
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. *
-* panel = panneau d'affichage à supprimer. *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
* *
-* Description : Retire un panneau dans le conteneur en tuiles. *
+* Description : Met à jour une propriété d'instance GObject. *
* *
* Retour : - *
* *
@@ -949,90 +896,65 @@ void gtk_tiled_grid_add(GtkTiledGrid *tgrid, GPanelItem *panel)
* *
******************************************************************************/
-void gtk_tiled_grid_remove(GtkTiledGrid *tgrid, GPanelItem *panel)
+static void gtk_tiling_grid_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
- GtkWidget *station; /* Support courant */
- grid_tile_t *tile; /* Tuile d'accueil */
-
- assert(g_panel_item_is_docked(panel));
-
- gtk_dockable_decompose(GTK_DOCKABLE(panel), &station);
-
- tile = find_tile_for_widget(tgrid->tiles, station);
- assert(tile != NULL);
+ GtkTilingGrid *grid; /* Version spécialisée */
- gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(panel));
+ grid = GTK_TILING_GRID(object);
- g_panel_item_set_dock_at_startup(panel, false);
-
- if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(station)) == 0)
+ switch (prop_id)
{
- /* Si le panneau par défaut devient nécessaire */
- if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0')
- gtk_tiled_grid_add(tgrid, tgrid->def_panel);
-
- else
- {
- /* La racine est concernée ! */
- if (tile->parent == NULL)
+ case PROP_LAYOUT:
+ if (grid->layout != g_value_get_flags(value))
{
- assert(tile == tgrid->tiles);
+ grid->layout = g_value_get_flags(value);
- g_object_ref(G_OBJECT(tile->widget));
- gtk_container_remove(GTK_CONTAINER(tgrid), tile->widget);
+ apply_tiling_grid_layout(GTK_GRID(grid), grid->layout, (GtkWidget *[]) {
+ GTK_WIDGET(grid->top), GTK_WIDGET(grid->left),
+ GTK_WIDGET(grid->right), GTK_WIDGET(grid->bottom)
+ });
- delete_tile(tile);
- tgrid->tiles = NULL;
+ g_object_notify_by_pspec(object, pspec);
}
+ break;
- else
- collapse_tile(tile->parent, tile);
-
- }
-
- }
-
-}
-
+ gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value));
+ break;
-/******************************************************************************
-* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. *
-* station = station d'accueil à retrouver. *
-* *
-* Description : Indique le chemin correspondant à une station intégrée. *
-* *
-* Retour : Copie de chemin trouvé, à libérer ensuite, ou NULL si échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ case PROP_VISIBLE_TOP:
+ gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value));
+ break;
-char *gtk_tiled_grid_get_path_for_station(const GtkTiledGrid *tgrid, GtkDockStation *station)
-{
- char *result; /* Chemin d'accès à renvoyer */
- grid_tile_t *tile; /* Tuile d'accueil */
+ case PROP_VISIBLE_LEFT:
+ gtk_tiling_grid_set_visible(grid, TGB_LEFT, g_value_get_boolean(value));
+ break;
- tile = find_tile_for_widget(tgrid->tiles, GTK_WIDGET(station));
+ case PROP_VISIBLE_RIGHT:
+ gtk_tiling_grid_set_visible(grid, TGB_RIGHT, g_value_get_boolean(value));
+ break;
- if (tile == NULL)
- result = NULL;
+ case PROP_VISIBLE_BOTTOM:
+ gtk_tiling_grid_set_visible(grid, TGB_BOTTOM, g_value_get_boolean(value));
+ break;
- else
- result = strdup(tile->path);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
- return result;
+ }
}
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à mettre à jour. *
-* config = configuration à consulter. *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
* *
-* Description : Replace les positions des séparateurs de tuiles. *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
* *
* Retour : - *
* *
@@ -1040,57 +962,68 @@ char *gtk_tiled_grid_get_path_for_station(const GtkTiledGrid *tgrid, GtkDockStat
* *
******************************************************************************/
-void gtk_tiled_grid_restore_positions(const GtkTiledGrid *tgrid, GGenConfig *config)
+static void gtk_tiling_grid_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
+ GtkTilingGrid *grid; /* Version spécialisée */
- void visit_tiles_for_restoring(grid_tile_t *tile, const char *vpath)
- {
- GtkOrientation orientation; /* Direction de la tuile */
- char hint; /* Inutile donc indispensable */
- char *key; /* Clef d'accès à un paramètre */
- gint position; /* Nouvelle position de barre */
- size_t i; /* Boucle de parcours */
- char *child_key; /* Clef d'accès des suivants */
-
- if (!IS_LEAF_TILE(tile))
- {
- orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget));
+ grid = GTK_TILING_GRID(object);
- hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v';
+ switch (prop_id)
+ {
+ case PROP_EMPTY_TOP:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->top_station));
+ break;
- asprintf(&key, "%s%c", vpath, hint);
+ case PROP_EMPTY_LEFT:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->left_station));
+ break;
- if (g_generic_config_get_value(config, key, &position))
- gtk_paned_set_position(GTK_PANED(tile->widget), position);
+ case PROP_EMPTY_RIGHT:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->right_station));
+ break;
- for (i = 0; i < 2; i++)
- {
- asprintf(&child_key, "%s%zu", key, i);
+ case PROP_EMPTY_BOTTOM:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->bottom_station));
+ break;
- visit_tiles_for_restoring(tile->children[i], child_key);
+ case PROP_VISIBLE_TOP:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_TOP));
+ break;
- free(child_key);
+ case PROP_VISIBLE_LEFT:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_LEFT));
+ break;
- }
+ case PROP_VISIBLE_RIGHT:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_RIGHT));
+ break;
- free(key);
+ case PROP_VISIBLE_BOTTOM:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_BOTTOM));
+ break;
- }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
}
+}
- visit_tiles_for_restoring(tgrid->tiles, "gui.panels.positions.R");
-}
+
+/* ---------------------------------------------------------------------------------- */
+/* FORME GENERIQUE DE MISE EN DISPOSITION */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. *
-* config = configuration à mettre à jour. *
+* Paramètres : grid = composant GTK dont le contenu est à arranger. *
+* options = options de mise en place. *
+* panels = liste organisée de composants à déplacer. *
* *
-* Description : Sauvegarde les positions des séparateurs de tuiles. *
+* Description : Met en place une disposition particulière de panneaux. *
* *
* Retour : - *
* *
@@ -1098,49 +1031,98 @@ void gtk_tiled_grid_restore_positions(const GtkTiledGrid *tgrid, GGenConfig *con
* *
******************************************************************************/
-void gtk_tiled_grid_save_positions(const GtkTiledGrid *tgrid, GGenConfig *config)
+void apply_tiling_grid_layout(GtkGrid *grid, LayoutReachOptions options, GtkWidget *panels[TGB_COUNT])
{
-
- void visit_tiles_for_saving(grid_tile_t *tile, const char *vpath)
+ int top_panel_span; /* Etendue d'un composant #1 */
+ int left_panel_span; /* Etendue d'un composant #2 */
+ int right_panel_span; /* Etendue d'un composant #3 */
+ int bottom_panel_span; /* Etendue d'un composant #4 */
+ int top_panel_column; /* Position de composant #1 */
+ int left_panel_row; /* Position de composant #2 */
+ int right_panel_row; /* Position de composant #3 */
+ int bottom_panel_column; /* Position de composant #4 */
+ GtkLayoutManager *layout; /* Gestionnaire de disposition */
+ GtkGridLayoutChild *top_panel_layout; /* Disposition de composant #1 */
+ GtkGridLayoutChild *left_panel_layout; /* Disposition de composant #2 */
+ GtkGridLayoutChild *right_panel_layout; /* Disposition de composant #3 */
+ GtkGridLayoutChild *bottom_panel_layout;/* Disposition de composant #4 */
+
+ /* Calcul des placements */
+
+ top_panel_span = 3;
+ left_panel_span = 3;
+ right_panel_span = 3;
+ bottom_panel_span = 3;
+
+ if (options & LRO_LEFT_TOP_REACH)
{
- GtkOrientation orientation; /* Direction de la tuile */
- char hint; /* Inutile donc indispensable */
- char *key; /* Clef d'accès à un paramètre */
- gint position; /* Nouvelle position de barre */
- size_t i; /* Boucle de parcours */
- char *child_key; /* Clef d'accès des suivants */
-
- if (!IS_LEAF_TILE(tile))
- {
- orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget));
-
- hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v';
+ top_panel_column = 1;
+ top_panel_span--;
+ left_panel_row = 0;
+ }
+ else
+ {
+ top_panel_column = 0;
+ left_panel_row = 1;
+ left_panel_span--;
+ }
- asprintf(&key, "%s%c", vpath, hint);
+ if (options & LRO_LEFT_BOTTOM_REACH)
+ {
+ bottom_panel_column = 1;
+ bottom_panel_span--;
+ }
+ else
+ {
+ left_panel_span--;
+ bottom_panel_column = 0;
+ }
- position = gtk_paned_get_position(GTK_PANED(tile->widget));
- g_generic_config_create_or_udpdate_param(config, key, CPT_INTEGER, -1, position);
+ if (options & LRO_RIGHT_TOP_REACH)
+ {
+ top_panel_span--;
+ right_panel_row = 0;
+ }
+ else
+ {
+ right_panel_row = 1;
+ right_panel_span--;
+ }
- for (i = 0; i < 2; i++)
- {
- asprintf(&child_key, "%s%zu", key, i);
+ if (options & LRO_RIGHT_BOTTOM_REACH)
+ bottom_panel_span--;
+ else
+ right_panel_span--;
- visit_tiles_for_saving(tile->children[i], child_key);
+ /* Mise en application des contraintes */
- free(child_key);
+ layout = gtk_widget_get_layout_manager(GTK_WIDGET(grid));
- }
+ top_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_TOP]));
+ left_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_LEFT]));
+ right_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_RIGHT]));
+ bottom_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_BOTTOM]));
- free(key);
+ g_object_set(G_OBJECT(top_panel_layout),
+ "column", top_panel_column,
+ "column-span", top_panel_span,
+ NULL);
- }
+ g_object_set(G_OBJECT(left_panel_layout),
+ "row", left_panel_row,
+ "row-span", left_panel_span,
+ NULL);
- }
+ g_object_set(G_OBJECT(right_panel_layout),
+ "row", right_panel_row,
+ "row-span", right_panel_span,
+ NULL);
+ g_object_set(G_OBJECT(bottom_panel_layout),
+ "column", bottom_panel_column,
+ "column-span", bottom_panel_span,
+ NULL);
- visit_tiles_for_saving(tgrid->tiles, "gui.panels.positions.R");
+ gtk_layout_manager_layout_changed(layout);
}
-
-
-#endif
diff --git a/src/gtkext/grid.h b/src/gtkext/grid.h
index d9b7ef1..fd98035 100644
--- a/src/gtkext/grid.h
+++ b/src/gtkext/grid.h
@@ -25,10 +25,10 @@
#define _GTKEXT_GRID_H
+#include <stdbool.h>
#include <gtk/gtk.h>
-#include "dockstation.h"
#include "panel.h"
#include "../glibext/helpers.h"
@@ -42,7 +42,51 @@ DECLARE_GTYPE(GtkTilingGrid, gtk_tiling_grid, GTK, TILING_GRID);
/* Crée une nouvelle instance de conteneur avec tuiles. */
GtkWidget *gtk_tiling_grid_new(void);
+/* Liste des zones de bordure */
+typedef enum _TilingGridBorder /*< skip (glib-mkenums) >*/
+{
+ TGB_TOP, /* Zone supérieure */
+ TGB_LEFT, /* Zone de gauche */
+ TGB_RIGHT, /* Zone de droite */
+ TGB_BOTTOM, /* Zone inférieure */
+} TilingGridBorder;
+
+/**
+ * Fixe le nombre de combinaisons sans le rendre visible dans l'énumération.
+ */
+#define TGB_COUNT (TGB_BOTTOM + 1)
+
+/* Affiche ou masque une zone du conteneur en tuiles. */
+void gtk_tiling_grid_set_visible(GtkTilingGrid *, TilingGridBorder, bool);
+
+/* Fournit la visibilité d'une zone du conteneur en tuiles. */
+bool gtk_tiling_grid_get_visible(GtkTilingGrid *, TilingGridBorder);
+
+/* Ajoute un panneau à un conteneur en tuiles. */
+void gtk_tiling_grid_add_panel(GtkTilingGrid *, GtkTiledPanel *, bool);
+
+/* Note un ajout ou un retrait de panneau principal. */
+void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *, GtkTiledPanel *, bool);
+
+
+
+/* --------------------- FORME GENERIQUE DE MISE EN DISPOSITION --------------------- */
+
+
+/* Options de dispositions cumulables */
+typedef enum _LayoutReachOptions /*< flags (glib-mkenums) >*/
+{
+ LRO_NONE = (0 << 0), /* Aucune atteinte des bords */
+ LRO_LEFT_TOP_REACH = (1 << 0), /* Atteinte du bord haut à G. */
+ LRO_LEFT_BOTTOM_REACH = (1 << 1), /* Atteinte du bord bas à G. */
+ LRO_RIGHT_TOP_REACH = (1 << 2), /* Atteinte du bord haut à D. */
+ LRO_RIGHT_BOTTOM_REACH = (1 << 3), /* Atteinte du bord bas à D. */
+
+} LayoutReachOptions;
+
+/* Met en place une disposition particulière de panneaux. */
+void apply_tiling_grid_layout(GtkGrid *, LayoutReachOptions, GtkWidget *[TGB_COUNT]);
diff --git a/src/gtkext/grid.ui b/src/gtkext/grid.ui
new file mode 100644
index 0000000..b14ced2
--- /dev/null
+++ b/src/gtkext/grid.ui
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkTilingGrid" parent="GtkGrid">
+
+ <!-- Zone supérieure -->
+
+ <child>
+ <object class="GtkRevealer" id="top">
+ <property name="transition-type">slide-up</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkDockStation" id="top_station">
+ <property name="orientation">vertical</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">false</property>
+ <property name="height-request">30</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="top_handle">
+ <property name="orientation">vertical</property>
+ <property name="height-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_top_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="column-span">3</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone de gauche -->
+
+ <child>
+ <object class="GtkRevealer" id="left">
+ <property name="transition-type">slide-right</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+
+ <child>
+ <object class="GtkDockStation" id="left_station">
+ <property name="orientation">vertical</property>
+ <property name="hexpand">false</property>
+ <property name="vexpand">true</property>
+ <property name="width-request">300</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="left_handle">
+ <property name="orientation">horizontal</property>
+ <property name="width-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_left_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">0</property>
+ <property name="row">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone centrale -->
+
+ <child>
+ <object class="GtkDockStation" id="main_station">
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone de droite -->
+
+ <child>
+ <object class="GtkRevealer" id="right">
+ <property name="transition-type">slide-left</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+
+ <child>
+ <object class="GtkSeparator" id="right_handle">
+ <property name="orientation">horizontal</property>
+ <property name="width-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_right_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkDockStation" id="right_station">
+ <property name="orientation">vertical</property>
+ <property name="hexpand">false</property>
+ <property name="vexpand">true</property>
+ <property name="width-request">300</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">2</property>
+ <property name="row">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone inférieure -->
+
+ <child>
+ <object class="GtkRevealer" id="bottom">
+ <property name="transition-type">slide-up</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkSeparator" id="bottom_handle">
+ <property name="orientation">vertical</property>
+ <property name="height-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_bottom_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkDockStation" id="bottom_station">
+ <property name="orientation">horizontal</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">false</property>
+ <property name="height-request">250</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">0</property>
+ <property name="row">2</property>
+ <property name="column-span">3</property>
+ </layout>
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/gtkext/hexview.c b/src/gtkext/hexview.c
index 6df1140..95b592e 100644
--- a/src/gtkext/hexview.c
+++ b/src/gtkext/hexview.c
@@ -37,6 +37,22 @@
/* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */
+/* Liste des propriétés */
+
+typedef enum _HexViewProperty {
+
+ PROP_0, /* Réservé */
+
+ PROP_SHOW_OFFSETS, /* Affichage des positions */
+ PROP_CONTENT, /* Contenu binaire affiché */
+
+ N_PROPERTIES
+
+} HexViewProperty;
+
+static GParamSpec *_hex_view_properties[N_PROPERTIES] = { NULL, };
+
+
/* Initialise la classe des afficheurs de tampons bruts. */
static void gtk_hex_view_class_init(GtkHexViewClass *);
@@ -44,10 +60,10 @@ static void gtk_hex_view_class_init(GtkHexViewClass *);
static void gtk_hex_view_init(GtkHexView *);
/* Supprime toutes les références externes. */
-static void gtk_hex_view_dispose(GtkHexView *);
+static void gtk_hex_view_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_hex_view_finalize(GtkHexView *);
+static void gtk_hex_view_finalize(GObject *);
/* Procède à l'actualisation de l'affichage d'un sous-composant. */
static void gtk_hex_view_dispatch_sub_snapshot(GtkWidget *, GtkSnapshot *, GtkWidget *);
@@ -57,14 +73,14 @@ static void gtk_hex_view_populate_cache(GtkHexView *);
-void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent);
-
-
-
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_hex_view_set_property(GObject *, guint, const GValue *, GParamSpec *);
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_hex_view_get_property(GObject *, guint, GValue *, GParamSpec *);
/* Prend acte de la taille allouée au composant d'affichage. */
static void gtk_hex_view_size_allocate(GtkWidget *, int, int, int);
@@ -105,12 +121,26 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class)
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_hex_view_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_hex_view_finalize;
+ object->dispose = gtk_hex_view_dispose;
+ object->finalize = gtk_hex_view_finalize;
+ object->set_property = gtk_hex_view_set_property;
+ object->get_property = gtk_hex_view_get_property;
+
+ _hex_view_properties[PROP_SHOW_OFFSETS] =
+ g_param_spec_boolean("show-offsets", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ _hex_view_properties[PROP_CONTENT] =
+ g_param_spec_object("content", NULL, NULL,
+ G_TYPE_BIN_CONTENT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _hex_view_properties);
widget = GTK_WIDGET_CLASS(class);
- // REMME gtk_widget_class_set_css_name(widget, "GtkHexView");
+ gtk_widget_class_set_css_name(widget, "hexview");
g_type_ensure(GTK_TYPE_COMPOSING_AREA);
@@ -167,12 +197,14 @@ static void gtk_hex_view_init(GtkHexView *view)
view->generator = NULL;
+ gtk_hex_view_create(view, NULL);
+
}
/******************************************************************************
* *
-* Paramètres : view = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -182,20 +214,24 @@ static void gtk_hex_view_init(GtkHexView *view)
* *
******************************************************************************/
-static void gtk_hex_view_dispose(GtkHexView *view)
+static void gtk_hex_view_dispose(GObject *object)
{
- gtk_widget_dispose_template(GTK_WIDGET(view), GTK_TYPE_HEX_VIEW);
+ GtkHexView *view; /* Version spécialisée */
+
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_HEX_VIEW);
+
+ view = GTK_HEX_VIEW(object);
g_clear_object(&view->generator);
- G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(G_OBJECT(view));
+ G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : view = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -205,9 +241,9 @@ static void gtk_hex_view_dispose(GtkHexView *view)
* *
******************************************************************************/
-static void gtk_hex_view_finalize(GtkHexView *view)
+static void gtk_hex_view_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(G_OBJECT(view));
+ G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(object);
}
@@ -263,13 +299,43 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content)
parent = GTK_BUFFER_VIEW(view);
- cache = g_buffer_cache_new(1, 2);
+ cache = g_buffer_cache_new(1 /* opt_count */, 2 /* reg_count */);
parent->view = g_buffer_view_new(cache, parent->style);
unref_object(cache);
- view->generator = g_hex_generator_new(content);
+
+
+ gtk_hex_view_set_content(view, content);
+
+
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = composant d'affichage à consulter. *
+* *
+* Description : Fournit le contenu associé au composant d'affichage. *
+* *
+* Retour : Contenu dans lequel puise le générateur pour les lignes. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBinContent *gtk_hex_view_get_content(const GtkHexView *view)
+{
+ GBinContent *result; /* Référence à retourner */
+
+ if (view->generator != NULL)
+ result = g_hex_generator_get_content(view->generator);
+ else
+ result = NULL;
return result;
@@ -278,6 +344,61 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content)
/******************************************************************************
* *
+* Paramètres : view = composant d'affichage à modifier. *
+* content = nouveau contenu pour source de génération. *
+* *
+* Description : Définit le contenu associé au composant d'affichage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_hex_view_set_content(GtkHexView *view, GBinContent *content)
+{
+ GBinContent *old; /* Ancienne valeur */
+ GBufferCache *cache; /* Tampon à représenter */
+
+ old = gtk_hex_view_get_content(view);
+
+ assert((old == NULL && view->generator == NULL) || (old != NULL && view->generator != NULL));
+
+ if (old != content)
+ {
+ if (view->generator != NULL)
+ {
+ cache = g_buffer_view_get_cache(GTK_BUFFER_VIEW(view)->view);
+
+ g_buffer_cache_wlock(cache);
+
+ g_buffer_cache_truncate(cache, 0);
+
+ g_buffer_cache_wunlock(cache);
+
+ unref_object(cache);
+
+ g_clear_object(&view->generator);
+
+ }
+
+ if (content != NULL)
+ view->generator = g_hex_generator_new(content);
+
+ g_object_notify_by_pspec(G_OBJECT(view), _hex_view_properties[PROP_CONTENT]);
+
+ assert(content != NULL);
+ gtk_widget_queue_resize(GTK_WIDGET(view));
+
+ }
+
+ g_clear_object(&old);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : widget = composant GTK à redessiner. *
* snapshot = gestionnaire de noeuds de rendu à solliciter. *
* parent = composant GTK parent et cadre de l'appel. *
@@ -380,67 +501,108 @@ static void gtk_hex_view_populate_cache(GtkHexView *view)
/* Mise à jour de l'affichage ? */
+ /*
if (needed != count)
gtk_widget_queue_resize(GTK_WIDGET(view));
+ */
}
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
+* *
+* Description : Met à jour une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
-
-void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent)
+static void gtk_hex_view_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
- GdkRGBA red, green, yellow, blue;
- float w, h;
-
- gdk_rgba_parse (&red, "red");
- gdk_rgba_parse (&green, "green");
- gdk_rgba_parse (&yellow, "yellow");
- gdk_rgba_parse (&blue, "blue");
+ GtkHexView *view; /* Version spécialisée */
+ GObject *content; /* Contenu sous forme simple */
- w = gtk_widget_get_width (widget) / 2.0;
- h = gtk_widget_get_height (widget) / 2.0;
+ view = GTK_HEX_VIEW(object);
- h /= 2.0;
+ switch (prop_id)
+ {
+ case PROP_SHOW_OFFSETS:
+ g_display_options_set(GTK_CONTENT_VIEW(view)->options, HCO_OFFSET, g_value_get_boolean(value));
+ gtk_widget_set_visible(view->offsets, g_value_get_boolean(value));
+ break;
- gtk_snapshot_append_color (snapshot, &red,
- &GRAPHENE_RECT_INIT(0, 0, w, h));
- gtk_snapshot_append_color (snapshot, &green,
- &GRAPHENE_RECT_INIT(w, 0, w, h));
- gtk_snapshot_append_color (snapshot, &yellow,
- &GRAPHENE_RECT_INIT(0, h, w, h));
- gtk_snapshot_append_color (snapshot, &blue,
- &GRAPHENE_RECT_INIT(w, h, w, h));
+ case PROP_CONTENT:
+ content = g_value_get_object(value);
+ gtk_hex_view_set_content(view, G_BIN_CONTENT(content));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
}
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+static void gtk_hex_view_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GtkHexView *view; /* Version spécialisée */
+ view = GTK_HEX_VIEW(object);
+ switch (prop_id)
+ {
+ case PROP_SHOW_OFFSETS:
+ g_value_set_boolean(value, gtk_widget_get_visible(view->offsets));
+ break;
+ case PROP_CONTENT:
+ g_value_take_object(value, gtk_hex_view_get_content(view));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
+}
/******************************************************************************
* *
-* Paramètres : widget = composant GTK à examiner. *
-* width = largeur affectée au composant graphique. *
-* height = hauteur affectée au composant graphique. *
+* Paramètres : widget = composant GTK à examiner. *
+* width = largeur affectée au composant graphique. *
+* height = hauteur affectée au composant graphique. *
* baseline = ligne de base affectée au composant graphique. *
* *
* Description : Prend acte de la taille allouée au composant d'affichage. *
@@ -467,7 +629,13 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height,
final_widths = alloca(_CHILDREN_COUNT * sizeof(int));
for (i = 0; i < _CHILDREN_COUNT; i++)
- gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL);
+ {
+ if (!gtk_widget_get_visible(view->children[i]))
+ min_widths[i] = 0;
+ else
+ gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL);
+
+ }
/* Passe 1 : tentative sans défilement vertical */
@@ -491,7 +659,10 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height,
for (i = 0; i < _CHILDREN_COUNT; i++)
{
- final_widths[i] += min_widths[i];
+ if (!gtk_widget_get_visible(view->children[i]))
+ final_widths[i] = 0;
+ else
+ final_widths[i] += min_widths[i];
g_width_tracker_set_column_min_width(tracker, i, final_widths[i]);
@@ -531,17 +702,6 @@ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget)
}
-
-
-
-
-
-
-
-
-
-
-
/******************************************************************************
* *
* Paramètres : widget = composant GTK à examiner. *
@@ -580,8 +740,12 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation,
for (i = 0; i < _CHILDREN_COUNT; i++)
{
+ if (!gtk_widget_get_visible(view->children[i]))
+ continue;
+
gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL);
requested += min;
+
}
for_size -= requested;
@@ -593,11 +757,14 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation,
GTK_BUFFER_VIEW(view)->style,
for_size);
- if (minimum != NULL) *minimum = 0;
+ if (minimum != NULL) *minimum = requested;
if (natural != NULL) *natural = requested;
for (i = 0; i < _CHILDREN_COUNT; i++)
{
+ if (!gtk_widget_get_visible(view->children[i]))
+ continue;
+
gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL);
if (minimum != NULL && min > *minimum)
diff --git a/src/gtkext/hexview.h b/src/gtkext/hexview.h
index 2199786..0d2cd5a 100644
--- a/src/gtkext/hexview.h
+++ b/src/gtkext/hexview.h
@@ -41,6 +41,12 @@ DECLARE_GTYPE(GtkHexView, gtk_hex_view, GTK, HEX_VIEW);
/* Crée un composant d'affichage d'octets bruts et imprimables. */
GtkHexView *gtk_hex_view_new(GBinContent *);
+/* Fournit le contenu associé au composant d'affichage. */
+GBinContent *gtk_hex_view_get_content(const GtkHexView *);
+
+/* Définit le contenu associé au composant d'affichage. */
+void gtk_hex_view_set_content(GtkHexView *, GBinContent *);
+
#endif /* _GTKEXT_HEXVIEW_H */
diff --git a/src/gtkext/hexview.ui b/src/gtkext/hexview.ui
index ae4586c..9b42936 100644
--- a/src/gtkext/hexview.ui
+++ b/src/gtkext/hexview.ui
@@ -1,27 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkHexView" parent="GtkBufferView">
- <property name="css-name">GtkHexView</property>
- <child>
- <object class="GtkComposingArea" id="offsets">
- <style>
- <class name="gutter"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkComposingArea" id="hex">
- <property name="hexpand">true</property>
- <style>
- <class name="custom-view"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkComposingArea" id="ascii">
- <style>
- <class name="custom-view"/>
- </style>
- </object>
- </child>
- </template>
+
+ <template class="GtkHexView" parent="GtkBufferView">
+ <child>
+ <object class="GtkComposingArea" id="offsets">
+ <style>
+ <class name="gutter"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkComposingArea" id="hex">
+ <property name="hexpand">true</property>
+ <style>
+ <class name="custom-view"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkComposingArea" id="ascii">
+ <style>
+ <class name="custom-view"/>
+ </style>
+ </object>
+ </child>
+ </template>
+
</interface>
diff --git a/src/gtkext/launcher-int.h b/src/gtkext/launcher-int.h
new file mode 100644
index 0000000..07152f0
--- /dev/null
+++ b/src/gtkext/launcher-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak-int.h - définitions internes pour un lanceur de panneau majeur
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GTKEXT_LAUNCHER_INT_H
+#define _GTKEXT_LAUNCHER_INT_H
+
+
+#include "launcher.h"
+
+
+
+/* Elément de lancement d'un panneau majeur pour l'interface (instance) */
+struct _GtkPanelLauncher
+{
+ GtkListBoxRow parent; /* A laisser en premier */
+
+ GtkImage *icon; /* Eventuelle image */
+ GtkLabel *title; /* Etiquette associée */
+ GtkLabel *desc; /* Description du panneau */
+
+};
+
+/* Elément de lancement d'un panneau majeur pour l'interface (classe) */
+struct _GtkPanelLauncherClass
+{
+ GtkListBoxRowClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un nouveau lanceur de panneau majeur. */
+bool gtk_panel_launcher_create(GtkPanelLauncher *, const char *, const char *, const char *);
+
+
+
+#endif /* _GTKEXT_LAUNCHER_INT_H */
diff --git a/src/gtkext/launcher.c b/src/gtkext/launcher.c
new file mode 100644
index 0000000..5bb850b
--- /dev/null
+++ b/src/gtkext/launcher.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * launcher.c - lanceur de panneau majeur
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "launcher.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "helpers.h"
+#include "launcher-int.h"
+#include "../common/extstr.h"
+
+
+
+/* Initialise la classe des sections d'éléments paramétrables. */
+static void gtk_panel_launcher_class_init(GtkPanelLauncherClass *);
+
+/* Initialise une instance de lanceur de panneau majeur. */
+static void gtk_panel_launcher_init(GtkPanelLauncher *);
+
+/* Supprime toutes les références externes. */
+static void gtk_panel_launcher_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_panel_launcher_finalize(GObject *);
+
+
+
+/* Détermine le type du composant d'affichage générique. */
+G_DEFINE_TYPE(GtkPanelLauncher, gtk_panel_launcher, GTK_TYPE_LIST_BOX_ROW);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Initialise la classe des sections d'éléments paramétrables. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_class_init(GtkPanelLauncherClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_panel_launcher_dispose;
+ object->finalize = gtk_panel_launcher_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/launcher.ui");
+
+ gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, icon);
+ gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, title);
+ gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, desc);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : launcher = composant GTK à initialiser. *
+* *
+* Description : Initialise une instance de lanceur de panneau majeur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_init(GtkPanelLauncher *launcher)
+{
+ gtk_widget_init_template(GTK_WIDGET(launcher));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_dispose(GObject *object)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PANEL_LAUNCHER);
+
+ G_OBJECT_CLASS(gtk_panel_launcher_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_panel_launcher_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : icon = désignation de l'image de représentation. *
+* title = titre principal à afficher. *
+* desc = description du panneau ciblé. *
+* *
+* Description : Crée un nouveau lanceur de panneau majeur. *
+* *
+* Retour : Composant GTK mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkPanelLauncher *gtk_panel_launcher_new(const char *icon, const char *title, const char *desc)
+{
+ GtkPanelLauncher *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_PANEL_LAUNCHER, NULL);
+
+ if (!gtk_panel_launcher_create(result, icon, title, desc))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : launcher = lanceur à initialiser pleinement. *
+* icon = désignation de l'image de représentation. *
+* title = titre principal à afficher. *
+* desc = description du panneau ciblé. *
+* *
+* Description : Met en place un nouveau lanceur de panneau majeur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_panel_launcher_create(GtkPanelLauncher *launcher, const char *icon, const char *title, const char *desc)
+{
+ bool result; /* Bilan à retourner */
+ char *bold; /* Titre sublimé */
+
+ result = true;
+
+ gtk_image_set_from_icon_name(launcher->icon, icon);
+
+ bold = strdup(title);
+ bold = strprep(bold, "<b>");
+ bold = stradd(bold, "</b>");
+
+ gtk_label_set_label(launcher->title, bold);
+
+ free(bold);
+
+ gtk_label_set_label(launcher->desc, desc);
+
+ return result;
+
+}
diff --git a/src/gtkext/launcher.h b/src/gtkext/launcher.h
new file mode 100644
index 0000000..3857216
--- /dev/null
+++ b/src/gtkext/launcher.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * launcher.h - prototypes pour pour un lanceur de panneau majeur
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GTKEXT_LAUNCHER_H
+#define _GTKEXT_LAUNCHER_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../glibext/helpers.h"
+
+
+
+#define GTK_TYPE_PANEL_LAUNCHER (gtk_panel_launcher_get_type())
+
+DECLARE_GTYPE(GtkPanelLauncher, gtk_panel_launcher, GTK, PANEL_LAUNCHER);
+
+
+/* Crée un nouveau lanceur de panneau majeur. */
+GtkPanelLauncher *gtk_panel_launcher_new(const char *, const char *, const char *);
+
+
+
+#endif /* _GTKEXT_LAUNCHER_H */
diff --git a/src/gtkext/launcher.ui b/src/gtkext/launcher.ui
new file mode 100644
index 0000000..f6f4fec
--- /dev/null
+++ b/src/gtkext/launcher.ui
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkPanelLauncher" parent="GtkListBoxRow">
+
+ <property name="child">
+
+ <object class="GtkGrid">
+ <property name="margin-bottom">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">12</property>
+ <property name="column-spacing">12</property>
+
+ <child>
+ <object class="GtkImage" id="icon">
+ <property name="icon-name"></property>
+ <property name="pixel-size">48</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="row-span">2</property>
+ </layout>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="label"></property>
+ <property name="use-markup">TRUE</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="desc">
+ <property name="label"></property>
+ <property name="hexpand">true</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">1</property>
+ </layout>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">go-next-symbolic</property>
+ <property name="margin-start">12</property>
+ <layout>
+ <property name="column">2</property>
+ <property name="row">0</property>
+ <property name="row-span">2</property>
+ </layout>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+
+ </property>
+
+ </template>
+</interface>
diff --git a/src/gtkext/panel-int.h b/src/gtkext/panel-int.h
index 07ade20..5398e51 100644
--- a/src/gtkext/panel-int.h
+++ b/src/gtkext/panel-int.h
@@ -30,9 +30,14 @@
+/* Indique l'emplacement par défaut pour un affichage. */
+typedef char * (* get_tiled_panel_path) (const GtkTiledPanel *);
+
/* Fournit les composants adaptés pour la barre de titre. */
-typedef GListStore * (* get_tiled_panel_widgets_cb) (GtkTiledPanel *, bool);
+typedef GListStore * (* get_tiled_panel_widgets_cb) (const GtkTiledPanel *, bool);
+/* Note un ajout ou un retrait de panneau principal. */
+typedef void (* notify_tiled_panel_state_cb) (GtkTiledPanel *, GtkTiledPanel *, bool);
/* Elément réactif pour panneaux de l'éditeur (instance) */
@@ -47,8 +52,11 @@ struct _GtkTiledPanelClass
{
GtkBoxClass parent; /* A laisser en premier */
+ get_tiled_panel_path get_default_path; /* Localisation de l'affichage */
get_tiled_panel_widgets_cb get_widgets; /* Récupération de composants */
+ notify_tiled_panel_state_cb notify; /* Note d'un ajout ou retrait */
+
};
diff --git a/src/gtkext/panel.c b/src/gtkext/panel.c
index de55917..f63cfa1 100644
--- a/src/gtkext/panel.c
+++ b/src/gtkext/panel.c
@@ -137,6 +137,35 @@ static void gtk_tiled_panel_finalize(GtkTiledPanel *panel)
/******************************************************************************
* *
* Paramètres : panel = panneau graphique à consulter. *
+* *
+* Description : Indique l'emplacement attendu pour un affichage. *
+* *
+* Retour : Chemin représenté ou NULL pour l'emplacement "M" par défaut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *gtk_tiled_panel_get_path(const GtkTiledPanel *panel)
+{
+ char *result; /* Chemin à retourner */
+ GtkTiledPanelClass *class; /* Classe à actionner */
+
+ class = GTK_TILED_PANEL_GET_CLASS(panel);
+
+ if (class->get_default_path != NULL)
+ result = class->get_default_path(panel);
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau graphique à consulter. *
* left = indication quant au côté ciblé. *
* *
* Description : Fournit les composants adaptés pour la barre de titre. *
@@ -147,7 +176,7 @@ static void gtk_tiled_panel_finalize(GtkTiledPanel *panel)
* *
******************************************************************************/
-GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *panel, bool left)
+GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *panel, bool left)
{
GListStore *result; /* Composant(s) à retourner */
GtkTiledPanelClass *class; /* Classe à actionner */
@@ -164,6 +193,32 @@ GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *panel, bool left)
}
+/******************************************************************************
+* *
+* Paramètres : panel = panneau graphique à manipuler. *
+* main = panneau principal visé par l'opération. *
+* activated = nature du changement de statut : ajout, retrait ?*
+* *
+* Description : Note un ajout ou un retrait de panneau principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *panel, GtkTiledPanel *main, bool activated)
+{
+ GtkTiledPanelClass *class; /* Classe à actionner */
+
+ class = GTK_TILED_PANEL_GET_CLASS(panel);
+
+ if (class->notify != NULL)
+ class->notify(panel, main, activated);
+
+}
+
+
diff --git a/src/gtkext/panel.h b/src/gtkext/panel.h
index d2259ef..9b00657 100644
--- a/src/gtkext/panel.h
+++ b/src/gtkext/panel.h
@@ -38,9 +38,14 @@
DECLARE_GTYPE(GtkTiledPanel, gtk_tiled_panel, GTK, TILED_PANEL);
+/* Indique l'emplacement attendu pour un affichage. */
+char *gtk_tiled_panel_get_path(const GtkTiledPanel *);
+
/* Fournit les composants adaptés pour la barre de titre. */
-GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *, bool);
+GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *, bool);
+/* Note un ajout ou un retrait de panneau principal. */
+void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *, GtkTiledPanel *, bool);
diff --git a/src/gtkext/statusstack-int.h b/src/gtkext/statusstack-int.h
index facc5af..721b982 100644
--- a/src/gtkext/statusstack-int.h
+++ b/src/gtkext/statusstack-int.h
@@ -26,6 +26,7 @@
#include "statusstack.h"
+#include "../glibext/secstorage.h"
@@ -49,6 +50,12 @@ struct _GtkStatusStack
GSourceFunc def_source; /* Appel en fin d'activité */
+ /* Message simple par défaut */
+
+ GtkLabel *def_label; /* Afficheur de message */
+
+ char *msg; /* Contenu associé */
+
/* Navigation */
GtkLabel *nav_segment; /* Désignation du segment */
@@ -70,6 +77,9 @@ struct _GtkStatusStack
/* Tronc commun */
+ GSecretStorage *storage; /* Stockage des secrets */
+ GtkToggleButton *lock_update; /* Activation des accès */
+
GtkLabel *net_recv_speed; /* Débit en réception */
GtkLabel *net_send_speed; /* Débit en émission */
@@ -80,6 +90,8 @@ struct _GtkStatusStack
guint network_update_tag; /* Identifiant de mise à jour */
+ GtkToggleButton *bottom_toggler; /* Bascule de panneaux inf. */
+
};
/* Gestion de barre de statut adaptable (classe) */
diff --git a/src/gtkext/statusstack.c b/src/gtkext/statusstack.c
index 0d8ef62..92c296a 100644
--- a/src/gtkext/statusstack.c
+++ b/src/gtkext/statusstack.c
@@ -41,6 +41,25 @@
/* -------------------------- GESTION GENERALE DES STATUTS -------------------------- */
+/* Liste des propriétés */
+
+typedef enum _StatusStackProperty {
+
+ PROP_0, /* Réservé */
+
+ PROP_SHOW_BOTTOM, /* Affichage de la zone inf. */
+
+ N_PROPERTIES
+
+} StatusStackProperty;
+
+static GParamSpec *_status_stack_properties[N_PROPERTIES] = { NULL, };
+
+
+/* Source d'affichage par défaut */
+#define gtk_status_stack_default_source gtk_status_stack_show_simple_message
+
+
/* Initialise la classe des barres de statut améliorées. */
static void gtk_status_stack_class_init(GtkStatusStackClass *);
@@ -53,11 +72,33 @@ static void gtk_status_stack_dispose(GtkStatusStack *);
/* Procède à la libération totale de la mémoire. */
static void gtk_status_stack_finalize(GtkStatusStack *);
+/* Note le changement de verrouillage du stockage sécurisé. */
+static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *, GtkStatusStack *);
+
/* Met à jour dans la barre les débits réseau observés. */
static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *);
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_status_stack_set_property(GObject *, guint, const GValue *, GParamSpec *);
+
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_status_stack_get_property(GObject *, guint, GValue *, GParamSpec *);
+
+
+
+/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */
+
+
+/* S'assure de l'affichage à jour de la partie "default". */
+static gboolean gtk_status_stack_show_simple_message(gpointer);
+
+
+
/* -------------------- STATUT DES INFORMATIONS DE DESASSEMBLAGE -------------------- */
@@ -86,7 +127,7 @@ static void init_navigation_info(navigation_info_t *);
static void fini_navigation_info(navigation_info_t *);
/* S'assure de l'affichage à jour de la partie "navigation". */
-static gboolean gtk_status_stack_show_current_location(GtkStatusStack *);
+static gboolean gtk_status_stack_show_current_location(gpointer);
/* Réagit à un clic sur l'icône de zoom. */
static void gtk_status_stack_on_zoom_icon_press(GtkEntry *, GtkEntryIconPosition, GtkStatusStack *);
@@ -136,7 +177,7 @@ static void fini_activity_info(activity_info_t *);
static activity_status_t *find_activity_status_by_id(activity_info_t *, activity_id_t);
/* S'assure de l'affichage à jour de la partie "activité". */
-static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *);
+static gboolean gtk_status_stack_show_current_activity(gpointer);
@@ -170,6 +211,15 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class)
object->dispose = (GObjectFinalizeFunc/* ! */)gtk_status_stack_dispose;
object->finalize = (GObjectFinalizeFunc)gtk_status_stack_finalize;
+ object->set_property = gtk_status_stack_set_property;
+ object->get_property = gtk_status_stack_get_property;
+
+ _status_stack_properties[PROP_SHOW_BOTTOM] =
+ g_param_spec_boolean("show-bottom", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _status_stack_properties);
widget = GTK_WIDGET_CLASS(class);
@@ -179,6 +229,8 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class)
gtk_widget_class_bind_template_child(widget, GtkStatusStack, main);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, def_label);
+
gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_segment);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_phys);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_virt);
@@ -190,9 +242,13 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class)
gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_message);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_progress);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, lock_update);
+
gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_recv_speed);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_send_speed);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, bottom_toggler);
+
}
@@ -212,7 +268,9 @@ static void gtk_status_stack_init(GtkStatusStack *stack)
{
gtk_widget_init_template(GTK_WIDGET(stack));
- stack->def_source = NULL;
+ stack->def_source = gtk_status_stack_default_source;
+
+ stack->msg = NULL;
stack->nav_info = calloc(1, sizeof(navigation_info_t));
init_navigation_info(stack->nav_info);
@@ -220,11 +278,26 @@ static void gtk_status_stack_init(GtkStatusStack *stack)
stack->activity_info = calloc(1, sizeof(activity_info_t));
init_activity_info(stack->activity_info);
+ /* Suivi des évolutions relatives au stockage sécurisé */
+
+ stack->storage = get_secret_storage();
+
+ g_signal_connect(stack->storage, "lock-update",
+ G_CALLBACK(gtk_status_stack_on_secret_storage_lock_update), stack);
+
+ gtk_status_stack_on_secret_storage_lock_update(stack->storage, stack);
+
+ /* Suivi des débits de connexion */
+
stack->next_index = 0;
stack->network_update_tag = g_timeout_add(NETWORK_UPDATE_INTERVAL,
G_SOURCE_FUNC(gtk_status_stack_update_network_stats), stack);
+ /* Premier affichage... */
+
+ gtk_status_stack_reset_to_default(stack);
+
}
@@ -242,6 +315,12 @@ static void gtk_status_stack_init(GtkStatusStack *stack)
static void gtk_status_stack_dispose(GtkStatusStack *stack)
{
+ if (stack->storage != NULL)
+ g_signal_handlers_disconnect_by_func(stack->storage,
+ gtk_status_stack_on_secret_storage_lock_update, stack);
+
+ g_clear_object(&stack->storage);
+
g_source_remove(stack->network_update_tag);
gtk_widget_dispose_template(GTK_WIDGET(stack), GTK_TYPE_STATUS_STACK);
@@ -265,6 +344,9 @@ static void gtk_status_stack_dispose(GtkStatusStack *stack)
static void gtk_status_stack_finalize(GtkStatusStack *stack)
{
+ if (stack->msg != NULL)
+ free(stack->msg);
+
fini_navigation_info(stack->nav_info);
free(stack->nav_info);
@@ -311,11 +393,49 @@ GtkStatusStack *gtk_status_stack_new(void)
* *
******************************************************************************/
-void gtk_status_stack_reset(GtkStatusStack *stack)
+void gtk_status_stack_reset_to_default(GtkStatusStack *stack)
{
- gtk_stack_set_visible_child_name(stack->main, "default");
+ /**
+ * Une amélioration possible serait de passer à g_idle_add_once(),
+ * et de s'affranchir des retours G_SOURCE_REMOVE systématiques,
+ * mais la fonction n'est disponible qu'à partir de la GLib 2.74.
+ */
- stack->def_source = NULL;
+ g_idle_add(stack->def_source, stack);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gardien des secrets impliqué. *
+* stack = barre de statut à actualiser. *
+* *
+* Description : Note le changement de verrouillage du stockage sécurisé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *storage, GtkStatusStack *stack)
+{
+ if (!g_secret_storage_has_key(stack->storage))
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), false);
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "nolock-symbolic");
+ }
+ else
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), true);
+
+ if (g_secret_storage_is_locked(stack->storage))
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "locked-symbolic");
+ else
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "unlocked-symbolic");
+
+ }
}
@@ -441,6 +561,148 @@ static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *stack)
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
+* *
+* Description : Met à jour une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(object);
+
+ switch (prop_id)
+ {
+ case PROP_SHOW_BOTTOM:
+ gtk_toggle_button_set_active(stack->bottom_toggler, g_value_get_boolean(value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(object);
+
+ switch (prop_id)
+ {
+ case PROP_SHOW_BOTTOM:
+ g_value_set_boolean(value, gtk_toggle_button_get_active(stack->bottom_toggler));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MISE EN AVANT DES MESSAGES SIMPLES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* msg = simple message à faire paraître. *
+* *
+* Description : Inscrit un message simple dans la barre de statut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_display_message(GtkStatusStack *stack, const char *msg)
+{
+ if (stack->msg != NULL)
+ free(stack->msg);
+
+ if (msg != NULL)
+ stack->msg = strdup(msg);
+ else
+ stack->msg = NULL;
+
+ gtk_status_stack_show_simple_message(stack);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = pile de statuts à manipuler. *
+* *
+* Description : S'assure de l'affichage à jour de la partie "default". *
+* *
+* Retour : G_SOURCE_REMOVE pour une exécution unique. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_status_stack_show_simple_message(gpointer data)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(data);
+
+ stack->def_source = gtk_status_stack_show_simple_message;
+
+ gtk_label_set_text(stack->def_label, stack->msg != NULL ? stack->msg : "");
+
+ gtk_stack_set_visible_child_name(stack->main, "default");
+
+ return G_SOURCE_REMOVE;
+
+}
+
+
+
/* ---------------------------------------------------------------------------------- */
/* STATUT DES INFORMATIONS DE DESASSEMBLAGE */
/* ---------------------------------------------------------------------------------- */
@@ -572,7 +834,7 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrang
/******************************************************************************
* *
-* Paramètres : stack = pile de statuts à manipuler. *
+* Paramètres : data = pile de statuts à manipuler. *
* *
* Description : S'assure de l'affichage à jour de la partie "navigation". *
* *
@@ -582,14 +844,15 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrang
* *
******************************************************************************/
-static gboolean gtk_status_stack_show_current_location(GtkStatusStack *stack)
+static gboolean gtk_status_stack_show_current_location(gpointer data)
{
+ GtkStatusStack *stack; /* Version spécialisée */
navigation_info_t *info; /* Informations à constituer */
char raw_pos[6 + VMPA_MAX_LEN + 1]; /* Formatage final en direct */
- stack->def_source = (GSourceFunc)gtk_status_stack_show_current_location;
+ stack = GTK_STATUS_STACK(data);
- gtk_stack_set_visible_child_name(stack->main, "navigation");
+ stack->def_source = gtk_status_stack_show_current_location;
info = stack->nav_info;
@@ -613,6 +876,10 @@ static gboolean gtk_status_stack_show_current_location(GtkStatusStack *stack)
gtk_label_set_text(stack->nav_details, info->details != NULL ? info->details : "");
+ /* Conclusion */
+
+ gtk_stack_set_visible_child_name(stack->main, "navigation");
+
return G_SOURCE_REMOVE;
}
@@ -813,7 +1080,7 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
g_mutex_unlock(&info->access);
@@ -880,7 +1147,7 @@ void gtk_status_stack_update_activity_message(GtkStatusStack *stack, activity_id
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
}
@@ -937,7 +1204,7 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
}
@@ -989,7 +1256,7 @@ void gtk_status_stack_extend_activity_max(GtkStatusStack *stack, activity_id_t i
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
}
@@ -1055,10 +1322,10 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
if (info->count == 0)
{
info->tag = 0;
- g_idle_add(stack->def_source, stack);
+ gtk_status_stack_reset_to_default(stack);
}
else if (is_last)
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
exit:
@@ -1069,7 +1336,7 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
/******************************************************************************
* *
-* Paramètres : stack = pile de statuts à manipuler. *
+* Paramètres : data = pile de statuts à manipuler. *
* *
* Description : S'assure de l'affichage à jour de la partie "activité". *
* *
@@ -1079,11 +1346,14 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
* *
******************************************************************************/
-static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack)
+static gboolean gtk_status_stack_show_current_activity(gpointer data)
{
+ GtkStatusStack *stack; /* Version spécialisée */
activity_info_t *info; /* Informations à consulter */
activity_status_t *last; /* Dernier statut à traiter */
+ stack = GTK_STATUS_STACK(data);
+
info = stack->activity_info;
g_mutex_lock(&info->access);
@@ -1092,14 +1362,14 @@ static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack)
{
if (info->count > 0)
{
- gtk_stack_set_visible_child_name(stack->main, "activity");
-
last = &info->statuses[info->count - 1];
gtk_label_set_text(stack->activity_message, last->message);
gtk_progress_bar_set_fraction(stack->activity_progress, (last->current * 1.0) / last->max);
+ gtk_stack_set_visible_child_name(stack->main, "activity");
+
}
info->tag = 0;
diff --git a/src/gtkext/statusstack.h b/src/gtkext/statusstack.h
index 66ad6db..96d008c 100644
--- a/src/gtkext/statusstack.h
+++ b/src/gtkext/statusstack.h
@@ -45,7 +45,15 @@ DECLARE_GTYPE(GtkStatusStack, gtk_status_stack, GTK, STATUS_STACK);
GtkStatusStack *gtk_status_stack_new(void);
/* Réinitialise la barre de statut à son stade par défaut. */
-void gtk_status_stack_reset(GtkStatusStack *);
+void gtk_status_stack_reset_to_default(GtkStatusStack *);
+
+
+
+/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */
+
+
+/* Inscrit un message simple dans la barre de statut. */
+void gtk_status_stack_display_message(GtkStatusStack *, const char *);
diff --git a/src/gtkext/statusstack.ui b/src/gtkext/statusstack.ui
index 422f95d..0b7cd6d 100644
--- a/src/gtkext/statusstack.ui
+++ b/src/gtkext/statusstack.ui
@@ -1,6 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkStatusStack" parent="GtkBox">
+ <!--property name="show-bottom" bind-source="bottom_toggler" bind-property="active" bind-flags="bidirectional|sync-create"/-->
+
<child>
<object class="GtkStack" id="main">
<property name="margin-start">8</property>
@@ -9,16 +12,19 @@
<!-- Vide par défaut -->
<child>
- <object class="GtkStackPage" id="stack">
+ <object class="GtkStackPage">
<property name="name">default</property>
<property name="child">
- <object class="GtkLabel">
+ <object class="GtkLabel" id="def_label">
<property name="hexpand">true</property>
<property name="halign">fill</property>
- <property name="valign">center</property>
+ <property name="valign">baseline</property>
<property name="xalign">0</property>
<property name="label"></property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</object>
</property>
@@ -148,6 +154,20 @@
</child>
<child>
+ <object class="GtkToggleButton" id="lock_update">
+ <property name="sensitive">false</property>
+ <property name="has-frame">false</property>
+ <property name="icon-name">nolock-symbolic</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator">
+ <property name="orientation">vertical</property>
+ </object>
+ </child>
+
+ <child>
<object class="GtkImage">
<property name="margin-start">8</property>
<property name="icon-name">pan-down-symbolic</property>
@@ -185,7 +205,8 @@
<child>
<object class="GtkToggleButton" id="bottom_toggler">
<property name="has-frame">false</property>
- <property name="icon-name">panel-bottom-symbolic</property>
+ <property name="icon-name">dock-station-bottom-symbolic</property>
+ <property name="action-name">win.toggle-bottom</property>
</object>
</child>
diff --git a/src/gtkext/tweak-int.h b/src/gtkext/tweak-int.h
new file mode 100644
index 0000000..0d2c213
--- /dev/null
+++ b/src/gtkext/tweak-int.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak-int.h - définitions internes pour une section d'éléments à paramétrer
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GTKEXT_TWEAK_INT_H
+#define _GTKEXT_TWEAK_INT_H
+
+
+#include "tweak.h"
+
+
+
+/* Section de paramétrage pour liste d'éléments à configurer (instance) */
+struct _GtkTweakSection
+{
+ GtkListBoxRow parent; /* A laisser en premier */
+
+ GtkImage *icon; /* Eventuelle image */
+ GtkLabel *label; /* Etiquette associée */
+ GtkWidget *next; /* Eventuelle progression */
+
+ char *category; /* Groupe de rassemblement */
+
+ union
+ {
+ GType panel; /* Accès à la page de config. */
+ char *sub; /* Sous-ensemble à presenter */
+ };
+ bool has_sub_section; /* Choix du champ valide */
+
+};
+
+/* Section de paramétrage pour liste d'éléments à configurer (classe) */
+struct _GtkTweakSectionClass
+{
+ GtkListBoxRowClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une nouvelle section de configuration. */
+bool gtk_tweak_section_create(GtkTweakSection *, const tweak_info_t *);
+
+
+
+#endif /* _GTKEXT_TWEAK_INT_H */
diff --git a/src/gtkext/tweak.c b/src/gtkext/tweak.c
new file mode 100644
index 0000000..b03cf17
--- /dev/null
+++ b/src/gtkext/tweak.c
@@ -0,0 +1,319 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak.c - section d'éléments à paramétrer
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "tweak.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "helpers.h"
+#include "tweak-int.h"
+
+
+
+/* Initialise la classe des sections d'éléments paramétrables. */
+static void gtk_tweak_section_class_init(GtkTweakSectionClass *);
+
+/* Initialise une instance de section d'éléments paramétrables. */
+static void gtk_tweak_section_init(GtkTweakSection *);
+
+/* Supprime toutes les références externes. */
+static void gtk_tweak_section_dispose(GtkTweakSection *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_tweak_section_finalize(GtkTweakSection *);
+
+
+
+/* Détermine le type du composant d'affichage générique. */
+G_DEFINE_TYPE(GtkTweakSection, gtk_tweak_section, GTK_TYPE_LIST_BOX_ROW);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Initialise la classe des sections d'éléments paramétrables. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_class_init(GtkTweakSectionClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tweak_section_dispose;
+ object->finalize = (GObjectFinalizeFunc)gtk_tweak_section_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/tweak.ui");
+
+ gtk_widget_class_bind_template_child(widget, GtkTweakSection, icon);
+ gtk_widget_class_bind_template_child(widget, GtkTweakSection, label);
+ gtk_widget_class_bind_template_child(widget, GtkTweakSection, next);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = composant GTK à initialiser. *
+* *
+* Description : Initialise une instance de section d'éléments paramétrables. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_init(GtkTweakSection *section)
+{
+ gtk_widget_init_template(GTK_WIDGET(section));
+
+ section->category = NULL;
+
+ section->sub = NULL;
+ section->has_sub_section = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_dispose(GtkTweakSection *section)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(section), GTK_TYPE_TWEAK_SECTION);
+
+ G_OBJECT_CLASS(gtk_tweak_section_parent_class)->dispose(G_OBJECT(section));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_finalize(GtkTweakSection *section)
+{
+ if (section->category != NULL)
+ free(section->category);
+
+ if (section->has_sub_section && section->sub != NULL)
+ free(section->sub);
+
+ G_OBJECT_CLASS(gtk_tweak_section_parent_class)->finalize(G_OBJECT(section));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations associées à la section. *
+* *
+* Description : Crée une nouvelle section de configuration. *
+* *
+* Retour : Composant GTK mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkTweakSection *gtk_tweak_section_new(const tweak_info_t *info)
+{
+ GtkTweakSection *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_TWEAK_SECTION, NULL);
+
+ if (!gtk_tweak_section_create(result, info))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à initialiser pleinement. *
+* info = informations associées à la section. *
+* *
+* Description : Met en place une nouvelle section de configuration. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_tweak_section_create(GtkTweakSection *section, const tweak_info_t *info)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ gtk_image_set_from_icon_name(section->icon, info->image);
+ gtk_label_set_label(section->label, info->label);
+
+ gtk_widget_set_visible(section->next, info->has_sub_section);
+
+ section->category = strdup(info->category);
+
+ if (info->has_sub_section)
+ {
+ section->sub = strdup(info->sub);
+ section->has_sub_section = true;
+ }
+ else
+ {
+ section->panel = info->panel;
+ section->has_sub_section = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Fournit l'étiquette associée à une section de configuration. *
+* *
+* Retour : Désignation humaine de la section. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *gtk_tweak_section_get_label(const GtkTweakSection *section)
+{
+ const char *result; /* Texte à retourner */
+
+ result = gtk_label_get_text(section->label);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Indique si la section renvoie vers une sous-section. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_tweak_section_has_sub_section(const GtkTweakSection *section)
+{
+ bool result; /* Statut à retourner */
+
+ result = section->has_sub_section;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Fournit le type d'un éventuel panneau de configuration lié. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GType gtk_tweak_section_get_panel(const GtkTweakSection *section)
+{
+ GType result; /* Type d'objet à retourner */
+
+ assert(!section->has_sub_section);
+
+ result = section->panel;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Fournit la désignation d'une éventuelle sous-section liée. *
+* *
+* Retour : Désignation associée à la sous-section. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *gtk_tweak_section_get_sub_section(const GtkTweakSection *section)
+{
+ const char *result; /* Désignation à renvoyer */
+
+ assert(section->has_sub_section);
+
+ result = section->sub;
+
+ return result;
+
+}
diff --git a/src/gtkext/tweak.h b/src/gtkext/tweak.h
new file mode 100644
index 0000000..8c44844
--- /dev/null
+++ b/src/gtkext/tweak.h
@@ -0,0 +1,90 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak.h - prototypes pour pour une section d'éléments à paramétrer
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GTKEXT_TWEAK_H
+#define _GTKEXT_TWEAK_H
+
+
+#include <stdbool.h>
+#include <gtk/gtk.h>
+
+
+#include "../glibext/helpers.h"
+
+
+
+/* Définition d'une section de configuration */
+typedef struct _tweak_info_t
+{
+ const char *parent; /* Ensemble d'appartenance */
+
+ const char *category; /* Groupe de rassemblement */
+
+ const char *image; /* Eventuelle image associée */
+ const char *key; /* Désignation de la section */
+ const char *label; /* Désignation humaine */
+
+ union
+ {
+ GType panel; /* Accès à la page de config. */
+ const char *sub; /* Sous-ensemble à presenter */
+ };
+ bool has_sub_section; /* Choix du champ valide */
+
+} tweak_info_t;
+
+
+#define TWEAK_SIMPLE_DEF(p, c, i, k, l, t) \
+ { \
+ .parent = p, \
+ .category = c, \
+ .image = i, \
+ .key = k, \
+ .label = l, \
+ .panel = t, \
+ .has_sub_section = false, \
+ }
+
+#define GTK_TYPE_TWEAK_SECTION (gtk_tweak_section_get_type())
+
+DECLARE_GTYPE(GtkTweakSection, gtk_tweak_section, GTK, TWEAK_SECTION);
+
+
+/* Crée une nouvelle section de configuration. */
+GtkTweakSection *gtk_tweak_section_new(const tweak_info_t *);
+
+/* Fournit l'étiquette associée à une section de configuration. */
+const char *gtk_tweak_section_get_label(const GtkTweakSection *);
+
+/* Indique si la section renvoie vers une sous-section. */
+bool gtk_tweak_section_has_sub_section(const GtkTweakSection *);
+
+/* Fournit le type d'un éventuel panneau de configuration lié. */
+GType gtk_tweak_section_get_panel(const GtkTweakSection *);
+
+/* Fournit la désignation d'une éventuelle sous-section liée. */
+const char *gtk_tweak_section_get_sub_section(const GtkTweakSection *);
+
+
+
+#endif /* _GTKEXT_TWEAK_H */
diff --git a/src/gtkext/tweak.ui b/src/gtkext/tweak.ui
new file mode 100644
index 0000000..576e25e
--- /dev/null
+++ b/src/gtkext/tweak.ui
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkTweakSection" parent="GtkListBoxRow">
+
+ <property name="child">
+
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="margin-top">14</property>
+ <property name="margin-bottom">14</property>
+
+ <child>
+ <object class="GtkImage" id="icon">
+ <property name="icon-name">security-high-symbolic</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Security</property>
+ <property name="hexpand">true</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkImage" id="next">
+ <property name="icon-name">go-next-symbolic</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+ </property>
+
+ </template>
+</interface>
diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am
index 42761c4..be70445 100644
--- a/src/gui/Makefile.am
+++ b/src/gui/Makefile.am
@@ -26,8 +26,6 @@ libgui_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
libgui4_la_SOURCES = \
- panel-int.h \
- panel.h panel.c \
resources.h resources.c \
window-int.h \
window.h window.c
diff --git a/src/gui/core/core.c b/src/gui/core/core.c
index 4a6809c..57a398a 100644
--- a/src/gui/core/core.c
+++ b/src/gui/core/core.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* core.c - chargement et le déchargement du tronc commun pour l'éditeur graphique
*
- * Copyright (C) 2016-2019 Cyrille Bagard
+ * Copyright (C) 2016-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -63,7 +63,7 @@ bool load_gui_components(AvailableGuiComponent flags)
if ((flags & AGC_PANELS) != 0 && (__loaded & AGC_PANELS) == 0)
{
- result = load_main_panels();
+ result = load_main_framework_panel_definitions();
if (!result) goto done;
__loaded |= AGC_PANELS;
@@ -93,7 +93,7 @@ void unload_gui_components(AvailableGuiComponent flags)
{
if ((flags & AGC_PANELS) != 0 && (__loaded & AGC_PANELS) == 0)
{
- unload_all_panels();
+ unload_all_framework_panel_definitions();
__loaded &= ~AGC_PANELS;
diff --git a/src/gui/core/logs.c b/src/gui/core/logs.c
index 59910f1..cdb2a0d 100644
--- a/src/gui/core/logs.c
+++ b/src/gui/core/logs.c
@@ -24,6 +24,14 @@
#include "logs.h"
+#include <assert.h>
+
+
+#include "panels.h"
+#include "../panels/logs.h"
+#include "../../glibext/log.h"
+
+
/******************************************************************************
* *
@@ -38,26 +46,20 @@
* *
******************************************************************************/
-void do_log_message_alt2(LogMessageType type, const char *msg)
+void do_log_message_alt(LogMessageType type, const char *msg)
{
-#if 0
-
-#ifdef INCLUDE_GTK_SUPPORT
-
- GEditorItem *item; /* Eventuel affichage présent */
+ GLogEntry *entry; /* Nouvel élément de journal */
+ GtkTiledPanel *panel; /* Panneau de journalisation */
- item = find_editor_item_by_type(G_TYPE_LOG_PANEL);
+ entry = g_log_entry_new(type, msg);
- if (item != NULL)
- {
- g_log_panel_add_message(G_LOG_PANEL(item), type, msg);
- g_object_unref(G_OBJECT(item));
- }
+ panel = get_framework_panel_singleton(GTK_TYPE_LOGS_PANEL);
+ assert(panel != NULL);
-#endif
+ g_log_panel_add_message(GTK_LOGS_PANEL(panel), entry);
-#endif
+ unref_object(panel);
- printf("[log GUI] [%u] %s\n", type, msg);
+ unref_object(entry);
}
diff --git a/src/gui/core/panels.c b/src/gui/core/panels.c
index 69ab2aa..9fca411 100644
--- a/src/gui/core/panels.c
+++ b/src/gui/core/panels.c
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* panels.c - gestion d'ensemble de tous les panneaux graphiques du framework
*
- * Copyright (C) 2016-2024 Cyrille Bagard
+ * Copyright (C) 2016-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -25,25 +25,138 @@
#include "panels.h"
+#include <assert.h>
#include <malloc.h>
+#include <string.h>
+
+
+#include <i18n.h>
#include "../panels/binary.h"
+#include "../panels/binary-params.h"
+#include "../panels/logs.h"
#include "../panels/welcome.h"
+#include "../../gtkext/launcher.h"
+
+
+
+/* Définition générique complète d'un panneau */
+typedef struct _ext_panel_info_t
+{
+ /* Début des champs copiés de panel_info_t */
+
+ char *category; /* Groupe de rassemblement */
+
+ char *image; /* Eventuelle image associée */
+ char *title; /* Désignation humaine */
+ char *desc; /* Description humaine */
+
+ FrameworkPanelPersonality personality; /* Comportement attendu */
+
+ GType panel_type; /* Type du panneau représenté */
+ GType params_type; /* Composant de paramètre */
+ /* Fin des champs copiés de panel_info_t */
+
+ GtkTiledPanel *singleton; /* Conservation des allocations*/
+
+} ext_panel_info_t;
/* Liste des panneaux disponibles */
-static GPanelItem **_panels_list = NULL;
+static ext_panel_info_t **_panels_list = NULL;
static size_t _panels_count = 0;
+/* Copie une définition basique de panneau graphqiue. */
+static ext_panel_info_t *copy_panel_info(const panel_info_t *);
+
+/* Efface une définition étendue de panneau graphique. */
+static void delete_panel_info(ext_panel_info_t *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : info = information de base à copier. *
+* *
+* Description : Copie une définition basique de panneau graphqiue. *
+* *
+* Retour : Structure mémorisant l'ensemble des informations. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static ext_panel_info_t *copy_panel_info(const panel_info_t *info)
+{
+ ext_panel_info_t *result; /* Structure à retourner */
+
+ result = calloc(1, sizeof(ext_panel_info_t));
+
+ if (info->category != NULL)
+ result->category = strdup(info->category);
+
+ if (info->image != NULL)
+ result->image = strdup(info->image);
+
+ result->title = strdup(info->title);
+
+ if (info->desc != NULL)
+ result->desc = strdup(info->desc);
+
+ result->personality = info->personality;
+
+ result->panel_type = info->panel_type;
+ result->params_type = info->params_type;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations à supprimer de la mémoire. *
+* *
+* Description : Efface une définition étendue de panneau graphique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void delete_panel_info(ext_panel_info_t *info)
+{
+ if (info->category != NULL)
+ free(info->category);
+
+ if (info->image != NULL)
+ free(info->image);
+
+ free(info->title);
+
+ if (info->desc != NULL)
+ free(info->desc);
+
+ if (info->singleton != NULL)
+ {
+ assert(info->personality & FPP_SINGLETON);
+ unref_object(info->singleton);
+ }
+
+ free(info);
+
+}
+
/******************************************************************************
* *
* Paramètres : - *
* *
-* Description : Charge les principaux panneaux graphiques du framework. *
+* Description : Charge les définitions des principaux panneaux du framework. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -51,19 +164,60 @@ static size_t _panels_count = 0;
* *
******************************************************************************/
-bool load_main_panels(void)
+bool load_main_framework_panel_definitions(void)
{
bool result; /* Bilan à retourner */
+ panel_info_t info; /* Infos d'enregistrement */
- result = true;
+ /* Chargement du panneau de rapport au plus tôt */
- // TODO register_panel_item(G_TYPE_LOG_PANEL, config);
+ info.category = NULL;
- /* Chargement du panneau de rapport au plus tôt */
- // TODO panel = g_panel_item_new(G_TYPE_LOG_PANEL, NULL);
+ info.image = NULL;
+ info.title = _("Logs");
+ info.desc = NULL;
+
+ info.personality = FPP_SINGLETON;
+
+ info.panel_type = GTK_TYPE_LOGS_PANEL;
+ info.params_type = G_TYPE_INVALID;
+
+ result = register_framework_panel_definition(&info);
+ if (!result) goto done;
+
+ /* Chargements des panneaux restants */
+
+ info.category = "Main";
+
+ info.image = "binfile-symbolic";
+ info.title = _("Binary analysis");
+ info.desc = _("Load a binary content and parse its format if recognized");
+
+ info.personality = FPP_MAIN_PANEL;
+
+ info.panel_type = GTK_TYPE_BINARY_PANEL;
+ info.params_type = GTK_TYPE_BINARY_PARAMETERS;
+
+ result = register_framework_panel_definition(&info);
+ if (!result) goto done;
+
+ /* --- */
+
+ info.category = NULL;
+
+ info.image = NULL;
+ info.title = _("Welcome");
+ info.desc = NULL;
+
+ info.personality = FPP_MAIN_PANEL | FPP_SINGLETON;
+
+ info.panel_type = GTK_TYPE_WELCOME_PANEL;
+ info.params_type = G_TYPE_INVALID;
- register_panel_item(g_binary_panel_new());
- register_panel_item(g_welcome_panel_new());
+ result = register_framework_panel_definition(&info);
+ if (!result) goto done;
+
+ done:
return result;
@@ -82,12 +236,12 @@ bool load_main_panels(void)
* *
******************************************************************************/
-void unload_all_panels(void)
+void unload_all_framework_panel_definitions(void)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < _panels_count; i++)
- unref_object(_panels_list[i]);
+ delete_panel_info(_panels_list[i]);
_panels_list = NULL;
_panels_count = 0;
@@ -97,10 +251,9 @@ void unload_all_panels(void)
/******************************************************************************
* *
-* Paramètres : type = type du composant à présenter à l'affichage. *
-* config = configuration à compléter. *
+* Paramètres : info = information de base à copier. *
* *
-* Description : Enregistre un panneau comme partie intégrante de l'éditeur. *
+* Description : Enregistre la définition d'un panneau graphique. *
* *
* Retour : - *
* *
@@ -108,11 +261,36 @@ void unload_all_panels(void)
* *
******************************************************************************/
-void register_panel_item(/* __steal */ GPanelItem *item)
+bool register_framework_panel_definition(const panel_info_t *info)
{
- _panels_list = realloc(_panels_list, ++_panels_count * sizeof(GPanelItem *));
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ ext_panel_info_t *ext_info; /* Informations conservées */
+
+ result = false;
+
+ /* Validation */
+
+ for (i = 0; i < _panels_count; i++)
+ if (_panels_list[i]->panel_type == info->panel_type)
+ break;
+
+ if (i < _panels_count)
+ goto done;
+
+ /* Enregistrement */
- _panels_list[_panels_count - 1] = item;
+ ext_info = copy_panel_info(info);
+
+ _panels_list = realloc(_panels_list, ++_panels_count * sizeof(ext_panel_info_t *));
+
+ _panels_list[_panels_count - 1] = ext_info;
+
+ result = true;
+
+ done:
+
+ return result;
}
@@ -121,7 +299,44 @@ void register_panel_item(/* __steal */ GPanelItem *item)
* *
* Paramètres : target = type de définition de panneau recherchée. *
* *
-* Description : Retrouve la définition d'un type de panneau. *
+* Description : Récupère les particularités d'un panneau graphique. *
+* *
+* Retour : Détails du comportement associé au panneau visé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+FrameworkPanelPersonality get_framework_panel_personality(GType target)
+{
+ FrameworkPanelPersonality result; /* Propriétées à retourner */
+ size_t i; /* Boucle de parcours */
+ ext_panel_info_t *info; /* Informations conservées */
+
+ result = FPP_NONE;
+
+ for (i = 0; i < _panels_count; i++)
+ {
+ info = _panels_list[i];
+
+ if (info->panel_type == target)
+ {
+ result = info->personality;
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : target = type de définition de panneau recherchée. *
+* *
+* Description : Met en place (au besoin) un panneau graphique unique. *
* *
* Retour : Instance de définition identifiée ou NULL en cas d'échec. *
* *
@@ -129,23 +344,27 @@ void register_panel_item(/* __steal */ GPanelItem *item)
* *
******************************************************************************/
-GPanelItem *find_item_panel_by_type(GType target)
+GtkTiledPanel *get_framework_panel_singleton(GType target)
{
- GPanelItem *result; /* Instance à renvoyer */
+ GtkTiledPanel *result; /* Instance à renvoyer */
size_t i; /* Boucle de parcours */
- GPanelItem *item; /* Définition de panneau */
+ ext_panel_info_t *info; /* Informations conservées */
result = NULL;
for (i = 0; i < _panels_count; i++)
{
- item = _panels_list[i];
+ info = _panels_list[i];
- if (G_OBJECT_TYPE(item) == target)
+ if (info->panel_type == target)
{
- result = item;
+ if (info->singleton == NULL)
+ info->singleton = g_object_new(target, NULL);
+
+ result = info->singleton;
ref_object(result);
break;
+
}
}
@@ -157,39 +376,84 @@ GPanelItem *find_item_panel_by_type(GType target)
/******************************************************************************
* *
-* Paramètres : skip = saute le panneau d'accueil lors du parcours ? *
-* handle = routine à appeler pour chaque panneau. *
-* data = données fournies pour accompagner cet appel. *
+* Paramètres : list = liste à compléter. *
* *
-* Description : Effectue le parcours de tous les panneaux chargés. *
+* Description : Intègre une définition de panneau enregistrée. *
* *
-* Retour : true si le parcours a été total, false sinon. *
+* Retour : true pour un parcours complet de la liste des définitions. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool browse_all_item_panels(bool skip, handle_panel_item_fc handle, void *data)
+void populate_framework_panel_launcher_list(GtkListBox *list)
{
- bool result; /* Résultat à renvoyer */
size_t i; /* Boucle de parcours */
- GPanelItem *item; /* Définition de panneau */
-
- result = true;
+ ext_panel_info_t *info; /* Informations conservées */
+ GtkPanelLauncher *launcher; /* Lanceur à intégrer */
for (i = 0; i < _panels_count; i++)
{
- item = _panels_list[i];
+ info = _panels_list[i];
- if (skip && G_OBJECT_TYPE(item) == G_TYPE_WELCOME_PANEL)
+ if (info->category == NULL)
continue;
- result = handle(item, data);
+ launcher = gtk_panel_launcher_new(info->image, info->title, info->desc);
+
+ g_object_set_data(G_OBJECT(launcher), "panel_type", GSIZE_TO_POINTER(info->panel_type));
+
+ gtk_list_box_append(list, GTK_WIDGET(launcher));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : row = lanceur sélectionné. *
+* *
+* Description : Fournit un composant d'édition de paramètres de panneau. *
+* *
+* Retour : Composant d'édition de paramètres ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkWidget *get_framework_panel_parameters(GtkListBoxRow *row)
+{
+ GtkWidget *result; /* Composant à retourner */
+ gpointer *data; /* Valeur incrustée */
+ GType target; /* Type de panneau recherché */
+ ext_panel_info_t *info; /* Informations conservées */
+ size_t i; /* Boucle de parcours */
- if (!result) break;
+ data = g_object_get_data(G_OBJECT(row), "panel_type");
+ assert(data != NULL);
+
+ target = GPOINTER_TO_SIZE(data);
+
+ info = NULL;
+
+ for (i = 0; i < _panels_count; i++)
+ {
+ info = _panels_list[i];
+
+ if (info->panel_type == target)
+ break;
}
+ assert(info != NULL);
+ assert(i < _panels_count);
+
+ if (info->params_type == G_TYPE_INVALID)
+ result = NULL;
+ else
+ result = g_object_new(info->params_type, NULL);
+
return result;
}
diff --git a/src/gui/core/panels.h b/src/gui/core/panels.h
index aaea9e6..e17ef8a 100644
--- a/src/gui/core/panels.h
+++ b/src/gui/core/panels.h
@@ -2,7 +2,7 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
* panels.h - prototypes pour la gestion d'ensemble de tous les panneaux graphiques du framework
*
- * Copyright (C) 2016-2024 Cyrille Bagard
+ * Copyright (C) 2016-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -26,30 +26,62 @@
#define _GUI_CORE_PANELS_H
+#include <glib-object.h>
#include <stdbool.h>
+#include <gtk/gtk.h>
-#include "../panel.h"
+#include "../../gtkext/panel.h"
-/* Charge les principaux panneaux graphiques du framework. */
-bool load_main_panels(void);
+/* Types de panneaux pour éditeur */
+typedef enum _FrameworkPanelPersonality
+{
+ FPP_NONE = (0 << 0), /* Pas de particularité */
+
+ FPP_MAIN_PANEL = (1 << 0), /* Panneau principal */
+ FPP_SINGLETON = (1 << 1), /* Instance unique */
+
+} FrameworkPanelPersonality;
+
+/* Définition générique d'un panneau */
+typedef struct _panel_info_t
+{
+ const char *category; /* Groupe de rassemblement */
+
+ const char *image; /* Eventuelle image associée */
+ const char *title; /* Désignation humaine */
+ const char *desc; /* Description humaine */
+
+ FrameworkPanelPersonality personality; /* Comportement attendu */
+
+ GType panel_type; /* Type du panneau représenté */
+ GType params_type; /* Composant de paramètre */
+
+} panel_info_t;
+
+
+/* Charge les définitions des principaux panneaux du framework. */
+bool load_main_framework_panel_definitions(void);
/* Décharge tous les panneaux graphiques du framework. */
-void unload_all_panels(void);
+void unload_all_framework_panel_definitions(void);
+
+/* Enregistre la définition d'un panneau graphique. */
+bool register_framework_panel_definition(const panel_info_t *);
-/* Enregistre un panneau comme partie intégrante de l'éditeur. */
-void register_panel_item(/* __steal */ GPanelItem *);
+/* Récupère les particularités d'un panneau graphique. */
+FrameworkPanelPersonality get_framework_panel_personality(GType);
-/* Retrouve la définition d'un type de panneau. */
-GPanelItem *find_item_panel_by_type(GType);
+/* Met en place (au besoin) un panneau graphique unique. */
+GtkTiledPanel *get_framework_panel_singleton(GType);
-/* Réalise un traitement sur un panneau de l'éditeur. */
-typedef bool (* handle_panel_item_fc) (GPanelItem *, void *);
+/* Intègre une définition de panneau enregistrée. */
+void populate_framework_panel_launcher_list(GtkListBox *);
-/* Effectue le parcours de tous les panneaux chargés. */
-bool browse_all_item_panels(bool, handle_panel_item_fc, void *);
+/* Fournit un composant d'édition de paramètres de panneau. */
+GtkWidget *get_framework_panel_parameters(GtkListBoxRow *);
diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am
index 5a77b99..3492f63 100644
--- a/src/gui/dialogs/Makefile.am
+++ b/src/gui/dialogs/Makefile.am
@@ -3,21 +3,25 @@ BUILT_SOURCES = resources.h resources.c
noinst_LTLIBRARIES = libguidialogs.la
-UI_FILES = \
- about.ui
+
+UI_FILES = \
+ about.css \
+ about.ui \
+ preferences.ui
# bookmark.ui \
# export_graph.ui \
# identity.ui \
# loading.ui \
-# preferences.ui \
# prefs_fgraph.ui \
# prefs_labels.ui \
# snapshots.ui \
# storage.ui
-libguidialogs_la_SOURCES = \
- about-int.h \
- about.h about.c \
+libguidialogs_la_SOURCES = \
+ about-int.h \
+ about.h about.c \
+ preferences-int.h \
+ preferences.h preferences.c \
resources.h resources.c
# bookmark.h bookmark.c \
# export_disass.h export_disass.c \
@@ -26,12 +30,15 @@ libguidialogs_la_SOURCES = \
# gotox.h gotox.c \
# identity.h identity.c \
# loading.h loading.c \
-# preferences.h preferences.c \
+# \
# prefs_fgraph.h prefs_fgraph.c \
# prefs_labels.h prefs_labels.c \
# snapshots.h snapshots.c \
# storage.h storage.c
+libguidialogs_la_LIBADD = \
+ prefs/libguidialogsprefs.la
+
libguidialogs_la_CFLAGS = $(LIBGTK4_CFLAGS)
@@ -40,6 +47,9 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libguidialogs_la_SOURCES:%c=)
+SUBDIRS = prefs
+
+
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/about-int.h b/src/gui/dialogs/about-int.h
index 382859b..96a470e 100644
--- a/src/gui/dialogs/about-int.h
+++ b/src/gui/dialogs/about-int.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * about.h - définitions internes pour la boîte de dialogue d'information sur le programme
+ * about-int.h - définitions internes pour la boîte de dialogue d'information sur le programme
*
* Copyright (C) 2024 Cyrille Bagard
*
@@ -28,7 +28,7 @@
#include <stdbool.h>
-#include "about-int.h"
+#include "about.h"
@@ -37,20 +37,6 @@ struct _GtkAppAboutDialog
{
GtkWindow parent; /* A laisser en premier */
- union
- {
- struct
- {
- GtkPicture *revision_0; /* Numéro #0 */
- GtkPicture *revision_1; /* Numéro #1 */
- GtkPicture *revision_2; /* Numéro #2 */
- GtkPicture *revision_3; /* Numéro #3 */
- GtkPicture *revision_4; /* Numéro #4 */
- GtkPicture *revision_5; /* Numéro #5 */
- };
- GtkPicture *revisions[6]; /* Tous les numéros d'un coup */
- };
-
};
/* Boîte "A propos de" dédiée à l'application (classe) */
diff --git a/src/gui/dialogs/about.c b/src/gui/dialogs/about.c
index 5c938ad..1dca752 100644
--- a/src/gui/dialogs/about.c
+++ b/src/gui/dialogs/about.c
@@ -44,10 +44,10 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *);
static void gtk_app_about_dialog_init(GtkAppAboutDialog *);
/* Supprime toutes les références externes. */
-static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *);
+static void gtk_app_about_dialog_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_app_about_dialog_finalize(GtkAppAboutDialog *);
+static void gtk_app_about_dialog_finalize(GObject *);
@@ -74,22 +74,17 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *class)
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_app_about_dialog_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_app_about_dialog_finalize;
+ object->dispose = gtk_app_about_dialog_dispose;
+ object->finalize = gtk_app_about_dialog_finalize;
widget = GTK_WIDGET_CLASS(class);
+ gtk_widget_class_set_css_name(widget, "aboutdialog");
+
gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0, "window.close", NULL);
gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/about.ui");
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_0);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_1);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_2);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_3);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_4);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_5);
-
}
@@ -107,40 +102,14 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *class)
static void gtk_app_about_dialog_init(GtkAppAboutDialog *dialog)
{
- unsigned int revision; /* Numéro de révision */
- unsigned int max; /* Nbre. de boucles à effectuer*/
- unsigned int i; /* Boucle de parcours */
- unsigned int level; /* Unité la plus importante */
- char buffer[64]; /* Nom d'image à forger */
-
gtk_widget_init_template(GTK_WIDGET(dialog));
- revision = REVISION;
- max = log(revision) / log(10);
-
- assert(max <= 6);
-
- for (i = 0; i <= max; i++)
- {
- level = pow(10, max - i);
-
- snprintf(buffer, 64, "/org/chrysalide/gui/dialogs/about/revision_%u.png", revision / level);
-
- gtk_picture_set_resource(dialog->revisions[i], buffer);
-
- revision %= level;
-
- }
-
- for (; i < 6; i++)
- gtk_widget_set_visible(GTK_WIDGET(dialog->revisions[i]), FALSE);
-
}
/******************************************************************************
* *
-* Paramètres : dialog = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -150,18 +119,18 @@ static void gtk_app_about_dialog_init(GtkAppAboutDialog *dialog)
* *
******************************************************************************/
-static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *dialog)
+static void gtk_app_about_dialog_dispose(GObject *object)
{
- gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_APP_ABOUT_DIALOG);
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_APP_ABOUT_DIALOG);
- G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->dispose(G_OBJECT(dialog));
+ G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : dialog = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -171,9 +140,9 @@ static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *dialog)
* *
******************************************************************************/
-static void gtk_app_about_dialog_finalize(GtkAppAboutDialog *dialog)
+static void gtk_app_about_dialog_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->finalize(G_OBJECT(dialog));
+ G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->finalize(object);
}
@@ -207,8 +176,8 @@ GtkWindow *gtk_app_about_dialog_new(GtkWindow *parent)
/******************************************************************************
* *
-* Paramètres : dialog = boîte de dialogue à initialiser pleinement. *
-* content = contenu binaire à exposer de façon brute. *
+* Paramètres : dialog = boîte de dialogue à initialiser pleinement. *
+* parent = fenêtre parente à surpasser. *
* *
* Description : Met en place la fenêtre d'informations sur le logiciel. *
* *
diff --git a/src/gui/dialogs/about.css b/src/gui/dialogs/about.css
new file mode 100644
index 0000000..af3fa97
--- /dev/null
+++ b/src/gui/dialogs/about.css
@@ -0,0 +1,9 @@
+
+aboutdialog > box {
+
+ background-color: black;
+
+ background-image: url('resource:///re/chrysalide/framework/gui/dialogs/about/bg.png');
+ background-repeat: no-repeat;
+
+}
diff --git a/src/gui/dialogs/about.ui b/src/gui/dialogs/about.ui
index 892b468..7b519d2 100644
--- a/src/gui/dialogs/about.ui
+++ b/src/gui/dialogs/about.ui
@@ -8,93 +8,15 @@
<property name="modal">true</property>
<property name="resizable">false</property>
- <style>
- <class name="black-bg"/>
- </style>
-
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
- <child>
- <object class="GtkPicture" id="logo">
- <property name="margin-top">10</property>
- <property name="file">resource://org/chrysalide/gui/dialogs/about/chrysalide-full.png</property>
- </object>
- </child>
-
- <!--
- Etage intermédiaire pour ne pas que l'image se voie allouer la largeur entière
- de la fenêtre. Sinon des marges sont placées autour du rendu lors que l'image
- n'est pas étendue pour couvrir cette largeur entière.
- -->
- <child>
- <object class="GtkBox">
- <property name="orientation">horizontal</property>
- <property name="halign">center</property>
- <property name="margin-top">14</property>
- <child>
- <object class="GtkPicture" id="text">
- <property name="width-request">253</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/chrysalide_text.png</property>
- </object>
- </child>
- </object>
- </child>
-
- <child>
- <object class="GtkBox">
- <property name="orientation">horizontal</property>
- <property name="margin-start">149</property>
- <child>
- <object class="GtkPicture" id="revision">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_0">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_1">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_2">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_3">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_4">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_5">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- </object>
- </child>
<child>
<object class="GtkLabel">
- <property name="margin-top">22</property>
+ <property name="margin-top">368</property>
<property name="margin-bottom">10</property>
- <property name="label" translatable="yes">&lt;span fgcolor='white'&gt;Copyright (C) 2008-2024 Cyrille Bagard&lt;/span&gt;</property>
+ <property name="label" translatable="yes">&lt;span fgcolor='white'&gt;Copyright (C) 2008-2025 Cyrille Bagard&lt;/span&gt;</property>
<property name="use-markup">True</property>
</object>
</child>
diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml
index b9bc7e2..966d9c8 100644
--- a/src/gui/dialogs/gresource.xml
+++ b/src/gui/dialogs/gresource.xml
@@ -1,30 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/re/chrysalide/framework/gui/dialogs">
+ <file compressed="true">about.css</file>
<file compressed="true">about.ui</file>
- <file compressed="true">bookmark.ui</file>
- <file compressed="true">export_graph.ui</file>
- <file compressed="true">identity.ui</file>
- <file compressed="true">loading.ui</file>
<file compressed="true">preferences.ui</file>
- <file compressed="true">prefs_fgraph.ui</file>
- <file compressed="true">prefs_labels.ui</file>
- <file compressed="true">snapshots.ui</file>
- <file compressed="true">storage.ui</file>
- </gresource>
- <gresource prefix="/org/chrysalide/gui/dialogs/about">
- <file compressed="true" alias="chrysalide-full.png">../../../pixmaps/chrysalide-full.png</file>
- <file compressed="true" alias="chrysalide_text.png">../../../pixmaps/chrysalide_text.png</file>
- <file compressed="true" alias="revision.png">../../../pixmaps/revision.png</file>
- <file compressed="true" alias="revision_0.png">../../../pixmaps/revision_0.png</file>
- <file compressed="true" alias="revision_1.png">../../../pixmaps/revision_1.png</file>
- <file compressed="true" alias="revision_2.png">../../../pixmaps/revision_2.png</file>
- <file compressed="true" alias="revision_3.png">../../../pixmaps/revision_3.png</file>
- <file compressed="true" alias="revision_4.png">../../../pixmaps/revision_4.png</file>
- <file compressed="true" alias="revision_5.png">../../../pixmaps/revision_5.png</file>
- <file compressed="true" alias="revision_6.png">../../../pixmaps/revision_6.png</file>
- <file compressed="true" alias="revision_7.png">../../../pixmaps/revision_7.png</file>
- <file compressed="true" alias="revision_8.png">../../../pixmaps/revision_8.png</file>
- <file compressed="true" alias="revision_9.png">../../../pixmaps/revision_9.png</file>
</gresource>
</gresources>
diff --git a/src/gui/dialogs/preferences-int.h b/src/gui/dialogs/preferences-int.h
new file mode 100644
index 0000000..806f5f6
--- /dev/null
+++ b/src/gui/dialogs/preferences-int.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * preferences-int.h - définitions internes pour la boîte de dialogue d'édition des préférences de l'utilisateur
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_DIALOGS_PREFERENCES_INT_H
+#define _GUI_DIALOGS_PREFERENCES_INT_H
+
+
+#include <stdbool.h>
+
+
+#include "preferences.h"
+
+
+
+/* Fenêtre d'édition générale de la configuration (instance) */
+struct _GtkPreferencesDialog
+{
+ GtkWindow parent; /* A laisser en premier */
+
+ GtkLabel *side_title; /* Titre principal */
+ GtkScrolledWindow *side_content; /* Liste des sections */
+ GtkLabel *main_title; /* Titre de section */
+ GtkScrolledWindow *main_content; /* Page de configuration */
+
+ GHashTable *navigations; /* Liste de sections en place */
+
+};
+
+/* Fenêtre d'édition générale de la configuration (classe) */
+struct _GtkPreferencesDialogClass
+{
+ GtkWindowClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place la boîte de dialogue pour les préférences. */
+bool gtk_preferences_dialog_create(GtkPreferencesDialog *, GtkWindow *);
+
+
+
+#endif /* _GUI_DIALOGS_PREFERENCES_INT_H */
diff --git a/src/gui/dialogs/preferences.c b/src/gui/dialogs/preferences.c
index 4a3fb7c..0369241 100644
--- a/src/gui/dialogs/preferences.c
+++ b/src/gui/dialogs/preferences.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * preferences.c - (re)définition de l'identité de l'utilisateur
+ * preferences.c - boîte de dialogue d'édition des préférences de l'utilisateur
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -24,129 +24,105 @@
#include "preferences.h"
-#include <i18n.h>
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <gdk/gdkkeysyms.h>
-#include "prefs_fgraph.h"
-#include "prefs_labels.h"
-#include "../../core/params.h"
-#include "../../gtkext/easygtk.h"
+#include <config.h>
+#include "preferences-int.h"
+#include "prefs/appearance.h"
+#include "prefs/security.h"
+#include "../../common/cpp.h"
+#include "../../gtkext/tweak.h"
+#include "../../plugins/pglist.h"
+#include "../../plugins/tweakable.h"
-/* Constructeur de panneau de paramétrage */
-typedef GtkWidget * (* prefs_panel_creation_cb) (GtkBuilder **);
-/* Chargement de la configuration */
-typedef void (* prefs_config_update_cb) (GtkBuilder *, GGenConfig *);
-/* Description d'un noeud de préférences */
-typedef struct _pref_node_desc_t
-{
- prefs_panel_creation_cb create; /* Procédure de création */
- prefs_config_update_cb load; /* Procédure de chargement */
- prefs_config_update_cb store; /* Procédure d'enregistrement */
-
- const char *name; /* Désignation interne */
- const char *title; /* Désignation humaine */
-
- GtkBuilder *builder; /* Constructeur GTK */
- GtkWidget *panel; /* Panneau GTK */
-
- struct _pref_node_desc_t *children; /* Sous-arborescence */
-
-} pref_node_desc_t;
-
-
-#define PREF_NODE_NULL_ENTRY { .title = NULL }
+/* --------------------------- BASES DE BOITE DE DIALOGUE --------------------------- */
-/* Liste des paramétrages à afficher */
-static pref_node_desc_t _prefs_nodes[] = {
+/* Procède à l'initialisation de la fenêtre des paramètres. */
+static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *);
- {
- .create = NULL,
-
- .title = "Analysis",
+/* Procède à l'initialisation de la fenêtre des paramètres. */
+static void gtk_preferences_dialog_init(GtkPreferencesDialog *);
- .children = (pref_node_desc_t []){
+/* Supprime toutes les références externes. */
+static void gtk_preferences_dialog_dispose(GObject *);
- {
- .create = create_labels_preferences,
- .load = load_labels_configuration,
- .store = store_labels_configuration,
+/* Procède à la libération totale de la mémoire. */
+static void gtk_preferences_dialog_finalize(GObject *);
- .name = "labels",
- .title = "Colored labels",
+/* Fournit la liste de section désignée par un nom. */
+static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *, const char *, bool);
- },
+/* Réagit à un changement de sélection dans les sections. */
+static void gtk_preferences_dialog_on_row_selected(GtkListBox *, GtkListBoxRow *, GtkPreferencesDialog *);
- PREF_NODE_NULL_ENTRY
- }
- },
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
- {
- .create = NULL,
- .title = "Editor",
- .children = (pref_node_desc_t []){
- {
- .create = create_fgraph_preferences,
- .load = load_fgraph_configuration,
- .store = store_fgraph_configuration,
- .name = "fgraph",
- .title = "Function graph",
+/* ---------------------------------------------------------------------------------- */
+/* BASES DE BOITE DE DIALOGUE */
+/* ---------------------------------------------------------------------------------- */
- },
-
- PREF_NODE_NULL_ENTRY
-
- }
- },
+/* Détermine le type du composant d'affichage générique. */
+G_DEFINE_TYPE(GtkPreferencesDialog, gtk_preferences_dialog, GTK_TYPE_WINDOW);
- PREF_NODE_NULL_ENTRY
-
-};
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de la fenêtre des paramètres. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
-/* Eléments de la liste de sections */
-typedef enum _PrefListItem
+static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *class)
{
- PLI_TITLE, /* Etiquette de la section */
- PLI_PANEL, /* Panneau graphique associé */
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
-} PrefListItem;
+ object = G_OBJECT_CLASS(class);
+ object->dispose = gtk_preferences_dialog_dispose;
+ object->finalize = gtk_preferences_dialog_finalize;
-/* Ajoute un panneau de paramétrage à la boîte de dialogue. */
-static void add_preferences_node(GtkTreeStore *, GtkTreeIter *, GGenConfig *, GtkStack *, pref_node_desc_t *);
+ widget = GTK_WIDGET_CLASS(class);
-/* Affiche le panneau correspondant au noeud sélectionné. */
-static void on_prefs_selection_changed(GtkTreeSelection *, GtkBuilder *);
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/preferences.ui");
-/* Lance la sauvegarde d'éléments de paramétrage. */
-static void store_preferences_node(GGenConfig *, pref_node_desc_t *);
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_title);
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_content);
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_title);
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_content);
-/* Sauvegarde l'ensemble des paramètres de configuration. */
-static void on_prefs_apply_button_clicked(GtkButton *, GtkBuilder *);
+ /* Active une action native (cf. https://docs.gtk.org/gtk4/class.Window.html#actions) */
+ gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0 /* GDK 4.14 : GDK_NO_MODIFIER_MASK */, "window.close", NULL);
+}
/******************************************************************************
* *
-* Paramètres : store = arborescence des sections à compléter. *
-* parent = point d'insertion du parent. *
-* config = configuration globale à charger. *
-* stack = pile de composants GTK à constituer. *
-* node = noeud de description courant à traiter. *
+* Paramètres : dialog = composant GTK à initialiser. *
* *
-* Description : Ajoute un panneau de paramétrage à la boîte de dialogue. *
+* Description : Procède à l'initialisation de la fenêtre des paramètres. *
* *
* Retour : - *
* *
@@ -154,95 +130,152 @@ static void on_prefs_apply_button_clicked(GtkButton *, GtkBuilder *);
* *
******************************************************************************/
-static void add_preferences_node(GtkTreeStore *store, GtkTreeIter *parent, GGenConfig *config, GtkStack *stack, pref_node_desc_t *node)
+static void gtk_preferences_dialog_init(GtkPreferencesDialog *dialog)
{
- GtkTreeIter iter; /* Point d'insertion */
- pref_node_desc_t *child; /* Sous-élément à traiter */
+ size_t i; /* Boucle de parcours */
+ const tweak_info_t *info; /* Informations à considérer */
+ GtkListBox *navigation; /* Liste de sections à afficher*/
+ GtkTweakSection *section; /* Nouvelle section à présenter*/
+ tweak_info_t *dyn_infos; /* Informations supplémentaires*/
+ size_t dyn_count; /* Quantité de ces informations*/
+
+ tweak_info_t infos[] = {
+ TWEAK_SIMPLE_DEF("root", "Basics",
+ "security-high-symbolic", "appearance", "Appearance", GTK_TYPE_APPEARANCE_TWEAK_PANEL),
+ TWEAK_SIMPLE_DEF("root", "Basics",
+ "security-high-symbolic", "security", "Security", GTK_TYPE_SECURITY_TWEAK_PANEL),
+ };
+
+ gtk_widget_init_template(GTK_WIDGET(dialog));
- if (node->create == NULL)
+ dialog->navigations = g_hash_table_new_full(g_str_hash, g_str_equal, free, g_object_unref);
+
+ /* Chargement des sections fixes */
+
+ for (i = 0; i < ARRAY_SIZE(infos); i++)
{
- node->builder = NULL;
- node->panel = NULL;
+ info = &infos[i];
+
+ navigation = gtk_preferences_dialog_get_navigation(dialog, info->parent, true);
+ assert(navigation != NULL);
+
+ section = gtk_tweak_section_new(info);
+
+ gtk_list_box_append(navigation, GTK_WIDGET(section));
+
}
- else
+
+ /* Chargement des sections dynamiques */
+
+ dyn_infos = get_tweakable_plugins_info(&dyn_count);
+
+ for (i = 0; i < dyn_count; i++)
{
- node->panel = node->create(&node->builder);
+ info = &dyn_infos[i];
- node->load(node->builder, config);
+ navigation = gtk_preferences_dialog_get_navigation(dialog, info->parent, true);
+ assert(navigation != NULL);
- gtk_widget_show(node->panel);
+ section = gtk_tweak_section_new(info);
- gtk_stack_add_named(stack, node->panel, node->name);
+ gtk_list_box_append(navigation, GTK_WIDGET(section));
}
- gtk_tree_store_append(store, &iter, parent);
+ if (dyn_infos != NULL)
+ free(dyn_infos);
+
+ /* Affichage de la liste racine */
- gtk_tree_store_set(store, &iter,
- PLI_TITLE, _(node->title),
- PLI_PANEL, node->panel,
- -1);
+ navigation = gtk_preferences_dialog_get_navigation(dialog, "root", false);
+ assert(navigation != NULL);
- if (node->children != NULL)
- for (child = node->children; child->title != NULL; child++)
- add_preferences_node(store, &iter, config, stack, child);
+ g_signal_connect(navigation, "row-selected",
+ G_CALLBACK(gtk_preferences_dialog_on_row_selected), dialog);
+
+ gtk_scrolled_window_set_child(dialog->side_content, GTK_WIDGET(navigation));
+
+ unref_object(navigation);
}
/******************************************************************************
* *
-* Paramètres : parent = fenêtre principale de l'éditeur. *
-* outb = constructeur à détruire après usage. [OUT] *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Propose une boîte de dialogue pour la configuration générale.*
+* Description : Supprime toutes les références externes. *
* *
-* Retour : Adresse de la fenêtre mise en place. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GtkWidget *create_preferences_dialog(GtkWindow *parent, GtkBuilder **outb)
+static void gtk_preferences_dialog_dispose(GObject *object)
{
- GtkWidget *result; /* Fenêtre à renvoyer */
- GtkBuilder *builder; /* Constructeur utilisé */
- GGenConfig *config; /* Configuration globale */
- GtkStack *stack; /* Pile à mettre à jour */
- GtkTreeStore *store; /* Arborescence des sections */
- pref_node_desc_t *iter; /* Boucle de parcours */
- GtkTreeView *treeview; /* Arborescence principale */
+ GtkPreferencesDialog *dialog; /* Version spécialisée */
+
+ dialog = GTK_PREFERENCES_DIALOG(object);
- builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/preferences.ui");
- *outb = builder;
+ if (dialog->navigations != NULL)
+ {
+ /**
+ * Cf. documentation de g_hash_table_new_full().
+ */
+ g_hash_table_remove_all(dialog->navigations);
- result = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
+ g_hash_table_unref(dialog->navigations);
+ dialog->navigations = NULL;
- gtk_window_set_transient_for(GTK_WINDOW(result), parent);
+ }
- /* Intégration des différentes sections */
+ gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_PREFERENCES_DIALOG);
+
+ G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->dispose(object);
+
+}
- config = get_main_configuration();
- stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- store = GTK_TREE_STORE(gtk_builder_get_object(builder, "pref_list"));
+static void gtk_preferences_dialog_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->finalize(object);
- for (iter = _prefs_nodes; iter->title != NULL; iter++)
- add_preferences_node(store, NULL, config, stack, iter);
+}
- treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview"));
- gtk_tree_view_expand_all(treeview);
+/******************************************************************************
+* *
+* Paramètres : parent = fenêtre parente à surpasser. *
+* *
+* Description : Construit une boîte de dialogue pour les préférences. *
+* *
+* Retour : Adresse de la fenêtre mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- /* Connexion des signaux */
+GtkWindow *gtk_preferences_dialog_new(GtkWindow *parent)
+{
+ GtkWindow *result; /* Boite de dialogue à renvoyer*/
- gtk_builder_add_callback_symbols(builder,
- BUILDER_CALLBACK(on_prefs_selection_changed),
- BUILDER_CALLBACK(on_prefs_apply_button_clicked),
- NULL);
+ result = g_object_new(GTK_TYPE_PREFERENCES_DIALOG, NULL);
- gtk_builder_connect_signals(builder, builder);
+ if (!gtk_preferences_dialog_create(GTK_PREFERENCES_DIALOG(result), parent))
+ g_clear_object(&result);
return result;
@@ -251,79 +284,85 @@ GtkWidget *create_preferences_dialog(GtkWindow *parent, GtkBuilder **outb)
/******************************************************************************
* *
-* Paramètres : selection = sélection courante de l'arborescence des options.*
-* builder = constructeur GTK avec toutes les références. *
+* Paramètres : dialog = boîte de dialogue à initialiser pleinement. *
+* parent = fenêtre parente à surpasser. *
* *
-* Description : Affiche le panneau correspondant au noeud sélectionné. *
+* Description : Met en place la boîte de dialogue pour les préférences. *
* *
-* Retour : - *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void on_prefs_selection_changed(GtkTreeSelection *selection, GtkBuilder *builder)
+bool gtk_preferences_dialog_create(GtkPreferencesDialog *dialog, GtkWindow *parent)
{
- GtkTreeModel *model; /* Gestionnaire de données */
- GtkTreeIter iter; /* Position courante */
- GtkWidget *panel; /* Panneau à mettre en avant */
- GtkStack *stack; /* Pile à mettre à jour */
-
- if (gtk_tree_selection_get_selected(selection, &model, &iter))
- {
- gtk_tree_model_get(model, &iter, PLI_PANEL, &panel, -1);
+ bool result; /* Bilan à retourner */
- stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
+ result = true;
- if (panel == NULL)
- gtk_stack_set_visible_child_name(stack, "empty");
-
- else
- {
- gtk_stack_set_visible_child(stack, panel);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
- g_object_unref(G_OBJECT(panel));
-
- }
-
- }
+ return result;
}
/******************************************************************************
* *
-* Paramètres : config = configuration globale à actualiser. *
-* node = noeud de description courant à traiter. *
+* Paramètres : dialog = boîte de dialogue à initialiser pleinement. *
+* key = désignation de la liste à fournir. *
+* create = autorisation d'une création si besoin est. *
* *
-* Description : Lance la sauvegarde d'éléments de paramétrage. *
+* Description : Fournit la liste de section désignée par un nom. *
* *
-* Retour : - *
+* Retour : Composant graphique à utiliser. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void store_preferences_node(GGenConfig *config, pref_node_desc_t *node)
+static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *dialog, const char *key, bool create)
{
- pref_node_desc_t *child; /* Sous-élément à traiter */
+ GtkListBox *result; /* Instance à retourner */
+#ifndef NDEBUG
+ gboolean status; /* Bilan d'une insertion */
+#endif
- if (node->create != NULL)
- node->store(node->builder, config);
+ result = g_hash_table_lookup(dialog->navigations, key);
- if (node->children != NULL)
- for (child = node->children; child->title != NULL; child++)
- store_preferences_node(config, child);
+ if (result == NULL && create)
+ {
+ result = GTK_LIST_BOX(gtk_list_box_new());
+ g_object_ref_sink(G_OBJECT(result));
+
+ gtk_list_box_set_selection_mode(result, GTK_SELECTION_BROWSE);
+ gtk_widget_add_css_class(GTK_WIDGET(result), "navigation-sidebar");
+
+#ifndef NDEBUG
+ status = g_hash_table_insert(dialog->navigations, strdup(key), result);
+ assert(status);
+#else
+ g_hash_table_insert(dialog->navigations, key, result);
+#endif
+
+ }
+
+ if (result != NULL)
+ ref_object(result);
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : button = bouton GTK à l'origine de l'opération. *
-* builder = constructeur GTK avec toutes les références. *
+* Paramètres : navigation = liste concernée par l'événement. *
+* selected = élément sélectionné (voire NULL). *
+* dialog = boîte de dialogue à initialiser pleinement. *
* *
-* Description : Sauvegarde l'ensemble des paramètres de configuration. *
+* Description : Réagit à un changement de sélection dans les sections. *
* *
* Retour : - *
* *
@@ -331,14 +370,41 @@ static void store_preferences_node(GGenConfig *config, pref_node_desc_t *node)
* *
******************************************************************************/
-static void on_prefs_apply_button_clicked(GtkButton *button, GtkBuilder *builder)
+static void gtk_preferences_dialog_on_row_selected(GtkListBox *navigation, GtkListBoxRow *selected, GtkPreferencesDialog *dialog)
{
- GGenConfig *config; /* Configuration globale */
- pref_node_desc_t *iter; /* Boucle de parcours */
+ GtkTweakSection *section; /* Nature réelle sélectionnée */
+ GType type; /* Type de panneau de config. */
+ GtkWidget *panel; /* Nouveau panneau à présenter */
+
+ if (selected != NULL)
+ {
+ if (!gtk_tweak_section_has_sub_section(GTK_TWEAK_SECTION(selected)))
+ {
+ section = GTK_TWEAK_SECTION(selected);
+
+ gtk_label_set_text(dialog->main_title, gtk_tweak_section_get_label(section));
+
+ type = gtk_tweak_section_get_panel(section);
+ panel = g_object_new(type, NULL);
- config = get_main_configuration();
+ gtk_scrolled_window_set_child(dialog->main_content, panel);
- for (iter = _prefs_nodes; iter->title != NULL; iter++)
- store_preferences_node(config, iter);
+ }
+
+ else
+ {
+
+ // TODO
+
+ }
+
+ }
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
diff --git a/src/gui/dialogs/preferences.h b/src/gui/dialogs/preferences.h
index d04af72..e291ea8 100644
--- a/src/gui/dialogs/preferences.h
+++ b/src/gui/dialogs/preferences.h
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * preferences.h - prototypes pour la (re)définition de l'identité de l'utilisateur
+ * preferences.h - prototypes pour la boîte de dialogue d'édition des préférences de l'utilisateur
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -28,9 +28,17 @@
#include <gtk/gtk.h>
+#include "../../glibext/helpers.h"
-/* Propose une boîte de dialogue pour la configuration générale. */
-GtkWidget *create_preferences_dialog(GtkWindow *, GtkBuilder **);
+
+
+#define GTK_TYPE_PREFERENCES_DIALOG (gtk_preferences_dialog_get_type())
+
+DECLARE_GTYPE(GtkPreferencesDialog, gtk_preferences_dialog, GTK, PREFERENCES_DIALOG);
+
+
+/* Construit une boîte de dialogue pour les préférences. */
+GtkWindow *gtk_preferences_dialog_new(GtkWindow *);
diff --git a/src/gui/dialogs/preferences.ui b/src/gui/dialogs/preferences.ui
index 251ef46..950242a 100644
--- a/src/gui/dialogs/preferences.ui
+++ b/src/gui/dialogs/preferences.ui
@@ -1,156 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.21.0 -->
<interface>
- <requires lib="gtk+" version="3.20"/>
- <object class="GtkTreeStore" id="pref_list">
- <columns>
- <!-- column-name title -->
- <column type="gchararray"/>
- <!-- column-name panel -->
- <column type="GObject"/>
- </columns>
- </object>
- <object class="GtkDialog" id="window">
- <property name="can_focus">False</property>
- <property name="title" translatable="yes">General preferences</property>
- <property name="modal">True</property>
- <property name="default_width">800</property>
- <property name="default_height">500</property>
- <property name="type_hint">dialog</property>
- <child internal-child="vbox">
- <object class="GtkBox">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">2</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox">
- <property name="can_focus">False</property>
- <property name="margin_left">8</property>
- <property name="margin_right">8</property>
- <property name="margin_top">8</property>
- <property name="margin_bottom">8</property>
- <property name="layout_style">end</property>
- <child>
- <object class="GtkButton" id="button1">
- <property name="label">gtk-cancel</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="button2">
- <property name="label">gtk-apply</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- <signal name="clicked" handler="on_prefs_apply_button_clicked" swapped="no"/>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
+
+ <template class="GtkPreferencesDialog" parent="GtkWindow">
+
+ <property name="default-width">980</property>
+ <property name="default-height">640</property>
+ <property name="modal">true</property>
+ <property name="resizable">true</property>
+
+ <child type="titlebar">
+ <object class="GtkBox">
+ <child>
+ <object class="GtkHeaderBar" id="sidebar-header">
+ <property name="decoration-layout">:</property>
+
+ <property name="title-widget">
+ <object class="GtkLabel" id="side_title">
+ <property name="label" translatable="yes">Parameters</property>
+ <property name="single-line-mode">True</property>
+ <property name="ellipsize">end</property>
+ <property name="width-chars">5</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ </property>
+
+ <child type="start">
+ <object class="GtkToggleButton">
+ <property name="icon-name">edit-find-symbolic</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <!-- Séparation centrale -->
+ <child>
+ <object class="GtkSeparator">
+ <property name="orientation">vertical</property>
+ <property name="css-name">sidebar</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkHeaderBar" id="main-header">
+ <property name="hexpand">1</property>
+
+ <property name="title-widget">
+ <object class="GtkLabel" id="main_title">
+ <property name="label" translatable="yes"></property>
+ <property name="single-line-mode">True</property>
+ <property name="ellipsize">end</property>
+ <property name="width-chars">5</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ </property>
+
+ </object>
+ </child>
+ </object>
</child>
+
<child>
- <object class="GtkPaned">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="position">200</property>
- <property name="wide_handle">True</property>
- <child>
- <object class="GtkScrolledWindow">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="margin_left">8</property>
- <property name="margin_right">8</property>
- <property name="margin_top">8</property>
- <property name="shadow_type">in</property>
+ <object class="GtkBox">
<child>
- <object class="GtkTreeView" id="treeview">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="model">pref_list</property>
- <property name="headers_visible">False</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection">
- <signal name="changed" handler="on_prefs_selection_changed" swapped="no"/>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn">
- <property name="title" translatable="yes">column</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- </object>
+ <object class="GtkScrolledWindow" id="side_content">
+ <property name="hexpand">false</property>
+ <property name="vexpand">true</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ </object>
+ </child>
+
+ <!-- Séparation centrale -->
+ <child>
+ <object class="GtkSeparator">
+ <property name="orientation">vertical</property>
+ <property name="css-name">sidebar</property>
+ </object>
</child>
- </object>
- <packing>
- <property name="resize">False</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- <child>
- <object class="GtkStack" id="stack">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">8</property>
- <property name="margin_right">8</property>
- <property name="margin_top">8</property>
+
<child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="name">empty</property>
- </packing>
+ <object class="GtkScrolledWindow" id="main_content">
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ </object>
</child>
- </object>
- <packing>
- <property name="resize">True</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
+ </object>
</child>
- </object>
- </child>
- <action-widgets>
- <action-widget response="-6">button1</action-widget>
- <action-widget response="-10">button2</action-widget>
- </action-widgets>
- <child>
- <placeholder/>
- </child>
- </object>
+
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="sidebar-header"/>
+ <widget name="side_content"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="main-header"/>
+ <widget name="main_content"/>
+ </widgets>
+ </object>
+
+ </template>
</interface>
diff --git a/src/gui/dialogs/prefs/Makefile.am b/src/gui/dialogs/prefs/Makefile.am
new file mode 100644
index 0000000..50bc3c8
--- /dev/null
+++ b/src/gui/dialogs/prefs/Makefile.am
@@ -0,0 +1,34 @@
+
+BUILT_SOURCES = resources.h resources.c
+
+noinst_LTLIBRARIES = libguidialogsprefs.la
+
+UI_FILES = \
+ appearance.ui \
+ security.ui
+
+libguidialogsprefs_la_SOURCES = \
+ appearance-int.h \
+ appearance.h appearance.c \
+ resources.h resources.c \
+ security-int.h \
+ security.h security.c
+
+libguidialogsprefs_la_CFLAGS = $(LIBGTK4_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libguidialogsprefs_la_SOURCES:%c=)
+
+
+resources.c: gresource.xml $(UI_FILES)
+ glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_dialogs_prefs gresource.xml
+
+resources.h: gresource.xml
+ glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name gui_dialogs_prefs gresource.xml
+
+
+CLEANFILES = resources.h resources.c
+
+EXTRA_DIST = gresource.xml $(UI_FILES)
diff --git a/src/gui/dialogs/prefs/appearance-int.h b/src/gui/dialogs/prefs/appearance-int.h
new file mode 100644
index 0000000..886a562
--- /dev/null
+++ b/src/gui/dialogs/prefs/appearance-int.h
@@ -0,0 +1,64 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * appearance-int.h - définitions internes pour la configuration des paramètres liés aux apparences
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_DIALOGS_PREFS_APPEARANCE_INT_H
+#define _GUI_DIALOGS_PREFS_APPEARANCE_INT_H
+
+
+#include "appearance.h"
+
+
+
+/* Composant d'édition des paramètres liés aux apparences (instance) */
+struct _GtkAppearanceTweakPanel
+{
+ GtkBox parent; /* A laisser en premier */
+
+ /* Disposition des panneaux */
+
+ GSettings *tiles_settings; /* Configuration sollicitée */
+
+ GtkWidget *layout_preview; /* Zone d'aperçu de dispositon*/
+
+ GtkWidget *top_panel; /* Composant d'aperçu #1 */
+ GtkWidget *left_panel; /* Composant d'aperçu #2 */
+ GtkWidget *right_panel; /* Composant d'aperçu #3 */
+ GtkWidget *bottom_panel; /* Composant d'aperçu #4 */
+
+ GtkCheckButton *left_top_reach; /* Paramètre de disposition #1 */
+ GtkCheckButton *left_bottom_reach; /* Paramètre de disposition #2 */
+ GtkCheckButton *right_top_reach; /* Paramètre de disposition #3 */
+ GtkCheckButton *right_bottom_reach; /* Paramètre de disposition #4 */
+
+};
+
+/* Composant d'édition des paramètres liés aux apparences (classe) */
+struct _GtkAppearanceTweakPanelClass
+{
+ GtkBoxClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _GUI_DIALOGS_PREFS_APPEARANCE_INT_H */
diff --git a/src/gui/dialogs/prefs/appearance.c b/src/gui/dialogs/prefs/appearance.c
new file mode 100644
index 0000000..a8585fa
--- /dev/null
+++ b/src/gui/dialogs/prefs/appearance.c
@@ -0,0 +1,251 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * appearance.c - configuration des paramètres liés aux apparences
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "appearance.h"
+
+
+#include "appearance-int.h"
+#include "../../../gtkext/grid.h"
+#include "../../../gtkext/helpers.h"
+
+
+
+/* Procède à l'initialisation de classe des configurations. */
+static void gtk_appearance_tweak_panel_class_init(GtkAppearanceTweakPanelClass *);
+
+/* Procède à l'initialisation des configurations de sécurité. */
+static void gtk_appearance_tweak_panel_init(GtkAppearanceTweakPanel *);
+
+/* Supprime toutes les références externes. */
+static void gtk_appearance_tweak_panel_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_appearance_tweak_panel_finalize(GObject *);
+
+/* Réagit à un changement de paramètre de configuration. */
+static void gtk_appearance_tweak_panel_on_tiles_settings_changed(GSettings *, const gchar *, GtkAppearanceTweakPanel *);
+
+/* Change la disposition des panneaux de la fenêtre principale. */
+static void gtk_appearance_tweak_panel_on_panel_reach_toggled(GtkCheckButton *, GtkAppearanceTweakPanel *);
+
+
+/* Indique le type du composant de configuration des notes. */
+G_DEFINE_TYPE(GtkAppearanceTweakPanel, gtk_appearance_tweak_panel, GTK_TYPE_BOX);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de classe des configurations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_appearance_tweak_panel_class_init(GtkAppearanceTweakPanelClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_appearance_tweak_panel_dispose;
+ object->finalize = gtk_appearance_tweak_panel_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/prefs/appearance.ui");
+
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_appearance_tweak_panel_on_panel_reach_toggled));
+
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, layout_preview);
+
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, top_panel);
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_panel);
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_panel);
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, bottom_panel);
+
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_top_reach);
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_bottom_reach);
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_top_reach);
+ gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_bottom_reach);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = composant GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation des configurations de sécurité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_appearance_tweak_panel_init(GtkAppearanceTweakPanel *panel)
+{
+ LayoutReachOptions options; /* Détails de disposition */
+
+ gtk_widget_init_template(GTK_WIDGET(panel));
+
+ panel->tiles_settings = g_settings_new_with_path("re.chrysalide.framework.tiledgrid",
+ "/re/chrysalide/framework/gui/tiles/");
+
+ options = g_settings_get_flags(panel->tiles_settings, "layout");
+
+ gtk_check_button_set_active(panel->left_top_reach, options & LRO_LEFT_TOP_REACH);
+ gtk_check_button_set_active(panel->left_bottom_reach, options & LRO_LEFT_BOTTOM_REACH);
+ gtk_check_button_set_active(panel->right_top_reach, options & LRO_RIGHT_TOP_REACH);
+ gtk_check_button_set_active(panel->right_bottom_reach, options & LRO_RIGHT_BOTTOM_REACH);
+
+ gtk_appearance_tweak_panel_on_tiles_settings_changed(panel->tiles_settings, "layout", panel);
+
+ g_signal_connect(panel->tiles_settings, "changed",
+ G_CALLBACK(gtk_appearance_tweak_panel_on_tiles_settings_changed), panel);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_appearance_tweak_panel_dispose(GObject *object)
+{
+ GtkAppearanceTweakPanel *panel; /* Version spécialisée */
+
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_APPEARANCE_TWEAK_PANEL);
+
+ panel = GTK_APPEARANCE_TWEAK_PANEL(object);
+
+ g_clear_object(&panel->tiles_settings);
+
+ G_OBJECT_CLASS(gtk_appearance_tweak_panel_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_appearance_tweak_panel_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_appearance_tweak_panel_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : settings = ensemble de paramètres connaissant une évolution. *
+* key = identifiant du paramètre ayant changé. *
+* panel = panneau de paramétrage concerné par l'appel. *
+* *
+* Description : Réagit à un changement de paramètre de configuration. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_appearance_tweak_panel_on_tiles_settings_changed(GSettings *settings, const gchar *key, GtkAppearanceTweakPanel *panel)
+{
+ LayoutReachOptions options; /* Détails de disposition */
+
+ if (strcmp(key, "layout") == 0)
+ {
+ options = g_settings_get_flags(panel->tiles_settings, "layout");
+
+ apply_tiling_grid_layout(GTK_GRID(panel->layout_preview), options, (GtkWidget *[]) {
+ panel->top_panel, panel->left_panel, panel->right_panel, panel->bottom_panel
+ });
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = composant radio dont l'état vient de basculer. *
+* panel = panneau d'édition des préférences courant. *
+* *
+* Description : Change la disposition des panneaux de la fenêtre principale. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_appearance_tweak_panel_on_panel_reach_toggled(GtkCheckButton *button, GtkAppearanceTweakPanel *panel)
+{
+ gboolean left_top_reach; /* Paramètre de disposition #1 */
+ gboolean left_bottom_reach; /* Paramètre de disposition #2 */
+ gboolean right_top_reach; /* Paramètre de disposition #3 */
+ gboolean right_bottom_reach; /* Paramètre de disposition #4 */
+ LayoutReachOptions options; /* Options à appliquer */
+
+ /* Récupération des indications */
+
+ left_top_reach = gtk_check_button_get_active(panel->left_top_reach);
+ left_bottom_reach = gtk_check_button_get_active(panel->left_bottom_reach);
+ right_top_reach = gtk_check_button_get_active(panel->right_top_reach);
+ right_bottom_reach = gtk_check_button_get_active(panel->right_bottom_reach);
+
+ /* Conversion et application */
+
+ options = LRO_NONE;
+
+ if (left_top_reach) options |= LRO_LEFT_TOP_REACH;
+ if (left_bottom_reach) options |= LRO_LEFT_BOTTOM_REACH;
+ if (right_top_reach) options |= LRO_RIGHT_TOP_REACH;
+ if (right_bottom_reach) options |= LRO_RIGHT_BOTTOM_REACH;
+
+ g_settings_set_flags(panel->tiles_settings, "layout", options);
+
+}
diff --git a/src/gui/dialogs/prefs/appearance.h b/src/gui/dialogs/prefs/appearance.h
new file mode 100644
index 0000000..916b194
--- /dev/null
+++ b/src/gui/dialogs/prefs/appearance.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * appearance.h - prototypes pour la configuration des paramètres liés aux apparences
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_DIALOGS_PREFS_APPEARANCE_H
+#define _GUI_DIALOGS_PREFS_APPEARANCE_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../../../glibext/helpers.h"
+
+
+
+#define GTK_TYPE_APPEARANCE_TWEAK_PANEL (gtk_appearance_tweak_panel_get_type())
+
+DECLARE_GTYPE(GtkAppearanceTweakPanel, gtk_appearance_tweak_panel, GTK, APPEARANCE_TWEAK_PANEL);
+
+
+
+#endif /* _GUI_DIALOGS_PREFS_APPEARANCE_H */
diff --git a/src/gui/dialogs/prefs/appearance.ui b/src/gui/dialogs/prefs/appearance.ui
new file mode 100644
index 0000000..3410115
--- /dev/null
+++ b/src/gui/dialogs/prefs/appearance.ui
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <template class="GtkAppearanceTweakPanel" parent="GtkBox">
+
+ <property name="orientation">vertical</property>
+ <property name="margin-start">20</property>
+ <property name="margin-end">20</property>
+ <property name="margin-top">20</property>
+ <property name="margin-bottom">20</property>
+ <property name="spacing">10</property>
+
+ <!-- Disposition des panneaux -->
+
+ <child>
+ <object class="GtkLabel">
+ <property name="label">Layout</property>
+ <property name="use-markup">true</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="label">Layout defines the global panel organization of the main window.</property>
+ <property name="wrap">true</property>
+ <property name="use-markup">true</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+
+ <!-- Aperçu -->
+
+ <child>
+ <object class="GtkGrid" id="layout_preview">
+ <property name="margin-start">20</property>
+ <property name="margin-end">20</property>
+ <property name="margin-top">10</property>
+ <property name="margin-bottom">10</property>
+ <property name="row-spacing">5</property>
+ <property name="column-spacing">5</property>
+ <property name="hexpand">false</property>
+ <property name="vexpand">false</property>
+ <property name="height-request">200</property>
+ <property name="width-request">300</property>
+
+ <child>
+ <object class="GtkFrame" id="top_panel">
+ <property name="hexpand">true</property>
+ <property name="vexpand">false</property>
+ <property name="height-request">20</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="column-span">3</property>
+ </layout>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkFrame" id="left_panel">
+ <property name="hexpand">false</property>
+ <property name="vexpand">true</property>
+ <property name="width-request">50</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">1</property>
+ </layout>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkFrame">
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">1</property>
+ </layout>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkFrame" id="right_panel">
+ <property name="hexpand">false</property>
+ <property name="vexpand">true</property>
+ <property name="width-request">50</property>
+ <layout>
+ <property name="column">2</property>
+ <property name="row">1</property>
+ </layout>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkFrame" id="bottom_panel">
+ <property name="hexpand">true</property>
+ <property name="vexpand">false</property>
+ <property name="height-request">50</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">2</property>
+ <property name="column-span">3</property>
+ </layout>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <!-- Options -->
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="valign">center</property>
+ <property name="spacing">10</property>
+
+ <child>
+ <object class="GtkCheckButton" id="left_top_reach">
+ <property name="label">Left panels reach the top of the window</property>
+ <property name="active">false</property>
+ <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkCheckButton" id="left_bottom_reach">
+ <property name="label">Left panels reach the bottom of the window</property>
+ <property name="active">false</property>
+ <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkCheckButton" id="right_top_reach">
+ <property name="label">Right panels reach the top of the window</property>
+ <property name="active">false</property>
+ <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkCheckButton" id="right_bottom_reach">
+ <property name="label">Right panels reach the bottom of the window</property>
+ <property name="active">false</property>
+ <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/gui/dialogs/prefs/gresource.xml b/src/gui/dialogs/prefs/gresource.xml
new file mode 100644
index 0000000..ad0f97f
--- /dev/null
+++ b/src/gui/dialogs/prefs/gresource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/re/chrysalide/framework/gui/dialogs/prefs">
+ <file compressed="true">appearance.ui</file>
+ <file compressed="true">security.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/gui/dialogs/prefs/security-int.h b/src/gui/dialogs/prefs/security-int.h
new file mode 100644
index 0000000..be7867c
--- /dev/null
+++ b/src/gui/dialogs/prefs/security-int.h
@@ -0,0 +1,64 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * security-int.h - définitions internes pour la configuration des paramètres liés à la sécurité
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_DIALOGS_PREFS_SECURITY_INT_H
+#define _GUI_DIALOGS_PREFS_SECURITY_INT_H
+
+
+#include "security.h"
+#include "../../../glibext/secstorage.h"
+
+
+
+/* Composant d'édition des paramètres de sécurité (instance) */
+struct _GtkSecurityTweakPanel
+{
+ GtkBox parent; /* A laisser en premier */
+
+ /* Stockage sécurisé */
+
+ GSecretStorage *storage; /* Stockage des secrets */
+
+ GtkWidget *current_primary_passwd; /* Mot de passe courant */
+
+ GtkWidget *new_primary_passwd; /* Nouveau mot de passe */
+ GtkWidget *new_primary_passwd_lbl; /* Etiquette associée */
+ GtkWidget *new_primary_passwd_2; /* Nouveau mot de passe (#2) */
+ GtkWidget *new_primary_passwd_2_lbl; /* Etiquette associée (#2) */
+
+ GtkWidget *set_password; /* Bouton de définition de mdp */
+ GtkWidget *change_password; /* Bouton de changement de mdp */
+ GtkWidget *remove_password; /* Bouton de suppression de mdp*/
+
+};
+
+/* Composant d'édition des paramètres de sécurité (classe) */
+struct _GtkSecurityTweakPanelClass
+{
+ GtkBoxClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _GUI_DIALOGS_PREFS_SECURITY_INT_H */
diff --git a/src/gui/dialogs/prefs/security.c b/src/gui/dialogs/prefs/security.c
new file mode 100644
index 0000000..2b82339
--- /dev/null
+++ b/src/gui/dialogs/prefs/security.c
@@ -0,0 +1,400 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * security.c - configuration des paramètres liés à la sécurité
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "security.h"
+
+
+#include <i18n.h>
+
+
+#include "security-int.h"
+#include "../../../core/global.h"
+#include "../../../core/logs.h"
+#include "../../../gtkext/helpers.h"
+
+
+
+/* ---------------------- GESTION DE L'ENSEMBLE DES PARAMETRES ---------------------- */
+
+
+/* Procède à l'initialisation de classe des configurations. */
+static void gtk_security_tweak_panel_class_init(GtkSecurityTweakPanelClass *);
+
+/* Procède à l'initialisation des configurations de sécurité. */
+static void gtk_security_tweak_panel_init(GtkSecurityTweakPanel *);
+
+/* Supprime toutes les références externes. */
+static void gtk_security_tweak_panel_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_security_tweak_panel_finalize(GObject *);
+
+
+
+/* ---------------------- CONSERVATION SECURISEE DE PARAMETRES ---------------------- */
+
+
+/* Initalise la partie relative au stockage sécurisé. */
+static void gtk_security_tweak_panel_init_secret_storage(GtkSecurityTweakPanel *);
+
+/* Supprime toutes les références externes. */
+static void gtk_security_tweak_panel_dispose_secret_storage(GtkSecurityTweakPanel *);
+
+/* Note le changement de verrouillage du stockage sécurisé. */
+static void gtk_security_tweak_panel_on_secret_storage_lock_update(GSecretStorage *, GtkSecurityTweakPanel *);
+
+/* Réagit à un changement dans l'édition d'un mot de passe. */
+static void gtk_security_tweak_panel_on_new_passwords_changed(GtkEditable *, GtkSecurityTweakPanel *);
+
+/* Réagit à une demande de création de mot de passe. */
+static void gtk_security_tweak_panel_on_set_password_clicked(GtkButton *, GtkSecurityTweakPanel *);
+
+/* Réagit à une demande de changement de mot de passe. */
+static void gtk_security_tweak_panel_on_change_password_clicked(GtkButton *, GtkSecurityTweakPanel *);
+
+/* Réagit à une demande de suppression de mot de passe. */
+static void gtk_security_tweak_panel_on_remove_password_clicked(GtkButton *, GtkSecurityTweakPanel *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION DE L'ENSEMBLE DES PARAMETRES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type du composant d'édition des paramètres de sécurité. */
+G_DEFINE_TYPE(GtkSecurityTweakPanel, gtk_security_tweak_panel, GTK_TYPE_BOX);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de classe des configurations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_class_init(GtkSecurityTweakPanelClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_security_tweak_panel_dispose;
+ object->finalize = gtk_security_tweak_panel_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/prefs/security.ui");
+
+ /* Stockage sécurisé */
+
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_new_passwords_changed));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_set_password_clicked));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_change_password_clicked));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_remove_password_clicked));
+
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, current_primary_passwd);
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd);
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd_lbl);
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd_2);
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd_2_lbl);
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, set_password);
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, change_password);
+ gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, remove_password);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = composant GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation des configurations de sécurité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_init(GtkSecurityTweakPanel *panel)
+{
+ gtk_widget_init_template(GTK_WIDGET(panel));
+
+ gtk_security_tweak_panel_init_secret_storage(panel);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_dispose(GObject *object)
+{
+ GtkSecurityTweakPanel *panel; /* Version spécialisée */
+
+ panel = GTK_SECURITY_TWEAK_PANEL(object);
+
+ gtk_security_tweak_panel_dispose_secret_storage(panel);
+
+ gtk_widget_dispose_template(GTK_WIDGET(panel), GTK_TYPE_SECURITY_TWEAK_PANEL);
+
+ G_OBJECT_CLASS(gtk_security_tweak_panel_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_security_tweak_panel_parent_class)->finalize(object);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION SECURISEE DE PARAMETRES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = composant GTK à initialiser. *
+* *
+* Description : Initalise la partie relative au stockage sécurisé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_init_secret_storage(GtkSecurityTweakPanel *panel)
+{
+ panel->storage = get_secret_storage();
+
+ g_signal_connect(panel->storage, "lock-update",
+ G_CALLBACK(gtk_security_tweak_panel_on_secret_storage_lock_update), panel);
+
+ gtk_security_tweak_panel_on_secret_storage_lock_update(panel->storage, panel);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_dispose_secret_storage(GtkSecurityTweakPanel *panel)
+{
+ if (panel->storage != NULL)
+ g_signal_handlers_disconnect_by_func(panel->storage,
+ gtk_security_tweak_panel_on_secret_storage_lock_update, panel);
+
+ g_clear_object(&panel->storage);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gardien des secrets impliqué. *
+* panel = support de la partie relative au stockage sécurisé.*
+* *
+* Description : Note le changement de verrouillage du stockage sécurisé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_on_secret_storage_lock_update(GSecretStorage *storage, GtkSecurityTweakPanel *panel)
+{
+ bool has_key; /* Existence d'une clef ? */
+
+ has_key = g_secret_storage_has_key(panel->storage);
+
+ gtk_widget_set_visible(panel->new_primary_passwd, has_key);
+ gtk_widget_set_visible(panel->new_primary_passwd_lbl, has_key);
+
+ gtk_widget_set_visible(panel->new_primary_passwd_2, has_key);
+ gtk_widget_set_visible(panel->new_primary_passwd_2_lbl, has_key);
+
+ gtk_widget_set_visible(panel->set_password, !has_key);
+ gtk_widget_set_visible(panel->change_password, has_key);
+ gtk_widget_set_visible(panel->remove_password, has_key);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : editable = zone de saisie bouton GTK concerné par l'appel. *
+* panel = support de la partie liée au stockage sécurisé. *
+* *
+* Description : Réagit à un changement dans l'édition d'un mot de passe. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_on_new_passwords_changed(GtkEditable *editable, GtkSecurityTweakPanel *panel)
+{
+ const char *new_passwd; /* Nouveau mot de passe #1 */
+ const char *new_passwd_2; /* Nouveau mot de passe #2 */
+ bool status; /* Bilan de l'opération */
+
+ new_passwd = gtk_editable_get_text(GTK_EDITABLE(panel->new_primary_passwd));
+
+ new_passwd_2 = gtk_editable_get_text(GTK_EDITABLE(panel->new_primary_passwd_2));
+
+ status = (strcmp(new_passwd, new_passwd_2) == 0);
+
+ gtk_widget_set_sensitive(panel->change_password, status);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton GTK concerné par l'appel. *
+* panel = support de la partie relative au stockage sécurisé. *
+* *
+* Description : Réagit à une demande de création de mot de passe. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_on_set_password_clicked(GtkButton *button, GtkSecurityTweakPanel *panel)
+{
+ const char *passwd; /* Mot de passe à considérer */
+ bool status; /* Bilan de l'opération */
+
+ passwd = gtk_editable_get_text(GTK_EDITABLE(panel->current_primary_passwd));
+
+ status = g_secret_storage_set_password(panel->storage, passwd);
+
+ log_variadic_message(LMT_INFO, _("Setting password for secret storage: %s"),
+ status ? _("success") : _("failed"));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton GTK concerné par l'appel. *
+* panel = support de la partie relative au stockage sécurisé. *
+* *
+* Description : Réagit à une demande de changement de mot de passe. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_on_change_password_clicked(GtkButton *button, GtkSecurityTweakPanel *panel)
+{
+ const char *old_passwd; /* Ancien mot de passe */
+ const char *new_passwd; /* Nouveau mot de passe */
+ bool status; /* Bilan de l'opération */
+
+ old_passwd = gtk_editable_get_text(GTK_EDITABLE(panel->current_primary_passwd));
+
+ new_passwd = gtk_editable_get_text(GTK_EDITABLE(panel->new_primary_passwd));
+
+ status = g_secret_storage_change_password(panel->storage, old_passwd, new_passwd);
+
+ log_variadic_message(LMT_INFO, _("Changed password for secret storage: %s"),
+ status ? _("success") : _("failed"));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton GTK concerné par l'appel. *
+* panel = support de la partie relative au stockage sécurisé. *
+* *
+* Description : Réagit à une demande de suppression de mot de passe. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_security_tweak_panel_on_remove_password_clicked(GtkButton *button, GtkSecurityTweakPanel *panel)
+{
+ const char *passwd; /* Mot de passe à considérer */
+ bool status; /* Bilan de l'opération */
+
+ passwd = gtk_editable_get_text(GTK_EDITABLE(panel->current_primary_passwd));
+
+ status = g_secret_storage_remove_password(panel->storage, passwd);
+
+ log_variadic_message(LMT_INFO, _("Removed password for secret storage: %s"),
+ status ? _("success") : _("failed"));
+
+}
diff --git a/src/gui/dialogs/prefs/security.h b/src/gui/dialogs/prefs/security.h
new file mode 100644
index 0000000..206a123
--- /dev/null
+++ b/src/gui/dialogs/prefs/security.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * security.h - prototypes pour la configuration des paramètres liés à la sécurité
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_DIALOGS_PREFS_SECURITY_H
+#define _GUI_DIALOGS_PREFS_SECURITY_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../../../glibext/helpers.h"
+
+
+
+#define GTK_TYPE_SECURITY_TWEAK_PANEL (gtk_security_tweak_panel_get_type())
+
+DECLARE_GTYPE(GtkSecurityTweakPanel, gtk_security_tweak_panel, GTK, SECURITY_TWEAK_PANEL);
+
+
+
+#endif /* _GUI_DIALOGS_PREFS_SECURITY_H */
diff --git a/src/gui/dialogs/prefs/security.ui b/src/gui/dialogs/prefs/security.ui
new file mode 100644
index 0000000..ccf2d39
--- /dev/null
+++ b/src/gui/dialogs/prefs/security.ui
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <template class="GtkSecurityTweakPanel" parent="GtkBox">
+
+ <property name="orientation">vertical</property>
+
+ <!-- Conservation de paramètres sécurisée -->
+ <child>
+ <object class="GtkGrid">
+ <property name="margin-start">20</property>
+ <property name="margin-end">20</property>
+ <property name="margin-top">20</property>
+ <property name="margin-bottom">20</property>
+ <property name="row-spacing">10</property>
+ <property name="column-spacing">10</property>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="label">Secret storage</property>
+ <property name="use-markup">true</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="column-span">2</property>
+ </layout>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="label">Configuration may handle sensitive data (such as passwords or API keys) which can be saved in plain text or stored encrypted using a Primary Password.
+
+If encryption is activated, entering the Primary Password will be asked on need once per session.</property>
+ <property name="wrap">true</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">1</property>
+ <property name="column-span">2</property>
+ </layout>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+
+ <!-- Mot de passe courant -->
+
+ <child>
+ <object class="GtkLabel">
+ <property name="label">Enter current password:</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">2</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkPasswordEntry" id="current_primary_passwd">
+ <property name="hexpand">true</property>
+ <property name="show-peek-icon">true</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">2</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Nouveau mot de passe -->
+
+ <child>
+ <object class="GtkLabel" id="new_primary_passwd_lbl">
+ <property name="label">Enter new password:</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">3</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkPasswordEntry" id="new_primary_passwd">
+ <property name="hexpand">true</property>
+ <property name="show-peek-icon">true</property>
+ <signal name="changed" handler="gtk_security_tweak_panel_on_new_passwords_changed"/>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">3</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Confirmation de mot de passe -->
+
+ <child>
+ <object class="GtkLabel" id="new_primary_passwd_2_lbl">
+ <property name="label">Re-enter new password:</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">4</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkPasswordEntry" id="new_primary_passwd_2">
+ <property name="hexpand">true</property>
+ <property name="show-peek-icon">true</property>
+ <signal name="changed" handler="gtk_security_tweak_panel_on_new_passwords_changed"/>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">4</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Boutons de contrôle -->
+
+ <child>
+ <object class="GtkBox">
+ <property name="halign">center</property>
+ <property name="homogeneous">true</property>
+ <property name="spacing">8</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">5</property>
+ <property name="column-span">2</property>
+ </layout>
+
+ <child>
+ <object class="GtkButton" id="set_password">
+ <property name="label">Set</property>
+ <signal name="clicked" handler="gtk_security_tweak_panel_on_set_password_clicked"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="change_password">
+ <property name="label">Change</property>
+ <signal name="clicked" handler="gtk_security_tweak_panel_on_change_password_clicked"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="remove_password">
+ <property name="label">Remove</property>
+ <signal name="clicked" handler="gtk_security_tweak_panel_on_remove_password_clicked"/>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/gui/panel-int.h b/src/gui/panel-int.h
deleted file mode 100644
index 7e6f7e3..0000000
--- a/src/gui/panel-int.h
+++ /dev/null
@@ -1,71 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * panel-int.h - prototypes pour les définitions internes liées aux panneaux d'affichage
- *
- * Copyright (C) 2019-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 this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#ifndef _GUI_PANEL_INT_H
-#define _GUI_PANEL_INT_H
-
-
-#include "panel.h"
-
-
-
-/* Fournit une indication sur la personnalité du panneau. */
-typedef PanelItemPersonality (* get_panel_item_personality_cb) (const GPanelItem *);
-
-/* Fournit un composant pour lancer l'activité d'un panneau. */
-typedef GtkWidget * (* get_panel_item_widget_cb) (GPanelItem *);
-
-/* Fournit un composant représentant un panneau graphique. */
-typedef GtkTiledPanel * (* get_panel_item_panel_cb) (GPanelItem *, GtkWidget *);
-
-
-/* Elément réactif pour panneaux de l'éditeur (instance) */
-struct _GPanelItem
-{
- GObject parent; /* A laisser en premier */
-
- GtkWidget *launcher; /* Eventuel lanceur associé */
- GtkWidget *properties; /* Propriétés de lancement */
-
- GtkTiledPanel **panels; /* Instances complètes ouvertes*/
- size_t pcount; /* Quantité de ces instances */
-
-};
-
-/* Elément réactif pour panneaux de l'éditeur (classe) */
-struct _GPanelItemClass
-{
- GObjectClass parent; /* A laisser en premier */
-
- get_panel_item_personality_cb get_personality; /* Fourniture de nature */
-
- get_panel_item_widget_cb get_launcher; /* Lancement d'une activité */
- get_panel_item_widget_cb get_properties;/* Préparation au lancement */
- get_panel_item_panel_cb get_panel; /* Panneau principal */
-
-};
-
-
-
-#endif /* _GUI_PANEL_INT_H */
diff --git a/src/gui/panel.c b/src/gui/panel.c
deleted file mode 100644
index b361153..0000000
--- a/src/gui/panel.c
+++ /dev/null
@@ -1,1207 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * panel.c - gestion des éléments réactifs spécifiques aux panneaux
- *
- * Copyright (C) 2019-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 this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include "panel.h"
-
-
-#include "panel-int.h"
-
-
-
-/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */
-
-
-
-
-
-/* Initialise la classe des panneaux graphiques de l'éditeur. */
-static void g_panel_item_class_init(GPanelItemClass *);
-
-/* Initialise une instance de panneau graphique pour l'éditeur. */
-static void g_panel_item_init(GPanelItem *);
-
-/* Supprime toutes les références externes. */
-static void g_panel_item_dispose(GPanelItem *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_panel_item_finalize(GPanelItem *);
-
-
-
-
-
-/* Indique le type défini pour un élément destiné à un panneau. */
-G_DEFINE_TYPE(GPanelItem, g_panel_item, G_TYPE_OBJECT);
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à initialiser. *
-* *
-* Description : Initialise la classe des panneaux graphiques de l'éditeur. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_panel_item_class_init(GPanelItemClass *class)
-{
- GObjectClass *object; /* Autre version de la classe */
-
- object = G_OBJECT_CLASS(class);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_panel_item_dispose;
- object->finalize = (GObjectFinalizeFunc)g_panel_item_finalize;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance à initialiser. *
-* *
-* Description : Initialise une instance de panneau graphique pour l'éditeur. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_panel_item_init(GPanelItem *item)
-{
- //item->docked = false;
-
- //item->widget = NULL;
- //item->cached_widget = NULL;
-
- //item->filter = NULL;
-
- //g_atomic_int_set(&item->switched, 0);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_panel_item_dispose(GPanelItem *item)
-{
- //g_clear_object(&item->widget);
- //g_clear_object(&item->cached_widget);
-
- G_OBJECT_CLASS(g_panel_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_panel_item_finalize(GPanelItem *item)
-{
- G_OBJECT_CLASS(g_panel_item_parent_class)->finalize(G_OBJECT(item));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = définition de panneau à consulter. *
-* *
-* Description : Fournit une indication sur la personnalité du panneau. *
-* *
-* Retour : Identifiant lié à la nature du panneau. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-PanelItemPersonality g_panel_item_get_personality(const GPanelItem *item)
-{
- PanelItemPersonality result; /* Personnalité à retourner */
- GPanelItemClass *class; /* Classe à actionner */
-
- class = G_PANEL_ITEM_GET_CLASS(item);
-
- result = class->get_personality(item);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = définition de panneau à manipuler. *
-* *
-* Description : Fournit un composant pour lancer l'activité d'un panneau. *
-* *
-* Retour : Composant GTK (déjà ?) mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GtkWidget *g_panel_item_get_launcher(GPanelItem *item)
-{
- GtkWidget *result; /* Composant à retourner */
- GPanelItemClass *class; /* Classe à actionner */
-
- if (item->launcher == NULL)
- {
- class = G_PANEL_ITEM_GET_CLASS(item);
- item->launcher = class->get_launcher(item);
- }
-
- result = item->launcher;
-
- if (result != NULL)
- ref_object(result);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = définition de panneau à manipuler. *
-* *
-* Description : Fournit un composant pour paramétrer l'activité d'un panneau.*
-* *
-* Retour : Composant GTK (déjà ?) mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GtkWidget *g_panel_item_get_properties(GPanelItem *item)
-{
- GtkWidget *result; /* Composant à retourner */
- GPanelItemClass *class; /* Classe à actionner */
-
- if (item->properties == NULL)
- {
- class = G_PANEL_ITEM_GET_CLASS(item);
- item->properties = class->get_properties(item);
- }
-
- result = item->properties;
-
- if (result != NULL)
- ref_object(result);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = définition de panneau à manipuler. *
-* *
-* Description : Fournit un composant représentant un panneau graphique. *
-* *
-* Retour : Composant GTK (déjà ?) mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GtkTiledPanel *g_panel_item_get_panel(GPanelItem *item)
-{
- GtkTiledPanel *result; /* Composant à retourner */
- GPanelItemClass *class; /* Classe à actionner */
-
- if (item->pcount == 0 /* || !singleton */)
- {
- class = G_PANEL_ITEM_GET_CLASS(item);
- result = class->get_panel(item, item->properties);
-
- if (result != NULL)
- {
- item->panels = realloc(item->panels, ++item->pcount * sizeof(GtkTiledPanel *));
- item->panels[item->pcount - 1] = result;
- }
-
- }
-
- else
- result = item->panels[item->pcount - 1];
-
- if (result != NULL)
- ref_object(result);
-
- return result;
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-#if 0
-
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-
-#include "panel-int.h"
-#include "core/global.h"
-#include "core/items.h"
-#include "../common/extstr.h"
-#include "../core/params.h"
-#include "../gtkext/gtkdockable-int.h"
-#include "../gtkext/named.h"
-#include "../plugins/dt.h"
-#include "../plugins/pglist.h"
-
-
-
-/* ------------------------- COEUR DES PANNEAUX D'AFFICHAGE ------------------------- */
-
-
-
-
-/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */
-
-
-/* Construit la chaîne d'accès à un élément de configuration. */
-static char *gtk_panel_item_class_build_configuration_key(const GPanelItemClass *, const char *);
-
-/* Fournit le nom court du composant encapsulable. */
-static char *gtk_panel_item_get_name(const GPanelItem *);
-
-/* Fournit le nom long du composant encapsulable. */
-static char *gtk_panel_item_get_desc(const GPanelItem *);
-
-/* Détermine si un panneau peut être filtré. */
-static bool gtk_panel_item_can_search(const GPanelItem *);
-
-/* Fournit le composant graphique intégrable dans un ensemble. */
-static GtkWidget *gtk_panel_item_get_widget(GPanelItem *);
-
-/* Démarre l'actualisation du filtrage du contenu. */
-static void gtk_panel_item_update_filtered(GPanelItem *, const char *);
-
-
-
-/* ---------------------- MECANISMES DE MISE A JOUR DE PANNEAU ---------------------- */
-
-
-/* Présente une copie de l'affichage du composant rafraîchi. */
-static gboolean g_panel_item_draw_mask(GtkWidget *, cairo_t *, GPanelItem *);
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* COEUR DES PANNEAUX D'AFFICHAGE */
-/* ---------------------------------------------------------------------------------- */
-
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Fournit une indication sur la personnalité du panneau. *
-* *
-* Retour : Identifiant lié à la nature unique du panneau. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-PanelItemPersonality gtk_panel_item_class_get_personality_singleton(const GPanelItemClass *class)
-{
- PanelItemPersonality result; /* Personnalité à retourner */
-
- result = PIP_SINGLETON;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Fournit une indication d'accroche du panneau au démarrage. *
-* *
-* Retour : true si le panneau doit être affiché de prime abord. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool gtk_panel_item_class_dock_at_startup(const GPanelItemClass *class)
-{
- bool result; /* Statut à retourner */
- GGenConfig *config; /* Configuration courante */
- char *key; /* Clef d'accès à un paramètre */
-#ifndef NDEBUG
- bool status; /* Bilan de consultation */
-#endif
-
- config = get_main_configuration();
-
- key = gtk_panel_item_class_build_configuration_key(class, "dock_at_startup");
-
-#ifndef NDEBUG
- status = g_generic_config_get_value(config, key, &result);
- assert(status);
-#else
- g_generic_config_get_value(config, key, &result);
-#endif
-
- free(key);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe associée à la consultation. *
-* *
-* Description : Renvoie false lors d'une consultation de la classe. *
-* *
-* Retour : false. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool gtk_panel_item_class_return_false(const GPanelItemClass *class)
-{
- bool result; /* Statut à retourner */
-
- result = false;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe associée à la consultation. *
-* *
-* Description : Renvoie true lors d'une consultation de la classe. *
-* *
-* Retour : true. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool gtk_panel_item_class_return_true(const GPanelItemClass *class)
-{
- bool result; /* Statut à retourner */
-
- result = true;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Détermine si un panneau peut être filtré. *
-* *
-* Retour : Bilan de la consultation. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool gtk_panel_item_class_can_search(const GPanelItemClass *class)
-{
- bool result; /* Statut à retourner */
-
- result = class->can_search(class);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Indique le chemin initial de la localisation d'un panneau. *
-* *
-* Retour : Chemin fixé associé à la position initiale. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-char *gtk_panel_item_class_get_path(const GPanelItemClass *class)
-{
- char *result; /* Emplacement à retourner */
- GGenConfig *config; /* Configuration courante */
- char *key; /* Clef d'accès à un paramètre */
- const char *path; /* Nouveau chemin de placement */
-#ifndef NDEBUG
- bool status; /* Statut de l'encapsulation */
-#endif
-
- config = get_main_configuration();
-
- key = gtk_panel_item_class_build_configuration_key(class, "path");
-
-#ifndef NDEBUG
- status = g_generic_config_get_value(config, key, &path);
- assert(status);
-#else
- g_generic_config_get_value(config, key, &path);
-#endif
-
- free(key);
-
- result = strdup(path);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Indique la définition d'un éventuel raccourci clavier. *
-* *
-* Retour : Description d'un raccourci ou NULL si aucun de défini. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-char *gtk_panel_item_class_get_key_bindings(const GPanelItemClass *class)
-{
- char *result; /* Emplacement à retourner */
-
- if (class->get_bindings != NULL)
- result = class->get_bindings(class);
-
- else
- result = NULL;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe du type de panneau à traiter. *
-* attrib = élément de configuration à inclure dans le résultat.*
-* *
-* Description : Construit la chaîne d'accès à un élément de configuration. *
-* *
-* Retour : Chaîne de caractères à libérer après usage. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *gtk_panel_item_class_build_configuration_key(const GPanelItemClass *class, const char *attrib)
-{
- char *result; /* Construction à renvoyer */
- const char *name; /* Nom court du panneau */
-
- name = g_editor_item_class_get_key(G_EDITOR_ITEM_CLASS(class));
-
- asprintf(&result, "gui.panels.%s.%s", attrib, name);
-
- result = strrpl(result, " ", "_");
-
- result = strlower(result);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe de panneau à consulter. *
-* config = configuration à compléter. *
-* *
-* Description : Met en place les bases de la configuration d'un panneau. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool gtk_panel_item_class_setup_configuration(const GPanelItemClass *class, GGenConfig *config)
-{
- bool result; /* Bilan à retourner */
- char *key; /* Clef d'accès à un paramètre */
- bool dock_at_startup; /* Affichage dès le départ ? */
- char *path; /* Localisation du panneau */
-
- key = gtk_panel_item_class_build_configuration_key(class, "dock_at_startup");
-
- dock_at_startup = class->dock_at_startup(class);
-
- result = g_generic_config_create_param_if_not_exist(config, key, CPT_BOOLEAN, dock_at_startup);
-
- free(key);
-
- if (!result)
- goto exit;
-
- key = gtk_panel_item_class_build_configuration_key(class, "path");
-
- path = class->get_path(class);
-
- result = g_generic_config_create_param_if_not_exist(config, key, CPT_STRING, path);
-
- free(path);
-
- free(key);
-
- exit:
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : type = type de panneau à mettre en place. *
-* path = emplacement d'affichage ou NULL. *
-* *
-* Description : Crée un élément de panneau réactif. *
-* *
-* Retour : Adresse de la structure mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GPanelItem *g_panel_item_new(GType type, const char *path)
-{
- GPanelItem *result; /* Structure à retourner */
- GPanelItemClass *class; /* Classe associée au type */
- PanelItemPersonality personality; /* Caractéristique de panneau */
- GtkTiledGrid *grid; /* Composant d'affichage */
-
- class = g_type_class_ref(type);
-
- personality = gtk_panel_item_class_get_personality(class);
- assert(path != NULL || personality == PIP_PERSISTENT_SINGLETON);
-
- g_type_class_unref(class);
-
- if (personality == PIP_PERSISTENT_SINGLETON || personality == PIP_SINGLETON)
- {
- result = G_PANEL_ITEM(find_editor_item_by_type(type));
-
- if (result != NULL)
- goto singleton;
-
- }
-
- result = create_object_from_type(type);
-
- grid = get_tiled_grid();
-
- g_signal_connect_swapped(result, "dock-request", G_CALLBACK(gtk_tiled_grid_add), grid);
- g_signal_connect_swapped(result, "undock-request", G_CALLBACK(gtk_tiled_grid_remove), grid);
-
- gtk_dockable_setup_dnd(GTK_DOCKABLE(result));
-
- register_editor_item(G_EDITOR_ITEM(result));
-
- notify_panel_creation(result);
-
- singleton:
-
- if (path != NULL)
- {
- if (path[0] != '\0')
- gtk_panel_item_set_path(result, path);
-
- g_panel_item_dock(result);
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance de panneau à consulter. *
-* *
-* Description : Indique le composant graphique principal du panneau. *
-* *
-* Retour : Composant graphique avec nom constituant le panneau. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GNamedWidget *gtk_panel_item_get_named_widget(const GPanelItem *item)
-{
- GNamedWidget *result; /* Composant nommé à retourner */
-
- result = item->widget;
-
- g_object_ref(G_OBJECT(result));
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance GTK dont l'interface est à consulter. *
-* *
-* Description : Fournit le nom court du composant encapsulable. *
-* *
-* Retour : Désignation humaine pour titre d'onglet ou de fenêtre. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *gtk_panel_item_get_name(const GPanelItem *item)
-{
- char *result; /* Désignation à retourner */
-
- result = g_named_widget_get_name(G_NAMED_WIDGET(item->widget), false);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance GTK dont l'interface est à consulter. *
-* *
-* Description : Fournit le nom long du composant encapsulable. *
-* *
-* Retour : Désignation humaine pour titre d'onglet ou de fenêtre. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *gtk_panel_item_get_desc(const GPanelItem *item)
-{
- char *result; /* Description à retourner */
-
- result = g_named_widget_get_name(G_NAMED_WIDGET(item->widget), true);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance GTK dont l'interface est à consulter. *
-* *
-* Description : Détermine si un panneau peut être filtré. *
-* *
-* Retour : Bilan de la consultation. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool gtk_panel_item_can_search(const GPanelItem *item)
-{
- bool result; /* Indication à retourner */
- GPanelItemClass *class; /* Classe de l'élément visé */
-
- class = G_PANEL_ITEM_GET_CLASS(item);
-
- result = gtk_panel_item_class_can_search(class);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance GTK dont l'interface est à consulter. *
-* *
-* Description : Fournit le composant graphique intégrable dans un ensemble. *
-* *
-* Retour : Composant graphique prêt à emploi. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GtkWidget *gtk_panel_item_get_widget(GPanelItem *item)
-{
- GtkWidget *result; /* Composant à retourner */
-
- if (item->cached_widget == NULL)
- item->cached_widget = g_named_widget_get_widget(G_NAMED_WIDGET(item->widget));
-
- result = item->cached_widget;
-
- g_object_ref(G_OBJECT(result));
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance GTK dont l'interface est à sollicitée. *
-* *
-* Description : Démarre l'actualisation du filtrage du contenu. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void gtk_panel_item_update_filtered(GPanelItem *item, const char *filter)
-{
- assert(gtk_panel_item_can_search(item));
-
- if (item->filter != NULL)
- free(item->filter);
-
- item->filter = (filter ? strdup(filter) : NULL);
-
- G_PANEL_ITEM_GET_CLASS(item)->update_filtered(item);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = instance GTK à consulter. *
-* path = nouvelle emplacement d'inclusion. *
-* *
-* Description : Définit le chemin d'accès à utiliser pour les encapsulations.*
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void gtk_panel_item_set_path(GPanelItem *item, const char *path)
-{
- GGenConfig *config; /* Configuration courante */
- char *key; /* Clef d'accès à un paramètre */
-
- config = get_main_configuration();
-
- key = gtk_panel_item_class_build_configuration_key(G_PANEL_ITEM_GET_CLASS(item), "path");
-
- g_generic_config_set_value(config, key, path);
-
- free(key);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = composant à présenter à l'affichage. *
-* *
-* Description : Place un panneau dans l'ensemble affiché. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_panel_item_dock(GPanelItem *item)
-{
- assert(!item->docked);
-
- g_signal_emit_by_name(item, "dock-request");
-
- if (G_PANEL_ITEM_GET_CLASS(item)->ack_dock != NULL)
- G_PANEL_ITEM_GET_CLASS(item)->ack_dock(item);
-
- notify_panel_docking(item, true);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = composant d'affichage à mettre à jour. *
-* status = nouvel état d'encapsulation. *
-* *
-* Description : Définit si le composant repose sur un support de l'éditeur. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_panel_item_set_dock_at_startup(GPanelItem *item, bool status)
-{
- char *key; /* Clef d'accès à un paramètre */
-
- item->docked = status;
-
- key = gtk_panel_item_class_build_configuration_key(G_PANEL_ITEM_GET_CLASS(item), "dock_at_startup");
-
- g_generic_config_set_value(get_main_configuration(), key, status);
-
- free(key);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = composant d'affichage à consulter. *
-* *
-* Description : Indique si le composant repose sur un support de l'éditeur. *
-* *
-* Retour : true si le composant est bien incrusté quelque part. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_panel_item_is_docked(const GPanelItem *item)
-{
- bool result; /* Statut à retourner */
-
- result = item->docked;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : item = composant à retirer de l'affichage. *
-* *
-* Description : Supprime un panneau de l'ensemble affiché. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_panel_item_undock(GPanelItem *item)
-{
- PanelItemPersonality personality; /* Caractéristique de panneau */
-
- assert(item->docked);
-
- g_signal_emit_by_name(item, "undock-request");
-
- if (G_PANEL_ITEM_GET_CLASS(item)->ack_undock != NULL)
- G_PANEL_ITEM_GET_CLASS(item)->ack_undock(item);
-
- notify_panel_docking(item, false);
-
- personality = gtk_panel_item_class_get_personality(G_PANEL_ITEM_GET_CLASS(item));
-
- if (personality != PIP_PERSISTENT_SINGLETON)
- unregister_editor_item(G_EDITOR_ITEM(item));
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* MECANISMES DE MISE A JOUR DE PANNEAU */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : item = panneau ciblé par une mise à jour. *
-* *
-* Description : Obtient le groupe de travail dédié à une mise à jour. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-wgroup_id_t g_panel_item_get_group(const GPanelItem *item)
-{
- wgroup_id_t result; /* Identifiant à retourner */
-
- result = G_PANEL_ITEM_GET_CLASS(item)->gid;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : widget = composant graphique sur lequel dessiner. *
-* cr = contexte graphique pour le dessin. *
-* panel = panneau ciblé par une mise à jour. *
-* *
-* Description : Présente une copie de l'affichage du composant rafraîchi. *
-* *
-* Retour : FALSE afin de poursuivre les traitements. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static gboolean g_panel_item_draw_mask(GtkWidget *widget, cairo_t *cr, GPanelItem *item)
-{
- int width; /* Largeur du composant actuel */
- int height; /* Hauteur du composant actuel */
-
- width = gtk_widget_get_allocated_width(widget);
- height = gtk_widget_get_allocated_height(widget);
-
- cairo_save(cr);
-
- cairo_set_source_surface(cr, item->surface, 0, 0);
- cairo_rectangle(cr, 0, 0, width, height);
-
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_fill(cr);
-
- cairo_restore(cr);
-
- return FALSE;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = panneau ciblé par une mise à jour. *
-* *
-* Description : Bascule l'affichage d'un panneau avant sa mise à jour. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_panel_item_switch_to_updating_mask(GPanelItem *item)
-{
- GtkBuilder *builder; /* Constructeur sous-jacent */
- GtkWidget *content; /* Composant à faire évoluer */
- GdkWindow *window; /* Fenêtre au contenu à copier */
- int width; /* Largeur du composant actuel */
- int height; /* Hauteur du composant actuel */
- cairo_t *cr; /* Pinceau pour les dessins */
- GtkAdjustment *adj; /* Défilement éventuel */
- GtkStack *stack; /* Pile de composants GTK */
- GtkWidget *mask; /* Masque des travaux */
-
- if (g_atomic_int_add(&item->switched, 1) > 0)
- return;
-
- /* Copie de l'affichage courant */
-
- assert(item->surface == NULL);
-
- builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(item->widget));
-
- content = GTK_WIDGET(gtk_builder_get_object(builder, "content"));
-
- window = gtk_widget_get_window(content);
-
- if (window != NULL)
- {
- width = gtk_widget_get_allocated_width(content);
- height = gtk_widget_get_allocated_height(content);
-
- item->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
-
- cr = cairo_create(item->surface);
-
- gdk_cairo_set_source_window(cr, window, 0, 0);
-
- cairo_paint(cr);
-
- cairo_destroy(cr);
-
- }
-
- /* Sauvegarde de l'éventuelle position */
-
- if (GTK_IS_SCROLLED_WINDOW(content))
- {
- adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(content));
- item->hadj_value = gtk_adjustment_get_value(adj);
-
- adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(content));
- item->vadj_value = gtk_adjustment_get_value(adj);
-
- }
-
- /* Opération de basculement effectif */
-
- stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
-
- mask = GTK_WIDGET(gtk_builder_get_object(builder, "mask"));
-
- gtk_spinner_start(GTK_SPINNER(mask));
-
- if (item->surface != NULL)
- g_signal_connect(mask, "draw", G_CALLBACK(g_panel_item_draw_mask), item);
-
- gtk_stack_set_visible_child(stack, mask);
-
- g_object_unref(G_OBJECT(builder));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = panneau ciblé par une mise à jour. *
-* *
-* Description : Bascule l'affichage d'un panneau après sa mise à jour. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_panel_item_switch_to_updated_content(GPanelItem *item)
-{
- GtkBuilder *builder; /* Constructeur sous-jacent */
- GtkWidget *content; /* Composant à faire évoluer */
- GtkAdjustment *adj; /* Défilement éventuel */
- GtkStack *stack; /* Pile de composants GTK */
- GtkWidget *mask; /* Masque des travaux */
-
- if (g_atomic_int_get(&item->switched) > 1)
- goto skip;
-
- /* Restauration d'une éventuelle position */
-
- builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(item->widget));
-
- content = GTK_WIDGET(gtk_builder_get_object(builder, "content"));
-
- if (GTK_IS_SCROLLED_WINDOW(content))
- {
- adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(content));
- gtk_adjustment_set_value(adj, item->hadj_value);
-
- adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(content));
- gtk_adjustment_set_value(adj, item->vadj_value);
-
- }
-
- /* Opération de basculement effectif */
-
- stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
-
- gtk_stack_set_visible_child(stack, content);
-
- mask = GTK_WIDGET(gtk_builder_get_object(builder, "mask"));
-
- g_signal_handlers_disconnect_by_func(mask, G_CALLBACK(g_panel_item_draw_mask), item);
-
- gtk_spinner_stop(GTK_SPINNER(mask));
-
- /* Supression de la copie d'affichage */
-
- if (item->surface != NULL)
- {
- cairo_surface_destroy(item->surface);
- item->surface = NULL;
- }
-
- g_object_unref(G_OBJECT(builder));
-
- skip:
-
- g_atomic_int_dec_and_test(&item->switched);
-
-}
-
-
-#endif
diff --git a/src/gui/panel.h b/src/gui/panel.h
deleted file mode 100644
index 03b67d4..0000000
--- a/src/gui/panel.h
+++ /dev/null
@@ -1,148 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * panel.h - prototypes pour la gestion des éléments réactifs spécifiques aux panneaux
- *
- * Copyright (C) 2019-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 this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#ifndef _GUI_PANEL_H
-#define _GUI_PANEL_H
-
-
-#include "../glibext/helpers.h"
-#include "../gtkext/panel.h"
-
-
-#include <gtk/gtk.h>
-
-
-
-#define G_TYPE_PANEL_ITEM (g_panel_item_get_type())
-
-DECLARE_GTYPE(GPanelItem, g_panel_item, G, PANEL_ITEM);
-
-
-/* Types de panneaux pour éditeur */
-typedef enum _PanelItemPersonality
-{
- PIP_NONE, /* Pas de particularité */
-
- PIP_MAIN_PANEL, /* Panneau principal */
- PIP_SINGLETON, /* Instance unique */
-
- PIP_COUNT
-
-} PanelItemPersonality;
-
-
-/* Fournit une indication sur la personnalité du panneau. */
-PanelItemPersonality g_panel_item_get_personality(const GPanelItem *);
-
-/* Fournit un composant pour lancer l'activité d'un panneau. */
-GtkWidget *g_panel_item_get_launcher(GPanelItem *);
-
-/* Fournit un composant pour paramétrer l'activité d'un panneau. */
-GtkWidget *g_panel_item_get_properties(GPanelItem *);
-
-/* Fournit un composant représentant un panneau graphique. */
-GtkTiledPanel *g_panel_item_get_panel(GPanelItem *);
-
-
-
-
-
-
-
-
-
-#if 0
-
-
-#include <stdbool.h>
-#include <gtk/gtk.h>
-
-
-#include "../glibext/configuration.h"
-#include "../glibext/named.h"
-
-
-
-#define G_TYPE_PANEL_ITEM g_panel_item_get_type()
-#define G_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PANEL_ITEM, GPanelItem))
-#define G_IS_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PANEL_ITEM))
-#define G_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PANEL_ITEM, GPanelItemClass))
-#define G_IS_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PANEL_ITEM))
-#define G_PANEL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PANEL_ITEM, GPanelItemClass))
-
-
-/* Elément réactif pour panneaux de l'éditeur (instance) */
-typedef struct _GPanelItem GPanelItem;
-
-/* Elément réactif pour panneaux de l'éditeur (classe) */
-typedef struct _GPanelItemClass GPanelItemClass;
-
-
-
-
-/* Indique le type défini pour un élément destiné à un panneau. */
-GType g_panel_item_get_type(void);
-
-/* Fournit une indication d'accroche du panneau au démarrage. */
-bool gtk_panel_item_class_dock_at_startup(const GPanelItemClass *);
-
-/* Détermine si un panneau peut être filtré. */
-bool gtk_panel_item_class_can_search(const GPanelItemClass *);
-
-/* Indique le chemin initial de la localisation d'un panneau. */
-char *gtk_panel_item_class_get_path(const GPanelItemClass *);
-
-/* Indique la définition d'un éventuel raccourci clavier. */
-char *gtk_panel_item_class_get_key_bindings(const GPanelItemClass *);
-
-/* Met en place les bases de la configuration du panneau. */
-bool gtk_panel_item_class_setup_configuration(const GPanelItemClass *, GGenConfig *);
-
-/* Crée un élément de panneau réactif. */
-GPanelItem *g_panel_item_new(GType, const char *);
-
-/* Indique le composant graphique principal du panneau. */
-GNamedWidget *gtk_panel_item_get_named_widget(const GPanelItem *);
-
-/* Définit le chemin d'accès à utiliser pour les encapsulations. */
-void gtk_panel_item_set_path(GPanelItem *, const char *);
-
-/* Place un panneau dans l'ensemble affiché. */
-void g_panel_item_dock(GPanelItem *);
-
-/* Définit si le composant repose sur un support de l'éditeur. */
-void g_panel_item_set_dock_at_startup(GPanelItem *, bool);
-
-/* Indique si le composant repose sur un support de l'éditeur. */
-bool g_panel_item_is_docked(const GPanelItem *);
-
-/* Supprime un panneau de l'ensemble affiché. */
-void g_panel_item_undock(GPanelItem *);
-
-
-#endif
-
-
-
-#endif /* _GUI_PANEL_H */
diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am
index 476a436..ecff6c7 100644
--- a/src/gui/panels/Makefile.am
+++ b/src/gui/panels/Makefile.am
@@ -11,7 +11,6 @@ UI_FILES = \
errors.ui \
glance.ui \
history.ui \
- log.ui \
regedit.ui \
strings.ui \
symbols.ui
@@ -22,7 +21,6 @@ libguipanels_la_SOURCES = \
errors.h errors.c \
glance.h glance.c \
history.h history.c \
- log.h log.c \
regedit.h regedit.c \
resources.h resources.c \
strings.h strings.c \
@@ -38,9 +36,11 @@ IMG_PATH = ../../../data/images
RES_FILES = \
binary.ui \
- binary-launch.ui \
- binary-props.ui \
+ binary-params.ui \
$(IMG_PATH)/binfile-symbolic.svg \
+ logs.ui \
+ logs-col-icon.ui \
+ logs-col-message.ui \
welcome.ui \
welcome-hints.txt \
$(IMG_PATH)/tipoftheday-symbolic.svg
@@ -48,6 +48,10 @@ RES_FILES = \
libguipanels4_la_SOURCES = \
binary-int.h \
binary.h binary.c \
+ binary-params-int.h \
+ binary-params.h binary-params.c \
+ logs-int.h \
+ logs.h logs.c \
resources.h resources.c \
welcome-int.h \
welcome.h welcome.c
diff --git a/src/gui/panels/binary-int.h b/src/gui/panels/binary-int.h
index f68da9b..5116f5c 100644
--- a/src/gui/panels/binary-int.h
+++ b/src/gui/panels/binary-int.h
@@ -27,14 +27,10 @@
#include "binary.h"
-#include "../panel-int.h"
#include "../../gtkext/panel-int.h"
-/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */
-
-
/* Panneau d'accueil par défaut (instance) */
struct _GtkBinaryPanel
{
@@ -53,23 +49,4 @@ struct _GtkBinaryPanelClass
-/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */
-
-
-/* Définition pour gestion par le framework d'un panneau graphique (instance) */
-struct _GBinaryPanel
-{
- GPanelItem parent; /* A laisser en premier */
-
-};
-
-/* Définition pour gestion par le framework d'un panneau graphique (classe) */
-struct _GBinaryPanelClass
-{
- GPanelItemClass parent; /* A laisser en premier */
-
-};
-
-
-
#endif /* _GUI_PANELS_BINARY_INT_H */
diff --git a/src/gui/panels/binary-launch.ui b/src/gui/panels/binary-launch.ui
deleted file mode 100644
index 553f758..0000000
--- a/src/gui/panels/binary-launch.ui
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<interface>
-
- <object class="GtkGrid" id="launcher">
- <property name="margin-bottom">12</property>
- <property name="margin-end">12</property>
- <property name="margin-start">12</property>
- <property name="margin-top">12</property>
- <property name="column-spacing">12</property>
- <child>
- <object class="GtkImage">
- <property name="icon-name">binfile-symbolic</property>
- <property name="pixel-size">48</property>
- <layout>
- <property name="column">0</property>
- <property name="row">0</property>
- <property name="row-span">2</property>
- </layout>
- <style>
- <class name="icon-dropshadow"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="label">&lt;b&gt;Binary analysis&lt;/b&gt;</property>
- <property name="use-markup">TRUE</property>
- <property name="xalign">0</property>
- <layout>
- <property name="column">1</property>
- <property name="row">0</property>
- </layout>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="label">Load a binary content and parse its format if recognized</property>
- <property name="hexpand">true</property>
- <property name="xalign">0</property>
- <layout>
- <property name="column">1</property>
- <property name="row">1</property>
- </layout>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkImage">
- <property name="icon-name">go-next-symbolic</property>
- <property name="margin-start">12</property>
- <layout>
- <property name="column">2</property>
- <property name="row">0</property>
- <property name="row-span">2</property>
- </layout>
- <style>
- <class name="icon-dropshadow"/>
- </style>
- </object>
- </child>
- </object>
-
-</interface>
diff --git a/src/gui/panels/binary-params-int.h b/src/gui/panels/binary-params-int.h
new file mode 100644
index 0000000..0fbef24
--- /dev/null
+++ b/src/gui/panels/binary-params-int.h
@@ -0,0 +1,50 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * binary-params-int.h - définitions internes pour l'édition des paramètres initiaux d'un chargement de binaire
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_PANELS_BINARY_PARAMS_INT_H
+#define _GUI_PANELS_BINARY_PARAMS_INT_H
+
+
+#include "binary-params.h"
+
+
+
+/* Composant pour les paramètres de chargement d'un binaire (instance) */
+struct _GtkBinaryParameters
+{
+ GtkGrid parent; /* A laisser en premier */
+
+ GtkEntry *filename; /* CHemin d'un binaire */
+
+};
+
+/* Composant pour les paramètres de chargement d'un binaire (classe) */
+struct _GtkBinaryParametersClass
+{
+ GtkGridClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _GUI_PANELS_BINARY_PARAMS_INT_H */
diff --git a/src/gui/panels/binary-params.c b/src/gui/panels/binary-params.c
new file mode 100644
index 0000000..1059761
--- /dev/null
+++ b/src/gui/panels/binary-params.c
@@ -0,0 +1,178 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * binary-params.c - édition des paramètres initiaux d'un chargement de binaire
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "binary-params.h"
+
+
+#include "binary.h"
+#include "binary-params-int.h"
+#include "../window.h"
+#include "../../analysis/contents/file.h"
+#include "../../gtkext/helpers.h"
+
+
+
+/* Initialise la classe des composants d'édition de paramètres. */
+static void gtk_binary_parameters_class_init(GtkBinaryParametersClass *);
+
+/* Initialise une instance de composant d'édition de paramètres. */
+static void gtk_binary_parameters_init(GtkBinaryParameters *);
+
+/* Supprime toutes les références externes. */
+static void gtk_binary_parameters_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_binary_parameters_finalize(GObject *);
+
+/* Ouvre une boîte de dialogue pour récupérer un fichier. */
+static void gtk_binary_parameters_on_new_file_entry_icon_release(GtkEntry *, GtkEntryIconPosition, GtkBinaryParameters *);
+
+
+
+/* Détermine le type du composant d'édition des paramètres de chargement. */
+G_DEFINE_TYPE(GtkBinaryParameters, gtk_binary_parameters, GTK_TYPE_GRID);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Initialise la classe des composants d'édition de paramètres. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_binary_parameters_class_init(GtkBinaryParametersClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_binary_parameters_dispose;
+ object->finalize = gtk_binary_parameters_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/binary-params.ui");
+
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_binary_parameters_on_new_file_entry_icon_release));
+
+ gtk_widget_class_bind_template_child(widget, GtkBinaryParameters, filename);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : params = composant GTK à initialiser. *
+* *
+* Description : Initialise une instance de composant d'édition de paramètres.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_binary_parameters_init(GtkBinaryParameters *params)
+{
+ gtk_widget_init_template(GTK_WIDGET(params));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_binary_parameters_dispose(GObject *object)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_BINARY_PARAMETERS);
+
+ G_OBJECT_CLASS(gtk_binary_parameters_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_binary_parameters_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_binary_parameters_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : entry = zone de saisie concernée par l'appel. *
+* icon_pos = position de l'icone incrustée dans la zone. *
+* params = composant d'édition des paramètres. *
+* *
+* Description : Ouvre une boîte de dialogue pour récupérer un fichier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_binary_parameters_on_new_file_entry_icon_release(GtkEntry *entry, GtkEntryIconPosition icon_pos, GtkBinaryParameters *params)
+{
+ GtkRoot *root; /* Racine du composant */
+ GBinContent *content; /* Contenu binaire à afficher */
+ GtkTiledPanel *tiled; /* Panneau d'affichage complet */
+
+ root = gtk_widget_get_root(GTK_WIDGET(entry));
+
+ content = g_file_content_new("/bin/id");
+
+ tiled = gtk_binary_panel_new_for_content(content);
+
+ unref_object(content);
+
+ gtk_framework_window_add(GTK_FRAMEWORK_WINDOW(root), tiled);
+
+}
diff --git a/src/gui/panels/binary-params.h b/src/gui/panels/binary-params.h
new file mode 100644
index 0000000..450da25
--- /dev/null
+++ b/src/gui/panels/binary-params.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * binary-params.h - prototypes pour l'édition des paramètres initiaux d'un chargement de binaire
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_PANELS_BINARY_PARAMS_H
+#define _GUI_PANELS_BINARY_PARAMS_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../../glibext/helpers.h"
+
+
+
+#define GTK_TYPE_BINARY_PARAMETERS (gtk_binary_parameters_get_type())
+
+DECLARE_GTYPE(GtkBinaryParameters, gtk_binary_parameters, GTK, BINARY_PARAMETERS);
+
+
+
+#endif /* _GUI_PANELS_BINARY_PARAMS_H */
diff --git a/src/gui/panels/binary-props.ui b/src/gui/panels/binary-params.ui
index bd48ea8..dcbaf7c 100644
--- a/src/gui/panels/binary-props.ui
+++ b/src/gui/panels/binary-params.ui
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <object class="GtkGrid" id="properties">
+ <template class="GtkBinaryParameters" parent="GtkGrid">
<property name="margin-bottom">12</property>
<property name="margin-end">12</property>
<property name="margin-start">12</property>
<property name="margin-top">12</property>
<property name="column-spacing">12</property>
<property name="row-spacing">8</property>
+
<child>
<object class="GtkLabel">
<property name="label">Load and analyze a new file:</property>
@@ -18,8 +19,9 @@
</layout>
</object>
</child>
+
<child>
- <object class="GtkEntry" id="new_file">
+ <object class="GtkEntry" id="filename">
<property name="secondary-icon-name">document-open-symbolic</property>
<property name="placeholder-text">File location</property>
<property name="hexpand">TRUE</property>
@@ -31,9 +33,10 @@
<style>
<class name="background"/>
</style>
- <signal name="icon-release" handler="g_binary_panel_on_new_file_entry_icon_release"/>
+ <signal name="icon-release" handler="gtk_binary_parameters_on_new_file_entry_icon_release"/>
</object>
</child>
- </object>
+
+ </template>
</interface>
diff --git a/src/gui/panels/binary.c b/src/gui/panels/binary.c
index de0a4d0..f58c06b 100644
--- a/src/gui/panels/binary.c
+++ b/src/gui/panels/binary.c
@@ -26,8 +26,6 @@
#include "binary-int.h"
-#include "../window.h"
-#include "../../analysis/contents/file.h"
#include "../../gtkext/helpers.h"
#include "../../gtkext/hexview.h"
@@ -43,10 +41,10 @@ static void gtk_binary_panel_class_init(GtkBinaryPanelClass *);
static void gtk_binary_panel_init(GtkBinaryPanel *);
/* Supprime toutes les références externes. */
-static void gtk_binary_panel_dispose(GtkBinaryPanel *);
+static void gtk_binary_panel_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_binary_panel_finalize(GtkBinaryPanel *);
+static void gtk_binary_panel_finalize(GObject *);
@@ -57,49 +55,12 @@ static void gtk_binary_panel_finalize(GtkBinaryPanel *);
-/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */
-
-
-/* Initialise la classe des panneaux graphiques pour binaires. */
-static void g_binary_panel_class_init(GBinaryPanelClass *);
-
-/* Initialise une instance de panneau graphique pour binaire. */
-static void g_binary_panel_init(GBinaryPanel *);
-
-/* Supprime toutes les références externes. */
-static void g_binary_panel_dispose(GBinaryPanel *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_binary_panel_finalize(GBinaryPanel *);
-
-
-
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-
-
-/* Fournit une indication sur la personnalité du panneau. */
-static PanelItemPersonality g_binary_panel_get_personality(const GBinaryPanel *);
-
-/* Fournit un composant pour lancer l'activité d'un panneau. */
-static GtkWidget *g_binary_panel_get_launcher(GBinaryPanel *);
-
-/* Fournit un composant pour paramétrer l'activité d'un panneau. */
-static GtkWidget *g_binary_panel_get_properties(GBinaryPanel *);
-
-/* Ouvre une boîte de dialogue pour récupérer un fichier. */
-static void g_binary_panel_on_new_file_entry_icon_release(GtkEntry *, GtkEntryIconPosition, GBinaryPanel *);
-
-/* Fournit un composant représentant un panneau graphique. */
-static GtkTiledPanel *g_binary_panel_get_panel(GBinaryPanel *, GtkWidget *);
-
-
-
/* ---------------------------------------------------------------------------------- */
/* COEUR D'UN PANNEAU D'AFFICHAGE */
/* ---------------------------------------------------------------------------------- */
-/* Indique le type défini pour un panneau d'accueil. */
+/* Indique le type défini pour un panneau d'affichage de contenus d'un binaire. */
G_DEFINE_TYPE(GtkBinaryPanel, gtk_binary_panel, GTK_TYPE_TILED_PANEL);
@@ -122,8 +83,8 @@ static void gtk_binary_panel_class_init(GtkBinaryPanelClass *class)
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_binary_panel_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_binary_panel_finalize;
+ object->dispose = gtk_binary_panel_dispose;
+ object->finalize = gtk_binary_panel_finalize;
widget = GTK_WIDGET_CLASS(class);
@@ -155,7 +116,7 @@ static void gtk_binary_panel_init(GtkBinaryPanel *panel)
/******************************************************************************
* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -165,18 +126,18 @@ static void gtk_binary_panel_init(GtkBinaryPanel *panel)
* *
******************************************************************************/
-static void gtk_binary_panel_dispose(GtkBinaryPanel *panel)
+static void gtk_binary_panel_dispose(GObject *object)
{
- gtk_widget_dispose_template(GTK_WIDGET(panel), GTK_TYPE_BINARY_PANEL);
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_BINARY_PANEL);
- G_OBJECT_CLASS(gtk_binary_panel_parent_class)->dispose(G_OBJECT(panel));
+ G_OBJECT_CLASS(gtk_binary_panel_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -186,9 +147,9 @@ static void gtk_binary_panel_dispose(GtkBinaryPanel *panel)
* *
******************************************************************************/
-static void gtk_binary_panel_finalize(GtkBinaryPanel *panel)
+static void gtk_binary_panel_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_binary_panel_parent_class)->finalize(G_OBJECT(panel));
+ G_OBJECT_CLASS(gtk_binary_panel_parent_class)->finalize(object);
}
@@ -232,286 +193,3 @@ GtkTiledPanel *gtk_binary_panel_new_for_content(GBinContent *content)
-
-/* ---------------------------------------------------------------------------------- */
-/* MANIPULATIONS D'UN PANNEAU GRAPHIQUE */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour une manipulation de panneau pour binaires. */
-G_DEFINE_TYPE(GBinaryPanel, g_binary_panel, G_TYPE_PANEL_ITEM);
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à initialiser. *
-* *
-* Description : Initialise la classe des panneaux graphiques pour binaires. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_binary_panel_class_init(GBinaryPanelClass *class)
-{
- GObjectClass *object; /* Autre version de la classe */
- GPanelItemClass *panel; /* Encore une autre vision... */
-
- object = G_OBJECT_CLASS(class);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_panel_dispose;
- object->finalize = (GObjectFinalizeFunc)g_binary_panel_finalize;
-
- panel = G_PANEL_ITEM_CLASS(class);
-
- panel->get_personality = (get_panel_item_personality_cb)g_binary_panel_get_personality;
- panel->get_launcher = (get_panel_item_widget_cb)g_binary_panel_get_launcher;
- panel->get_properties = (get_panel_item_widget_cb)g_binary_panel_get_properties;
- panel->get_panel = (get_panel_item_panel_cb)g_binary_panel_get_panel;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance à initialiser. *
-* *
-* Description : Initialise une instance de panneau graphique pour binaire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_binary_panel_init(GBinaryPanel *panel)
-{
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_binary_panel_dispose(GBinaryPanel *panel)
-{
- G_OBJECT_CLASS(g_binary_panel_parent_class)->dispose(G_OBJECT(panel));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_binary_panel_finalize(GBinaryPanel *panel)
-{
- G_OBJECT_CLASS(g_binary_panel_parent_class)->finalize(G_OBJECT(panel));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Constitue une définition de manipulation de panneau. *
-* *
-* Retour : Définition de propriétés mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GPanelItem *g_binary_panel_new(void)
-{
- GPanelItem *result; /* Structure à retourner */
-
- result = g_object_new(G_TYPE_BINARY_PANEL, NULL);
-
- return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = définition de panneau à consulter. *
-* *
-* Description : Fournit une indication sur la personnalité du panneau. *
-* *
-* Retour : Identifiant lié à la nature du panneau. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PanelItemPersonality g_binary_panel_get_personality(const GBinaryPanel *panel)
-{
- PanelItemPersonality result; /* Personnalité à retourner */
-
- result = PIP_MAIN_PANEL;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = définition de panneau à manipuler. *
-* *
-* Description : Fournit un composant pour lancer l'activité d'un panneau. *
-* *
-* Retour : Composant GTK (déjà ?) mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GtkWidget *g_binary_panel_get_launcher(GBinaryPanel *panel)
-{
- GtkWidget *result; /* Composant à retourner */
- GtkBuilder *builder; /* Constructeur d'UI */
-
- builder = gtk_builder_new_from_resource("/re/chrysalide/framework/gui/panels/binary-launch.ui");
-
- result = GTK_WIDGET(gtk_builder_get_object(builder, "launcher"));
- ref_object(result);
-
- unref_object(builder);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = définition de panneau à manipuler. *
-* *
-* Description : Fournit un composant pour paramétrer l'activité d'un panneau.*
-* *
-* Retour : Composant GTK (déjà ?) mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GtkWidget *g_binary_panel_get_properties(GBinaryPanel *panel)
-{
- GtkWidget *result; /* Composant à retourner */
- GtkBuilderScope *scope; /* Fonctions pour signaux */
- GtkBuilderCScope *cscope; /* Fonctions pour signaux */
- GtkBuilder *builder; /* Constructeur d'UI */
-#ifndef NDEBUG
- gboolean status; /* Bilan d'un chargement */
-#endif
-
- scope = gtk_builder_cscope_new();
- cscope = GTK_BUILDER_CSCOPE(scope);
-
- gtk_builder_cscope_add_callback_symbol(cscope, BUILDER_CB(g_binary_panel_on_new_file_entry_icon_release));
-
- builder = gtk_builder_new();
- gtk_builder_set_scope(builder, scope);
- gtk_builder_set_current_object(builder, G_OBJECT(panel));
-
-#ifndef NDEBUG
- status = gtk_builder_add_from_resource(builder, "/re/chrysalide/framework/gui/panels/binary-props.ui", NULL);
- assert(status);
-#else
- gtk_builder_add_from_resource(builder, "/re/chrysalide/framework/gui/panels/binary-props.ui", NULL);
-#endif
-
- result = GTK_WIDGET(gtk_builder_get_object(builder, "properties"));
- ref_object(result);
-
- unref_object(builder);
- unref_object(scope);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : entry = zone de saisie concernée par l'appel. *
-* icon_pos = position de l'icone incrustée dans la zone. *
-* panel = définition de panneau à manipuler. *
-* *
-* Description : Ouvre une boîte de dialogue pour récupérer un fichier. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_binary_panel_on_new_file_entry_icon_release(GtkEntry *entry, GtkEntryIconPosition icon_pos, GBinaryPanel *panel)
-{
- GtkRoot *root; /* Racine du composant */
- GtkTiledPanel *tiled; /* Panneau d'affichage complet */
-
- root = gtk_widget_get_root(GTK_WIDGET(entry));
-
- tiled = g_binary_panel_get_panel(panel, NULL);
-
- gtk_framework_window_add(GTK_FRAMEWORK_WINDOW(root), tiled);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = définition de panneau à manipuler. *
-* props = éventuels éléments graphiques de paramétrages. *
-* *
-* Description : Fournit un composant représentant un panneau graphique. *
-* *
-* Retour : Composant GTK (déjà ?) mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GtkTiledPanel *g_binary_panel_get_panel(GBinaryPanel *panel, GtkWidget *props)
-{
- GtkTiledPanel *result; /* Composant à retourner */
- GBinContent *content; /* Contenu binaire à afficher */
-
- content = g_file_content_new("/bin/id");
-
- result = gtk_binary_panel_new_for_content(content);
-
- unref_object(content);
-
- return result;
-
-}
diff --git a/src/gui/panels/binary.h b/src/gui/panels/binary.h
index e92895b..26f8a7d 100644
--- a/src/gui/panels/binary.h
+++ b/src/gui/panels/binary.h
@@ -29,16 +29,12 @@
#include <gtk/gtk.h>
-#include "../panel.h"
#include "../../analysis/content.h"
#include "../../glibext/helpers.h"
#include "../../gtkext/panel.h"
-/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */
-
-
#define GTK_TYPE_BINARY_PANEL (gtk_binary_panel_get_type())
DECLARE_GTYPE(GtkBinaryPanel, gtk_binary_panel, GTK, BINARY_PANEL);
@@ -49,17 +45,4 @@ GtkTiledPanel *gtk_binary_panel_new_for_content(GBinContent *);
-/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */
-
-
-#define G_TYPE_BINARY_PANEL (g_binary_panel_get_type())
-
-DECLARE_GTYPE(GBinaryPanel, g_binary_panel, G, BINARY_PANEL);
-
-
-/* Constitue une définition de manipulation de panneau. */
-GPanelItem *g_binary_panel_new(void);
-
-
-
#endif /* _GUI_PANELS_BINARY_H */
diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml
index d00953d..2765b25 100644
--- a/src/gui/panels/gresource.xml
+++ b/src/gui/panels/gresource.xml
@@ -2,8 +2,10 @@
<gresources>
<gresource prefix="/re/chrysalide/framework/gui/panels">
<file compressed="true">binary.ui</file>
- <file compressed="true">binary-launch.ui</file>
- <file compressed="true">binary-props.ui</file>
+ <file compressed="true">binary-params.ui</file>
+ <file compressed="true">logs.ui</file>
+ <file compressed="true">logs-col-icon.ui</file>
+ <file compressed="true">logs-col-message.ui</file>
<file compressed="true">welcome.ui</file>
<file compressed="true">welcome-hints.txt</file>
</gresource>
diff --git a/src/gui/panels/log.c b/src/gui/panels/log.c
deleted file mode 100644
index d11fbd2..0000000
--- a/src/gui/panels/log.c
+++ /dev/null
@@ -1,451 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * log.c - panneau d'affichage des messages système
- *
- * Copyright (C) 2012-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 "log.h"
-
-
-#include <malloc.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <gtk/gtk.h>
-
-
-#include "../panel-int.h"
-#include "../core/panels.h"
-#include "../../gtkext/easygtk.h"
-#include "../../gtkext/named.h"
-
-
-
-/* Colonnes de la liste des messages */
-typedef enum _LogColumn
-{
- LGC_PICTURE, /* Image de représentation */
- LGC_STRING, /* Chaîne de caractères */
-
- LGC_COUNT /* Nombre de colonnes */
-
-} LogColumn;
-
-
-/* Paramètres à transmettre pour un affichage */
-typedef struct _log_data
-{
- GPanelItem *item; /* Intermédiaire mis en place */
- LogMessageType type; /* Type de message à afficher */
- char *msg; /* Contenu du message */
-
-} log_data;
-
-
-/* Panneau d'accueil (instance) */
-struct _GLogPanel
-{
- GPanelItem parent; /* A laisser en premier */
-
-};
-
-
-/* Panneau d'accueil (classe) */
-struct _GLogPanelClass
-{
- GPanelItemClass parent; /* A laisser en premier */
-
-};
-
-
-/* Initialise la classe des panneaux d'affichage des messages. */
-static void g_log_panel_class_init(GLogPanelClass *);
-
-/* Initialise une instance de panneau d'affichage des messages. */
-static void g_log_panel_init(GLogPanel *);
-
-/* Supprime toutes les références externes. */
-static void g_log_panel_dispose(GLogPanel *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_log_panel_finalize(GLogPanel *);
-
-/* Fournit le nom interne attribué à l'élément réactif. */
-static char *g_log_panel_class_get_key(const GLogPanelClass *);
-
-/* Fournit une indication sur la personnalité du panneau. */
-static PanelItemPersonality g_log_panel_class_get_personality(const GLogPanelClass *);
-
-/* Indique le chemin initial de la localisation d'un panneau. */
-static char *g_log_panel_class_get_path(const GLogPanelClass *);
-
-/* Indique la définition d'un éventuel raccourci clavier. */
-static char *g_log_panel_class_get_key_bindings(const GLogPanelClass *);
-
-/* Affiche un message dans le journal des messages système. */
-static gboolean log_message(log_data *);
-
-
-
-/* Indique le type défini pour un panneau d'affichage de messages. */
-G_DEFINE_TYPE(GLogPanel, g_log_panel, G_TYPE_PANEL_ITEM);
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à initialiser. *
-* *
-* Description : Initialise la classe des panneaux d'affichage des messages. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_log_panel_class_init(GLogPanelClass *class)
-{
- GObjectClass *object; /* Autre version de la classe */
- GEditorItemClass *item; /* Encore une autre vision... */
- GPanelItemClass *panel; /* Version parente de la classe*/
-
- object = G_OBJECT_CLASS(class);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_log_panel_dispose;
- object->finalize = (GObjectFinalizeFunc)g_log_panel_finalize;
-
- item = G_EDITOR_ITEM_CLASS(class);
-
- item->get_key = (get_item_key_fc)g_log_panel_class_get_key;
-
- panel = G_PANEL_ITEM_CLASS(class);
-
- panel->get_personality = (get_panel_personality_fc)g_log_panel_class_get_personality;
- panel->get_path = (get_panel_path_fc)g_log_panel_class_get_path;
- panel->get_bindings = (get_panel_bindings_fc)g_log_panel_class_get_key_bindings;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance à initialiser. *
-* *
-* Description : Initialise une instance de panneau d'affichage des messages. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_log_panel_init(GLogPanel *panel)
-{
- GPanelItem *pitem; /* Version parente du panneau */
-
- /* Eléments de base */
-
- pitem = G_PANEL_ITEM(panel);
-
- pitem->widget = G_NAMED_WIDGET(gtk_built_named_widget_new_for_panel(_("Messages"),
- _("Misc information"),
- PANEL_LOG_ID));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_log_panel_dispose(GLogPanel *panel)
-{
- G_OBJECT_CLASS(g_log_panel_parent_class)->dispose(G_OBJECT(panel));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_log_panel_finalize(GLogPanel *panel)
-{
- G_OBJECT_CLASS(g_log_panel_parent_class)->finalize(G_OBJECT(panel));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Fournit le nom interne attribué à l'élément réactif. *
-* *
-* Retour : Désignation (courte) de l'élément de l'éditeur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *g_log_panel_class_get_key(const GLogPanelClass *class)
-{
- char *result; /* Description à renvoyer */
-
- result = strdup(PANEL_LOG_ID);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Fournit une indication sur la personnalité du panneau. *
-* *
-* Retour : Identifiant lié à la nature unique du panneau. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PanelItemPersonality g_log_panel_class_get_personality(const GLogPanelClass *class)
-{
- PanelItemPersonality result; /* Personnalité à retourner */
-
- result = PIP_PERSISTENT_SINGLETON;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Indique le chemin initial de la localisation d'un panneau. *
-* *
-* Retour : Chemin fixé associé à la position initiale. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *g_log_panel_class_get_path(const GLogPanelClass *class)
-{
- char *result; /* Emplacement à retourner */
-
- result = strdup("Ms");
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à consulter. *
-* *
-* Description : Indique la définition d'un éventuel raccourci clavier. *
-* *
-* Retour : Description d'un raccourci ou NULL si aucun de défini. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static char *g_log_panel_class_get_key_bindings(const GLogPanelClass *class)
-{
- char *result; /* Emplacement à retourner */
-
- result = strdup("<Shift>F1");
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Crée un panneau d'affichage des messages système. *
-* *
-* Retour : Adresse de la structure mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GPanelItem *g_log_panel_new(void)
-{
- GPanelItem *result; /* Structure à retourner */
-
- result = g_object_new(G_TYPE_LOG_PANEL, NULL);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* type = espèce du message à ajouter. *
-* msg = message à faire apparaître à l'écran. *
-* *
-* Description : Affiche un message dans le journal des messages système. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_log_panel_add_message(GLogPanel *panel, LogMessageType type, const char *msg)
-{
- log_data *data; /* Paramètres à joindre */
-
- data = calloc(1, sizeof(log_data));
-
- data->item = G_PANEL_ITEM(panel);
- data->type = type;
- data->msg = strdup(msg);
-
- g_object_ref(G_OBJECT(data->item));
-
- g_main_context_invoke(NULL, (GSourceFunc)log_message, data);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : data = paramètres destinés à l'affichage d'un message. *
-* *
-* Description : Affiche un message dans le journal des messages système. *
-* *
-* Retour : - *
-* *
-* Remarques : Cette fonction, et c'est tout son intérêt, est toujours *
-* exécutée dans le contexte GTK principal. *
-* *
-******************************************************************************/
-
-static gboolean log_message(log_data *data)
-{
- GtkBuilder *builder; /* Constructeur utilisé */
- GtkListStore *store; /* Modèle de gestion */
- GtkTreeIter iter; /* Point d'insertion */
- GtkTreeView *treeview; /* Affichage de la liste */
-
- builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(data->item)->widget));
-
- /* Mise en place du message */
-
- store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store"));
-
- gtk_list_store_append(store, &iter);
-
- switch (data->type)
- {
- case LMT_INFO:
- gtk_list_store_set(store, &iter,
- LGC_PICTURE, "gtk-info",
- LGC_STRING, data->msg,
- -1);
- break;
-
- case LMT_PROCESS:
- gtk_list_store_set(store, &iter,
- LGC_PICTURE, "gtk-execute",
- LGC_STRING, data->msg,
- -1);
- break;
-
- case LMT_WARNING:
- gtk_list_store_set(store, &iter,
- LGC_PICTURE, "gtk-dialog-warning",
- LGC_STRING, data->msg,
- -1);
- break;
-
- case LMT_BAD_BINARY:
- gtk_list_store_set(store, &iter,
- LGC_PICTURE, "gtk-dialog-warning",
- LGC_STRING, data->msg,
- -1);
- break;
-
- case LMT_ERROR:
- case LMT_EXT_ERROR:
- gtk_list_store_set(store, &iter,
- LGC_PICTURE, "gtk-dialog-error",
- LGC_STRING, data->msg,
- -1);
- break;
-
- default:
- gtk_list_store_set(store, &iter,
- LGC_STRING, data->msg,
- -1);
- break;
-
- }
-
- /* Défilement pour pointer à l'affichage */
-
- treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview"));
-
- scroll_to_treeview_iter(treeview, GTK_TREE_MODEL(store), &iter);
-
- g_object_unref(G_OBJECT(builder));
-
- /* Nettoyage de la mémoire */
-
- g_object_unref(G_OBJECT(data->item));
-
- free(data->msg);
-
- free(data);
-
- return G_SOURCE_REMOVE;
-
-}
diff --git a/src/gui/panels/log.h b/src/gui/panels/log.h
deleted file mode 100644
index 4d155a2..0000000
--- a/src/gui/panels/log.h
+++ /dev/null
@@ -1,67 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * log.h - prototypes pour le panneau d'affichage des messages système
- *
- * Copyright (C) 2012-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 _GUI_PANELS_LOG_H
-#define _GUI_PANELS_LOG_H
-
-
-#include <i18n.h>
-
-
-#include "../panel.h"
-#include "../../core/logs.h"
-
-
-
-#define PANEL_LOG_ID "log"
-
-
-#define G_TYPE_LOG_PANEL g_log_panel_get_type()
-#define G_LOG_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_log_panel_get_type(), GLogPanel))
-#define G_IS_LOG_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_log_panel_get_type()))
-#define G_LOG_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LOG_PANEL, GLogPanelClass))
-#define G_IS_LOG_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LOG_PANEL))
-#define G_LOG_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LOG_PANEL, GLogPanelClass))
-
-
-/* Panneau d'affichage de messages (instance) */
-typedef struct _GLogPanel GLogPanel;
-
-/* Panneau d'affichage de messages (classe) */
-typedef struct _GLogPanelClass GLogPanelClass;
-
-
-
-/* Indique le type défini pour un panneau d'affichage de messages. */
-GType g_log_panel_get_type(void);
-
-/* Crée un panneau d'affichage des messages système. */
-GPanelItem *g_log_panel_new(void);
-
-/* Affiche un message dans le journal des messages système. */
-void g_log_panel_add_message(GLogPanel *, LogMessageType, const char *);
-
-
-
-#endif /* _GUI_PANELS_LOG_H */
diff --git a/src/gui/panels/log.ui b/src/gui/panels/log.ui
deleted file mode 100644
index 4ffe96c..0000000
--- a/src/gui/panels/log.ui
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.21.0 -->
-<interface>
- <requires lib="gtk+" version="3.20"/>
- <object class="GtkListStore" id="store">
- <columns>
- <!-- column-name picture -->
- <column type="gchararray"/>
- <!-- column-name string -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkOffscreenWindow">
- <property name="can_focus">False</property>
- <child>
- <object class="GtkScrolledWindow" id="box">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="treeview">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="model">store</property>
- <property name="headers_visible">False</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection"/>
- </child>
- <child>
- <object class="GtkTreeViewColumn">
- <property name="title" translatable="yes">picture</property>
- <child>
- <object class="GtkCellRendererPixbuf"/>
- <attributes>
- <attribute name="stock-id">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn">
- <property name="title" translatable="yes">string</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="markup">1</attribute>
- </attributes>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child type="titlebar">
- <placeholder/>
- </child>
- </object>
-</interface>
diff --git a/src/gui/panels/logs-col-icon.ui b/src/gui/panels/logs-col-icon.ui
new file mode 100644
index 0000000..6463e84
--- /dev/null
+++ b/src/gui/panels/logs-col-icon.ui
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <template class="GtkListItem">
+ <property name="child">
+ <object class="GtkImage">
+ <binding name="icon-name">
+ <lookup name="icon-name" type="GLogEntry">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </property>
+
+ </template>
+
+</interface>
diff --git a/src/gui/panels/logs-col-message.ui b/src/gui/panels/logs-col-message.ui
new file mode 100644
index 0000000..49839e4
--- /dev/null
+++ b/src/gui/panels/logs-col-message.ui
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <template class="GtkListItem">
+ <property name="child">
+ <object class="GtkLabel">
+ <property name="xalign">0</property>
+ <property name="use-markup">true</property>
+ <binding name="label">
+ <lookup name="message" type="GLogEntry">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </property>
+
+ </template>
+
+</interface>
diff --git a/src/gui/panels/logs-int.h b/src/gui/panels/logs-int.h
new file mode 100644
index 0000000..692c1b4
--- /dev/null
+++ b/src/gui/panels/logs-int.h
@@ -0,0 +1,53 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * logs-int.h - prototypes internes pour le panneau d'affichage des messages système
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_PANELS_LOGS_INT_H
+#define _GUI_PANELS_LOGS_INT_H
+
+
+#include "logs.h"
+#include "../../gtkext/panel-int.h"
+
+
+
+/* Panneau d'affichage de messages (instance) */
+struct _GtkLogsPanel
+{
+ GtkTiledPanel parent; /* A laisser en premier */
+
+ GListStore *store; /* Liste des eléments conservés*/
+ GtkWidget *list; /* Composant d'affichage */
+
+};
+
+/* Panneau d'affichage de messages (classe) */
+struct _GtkLogsPanelClass
+{
+ GtkTiledPanelClass parent; /* A laisser en premier */
+
+};
+
+
+
+#endif /* _GUI_PANELS_LOGS_INT_H */
diff --git a/src/gui/panels/logs.c b/src/gui/panels/logs.c
new file mode 100644
index 0000000..399c4c0
--- /dev/null
+++ b/src/gui/panels/logs.c
@@ -0,0 +1,227 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * logs.c - panneau d'affichage des messages système
+ *
+ * Copyright (C) 2012-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "logs.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include "logs-int.h"
+#include "../../gtkext/helpers.h"
+
+
+
+/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */
+
+
+/* Initialise la classe des panneaux d'affichage des journaux. */
+static void gtk_logs_panel_class_init(GtkLogsPanelClass *);
+
+/* Initialise une instance de panneau d'affichage des journaux. */
+static void gtk_logs_panel_init(GtkLogsPanel *);
+
+/* Supprime toutes les références externes. */
+static void gtk_logs_panel_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_logs_panel_finalize(GObject *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique l'emplacement par défaut pour un affichage. */
+static char *gtk_logs_panel_get_default_path(const GtkTiledPanel *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* COEUR D'UN PANNEAU D'AFFICHAGE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un panneau d'accueil. */
+G_DEFINE_TYPE(GtkLogsPanel, gtk_logs_panel, GTK_TYPE_TILED_PANEL);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à initialiser. *
+* *
+* Description : Initialise la classe des panneaux d'affichage des journaux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_logs_panel_class_init(GtkLogsPanelClass *class)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+ GtkTiledPanelClass *panel; /* Classe parente */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_logs_panel_dispose;
+ object->finalize = gtk_logs_panel_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ g_type_ensure(G_TYPE_LOG_ENTRY);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/logs.ui");
+
+ //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_logs_panel_on_selected_rows_changed));
+
+ gtk_widget_class_bind_template_child(widget, GtkLogsPanel, store);
+ gtk_widget_class_bind_template_child(widget, GtkLogsPanel, list);
+
+ panel = GTK_TILED_PANEL_CLASS(class);
+
+ panel->get_default_path = gtk_logs_panel_get_default_path;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance à initialiser. *
+* *
+* Description : Initialise une instance de panneau d'affichage des journaux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_logs_panel_init(GtkLogsPanel *panel)
+{
+ GtkWidget *headers; /* Composant à cacher */
+
+ gtk_widget_init_template(GTK_WIDGET(panel));
+
+ /**
+ * Retrait des entêtes de colonne de l'affichage.
+ */
+
+ headers = gtk_widget_get_first_child(panel->list);
+
+ gtk_widget_set_visible(headers, FALSE);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_logs_panel_dispose(GObject *object)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_LOGS_PANEL);
+
+ G_OBJECT_CLASS(gtk_logs_panel_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_logs_panel_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_logs_panel_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance d'objet GLib à traiter. *
+* entry = élément de journalisation à intégrer. *
+* *
+* Description : Affiche un message dans le journal des messages système. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_log_panel_add_message(GtkLogsPanel *panel, GLogEntry *entry)
+{
+ g_list_store_append(panel->store, entry);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau graphique à consulter. *
+* *
+* Description : Indique l'emplacement par défaut pour un affichage. *
+* *
+* Retour : Chemin représenté ou NULL pour l'emplacement "M" par défaut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *gtk_logs_panel_get_default_path(const GtkTiledPanel *panel)
+{
+ char *result; /* Chemin à retourner */
+
+ result = strdup("S");
+
+ return result;
+
+}
diff --git a/src/gui/panels/logs.h b/src/gui/panels/logs.h
new file mode 100644
index 0000000..a8b902b
--- /dev/null
+++ b/src/gui/panels/logs.h
@@ -0,0 +1,47 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * logs.h - prototypes pour le panneau d'affichage des messages système
+ *
+ * Copyright (C) 2012-2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 _GUI_PANELS_LOGS_H
+#define _GUI_PANELS_LOGS_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../../glibext/helpers.h"
+#include "../../glibext/log.h"
+
+
+
+#define GTK_TYPE_LOGS_PANEL (gtk_logs_panel_get_type())
+
+DECLARE_GTYPE(GtkLogsPanel, gtk_logs_panel, GTK, LOGS_PANEL);
+
+
+/* Affiche un message dans le journal des messages système. */
+void g_log_panel_add_message(GtkLogsPanel *, GLogEntry *);
+
+
+
+#endif /* _GUI_PANELS_LOGS_H */
diff --git a/src/gui/panels/logs.ui b/src/gui/panels/logs.ui
new file mode 100644
index 0000000..ba920cd
--- /dev/null
+++ b/src/gui/panels/logs.ui
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+
+ <object class="GtkNoSelection" id="noselection">
+ <property name="model">
+ <object class="GListStore" id="store">
+ <property name="item-type">GLogEntry</property>
+ </object>
+ </property>
+ </object>
+
+ <template class="GtkLogsPanel" parent="GtkTiledPanel">
+
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">automatic</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <property name="has-frame">0</property>
+
+ <child>
+ <object class="GtkColumnView" id="list">
+ <property name="vexpand">true</property>
+ <property name="model">noselection</property>
+
+ <child>
+ <object class="GtkColumnViewColumn">
+ <property name="title"></property>
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="resource">/re/chrysalide/framework/gui/panels/logs-col-icon.ui</property>
+ </object>
+ </property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkColumnViewColumn">
+ <property name="expand">true</property>
+ <property name="title">Message</property>
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="resource">/re/chrysalide/framework/gui/panels/logs-col-message.ui</property>
+ </object>
+ </property>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </template>
+
+</interface>
diff --git a/src/gui/panels/welcome-int.h b/src/gui/panels/welcome-int.h
index d99d316..206bc2c 100644
--- a/src/gui/panels/welcome-int.h
+++ b/src/gui/panels/welcome-int.h
@@ -27,20 +27,15 @@
#include "welcome.h"
-#include "../panel-int.h"
#include "../../gtkext/panel-int.h"
-/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */
-
-
/* Panneau d'accueil par défaut (instance) */
struct _GtkWelcomePanel
{
GtkTiledPanel parent; /* A laisser en premier */
- GListStore *store; /* Données brutes */
GtkListBox *list; /* Liste de lanceurs */
GtkStack *properties; /* Premières propriétés */
@@ -62,28 +57,5 @@ struct _GtkWelcomePanelClass
};
-/* Met en place un nouveau panneau d'accueil. */
-bool gtk_welcome_panel_create(GtkWelcomePanel *);
-
-
-
-/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */
-
-
-/* Définition pour gestion par le framework d'un panneau graphique (instance) */
-struct _GWelcomePanel
-{
- GPanelItem parent; /* A laisser en premier */
-
-};
-
-/* Définition pour gestion par le framework d'un panneau graphique (classe) */
-struct _GWelcomePanelClass
-{
- GPanelItemClass parent; /* A laisser en premier */
-
-};
-
-
#endif /* _GUI_PANELS_WELCOME_INT_H */
diff --git a/src/gui/panels/welcome.c b/src/gui/panels/welcome.c
index 3cd349f..6e8763b 100644
--- a/src/gui/panels/welcome.c
+++ b/src/gui/panels/welcome.c
@@ -28,9 +28,6 @@
#include <assert.h>
-#include <i18n.h>
-
-
#include "welcome-int.h"
#include "../core/panels.h"
#include "../../common/shuffle.h"
@@ -48,16 +45,10 @@ static void gtk_welcome_panel_class_init(GtkWelcomePanelClass *);
static void gtk_welcome_panel_init(GtkWelcomePanel *);
/* Supprime toutes les références externes. */
-static void gtk_welcome_panel_dispose(GtkWelcomePanel *);
+static void gtk_welcome_panel_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_welcome_panel_finalize(GtkWelcomePanel *);
-
-/* Intègre une définition de panneau enregistrée. */
-static bool gtk_welcome_panel_add_launcher(GPanelItem *, GListStore *);
-
-/* Prépare un composant pour représenter une définition. */
-static GtkWidget *gtk_welcome_panel_create_launcher_widget(GPanelItem *, gpointer);
+static void gtk_welcome_panel_finalize(GObject *);
/* Réagit à un changement de sélection de la liste de panneaux. */
static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *, GtkWelcomePanel *);
@@ -78,32 +69,6 @@ static void gtk_welcome_panel_on_next_hint_clicked(GtkButton *, GtkWelcomePanel
-/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */
-
-
-/* Initialise la classe des panneaux graphiques pour binaires. */
-static void g_welcome_panel_class_init(GWelcomePanelClass *);
-
-/* Initialise une instance de panneau graphique pour binaire. */
-static void g_welcome_panel_init(GWelcomePanel *);
-
-/* Supprime toutes les références externes. */
-static void g_welcome_panel_dispose(GWelcomePanel *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_welcome_panel_finalize(GWelcomePanel *);
-
-
-
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-
-
-/* Fournit une indication sur la personnalité du panneau. */
-static PanelItemPersonality g_welcome_panel_get_personality(const GWelcomePanel *);
-
-/* Fournit un composant représentant un panneau graphique. */
-static GtkTiledPanel *g_welcome_panel_get_panel(GWelcomePanel *, GtkWidget *);
-
/* ---------------------------------------------------------------------------------- */
@@ -134,8 +99,8 @@ static void gtk_welcome_panel_class_init(GtkWelcomePanelClass *class)
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_welcome_panel_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_welcome_panel_finalize;
+ object->dispose = gtk_welcome_panel_dispose;
+ object->finalize = gtk_welcome_panel_finalize;
widget = GTK_WIDGET_CLASS(class);
@@ -169,13 +134,16 @@ static void gtk_welcome_panel_init(GtkWelcomePanel *panel)
{
GBytes *bytes; /* Données brutes de ressource */
const gchar *data; /* Données brutes natives */
+ int min; /* Taille à gauche minimale */
+ GtkConstraintLayout *layout; /* Disposition fixant la taille*/
+ GtkConstraint *constraint; /* Contrainte à considérer */
gtk_widget_init_template(GTK_WIDGET(panel));
- panel->store = g_list_store_new(G_TYPE_PANEL_ITEM);
-
panel->other_child = NULL;
+ /* Chargement des astuces */
+
bytes = g_resources_lookup_data("/re/chrysalide/framework/gui/panels/welcome-hints.txt",
G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
assert(bytes != NULL);
@@ -191,105 +159,9 @@ static void gtk_welcome_panel_init(GtkWelcomePanel *panel)
panel->cur_hint = 0;
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void gtk_welcome_panel_dispose(GtkWelcomePanel *panel)
-{
- gtk_widget_dispose_template(GTK_WIDGET(panel), GTK_TYPE_WELCOME_PANEL);
-
- g_clear_object(&panel->other_child);
-
- G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->dispose(G_OBJECT(panel));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void gtk_welcome_panel_finalize(GtkWelcomePanel *panel)
-{
- G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->finalize(G_OBJECT(panel));
-
- g_strfreev(panel->raw_hints);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Crée une nouvelle instance de panneau d'accueil. *
-* *
-* Retour : Composant GTK mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GtkTiledPanel *gtk_welcome_panel_new(void)
-{
- GtkTiledPanel *result; /* Instance à retourner */
-
- result = g_object_new(GTK_TYPE_WELCOME_PANEL, NULL);
-
- if (!gtk_welcome_panel_create(GTK_WELCOME_PANEL(result)))
- g_clear_object(&result);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = panneau d'accueil à initialiser. *
-* *
-* Description : Met en place un nouveau panneau d'accueil. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool gtk_welcome_panel_create(GtkWelcomePanel *panel)
-{
- bool result; /* Bilan à retourner */
- int min; /* Taille à gauche minimale */
- GtkConstraintLayout *layout; /* Disposition fixant la taille*/
- GtkConstraint *constraint; /* Contrainte à considérer */
-
/* Constitution de la liste des démarreurs */
- result = browse_all_item_panels(true, (handle_panel_item_fc)gtk_welcome_panel_add_launcher, panel->store);
-
- gtk_list_box_bind_model(panel->list, G_LIST_MODEL(panel->store),
- (GtkListBoxCreateWidgetFunc)gtk_welcome_panel_create_launcher_widget,
- NULL, NULL);
+ populate_framework_panel_launcher_list(panel->list);
/* Dimensionnement de la zone d'astuces */
@@ -327,57 +199,57 @@ bool gtk_welcome_panel_create(GtkWelcomePanel *panel)
gtk_label_set_markup(panel->hints, panel->raw_hints[panel->cur_hint]);
- return result;
-
}
/******************************************************************************
* *
-* Paramètres : item = définition de panneau à intégrer. *
-* store = liste à compléter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Intègre une définition de panneau enregistrée. *
+* Description : Supprime toutes les références externes. *
* *
-* Retour : true pour un parcours complet de la liste des définitions. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool gtk_welcome_panel_add_launcher(GPanelItem *item, GListStore *store)
+static void gtk_welcome_panel_dispose(GObject *object)
{
- bool result; /* Poursuite du parcours */
+ GtkWelcomePanel *panel; /* Version spécialisée */
+
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_WELCOME_PANEL);
- result = true;
+ panel = GTK_WELCOME_PANEL(object);
- g_list_store_append(store, G_OBJECT(item));
+ g_clear_object(&panel->other_child);
- return result;
+ G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : item = définition de panneau à consulter. *
-* unused = adresse non utilisée ici. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Prépare un composant pour représenter une définition. *
+* Description : Procède à la libération totale de la mémoire. *
* *
-* Retour : Composant de représentation de définition de panneau. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static GtkWidget *gtk_welcome_panel_create_launcher_widget(GPanelItem *item, gpointer unused)
+static void gtk_welcome_panel_finalize(GObject *object)
{
- GtkWidget *result; /* Composant GTK à retourner */
+ GtkWelcomePanel *panel; /* Version spécialisée */
+
+ panel = GTK_WELCOME_PANEL(object);
- result = g_panel_item_get_launcher(item);
+ g_strfreev(panel->raw_hints);
- return result;
+ G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->finalize(object);
}
@@ -398,8 +270,6 @@ static GtkWidget *gtk_welcome_panel_create_launcher_widget(GPanelItem *item, gpo
static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *box, GtkWelcomePanel *panel)
{
GtkListBoxRow *row; /* Ligne sélectionnée */
- int selected; /* Indice de sélection */
- GPanelItem *item; /* Elément correspondant */
GtkWidget *new; /* Nouvelles propriétés */
row = gtk_list_box_get_selected_row(box);
@@ -414,7 +284,7 @@ static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *box, GtkWelco
gtk_stack_set_visible_child(panel->properties, panel->def_child);
gtk_stack_remove(panel->properties, panel->other_child);
- g_clear_object(&panel->other_child);
+ panel->other_child = NULL;
}
@@ -423,24 +293,16 @@ static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *box, GtkWelco
*/
else
{
- selected = gtk_list_box_row_get_index(row);
- item = g_list_model_get_item(G_LIST_MODEL(panel->store), selected);
+ new = get_framework_panel_parameters(row);
+ assert(new != NULL);
- new = g_panel_item_get_properties(item);
-
- if (new == panel->other_child)
- unref_object(new);
-
- else
+ if (new != panel->other_child)
{
gtk_stack_add_child(panel->properties, new);
gtk_stack_set_visible_child(panel->properties, new);
if (panel->other_child != NULL)
- {
gtk_stack_remove(panel->properties, panel->other_child);
- g_clear_object(&panel->other_child);
- }
panel->other_child = new;
@@ -513,178 +375,3 @@ static void gtk_welcome_panel_on_next_hint_clicked(GtkButton *button, GtkWelcome
-
-/* ---------------------------------------------------------------------------------- */
-/* MANIPULATIONS D'UN PANNEAU GRAPHIQUE */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour une manipulation de panneau de bienvenue. */
-G_DEFINE_TYPE(GWelcomePanel, g_welcome_panel, G_TYPE_PANEL_ITEM);
-
-
-/******************************************************************************
-* *
-* Paramètres : class = classe à initialiser. *
-* *
-* Description : Initialise la classe des panneaux graphiques pour binaires. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_welcome_panel_class_init(GWelcomePanelClass *class)
-{
- GObjectClass *object; /* Autre version de la classe */
- GPanelItemClass *panel; /* Encore une autre vision... */
-
- object = G_OBJECT_CLASS(class);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_welcome_panel_dispose;
- object->finalize = (GObjectFinalizeFunc)g_welcome_panel_finalize;
-
- panel = G_PANEL_ITEM_CLASS(class);
-
- panel->get_personality = (get_panel_item_personality_cb)g_welcome_panel_get_personality;
- panel->get_panel = (get_panel_item_panel_cb)g_welcome_panel_get_panel;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance à initialiser. *
-* *
-* Description : Initialise une instance de panneau graphique pour binaire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_welcome_panel_init(GWelcomePanel *panel)
-{
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_welcome_panel_dispose(GWelcomePanel *panel)
-{
- G_OBJECT_CLASS(g_welcome_panel_parent_class)->dispose(G_OBJECT(panel));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_welcome_panel_finalize(GWelcomePanel *panel)
-{
- G_OBJECT_CLASS(g_welcome_panel_parent_class)->finalize(G_OBJECT(panel));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Constitue une définition de manipulation de panneau. *
-* *
-* Retour : Définition de propriétés mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GPanelItem *g_welcome_panel_new(void)
-{
- GPanelItem *result; /* Structure à retourner */
-
- result = g_object_new(G_TYPE_WELCOME_PANEL, NULL);
-
- return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = définition de panneau à consulter. *
-* *
-* Description : Fournit une indication sur la personnalité du panneau. *
-* *
-* Retour : Identifiant lié à la nature du panneau. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static PanelItemPersonality g_welcome_panel_get_personality(const GWelcomePanel *panel)
-{
- PanelItemPersonality result; /* Personnalité à retourner */
-
- result = PIP_MAIN_PANEL | PIP_SINGLETON;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : panel = définition de panneau à manipuler. *
-* props = éventuels éléments graphiques de paramétrages. *
-* *
-* Description : Fournit un composant représentant un panneau graphique. *
-* *
-* Retour : Composant GTK (déjà ?) mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GtkTiledPanel *g_welcome_panel_get_panel(GWelcomePanel *panel, GtkWidget *props)
-{
- GtkTiledPanel *result; /* Composant à retourner */
-
- /**
- * Il n'existe pas de composants de paramètrage pour ce panneau.
- */
- assert(props == NULL);
-
- result = gtk_welcome_panel_new();
-
- return result;
-
-}
diff --git a/src/gui/panels/welcome.h b/src/gui/panels/welcome.h
index d267f80..d9ea18d 100644
--- a/src/gui/panels/welcome.h
+++ b/src/gui/panels/welcome.h
@@ -29,36 +29,15 @@
#include <gtk/gtk.h>
-#include "../panel.h"
#include "../../glibext/helpers.h"
#include "../../gtkext/panel.h"
-/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */
-
-
#define GTK_TYPE_WELCOME_PANEL (gtk_welcome_panel_get_type())
DECLARE_GTYPE(GtkWelcomePanel, gtk_welcome_panel, GTK, WELCOME_PANEL);
-/* Crée une nouvelle instance de panneau d'accueil. */
-GtkTiledPanel *gtk_welcome_panel_new(void);
-
-
-
-/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */
-
-
-#define G_TYPE_WELCOME_PANEL (g_welcome_panel_get_type())
-
-DECLARE_GTYPE(GWelcomePanel, g_welcome_panel, G, WELCOME_PANEL);
-
-
-/* Constitue une définition de manipulation de panneau. */
-GPanelItem *g_welcome_panel_new(void);
-
-
#endif /* _GUI_PANELS_WELCOME_H */
diff --git a/src/gui/style.css b/src/gui/style.css
index 44161f7..dce41fa 100644
--- a/src/gui/style.css
+++ b/src/gui/style.css
@@ -1,4 +1,13 @@
+/* Extension de style */
+
+.dim-label {
+
+ margin-bottom: 4px;
+
+}
+
+
.boxed-widget {
border-top-left-radius: 12px;
@@ -27,11 +36,7 @@ list.boxed-list, list.boxed-list > row:last-child {
/* about.css */
-.black-bg {
-
- background-color: black;
-
-}
+@import url('resource:///re/chrysalide/framework/gui/dialogs/about.css');
/* welcome.css */
@@ -52,3 +57,15 @@ grid.hints > box {
min-width: 130px;
}
+
+
+/* dockstation.css */
+
+.control-button {
+
+ min-height: 0;
+ min-width: 0;
+
+ padding: 6px;
+
+}
diff --git a/src/gui/window-int.h b/src/gui/window-int.h
index d79e189..4f3dd57 100644
--- a/src/gui/window-int.h
+++ b/src/gui/window-int.h
@@ -37,7 +37,10 @@ struct _GtkFrameworkWindow
GSettings *settings; /* Paramètres globaux */
- GtkStack *grid; /* Réceptacle de panneaux */
+ GtkTilingGrid *grid; /* Réceptacle de panneaux */
+ GtkStatusStack *status; /* Barre de statut */
+
+ GtkTiledPanel *main; /* Panneau principal courant */
};
diff --git a/src/gui/window.c b/src/gui/window.c
index 2680c89..e14ecf7 100644
--- a/src/gui/window.c
+++ b/src/gui/window.c
@@ -28,9 +28,11 @@
#include "window-int.h"
#include "core/panels.h"
#include "dialogs/about.h"
+#include "dialogs/preferences.h"
+#include "panels/logs.h"
#include "panels/welcome.h"
+#include "../gtkext/grid.h"
#include "../gtkext/helpers.h"
-#include "../gtkext/statusstack.h"
@@ -41,10 +43,28 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *);
static void gtk_framework_window_init(GtkFrameworkWindow *);
/* Supprime toutes les références externes. */
-static void gtk_framework_window_dispose(GtkFrameworkWindow *);
+static void gtk_framework_window_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_framework_window_finalize(GtkFrameworkWindow *);
+static void gtk_framework_window_finalize(GObject *);
+
+/* Bascule l'affichage d'un panneau de bordure. */
+static void gtk_framework_window_toggle_pannel_visibility(GtkFrameworkWindow *, TilingGridBorder);
+
+/* Réagit à une activation de bascule du panneau supérieur. */
+static void gtk_framework_window_activate_toggle_top(GSimpleAction *, GVariant *, gpointer);
+
+/* Réagit à une activation de bascule du panneau de gauche. */
+static void gtk_framework_window_activate_toggle_left(GSimpleAction *action, GVariant *, gpointer);
+
+/* Réagit à une activation de bascule du panneau de droite. */
+static void gtk_framework_window_activate_toggle_right(GSimpleAction *, GVariant *, gpointer);
+
+/* Réagit à une activation de bascule du panneau inférieur. */
+static void gtk_framework_window_activate_toggle_bottom(GSimpleAction *, GVariant *, gpointer);
+
+/* Réagit à une activation du menu "Préférences" de la fenetre. */
+static void gtk_framework_window_activate_preferences(GSimpleAction *, GVariant *, gpointer);
/* Réagit à une activation du menu "A propos de" de la fenetre. */
static void gtk_framework_window_activate_about(GSimpleAction *, GVariant *, gpointer);
@@ -79,15 +99,19 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *class)
widget = GTK_WIDGET_CLASS(class);
+ g_type_ensure(GTK_TYPE_TILING_GRID);
g_type_ensure(GTK_TYPE_STATUS_STACK);
gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/window.ui");
gtk_widget_class_bind_template_child(widget, GtkFrameworkWindow, grid);
+ gtk_widget_class_bind_template_child(widget, GtkFrameworkWindow, status);
/* Active une action native (cf. https://docs.gtk.org/gtk4/class.Window.html#actions) */
gtk_widget_class_add_binding_action(widget, GDK_KEY_Q, GDK_CONTROL_MASK, "window.close", NULL);
+ gtk_widget_class_add_binding_action(widget, GDK_KEY_comma, GDK_CONTROL_MASK, "win.preferences", NULL);
+
}
@@ -105,7 +129,14 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *class)
static void gtk_framework_window_init(GtkFrameworkWindow *window)
{
+ GAction *action; /* Action mise en place */
+
static GActionEntry app_entries[] = {
+ { "toggle-top", gtk_framework_window_activate_toggle_top, NULL, NULL, NULL },
+ { "toggle-left", gtk_framework_window_activate_toggle_left, NULL, NULL, NULL },
+ { "toggle-right", gtk_framework_window_activate_toggle_right, NULL, NULL, NULL },
+ { "toggle-bottom", gtk_framework_window_activate_toggle_bottom, NULL, NULL, NULL },
+ { "preferences", gtk_framework_window_activate_preferences, NULL, NULL, NULL },
{ "about", gtk_framework_window_activate_about, NULL, NULL, NULL },
};
@@ -117,16 +148,47 @@ static void gtk_framework_window_init(GtkFrameworkWindow *window)
g_settings_bind(window->settings, "window-height", G_OBJECT(window), "default-height", G_SETTINGS_BIND_DEFAULT);
g_settings_bind(window->settings, "window-maximized", G_OBJECT(window), "maximized", G_SETTINGS_BIND_DEFAULT);
+ window->main = NULL;
+
g_action_map_add_action_entries(G_ACTION_MAP(window),
app_entries, G_N_ELEMENTS(app_entries),
window);
+ /**
+ * Définition de l'accès aux actions pour obtenir un effet de bord sur
+ * l'accès aux boutons graphiques de déclenchement.
+ */
+
+ action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-top");
+
+ g_object_bind_property(G_OBJECT(window->grid), "empty-top",
+ G_OBJECT(action), "enabled",
+ G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+ action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-left");
+
+ g_object_bind_property(G_OBJECT(window->grid), "empty-left",
+ G_OBJECT(action), "enabled",
+ G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+ action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-right");
+
+ g_object_bind_property(G_OBJECT(window->grid), "empty-right",
+ G_OBJECT(action), "enabled",
+ G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+ action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-bottom");
+
+ g_object_bind_property(G_OBJECT(window->grid), "empty-bottom",
+ G_OBJECT(action), "enabled",
+ G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
}
/******************************************************************************
* *
-* Paramètres : window = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -136,20 +198,26 @@ static void gtk_framework_window_init(GtkFrameworkWindow *window)
* *
******************************************************************************/
-static void gtk_framework_window_dispose(GtkFrameworkWindow *window)
+static void gtk_framework_window_dispose(GObject *object)
{
+ GtkFrameworkWindow *window; /* Version spécialisée */
+
+ window = GTK_FRAMEWORK_WINDOW(object);
+
gtk_widget_dispose_template(GTK_WIDGET(window), GTK_TYPE_FRAMEWORK_WINDOW);
g_clear_object(&window->settings);
- G_OBJECT_CLASS(gtk_framework_window_parent_class)->dispose(G_OBJECT(window));
+ g_clear_object(&window->main);
+
+ G_OBJECT_CLASS(gtk_framework_window_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : window = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -159,9 +227,9 @@ static void gtk_framework_window_dispose(GtkFrameworkWindow *window)
* *
******************************************************************************/
-static void gtk_framework_window_finalize(GtkFrameworkWindow *window)
+static void gtk_framework_window_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_framework_window_parent_class)->finalize(G_OBJECT(window));
+ G_OBJECT_CLASS(gtk_framework_window_parent_class)->finalize(object);
}
@@ -208,7 +276,6 @@ GtkApplicationWindow *gtk_framework_window_new(GtkApplication *app)
bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app)
{
bool result; /* Bilan à retourner */
- GPanelItem *item; /* Définition de panneau */
GtkTiledPanel *panel; /* Panneau d'affichage */
GtkCssProvider *css; /* Feuille de style maison */
@@ -218,12 +285,17 @@ bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app
/* Inclusion d'un écran d'accueil */
- item = find_item_panel_by_type(G_TYPE_WELCOME_PANEL);
+ panel = get_framework_panel_singleton(GTK_TYPE_WELCOME_PANEL);
- panel = g_panel_item_get_panel(item);
gtk_framework_window_add(window, panel);
- unref_object(item);
+ if (1/* FIXME : first time */)
+ {
+ panel = get_framework_panel_singleton(GTK_TYPE_LOGS_PANEL);
+
+ gtk_framework_window_add(window, panel);
+
+ }
/* Chargement des extensions de thème */
@@ -254,6 +326,144 @@ bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app
/******************************************************************************
* *
+* Paramètres : window = instance de fenêtre principale à manipuler. *
+* border = sélection de la zone à considérer. *
+* *
+* Description : Bascule l'affichage d'un panneau de bordure. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_framework_window_toggle_pannel_visibility(GtkFrameworkWindow *window, TilingGridBorder border)
+{
+ bool state; /* Etat courant à basculer */
+
+ state = gtk_tiling_grid_get_visible(window->grid, border);
+
+ state = !state;
+
+ gtk_tiling_grid_set_visible(window->grid, border, state);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : action = désignation de l'action concernée par l'appel. *
+* unused = adresse non utilisée ici. *
+* _window = instance de fenêtre principale à manipuler. *
+* *
+* Description : Réagit à une activation de bascule du panneau supérieur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_framework_window_activate_toggle_top(GSimpleAction *action, GVariant *unused, gpointer _window)
+{
+ gtk_framework_window_toggle_pannel_visibility(_window, TGB_TOP);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : action = désignation de l'action concernée par l'appel. *
+* unused = adresse non utilisée ici. *
+* _window = instance de fenêtre principale à manipuler. *
+* *
+* Description : Réagit à une activation de bascule du panneau de gauche. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_framework_window_activate_toggle_left(GSimpleAction *action, GVariant *unused, gpointer _window)
+{
+ gtk_framework_window_toggle_pannel_visibility(_window, TGB_LEFT);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : action = désignation de l'action concernée par l'appel. *
+* unused = adresse non utilisée ici. *
+* _window = instance de fenêtre principale à manipuler. *
+* *
+* Description : Réagit à une activation de bascule du panneau de droite. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_framework_window_activate_toggle_right(GSimpleAction *action, GVariant *unused, gpointer _window)
+{
+ gtk_framework_window_toggle_pannel_visibility(_window, TGB_RIGHT);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : action = désignation de l'action concernée par l'appel. *
+* unused = adresse non utilisée ici. *
+* _window = instance de fenêtre principale à manipuler. *
+* *
+* Description : Réagit à une activation de bascule du panneau inférieur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_framework_window_activate_toggle_bottom(GSimpleAction *action, GVariant *unused, gpointer _window)
+{
+ gtk_framework_window_toggle_pannel_visibility(_window, TGB_BOTTOM);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : action = désignation de l'action concernée par l'appel. *
+* unused = adresse non utilisée ici. *
+* _window = instance de fenêtre principale à manipuler. *
+* *
+* Description : Réagit à une activation du menu "Préférences" de la fenetre. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_framework_window_activate_preferences(GSimpleAction *action, GVariant *unused, gpointer _window)
+{
+ GtkFrameworkWindow *window; /* Fenêtre principale associée */
+ GtkWindow *dialog; /* Boîte de dialogue à afficher*/
+
+ window = _window;
+
+ dialog = gtk_preferences_dialog_new(GTK_WINDOW(window));
+
+ gtk_window_present(dialog);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : action = désignation de l'action concernée par l'appel. *
* unused = adresse non utilisée ici. *
* _window = instance de fenêtre principale à manipuler. *
@@ -282,6 +492,31 @@ static void gtk_framework_window_activate_about(GSimpleAction *action, GVariant
/******************************************************************************
* *
+* Paramètres : window = instance de fenêtre principale à consulter. *
+* *
+* Description : Fournit une référence à la barre de statut intégrée. *
+* *
+* Retour : Composant GTK en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkStatusStack *gtk_framework_window_get_status_stack(const GtkFrameworkWindow *window)
+{
+ GtkStatusStack *result; /* Instance à retourner */
+
+ result = window->status;
+ ref_object(result);
+
+ return result;
+
+}
+
+
+
+/******************************************************************************
+* *
* Paramètres : window = instance de fenêtre principale à remplir. *
* panel = nouveau panneau à afficher. *
* *
@@ -300,10 +535,12 @@ void gtk_framework_window_add(GtkFrameworkWindow *window, /* __steal */GtkTiledP
guint count; /* Nombre d'élements présents */
guint i; /* Boucle de parcours */
GtkWidget *widget; /* Composant à intégrer */
+ FrameworkPanelPersonality personality; /* Propriétés du panneau */
- gtk_stack_add_child(window->grid, GTK_WIDGET(panel));
- gtk_stack_set_visible_child(window->grid, GTK_WIDGET(panel));
+
+ gtk_tiling_grid_add_panel(window->grid, panel, G_OBJECT_TYPE(panel) == GTK_TYPE_WELCOME_PANEL);
+
@@ -331,4 +568,54 @@ void gtk_framework_window_add(GtkFrameworkWindow *window, /* __steal */GtkTiledP
}
+ /* Mise à jour des liens vers un panneau principal */
+
+ personality = get_framework_panel_personality(G_OBJECT_TYPE(panel));
+
+ if (personality & FPP_MAIN_PANEL)
+ gtk_framework_window_notify_new_main_panel_state(window, panel, true);
+
+ else
+ {
+ if (window->main != NULL)
+ gtk_tiled_panel_notify_new_main_panel_state(panel, window->main, true);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : window = instance de fenêtre principale à manipuler. *
+* main = panneau principal visé par l'opération. *
+* activated = nature du changement de statut : ajout, retrait ?*
+* *
+* Description : Note un ajout ou un retrait de panneau principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_framework_window_notify_new_main_panel_state(GtkFrameworkWindow *window, GtkTiledPanel *main, bool activated)
+{
+ if (activated)
+ {
+ g_clear_object(&window->main);
+
+ window->main = main;
+ ref_object(main);
+
+ }
+
+ else
+ {
+ if (main == window->main)
+ g_clear_object(&window->main);
+
+ }
+
+ gtk_tiling_grid_notify_new_main_panel_state(window->grid, main, activated);
+
}
diff --git a/src/gui/window.h b/src/gui/window.h
index 56c56ec..077d51a 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -30,6 +30,7 @@
#include "../glibext/helpers.h"
#include "../gtkext/panel.h"
+#include "../gtkext/statusstack.h"
@@ -43,13 +44,18 @@
DECLARE_GTYPE(GtkFrameworkWindow, gtk_framework_window, GTK, FRAMEWORK_WINDOW);
-
/* Crée une nouvelle application principale pour Chrysalide. */
GtkApplicationWindow *gtk_framework_window_new(GtkApplication *);
+/* Fournit une référence à la barre de statut intégrée. */
+GtkStatusStack *gtk_framework_window_get_status_stack(const GtkFrameworkWindow *);
+
/* Ajoute un panneau à la fenêtre principale de Chrysalide. */
void gtk_framework_window_add(GtkFrameworkWindow *, GtkTiledPanel *);
+/* Note un ajout ou un retrait de panneau principal. */
+void gtk_framework_window_notify_new_main_panel_state(GtkFrameworkWindow *, GtkTiledPanel *, bool);
+
#endif /* _GUI_WINDOW_H */
diff --git a/src/gui/window.ui b/src/gui/window.ui
index 59b8b2c..1c6a89a 100644
--- a/src/gui/window.ui
+++ b/src/gui/window.ui
@@ -5,6 +5,7 @@
<section>
<item>
<attribute name="label" translatable="yes">Preferences</attribute>
+ <attribute name="action">win.preferences</attribute>
</item>
<item>
<attribute name="label" translatable="yes">About</attribute>
@@ -21,6 +22,23 @@
<child type="titlebar">
<object class="GtkHeaderBar">
+
+ <child type="start">
+ <object class="GtkToggleButton">
+ <property name="icon-name">dock-station-left-symbolic</property>
+ <property name="action-name">win.toggle-left</property>
+ <property name="active" bind-source="grid" bind-property="visible-left" bind-flags="sync-create"/>
+ </object>
+ </child>
+
+ <child type="end">
+ <object class="GtkToggleButton">
+ <property name="icon-name">dock-station-right-symbolic</property>
+ <property name="action-name">win.toggle-right</property>
+ <property name="active" bind-source="grid" bind-property="visible-right" bind-flags="sync-create"/>
+ </object>
+ </child>
+
<child type="end">
<object class="GtkMenuButton">
<property name="icon-name">open-menu-symbolic</property>
@@ -36,7 +54,7 @@
<property name="orientation">vertical</property>
<child>
- <object class="GtkStack" id="grid">
+ <object class="GtkTilingGrid" id="grid">
<property name="vexpand">TRUE</property>
</object>
</child>
@@ -49,6 +67,7 @@
<child>
<object class="GtkStatusStack" id="status">
+ <property name="show-bottom" bind-source="grid" bind-property="visible-bottom" bind-flags="sync-create"/>
</object>
</child>
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 7d375e3..fa65484 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -10,7 +10,9 @@ libplugins_la_SOURCES = \
plugin-def.h \
plugin-int.h \
plugin.h plugin.c \
- self.h
+ self.h \
+ tweakable-int.h \
+ tweakable.h tweakable.c
libplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
diff --git a/src/plugins/manager-int.h b/src/plugins/manager-int.h
index 5ccc8f8..dbd1d69 100644
--- a/src/plugins/manager-int.h
+++ b/src/plugins/manager-int.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * singleton-int.h - définitions internes propres aux interventions dans la gestion des extensions
+ * manager-int.h - définitions internes propres aux interventions dans la gestion des extensions
*
* Copyright (C) 2025 Cyrille Bagard
*
@@ -21,8 +21,8 @@
*/
-#ifndef _PLUGINS_CONTAINER_INT_H
-#define _PLUGINS_CONTAINER_INT_H
+#ifndef _PLUGINS_MANAGER_INT_H
+#define _PLUGINS_MANAGER_INT_H
#include "manager.h"
@@ -39,7 +39,7 @@ typedef void (* handle_native_plugins_cb) (GPluginManager *);
typedef void (* handle_all_plugins_cb) (GPluginManager *);
-/* Instance d'objet visant à être unique (interface) */
+/* Accompagnant dans la gestion des extensions (interface) */
struct _GPluginManagerInterface
{
GTypeInterface base_iface; /* A laisser en premier */
@@ -51,4 +51,4 @@ struct _GPluginManagerInterface
-#endif /* _PLUGINS_CONTAINER_INT_H */
+#endif /* _PLUGINS_MANAGER_INT_H */
diff --git a/src/plugins/native-int.h b/src/plugins/native-int.h
index 8b8e0eb..575994f 100644
--- a/src/plugins/native-int.h
+++ b/src/plugins/native-int.h
@@ -41,7 +41,18 @@ struct _GNativePlugin
{
GPluginModule parent; /* A laisser en premier */
- GModule *module; /* Abstration de manipulation */
+ /**
+ * Le module porte le code et les données en mémoire.
+ *
+ * Les fonctions *_dispose() et *_finalize() accompagnant la libération des
+ * greffons de la mémoire ne peuvent donc pas libérer ce module car elles
+ * scieraient la branche sur laquelle elles se trouvent.
+ *
+ * Par ailleurs, même s'ils sont conservés dans chaque greffon, les modules
+ * sont mis en place dans le code principal. C'est donc ce dernier qui les
+ * libère, dans la fonction on_plugin_ref_toggle().
+ */
+ GModule *module; /* Structure de chargement GLib*/
};
diff --git a/src/plugins/native.c b/src/plugins/native.c
index fedccbe..de20abe 100644
--- a/src/plugins/native.c
+++ b/src/plugins/native.c
@@ -131,12 +131,6 @@ static void g_native_plugin_init(GNativePlugin *plugin)
static void g_native_plugin_dispose(GNativePlugin *plugin)
{
- if (plugin->module != NULL)
- {
- g_module_close(plugin->module);
- plugin->module = NULL;
- }
-
G_OBJECT_CLASS(g_native_plugin_parent_class)->dispose(G_OBJECT(plugin));
}
@@ -194,6 +188,29 @@ bool g_native_plugin_create(GNativePlugin *plugin, const char *name, const char
}
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à consulter. *
+* *
+* Description : Renvoie la structure opaque associée au module en mémoire. *
+* *
+* Retour : Structure de chargement côté GLib. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GModule *g_native_plugin_get_module(const GNativePlugin *plugin)
+{
+ GModule *result; /* Accès au module à renvoyer */
+
+ result = plugin->module;
+
+ return result;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
diff --git a/src/plugins/native.h b/src/plugins/native.h
index 205342c..18039c8 100644
--- a/src/plugins/native.h
+++ b/src/plugins/native.h
@@ -26,6 +26,9 @@
#define _PLUGINS_NATIVE_H
+#include <gmodule.h>
+
+
#include "../glibext/helpers.h"
@@ -35,5 +38,9 @@
DECLARE_GTYPE(GNativePlugin, g_native_plugin, G, NATIVE_PLUGIN);
+/* Renvoie la structure opaque associée au module en mémoire. */
+GModule *g_native_plugin_get_module(const GNativePlugin *);
+
+
#endif /* _PLUGINS_NATIVE_H */
diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c
index 277e4f5..3e107b8 100644
--- a/src/plugins/pglist.c
+++ b/src/plugins/pglist.c
@@ -37,9 +37,10 @@
#include "manager.h"
+#include "native.h"
#include "plugin-int.h"
#include "../common/cpp.h"
-#include "../common/extstr.h" // REMME ?
+#include "../common/extstr.h"
#include "../core/logs.h"
#include "../core/nox.h"
#include "../core/paths.h"
@@ -69,6 +70,9 @@ static void browse_directory_for_plugins(const char *);
/* Suit les variations du compteur de références d'un greffon. */
static void on_plugin_ref_toggle(gpointer, GPluginModule *, gboolean);
+/* Fournit le greffon répondant à un nom donné. */
+static GPluginModule *_find_plugin_by_name(const char *, size_t *);
+
/******************************************************************************
@@ -134,71 +138,23 @@ bool init_all_plugins(bool load)
void exit_all_plugins(void)
{
-
-#if 0 //////
-
-
size_t i; /* Boucle de parcours */
- const plugin_interface *pg_iface; /* Définition du greffon */
lock_plugin_list_for_reading();
- if (_pg_list != NULL)
+ for (i = 0; i < _pg_count; i++)
{
- for (i = 0; i < _pg_count; i++)
- {
- assert(_pg_list[i] != NULL);
-
- /**
- * Si le greffon a conduit à la mise en place d'autres greffons, le
- * système de dépendances ne suffit pas pour le décompte des références :
- * le greffon voit à un instant T son compteur décroître ici ; à un
- * instant T+1, un greffon fils décrémente à son tour le compteur vers
- * le greffon principal.
- *
- * Le compteur du conteneur tombe alors à 0, et le code correspondant
- * est retiré. Lorsque que le flot d'exécution revient à la procédure
- * de sortie du second greffon, son code n'est plus en mémoire.
- *
- * On s'assure donc que les greffons qui génèrent d'autres greffons
- * sont bien traités en dernier.
- */
-
- pg_iface = g_plugin_module_get_interface(_pg_list[i]);
-
- if (pg_iface != NULL && pg_iface->container)
- g_object_ref(_pg_list[i]);
-
- g_object_unref(_pg_list[i]);
-
- }
-
- for (i = 0; i < _pg_count; i++)
- {
- if (_pg_list[i] == NULL)
- continue;
-
- pg_iface = g_plugin_module_get_interface(_pg_list[i]);
-
- if (pg_iface == NULL || !pg_iface->container)
- continue;
-
- g_object_unref(_pg_list[i]);
-
- }
+ assert(_pg_list[i] != NULL);
+ unref_object(_pg_list[i]);
+ }
+ if (_pg_list != NULL)
free(_pg_list);
- }
-
unlock_plugin_list_for_reading();
g_rw_lock_clear(&_pg_lock);
-
-
-#endif
-
}
@@ -388,22 +344,10 @@ static void browse_directory_for_plugins(const char *dir)
else
{
-
- printf("// Candidate // %s\n", filename);
-
has_alt = check_for_plugin_versions(dir, namelist[k]->d_name, &is_nox, &is_ui);
- printf(" -> nox=%d ui=%d -> alt? %d\n", is_nox, is_ui, has_alt);
-
-
if ((nox_mode && is_nox) || (!nox_mode && ((is_nox && !has_alt) || is_ui)))
{
-
-
- printf(" ---> load!\n");
-
-
-
module = g_module_open(filename, G_MODULE_BIND_LAZY);
if (module == NULL)
{
@@ -413,32 +357,18 @@ static void browse_directory_for_plugins(const char *dir)
goto next_file;
}
-
- printf(" (main) module=%p '%s'\n", module, g_module_name(module));
-
+ get_instance = NULL;
if (!g_module_symbol(module, "get_chrysalide_plugin_instance", (gpointer *)&get_instance))
- {
log_variadic_message(LMT_ERROR,
_("No '%s' entry in plugin candidate '%s'"),
"<sym>", filename);
-
-
- }
-
-
if (get_instance == NULL)
plugin = NULL;
else
plugin = get_instance(module);
-
-
- printf(" ===> plugin: %p\n", plugin);
-
-
-
if (plugin != NULL)
{
register_plugin(plugin);
@@ -485,6 +415,7 @@ static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolea
const char *name; /* Désignation du greffon */
size_t index; /* Indice du greffon */
GPluginModule *same; /* Juste pour la récupération */
+ GModule *module; /* Structure de chargement GLib*/
if (last)
{
@@ -492,15 +423,44 @@ static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolea
name = g_plugin_module_get_name(plugin);
- same = get_plugin_by_name(name, &index);
+ /**
+ * Les mécanismes de g_object_unref() prennent en compte la bascule d'un
+ * compteur de références initialement à 2 avant appel pour déclencher
+ * cet appel à on_plugin_ref_toggle() mis en place par g_object_add_toggle_ref().
+ *
+ * Incrémenter ce compteur à nouveau, via get_plugin_by_name(), puis le
+ * décrémenter ensuite via unref_object() va conduire à une nouvelle
+ * bascule des statuts de suivi dans g_object_unref().
+ *
+ * Il est ainsi impératif de rechercher une instance du greffon dans
+ * la liste des extensions sans toucher au compteur de références.
+ */
+
+ same = _find_plugin_by_name(name, &index);
+
assert(same != NULL);
assert(same == plugin);
- g_clear_object(&_pg_list[index]);
+ _pg_list[index] = NULL;
+
+ /**
+ * Suppression de la dernière référence.
+ */
+
+ if (G_IS_NATIVE_PLUGIN(plugin))
+ module = g_native_plugin_get_module(G_NATIVE_PLUGIN(plugin));
+ else
+ module = NULL;
g_object_remove_toggle_ref(G_OBJECT(same), (GToggleNotify)on_plugin_ref_toggle, NULL);
- unref_object(same);
+ /**
+ * Plus aucun code issu du greffon n'est désormais utile. Le module associé peut
+ * être libéré de la mémoire.
+ */
+
+ if (module != NULL)
+ g_module_close(module);
}
@@ -622,13 +582,18 @@ void load_remaning_plugins(void)
/* Supprime les greffons non chargés */
- for (i = 0; i < _pg_count; i++)
+ for (i = 0; i < _pg_count;)
{
flags = g_plugin_module_get_flags(_pg_list[i]);
- if ((flags & PSF_LOADED) == 0)
+ if (flags & PSF_LOADED)
+ i++;
+
+ else
{
- g_object_unref(G_OBJECT(_pg_list[i]));
+ unref_object(_pg_list[i]);
+
+ assert(_pg_list[i] == NULL);
memmove(&_pg_list[i], &_pg_list[i + 1], (_pg_count - i - 1) * sizeof(GPluginModule *));
_pg_count--;
@@ -655,11 +620,12 @@ void load_remaning_plugins(void)
* *
* Retour : Instance du greffon trouvé ou NULL si aucun. *
* *
-* Remarques : - *
+* Remarques : Le compteur de référence d'un greffon trouvé n'est pas *
+* modifié. *
* *
******************************************************************************/
-GPluginModule *get_plugin_by_name(const char *name, size_t *index)
+static GPluginModule *_find_plugin_by_name(const char *name, size_t *index)
{
GPluginModule *result; /* Greffon trouvé à renvoyer */
size_t i; /* Boucle de parcours */
@@ -682,7 +648,6 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)
if (strcmp(current, name) == 0)
{
result = _pg_list[i];
- ref_object(result);
if (index != NULL)
*index = i;
@@ -698,6 +663,33 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)
/******************************************************************************
* *
+* Paramètres : name = désignation du greffon recherché. *
+* index = indice du greffon trouvé. [OUT] *
+* *
+* Description : Fournit le greffon répondant à un nom donné. *
+* *
+* Retour : Instance du greffon trouvé ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GPluginModule *get_plugin_by_name(const char *name, size_t *index)
+{
+ GPluginModule *result; /* Greffon trouvé à renvoyer */
+
+ result = _find_plugin_by_name(name, index);
+
+ if (result != NULL)
+ ref_object(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : count = nombre de greffons trouvés. [OUT] *
* *
* Description : Fournit la liste de l'ensemble des greffons. *
diff --git a/src/plugins/pglist.h b/src/plugins/pglist.h
index 5541493..777b19c 100644
--- a/src/plugins/pglist.h
+++ b/src/plugins/pglist.h
@@ -69,25 +69,60 @@ GPluginModule **get_all_plugins(size_t *);
* Définitions des opérations appliquables à une catégories de greffons.
*/
-#define process_all_plugins_for(tp, cst, fc) \
- do \
- { \
- size_t __count; \
- GPluginModule **__list; \
- size_t __i; \
- __list = get_all_plugins(&__count); \
- for (__i = 0; __i < __count; __i++) \
- { \
- if (G_TYPE_CHECK_INSTANCE_TYPE(__list[__i], tp)) \
- fc(cst(__list[__i])); \
- unref_object(__list[__i]); \
- } \
- if (__list != NULL) \
- free(__list); \
- } \
+#define process_all_plugins_for(tp, cst, fc) \
+ do \
+ { \
+ size_t __count; \
+ GPluginModule **__list; \
+ size_t __i; \
+ GPluginModule *__pg; \
+ __list = get_all_plugins(&__count); \
+ for (__i = 0; __i < __count; __i++) \
+ { \
+ __pg = __list[__i]; \
+ if (G_TYPE_CHECK_INSTANCE_TYPE(__pg, tp)) \
+ fc(cst(__pg)); \
+ unref_object(__pg); \
+ } \
+ if (__list != NULL) \
+ free(__list); \
+ } \
while (0)
-
+#define accumulate_from_all_plugins(tp, cst, fc, atp, cnt) \
+ ({ \
+ atp *__acc_list; \
+ size_t __count; \
+ GPluginModule **__list; \
+ size_t __i; \
+ GPluginModule *__pg; \
+ size_t __tmp_count; \
+ atp *__tmp_list; \
+ *cnt = 0; \
+ __acc_list = NULL; \
+ __list = get_all_plugins(&__count); \
+ for (__i = 0; __i < __count; __i++) \
+ { \
+ __pg = __list[__i]; \
+ if (G_TYPE_CHECK_INSTANCE_TYPE(__pg, tp)) \
+ { \
+ __tmp_list = fc(cst(__pg), &__tmp_count); \
+ if (__tmp_list != NULL) \
+ { \
+ __acc_list = realloc(__acc_list, \
+ (*cnt + __tmp_count) * sizeof(atp)); \
+ memcpy(&__acc_list[*cnt], __tmp_list, \
+ __tmp_count * sizeof(atp)); \
+ *cnt += __tmp_count; \
+ free(__tmp_list); \
+ } \
+ } \
+ unref_object(__pg); \
+ } \
+ if (__list != NULL) \
+ free(__list); \
+ __acc_list; \
+ })
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index d14e656..dfdf3ed 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -135,34 +135,45 @@ static void g_plugin_module_init(GPluginModule *plugin)
static void g_plugin_module_dispose(GPluginModule *plugin)
{
size_t i; /* Boucle de parcours */
+ size_t index; /* Indice de greffon visé */
GPluginModule *dependency; /* Module nécessaire */
GPluginModuleClass *class; /* Classe de l'instance active */
- lock_plugin_list_for_reading();
-
- for (i = 0; i < plugin->required_count; i++)
+ if (plugin->dependencies != NULL)
{
- dependency = get_plugin_by_name(plugin->required[i], NULL);
+ lock_plugin_list_for_reading();
- /* Si le chargement a bien été complet avant la sortie... */
- if (dependency != NULL)
+ for (i = 0; i < plugin->required_count; i++)
{
- /* Un coup pour l'appel à get_plugin_by_name(). */
- unref_object(dependency);
+ dependency = get_plugin_by_name(plugin->required[i], &index);
+
+ /* Si la dépendance a bien été pris en compte... */
+ if (test_in_bit_field(plugin->dependencies, index))
+ {
+ assert(dependency != NULL);
+
+ /* Un coup pour l'appel à get_plugin_by_name(). */
+ unref_object(dependency);
- /* Un coup pour la dépendance */
- unref_object(dependency);
+ /* Un coup pour la dépendance */
+ unref_object(dependency);
+
+ }
}
+ unlock_plugin_list_for_reading();
+
}
- unlock_plugin_list_for_reading();
+ if (plugin->flags & PSF_LOADED)
+ {
+ class = G_PLUGIN_MODULE_GET_CLASS(plugin);
- class = G_PLUGIN_MODULE_GET_CLASS(plugin);
+ if (class->disable != NULL)
+ class->disable(plugin);
- if (class->disable != NULL)
- class->disable(plugin);
+ }
G_OBJECT_CLASS(g_plugin_module_parent_class)->dispose(G_OBJECT(plugin));
diff --git a/src/plugins/tweakable-int.h b/src/plugins/tweakable-int.h
new file mode 100644
index 0000000..776626f
--- /dev/null
+++ b/src/plugins/tweakable-int.h
@@ -0,0 +1,50 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweakable-int.h - définitions internes propres aux participations aux mécanismes de configuration
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_TWEAKABLE_INT_H
+#define _PLUGINS_TWEAKABLE_INT_H
+
+
+#include "tweakable.h"
+
+
+
+/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */
+
+
+/* Fournit une liste de sections de configuration. */
+typedef tweak_info_t * (* get_tweakable_plugin_info) (const GTweakablePlugin *, size_t *);
+
+
+/* Greffon avec des compléments pour l'interface de configuration (interface) */
+struct _GTweakablePluginInterface
+{
+ GTypeInterface base_iface; /* A laisser en premier */
+
+ get_tweakable_plugin_info get_info; /* Récupération de section(s) */
+
+};
+
+
+
+#endif /* _PLUGINS_TWEAKABLE_INT_H */
diff --git a/src/plugins/tweakable.c b/src/plugins/tweakable.c
new file mode 100644
index 0000000..517c4a3
--- /dev/null
+++ b/src/plugins/tweakable.c
@@ -0,0 +1,98 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweakable.c - participation aux mécanismes de configuration
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "tweakable.h"
+
+
+#include "tweakable-int.h"
+
+
+
+/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */
+
+
+/* Procède à l'initialisation de l'interface d'intervention. */
+static void g_tweakable_plugin_default_init(GTweakablePluginInterface *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTEGRATION DANS L'EDITION DES PREFERENCES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Détermine le type d'une interface pour l'intervention dans la gestion des greffons. */
+G_DEFINE_INTERFACE(GTweakablePlugin, g_tweakable_plugin, G_TYPE_OBJECT)
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'interface d'intervention. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_tweakable_plugin_default_init(GTweakablePluginInterface *iface)
+{
+ iface->get_info = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = interface à manipuler. *
+* count = taille de la liste renvoyée. [OUT] *
+* *
+* Description : Fournit une liste de sections de configuration. *
+* *
+* Retour : Définition(s) de section de configuration ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+tweak_info_t *g_tweakable_plugin_get_tweak_info(const GTweakablePlugin *plugin, size_t *count)
+{
+ tweak_info_t *result; /* Liste à renvoyer */
+ GTweakablePluginInterface *iface; /* Interface utilisée */
+
+ iface = G_TWEAKABLE_PLUGIN_GET_IFACE(plugin);
+
+ if (iface->get_info != NULL)
+ result = iface->get_info(plugin, count);
+
+ else
+ {
+ *count = 0;
+ result = NULL;
+ }
+
+ return result;
+
+}
diff --git a/src/plugins/tweakable.h b/src/plugins/tweakable.h
new file mode 100644
index 0000000..aea70b4
--- /dev/null
+++ b/src/plugins/tweakable.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweakable.h - prototypes pour la participation aux mécanismes de configuration
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_TWEAKABLE_H
+#define _PLUGINS_TWEAKABLE_H
+
+
+#include "../glibext/helpers.h"
+#include "../gtkext/tweak.h"
+
+
+
+/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */
+
+
+#define G_TYPE_TWEAKABLE_PLUGIN (g_tweakable_plugin_get_type())
+
+DECLARE_INTERFACE(GTweakablePlugin, g_tweakable_plugin, G, TWEAKABLE_PLUGIN);
+
+
+/* Fournit une liste de sections de configuration. */
+tweak_info_t *g_tweakable_plugin_get_tweak_info(const GTweakablePlugin *, size_t *);
+
+
+
+/* -------------------- SOLLICITATION DES FONCTIONNALITES CREEES -------------------- */
+
+
+#define get_tweakable_plugins_info(c) \
+ ({ \
+ tweak_info_t *__all_info; \
+ __all_info = accumulate_from_all_plugins(G_TYPE_TWEAKABLE_PLUGIN, \
+ G_TWEAKABLE_PLUGIN, \
+ g_tweakable_plugin_get_tweak_info, \
+ tweak_info_t, \
+ c); \
+ __all_info; \
+ })
+
+
+
+#endif /* _PLUGINS_TWEAKABLE_H */
diff --git a/src/rost.c b/src/rost.c
index 4a052c3..b94b367 100644
--- a/src/rost.c
+++ b/src/rost.c
@@ -41,7 +41,9 @@
#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"
+#ifdef INCLUDE_HS_SUPPORT
+# include "analysis/scan/patterns/backends/hyperscan.h"
+#endif
#include "core/core.h"
#include "core/global.h"
#include "core/logs.h"
@@ -93,7 +95,11 @@ static void show_rost_help(const char *name)
printf("\n");
+#ifdef INCLUDE_HS_SUPPORT
printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: acism, bitmap, hyperscan (default: acsim).\n");
+#else
+ printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: acism, bitmap (default: acsim).\n");
+#endif
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");
@@ -303,8 +309,10 @@ int main(int argc, char **argv)
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);
+#ifdef INCLUDE_HS_SUPPORT
else if (strcmp(optarg, "hyperscan") == 0)
g_scan_options_set_backend_for_data(options, G_TYPE_HYPERSCAN_BACKEND);
+#endif
else
g_scan_options_set_backend_for_data(options, G_TYPE_INVALID);
break;
diff --git a/src/schemas/re.chrysalide.framework.gschema.xml b/src/schemas/re.chrysalide.framework.gschema.xml
index e8331ff..534f735 100644
--- a/src/schemas/re.chrysalide.framework.gschema.xml
+++ b/src/schemas/re.chrysalide.framework.gschema.xml
@@ -1,19 +1,106 @@
<schemalist gettext-domain="chrysalide">
- <schema id="re.chrysalide.framework" path="/re/chrysalide/framework/">
- <child schema="re.chrysalide.framework.gui" name="gui"/>
- </schema>
-
- <schema id="re.chrysalide.framework.gui" path="/re/chrysalide/framework/gui/">
- <key name="window-width" type="i">
- <default>600</default>
- </key>
- <key name="window-height" type="i">
- <default>400</default>
- </key>
- <key name="window-maximized" type="b">
- <default>false</default>
- </key>
- </schema>
+ <schema id="re.chrysalide.framework" path="/re/chrysalide/framework/">
+ <child schema="re.chrysalide.framework.paths" name="paths"/>
+ <child schema="re.chrysalide.framework.gui" name="gui"/>
+ <child schema="re.chrysalide.framework.tiledgrid" name="tiles"/>
+ <child schema="re.chrysalide.framework.secstorage" name="secstorage"/>
+ </schema>
+
+ <schema id="re.chrysalide.framework.paths" path="/re/chrysalide/framework/paths/">
+ <key name="tmp-work-dir" type="s">
+ <default>"/tmp/chrysalide"</default>
+ <summary>Directory for temporary contents</summary>
+ <description>
+ Location of files created as cache and meant to get deleted when unused
+ </description>
+ </key>
+ </schema>
+
+ <schema id="re.chrysalide.framework.gui" path="/re/chrysalide/framework/gui/">
+ <key name="window-width" type="i">
+ <default>600</default>
+ </key>
+ <key name="window-height" type="i">
+ <default>400</default>
+ </key>
+ <key name="window-maximized" type="b">
+ <default>false</default>
+ </key>
+ </schema>
+
+ <flags id="re.chrysalide.framework.tiledgrid.LayoutReachOptions">
+ <value nick="left-top-reach" value="1"/>
+ <value nick="left-bottom-reach" value="2"/>
+ <value nick="right-top-reach" value="4"/>
+ <value nick="right-bottom-reach" value="8"/>
+ </flags>
+
+ <schema id="re.chrysalide.framework.tiledgrid">
+
+ <key name="layout" flags="re.chrysalide.framework.tiledgrid.LayoutReachOptions">
+ <default>["left-top-reach","right-top-reach"]</default>
+ <summary>Main panel layout</summary>
+ <description>Layout details describing the border panel locations</description>
+ </key>
+
+ <key name="top-visibility" type="b">
+ <default>false</default>
+ <summary>Top panel visibility</summary>
+ <description>Visbility of the panel located at the top of a tiling grid</description>
+ </key>
+
+ <key name="top-request" type="u">
+ <default>300</default>
+ <summary>Top panel height</summary>
+ <description>Height request for the panel located at the top of a tiling grid</description>
+ </key>
+
+ <key name="left-visibility" type="b">
+ <default>false</default>
+ <summary>Left panel visibility</summary>
+ <description>Visbility of the panel located at the left of a tiling grid</description>
+ </key>
+
+ <key name="left-request" type="u">
+ <default>300</default>
+ <summary>Left panel height</summary>
+ <description>Width request for the panel located at the left of a tiling grid</description>
+ </key>
+
+ <key name="right-visibility" type="b">
+ <default>false</default>
+ <summary>Right panel visibility</summary>
+ <description>Visbility of the panel located at the right of a tiling grid</description>
+ </key>
+
+ <key name="right-request" type="u">
+ <default>300</default>
+ <summary>Right panel height</summary>
+ <description>Width request for the panel located at the right of a tiling grid</description>
+ </key>
+
+ <key name="bottom-visibility" type="b">
+ <default>false</default>
+ <summary>Bottom panel visibility</summary>
+ <description>Visbility of the panel located at the bottom of a tiling grid</description>
+ </key>
+
+ <key name="bottom-request" type="u">
+ <default>250</default>
+ <summary>Bottom panel height</summary>
+ <description>Height request for the panel located at the bottom of a tiling grid</description>
+ </key>
+
+ </schema>
+
+ <schema id="re.chrysalide.framework.secstorage" path="/re/chrysalide/framework/secstorage/">
+ <key name="salt" type="ay">
+ <default>[]</default>
+ </key>
+ <key name="master" type="ay">
+ <default>[]</default>
+ </key>
+ </schema>
</schemalist>
diff --git a/system/magic/storage b/system/magic/storage
new file mode 100644
index 0000000..b7698d1
--- /dev/null
+++ b/system/magic/storage
@@ -0,0 +1,40 @@
+
+# 4.3.7 Local file header:
+# Cf. https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
+
+# local file header signature 4 bytes (0x04034b50)
+# version needed to extract 2 bytes
+# general purpose bit flag 2 bytes
+# compression method 2 bytes
+# last mod file time 2 bytes
+# last mod file date 2 bytes
+# crc-32 4 bytes
+# compressed size 4 bytes
+# uncompressed size 4 bytes
+# file name length 2 bytes
+# extra field length 2 bytes
+
+
+# ZIP local file header #1
+
+0 string PK\003\004
+
+# First entry: control (file name length = 7)
+
+>0x1a uleshort 7
+>>0x1e string control
+
+# Content of control
+
+>>>&(0x1c.h) string COBSTR Chrysalide GObject storage
+>>>>&0 string \001\000 (version 1.0)
+
+# Storage for PythonNotebook
+
+>>>>>&0 byte 14
+>>>>>>&0 string PythonNotebook - PythonNotebook
+
+>>>>>>>&0 byte 1 v1
+
+!:mime application/vnd.chrysalide.notebook
+!:ext cnb
diff --git a/tests/analysis/storage/storage.py b/tests/analysis/storage/storage.py
deleted file mode 100644
index 612d500..0000000
--- a/tests/analysis/storage/storage.py
+++ /dev/null
@@ -1,81 +0,0 @@
-
-from chrysacase import ChrysalideTestCase
-from pychrysalide import core
-from pychrysalide.analysis.contents import FileContent
-from pychrysalide.analysis.storage import ObjectStorage
-from pychrysalide.common import PackedBuffer
-import os
-import shutil
-import tempfile
-
-
-class TestObjectStorage(ChrysalideTestCase):
- """TestCase for analysis.storage."""
-
- @classmethod
- def setUpClass(cls):
-
- super(TestObjectStorage, cls).setUpClass()
-
- cls._tmp_path = tempfile.mkdtemp()
-
- config = core.get_main_configuration()
- param = config.search(core.MainParameterKeys.TMPDIR)
-
- cls._old_tmpdir = param.value
- param.value = cls._tmp_path
-
- cls.log('Using temporary directory "%s"' % cls._tmp_path)
-
-
- @classmethod
- def tearDownClass(cls):
-
- super(TestObjectStorage, cls).tearDownClass()
-
- config = core.get_main_configuration()
- param = config.search(core.MainParameterKeys.TMPDIR)
-
- param.value = cls._old_tmpdir
-
- # import os
- # os.system('ls -laihR %s' % cls._tmp_path)
-
- cls.log('Delete directory "%s"' % cls._tmp_path)
-
- shutil.rmtree(cls._tmp_path)
-
-
- def testFileContentStorage(self):
- """Store and load file binary content."""
-
- storage = ObjectStorage('my-storage-hash')
- self.assertIsNotNone(storage)
-
- filename = os.path.join(self._tmp_path, 'test.bin')
-
- with open(filename, 'wb') as fd:
- fd.write(b'ABC')
-
- cnt = FileContent(filename)
- self.assertIsNotNone(cnt)
-
- ret = storage.store_object('contents', cnt)
- self.assertEqual(ret, 0)
-
- pbuf = PackedBuffer()
-
- ret = storage.store(pbuf)
- self.assertTrue(ret)
-
- self.assertTrue(pbuf.payload_length > 0)
-
- pbuf.rewind()
-
- storage2 = ObjectStorage.load(pbuf)
- self.assertIsNotNone(storage2)
-
- cnt2 = storage2.load_object('contents', 0)
- self.assertIsNotNone(cnt2)
-
- self.assertEqual(cnt.data, cnt2.data)
diff --git a/tests/arch/instruction.py b/tests/arch/instruction.py
new file mode 100644
index 0000000..da4d8c1
--- /dev/null
+++ b/tests/arch/instruction.py
@@ -0,0 +1,52 @@
+
+import pychrysalide
+from chrysacase import ChrysalideTestCase
+from pychrysalide.arch import ArchInstruction
+
+
+class TestProcessor(ChrysalideTestCase):
+ """TestCase for arch.ArchProcessor."""
+
+
+ def testAbstractClass(self):
+ """Forbid instruction class instance."""
+
+ with self.assertRaisesRegex(RuntimeError, 'pychrysalide.arch.ArchInstruction is an abstract class'):
+ ins = ArchInstruction()
+
+
+ def testInstructionBasicImplementation(self):
+ """Implement basic custom instructions."""
+
+
+ class TodoInstruction(ArchInstruction):
+
+ def __init__(self):
+ super().__init__(0x123)
+
+
+ ins = TodoInstruction()
+
+ with self.assertRaisesRegex(NotImplementedError, 'unexpected NULL value as encoding'):
+ print(ins.encoding)
+
+ with self.assertRaisesRegex(NotImplementedError, 'unexpected NULL value as keyword'):
+ print(ins.keyword)
+
+
+ class CustomInstruction(ArchInstruction):
+
+ def __init__(self):
+ super().__init__(0x123)
+
+ def _get_encoding(self):
+ return 'custom'
+
+ def _get_keyword(self):
+ return 'kw'
+
+
+ ins = CustomInstruction()
+
+ self.assertEqual('custom', ins.encoding)
+ self.assertEqual('kw', ins.keyword)
diff --git a/tests/arch/operand.py b/tests/arch/operand.py
new file mode 100644
index 0000000..e8df8b5
--- /dev/null
+++ b/tests/arch/operand.py
@@ -0,0 +1,72 @@
+
+import pychrysalide
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.arch import ArchOperand
+from pychrysalide.glibext import HashableObject, StringBuilder
+
+
+class TestOperand(ChrysalideTestCase):
+ """TestCase for arch.ArchOperand."""
+
+
+ def testAbstractClass(self):
+ """Forbid operand class instance."""
+
+ with self.assertRaisesRegex(RuntimeError, 'pychrysalide.arch.ArchOperand is an abstract class'):
+ pc = ArchOperand()
+
+
+ def testStringBuilderMethodsOverriding(self):
+ """Override the StringBuilder interface provided by native implementations."""
+
+ class MyOperand(ArchOperand, StringBuilder):
+
+ def __init__(self):
+ super().__init__(self)
+
+ def _to_string(self, flags=0):
+ return 'my-op'
+
+ op = MyOperand()
+
+ self.assertEqual(op.to_string(), 'my-op')
+ self.assertEqual(str(op), 'my-op')
+ self.assertEqual(f'{op}', 'my-op')
+
+
+ def testHashableObjectMethods(self):
+ """Test the HashableObject methods implemantation for operands."""
+
+ # Pas d'implementation de particulière de HashableObject,
+ # c'est donc la définition d'implémentation d'ArchOperand
+ # qui s'applique.
+
+ # Spécificité de l'implémentation GLib : hash 32 bits
+
+ class DefaultHashableOperand(ArchOperand):
+ pass
+
+ def_op = DefaultHashableOperand()
+
+ h = hash(def_op)
+
+ self.assertEqual(0, h & ~0xffffffff)
+
+
+ # Définition particulière de l'opérande, sur la base de
+ # l'implémentation parente.
+
+ class CustomHashableOperand(ArchOperand, HashableObject):
+
+ def _hash(self):
+ h = self.parent_hash()
+ h &= ~0xffff
+ return h
+
+ cust_op = CustomHashableOperand()
+
+ h = hash(cust_op)
+
+ self.assertEqual(0, h & 0xffff)
+ self.assertEqual(0, h & ~0xffffffff)
diff --git a/tests/arch/operands/immediate.py b/tests/arch/operands/immediate.py
index 74b8069..c3fcb84 100644
--- a/tests/arch/operands/immediate.py
+++ b/tests/arch/operands/immediate.py
@@ -1,35 +1,59 @@
-#!/usr/bin/python3-dbg
-# -*- coding: utf-8 -*-
-
import pychrysalide
-from chrysacase import ChrysalideTestCase
-from pychrysalide import arch
-from pychrysalide.arch import ImmOperand
+from chrysacase import ChrysalideTestCase
+from pychrysalide import MemoryDataSize
+from pychrysalide.arch.operands import ImmediateOperand
+from pychrysalide.glibext import StringBuilder
class TestImmediate(ChrysalideTestCase):
- """TestCase for arch.ImmOperand."""
+ """TestCase for arch.ImmediateOperand."""
+
+
+ def testBasicImmediate(self):
+ """Check basic properties of immediate values."""
+
+ imm = ImmediateOperand(MemoryDataSize._32_BITS_UNSIGNED, 0x123)
+
+ self.assertEqual(imm.size, MemoryDataSize._32_BITS_UNSIGNED)
+ self.assertEqual(imm.value, 0x123)
+ self.assertFalse(imm.is_negative)
+
+
+ def testStringBuilderForImmediatesOverriding(self):
+ """Override the StringBuilder interface for immediate values."""
+
+ class MyImmOperand(ImmediateOperand, StringBuilder):
+
+ def __init__(self):
+ super().__init__(MemoryDataSize._32_BITS_UNSIGNED, 0x123)
+
+ def _to_string(self, flags=0):
+ return 'NaN'
+
+ op = MyImmOperand()
+
+ self.assertEqual(op.to_string(), 'NaN')
+ self.assertEqual(str(op), 'NaN')
+ self.assertEqual(f'{op}', 'NaN')
def validateValue(self, value, size, padding, strings):
"""Check all kinds of things with a given immediate operand."""
- display = [
- ImmOperand.IOD_BIN, ImmOperand.IOD_OCT,
- ImmOperand.IOD_DEC,
- ImmOperand.IOD_HEX
- ]
+ for d in strings.keys():
- for d in display:
-
- op = ImmOperand(size, value)
+ op = ImmediateOperand(size, value)
self.assertTrue(op.size == size)
self.assertTrue(op.value == value)
- op.padding = padding
+ if padding:
+ op.set_flag(ImmediateOperand.ImmOperandFlag.ZERO_PADDING)
+ else:
+ op.unset_flag(ImmediateOperand.ImmOperandFlag.ZERO_PADDING_BY_DEFAULT)
+
op.display = d
string = op.to_string()
@@ -40,23 +64,23 @@ class TestImmediate(ChrysalideTestCase):
"""Run sanity checks on immediate operand with value 1."""
strings = {
- ImmOperand.IOD_BIN: 'b1',
- ImmOperand.IOD_OCT: '01',
- ImmOperand.IOD_DEC: '1',
- ImmOperand.IOD_HEX: '0x1'
+ ImmediateOperand.ImmOperandDisplay.BIN: 'b1',
+ ImmediateOperand.ImmOperandDisplay.OCT: '01',
+ ImmediateOperand.ImmOperandDisplay.DEC: '1',
+ ImmediateOperand.ImmOperandDisplay.HEX: '0x1'
}
- self.validateValue(1, arch.MDS_8_BITS_UNSIGNED, False, strings)
+ self.validateValue(1, pychrysalide.MemoryDataSize._8_BITS_UNSIGNED, False, strings)
def testByteOnePadded(self):
"""Run sanity checks on immediate operand with padded value 1."""
strings = {
- ImmOperand.IOD_BIN: 'b00000001',
- ImmOperand.IOD_OCT: '01',
- ImmOperand.IOD_DEC: '1',
- ImmOperand.IOD_HEX: '0x01'
+ ImmediateOperand.ImmOperandDisplay.BIN: 'b00000001',
+ ImmediateOperand.ImmOperandDisplay.OCT: '01',
+ ImmediateOperand.ImmOperandDisplay.DEC: '1',
+ ImmediateOperand.ImmOperandDisplay.HEX: '0x01'
}
- self.validateValue(1, arch.MDS_8_BITS_UNSIGNED, True, strings)
+ self.validateValue(1, pychrysalide.MemoryDataSize._8_BITS_UNSIGNED, True, strings)
diff --git a/tests/common/leb128.py b/tests/common/leb128.py
index db3013e..037af4d 100644
--- a/tests/common/leb128.py
+++ b/tests/common/leb128.py
@@ -1,7 +1,6 @@
from chrysacase import ChrysalideTestCase
from pychrysalide.common import pack_uleb128, unpack_uleb128, pack_leb128, unpack_leb128
-from pychrysalide.common import PackedBuffer
class TestLEB128Values(ChrysalideTestCase):
@@ -16,34 +15,30 @@ class TestLEB128Values(ChrysalideTestCase):
128: b'\x80\x01',
}
- for value, encoding in cases.items():
-
- pbuf = PackedBuffer()
+ # Lecture depuis des blocs individuels
- status = pack_uleb128(value, pbuf)
- self.assertTrue(status)
+ for value, encoding in cases.items():
- self.assertEqual(pbuf.payload_length, len(encoding))
+ self.assertEqual(pack_uleb128(value), encoding)
- pbuf.rewind()
+ v, r = unpack_uleb128(encoding)
- got = pbuf.extract(len(encoding))
+ self.assertEqual(value, v)
+ self.assertEqual(b'', r)
- self.assertEqual(got, encoding)
+ # Lecture depuis un bloc commun
- self.assertFalse(pbuf.more_data)
+ data = b''.join(cases.values())
- for value, encoding in cases.items():
+ values = []
- pbuf = PackedBuffer()
- pbuf.extend(encoding, False)
+ while len(data) > 0:
- pbuf.rewind()
+ val, data = unpack_uleb128(data)
- got = unpack_uleb128(pbuf)
- self.assertIsNotNone(got)
+ values.append(val)
- self.assertEqual(got, value)
+ self.assertEqual(values, [ k for k in cases.keys() ])
def testSignedLeb128Encoding(self):
@@ -55,54 +50,39 @@ class TestLEB128Values(ChrysalideTestCase):
-9001: b'\xd7\xb9\x7f',
}
- for value, encoding in cases.items():
+ # Lecture depuis des blocs individuels
- pbuf = PackedBuffer()
+ for value, encoding in cases.items():
- status = pack_leb128(value, pbuf)
- self.assertTrue(status)
+ self.assertEqual(pack_leb128(value), encoding)
- self.assertEqual(pbuf.payload_length, len(encoding))
+ v, r = unpack_leb128(encoding)
- pbuf.rewind()
+ self.assertEqual(value, v)
+ self.assertEqual(b'', r)
- got = pbuf.extract(len(encoding))
+ # Lecture depuis un bloc commun
- self.assertEqual(got, encoding)
+ data = b''.join(cases.values())
- self.assertFalse(pbuf.more_data)
+ values = []
- for value, encoding in cases.items():
+ while len(data) > 0:
- pbuf = PackedBuffer()
- pbuf.extend(encoding, False)
+ val, data = unpack_leb128(data)
- pbuf.rewind()
+ values.append(val)
- got = unpack_leb128(pbuf)
- self.assertIsNotNone(got)
-
- self.assertEqual(got, value)
+ self.assertEqual(values, [ k for k in cases.keys() ])
def testTooBigLeb128Encodings(self):
"""Prevent overflow for LEB128 values."""
- pbuf = PackedBuffer()
- pbuf.extend(b'\x80' * 10 + b'\x7f', False)
-
- pbuf.rewind()
-
- got = unpack_uleb128(pbuf)
-
- self.assertIsNone(got)
-
- pbuf = PackedBuffer()
- pbuf.extend(b'\x80' * 10 + b'\x7f', False)
-
- pbuf.rewind()
+ v = unpack_uleb128(b'\x80' * 10 + b'\x7f')
- got = unpack_leb128(pbuf)
+ self.assertIsNone(v)
- self.assertIsNone(got)
+ v = unpack_leb128(b'\x80' * 10 + b'\x7f')
+ self.assertIsNone(v)
diff --git a/tests/constval.py b/tests/constval.py
deleted file mode 100644
index eafb8d3..0000000
--- a/tests/constval.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/python3-dbg
-# -*- coding: utf-8 -*-
-
-
-from chrysacase import ChrysalideTestCase
-from pychrysalide import PyConstvalObject
-from pychrysalide.arch import ArchInstruction
-import pickle
-
-
-class TestConstVal(ChrysalideTestCase):
- """TestCase for PyConstvalObject."""
-
-
- def testCreation(self):
- """Validate PyConstvalObject creation from Python."""
-
- cst = PyConstvalObject(123, 'XXX')
-
- self.assertEqual(cst, 123)
-
- self.assertEqual(str(cst), 'XXX')
-
-
- def testString(self):
- """Validate the PyConstvalObject implementation."""
-
- self.assertEqual(ArchInstruction.ILT_JUMP, 1)
-
- self.assertEqual(str(ArchInstruction.ILT_JUMP), 'ILT_JUMP')
-
-
- def testStorage(self):
- """Ensure PyConstvalObject instances are storable."""
-
- cst = ArchInstruction.ILT_JUMP
-
- data = pickle.dumps(cst)
-
- cst = pickle.loads(data)
-
- self.assertEqual(cst, ArchInstruction.ILT_JUMP)
-
- self.assertEqual(str(cst), 'ILT_JUMP')
diff --git a/tests/glibext/comparable.py b/tests/glibext/comparable.py
new file mode 100644
index 0000000..48291ca
--- /dev/null
+++ b/tests/glibext/comparable.py
@@ -0,0 +1,132 @@
+
+import gi
+
+from chrysacase import ChrysalideTestCase
+from gi.repository import GObject
+from pychrysalide.glibext import ComparableObject
+
+
+class TestStringBuilder(ChrysalideTestCase):
+ """Test cases for pychrysalide.glibext.ComparableObject."""
+
+
+ def testComparableObjectCreation(self):
+ """Create objects with ComparableObject interface."""
+
+ with self.assertRaisesRegex(NotImplementedError, 'ComparableObject can not be constructed'):
+
+ co = ComparableObject()
+
+
+ class NewComparableObjectImplem(gi._gi.GObject, ComparableObject):
+ pass
+
+ nco = NewComparableObjectImplem()
+
+ self.assertIsNotNone(nco)
+
+
+ class NewComparableObjectImplem2(GObject.Object, ComparableObject):
+ pass
+
+ nco2 = NewComparableObjectImplem()
+
+ self.assertIsNotNone(nco2)
+
+
+ def testComparableObjectMethods(self):
+ """Test the ComparableObject methods."""
+
+ class BasicComparableObjectImplem(GObject.Object, ComparableObject):
+
+ def __init__(self, val):
+ super().__init__()
+ self._val = val
+
+ def _compare(self, other):
+ if self._val < other._val:
+ status = -1
+ elif self._val > other._val:
+ status = 1
+ else:
+ status = 0
+ return status
+
+
+ a = BasicComparableObjectImplem(123)
+ b = BasicComparableObjectImplem(456)
+
+ self.assertTrue(a <= b)
+
+ # Sans l'action de inherit_interface_slots(), c'est pygobject_richcompare() qui est appelée,
+ # laquelle compare simplement les adresses des pointeurs
+
+ c = BasicComparableObjectImplem(789)
+ d = BasicComparableObjectImplem(234)
+
+ self.assertTrue(c > d)
+
+
+ def testComparableObjectExceptions(self):
+ """Raise exceptions from the ComparableObject interface as expected."""
+
+
+ class OtherComparableObject(GObject.Object, ComparableObject):
+ pass
+
+ other = OtherComparableObject()
+
+
+ class BadComparableObjectImplem(GObject.Object, ComparableObject):
+ pass
+
+ obj = BadComparableObjectImplem()
+
+
+ with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_compare'"):
+
+ s = obj < other
+
+
+ class BadComparableObjectImplem2(GObject.Object, ComparableObject):
+
+ def _compare(self, other):
+ return 'AAA'
+
+ obj2 = BadComparableObjectImplem2()
+
+
+ with self.assertRaisesRegex(TypeError, 'comparison status has to be a signed integer'):
+
+ s = obj2 < other
+
+
+ class BadComparableObjectImplem3a(GObject.Object, ComparableObject):
+
+ def _compare(self, other):
+ return 123
+
+ class BadComparableObjectImplem3b(BadComparableObjectImplem3a, ComparableObject):
+
+ def _compare(self, other):
+ return self.parent_compare()
+
+ obj3 = BadComparableObjectImplem3b()
+
+
+ with self.assertRaisesRegex(RuntimeError, 'object parent is not a native type'):
+
+ s = obj3 < other
+
+
+ class BadComparableObjectImplem4(GObject.Object, ComparableObject):
+
+ def _compare(self, other):
+ raise Exception('error')
+
+ obj4 = BadComparableObjectImplem4()
+
+
+ with self.assertRaisesRegex(Exception, 'error'):
+
+ s = obj4 < other
diff --git a/tests/glibext/configuration.py b/tests/glibext/configuration.py
deleted file mode 100644
index 880b445..0000000
--- a/tests/glibext/configuration.py
+++ /dev/null
@@ -1,106 +0,0 @@
-
-import gi
-gi.require_version('Gdk', '3.0')
-from gi.repository import Gdk
-
-from chrysacase import ChrysalideTestCase
-from pychrysalide.glibext import ConfigParam, GenConfig
-
-
-class TestConfiguration(ChrysalideTestCase):
- """TestCase for configuration related items.*"""
-
-
- def testCfgParamValues(self):
- """Set and unset configuration parameter values."""
-
- color = Gdk.RGBA()
- color.parse('#3465A4')
-
- param = ConfigParam('config.color', ConfigParam.ConfigParamType.COLOR, color)
-
- self.assertEqual(param.value, color)
-
- param.make_empty()
-
- void = Gdk.RGBA(red=0, green=0, blue=0, alpha=0)
- self.assertEqual(param.value, void)
-
- param.value = color
-
- self.assertEqual(param.value, color)
-
-
- def testCfgParamStates(self):
- """Validate all states of an evolving parameter."""
-
- param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER)
-
- self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.DEFAULT)
-
- param.make_empty()
-
- self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.DEFAULT)
-
- param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER, 0x123)
-
- self.assertEqual(param.value, 0x123)
-
- self.assertEqual(param.state, ConfigParam.ConfigParamState.DEFAULT)
-
- param.make_empty()
-
- self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.CHANGED)
-
- param.value = 0x1
-
- self.assertEqual(param.state, ConfigParam.ConfigParamState.CHANGED)
-
- param.reset()
-
- self.assertEqual(param.state, ConfigParam.ConfigParamState.DEFAULT)
-
-
- def testCfgParamDesc(self):
- """Export types and states as strings when needed."""
-
- param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER)
-
- self.assertTrue('|' in str(param.state))
-
- self.assertTrue('.' in str(param.type))
-
-
- def testConfiguration(self):
- """Feed and browse a basic configuration."""
-
- config = GenConfig()
- self.assertIsNotNone(config)
- self.assertIsNone(config.filename)
-
- for i in range(5):
- param = ConfigParam('config.int.%u' % i, ConfigParam.ConfigParamType.INTEGER, i)
- config.add(param)
-
- chain = ''
-
- for p in config.params:
- chain += '%u' % p.value
-
- self.assertTrue(chain == ''.join([ '%u' % i for i in range(5) ]))
-
- found = config.search('config.int.3')
- self.assertTrue(found.value == 3)
-
- found = config.search('config.int.33')
- self.assertIsNone(found)
-
- for p in config.params:
- p.value *= 10
-
- chain = ''
-
- for p in config.params:
- chain += '%u' % p.value
-
- self.assertTrue(chain == ''.join([ '%u' % (i * 10) for i in range(5) ]))
diff --git a/tests/glibext/hashable.py b/tests/glibext/hashable.py
new file mode 100644
index 0000000..07f22e3
--- /dev/null
+++ b/tests/glibext/hashable.py
@@ -0,0 +1,190 @@
+
+import gi
+
+from chrysacase import ChrysalideTestCase
+from gi.repository import GObject
+from pychrysalide.glibext import HashableObject
+
+
+class TestStringBuilder(ChrysalideTestCase):
+ """Test cases for pychrysalide.glibext.HashableObject."""
+
+
+ def testHashableObjectCreation(self):
+ """Create objects with HashableObject interface."""
+
+ with self.assertRaisesRegex(NotImplementedError, 'HashableObject can not be constructed'):
+
+ ho = HashableObject()
+
+
+ class NewHashableObjectImplem(gi._gi.GObject, HashableObject):
+ pass
+
+ nho = NewHashableObjectImplem()
+
+ self.assertIsNotNone(nho)
+
+
+ class NewHashableObjectImplem2(GObject.Object, HashableObject):
+ pass
+
+ nho2 = NewHashableObjectImplem()
+
+ self.assertIsNotNone(nho2)
+
+
+ def testHashableObjectMethods(self):
+ """Test the HashableObject methods."""
+
+ class BasicHashableObjectImplem(gi._gi.GObject, HashableObject):
+
+ def __init__(self, val):
+ super().__init__()
+ self._val = val
+
+ def _hash(self):
+ return self._val
+
+ value = 1234
+
+ ho = BasicHashableObjectImplem(value)
+
+ self.assertEqual(hash(ho), value)
+
+
+ class BasicHashableObjectImplem2(GObject.Object, HashableObject):
+
+ def __init__(self, val):
+ super().__init__()
+ self._val = val
+
+ def _hash(self):
+ return self._val
+
+ value = 5678
+
+ ho2 = BasicHashableObjectImplem2(value)
+
+ self.assertEqual(hash(ho2), value)
+
+
+ def testCascadingHashableObjectImplementations(self):
+ """Request the hash from the object parent for a full computing."""
+
+
+ class CascadingHashableObjectFullImplemA(GObject.Object, HashableObject):
+
+ def _hash(self):
+ return 1
+
+ class CascadingHashableObjectFullImplemB(CascadingHashableObjectFullImplemA, HashableObject):
+
+ def _hash(self):
+ return super()._hash() * 2
+
+ class CascadingHashableObjectFullImplemC(CascadingHashableObjectFullImplemB, HashableObject):
+
+ def _hash(self):
+ return super()._hash() * 3
+
+
+ obj_a = CascadingHashableObjectFullImplemA()
+
+ obj_b = CascadingHashableObjectFullImplemB()
+
+ obj_c = CascadingHashableObjectFullImplemC()
+
+
+ self.assertEqual(hash(obj_a), 1)
+ self.assertEqual(hash(obj_b), 2)
+ self.assertEqual(hash(obj_c), 6)
+
+
+ class CascadingHashableObjectPartialImplemA(GObject.Object, HashableObject):
+
+ def _hash(self):
+ return 1
+
+ class CascadingHashableObjectPartialImplemB(CascadingHashableObjectPartialImplemA):
+ pass
+
+ class CascadingHashableObjectPartialImplemC(CascadingHashableObjectPartialImplemB, HashableObject):
+
+ def _hash(self):
+ return super()._hash() * 3
+
+
+ obj_a = CascadingHashableObjectPartialImplemA()
+
+ obj_b = CascadingHashableObjectPartialImplemB()
+
+ obj_c = CascadingHashableObjectPartialImplemC()
+
+
+ self.assertEqual(hash(obj_a), 1)
+ self.assertEqual(hash(obj_b), 1)
+ self.assertEqual(hash(obj_c), 3)
+
+
+ def testHashableObjectExceptions(self):
+ """Raise exceptions from the HashableObject interface as expected."""
+
+ class BadHashableObjectImplem(GObject.Object, HashableObject):
+ pass
+
+ obj = BadHashableObjectImplem()
+
+
+ with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_hash'"):
+
+ h = hash(obj)
+
+
+ with self.assertRaisesRegex(TypeError, 'object parent does not implement the HashableObject interface'):
+
+ h = obj.parent_hash()
+
+
+ class BadHashableObjectImplem2(GObject.Object, HashableObject):
+
+ def _hash(self):
+ return 'AAA'
+
+ obj2 = BadHashableObjectImplem2()
+
+
+ with self.assertRaisesRegex(TypeError, 'computed hash value has to be an unsigned integer'):
+
+ h = hash(obj2)
+
+
+ class BadHashableObjectImplem3a(GObject.Object, HashableObject):
+
+ def _hash(self):
+ return 123
+
+ class BadHashableObjectImplem3b(BadHashableObjectImplem3a, HashableObject):
+
+ def _hash(self):
+ return self.parent_hash()
+
+ obj3 = BadHashableObjectImplem3b()
+
+
+ with self.assertRaisesRegex(RuntimeError, 'object parent is not a native type'):
+
+ h = hash(obj3)
+
+
+ class BadHashableObjectImplem4(GObject.Object, HashableObject):
+
+ def _hash(self):
+ raise Exception('error')
+
+ obj4 = BadHashableObjectImplem4()
+
+
+ with self.assertRaisesRegex(Exception, 'error'):
+
+ h = hash(obj4)
diff --git a/tests/glibext/re.chrysalide.tests.secstorage.gschema.xml b/tests/glibext/re.chrysalide.tests.secstorage.gschema.xml
new file mode 100644
index 0000000..6afa96b
--- /dev/null
+++ b/tests/glibext/re.chrysalide.tests.secstorage.gschema.xml
@@ -0,0 +1,15 @@
+<schemalist>
+
+ <schema id="re.chrysalide.tests.secstorage" path="/re/chrysalide/tests/secstorage/">
+
+ <key name="salt" type="ay">
+ <default>[]</default>
+ </key>
+
+ <key name="master" type="ay">
+ <default>[]</default>
+ </key>
+
+ </schema>
+
+</schemalist>
diff --git a/tests/glibext/secstorage.py b/tests/glibext/secstorage.py
new file mode 100644
index 0000000..5b8f680
--- /dev/null
+++ b/tests/glibext/secstorage.py
@@ -0,0 +1,153 @@
+
+import gi
+import os
+import subprocess
+
+from chrysacase import ChrysalideTestCase
+from gi.repository import Gio, GLib
+from pychrysalide.glibext import SecretStorage
+
+
+class TestSecretStorage(ChrysalideTestCase):
+ """TestCase for secret storage features."""
+
+ @classmethod
+ def setUpClass(cls):
+
+ super(TestSecretStorage, cls).setUpClass()
+
+ cls.log('Creating GSettings schema...')
+
+ path = os.path.dirname(os.path.realpath(__file__))
+
+ subprocess.run([ 'glib-compile-schemas', path ])
+
+
+ @classmethod
+ def tearDownClass(cls):
+
+ super(TestSecretStorage, cls).tearDownClass()
+
+ cls.log('Removing compiled GSettings schema...')
+
+ path = os.path.dirname(os.path.realpath(__file__))
+
+ filename = os.path.join(path, 'gschemas.compiled')
+
+ if os.path.exists(filename):
+ os.remove(filename)
+
+
+ def _get_settings(self, sid):
+ """Provide local GSettings instance."""
+
+ path = os.path.dirname(os.path.realpath(__file__))
+
+ source = Gio.SettingsSchemaSource.new_from_directory(path, None, True)
+
+ schema = Gio.SettingsSchemaSource.lookup(source, sid, False)
+
+ settings = Gio.Settings.new_full(schema, None, None)
+
+ return settings
+
+
+ def testMasterKeyDefinition(self):
+ """Check for cryptographic parameters for secret storage."""
+
+ settings = self._get_settings('re.chrysalide.tests.secstorage')
+
+ storage = SecretStorage(settings)
+
+ settings.reset('master')
+
+ self.assertEqual(len(settings.get_value('master').unpack()), 0)
+
+ self.assertFalse(storage.has_key)
+
+ settings.set_value('master', GLib.Variant('ay', b'ABC'))
+
+ self.assertFalse(storage.has_key)
+
+ settings.set_value('master', GLib.Variant('ay', b'A' * 23))
+
+ self.assertTrue(storage.has_key)
+
+
+ def testMasterKeyCreation(self):
+ """Create and update cryptographic parameters for secret storage."""
+
+ settings = self._get_settings('re.chrysalide.tests.secstorage')
+
+ storage = SecretStorage(settings)
+
+ settings.reset('salt')
+ settings.reset('master')
+
+ self.assertFalse(storage.has_key)
+
+ status = storage.set_password('')
+
+ self.assertTrue(status);
+
+ self.assertTrue(storage.has_key)
+ self.assertTrue(storage.is_locked)
+
+ status = storage.unlock('')
+
+ self.assertTrue(status)
+
+ self.assertFalse(storage.is_locked)
+
+ storage.lock()
+
+ self.assertTrue(storage.is_locked)
+
+ status = storage.unlock('XXX')
+
+ self.assertFalse(status)
+
+ self.assertTrue(storage.is_locked)
+
+
+ def testDataEncryption(self):
+ """Encrypt and decrypt data with the secret storage."""
+
+ settings = self._get_settings('re.chrysalide.tests.secstorage')
+
+ storage = SecretStorage(settings)
+
+ settings.reset('salt')
+ settings.reset('master')
+
+ status = storage.set_password('<s3cUre>')
+
+ self.assertTrue(status);
+
+ status = storage.unlock('<s3cUre>')
+
+ self.assertTrue(status)
+
+
+ original = b'ABC'
+
+ encrypted = storage.encrypt_data(original)
+
+ self.assertIsNotNone(encrypted)
+
+ plain = storage.decrypt_data(encrypted)
+
+ self.assertIsNotNone(plain)
+ self.assertEqual(original, plain)
+
+
+ original = b'A' * 136
+
+ encrypted = storage.encrypt_data(original)
+
+ self.assertIsNotNone(encrypted)
+
+ plain = storage.decrypt_data(encrypted)
+
+ self.assertIsNotNone(plain)
+ self.assertEqual(original, plain)
diff --git a/tests/glibext/singleton.py b/tests/glibext/singleton.py
index 4588ae5..712aece 100644
--- a/tests/glibext/singleton.py
+++ b/tests/glibext/singleton.py
@@ -1,21 +1,24 @@
+import gi
+
from chrysacase import ChrysalideTestCase
from gi.repository import GObject
-from pychrysalide.glibext import SingletonCandidate, SingletonFactory
+from pychrysalide.glibext import ComparableObject, HashableObject, SingletonCandidate, SingletonFactory
class TestSingleton(ChrysalideTestCase):
"""Test cases for pychrysalide.glibext.SingletonFactory."""
- def testSingletonCreation(self):
- """Create singleton objects."""
+ def testSingletonCandidateCreation(self):
+ """Create objects with SingletonCandidate interface."""
with self.assertRaisesRegex(NotImplementedError, 'SingletonCandidate can not be constructed'):
sc = SingletonCandidate()
- class NewSingletonImplem(GObject.Object, SingletonCandidate):
+
+ class NewSingletonImplem(gi._gi.GObject, HashableObject, ComparableObject, SingletonCandidate):
pass
nsi = NewSingletonImplem()
@@ -23,121 +26,132 @@ class TestSingleton(ChrysalideTestCase):
self.assertIsNotNone(nsi)
- def testFactoryCreation(self):
- """Create singleton factories."""
+ class NewSingletonImplem2(GObject.Object, HashableObject, ComparableObject, SingletonCandidate):
+ pass
+
+ nsi2 = NewSingletonImplem2()
- sf = SingletonFactory()
+ self.assertIsNotNone(nsi2)
- self.assertIsNotNone(sf)
- class MyFactory(SingletonFactory):
- pass
+ # def testFactoryCreation(self):
+ # """Create singleton factories."""
+
+ # sf = SingletonFactory()
+
+ # self.assertIsNotNone(sf)
+
+ # class MyFactory(SingletonFactory):
+ # pass
+
+ # msf = MyFactory()
+
+ # self.assertIsNotNone(msf)
+
- msf = MyFactory()
- self.assertIsNotNone(msf)
- def testSingletonMethods(self):
- """Test the singleton methods."""
+ # def testSingletonMethods(self):
+ # """Test the singleton methods."""
- class IntegerCacheImplem(GObject.Object, SingletonCandidate):
+ # class IntegerCacheImplem(GObject.Object, SingletonCandidate):
- def __init__(self, val):
- super().__init__()
- self._val = val
+ # def __init__(self, val):
+ # super().__init__()
+ # self._val = val
- def _list_inner_instances(self):
- return ()
+ # def _list_inner_instances(self):
+ # return ()
- def __hash__(self):
- return hash('common-key')
+ # def __hash__(self):
+ # return hash('common-key')
- def __eq__(self, other):
- return self._val == other._val
+ # def __eq__(self, other):
+ # return self._val == other._val
- val_0 = IntegerCacheImplem(0)
- val_0_bis = IntegerCacheImplem(0)
- val_1 = IntegerCacheImplem(1)
+ # val_0 = IntegerCacheImplem(0)
+ # val_0_bis = IntegerCacheImplem(0)
+ # val_1 = IntegerCacheImplem(1)
- self.assertEqual(hash(val_0), hash(val_0_bis))
- self.assertEqual(hash(val_0), hash(val_1))
+ # self.assertEqual(hash(val_0), hash(val_0_bis))
+ # self.assertEqual(hash(val_0), hash(val_1))
- self.assertEqual(val_0.hash(), val_0_bis.hash())
- self.assertEqual(val_0.hash(), val_1.hash())
+ # self.assertEqual(val_0.hash(), val_0_bis.hash())
+ # self.assertEqual(val_0.hash(), val_1.hash())
- self.assertTrue(val_0 == val_0_bis)
- self.assertFalse(val_0 == val_1)
+ # self.assertTrue(val_0 == val_0_bis)
+ # self.assertFalse(val_0 == val_1)
- def testSingletonFootprint(self):
- """Check for singleton memory footprint."""
+ # def testSingletonFootprint(self):
+ # """Check for singleton memory footprint."""
- sf = SingletonFactory()
+ # sf = SingletonFactory()
- class IntegerCacheImplem(GObject.Object, SingletonCandidate):
+ # class IntegerCacheImplem(GObject.Object, SingletonCandidate):
- def __init__(self, val):
- super().__init__()
- self._val = val
+ # def __init__(self, val):
+ # super().__init__()
+ # self._val = val
- def _list_inner_instances(self):
- return ()
+ # def _list_inner_instances(self):
+ # return ()
- def __hash__(self):
- return hash('common-key')
+ # def __hash__(self):
+ # return hash('common-key')
- def __eq__(self, other):
- return self._val == other._val
+ # def __eq__(self, other):
+ # return self._val == other._val
- def _set_read_only(self):
- pass
+ # def _set_read_only(self):
+ # pass
- val_0 = IntegerCacheImplem(0)
- val_0_bis = IntegerCacheImplem(0)
- val_1 = IntegerCacheImplem(1)
+ # val_0 = IntegerCacheImplem(0)
+ # val_0_bis = IntegerCacheImplem(0)
+ # val_1 = IntegerCacheImplem(1)
- obj = sf.get_instance(val_0)
+ # obj = sf.get_instance(val_0)
- self.assertTrue(obj is val_0)
+ # self.assertTrue(obj is val_0)
- obj = sf.get_instance(val_0_bis)
+ # obj = sf.get_instance(val_0_bis)
- self.assertTrue(obj is val_0)
+ # self.assertTrue(obj is val_0)
- obj = sf.get_instance(val_1)
+ # obj = sf.get_instance(val_1)
- self.assertTrue(obj is val_1)
+ # self.assertTrue(obj is val_1)
- self.assertEqual(len(obj.inner_instances), 0)
+ # self.assertEqual(len(obj.inner_instances), 0)
- class MasterCacheImplem(GObject.Object, SingletonCandidate):
+ # class MasterCacheImplem(GObject.Object, SingletonCandidate):
- def __init__(self, children):
- super().__init__()
- self._children = children
+ # def __init__(self, children):
+ # super().__init__()
+ # self._children = children
- def _list_inner_instances(self):
- return self._children
+ # def _list_inner_instances(self):
+ # return self._children
- def _update_inner_instances(self, instances):
- self._children = instances
+ # def _update_inner_instances(self, instances):
+ # self._children = instances
- def __hash__(self):
- return hash('master-key')
+ # def __hash__(self):
+ # return hash('master-key')
- def __eq__(self, other):
- return False
+ # def __eq__(self, other):
+ # return False
- def _set_read_only(self):
- pass
+ # def _set_read_only(self):
+ # pass
- master = MasterCacheImplem(( val_0_bis, val_1 ))
+ # master = MasterCacheImplem(( val_0_bis, val_1 ))
- obj = sf.get_instance(master)
+ # obj = sf.get_instance(master)
- self.assertTrue(obj.inner_instances[0] is val_0)
+ # self.assertTrue(obj.inner_instances[0] is val_0)
- self.assertTrue(obj.inner_instances[1] is val_1)
+ # self.assertTrue(obj.inner_instances[1] is val_1)
diff --git a/tests/glibext/storage.py b/tests/glibext/storage.py
new file mode 100644
index 0000000..b60377a
--- /dev/null
+++ b/tests/glibext/storage.py
@@ -0,0 +1,74 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.glibext import ObjectStorage, SerializableObject
+import gi
+import os
+import tempfile
+
+
+class TestObjectStorage(ChrysalideTestCase):
+ """TestCase for analysis.storage."""
+
+ @classmethod
+ def setUpClass(cls):
+
+ super(TestObjectStorage, cls).setUpClass()
+
+ _, cls._tmp_filename = tempfile.mkstemp()
+
+ cls.log('Using temporary filename "%s"' % cls._tmp_filename)
+
+
+ @classmethod
+ def tearDownClass(cls):
+
+ super(TestObjectStorage, cls).tearDownClass()
+
+ cls.log('Delete filename "%s"' % cls._tmp_filename)
+
+ os.unlink(cls._tmp_filename)
+
+
+ def testGenericStorage(self):
+ """Store and load basic objects."""
+
+
+ class SimpleObject(gi._gi.GObject, SerializableObject):
+
+ def __init__(self, b=None):
+ super().__init__()
+ self._b = b
+
+ def _load(self, storage, fd):
+ assert(self._b is None)
+ self._b = os.read(fd, 1)[0]
+ return True
+
+ def _store(self, storage, fd):
+ os.write(fd, bytes([ self._b ]))
+ return True
+
+ def __eq__(self, other):
+ return self._b == other._b
+
+
+ # Store
+
+ storage = ObjectStorage('TestStorage', 0, 'my-storage-hash')
+ self.assertIsNotNone(storage)
+
+ so = SimpleObject(0x23)
+
+ pos = storage.store_object('simple', so)
+ self.assertIsNotNone(pos)
+
+ status = storage.store(self._tmp_filename)
+ self.assertTrue(status)
+
+ # Reload
+
+ storage2 = ObjectStorage.load(self._tmp_filename)
+
+ so2 = storage2.load_object('simple', pos)
+
+ self.assertEqual(so, so2)
diff --git a/tests/glibext/strbuilder.py b/tests/glibext/strbuilder.py
index ced405e..72fd5c2 100644
--- a/tests/glibext/strbuilder.py
+++ b/tests/glibext/strbuilder.py
@@ -1,4 +1,6 @@
+import gi
+
from chrysacase import ChrysalideTestCase
from gi.repository import GObject
from pychrysalide.glibext import StringBuilder
@@ -8,22 +10,31 @@ class TestStringBuilder(ChrysalideTestCase):
"""Test cases for pychrysalide.glibext.StringBuilder."""
- def testStringBuilderCreation(self):
+ def ZZZtestStringBuilderCreation(self):
"""Create objects with StringBuilder interface."""
with self.assertRaisesRegex(NotImplementedError, 'StringBuilder can not be constructed'):
- sc = StringBuilder()
+ sb = StringBuilder()
+
- class NewStringBuilderImplem(GObject.Object, StringBuilder):
+ class NewStringBuilderImplem(gi._gi.GObject, StringBuilder):
pass
- nsi = NewStringBuilderImplem()
+ nsb = NewStringBuilderImplem()
+
+ self.assertIsNotNone(nsb)
+
+
+ class NewStringBuilderImplem2(GObject.Object, StringBuilder):
+ pass
- self.assertIsNotNone(nsi)
+ nsb2 = NewStringBuilderImplem()
+ self.assertIsNotNone(nsb2)
- def testStringBuilderMethods(self):
+
+ def ZZZtestStringBuilderMethods(self):
"""Test the StringBuilder methods."""
class BasicStringBuilderImplem(GObject.Object, StringBuilder):
@@ -42,3 +53,62 @@ class TestStringBuilder(ChrysalideTestCase):
self.assertEqual(sb.to_string(), desc)
self.assertEqual(str(sb), desc)
self.assertEqual(f'{sb}', desc)
+
+
+ def testStringBuilderExceptions(self):
+ """Raise exceptions from the StringBuilder interface as expected."""
+
+
+ class BadStringBuilderImplem(GObject.Object, StringBuilder):
+ pass
+
+ obj = BadStringBuilderImplem()
+
+
+ with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_to_string'"):
+
+ s = str(obj)
+
+
+ class BadStringBuilderImplem2(GObject.Object, StringBuilder):
+
+ def _to_string(self, flags=0):
+ return 0xcafe
+
+ obj2 = BadStringBuilderImplem2()
+
+
+ with self.assertRaisesRegex(TypeError, 'object description has to get provided as an UTF-8 string value'):
+
+ s = str(obj2)
+
+
+ class BadStringBuilderImplem3a(GObject.Object, StringBuilder):
+
+ def _to_string(self, flags=0):
+ return 'desc'
+
+ class BadStringBuilderImplem3b(BadStringBuilderImplem3a, StringBuilder):
+
+ def _to_string(self, flags=0):
+ return self.parent_to_string()
+
+ obj3 = BadStringBuilderImplem3b()
+
+
+ with self.assertRaisesRegex(RuntimeError, 'object parent is not a native type'):
+
+ s = str(obj3)
+
+
+ class BadStringBuilderImplem4(GObject.Object, StringBuilder):
+
+ def _to_string(self, flags=0):
+ raise Exception('error')
+
+ obj4 = BadStringBuilderImplem4()
+
+
+ with self.assertRaisesRegex(Exception, 'error'):
+
+ s = str(obj4)
diff --git a/tools/about/build.py b/tools/about/build.py
new file mode 100644
index 0000000..2267492
--- /dev/null
+++ b/tools/about/build.py
@@ -0,0 +1,120 @@
+
+# apt install libcairo2-dev pkg-config python3-dev
+# pip install pycairo
+
+import cairo
+import math
+import sys
+
+from enum import IntEnum
+
+from ttf import create_cairo_font_face_for_file
+
+
+WIDTH = 350
+HEIGHT = 430
+
+
+def deg2rad(degrees):
+ return degrees * (math.pi / 180)
+
+
+class TextAlignment(IntEnum):
+ LEFT = 1
+ CENTER = 2
+ RIGHT = 3
+
+
+def draw_text(ctx, text, pos, fsize, noise, theta = 0.0, align = TextAlignment.CENTER):
+ """Dessine un texte en respectant des propriétées."""
+
+ ctx.save()
+
+ ctx.set_font_size(fsize)
+
+ fascent, fdescent, fheight, fxadvance, fyadvance = ctx.font_extents()
+ x_off, y_off, tw, th = ctx.text_extents(text)[:4]
+
+ if align == TextAlignment.LEFT:
+ nx = 0
+ elif align == TextAlignment.RIGHT:
+ nx = -tw
+ else:
+ nx = -tw / 2.0
+
+ ny = fheight / 2
+
+ ctx.translate(pos[0], pos[1])
+ ctx.rotate(theta)
+ ctx.translate(nx, ny)
+ ctx.move_to(0,0)
+
+ ctx.text_path(text)
+ ctx.set_source_surface(noise, 0, -fheight)
+ ctx.fill_preserve()
+ ctx.set_source_rgb(1.0, 1.0, 1.0)
+ ctx.set_line_width(1)
+ ctx.stroke()
+
+ ctx.restore()
+
+
+if __name__ == '__main__':
+ """Point d'entrée du script."""
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
+
+ cr = cairo.Context(surface)
+
+ face = create_cairo_font_face_for_file('cour10p_b.ttf')
+ cr.set_font_face(face)
+
+ noise = cairo.ImageSurface.create_from_png('noise.png')
+
+ # Type d'édition
+
+ if len(sys.argv) > 2:
+
+ draw_text(cr, sys.argv[2], [ 300, 25 ], 32, noise,
+ theta = deg2rad(270), align = TextAlignment.RIGHT)
+
+ cr.set_source_rgb(0, 0, 0)
+ cr.paint_with_alpha(0.4)
+
+ # Numéro de version
+
+ draw_text(cr, sys.argv[1], [ 149, 10 + 259 + 14 + 42 + 2 ], 23, noise, align=TextAlignment.LEFT)
+
+ cr.set_source_rgb(0, 0, 0)
+ cr.paint_with_alpha(0.5)
+
+ # Logo
+
+ logo = cairo.ImageSurface.create_from_png('logo.png')
+
+ scale_y = 259 / logo.get_height()
+
+ cr.save()
+
+ cr.translate((WIDTH - (logo.get_width() * scale_y)) / 2, 12)
+
+ cr.scale(scale_y, scale_y)
+
+ cr.set_source_surface(logo, 0, 0)
+ cr.paint()
+
+ cr.restore()
+
+ # Titre
+
+ draw_text(cr, 'Chrysalide', [ WIDTH / 2, 10 + 259 + 14 + 4 ], 42, noise)
+
+ # cr.rectangle(265, 30, 10, 10)
+ # cr.set_source_rgb(1, 0, 0)
+ # cr.fill()
+
+ # cr.rectangle(265, 255, 10, 10)
+ # cr.set_source_rgb(1, 0, 0)
+ # cr.fill()
+
+ surface.write_to_png('bg.png')
diff --git a/tools/about/courier-10-pitch-bold_EQ97V.zip b/tools/about/courier-10-pitch-bold_EQ97V.zip
new file mode 100644
index 0000000..0585fe6
--- /dev/null
+++ b/tools/about/courier-10-pitch-bold_EQ97V.zip
Binary files differ
diff --git a/tools/about/courier10point.zip b/tools/about/courier10point.zip
new file mode 100644
index 0000000..82cd0de
--- /dev/null
+++ b/tools/about/courier10point.zip
Binary files differ
diff --git a/tools/about/gen.sh b/tools/about/gen.sh
new file mode 100755
index 0000000..c22ec59
--- /dev/null
+++ b/tools/about/gen.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+
+# Cf. https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script/246128#246128
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+pushd $SCRIPT_DIR > /dev/null
+
+
+# Obtention de la police Courier-10-Pitch-Bold
+# --------------------------------------------
+
+# https://fontsgeek.com/fonts/Courier-10-Pitch-Bold
+# https://fontsgeek.com/terms-and-conditions
+
+# => courier-10-pitch-bold_EQ97V.zip
+
+
+# Courier 10 Pitch font missing after upgrade to 17.04?
+# https://askubuntu.com/questions/914352/courier-10-pitch-font-missing-after-upgrade-to-17-04
+
+# https://groups.google.com/g/trelby/c/CGkpcMBXW9U
+# -> http://www.trelby.org/files/release/font/courier10point.zip
+# --> https://web.archive.org/web/20140326080337/http://www.trelby.org/files/release/font/courier10point.zip
+
+# https://news.ycombinator.com/item?id=18802628
+# -> https://www.trelby.org/assets/courier10point.zip
+
+# => courier10point.zip
+
+if [ ! -f cour10p_b.ttf ]; then
+
+ unzip -p courier10point.zip courier10point/cour10p_b.ttf > cour10p_b.ttf
+
+fi
+
+
+# Construction de l'image de fond
+#--------------------------------
+
+if [ $# -lt 1 -o $# -gt 2 ]; then
+
+ echo "Usage: $0 <version> <edition>"
+ exit 123
+
+fi
+
+python3 ./build.py $*
+
+cp bg.png ../../src/data/images/about-bg.png
+
+popd > /dev/null
diff --git a/tools/about/logo.png b/tools/about/logo.png
new file mode 100644
index 0000000..9bf9969
--- /dev/null
+++ b/tools/about/logo.png
Binary files differ
diff --git a/tools/about/noise.png b/tools/about/noise.png
new file mode 100644
index 0000000..b5d6b91
--- /dev/null
+++ b/tools/about/noise.png
Binary files differ
diff --git a/tools/about/ttf.py b/tools/about/ttf.py
new file mode 100644
index 0000000..eb6c027
--- /dev/null
+++ b/tools/about/ttf.py
@@ -0,0 +1,111 @@
+
+# Source: https://www.cairographics.org/cookbook/freetypepython/
+
+import ctypes as ct
+import cairo
+
+_initialized = False
+def create_cairo_font_face_for_file (filename, faceindex=0, loadoptions=0):
+ "given the name of a font file, and optional faceindex to pass to FT_New_Face" \
+ " and loadoptions to pass to cairo_ft_font_face_create_for_ft_face, creates" \
+ " a cairo.FontFace object that may be used to render text with that font."
+ global _initialized
+ global _freetype_so
+ global _cairo_so
+ global _ft_lib
+ global _ft_destroy_key
+ global _surface
+
+ CAIRO_STATUS_SUCCESS = 0
+ FT_Err_Ok = 0
+
+ if not _initialized:
+ # find shared objects
+ _freetype_so = ct.CDLL("libfreetype.so.6")
+ _cairo_so = ct.CDLL("libcairo.so.2")
+ _cairo_so.cairo_ft_font_face_create_for_ft_face.restype = ct.c_void_p
+ _cairo_so.cairo_ft_font_face_create_for_ft_face.argtypes = [ ct.c_void_p, ct.c_int ]
+ _cairo_so.cairo_font_face_get_user_data.restype = ct.c_void_p
+ _cairo_so.cairo_font_face_get_user_data.argtypes = (ct.c_void_p, ct.c_void_p)
+ _cairo_so.cairo_font_face_set_user_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
+ _cairo_so.cairo_set_font_face.argtypes = [ ct.c_void_p, ct.c_void_p ]
+ _cairo_so.cairo_font_face_status.argtypes = [ ct.c_void_p ]
+ _cairo_so.cairo_font_face_destroy.argtypes = (ct.c_void_p,)
+ _cairo_so.cairo_status.argtypes = [ ct.c_void_p ]
+ # initialize freetype
+ _ft_lib = ct.c_void_p()
+ status = _freetype_so.FT_Init_FreeType(ct.byref(_ft_lib))
+ if status != FT_Err_Ok :
+ raise RuntimeError("Error %d initializing FreeType library." % status)
+ #end if
+
+ class PycairoContext(ct.Structure):
+ _fields_ = \
+ [
+ ("PyObject_HEAD", ct.c_byte * object.__basicsize__),
+ ("ctx", ct.c_void_p),
+ ("base", ct.c_void_p),
+ ]
+ #end PycairoContext
+
+ _surface = cairo.ImageSurface(cairo.FORMAT_A8, 0, 0)
+ _ft_destroy_key = ct.c_int() # dummy address
+ _initialized = True
+ #end if
+
+ ft_face = ct.c_void_p()
+ cr_face = None
+ try :
+ # load FreeType face
+ status = _freetype_so.FT_New_Face(_ft_lib, filename.encode("utf-8"), faceindex, ct.byref(ft_face))
+ if status != FT_Err_Ok :
+ raise RuntimeError("Error %d creating FreeType font face for %s" % (status, filename))
+ #end if
+
+ # create Cairo font face for freetype face
+ cr_face = _cairo_so.cairo_ft_font_face_create_for_ft_face(ft_face, loadoptions)
+ status = _cairo_so.cairo_font_face_status(cr_face)
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename))
+ #end if
+ # Problem: Cairo doesn't know to call FT_Done_Face when its font_face object is
+ # destroyed, so we have to do that for it, by attaching a cleanup callback to
+ # the font_face. This only needs to be done once for each font face, while
+ # cairo_ft_font_face_create_for_ft_face will return the same font_face if called
+ # twice with the same FT Face.
+ # The following check for whether the cleanup has been attached or not is
+ # actually unnecessary in our situation, because each call to FT_New_Face
+ # will return a new FT Face, but we include it here to show how to handle the
+ # general case.
+ if _cairo_so.cairo_font_face_get_user_data(cr_face, ct.byref(_ft_destroy_key)) == None :
+ status = _cairo_so.cairo_font_face_set_user_data \
+ (
+ cr_face,
+ ct.byref(_ft_destroy_key),
+ ft_face,
+ _freetype_so.FT_Done_Face
+ )
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d doing user_data dance for %s" % (status, filename))
+ #end if
+ ft_face = None # Cairo has stolen my reference
+ #end if
+
+ # set Cairo font face into Cairo context
+ cairo_ctx = cairo.Context(_surface)
+ cairo_t = PycairoContext.from_address(id(cairo_ctx)).ctx
+ _cairo_so.cairo_set_font_face(cairo_t, cr_face)
+ status = _cairo_so.cairo_font_face_status(cairo_t)
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename))
+ #end if
+
+ finally :
+ _cairo_so.cairo_font_face_destroy(cr_face)
+ _freetype_so.FT_Done_Face(ft_face)
+ #end try
+
+ # get back Cairo font face as a Python object
+ face = cairo_ctx.get_font_face()
+ return face
+#end create_cairo_font_face_for_file