From 9a3c8c711a63598a6d09277babdb63f2f62e18c9 Mon Sep 17 00:00:00 2001 From: Krys Kamieniecki Date: Sat, 11 Jan 2020 22:22:19 -0500 Subject: [PATCH] Added some todo notes, update GFX parsing --- TODO.md | 43 +++++++++++ deca/kaitai/gfx.py | 44 +++++++---- deca/kaitai/var_int.py | 39 ++++++++++ extern_tools/fsb_aud_extr/.gitignore | 5 ++ extern_tools/fsb_aud_extr/README.md | 3 + kaitai_struct/README.md | 2 +- kaitai_struct/gfx.ksy | 55 ++++++++++--- {deca/cmds => kaitai_struct}/gfx_test.py | 0 kaitai_struct/var_int.ksy | 98 ++++++++++++++++++++++++ 9 files changed, 264 insertions(+), 25 deletions(-) create mode 100644 TODO.md create mode 100644 deca/kaitai/var_int.py create mode 100644 extern_tools/fsb_aud_extr/.gitignore create mode 100644 extern_tools/fsb_aud_extr/README.md rename {deca/cmds => kaitai_struct}/gfx_test.py (100%) create mode 100644 kaitai_struct/var_int.ksy diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..7d83321 --- /dev/null +++ b/TODO.md @@ -0,0 +1,43 @@ +* Handle lFSB5 extract FSB5 files? +* Handle rival images, how are the name generated + +* track audio files to events, determine how translatable audio files are used + * Example file hash == 00FFFE21 file number 15604 + * Mission pm_03_southcoast, 218561533 (flicka translated to english) + * ``` + # Structure(0xC4AB11E3), Data Offset: 95832(0x00017658) + { + Id: + 462990682 # sint32(0x192FE633), Data Offset: 95832(0x00017658) + Name: + b'mission_wb_pm_03_missionitem_04_header' (0x2c250f28) # String Hash(0xC03F64BF), Data Offset: 95836(0x0001765c) + NameShort: + b'attach_paper' (0x6907c7bc) # String Hash(0xC03F64BF), Data Offset: 95840(0x00017660) + Type: + 3 # sint32(0x192FE633), Data Offset: 95844(0x00017664) + Event: + OBJID 6 0x0000ca9556052e33 (0xca9556052e33) # String Hash(0x7421FAD9), Data Offset: 95848(0x00017668) + Text: + b'mission_wb_pm_03_missionitem_04_content' (0xa6094cd9) # String Hash(0xC03F64BF), Data Offset: 95856(0x00017670) + PlayAudioEvent: + OBJID 6 0x0000189e8146ac44 (0x189e8146ac44) # String Hash(0x7421FAD9), Data Offset: 95860(0x00017674) + StopAudioEvent: + OBJID 6 0x00006f0f9f8d3f83 (0x6f0f9f8d3f83) # String Hash(0x7421FAD9), Data Offset: 95866(0x0001767a) + Enabled: + 1 # uint08(0x0CA2821D), Data Offset: 95872(0x00017680) + Image: + b'' # string(0x8955583E), Data Offset: 29584(0x00007390), Info Offset: 95880(0x00017688) + Entity: + b'pm03_audio_item_01' # string(0x8955583E), Data Offset: 95992(0x000176f8), Info Offset: 95888(0x00017690) + DependenciesRequired: + # Array of sint32s(0xFB9FD4CC), Data Offset: 96(0x00000060), Info Offset: 95896(0x00017698) + [ + ] + DependenciesOptional: + # Array of sint32s(0xFB9FD4CC), Data Offset: 96(0x00000060), Info Offset: 95912(0x000176a8) + [ + ] + Persist: + 1 # uint08(0x0CA2821D), Data Offset: 95928(0x000176b8) + } + ``` \ No newline at end of file diff --git a/deca/kaitai/gfx.py b/deca/kaitai/gfx.py index f50213a..a8454ae 100644 --- a/deca/kaitai/gfx.py +++ b/deca/kaitai/gfx.py @@ -141,24 +141,23 @@ def __init__(self, _io, _parent=None, _root=None): self._read() def _read(self): - self.b1 = self._io.read_u1() - self.skip = self._io.read_bytes(self.num_bytes) + self.num_bits = self._io.read_bits_int(5) + self.x_min_raw = [None] * (self.num_bits) + for i in range(self.num_bits): + self.x_min_raw[i] = self._io.read_bits_int(1) != 0 - @property - def num_bits(self): - if hasattr(self, '_m_num_bits'): - return self._m_num_bits if hasattr(self, '_m_num_bits') else None + self.x_max_raw = [None] * (self.num_bits) + for i in range(self.num_bits): + self.x_max_raw[i] = self._io.read_bits_int(1) != 0 - self._m_num_bits = (self.b1 >> 3) - return self._m_num_bits if hasattr(self, '_m_num_bits') else None + self.y_min_raw = [None] * (self.num_bits) + for i in range(self.num_bits): + self.y_min_raw[i] = self._io.read_bits_int(1) != 0 - @property - def num_bytes(self): - if hasattr(self, '_m_num_bytes'): - return self._m_num_bytes if hasattr(self, '_m_num_bytes') else None + self.y_max_raw = [None] * (self.num_bits) + for i in range(self.num_bits): + self.y_max_raw[i] = self._io.read_bits_int(1) != 0 - self._m_num_bytes = (((self.num_bits * 4) - 3) + 7) // 8 - return self._m_num_bytes if hasattr(self, '_m_num_bytes') else None class Tag(KaitaiStruct): @@ -199,6 +198,10 @@ def _read(self): self._raw_tag_body = self._io.read_bytes(self.record_header.len) io = KaitaiStream(BytesIO(self._raw_tag_body)) self.tag_body = self._root.ImportAssets2Body(io, self, self._root) + elif _on == self._root.TagType.define_shape3: + self._raw_tag_body = self._io.read_bytes(self.record_header.len) + io = KaitaiStream(BytesIO(self._raw_tag_body)) + self.tag_body = self._root.DefineShape3Body(io, self, self._root) elif _on == self._root.TagType.do_abc: self._raw_tag_body = self._io.read_bytes(self.record_header.len) io = KaitaiStream(BytesIO(self._raw_tag_body)) @@ -412,4 +415,17 @@ def _read(self): self.script_timeout_seconds = self._io.read_u2le() + class DefineShape3Body(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.shape_id = self._io.read_u2le() + self.bounds = self._root.Rect(self._io, self, self._root) + self.shapes = self._io.read_bytes_full() + + diff --git a/deca/kaitai/var_int.py b/deca/kaitai/var_int.py new file mode 100644 index 0000000..4ca4381 --- /dev/null +++ b/deca/kaitai/var_int.py @@ -0,0 +1,39 @@ +# 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 + + +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 VarInt(KaitaiStruct): + """LIMITATIONS: + Max number of bits is 32 + SWF has can have integers of variable bit lengths determined at runtime. This provides support for that + """ + def __init__(self, raw, num_bits, is_signed, is_le, _io, _parent=None, _root=None): + self._io = _io + self._parent = _parent + self._root = _root if _root else self + self.raw = raw + self.num_bits = num_bits + self.is_signed = is_signed + self.is_le = is_le + self._read() + + def _read(self): + self.raw = [None] * (self.num_bits) + for i in range(self.num_bits): + self.raw[i] = self._io.read_bits_int(1) != 0 + + + @property + def value(self): + if hasattr(self, '_m_value'): + return self._m_value if hasattr(self, '_m_value') else None + + self._m_value = (((((((((((((((((((((((((((((((((((1 if ((self.num_bits > 0) and (self.raw[0])) else 0) << 0) | ((1 if ((self.num_bits > 1) and (self.raw[1])) else 0) << 1)) | ((1 if ((self.num_bits > 2) and (self.raw[2])) else 0) << 2)) | ((1 if ((self.num_bits > 3) and (self.raw[3])) else 0) << 3)) | ((1 if ((self.num_bits > 4) and (self.raw[4])) else 0) << 4)) | ((1 if ((self.num_bits > 5) and (self.raw[5])) else 0) << 5)) | ((1 if ((self.num_bits > 6) and (self.raw[6])) else 0) << 6)) | ((1 if ((self.num_bits > 7) and (self.raw[7])) else 0) << 7)) | ((1 if ((self.num_bits > 8) and (self.raw[8])) else 0) << 8)) | ((1 if ((self.num_bits > 9) and (self.raw[9])) else 0) << 9)) | ((1 if ((self.num_bits > 10) and (self.raw[10])) else 0) << 10)) | ((1 if ((self.num_bits > 11) and (self.raw[11])) else 0) << 11)) | ((1 if ((self.num_bits > 12) and (self.raw[12])) else 0) << 12)) | ((1 if ((self.num_bits > 13) and (self.raw[13])) else 0) << 13)) | ((1 if ((self.num_bits > 14) and (self.raw[14])) else 0) << 14)) | ((1 if ((self.num_bits > 15) and (self.raw[15])) else 0) << 15)) | ((1 if ((self.num_bits > 16) and (self.raw[16])) else 0) << 16)) | ((1 if ((self.num_bits > 17) and (self.raw[17])) else 0) << 17)) | ((1 if ((self.num_bits > 18) and (self.raw[18])) else 0) << 18)) | ((1 if ((self.num_bits > 19) and (self.raw[19])) else 0) << 19)) | ((1 if ((self.num_bits > 20) and (self.raw[20])) else 0) << 20)) | ((1 if ((self.num_bits > 21) and (self.raw[21])) else 0) << 21)) | ((1 if ((self.num_bits > 22) and (self.raw[22])) else 0) << 22)) | ((1 if ((self.num_bits > 23) and (self.raw[23])) else 0) << 23)) | ((1 if ((self.num_bits > 24) and (self.raw[24])) else 0) << 24)) | ((1 if ((self.num_bits > 25) and (self.raw[25])) else 0) << 25)) | ((1 if ((self.num_bits > 26) and (self.raw[26])) else 0) << 26)) | ((1 if ((self.num_bits > 27) and (self.raw[27])) else 0) << 27)) | ((1 if ((self.num_bits > 28) and (self.raw[28])) else 0) << 28)) | ((1 if ((self.num_bits > 29) and (self.raw[29])) else 0) << 29)) | ((1 if ((self.num_bits > 30) and (self.raw[30])) else 0) << 30)) | ((1 if ((self.num_bits > 31) and (self.raw[31])) else 0) << 31)) | ((-1 << self.num_bits) if ((self.is_signed) and (self.raw[((self.num_bits - 1) if self.is_le else 0)])) else 0)) if self.is_le else ((((((((((((((((((((((((((((((((((1 if ((self.num_bits > 0) and (self.raw[0])) else 0) << ((self.num_bits - 1) - 0)) | ((1 if ((self.num_bits > 1) and (self.raw[1])) else 0) << ((self.num_bits - 1) - 1))) | ((1 if ((self.num_bits > 2) and (self.raw[2])) else 0) << ((self.num_bits - 1) - 2))) | ((1 if ((self.num_bits > 3) and (self.raw[3])) else 0) << ((self.num_bits - 1) - 3))) | ((1 if ((self.num_bits > 4) and (self.raw[4])) else 0) << ((self.num_bits - 1) - 4))) | ((1 if ((self.num_bits > 5) and (self.raw[5])) else 0) << ((self.num_bits - 1) - 5))) | ((1 if ((self.num_bits > 6) and (self.raw[6])) else 0) << ((self.num_bits - 1) - 6))) | ((1 if ((self.num_bits > 7) and (self.raw[7])) else 0) << ((self.num_bits - 1) - 7))) | ((1 if ((self.num_bits > 8) and (self.raw[8])) else 0) << ((self.num_bits - 1) - 8))) | ((1 if ((self.num_bits > 9) and (self.raw[9])) else 0) << ((self.num_bits - 1) - 9))) | ((1 if ((self.num_bits > 10) and (self.raw[10])) else 0) << ((self.num_bits - 1) - 10))) | ((1 if ((self.num_bits > 11) and (self.raw[11])) else 0) << ((self.num_bits - 1) - 11))) | ((1 if ((self.num_bits > 12) and (self.raw[12])) else 0) << ((self.num_bits - 1) - 12))) | ((1 if ((self.num_bits > 13) and (self.raw[13])) else 0) << ((self.num_bits - 1) - 13))) | ((1 if ((self.num_bits > 14) and (self.raw[14])) else 0) << ((self.num_bits - 1) - 14))) | ((1 if ((self.num_bits > 15) and (self.raw[15])) else 0) << ((self.num_bits - 1) - 15))) | ((1 if ((self.num_bits > 16) and (self.raw[16])) else 0) << ((self.num_bits - 1) - 16))) | ((1 if ((self.num_bits > 17) and (self.raw[17])) else 0) << ((self.num_bits - 1) - 17))) | ((1 if ((self.num_bits > 18) and (self.raw[18])) else 0) << ((self.num_bits - 1) - 18))) | ((1 if ((self.num_bits > 19) and (self.raw[19])) else 0) << ((self.num_bits - 1) - 19))) | ((1 if ((self.num_bits > 20) and (self.raw[20])) else 0) << ((self.num_bits - 1) - 20))) | ((1 if ((self.num_bits > 21) and (self.raw[21])) else 0) << ((self.num_bits - 1) - 21))) | ((1 if ((self.num_bits > 22) and (self.raw[22])) else 0) << ((self.num_bits - 1) - 22))) | ((1 if ((self.num_bits > 23) and (self.raw[23])) else 0) << ((self.num_bits - 1) - 23))) | ((1 if ((self.num_bits > 24) and (self.raw[24])) else 0) << ((self.num_bits - 1) - 24))) | ((1 if ((self.num_bits > 25) and (self.raw[25])) else 0) << ((self.num_bits - 1) - 25))) | ((1 if ((self.num_bits > 26) and (self.raw[26])) else 0) << ((self.num_bits - 1) - 26))) | ((1 if ((self.num_bits > 27) and (self.raw[27])) else 0) << ((self.num_bits - 1) - 27))) | ((1 if ((self.num_bits > 28) and (self.raw[28])) else 0) << ((self.num_bits - 1) - 28))) | ((1 if ((self.num_bits > 29) and (self.raw[29])) else 0) << ((self.num_bits - 1) - 29))) | ((1 if ((self.num_bits > 30) and (self.raw[30])) else 0) << ((self.num_bits - 1) - 30))) | ((1 if ((self.num_bits > 31) and (self.raw[31])) else 0) << ((self.num_bits - 1) - 31))) | ((-1 << self.num_bits) if ((self.is_signed) and (self.raw[((self.num_bits - 1) if self.is_le else 0)])) else 0))) + return self._m_value if hasattr(self, '_m_value') else None + + diff --git a/extern_tools/fsb_aud_extr/.gitignore b/extern_tools/fsb_aud_extr/.gitignore new file mode 100644 index 0000000..eb0dbef --- /dev/null +++ b/extern_tools/fsb_aud_extr/.gitignore @@ -0,0 +1,5 @@ +fmodL.dll +fmod_extr.exe +fmodex.dll +fsb_aud_extr.exe +*.wav diff --git a/extern_tools/fsb_aud_extr/README.md b/extern_tools/fsb_aud_extr/README.md new file mode 100644 index 0000000..80ddb16 --- /dev/null +++ b/extern_tools/fsb_aud_extr/README.md @@ -0,0 +1,3 @@ +FSB5 and RIFF audio extraction info + +https://zenhax.com/viewtopic.php?t=1901 \ No newline at end of file diff --git a/kaitai_struct/README.md b/kaitai_struct/README.md index 18c71cf..3703e3a 100644 --- a/kaitai_struct/README.md +++ b/kaitai_struct/README.md @@ -1,4 +1,4 @@ ``` cd deca/deca/kaitai/ -kaitai-struct-compiler -t python ../../kaitai_struct/gfx.ksy +kaitai-struct-compiler -t python --python-package deca.kaitai ../../kaitai_struct/gfx.ksy ``` diff --git a/kaitai_struct/gfx.ksy b/kaitai_struct/gfx.ksy index 18a494a..153a3e8 100644 --- a/kaitai_struct/gfx.ksy +++ b/kaitai_struct/gfx.ksy @@ -9,12 +9,16 @@ meta: wikidata: Q594447 license: CC0-1.0 endian: le -# imports: + imports: + - var_int # - abc_bytecode + doc: | First pass at a parser for ScaleForm GFX files. https://help.autodesk.com/view/SCLFRM/ENU/?guid=__scaleform_help_flash_support_controltags_html + doc-ref: https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf + seq: - id: compression -orig-id: Signature @@ -51,17 +55,36 @@ types: type: tag repeat: until repeat-until: _.record_header.tag_type == tag_type::end_of_file + rect: seq: - - id: b1 - type: u1 - - id: skip - size: num_bytes - instances: - num_bits: - value: b1 >> 3 - num_bytes: - value: ((num_bits * 4 - 3) + 7) / 8 + - id: num_bits + type: b5 + - id: x_min_raw + # type: var_int(num_bits, true, false) + type: b1 + repeat: expr + repeat-expr: num_bits + - id: x_max_raw + # type: var_int(num_bits, true, false) + type: b1 + repeat: expr + repeat-expr: num_bits + - id: y_min_raw + # type: var_int(num_bits, true, false) + type: b1 + repeat: expr + repeat-expr: num_bits + - id: y_max_raw + # type: var_int(num_bits, true, false) + type: b1 + repeat: expr + repeat-expr: num_bits +# instances: +# x_min: +# value: 'x_min_raw.as' +# value: 'var_int(x_min_raw, num_bits, true, false)' + rgb: seq: - id: r @@ -95,6 +118,7 @@ types: switch-on: record_header.tag_type cases: 'tag_type::define_sound': define_sound_body + 'tag_type::define_shape3': define_shape3_body 'tag_type::do_abc': do_abc_body 'tag_type::script_limits': script_limits_body 'tag_type::symbol_class': symbol_class_body @@ -104,6 +128,7 @@ types: 'tag_type::gfx_exporter_info': gfx_exporter_info_body 'tag_type::gfx_define_external_image': gfx_define_external_image_body 'tag_type::gfx_define_external_image2': gfx_define_external_image2_body + define_sound_body: seq: - id: id @@ -139,6 +164,16 @@ types: channels: 0: mono 1: stereo + + define_shape3_body: + seq: + - id: shape_id + type: u2 + - id: bounds + type: rect + - id: shapes + size-eos: true + do_abc_body: seq: - id: flags diff --git a/deca/cmds/gfx_test.py b/kaitai_struct/gfx_test.py similarity index 100% rename from deca/cmds/gfx_test.py rename to kaitai_struct/gfx_test.py diff --git a/kaitai_struct/var_int.ksy b/kaitai_struct/var_int.ksy new file mode 100644 index 0000000..5afed9b --- /dev/null +++ b/kaitai_struct/var_int.ksy @@ -0,0 +1,98 @@ +meta: + id: var_int + title: Variable length integer helper + license: CC0-1.0 + ks-version: 0.8 +doc: | + LIMITATIONS: + Max number of bits is 32 + SWF has can have integers of variable bit lengths determined at runtime. This provides support for that +params: + - id: raw + - id: num_bits + type: u1 + doc: Number of bits per digit. Only values of 4 and 8 are supported. + - id: is_signed + type: bool + doc: Endianness of bit array. True means signed integer, false means unsigned integer + - id: is_le + type: bool + doc: Endianness of bit array. True means little-endian, false is for big-endian. +seq: + - id: raw + type: b1 + repeat: expr + repeat-expr: num_bits + +instances: + value: + value: > + is_le ? ( + (((num_bits > 0) and raw[ 0]) ? 1 : 0) << 0 | + (((num_bits > 1) and raw[ 1]) ? 1 : 0) << 1 | + (((num_bits > 2) and raw[ 2]) ? 1 : 0) << 2 | + (((num_bits > 3) and raw[ 3]) ? 1 : 0) << 3 | + (((num_bits > 4) and raw[ 4]) ? 1 : 0) << 4 | + (((num_bits > 5) and raw[ 5]) ? 1 : 0) << 5 | + (((num_bits > 6) and raw[ 6]) ? 1 : 0) << 6 | + (((num_bits > 7) and raw[ 7]) ? 1 : 0) << 7 | + (((num_bits > 8) and raw[ 8]) ? 1 : 0) << 8 | + (((num_bits > 9) and raw[ 9]) ? 1 : 0) << 9 | + (((num_bits > 10) and raw[10]) ? 1 : 0) << 10 | + (((num_bits > 11) and raw[11]) ? 1 : 0) << 11 | + (((num_bits > 12) and raw[12]) ? 1 : 0) << 12 | + (((num_bits > 13) and raw[13]) ? 1 : 0) << 13 | + (((num_bits > 14) and raw[14]) ? 1 : 0) << 14 | + (((num_bits > 15) and raw[15]) ? 1 : 0) << 15 | + (((num_bits > 16) and raw[16]) ? 1 : 0) << 16 | + (((num_bits > 17) and raw[17]) ? 1 : 0) << 17 | + (((num_bits > 18) and raw[18]) ? 1 : 0) << 18 | + (((num_bits > 19) and raw[19]) ? 1 : 0) << 19 | + (((num_bits > 20) and raw[20]) ? 1 : 0) << 20 | + (((num_bits > 21) and raw[21]) ? 1 : 0) << 21 | + (((num_bits > 22) and raw[22]) ? 1 : 0) << 22 | + (((num_bits > 23) and raw[23]) ? 1 : 0) << 23 | + (((num_bits > 24) and raw[24]) ? 1 : 0) << 24 | + (((num_bits > 25) and raw[25]) ? 1 : 0) << 25 | + (((num_bits > 26) and raw[26]) ? 1 : 0) << 26 | + (((num_bits > 27) and raw[27]) ? 1 : 0) << 27 | + (((num_bits > 28) and raw[28]) ? 1 : 0) << 28 | + (((num_bits > 29) and raw[29]) ? 1 : 0) << 29 | + (((num_bits > 30) and raw[30]) ? 1 : 0) << 30 | + (((num_bits > 31) and raw[31]) ? 1 : 0) << 31 | + ((is_signed and raw[is_le ? (num_bits - 1) : 0]) ? (-1 << num_bits): 0) + ) : ( + (((num_bits > 0) and raw[ 0]) ? 1 : 0) << ((num_bits - 1) - 0) | + (((num_bits > 1) and raw[ 1]) ? 1 : 0) << ((num_bits - 1) - 1) | + (((num_bits > 2) and raw[ 2]) ? 1 : 0) << ((num_bits - 1) - 2) | + (((num_bits > 3) and raw[ 3]) ? 1 : 0) << ((num_bits - 1) - 3) | + (((num_bits > 4) and raw[ 4]) ? 1 : 0) << ((num_bits - 1) - 4) | + (((num_bits > 5) and raw[ 5]) ? 1 : 0) << ((num_bits - 1) - 5) | + (((num_bits > 6) and raw[ 6]) ? 1 : 0) << ((num_bits - 1) - 6) | + (((num_bits > 7) and raw[ 7]) ? 1 : 0) << ((num_bits - 1) - 7) | + (((num_bits > 8) and raw[ 8]) ? 1 : 0) << ((num_bits - 1) - 8) | + (((num_bits > 9) and raw[ 9]) ? 1 : 0) << ((num_bits - 1) - 9) | + (((num_bits > 10) and raw[10]) ? 1 : 0) << ((num_bits - 1) - 10) | + (((num_bits > 11) and raw[11]) ? 1 : 0) << ((num_bits - 1) - 11) | + (((num_bits > 12) and raw[12]) ? 1 : 0) << ((num_bits - 1) - 12) | + (((num_bits > 13) and raw[13]) ? 1 : 0) << ((num_bits - 1) - 13) | + (((num_bits > 14) and raw[14]) ? 1 : 0) << ((num_bits - 1) - 14) | + (((num_bits > 15) and raw[15]) ? 1 : 0) << ((num_bits - 1) - 15) | + (((num_bits > 16) and raw[16]) ? 1 : 0) << ((num_bits - 1) - 16) | + (((num_bits > 17) and raw[17]) ? 1 : 0) << ((num_bits - 1) - 17) | + (((num_bits > 18) and raw[18]) ? 1 : 0) << ((num_bits - 1) - 18) | + (((num_bits > 19) and raw[19]) ? 1 : 0) << ((num_bits - 1) - 19) | + (((num_bits > 20) and raw[20]) ? 1 : 0) << ((num_bits - 1) - 20) | + (((num_bits > 21) and raw[21]) ? 1 : 0) << ((num_bits - 1) - 21) | + (((num_bits > 22) and raw[22]) ? 1 : 0) << ((num_bits - 1) - 22) | + (((num_bits > 23) and raw[23]) ? 1 : 0) << ((num_bits - 1) - 23) | + (((num_bits > 24) and raw[24]) ? 1 : 0) << ((num_bits - 1) - 24) | + (((num_bits > 25) and raw[25]) ? 1 : 0) << ((num_bits - 1) - 25) | + (((num_bits > 26) and raw[26]) ? 1 : 0) << ((num_bits - 1) - 26) | + (((num_bits > 27) and raw[27]) ? 1 : 0) << ((num_bits - 1) - 27) | + (((num_bits > 28) and raw[28]) ? 1 : 0) << ((num_bits - 1) - 28) | + (((num_bits > 29) and raw[29]) ? 1 : 0) << ((num_bits - 1) - 29) | + (((num_bits > 30) and raw[30]) ? 1 : 0) << ((num_bits - 1) - 30) | + (((num_bits > 31) and raw[31]) ? 1 : 0) << ((num_bits - 1) - 31) | + ((is_signed and raw[is_le ? (num_bits - 1) : 0]) ? (-1 << num_bits): 0) + )