oscura 0.0.1__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oscura/__init__.py +813 -8
- oscura/__main__.py +392 -0
- oscura/analyzers/__init__.py +37 -0
- oscura/analyzers/digital/__init__.py +177 -0
- oscura/analyzers/digital/bus.py +691 -0
- oscura/analyzers/digital/clock.py +805 -0
- oscura/analyzers/digital/correlation.py +720 -0
- oscura/analyzers/digital/edges.py +632 -0
- oscura/analyzers/digital/extraction.py +413 -0
- oscura/analyzers/digital/quality.py +878 -0
- oscura/analyzers/digital/signal_quality.py +877 -0
- oscura/analyzers/digital/thresholds.py +708 -0
- oscura/analyzers/digital/timing.py +1104 -0
- oscura/analyzers/eye/__init__.py +46 -0
- oscura/analyzers/eye/diagram.py +434 -0
- oscura/analyzers/eye/metrics.py +555 -0
- oscura/analyzers/jitter/__init__.py +83 -0
- oscura/analyzers/jitter/ber.py +333 -0
- oscura/analyzers/jitter/decomposition.py +759 -0
- oscura/analyzers/jitter/measurements.py +413 -0
- oscura/analyzers/jitter/spectrum.py +220 -0
- oscura/analyzers/measurements.py +40 -0
- oscura/analyzers/packet/__init__.py +171 -0
- oscura/analyzers/packet/daq.py +1077 -0
- oscura/analyzers/packet/metrics.py +437 -0
- oscura/analyzers/packet/parser.py +327 -0
- oscura/analyzers/packet/payload.py +2156 -0
- oscura/analyzers/packet/payload_analysis.py +1312 -0
- oscura/analyzers/packet/payload_extraction.py +236 -0
- oscura/analyzers/packet/payload_patterns.py +670 -0
- oscura/analyzers/packet/stream.py +359 -0
- oscura/analyzers/patterns/__init__.py +266 -0
- oscura/analyzers/patterns/clustering.py +1036 -0
- oscura/analyzers/patterns/discovery.py +539 -0
- oscura/analyzers/patterns/learning.py +797 -0
- oscura/analyzers/patterns/matching.py +1091 -0
- oscura/analyzers/patterns/periodic.py +650 -0
- oscura/analyzers/patterns/sequences.py +767 -0
- oscura/analyzers/power/__init__.py +116 -0
- oscura/analyzers/power/ac_power.py +391 -0
- oscura/analyzers/power/basic.py +383 -0
- oscura/analyzers/power/conduction.py +314 -0
- oscura/analyzers/power/efficiency.py +297 -0
- oscura/analyzers/power/ripple.py +356 -0
- oscura/analyzers/power/soa.py +372 -0
- oscura/analyzers/power/switching.py +479 -0
- oscura/analyzers/protocol/__init__.py +150 -0
- oscura/analyzers/protocols/__init__.py +150 -0
- oscura/analyzers/protocols/base.py +500 -0
- oscura/analyzers/protocols/can.py +620 -0
- oscura/analyzers/protocols/can_fd.py +448 -0
- oscura/analyzers/protocols/flexray.py +405 -0
- oscura/analyzers/protocols/hdlc.py +399 -0
- oscura/analyzers/protocols/i2c.py +368 -0
- oscura/analyzers/protocols/i2s.py +296 -0
- oscura/analyzers/protocols/jtag.py +393 -0
- oscura/analyzers/protocols/lin.py +445 -0
- oscura/analyzers/protocols/manchester.py +333 -0
- oscura/analyzers/protocols/onewire.py +501 -0
- oscura/analyzers/protocols/spi.py +334 -0
- oscura/analyzers/protocols/swd.py +325 -0
- oscura/analyzers/protocols/uart.py +393 -0
- oscura/analyzers/protocols/usb.py +495 -0
- oscura/analyzers/signal_integrity/__init__.py +63 -0
- oscura/analyzers/signal_integrity/embedding.py +294 -0
- oscura/analyzers/signal_integrity/equalization.py +370 -0
- oscura/analyzers/signal_integrity/sparams.py +484 -0
- oscura/analyzers/spectral/__init__.py +53 -0
- oscura/analyzers/spectral/chunked.py +273 -0
- oscura/analyzers/spectral/chunked_fft.py +571 -0
- oscura/analyzers/spectral/chunked_wavelet.py +391 -0
- oscura/analyzers/spectral/fft.py +92 -0
- oscura/analyzers/statistical/__init__.py +250 -0
- oscura/analyzers/statistical/checksum.py +923 -0
- oscura/analyzers/statistical/chunked_corr.py +228 -0
- oscura/analyzers/statistical/classification.py +778 -0
- oscura/analyzers/statistical/entropy.py +1113 -0
- oscura/analyzers/statistical/ngrams.py +614 -0
- oscura/analyzers/statistics/__init__.py +119 -0
- oscura/analyzers/statistics/advanced.py +885 -0
- oscura/analyzers/statistics/basic.py +263 -0
- oscura/analyzers/statistics/correlation.py +630 -0
- oscura/analyzers/statistics/distribution.py +298 -0
- oscura/analyzers/statistics/outliers.py +463 -0
- oscura/analyzers/statistics/streaming.py +93 -0
- oscura/analyzers/statistics/trend.py +520 -0
- oscura/analyzers/validation.py +598 -0
- oscura/analyzers/waveform/__init__.py +36 -0
- oscura/analyzers/waveform/measurements.py +943 -0
- oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
- oscura/analyzers/waveform/spectral.py +1689 -0
- oscura/analyzers/waveform/wavelets.py +298 -0
- oscura/api/__init__.py +62 -0
- oscura/api/dsl.py +538 -0
- oscura/api/fluent.py +571 -0
- oscura/api/operators.py +498 -0
- oscura/api/optimization.py +392 -0
- oscura/api/profiling.py +396 -0
- oscura/automotive/__init__.py +73 -0
- oscura/automotive/can/__init__.py +52 -0
- oscura/automotive/can/analysis.py +356 -0
- oscura/automotive/can/checksum.py +250 -0
- oscura/automotive/can/correlation.py +212 -0
- oscura/automotive/can/discovery.py +355 -0
- oscura/automotive/can/message_wrapper.py +375 -0
- oscura/automotive/can/models.py +385 -0
- oscura/automotive/can/patterns.py +381 -0
- oscura/automotive/can/session.py +452 -0
- oscura/automotive/can/state_machine.py +300 -0
- oscura/automotive/can/stimulus_response.py +461 -0
- oscura/automotive/dbc/__init__.py +15 -0
- oscura/automotive/dbc/generator.py +156 -0
- oscura/automotive/dbc/parser.py +146 -0
- oscura/automotive/dtc/__init__.py +30 -0
- oscura/automotive/dtc/database.py +3036 -0
- oscura/automotive/j1939/__init__.py +14 -0
- oscura/automotive/j1939/decoder.py +745 -0
- oscura/automotive/loaders/__init__.py +35 -0
- oscura/automotive/loaders/asc.py +98 -0
- oscura/automotive/loaders/blf.py +77 -0
- oscura/automotive/loaders/csv_can.py +136 -0
- oscura/automotive/loaders/dispatcher.py +136 -0
- oscura/automotive/loaders/mdf.py +331 -0
- oscura/automotive/loaders/pcap.py +132 -0
- oscura/automotive/obd/__init__.py +14 -0
- oscura/automotive/obd/decoder.py +707 -0
- oscura/automotive/uds/__init__.py +48 -0
- oscura/automotive/uds/decoder.py +265 -0
- oscura/automotive/uds/models.py +64 -0
- oscura/automotive/visualization.py +369 -0
- oscura/batch/__init__.py +55 -0
- oscura/batch/advanced.py +627 -0
- oscura/batch/aggregate.py +300 -0
- oscura/batch/analyze.py +139 -0
- oscura/batch/logging.py +487 -0
- oscura/batch/metrics.py +556 -0
- oscura/builders/__init__.py +41 -0
- oscura/builders/signal_builder.py +1131 -0
- oscura/cli/__init__.py +14 -0
- oscura/cli/batch.py +339 -0
- oscura/cli/characterize.py +273 -0
- oscura/cli/compare.py +775 -0
- oscura/cli/decode.py +551 -0
- oscura/cli/main.py +247 -0
- oscura/cli/shell.py +350 -0
- oscura/comparison/__init__.py +66 -0
- oscura/comparison/compare.py +397 -0
- oscura/comparison/golden.py +487 -0
- oscura/comparison/limits.py +391 -0
- oscura/comparison/mask.py +434 -0
- oscura/comparison/trace_diff.py +30 -0
- oscura/comparison/visualization.py +481 -0
- oscura/compliance/__init__.py +70 -0
- oscura/compliance/advanced.py +756 -0
- oscura/compliance/masks.py +363 -0
- oscura/compliance/reporting.py +483 -0
- oscura/compliance/testing.py +298 -0
- oscura/component/__init__.py +38 -0
- oscura/component/impedance.py +365 -0
- oscura/component/reactive.py +598 -0
- oscura/component/transmission_line.py +312 -0
- oscura/config/__init__.py +191 -0
- oscura/config/defaults.py +254 -0
- oscura/config/loader.py +348 -0
- oscura/config/memory.py +271 -0
- oscura/config/migration.py +458 -0
- oscura/config/pipeline.py +1077 -0
- oscura/config/preferences.py +530 -0
- oscura/config/protocol.py +875 -0
- oscura/config/schema.py +713 -0
- oscura/config/settings.py +420 -0
- oscura/config/thresholds.py +599 -0
- oscura/convenience.py +457 -0
- oscura/core/__init__.py +299 -0
- oscura/core/audit.py +457 -0
- oscura/core/backend_selector.py +405 -0
- oscura/core/cache.py +590 -0
- oscura/core/cancellation.py +439 -0
- oscura/core/confidence.py +225 -0
- oscura/core/config.py +506 -0
- oscura/core/correlation.py +216 -0
- oscura/core/cross_domain.py +422 -0
- oscura/core/debug.py +301 -0
- oscura/core/edge_cases.py +541 -0
- oscura/core/exceptions.py +535 -0
- oscura/core/gpu_backend.py +523 -0
- oscura/core/lazy.py +832 -0
- oscura/core/log_query.py +540 -0
- oscura/core/logging.py +931 -0
- oscura/core/logging_advanced.py +952 -0
- oscura/core/memoize.py +171 -0
- oscura/core/memory_check.py +274 -0
- oscura/core/memory_guard.py +290 -0
- oscura/core/memory_limits.py +336 -0
- oscura/core/memory_monitor.py +453 -0
- oscura/core/memory_progress.py +465 -0
- oscura/core/memory_warnings.py +315 -0
- oscura/core/numba_backend.py +362 -0
- oscura/core/performance.py +352 -0
- oscura/core/progress.py +524 -0
- oscura/core/provenance.py +358 -0
- oscura/core/results.py +331 -0
- oscura/core/types.py +504 -0
- oscura/core/uncertainty.py +383 -0
- oscura/discovery/__init__.py +52 -0
- oscura/discovery/anomaly_detector.py +672 -0
- oscura/discovery/auto_decoder.py +415 -0
- oscura/discovery/comparison.py +497 -0
- oscura/discovery/quality_validator.py +528 -0
- oscura/discovery/signal_detector.py +769 -0
- oscura/dsl/__init__.py +73 -0
- oscura/dsl/commands.py +246 -0
- oscura/dsl/interpreter.py +455 -0
- oscura/dsl/parser.py +689 -0
- oscura/dsl/repl.py +172 -0
- oscura/exceptions.py +59 -0
- oscura/exploratory/__init__.py +111 -0
- oscura/exploratory/error_recovery.py +642 -0
- oscura/exploratory/fuzzy.py +513 -0
- oscura/exploratory/fuzzy_advanced.py +786 -0
- oscura/exploratory/legacy.py +831 -0
- oscura/exploratory/parse.py +358 -0
- oscura/exploratory/recovery.py +275 -0
- oscura/exploratory/sync.py +382 -0
- oscura/exploratory/unknown.py +707 -0
- oscura/export/__init__.py +25 -0
- oscura/export/wireshark/README.md +265 -0
- oscura/export/wireshark/__init__.py +47 -0
- oscura/export/wireshark/generator.py +312 -0
- oscura/export/wireshark/lua_builder.py +159 -0
- oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
- oscura/export/wireshark/type_mapping.py +165 -0
- oscura/export/wireshark/validator.py +105 -0
- oscura/exporters/__init__.py +94 -0
- oscura/exporters/csv.py +303 -0
- oscura/exporters/exporters.py +44 -0
- oscura/exporters/hdf5.py +219 -0
- oscura/exporters/html_export.py +701 -0
- oscura/exporters/json_export.py +291 -0
- oscura/exporters/markdown_export.py +367 -0
- oscura/exporters/matlab_export.py +354 -0
- oscura/exporters/npz_export.py +219 -0
- oscura/exporters/spice_export.py +210 -0
- oscura/extensibility/__init__.py +131 -0
- oscura/extensibility/docs.py +752 -0
- oscura/extensibility/extensions.py +1125 -0
- oscura/extensibility/logging.py +259 -0
- oscura/extensibility/measurements.py +485 -0
- oscura/extensibility/plugins.py +414 -0
- oscura/extensibility/registry.py +346 -0
- oscura/extensibility/templates.py +913 -0
- oscura/extensibility/validation.py +651 -0
- oscura/filtering/__init__.py +89 -0
- oscura/filtering/base.py +563 -0
- oscura/filtering/convenience.py +564 -0
- oscura/filtering/design.py +725 -0
- oscura/filtering/filters.py +32 -0
- oscura/filtering/introspection.py +605 -0
- oscura/guidance/__init__.py +24 -0
- oscura/guidance/recommender.py +429 -0
- oscura/guidance/wizard.py +518 -0
- oscura/inference/__init__.py +251 -0
- oscura/inference/active_learning/README.md +153 -0
- oscura/inference/active_learning/__init__.py +38 -0
- oscura/inference/active_learning/lstar.py +257 -0
- oscura/inference/active_learning/observation_table.py +230 -0
- oscura/inference/active_learning/oracle.py +78 -0
- oscura/inference/active_learning/teachers/__init__.py +15 -0
- oscura/inference/active_learning/teachers/simulator.py +192 -0
- oscura/inference/adaptive_tuning.py +453 -0
- oscura/inference/alignment.py +653 -0
- oscura/inference/bayesian.py +943 -0
- oscura/inference/binary.py +1016 -0
- oscura/inference/crc_reverse.py +711 -0
- oscura/inference/logic.py +288 -0
- oscura/inference/message_format.py +1305 -0
- oscura/inference/protocol.py +417 -0
- oscura/inference/protocol_dsl.py +1084 -0
- oscura/inference/protocol_library.py +1230 -0
- oscura/inference/sequences.py +809 -0
- oscura/inference/signal_intelligence.py +1509 -0
- oscura/inference/spectral.py +215 -0
- oscura/inference/state_machine.py +634 -0
- oscura/inference/stream.py +918 -0
- oscura/integrations/__init__.py +59 -0
- oscura/integrations/llm.py +1827 -0
- oscura/jupyter/__init__.py +32 -0
- oscura/jupyter/display.py +268 -0
- oscura/jupyter/magic.py +334 -0
- oscura/loaders/__init__.py +526 -0
- oscura/loaders/binary.py +69 -0
- oscura/loaders/configurable.py +1255 -0
- oscura/loaders/csv.py +26 -0
- oscura/loaders/csv_loader.py +473 -0
- oscura/loaders/hdf5.py +9 -0
- oscura/loaders/hdf5_loader.py +510 -0
- oscura/loaders/lazy.py +370 -0
- oscura/loaders/mmap_loader.py +583 -0
- oscura/loaders/numpy_loader.py +436 -0
- oscura/loaders/pcap.py +432 -0
- oscura/loaders/preprocessing.py +368 -0
- oscura/loaders/rigol.py +287 -0
- oscura/loaders/sigrok.py +321 -0
- oscura/loaders/tdms.py +367 -0
- oscura/loaders/tektronix.py +711 -0
- oscura/loaders/validation.py +584 -0
- oscura/loaders/vcd.py +464 -0
- oscura/loaders/wav.py +233 -0
- oscura/math/__init__.py +45 -0
- oscura/math/arithmetic.py +824 -0
- oscura/math/interpolation.py +413 -0
- oscura/onboarding/__init__.py +39 -0
- oscura/onboarding/help.py +498 -0
- oscura/onboarding/tutorials.py +405 -0
- oscura/onboarding/wizard.py +466 -0
- oscura/optimization/__init__.py +19 -0
- oscura/optimization/parallel.py +440 -0
- oscura/optimization/search.py +532 -0
- oscura/pipeline/__init__.py +43 -0
- oscura/pipeline/base.py +338 -0
- oscura/pipeline/composition.py +242 -0
- oscura/pipeline/parallel.py +448 -0
- oscura/pipeline/pipeline.py +375 -0
- oscura/pipeline/reverse_engineering.py +1119 -0
- oscura/plugins/__init__.py +122 -0
- oscura/plugins/base.py +272 -0
- oscura/plugins/cli.py +497 -0
- oscura/plugins/discovery.py +411 -0
- oscura/plugins/isolation.py +418 -0
- oscura/plugins/lifecycle.py +959 -0
- oscura/plugins/manager.py +493 -0
- oscura/plugins/registry.py +421 -0
- oscura/plugins/versioning.py +372 -0
- oscura/py.typed +0 -0
- oscura/quality/__init__.py +65 -0
- oscura/quality/ensemble.py +740 -0
- oscura/quality/explainer.py +338 -0
- oscura/quality/scoring.py +616 -0
- oscura/quality/warnings.py +456 -0
- oscura/reporting/__init__.py +248 -0
- oscura/reporting/advanced.py +1234 -0
- oscura/reporting/analyze.py +448 -0
- oscura/reporting/argument_preparer.py +596 -0
- oscura/reporting/auto_report.py +507 -0
- oscura/reporting/batch.py +615 -0
- oscura/reporting/chart_selection.py +223 -0
- oscura/reporting/comparison.py +330 -0
- oscura/reporting/config.py +615 -0
- oscura/reporting/content/__init__.py +39 -0
- oscura/reporting/content/executive.py +127 -0
- oscura/reporting/content/filtering.py +191 -0
- oscura/reporting/content/minimal.py +257 -0
- oscura/reporting/content/verbosity.py +162 -0
- oscura/reporting/core.py +508 -0
- oscura/reporting/core_formats/__init__.py +17 -0
- oscura/reporting/core_formats/multi_format.py +210 -0
- oscura/reporting/engine.py +836 -0
- oscura/reporting/export.py +366 -0
- oscura/reporting/formatting/__init__.py +129 -0
- oscura/reporting/formatting/emphasis.py +81 -0
- oscura/reporting/formatting/numbers.py +403 -0
- oscura/reporting/formatting/standards.py +55 -0
- oscura/reporting/formatting.py +466 -0
- oscura/reporting/html.py +578 -0
- oscura/reporting/index.py +590 -0
- oscura/reporting/multichannel.py +296 -0
- oscura/reporting/output.py +379 -0
- oscura/reporting/pdf.py +373 -0
- oscura/reporting/plots.py +731 -0
- oscura/reporting/pptx_export.py +360 -0
- oscura/reporting/renderers/__init__.py +11 -0
- oscura/reporting/renderers/pdf.py +94 -0
- oscura/reporting/sections.py +471 -0
- oscura/reporting/standards.py +680 -0
- oscura/reporting/summary_generator.py +368 -0
- oscura/reporting/tables.py +397 -0
- oscura/reporting/template_system.py +724 -0
- oscura/reporting/templates/__init__.py +15 -0
- oscura/reporting/templates/definition.py +205 -0
- oscura/reporting/templates/index.html +649 -0
- oscura/reporting/templates/index.md +173 -0
- oscura/schemas/__init__.py +158 -0
- oscura/schemas/bus_configuration.json +322 -0
- oscura/schemas/device_mapping.json +182 -0
- oscura/schemas/packet_format.json +418 -0
- oscura/schemas/protocol_definition.json +363 -0
- oscura/search/__init__.py +16 -0
- oscura/search/anomaly.py +292 -0
- oscura/search/context.py +149 -0
- oscura/search/pattern.py +160 -0
- oscura/session/__init__.py +34 -0
- oscura/session/annotations.py +289 -0
- oscura/session/history.py +313 -0
- oscura/session/session.py +445 -0
- oscura/streaming/__init__.py +43 -0
- oscura/streaming/chunked.py +611 -0
- oscura/streaming/progressive.py +393 -0
- oscura/streaming/realtime.py +622 -0
- oscura/testing/__init__.py +54 -0
- oscura/testing/synthetic.py +808 -0
- oscura/triggering/__init__.py +68 -0
- oscura/triggering/base.py +229 -0
- oscura/triggering/edge.py +353 -0
- oscura/triggering/pattern.py +344 -0
- oscura/triggering/pulse.py +581 -0
- oscura/triggering/window.py +453 -0
- oscura/ui/__init__.py +48 -0
- oscura/ui/formatters.py +526 -0
- oscura/ui/progressive_display.py +340 -0
- oscura/utils/__init__.py +99 -0
- oscura/utils/autodetect.py +338 -0
- oscura/utils/buffer.py +389 -0
- oscura/utils/lazy.py +407 -0
- oscura/utils/lazy_imports.py +147 -0
- oscura/utils/memory.py +836 -0
- oscura/utils/memory_advanced.py +1326 -0
- oscura/utils/memory_extensions.py +465 -0
- oscura/utils/progressive.py +352 -0
- oscura/utils/windowing.py +362 -0
- oscura/visualization/__init__.py +321 -0
- oscura/visualization/accessibility.py +526 -0
- oscura/visualization/annotations.py +374 -0
- oscura/visualization/axis_scaling.py +305 -0
- oscura/visualization/colors.py +453 -0
- oscura/visualization/digital.py +337 -0
- oscura/visualization/eye.py +420 -0
- oscura/visualization/histogram.py +281 -0
- oscura/visualization/interactive.py +858 -0
- oscura/visualization/jitter.py +702 -0
- oscura/visualization/keyboard.py +394 -0
- oscura/visualization/layout.py +365 -0
- oscura/visualization/optimization.py +1028 -0
- oscura/visualization/palettes.py +446 -0
- oscura/visualization/plot.py +92 -0
- oscura/visualization/power.py +290 -0
- oscura/visualization/power_extended.py +626 -0
- oscura/visualization/presets.py +467 -0
- oscura/visualization/protocols.py +932 -0
- oscura/visualization/render.py +207 -0
- oscura/visualization/rendering.py +444 -0
- oscura/visualization/reverse_engineering.py +791 -0
- oscura/visualization/signal_integrity.py +808 -0
- oscura/visualization/specialized.py +553 -0
- oscura/visualization/spectral.py +811 -0
- oscura/visualization/styles.py +381 -0
- oscura/visualization/thumbnails.py +311 -0
- oscura/visualization/time_axis.py +351 -0
- oscura/visualization/waveform.py +367 -0
- oscura/workflow/__init__.py +13 -0
- oscura/workflow/dag.py +377 -0
- oscura/workflows/__init__.py +58 -0
- oscura/workflows/compliance.py +280 -0
- oscura/workflows/digital.py +272 -0
- oscura/workflows/multi_trace.py +502 -0
- oscura/workflows/power.py +178 -0
- oscura/workflows/protocol.py +492 -0
- oscura/workflows/reverse_engineering.py +639 -0
- oscura/workflows/signal_integrity.py +227 -0
- oscura-0.1.0.dist-info/METADATA +300 -0
- oscura-0.1.0.dist-info/RECORD +463 -0
- oscura-0.1.0.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
- oscura-0.0.1.dist-info/METADATA +0 -63
- oscura-0.0.1.dist-info/RECORD +0 -5
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""Binary parsing utilities for packet analysis.
|
|
2
|
+
|
|
3
|
+
This module provides fast binary parsing using struct.Struct
|
|
4
|
+
pre-compilation and TLV record support.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from oscura.analyzers.packet.parser import BinaryParser, parse_tlv
|
|
9
|
+
>>> parser = BinaryParser(">HBB") # big-endian: ushort, 2 ubytes
|
|
10
|
+
>>> values = parser.unpack(data)
|
|
11
|
+
|
|
12
|
+
References:
|
|
13
|
+
Python struct module documentation
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import struct
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from collections.abc import Iterator
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class TLVRecord:
|
|
28
|
+
"""Type-Length-Value record.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
type_id: Record type identifier.
|
|
32
|
+
length: Data length in bytes.
|
|
33
|
+
value: Record data.
|
|
34
|
+
offset: Byte offset in source data.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
type_id: int
|
|
38
|
+
length: int
|
|
39
|
+
value: bytes
|
|
40
|
+
offset: int = 0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class BinaryParser:
|
|
44
|
+
"""Fast binary parser using pre-compiled struct format.
|
|
45
|
+
|
|
46
|
+
Uses struct.Struct for pre-compiled format strings to achieve
|
|
47
|
+
high parsing throughput (>10K packets/second).
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
format_string: struct format string (e.g., ">HBB").
|
|
51
|
+
|
|
52
|
+
Attributes:
|
|
53
|
+
format: The format string.
|
|
54
|
+
size: Size of the packed structure in bytes.
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
>>> parser = BinaryParser(">HHBBI") # Header format
|
|
58
|
+
>>> header = parser.unpack(data)
|
|
59
|
+
>>> print(f"Fields: {header}")
|
|
60
|
+
|
|
61
|
+
>>> # Unpack from offset
|
|
62
|
+
>>> payload = parser.unpack_from(data, offset=8)
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, format_string: str) -> None:
|
|
66
|
+
"""Initialize parser with format string.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
format_string: struct format string. Use standard prefixes:
|
|
70
|
+
- ">": Big-endian
|
|
71
|
+
- "<": Little-endian
|
|
72
|
+
- "=": Native byte order
|
|
73
|
+
- "!": Network byte order (big-endian)
|
|
74
|
+
"""
|
|
75
|
+
self._struct = struct.Struct(format_string)
|
|
76
|
+
self._format = format_string
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def format(self) -> str:
|
|
80
|
+
"""Get format string."""
|
|
81
|
+
return self._format
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def size(self) -> int:
|
|
85
|
+
"""Get packed size in bytes."""
|
|
86
|
+
return self._struct.size
|
|
87
|
+
|
|
88
|
+
def unpack(self, buffer: bytes) -> tuple[Any, ...]:
|
|
89
|
+
"""Unpack data from bytes.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
buffer: Bytes to unpack. Must be at least self.size bytes.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Tuple of unpacked values.
|
|
96
|
+
"""
|
|
97
|
+
return self._struct.unpack(buffer[: self.size])
|
|
98
|
+
|
|
99
|
+
def unpack_from(self, buffer: bytes, offset: int = 0) -> tuple[Any, ...]:
|
|
100
|
+
"""Unpack data from offset in buffer.
|
|
101
|
+
|
|
102
|
+
More efficient than slicing when parsing multiple fields
|
|
103
|
+
from a single buffer.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
buffer: Source buffer.
|
|
107
|
+
offset: Byte offset to start unpacking.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Tuple of unpacked values.
|
|
111
|
+
"""
|
|
112
|
+
return self._struct.unpack_from(buffer, offset)
|
|
113
|
+
|
|
114
|
+
def pack(self, *values: Any) -> bytes:
|
|
115
|
+
"""Pack values to bytes.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
*values: Values matching format string types.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Packed bytes.
|
|
122
|
+
"""
|
|
123
|
+
return self._struct.pack(*values)
|
|
124
|
+
|
|
125
|
+
def iter_unpack(self, buffer: bytes) -> Iterator[tuple[Any, ...]]:
|
|
126
|
+
"""Iterate over repeated structures in buffer.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
buffer: Source buffer.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Iterator yielding tuples of unpacked values.
|
|
133
|
+
|
|
134
|
+
Example:
|
|
135
|
+
>>> parser = BinaryParser(">HH")
|
|
136
|
+
>>> for a, b in parser.iter_unpack(data):
|
|
137
|
+
... print(f"Pair: {a}, {b}")
|
|
138
|
+
"""
|
|
139
|
+
return self._struct.iter_unpack(buffer)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class PacketParser:
|
|
143
|
+
"""Multi-field packet parser.
|
|
144
|
+
|
|
145
|
+
Parses packets with multiple fields using named field definitions.
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
>>> fields = [
|
|
149
|
+
... ("sync", "H"),
|
|
150
|
+
... ("length", "H"),
|
|
151
|
+
... ("type", "B"),
|
|
152
|
+
... ("flags", "B"),
|
|
153
|
+
... ]
|
|
154
|
+
>>> parser = PacketParser(fields, byte_order=">")
|
|
155
|
+
>>> packet = parser.parse(data)
|
|
156
|
+
>>> print(f"Type: {packet['type']}")
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def __init__(
|
|
160
|
+
self,
|
|
161
|
+
fields: list[tuple[str, str]],
|
|
162
|
+
byte_order: str = ">",
|
|
163
|
+
) -> None:
|
|
164
|
+
"""Initialize packet parser.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
fields: List of (name, format_char) tuples.
|
|
168
|
+
byte_order: Byte order prefix (">", "<", "=", "!").
|
|
169
|
+
"""
|
|
170
|
+
self._field_names = [f[0] for f in fields]
|
|
171
|
+
format_chars = "".join(f[1] for f in fields)
|
|
172
|
+
self._parser = BinaryParser(byte_order + format_chars)
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def size(self) -> int:
|
|
176
|
+
"""Get packet header size in bytes."""
|
|
177
|
+
return self._parser.size
|
|
178
|
+
|
|
179
|
+
def parse(self, buffer: bytes, offset: int = 0) -> dict[str, Any]:
|
|
180
|
+
"""Parse packet fields.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
buffer: Source buffer.
|
|
184
|
+
offset: Byte offset.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Dictionary mapping field names to values.
|
|
188
|
+
"""
|
|
189
|
+
values = self._parser.unpack_from(buffer, offset)
|
|
190
|
+
return dict(zip(self._field_names, values, strict=False))
|
|
191
|
+
|
|
192
|
+
def pack(self, **fields: Any) -> bytes:
|
|
193
|
+
"""Pack fields to bytes.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
**fields: Field values by name.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Packed bytes.
|
|
200
|
+
"""
|
|
201
|
+
values = [fields[name] for name in self._field_names]
|
|
202
|
+
return self._parser.pack(*values)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def parse_tlv(
|
|
206
|
+
buffer: bytes,
|
|
207
|
+
*,
|
|
208
|
+
type_size: int = 1,
|
|
209
|
+
length_size: int = 1,
|
|
210
|
+
big_endian: bool = True,
|
|
211
|
+
include_length_in_length: bool = False,
|
|
212
|
+
type_map: dict[int, str] | None = None,
|
|
213
|
+
) -> list[TLVRecord]:
|
|
214
|
+
"""Parse Type-Length-Value records.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
buffer: Source buffer containing TLV records.
|
|
218
|
+
type_size: Size of type field in bytes (1, 2, or 4).
|
|
219
|
+
length_size: Size of length field in bytes (1, 2, or 4).
|
|
220
|
+
big_endian: True for big-endian byte order.
|
|
221
|
+
include_length_in_length: True if length includes type+length fields.
|
|
222
|
+
type_map: Optional mapping of type IDs to names.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
List of TLVRecord objects.
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
>>> records = parse_tlv(data, type_size=2, length_size=2)
|
|
229
|
+
>>> for rec in records:
|
|
230
|
+
... print(f"Type {rec.type_id}: {rec.length} bytes")
|
|
231
|
+
"""
|
|
232
|
+
records: list[TLVRecord] = []
|
|
233
|
+
offset = 0
|
|
234
|
+
header_size = type_size + length_size
|
|
235
|
+
|
|
236
|
+
# Determine struct format
|
|
237
|
+
byte_order = ">" if big_endian else "<"
|
|
238
|
+
type_fmt = {1: "B", 2: "H", 4: "I"}[type_size]
|
|
239
|
+
length_fmt = {1: "B", 2: "H", 4: "I"}[length_size]
|
|
240
|
+
header_parser = BinaryParser(byte_order + type_fmt + length_fmt)
|
|
241
|
+
|
|
242
|
+
while offset + header_size <= len(buffer):
|
|
243
|
+
type_id, length = header_parser.unpack_from(buffer, offset)
|
|
244
|
+
|
|
245
|
+
# Adjust length if it includes header
|
|
246
|
+
data_length = length - header_size if include_length_in_length else length
|
|
247
|
+
|
|
248
|
+
if data_length < 0:
|
|
249
|
+
break
|
|
250
|
+
|
|
251
|
+
# Extract value
|
|
252
|
+
value_start = offset + header_size
|
|
253
|
+
value_end = value_start + data_length
|
|
254
|
+
|
|
255
|
+
if value_end > len(buffer):
|
|
256
|
+
break
|
|
257
|
+
|
|
258
|
+
value = buffer[value_start:value_end]
|
|
259
|
+
|
|
260
|
+
records.append(
|
|
261
|
+
TLVRecord(
|
|
262
|
+
type_id=type_id,
|
|
263
|
+
length=data_length,
|
|
264
|
+
value=value,
|
|
265
|
+
offset=offset,
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
offset = value_end
|
|
270
|
+
|
|
271
|
+
return records
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def parse_tlv_nested(
|
|
275
|
+
buffer: bytes,
|
|
276
|
+
*,
|
|
277
|
+
type_size: int = 1,
|
|
278
|
+
length_size: int = 1,
|
|
279
|
+
big_endian: bool = True,
|
|
280
|
+
container_types: set[int] | None = None,
|
|
281
|
+
) -> dict[int, Any]:
|
|
282
|
+
"""Parse nested TLV structure.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
buffer: Source buffer.
|
|
286
|
+
type_size: Size of type field.
|
|
287
|
+
length_size: Size of length field.
|
|
288
|
+
big_endian: Byte order.
|
|
289
|
+
container_types: Set of type IDs that contain nested TLV.
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
Dictionary with type_id keys and either bytes or nested dict values.
|
|
293
|
+
"""
|
|
294
|
+
container_types = container_types or set()
|
|
295
|
+
result: dict[int, Any] = {}
|
|
296
|
+
|
|
297
|
+
records = parse_tlv(
|
|
298
|
+
buffer,
|
|
299
|
+
type_size=type_size,
|
|
300
|
+
length_size=length_size,
|
|
301
|
+
big_endian=big_endian,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
for rec in records:
|
|
305
|
+
if rec.type_id in container_types:
|
|
306
|
+
# Recursively parse nested structure
|
|
307
|
+
nested = parse_tlv_nested(
|
|
308
|
+
rec.value,
|
|
309
|
+
type_size=type_size,
|
|
310
|
+
length_size=length_size,
|
|
311
|
+
big_endian=big_endian,
|
|
312
|
+
container_types=container_types,
|
|
313
|
+
)
|
|
314
|
+
result[rec.type_id] = nested
|
|
315
|
+
else:
|
|
316
|
+
result[rec.type_id] = rec.value
|
|
317
|
+
|
|
318
|
+
return result
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
__all__ = [
|
|
322
|
+
"BinaryParser",
|
|
323
|
+
"PacketParser",
|
|
324
|
+
"TLVRecord",
|
|
325
|
+
"parse_tlv",
|
|
326
|
+
"parse_tlv_nested",
|
|
327
|
+
]
|