LOKAL Studentenabteilung Adventskalender Tag 11
Ich war besorgt, dass alle Leute stur waren und "Bin ich nicht zu schwach ...?", Also beschloss ich, einen wechselnden Ball zu werfen. Soweit ich gesucht habe, gibt es keine japanische Literatur, daher denke ich, dass Leute, die dies in Zukunft erforschen, diesen Artikel fast automatisch sehen werden. Ich möchte euch alle fragen. Wenn Sie denken: "Worüber sprechen Sie? Ist es nicht voller falscher Informationen?", Bitte kommentieren Sie. Ich werde mein Bestes tun, um das Problem zu beheben.
Beamter: kaitai.io
Kaitai Struct ist eine deklarative Sprache zur Beschreibung von binären Datenstrukturen.
Der Quellcode des Binärdatenparsers kann automatisch basierend auf der in Ihrer eigenen Sprache geschriebenen Datenstruktur generiert werden.
license Der später beschriebene Compiler und Visualizer sind GPL v3 + und die Bibliothek für jede Sprache ist MIT (JS ist Apache v2). Bedeutet dies, dass der mit Compiler generierte Quellcode die GPL infiziert ...? Bitte sagen Sie mir eine detaillierte Person.
Kaitai Struct Compiler (KSC)
Weitere Informationen zur Installation hier
Mac ist ein Schuss mit Brew Install Kaitai-Struct-Compiler
.
Folgen Sie für Windows dem obigen Link, um das Installationsprogramm herunterzuladen.
# Import GPG key, if you never used any BinTray repos before
sudo apt-key adv --keyserver hkp://pool.sks-keyservers.net --recv 379CE192D401AB61
# Add stable repository
echo "deb https://dl.bintray.com/kaitai-io/debian jessie main" | sudo tee /etc/apt/sources.list.d/kaitai.list
# ... or unstable repository
echo "deb https://dl.bintray.com/kaitai-io/debian_unstable jessie main" | sudo tee /etc/apt/sources.list.d/kaitai.list
sudo apt-get update
sudo apt-get install kaitai-struct-compiler
Kaitai Struct Visualizer (KSV) Dies ist ein einfacher Visualisierer für .ksy-Dateien. Geschrieben in "Ruby", ist es als "Edelstein" -Paket erhältlich.
gem install kaitai-struct-visualizer
Für bekannte Dateien befindet sich im offiziellen Github-Repository eine .ksy-Datei (https://github.com/kaitai-io/kaitai_struct_formats).
(Wenn Sie die hier vorhandene ".ksy" -Datei verwenden möchten, überprüfen Sie bitte die in "Meta / Lizenz" in der Datei beschriebene Lizenz.)
Wenn Sie eine neue .ksy
schreiben, senden Sie eine Pull-Anfrage.
(kaitai_struct_formats/CONTRIBUTING.md)
matrix.py
import numpy as np
import struct
def create_header(*mats: [np.ndarray], magic: bytes = None) -> bytes:
header = magic
header += struct.pack('<H', len(mats))
length = len(header) + 8 * len(mats)
for mat in mats:
header += struct.pack('<HH', mat.shape[0], mat.shape[1])
header += struct.pack('<I', length)
length += 4 * mat.shape[0] * mat.shape[1]
return header
mat1 = np.random.randint(-1024, 1024, [3, 3], dtype=np.int32)
mat2 = np.random.randint(-1024, 1024, [5, 9], dtype=np.int32)
mat3 = np.random.randint(-1024, 1024, [2, 2], dtype=np.int32)
with open('test.matrix', 'wb') as o:
magic = b'THIS IS MAT FILE.\x01\x02'
o.write(create_header(mat1, mat2, mat3, magic=magic))
for mat in [mat1, mat2, mat3]:
for y in mat:
for x in y:
o.write(struct.pack('<i', x))
test.matrix
Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000: 4D 41 54 01 02 2F 03 00 03 00 03 00 20 00 00 00 MAT../..........
00000010: 05 00 09 00 44 00 00 00 02 00 02 00 F8 00 00 00 ....D.......x...
00000020: DC FE FF FF 49 01 00 00 A7 FF FF FF 17 02 00 00 \~..I...'.......
00000030: 25 FC FF FF 35 FF FF FF B5 00 00 00 CF FE FF FF %|..5...5...O~..
00000040: E2 FF FF FF 5D 00 00 00 15 FE FF FF 30 FC FF FF b...]....~..0|..
00000050: 4C 03 00 00 C1 FF FF FF B0 FD FF FF 31 02 00 00 L...A...0}..1...
00000060: 54 03 00 00 C4 FF FF FF 65 FF FF FF D0 FE FF FF T...D...e...P~..
00000070: 75 01 00 00 DE FE FF FF ED 00 00 00 ED FC FF FF u...^~..m...m|..
00000080: BE FD FF FF E5 02 00 00 EC FE FF FF 22 FE FF FF >}..e...l~.."~..
00000090: C3 02 00 00 11 00 00 00 29 03 00 00 00 01 00 00 C.......).......
000000a0: 78 00 00 00 C4 FC FF FF 4C 02 00 00 88 00 00 00 x...D|..L.......
000000b0: 43 FF FF FF 35 FF FF FF A4 00 00 00 CF 02 00 00 C...5...$...O...
000000c0: 3A FF FF FF 33 FF FF FF BD FE FF FF F9 01 00 00 :...3...=~..y...
000000d0: 22 FF FF FF 3A 02 00 00 7C 00 00 00 15 FF FF FF "...:...|.......
000000e0: D8 FE FF FF 42 00 00 00 82 02 00 00 24 02 00 00 X~..B.......$...
000000f0: 8A FE FF FF AF FF FF FF EF 02 00 00 96 01 00 00 .~../...o.......
00000100: 83 01 00 00 2F 02 00 00
Die Struktur der Datei ist von Anfang an
b'MAT\x01\x02/'
Schreiben wir dies in matrix.ksy
.
KSY (Kaitai Struct YAML) deklariert einen einzelnen benutzerdefinierten Typ (wörtlich übersetzt vom offiziellen). Benutzerdefinierter Typ
meta
doc
seq
types
instances
enums
Besteht aus.
Du musst nicht alles haben.
Weitere Informationen finden Sie in der offiziellen Referenz.meta
meta
meta:
id: matrix
endian: le
Beschreiben Sie den Namen des benutzerdefinierten Typs, der in "meta / id" beschrieben werden soll. Es muss immer in der .ksy-Datei sein.
meta / endian
beschreibt den in der Struktur verwendeten Standard-Endian ( le
/ be
)
seq
seq
seq:
- id: magic
contents: ['MAT', 1, 0x2, '/']
- id: header_num
type: u2
- id: headers
repeat: expr
repeat-expr: header_num
type: header
Beschreiben Sie die Datenstruktur in seq
.
id
ist der Variablenname.
Wenn die Daten eine Konstante sind, schreiben Sie die Konstante in "Inhalt".
Wenn Sie den Wert erhalten möchten, beschreiben Sie den Datentyp in type
(siehe hier für Details).
Sie können auch die unter "Typen" beschriebenen Typen verwenden, die später beschrieben werden. Hier wird der Typ "Header" verwendet.
repeat
kann expr
, eos
oder till
sein (siehe hier für Details). )
Wenn Sie "Ausdruck" eingeben, geben Sie die Anzahl der Wiederholungen in "Wiederholung-Ausdruck" ein.
types
types
types:
header:
seq:
- id: shape0
type: u2
- id: shape1
type: u2
- id: offset
type: u4
instances:
mat_body:
pos: offset
io: _root._io
type: matrix
matrix:
seq:
- id: dim0
repeat: expr
repeat-expr: _parent.shape0
type: dim1
types:
dim1:
seq:
- id: dim1
repeat: expr
repeat-expr: _parent._parent.shape0
type: s4
Benutzerdefinierte Typen können in "Typen" verschachtelt werden. Ich verwende "Instanzen" mit dem Typ "Header", mit denen andere als die nacheinander vorhandenen Daten gelesen werden können, z. B. "seq".
header.instances
instances:
mat_body:
pos: offset
io: _root._io
type: matrix
Die Verwendung ist der von "seq" sehr ähnlich.
id
ist hier der mat_body
.
io
ist der zu verwendende IO-Stream.
pos
ist die Anzahl der Bytes ab dem Beginn von io
.
type
ist das gleiche wie für seq
.
Einige Felder (in diesem Fall "repeat-expr", "pos", "io") können sich sowohl auf Variablen als auch auf konstante Werte beziehen.
Sie können keine Daten sehen, die noch nicht gelesen wurden.
Die Daten haben eine Baumstruktur (es ist leicht zu verstehen, wenn Sie ksv verwenden), und Sie können das übergeordnete Element mit "_parent" angeben.
Sie können das oberste Element auch mit _root
angeben.
Visualize
Zu diesem Zeitpunkt haben Sie den folgenden Code geschrieben.
matrix.ksy
meta:
id: matrix
endian: le
seq:
- id: magic
contents: ['MAT', 1, 0x2, '/']
- id: header_num
type: u2
- id: headers
repeat: expr
repeat-expr: header_num
type: header
types:
header:
seq:
- id: shape0
type: u2
- id: shape1
type: u2
- id: offset
type: u4
instances:
mat_body:
pos: offset
io: _root._io
type: matrix
matrix:
seq:
- id: dim0
repeat: expr
repeat-expr: _parent.shape0
type: dim1
types:
dim1:
seq:
- id: dim1
repeat: expr
repeat-expr: _parent._parent.shape0
type: s4
Lassen Sie uns dies mit ksv (Kaitai Struct Visualizer) visualisieren.
Die Verwendung ist ksv <file_to_parse.bin> <format.ksy>
.
shell
$ ksv test.matrix matrix.ksy
ksv
[-] [root] 00000000: 4d 41 54 01 02 2f 03 00 03 00 03 00 20 00 00 00 | MAT../...... ...
[.] magic = 4d 41 54 01 02 2f 00000010: 05 00 09 00 44 00 00 00 02 00 02 00 f8 00 00 00 | ....D...........
[.] header_num = 3 00000020: dc fe ff ff 49 01 00 00 a7 ff ff ff 17 02 00 00 | ....I...........
[-] headers (3 = 0x3 entries) 00000030: 25 fc ff ff 35 ff ff ff b5 00 00 00 cf fe ff ff | %...5...........
[-] 0 00000040: e2 ff ff ff 5d 00 00 00 15 fe ff ff 30 fc ff ff | ....].......0...
[.] shape0 = 3 00000050: 4c 03 00 00 c1 ff ff ff b0 fd ff ff 31 02 00 00 | L...........1...
[.] shape1 = 3 00000060: 54 03 00 00 c4 ff ff ff 65 ff ff ff d0 fe ff ff | T.......e.......
[.] offset = 32 00000070: 75 01 00 00 de fe ff ff ed 00 00 00 ed fc ff ff | u...............
[-] mat_body 00000080: be fd ff ff e5 02 00 00 ec fe ff ff 22 fe ff ff | ............"...
[-] dim0 (3 = 0x3 entries) 00000090: c3 02 00 00 11 00 00 00 29 03 00 00 00 01 00 00 | ........).......
[-] 0 000000a0: 78 00 00 00 c4 fc ff ff 4c 02 00 00 88 00 00 00 | x.......L.......
[-] dim1 (3 = 0x3 entries) 000000b0: 43 ff ff ff 35 ff ff ff a4 00 00 00 cf 02 00 00 | C...5...........
[.] 0 = -292 000000c0: 3a ff ff ff 33 ff ff ff bd fe ff ff f9 01 00 00 | :...3...........
[.] 1 = 329 000000d0: 22 ff ff ff 3a 02 00 00 7c 00 00 00 15 ff ff ff | "...:...|.......
[.] 2 = -89 000000e0: d8 fe ff ff 42 00 00 00 82 02 00 00 24 02 00 00 | ....B.......$...
[-] 1 000000f0: 8a fe ff ff af ff ff ff ef 02 00 00 96 01 00 00 | ................
[-] dim1 (3 = 0x3 entries) 00000100: 83 01 00 00 2f 02 00 00 | ..../...
[.] 0 = 535
[.] 1 = -987
[.] 2 = -203
[-] 2
[+] dim1
[-] 1
[.] shape0 = 5
[.] shape1 = 9
[.] offset = 68
[-] mat_body
[+] dim0
[+] 2
Es scheint, dass es gut gelesen werden kann.
Dies ist das Hauptthema. Ich habe im Artikel [hier] eine komprimierte Datei erstellt (https://qiita.com/mueru/items/2e99832304cf8b89d3ec). Entpacken Sie dieses Mal diese komprimierte Datei mit KS. Die Struktur der Datei finden Sie im Artikel.
mcp.ksy
meta:
id: mcp
encoding: UTF-8
endian: le
seq:
- id: file
type: file
repeat: eos
types:
file:
seq:
- id: filename_len
type: u4
- id: filebody_len
type: u4
- id: filename
type: str
size: filename_len
- id: filebody
size: filebody_len
process: zlib
meta / encoding
gibt die Standardcodierung an, die mit type: str
verwendet werden soll.
repeat: eos
wiederholt sich bis zum Ende des Streams.
process: zlib
beantwortet die gelesenen Daten mit zlib. (Sehr angenehm)
process
finden Sie hier](https://doc.kaitai.io/ksy_reference.html#spec-process)Generieren Sie Code aus mcp.ksy
mit ksc (Kaitai Struct Compiler).
usage
Usage: kaitai-struct-compiler [options] <file>...
<file>... source files (.ksy)
-t, --target <language> target languages (graphviz, csharp, all, perl, java, go, cpp_stl, php, lua, python, ruby, javascript)
-d, --outdir <directory>
output directory (filenames will be auto-generated)
-I, --import-path <directory>:<directory>:...
.ksy library search path(s) for imports (see also KSPATH env variable)
--go-package <package> Go package (Go only, default: none)
--java-package <package>
Java package (Java only, default: root package)
--java-from-file-class <class>
Java class to be invoked in fromFile() helper (default: io.kaitai.struct.ByteBufferKaitaiStream)
--dotnet-namespace <namespace>
.NET Namespace (.NET only, default: Kaitai)
--php-namespace <namespace>
PHP Namespace (PHP only, default: root package)
--python-package <package>
Python package (Python only, default: root package)
--opaque-types <value> opaque types allowed, default: false
--ksc-exceptions ksc throws exceptions instead of human-readable error messages
--ksc-json-output output compilation results as JSON to stdout
--verbose <value> verbose output
--debug enable debugging helpers (mostly used by visualization tools)
--help display this help and exit
--version output version information and exit
shell
$ ksc -t python mcp.ksy
mcp.py
# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
from pkg_resources import parse_version
from kaitaistruct import __version__ as ks_version, KaitaiStruct, KaitaiStream, BytesIO
import zlib
if parse_version(ks_version) < parse_version('0.7'):
raise Exception("Incompatible Kaitai Struct Python API: 0.7 or later is required, but you have %s" % (ks_version))
class Mcp(KaitaiStruct):
def __init__(self, _io, _parent=None, _root=None):
self._io = _io
self._parent = _parent
self._root = _root if _root else self
self._read()
def _read(self):
self.file = []
i = 0
while not self._io.is_eof():
self.file.append(self._root.File(self._io, self, self._root))
i += 1
class File(KaitaiStruct):
def __init__(self, _io, _parent=None, _root=None):
self._io = _io
self._parent = _parent
self._root = _root if _root else self
self._read()
def _read(self):
self.filename_len = self._io.read_u4le()
self.filebody_len = self._io.read_u4le()
self.filename = (self._io.read_bytes(self.filename_len)).decode(u"UTF-8")
self._raw_filebody = self._io.read_bytes(self.filebody_len)
self.filebody = zlib.decompress(self._raw_filebody)
Der Code, der "mcp.py" generiert. Schreiben wir damit ein Dekomprimierungsskript.
extract.py
from mcp import Mcp
import os
import sys
mcps = Mcp.from_file(sys.argv[1])
out = 'output/'
if len(sys.argv) >= 3:
out = sys.argv[2]
for f in mcps.file:
if os.path.dirname(f.filename):
os.makedirs(os.path.join(out, os.path.dirname(f.filename)), exist_ok=True)
with open(os.path.join(out, f.filename), 'wb') as o:
o.write(f.filebody)
Sie können mit "python extract.py <target.mcp> [output_folder]" antworten
Verwenden Sie zum Lesen der Datei "KaitaiStruct.from_file (file_path)". Wenn Sie die Byte-Zeichenfolge so lesen möchten, wie sie ist, verwenden Sie "KaitaiStruct.from_bytes (Bytes)". Verwenden Sie für E / A-Streams "KaitaiStruct.from_io (io)".
Ich denke, KS ist sehr praktisch. Es ist einfach zu schreiben und Sie können es in Ihrer Lieblingssprache verwenden, sodass die Kosten für das Erlernen neuer Dinge sehr gering sind. Die offizielle Referenz ist ehrlich gesagt schwer zu lesen, aber ich bin sicher, dass in Zukunft mehr Leute wie ich Artikel über KS schreiben werden (wahrscheinlich).
Möchten Sie mit KS "zerlegen"?
Recommended Posts