├── .gitignore ├── CHANGELOG.md ├── COPYING ├── README.md ├── abcexport.d ├── abcfile.d ├── abcreplace.d ├── asasm.hrc ├── asprogram.d ├── assembler.d ├── autodata.d ├── build_rabcdasm.d ├── common.d ├── deimos ├── lzma.d └── lzma_ │ ├── base.d │ ├── bcj.d │ ├── block.d │ ├── check.d │ ├── container.d │ ├── delta.d │ ├── filter.d │ ├── hardware.d │ ├── index.d │ ├── index_hash.d │ ├── lzma.d │ ├── stream_flags.d │ ├── version_.d │ └── vli.d ├── disassembler.d ├── liblzma.lib ├── lzma.d ├── murmurhash2a.d ├── rabcasm.d ├── rabcdasm.d ├── swf7zcompress.d ├── swfbinexport.d ├── swfbinreplace.d ├── swfdecompress.d ├── swffile.d ├── swflzmacompress.d └── zlibx.d /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.dll 3 | *.pdb 4 | *.ilk 5 | *.exp 6 | *.lib 7 | *.suo 8 | 9 | /build_rabcdasm 10 | /rabcasm 11 | /rabcdasm 12 | /abcexport 13 | /abcreplace 14 | /swfbinexport 15 | /swfbinreplace 16 | /swfdecompress 17 | /swf7zcompress 18 | /swflzmacompress 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | RABCDAsm Changelog 2 | ================== 3 | 4 | RABCDAsm v1.19 (????.??.??) 5 | --------------------------- 6 | 7 | * Ignore duplicate class names during dependency registration 8 | * Make over-estimation of uncompressed SWF size non-fatal 9 | * Improve robustness of zlib decompression 10 | * Disassemble type `0x00` as `Undefined` instead of `Void` 11 | - This matches the terminology used in the AVM specification. 12 | - `Void` continues to be recognized as a synonym for `Undefined`. 13 | 14 | RABCDAsm v1.18 (2016.01.16) 15 | --------------------------- 16 | 17 | * Fix disassembly of `pushbyte` instructions (the AVM specification 18 | incorrectly lists the argument as unsigned). 19 | * Bump `#version` directive of new disassemblies to 4: 20 | - Versions below 4 treat `pushbyte` as unsigned, and throw an exception if 21 | the argument is outside the range `0` ... `255`. 22 | - Versions 4 and above treat `pushbyte` as signed, and throw an exception 23 | if the argument is outside the range `-128` ... `127`. 24 | * Fix buffer reuse bugs when using macros 25 | * Dump floating-point numbers in hex notation if necessary to ensure precision 26 | * Cease emitting a number in a comment after opening `script` tags 27 | * Detect a known DMD bug in `build_rabcdasm` 28 | * Ignore invalid file size in header 29 | 30 | RABCDAsm v1.17 (2014.09.10) 31 | --------------------------- 32 | 33 | * Do not attempt to disassemble unreachable code 34 | * Improve handling of disassembly errors: 35 | methods will be partially disassembled as far as possible. 36 | * Fix LZMA errors with uncompressable data. 37 | 38 | RABCDAsm v1.16 (2014.04.21) 39 | --------------------------- 40 | 41 | * Fix handling of TypeName-kind Multinames with null parameters 42 | * Fix v1.15 regression in handling very long paths on Windows 43 | (DMD 2.066 is required when building from source for this to work) 44 | 45 | RABCDAsm v1.15 (2014.01.11) 46 | --------------------------- 47 | 48 | * Fix building on systems with a noexec `/tmp/` 49 | * Improve compatibility with 3rd-party players 50 | * Don't emit forward references in TypeName-kind Multinames 51 | * Improve performance and memory usage 52 | 53 | RABCDAsm v1.14 (2013.08.21) 54 | --------------------------- 55 | 56 | * Improved refid generation 57 | * Worked around liblzma dictionary size limitation, which prevented 58 | decompression of some LZMA-compressed files 59 | * Added an option to `swflzmacompress` to update the SWF version number 60 | * Added `finddef` instruction 61 | * Added unimplemented `{get|set|delete}propertylate` instructions 62 | * Documentation updates 63 | 64 | RABCDAsm v1.13 (2012.09.29) 65 | --------------------------- 66 | 67 | * Fixed handling of truncated SWF tags 68 | 69 | RABCDAsm v1.12 (2012.09.08) 70 | --------------------------- 71 | 72 | * Relaxed filename sanitization for names like "controller" 73 | * Added range validation for byte literals 74 | * Fixed LZMA support misdetection caused by stale rdmd cache 75 | * Added coerce_b, coerce_i and coerce_d opcodes 76 | * Fixed handling of recursively-nested function literals 77 | * Fixed handling of homonym non-private namespaces 78 | * #privatens directives are now ignored, and no longer generated 79 | * Improved refid generation 80 | * Bumped #version to 3 (v1.12 disassemblies are not backwards-compatible) 81 | * Documentation updates 82 | 83 | RABCDAsm v1.11 (2012.03.15) 84 | --------------------------- 85 | 86 | * Fixed v1.10 hierarchy flattening regression 87 | * Improved refid generation for protected namespaces 88 | * Improved handling of overflown signed integers 89 | * Fixed metadata handling (caused by error in ABC format specification) 90 | * Added #version directive (v1.11 disassemblies are not backwards-compatible) 91 | * Removed path length limitation on Windows 92 | * Improved filename sanitization 93 | * Updated asasm.hrc 94 | * Documentation updates 95 | 96 | RABCDAsm v1.10 (2012.02.29) 97 | --------------------------- 98 | 99 | * Fixed escaping of paths with empty segments 100 | 101 | RABCDAsm v1.9 (2012.02.07) 102 | -------------------------- 103 | 104 | * Added support for LZMA-compressed SWF files 105 | * Added swflzmacompress 106 | * Fixed undiscovered private namespaces in class interfaces 107 | * Fixed handling of overflown integers 108 | * Documentation updates 109 | 110 | RABCDAsm v1.8 (2011.07.06) 111 | -------------------------- 112 | 113 | * Fixed handling of orphan methods with multiple references 114 | * Treat out-of-bounds namespace/multiname indices as null 115 | * Documentation updates 116 | 117 | RABCDAsm v1.7 (2011.06.14) 118 | -------------------------- 119 | 120 | * Fixed handling of invalid UTF-8 in strings 121 | * Fixed handling of null namespaces and multinames 122 | * Fixed handling of exception info in corrupted method bodies 123 | * Fixed handling of orphan private namespaces 124 | * Fixed handling of out-of-bounds class/method indices 125 | * Disassembler now creates one file per class and script-level method 126 | * Disassembler now outputs blank lines after `si32` etc. instructions as well 127 | * `abcexport` now delimits the index with a dash in output filenames 128 | * Improved shortening of `double` literals 129 | * Documentation updates 130 | 131 | RABCDAsm v1.6 (2011.05.13) 132 | -------------------------- 133 | 134 | * Overhaul of the structure of disassembler-generated files 135 | * Private namespace names and `refid`s for nested classes are now generated 136 | from their referenced contexts 137 | * This also fixes problems caused by private namespaces being referenced 138 | in multiple distinct contexts 139 | * One `#include`d file per script instead of per class 140 | * Nested classes, script initializers and other script traits are now in 141 | the same file as their main class 142 | * Inline methods are now in separate files, placed according to their usage 143 | context 144 | * Private namespaces are sorted by their autogenerated names in the 145 | `.privatens.asasm` file 146 | * No syntax changes, output is backwards-compatible 147 | * Improved escaping of file names 148 | * Output correct opcode error locations 149 | * Disassembler will now refuse to overwrite files 150 | * `rabcdasm` will now always generate output in the same directory as the 151 | input file 152 | * Failure to decode a method body is now not a fatal error 153 | * Aggressively try to shorten double literals to their shortest representation 154 | * Added the `swfbinexport` and `swfbinreplace` utilities, to aid in 155 | manipulating contents of `DefineBinaryData` tags 156 | * The package can now be built using a simple, dedicated build tool 157 | * Documentation updates 158 | 159 | RABCDAsm v1.5 (2011.04.14) 160 | -------------------------- 161 | 162 | * Fixed v1.4 constant pool regression 163 | * Added support for memory-access and sign-extend opcodes 164 | * Speed optimizations 165 | * Documentation updates 166 | 167 | RABCDAsm v1.4 (2011.03.07) 168 | -------------------------- 169 | 170 | * Source code ported to D2 171 | * Add support for forward-references for TypeName-kind Multinames 172 | * Correctly order classes by dependencies (extends/implements) and reference 173 | count 174 | * Finish Metadata support 175 | * Documentation updates 176 | 177 | RABCDAsm v1.3 (2010.11.11) 178 | -------------------------- 179 | 180 | * Fixed double precision problem 181 | * This also fixes problems with illegal default values for function 182 | parameters (default values for integer parameters are stored as doubles, 183 | which might become out-of-range due to inadequate double precision) 184 | * Added Changelog 185 | * Documentation markdown fixes 186 | 187 | RABCDAsm v1.2 (2010.11.06) 188 | -------------------------- 189 | 190 | * Fixed ref generation for orphan objects which were only referenced by other 191 | orphans 192 | * Better error handling in `abcexport`; warn when no DoABC tags found 193 | * Documentation updates 194 | 195 | RABCDAsm v1.1 (2010.06.30) 196 | -------------------------- 197 | 198 | * Private namespaces are now referenced by auto-generated names 199 | * Use `:` to delimit namespace and name in QNames for consistency 200 | * Fixed relative include paths 201 | * Add optional byte offsets to labels, which allows lossless representation 202 | of jumps inside instructions and outside the function bounds 203 | * Documentation updates 204 | 205 | RABCDAsm v1.0 (2010.05.05) 206 | -------------------------- 207 | 208 | * Initial release. 209 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Robust ABC (ActionScript Bytecode) [Dis-]Assembler 2 | ================================================== 3 | 4 | [RABCDAsm][] is a collection of utilities including an ActionScript 3 5 | assembler/disassembler, and a few tools to manipulate SWF files. These are: 6 | 7 | * `rabcdasm` - ABC disassembler 8 | * `rabcasm` - ABC assembler 9 | * `abcexport` - extracts ABC from SWF files 10 | * `abcreplace` - replaces ABC in SWF files 11 | * `swfdecompress` - decompresses zlib-compressed SWF files 12 | * `swf7zcompress` - (re-)compress the contents of a SWF using 7-Zip 13 | * `swflzmacompress` - compress the contents of a SWF using LZMA 14 | * `swfbinexport` / `swfbinreplace` - extract/replace contents of binary data 15 | tags from SWF files 16 | 17 | `abcexport` and `abcreplace` are reimplementations of similar utilities from 18 | my [swfutilsex][] Java package, however these work faster as they do not parse 19 | the SWF files as deeply. 20 | `swfdecompress` is ancillary and is only useful for debugging and studying of 21 | the SWF file format, and not required for ABC manipulation. It is functionally 22 | equivalent to [flasm][]'s `-x` option. If you frequently work on compressed 23 | SWF files, you may want to decompress them to speed processing up. 24 | `swf7zcompress` is an utility to further reduce the size of SWF files. It uses 25 | [7-Zip][] to compress the data better than the standard zlib library would. It 26 | requires that the `7z` command-line program be installed and in `PATH`. 27 | `swflzmacompress` compresses SWF files using the [LZMA][] algorithm, support 28 | for which was introduced in Flash 11. It will only work with SWF files with 29 | version 13 or higher. 30 | `swfbinexport` and `swfbinreplace` aid in the manipulation of 31 | `DefineBinaryData` tags in SWF files (some files may contain nested SWF files 32 | stored in these tags). 33 | 34 | [RABCDAsm]: http://github.com/CyberShadow/RABCDAsm 35 | [swfutilsex]: http://github.com/CyberShadow/swfutilsex 36 | [flasm]: http://flasm.sourceforge.net/ 37 | [7-Zip]: http://www.7-zip.org/ 38 | [LZMA]: http://en.wikipedia.org/wiki/Lempel-Ziv-Markov_chain_algorithm 39 | 40 | Motivation and goals 41 | -------------------- 42 | 43 | This package was created due to lack of similar software out there. 44 | Particularly, I needed an utility which would allow me to edit ActionScript 3 45 | bytecode with the following properties: 46 | 47 | 1. Speed. Less waiting means more productivity. `rabcasm` can assemble large 48 | projects (>200000 LOC) in under a second on modern machines. 49 | 2. Comfortably-editable output. Each class is decompiled to its own file, 50 | with files arranged in subdirectories representing the package hierarchy. 51 | Class files are `#include`d from the main file. 52 | 3. Most importantly - robustness! If the Adobe AVM can load and run the file, 53 | then it must be editable - no matter if the file is obfuscated or 54 | otherwise mutilated to prevent reverse-engineering. RABCDAsm achieves this 55 | by using a textual representation closer to the ABC file format, rather 56 | than to what an ActionScript compiler would generate. 57 | 58 | Compiling from source 59 | --------------------- 60 | 61 | RABCDAsm is written in the [D programming language, version 2][d2]. 62 | 63 | Assuming you have [git][] and a D2 compiler, such as [dmd][] or [gdc][] 64 | installed, compiling should be as straight-forward as: 65 | 66 | git clone git://github.com/CyberShadow/RABCDAsm.git 67 | cd RABCDAsm 68 | dmd -run build_rabcdasm.d 69 | 70 | Substitute `dmd` with `gdmd` if you're using gdc. You can use the `DC` and 71 | `DCFLAGS` environment variables to override the detected compiler and default 72 | compilation flags (`-O -inline`). 73 | 74 | To be able to manipulate SWF files packed with LZMA compression, you'll need 75 | to have the [liblzma library][] and development files installed on your system. 76 | 77 | Note: DMD 2.066 is required for long path support on Windows since RABCDAsm 78 | 1.16. 79 | 80 | [d2]: http://dlang.org/ 81 | [dmd]: http://www.digitalmars.com/d/download.html 82 | [gdc]: http://bitbucket.org/goshawk/gdc/ 83 | [git]: http://git-scm.com/ 84 | [liblzma library]: http://tukaani.org/xz/ 85 | 86 | Pre-compiled binaries 87 | --------------------- 88 | 89 | You can find pre-compiled Windows binaries on [my website][downloads]. 90 | However, please don't expect them to be up-to-date with the latest source 91 | versions. 92 | 93 | [downloads]: http://files.thecybershadow.net/RABCDAsm/ 94 | 95 | Usage 96 | ----- 97 | 98 | To begin hacking on a SWF file: 99 | 100 | abcexport file.swf 101 | 102 | This will create `file-0.abc` ... `file-N.abc` (often just `file-0.abc`). Each 103 | file corresponds to an ABC block inside the SWF file. 104 | 105 | To disassemble one of the `.abc` files: 106 | 107 | rabcdasm file-0.abc 108 | 109 | This will create a `file-0` directory, which will contain `file-0.main.asasm` 110 | (the main program file) and files for ActionScript scripts, classes, and 111 | orphan and script-level methods. 112 | 113 | To assemble the `.asasm` files back, and update the SWF file: 114 | 115 | rabcasm file-0/file-0.main.asasm 116 | abcreplace file.swf 0 file-0/file-0.main.abc 117 | 118 | The second `abcreplace` argument represents the index of the ABC block in the 119 | SWF file, and corresponds to the number in the filename created by `abcexport`. 120 | 121 | `swfbinexport` and `swfbinreplace` are used in the same manner as `abcexport` 122 | and `abcreplace`. 123 | 124 | Syntax 125 | ====== 126 | 127 | The syntax of the disassembly was designed to be very simple and allow fast 128 | and easy parsing. It is a close representation of the `.abc` file format, and 129 | thus it is somewhat verbose. All constant pool elements (signed/unsigned 130 | integers, doubles, strings, namespaces, namespace sets, multinames) are always 131 | *expanded inline*, for ease of editing. Similarly, classes, instances, methods 132 | and method bodies are also defined inline, in the context of their "parent" 133 | object. By-index references of classes and methods (used in the `newclass`, 134 | `newfunction` and `callstatic` instructions) are represented via 135 | automatically-generated unique "reference strings", declared as `refid` fields. 136 | 137 | If you haven't yet, I strongly recommend that you look through Adobe's 138 | [ActionScript Virtual Machine 2 (AVM2) Overview][avm2]. You will most likely 139 | need to consult it for the instruction reference anyway (although you can also 140 | use [this handy list][avm2i] as well). You will find it difficult to 141 | understand the disassembly without good understanding of concepts such as 142 | namespaces and multinames. 143 | 144 | [avm2]: https://www.adobe.com/content/dam/acom/en/devnet/pdf/avm2overview.pdf 145 | [avm2i]: https://web.archive.org/web/20160215185222/www.anotherbigidea.com/javaswf/avm2/AVM2Instructions.html 146 | 147 | Overview 148 | -------- 149 | 150 | In order to guarantee unambiguity and data preservation, all strings read from 151 | the input file - including identifiers (variable/function/class names) - are 152 | represented as string literals. Thus, the syntax does not have any "reserved 153 | words" or such - an unrecognized word is treated as an error, not as an 154 | identifier. 155 | 156 | Whitespace (outside string literals, of course) is completely ignored, except 157 | where required to separate words. Comments are Intel-assembler-style: a single 158 | `;` demarks a comment until the next end-of-line. Control directives (such as 159 | `#include`) are allowed anywhere where whitespace is allowed. 160 | 161 | The syntax is comprised of hierarchical blocks. Each block contains a number 162 | of fields - starting with a keyword specifying the field type. A block is 163 | terminated with the `end` keyword. Some fields contain a limited number of 164 | parameters, and others are, or contain blocks. 165 | 166 | Hierarchy 167 | --------- 168 | 169 | The topmost block in the hierarchy is the `program` block. This must be the 170 | first block in the file (thus, `program` must be the first word in the file as 171 | well). The `program` block contains `script` fields, and `class` / `method` 172 | fields for "orphan" classes and methods (not owned by other objects in the 173 | hierarchy). Orphan methods are usually anonymous functions. The file version 174 | is also specified in the `program` block, using the `minorversion` and 175 | `majorversion` fields (both unsigned integers). 176 | 177 | `script` blocks have one mandatory `sinit` field (the script initialization 178 | method) and `trait` fields. 179 | 180 | A "trait" can be one of several kinds. The kind is specified right after the 181 | `trait` keyword, followed by the trait name (a multiname). Following the name 182 | are the trait fields, varying by trait kind: 183 | 184 | * `slot` / `const` : `slotid` (unsigned integer), `type` (multiname), `value` 185 | * `class` : `slotid`, `class` (the actual class block) 186 | * `function` : `slotid`, `method` (the actual method block) 187 | * `method` / `getter` / `setter` : `dispid` (unsigned integer), `method` 188 | 189 | Additionally, all traits may have `flag` fields, describing the trait's 190 | attributes (`FINAL` / `OVERRIDE` / `METADATA`), and `metadata` blocks. 191 | 192 | `metadata` blocks (which are ignored by the AVM) consist of a name string, and 193 | a series of `item` fields - each item having a key and value string. 194 | 195 | `class` blocks have mandatory `instance` and `cinit` fields, defining the 196 | class instance and the class initializer method respectively. They may also 197 | have `trait` fields and a `refid` field (the `refid` field is not part of the 198 | file format - it's an unique string to allow referencing the class, see above). 199 | 200 | `instance` blocks - always declared inline of their `class` block - must 201 | contain one `iinit` field (the instance initializer method), and may contain 202 | one `extends` field (multiname), `implements` fields (multinames), `flag` 203 | fields (`SEALED` / `FINAL` / `INTERFACE` / `PROTECTEDNS`), one `protectedns` 204 | field (namespace), and `trait` fields. 205 | 206 | `method` blocks may contain one `name` field (multiname), a `refid` field, 207 | `param` fields (multinames - this represents the parameter types), one 208 | `returns` field (multiname), `flag` fields (`NEED_ARGUMENTS` / 209 | `NEED_ACTIVATION` / `NEED_REST` / `HAS_OPTIONAL` / `SET_DXNS` / 210 | `HAS_PARAM_NAMES`), `optional` fields (values), `paramname` fields (strings), 211 | and a `body` field (method body). 212 | 213 | `body` blocks - always declared inline of their `method` block - must contain 214 | the `maxstack`, `localcount`, `initscopedepth` and `maxscopedepth` fields 215 | (unsigned integers), and a `code` field. It may also contain `try` and `trait` 216 | fields. 217 | 218 | `code` blocks - always declared inline of their `body` block - are somewhat 219 | different in syntax from other blocks - mostly in that they may contain 220 | labels. Labels follow the most common syntax - a word followed by a `:` 221 | character, optionally followed by a relative byte offset (in case of pointers 222 | inside instructions). Multiple instruction arguments are comma-separated. 223 | Instruction arguments' types depend on the instruction - see the `OpcodeInfo` 224 | array in `abcfile.d` for a reference. 225 | 226 | `try` blocks - always declared inline of their `body` block - represent an 227 | "exception" (try/catch) block. They contain five mandatory fields: `from`, 228 | `to` and `target` (names of labels representing start and end of the "try" 229 | block, and start of the "catch" block respectively), and `type` and `name` 230 | (multinames), representing the type and name of the exception variable. 231 | 232 | Values have the syntax *type* `(` *value* `)` . *type* can be one of 233 | `Integer`, `UInteger`, `Double`, `Utf8`, `Namespace`, `PackageNamespace`, 234 | `PackageInternalNs`, `ProtectedNamespace`, `ExplicitNamespace`, 235 | `StaticProtectedNs`, `PrivateNamespace`, `True`, `False`, `Null` or 236 | `Undefined`. The type of the value depends on *type*. Types `True`, `False`, 237 | `Null` and `Undefined` have no value. 238 | 239 | Constants 240 | --------- 241 | 242 | Multinames have the syntax *type* `(` *parameters* `)` . *type* can be one of 243 | `QName` / `QNameA`, `RTQName` / `RTQNameA`, `RTQNameL` / `RTQNameLA`, 244 | `Multiname` / `MultinameA`, `MultinameL` / `MultinameLA`, or `TypeName`. 245 | *parameters* depends on *type*: 246 | 247 | * `QName` / `QNameA` `(` *namespace* `,` *string* `)` 248 | * `RTQName` / `RTQNameA` `(` *string* `)` 249 | * `RTQNameL` / `RTQNameLA` `(` `)` 250 | * `Multiname` / `MultinameA` `(` *string* `,` *namespace-set* `)` 251 | * `MultinameL` / `MultinameLA` `(` *namespace-set* `)` 252 | * `TypeName` `(` *multiname* `<` *multiname [* `,` *multiname ... ]* `>` `)` 253 | 254 | Namespace sets have the syntax `[` *[ namespace [* `,` *namespace ... ] ]* `]` 255 | (that is, a comma-separated list of namespaces in square brackets). Empty 256 | namespace sets can be specified using `[]`. 257 | 258 | Namespaces have the syntax *type* `(` *string [* `,` *string ]* `)` . The 259 | first string indicates the namespace name. In the case that there are multiple 260 | distinct namespaces with the same type and name (as `PrivateNamespace` 261 | namespaces usually are), a second parameter may be present to uniquely 262 | distinguish them. Internally (the ABC file format), namespaces are 263 | distinguished by their numerical index. When disassembling, `rabcdasm` will 264 | attempt to assign descriptive labels to homonym namespaces based on their 265 | context. 266 | 267 | Strings have a syntax similar to C string literals. Strings start and end with 268 | a `"`. Supported escape sequences (a backslash followed by a letter) are `\n` 269 | (generates ASCII 0x0A), `\r` (ASCII 0x0D), and `\x` followed by two 270 | hexadecimal digits, which inserts the ASCII character with that code. Any 271 | other characters following a backslash generate that character - thus, you can 272 | escape backslashes using `\\` and double quotes using `\"`. When decompiling, 273 | high-ASCII characters (usually UTF-8) are not escaped - if you see gibberish 274 | instead of international text, configure your editor to open the files in 275 | UTF-8 encoding. 276 | 277 | Additionally, constant pool types (signed/unsigned integers, doubles, strings, 278 | namespaces, namespace sets and multinames) may also have the value `null` 279 | (which represents the index 0 in the ABC file). Note that `null` is 280 | conceptually different from zero, an empty string or empty namespace set. 281 | 282 | Macros 283 | ------ 284 | 285 | RABCDAsm has some basic macro-like capabilities, controlled by directives and 286 | variables. These bear some similarity to the C preprocessor, however these are 287 | processed in-loop rather than as a separate pre-processing step. 288 | 289 | ### Directives 290 | 291 | Directives start with a `#`, followed by a word identifying the directive: 292 | 293 | * `#include` *string* - inserts the contents of the file by the specified 294 | filename inline. Functionally equivalent to `#mixin #get` *string* , but 295 | faster. 296 | * `#mixin` *string* - inserts the contents of the specified string inline. 297 | Not very useful on its own. 298 | * `#call` *string* `(` *[ string [* `,` *string ... ] ]* `)` - same as 299 | `#mixin`, however it additionally sets the special variables `$1`, `$2` 300 | etc. to the contents of the specified arguments. When the end of the 301 | inserted string is reached, the old values of `$1`, `$2` etc. are restored. 302 | * `#get` *string* - inserts **a string containing** the contents of the file 303 | by the specified filename inline. Similar to #include, but it inserts a 304 | string (surrounded by `"` etc.) instead. 305 | * `#set` *word* *string* - assigns the contents of the string to the 306 | variable *word*. 307 | * `#unset` *word* - deletes the variable *word*. 308 | * `#privatens` *number* *string* - deprecated, currently ignored. 309 | * `#version` specifies the syntax version of the disassembly. Newer RABCDAsm 310 | versions may emit disassembly output that is not backwards-compatible, but 311 | should still understand older disassemblies. The versions are: 312 | 1. The first version. 313 | 2. Introduced in v1.11 to work around error in ABC format specification. 314 | 3. Introduced in v1.12 to support multiple non-private namespaces with 315 | the same name. This is the current version. 316 | 317 | ### Variables 318 | 319 | Variables are manipulated with the `#set` and `#unset` directives, and can be 320 | instantiated in two ways: 321 | 322 | 1. `$`*name* - this inserts the contents of the variable inline. Note that 323 | although variables are defined using a string syntax, they are not 324 | inserted as a string using this syntax. Thus, the code: 325 | 326 | #set str "Hello, world!" 327 | ... 328 | pushstring $str 329 | 330 | will expand to `pushstring Hello, world!`, which will result in an error. 331 | To correct the problem, add escaped quotes around the variable contents 332 | ( `#set str "\"Hello, world!\""` ), or use the second syntax: 333 | 334 | 2. `$"`*name*`"` - this inserts a string containing the contents of the 335 | variable inline. This syntax also works for `#call` arguments (e.g. 336 | `$"1"`). 337 | 338 | ### Example 339 | 340 | Here's an example of how to use the above features to create a macro which 341 | logs a string literal and the contents of a register: 342 | 343 | #set log " 344 | findpropstrict QName(PackageNamespace(\"\"), \"log\") 345 | pushstring $\"1\" 346 | getlocal $2 347 | callpropvoid QName(PackageNamespace(\"\"), \"log\"), 2 348 | " 349 | 350 | ; ... 351 | 352 | pushbyte 2 353 | pushbyte 2 354 | add_i 355 | setlocal1 356 | #call $"log"("two plus two equals", "1") 357 | 358 | Highlighting 359 | ------------ 360 | 361 | Included with the project is the file `asasm.hrc`, a simple syntax definition 362 | for the [Colorer take5][] syntax highlighting library. It should be 363 | straight-forward to adapt it to other syntax highlighting systems. 364 | 365 | [Colorer take5]: http://colorer.sourceforge.net/ 366 | 367 | Hacking 368 | ======= 369 | 370 | ABC is internally represented in two forms. The `ABCFile` class stores the raw 371 | data structures, as they appear in the binary file. `ASProgram` uses pointers 372 | instead of indexes, allowing easy manipulation without having to worry about 373 | record order or constant pools. Conversion between various states is done as 374 | follows: 375 | 376 | file.abc 377 | | ^ 378 | ------ ABCReader | | ABCWriter ---- 379 | / v | \ 380 | / ABCFile \ 381 | / | ^ \ 382 | rabcdasm---------- ABCtoAS | | AStoABC --------rabcasm 383 | \ v | / 384 | \ ASProgram / 385 | \ | ^ / 386 | --- Disassembler | | Assembler ---- 387 | v | 388 | file.asasm 389 | 390 | `AStoABC` will rebuild the constant pools, in a manner similar to Adobe's 391 | compilers (reverse-sorted by reference count). The exact order will almost 392 | surely be different, however. 393 | 394 | Should you need to write an utility to manipulate ABC, you can use the 395 | existing code to load the file to either an `ABCFile` or `ASProgram` instance, 396 | and perform the necessary manipulations using those classes. 397 | 398 | Tips 399 | ==== 400 | 401 | The following tips come from the author's experience and may be useful for 402 | RABCDAsm users. 403 | 404 | 1. Once you have disassembled a SWF file you intend to modify, you should 405 | immediately add the directory to a distributed source control system, such 406 | as [Git][] or [Mercurial][]. This will allow you to easily track and undo 407 | your changes, and easily merge your changes with new versions of SWF files. 408 | 409 | [Git]: http://git-scm.com/ 410 | [Mercurial]: http://mercurial.selenic.com/ 411 | 412 | 2. If you plan on making non-trivial changes to SWF files, you should install 413 | the [debug Flash Player][]. This will allow you to see validation and 414 | run-time error messages, instead of simply getting an empty window. 415 | 416 | [debug Flash Player]: http://www.adobe.com/support/flashplayer/downloads.html 417 | 418 | 3. The [Fiddler][] Web Debugging Proxy can be very useful for analyzing 419 | websites with SWF content. The following script fragment (which is to be 420 | placed in the `OnBeforeResponse` function) will automatically save all SWF 421 | files while preserving the directory structure. 422 | 423 | if (oSession.oResponse.headers.ExistsAndContains("Content-Type", 424 | "application/x-shockwave-flash")) { 425 | // Set desired path here 426 | var path:String = "C:\\Temp\\FiddlerCapture\\" + 427 | oSession.host + oSession.PathAndQuery; 428 | if (path.Contains('?')) 429 | path = path.Substring(0, path.IndexOf('?')); 430 | var dir:String = Path.GetDirectoryName(path); 431 | if (!Directory.Exists(dir)) 432 | Directory.CreateDirectory(dir); 433 | oSession.utilDecodeResponse(); 434 | oSession.SaveResponseBody(path); 435 | } 436 | 437 | A more robust version of the above snippet is available as a Fiddler plugin 438 | [here][FiddlerAutoCapture]. 439 | 440 | Once you have edited a SWF file, you can use Fiddler's [AutoResponder][] to 441 | replace the original file with your modified version. 442 | 443 | [Fiddler]: http://www.fiddler2.com/fiddler2/ 444 | [AutoResponder]: http://www.fiddler2.com/fiddler2/help/AutoResponder.asp 445 | [FiddlerAutoCapture]: https://github.com/CyberShadow/FiddlerAutoCapture 446 | 447 | Limitations 448 | =========== 449 | 450 | * None known. 451 | 452 | License 453 | ======= 454 | 455 | RABCDAsm is distributed under the terms of the GPL v3 or later, with the 456 | exception of `murmurhash2a.d`, `zlibx.d` and LZMA components, which are in the 457 | public domain, and `asasm.hrc`, which is tri-licensed under the MPL 1.1/GPL 458 | 2.0/LGPL 2.1. The full text of the GNU General Public License can be found in 459 | the file `COPYING`. 460 | -------------------------------------------------------------------------------- /abcexport.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module abcexport; 20 | 21 | import std.file; 22 | import std.path; 23 | import std.conv; 24 | import std.stdio; 25 | import swffile; 26 | 27 | void main(string[] args) 28 | { 29 | if (args.length == 1) 30 | throw new Exception("No file specified"); 31 | foreach (arg; args[1..$]) 32 | try 33 | { 34 | scope swf = SWFFile.read(cast(ubyte[])read(arg)); 35 | uint count = 0; 36 | foreach (ref tag; swf.tags) 37 | if ((tag.type == TagType.DoABC || tag.type == TagType.DoABC2)) 38 | { 39 | ubyte[] abc; 40 | if (tag.type == TagType.DoABC) 41 | abc = tag.data; 42 | else 43 | { 44 | auto p = tag.data.ptr+4; // skip flags 45 | while (*p++) {} // skip name 46 | abc = tag.data[p-tag.data.ptr..$]; 47 | } 48 | std.file.write(stripExtension(arg) ~ "-" ~ to!string(count++) ~ ".abc", abc); 49 | } 50 | if (count == 0) 51 | throw new Exception("No DoABC tags found"); 52 | } 53 | catch (Exception e) 54 | writefln("Error while processing %s: %s", arg, e); 55 | } 56 | -------------------------------------------------------------------------------- /abcreplace.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2012 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module abcreplace; 20 | 21 | import std.file; 22 | import std.conv; 23 | import swffile; 24 | 25 | void main(string[] args) 26 | { 27 | if (args.length != 4) 28 | throw new Exception("Bad arguments. Usage: abcreplace file.swf index code.abc"); 29 | auto swf = SWFFile.read(cast(ubyte[])read(args[1])); 30 | auto index = to!uint(args[2]); 31 | uint count; 32 | foreach (ref tag; swf.tags) 33 | if ((tag.type == TagType.DoABC || tag.type == TagType.DoABC2) && count++ == index) 34 | { 35 | auto abc = cast(ubyte[])read(args[3]); 36 | if (tag.type == TagType.DoABC) 37 | tag.data = abc; 38 | else 39 | { 40 | auto p = tag.data.ptr+4; // skip flags 41 | while (*p++) {} // skip name 42 | tag.data = tag.data[0..p-tag.data.ptr] ~ abc; 43 | } 44 | tag.length = cast(uint)tag.data.length; 45 | write(args[1], swf.write()); 46 | return; 47 | } 48 | throw new Exception("Not enough DoABC tags in file"); 49 | } 50 | -------------------------------------------------------------------------------- /asasm.hrc: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | 10 | ActionScript Assembler Syntax (RABCDAsm variant) 11 | 13 | ]]> 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 375 | -------------------------------------------------------------------------------- /autodata.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2012, 2014 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module autodata; 20 | 21 | import murmurhash2a; 22 | import std.traits; 23 | public import std.conv; 24 | 25 | string addAutoField(string name, bool reverseSort = false) 26 | { 27 | return `mixin(typeof(handler).getMixin!(typeof(` ~ name ~ `), "` ~ name ~ `", ` ~ (reverseSort ? "true" : "false") ~`));`; 28 | } 29 | 30 | template AutoCompare() 31 | { 32 | static if (is(typeof(this)==class)) 33 | { 34 | alias typeof(this) _AutoDataTypeReference; 35 | alias Object _AutoDataOtherTypeReference; 36 | 37 | override hash_t toHash() const { try { return _AutoDataHash(); } catch(object.Exception e) { assert(0, e.msg); } } 38 | override bool opEquals(Object o) const { return _AutoDataEquals(o); } 39 | override int opCmp(Object o) const { return _AutoDataCmp(o); } 40 | } 41 | else // struct 42 | { 43 | alias const(typeof(this)*) _AutoDataTypeReference; 44 | alias const(typeof(this)*) _AutoDataOtherTypeReference; 45 | 46 | hash_t toHash() const { return _AutoDataHash(); } 47 | bool opEquals(ref const typeof(this) s) const { return _AutoDataEquals(&s); } 48 | int opCmp(ref const typeof(this) s) const { return _AutoDataCmp(&s); } 49 | } 50 | 51 | @trusted private hash_t _AutoDataHash() const 52 | { 53 | HashDataHandler handler; 54 | handler.hasher.Begin(); 55 | processData!(void, q{}, q{})(handler); 56 | return handler.hasher.End(); 57 | } 58 | 59 | private bool _AutoDataEquals(_AutoDataOtherTypeReference other) const 60 | { 61 | auto handler = EqualsDataHandler!_AutoDataTypeReference(cast(_AutoDataTypeReference) other); 62 | if (handler.other is null) 63 | return false; 64 | return processData!(bool, q{auto _AutoDataOther = handler.other;}, q{return true;})(handler); 65 | } 66 | 67 | private int _AutoDataCmp(_AutoDataOtherTypeReference other) const 68 | { 69 | auto handler = CmpDataHandler!_AutoDataTypeReference(cast(_AutoDataTypeReference) other); 70 | if (handler.other is null) 71 | return false; 72 | return processData!(int, q{auto _AutoDataOther = handler.other;}, "return 0;")(handler); 73 | } 74 | } 75 | 76 | template AutoToString() 77 | { 78 | static if (is(typeof(this)==class)) 79 | override string toString() const { return _AutoDataToString(); } 80 | else // struct 81 | string toString() const { return _AutoDataToString(); } 82 | 83 | string _AutoDataToString() const 84 | { 85 | ToStringDataHandler handler; 86 | return processData!(string, "string _AutoDataResult;", "return _AutoDataResult;")(handler); 87 | } 88 | } 89 | 90 | template ProcessAllData() 91 | { 92 | R processData(R, string prolog, string epilog, H)(ref H handler) const 93 | { 94 | mixin(prolog); 95 | foreach (i, T; this.tupleof) 96 | mixin(addAutoField(this.tupleof[i].stringof[5..$])); // remove "this." 97 | mixin(epilog); 98 | } 99 | } 100 | 101 | /// For data handlers that only need to look at the raw data (currently only HashDataHandler) 102 | template RawDataHandlerWrapper() 103 | { 104 | template getMixin(T, string name, bool reverseSort) 105 | { 106 | enum getMixin = getMixinRecursive!(T, "this." ~ name, ""); 107 | } 108 | 109 | template getMixinRecursive(T, string name, string loopDepth) 110 | { 111 | static if (is(T U : U[])) 112 | enum getMixinRecursive = 113 | "{ bool _AutoDataNullTest = " ~ name ~ " is null; " ~ getRawMixin!("&_AutoDataNullTest", "bool.sizeof") ~ "}" ~ 114 | (!hasAliasing!(U) ? 115 | getRawMixin!(name ~ ".ptr", name ~ ".length") 116 | : 117 | "foreach (ref _AutoDataArrayItem" ~ loopDepth ~ "; " ~ name ~ ") {" ~ getMixinRecursive!(U, "_AutoDataArrayItem" ~ loopDepth, loopDepth~"Item") ~ "}" 118 | ); 119 | else 120 | static if (!hasAliasing!(T)) 121 | enum getMixinRecursive = getRawMixin!("&" ~ name, name ~ ".sizeof"); 122 | else 123 | static if (is(T==struct)) 124 | enum getMixinRecursive = name ~ ".processData!(void, ``, ``)(handler);"; 125 | else 126 | static if (is(T==class)) 127 | enum getMixinRecursive = "if ("~name~" !is null) " ~ name ~ ".processData!(void, ``, ``)(handler);"; 128 | else 129 | static assert(0, "Don't know how to process type: " ~ T.stringof); 130 | } 131 | } 132 | 133 | struct HashDataHandler 134 | { 135 | mixin RawDataHandlerWrapper; 136 | 137 | MurmurHash2A hasher; 138 | 139 | template getRawMixin(string ptr, string len) 140 | { 141 | enum getRawMixin = "handler.hasher.Add(" ~ ptr ~ ", to!int(" ~ len ~ "));"; 142 | } 143 | } 144 | 145 | struct EqualsDataHandler(O) 146 | { 147 | O other; 148 | 149 | template nullCheck(T, string name) 150 | { 151 | static if (is(typeof(T.init is null))) 152 | enum nullCheck = "if ((this." ~ name ~ " is null) != (_AutoDataOther." ~ name ~ " is null)) return false;"; 153 | else 154 | enum nullCheck = ""; 155 | } 156 | 157 | template getMixin(T, string name, bool reverseSort) 158 | { 159 | enum getMixin = nullCheck!(T, name) ~ "if (this." ~ name ~ " != _AutoDataOther." ~ name ~ ") return false;"; 160 | } 161 | } 162 | 163 | struct CmpDataHandler(O) 164 | { 165 | O other; 166 | 167 | template getMixin(T, string name, bool reverseSort) 168 | { 169 | enum getMixin = getMixinComposite!(T, name, reverseSort).code; 170 | } 171 | 172 | template nullCheck(T, string name, string reverseStr) 173 | { 174 | static if (is(typeof(T.init is null))) 175 | enum nullCheck = " 176 | if (this."~name~" is null && _AutoDataOther."~name~" is null) 177 | { /* skip */ } 178 | else 179 | if (this."~name~" is null && _AutoDataOther."~name~" !is null) 180 | return " ~ reverseStr ~ "(-1); 181 | else 182 | if (this."~name~" !is null && _AutoDataOther."~name~" is null) 183 | return " ~ reverseStr ~ "( 1); 184 | else"; 185 | else 186 | enum nullCheck = ""; 187 | } 188 | 189 | template getMixinComposite(T, string name, bool reverseSort) 190 | { 191 | enum reverseStr = reverseSort ? "-" : ""; 192 | static if (is(T U : U[])) 193 | enum arrCode = "{ int _AutoDataCmp = cast(int)(this." ~ name ~ " !is null) - cast(int)(_AutoDataOther." ~ name ~ " !is null); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; 194 | else 195 | enum arrCode = ""; 196 | 197 | static if (is(T == string) && is(std.string.cmp)) 198 | enum dataCode = "{ int _AutoDataCmp = std.string.cmp(this." ~ name ~ ", _AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; 199 | else 200 | static if (is(T == int)) 201 | enum dataCode = "{ int _AutoDataCmp = this." ~ name ~ " - _AutoDataOther." ~ name ~ "; if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; // TODO: use long? 202 | else 203 | static if (is(typeof(T.opCmp))) 204 | enum dataCode = nullCheck!(T, name, reverseStr) 205 | ~ "{ int _AutoDataCmp = this." ~ name ~ ".opCmp(cast()_AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; 206 | else 207 | enum dataCode = "if (this." ~ name ~ " < _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "(-1);" ~ 208 | "if (this." ~ name ~ " > _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "( 1);"; 209 | enum code = arrCode ~ dataCode; 210 | } 211 | } 212 | 213 | struct ToStringDataHandler 214 | { 215 | template getMixinSingle(T, string name) 216 | { 217 | /* 218 | enum getMixinSingle = " 219 | static if (is(typeof(_AutoDataResult ~= " ~ name ~ ".toString()))) 220 | _AutoDataResult ~= " ~ name ~ ".toString(); 221 | else 222 | _AutoDataResult ~= to!string(" ~ name ~ "); 223 | "; 224 | */ 225 | static if (is(typeof(T.init is null))) 226 | enum getMixinSingle = "_AutoDataResult ~= " ~ name ~ " ? to!string(" ~ name ~ ") : `null`;"; 227 | else 228 | enum getMixinSingle = "_AutoDataResult ~= to!string(" ~ name ~ ");"; 229 | } 230 | 231 | template getMixinBody(T, string name) 232 | { 233 | // TODO: arrays of arrays 234 | static if (is(T U : U[]) && !is(T : const(char)[])) 235 | { 236 | enum getMixinBody = " 237 | _AutoDataResult ~= ` [ `; 238 | foreach (_AutoDataArrayIndex, _AutoDataArrayItem; " ~ name ~ ") 239 | { 240 | if (_AutoDataArrayIndex) _AutoDataResult ~= ` , `; 241 | " ~ getMixinSingle!(U, "_AutoDataArrayItem") ~ " 242 | } 243 | _AutoDataResult ~= ` ] `; 244 | "; 245 | } 246 | else 247 | enum getMixinBody = getMixinSingle!(T, name); 248 | } 249 | 250 | template getMixin(T, string name, bool reverseSort) 251 | { 252 | enum getMixin = 253 | "_AutoDataResult ~= `" ~ name ~ " = `;" ~ 254 | getMixinBody!(T, name) ~ 255 | "_AutoDataResult ~= ` `;"; 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /build_rabcdasm.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2012, 2013, 2016 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | /// A simple tool to build RABCDAsm in one command. 20 | /// You can use the DC and DCFLAGS environment variables to override the detected compiler and compilation flags. 21 | /// You can also pass program names or compilation options on the command-line to override the default ones. 22 | 23 | module build_rabcdasm; 24 | 25 | version(D_Version2) 26 | { /* All OK */ } 27 | else 28 | static assert(false, "Unsupported D version.\nThis software requires a D2 ( http://dlang.org/ ) compiler to build."); 29 | 30 | version(D_Version2): 31 | 32 | version(DigitalMars) 33 | const DEFAULT_COMPILER = "dmd"; 34 | else 35 | const DEFAULT_COMPILER = "gdmd"; 36 | 37 | const DEFAULT_FLAGS = "-O -inline"; 38 | const LZMA_FLAGS = ["-version=HAVE_LZMA"]; 39 | 40 | import std.exception; 41 | import std.file; 42 | import std.process; 43 | import std.stdio; 44 | import std.string; 45 | 46 | string compiler; 47 | string[] flags; 48 | 49 | void compile(string program) 50 | { 51 | stderr.writeln("* Building ", program); 52 | enforce(spawnProcess(["rdmd", "--build-only", "--compiler=" ~ compiler] ~ flags ~ program).wait() == 0, "Compilation of " ~ program ~ " failed"); 53 | } 54 | 55 | void test(string code, in string[] extraFlags=null) 56 | { 57 | const BASE = "build_rabcdasm_buildtest"; 58 | const FN = BASE ~ ".d"; 59 | std.file.write(FN, code); 60 | scope(exit) foreach (de; dirEntries(".", BASE ~ "*", SpanMode.shallow)) remove(de.name); 61 | enforce(spawnProcess(["rdmd", "--force", "--compiler=" ~ compiler, "-od."] ~ flags ~ extraFlags ~ FN).wait() == 0, "Test failed"); 62 | stderr.writeln(" >>> OK"); 63 | } 64 | 65 | void testBug(string description, int bugId, string code) 66 | { 67 | stderr.writefln("* Checking for compiler bug %d...", bugId); 68 | scope(failure) 69 | { 70 | stderr.writefln("Compiler bug detected: %s ( https://issues.dlang.org/show_bug.cgi?id=%d ).", description, bugId); 71 | stderr.writeln("Try again with a different D compiler, compiler version, or build flags (DCFLAGS environment variable)"); 72 | } 73 | test(code); 74 | } 75 | 76 | int main(string[] args) 77 | { 78 | try 79 | { 80 | auto programs = ["rabcasm", "rabcdasm", "abcexport", "abcreplace", "swfbinexport", "swfbinreplace", "swfdecompress", "swf7zcompress"]; 81 | 82 | compiler = environment.get("DC", DEFAULT_COMPILER); 83 | flags = environment.get("DCFLAGS", DEFAULT_FLAGS).split(" "); 84 | 85 | string[] optionArgs, programArgs; 86 | foreach (arg; args[1..$]) 87 | (arg.startsWith("-") ? optionArgs : programArgs) ~= arg; 88 | 89 | if (optionArgs.length) 90 | flags = optionArgs; 91 | if (programArgs.length) 92 | programs = programArgs; 93 | 94 | stderr.writeln("* Checking for working compiler..."); 95 | test(` 96 | void main() {} 97 | `); 98 | 99 | testBug("[REG 2.064] Wrong code with -O on x86_64 for char comparisons", 11508, ` 100 | import assembler; int main() { foreach (c; "_") if (!Assembler.isWordChar(c)) return 1; return 0; } 101 | `); 102 | testBug("[REG 2.069] Wrong double-to-string conversion with -O", 15861, ` 103 | import std.format; int main() { return format("%.18g", 4286853117.0) == "4286853117" ? 0 : 1; } 104 | `); 105 | 106 | bool haveLZMA; 107 | 108 | stderr.writeln("* Checking for LZMA..."); 109 | try 110 | { 111 | test(` 112 | import lzma, std.exception; 113 | void main() 114 | { 115 | LZMAHeader header; 116 | auto data = cast(immutable(ubyte)[])"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; 117 | auto cdata = lzmaCompress(data, &header); 118 | header.decompressedSize = data.length; 119 | auto ddata = lzmaDecompress(header, cdata); 120 | enforce(data == ddata); 121 | } 122 | `, LZMA_FLAGS); 123 | 124 | // Test succeeded 125 | haveLZMA = true; 126 | } 127 | catch (Exception e) 128 | stderr.writeln(" >>> LZMA not found, building without LZMA support."); 129 | 130 | if (haveLZMA) 131 | flags ~= LZMA_FLAGS; 132 | 133 | foreach (program; programs) 134 | compile(program); 135 | 136 | if (haveLZMA) 137 | compile("swflzmacompress"); 138 | 139 | return 0; 140 | } 141 | catch (Exception e) 142 | { 143 | stderr.writeln("Error: ", e.msg); 144 | return 1; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /common.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012, 2014 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module common; 20 | 21 | import std.array; 22 | import std.path; 23 | import std.stdio; 24 | import std.string; 25 | 26 | string longPath(string s) 27 | { 28 | version(Windows) 29 | { 30 | if (s.startsWith(`\\`)) 31 | return s; 32 | else 33 | return `\\?\` ~ s.absolutePath().buildNormalizedPath().replace(`/`, `\`); 34 | } 35 | else 36 | return s; 37 | } 38 | 39 | File openFile(string fn, string mode) 40 | { 41 | File f; 42 | static if (is(typeof(&f.windowsHandleOpen))) 43 | { 44 | import core.sys.windows.windows; 45 | 46 | import std.exception; 47 | import std.utf; 48 | import std.windows.syserror; 49 | 50 | string winMode; 51 | foreach (c; mode) 52 | switch (c) 53 | { 54 | case 'r': 55 | case 'w': 56 | case 'a': 57 | case '+': 58 | winMode ~= c; 59 | break; 60 | case 'b': 61 | case 't': 62 | break; 63 | default: 64 | assert(false, "Unknown character in mode"); 65 | } 66 | DWORD access, creation; 67 | bool append; 68 | switch (winMode) 69 | { 70 | case "r" : access = GENERIC_READ ; creation = OPEN_EXISTING; break; 71 | case "r+": access = GENERIC_READ | GENERIC_WRITE; creation = OPEN_EXISTING; break; 72 | case "w" : access = GENERIC_WRITE; creation = OPEN_ALWAYS ; break; 73 | case "w+": access = GENERIC_READ | GENERIC_WRITE; creation = OPEN_ALWAYS ; break; 74 | case "a" : access = GENERIC_WRITE; creation = OPEN_ALWAYS ; append = true; break; 75 | case "a+": assert(false, "Not implemented"); // requires two file pointers 76 | default: assert(false, "Bad file mode: " ~ mode); 77 | } 78 | 79 | auto pathW = toUTF16z(longPath(fn)); 80 | auto h = CreateFileW(pathW, access, FILE_SHARE_READ, null, creation, 0, HANDLE.init); 81 | enforce(h != INVALID_HANDLE_VALUE, "Failed to open file \"" ~ fn ~ "\": " ~ sysErrorString(GetLastError())); 82 | 83 | assert(!append, "'a' mode not implemented"); 84 | 85 | f.windowsHandleOpen(h, mode); 86 | } 87 | else 88 | f.open(fn, mode); 89 | return f; 90 | } 91 | -------------------------------------------------------------------------------- /deimos/lzma.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file api/lzma.h 3 | * \brief The public API of liblzma data compression library 4 | * 5 | * liblzma is a public domain general-purpose data compression library with 6 | * a zlib-like API. The native file format is .xz, but also the old .lzma 7 | * format and raw (no headers) streams are supported. Multiple compression 8 | * algorithms (filters) are supported. Currently LZMA2 is the primary filter. 9 | * 10 | * liblzma is part of XZ Utils . XZ Utils includes 11 | * a gzip-like command line tool named xz and some other tools. XZ Utils 12 | * is developed and maintained by Lasse Collin. 13 | * 14 | * Major parts of liblzma are based on Igor Pavlov's public domain LZMA SDK 15 | * . 16 | * 17 | * The SHA-256 implementation is based on the public domain code found from 18 | * 7-Zip , which has a modified version of the public 19 | * domain SHA-256 code found from Crypto++ . 20 | * The SHA-256 code in Crypto++ was written by Kevin Springle and Wei Dai. 21 | */ 22 | 23 | /* 24 | * Author: Lasse Collin 25 | * 26 | * This file has been put into the public domain. 27 | * You can do whatever you want with this file. 28 | */ 29 | 30 | module deimos.lzma; 31 | 32 | /*********** 33 | * nothrow * 34 | ***********/ 35 | 36 | /* 37 | * None of the functions in liblzma may throw an exception. Even 38 | * the functions that use callback functions won't throw exceptions, 39 | * because liblzma would break if a callback function threw an exception. 40 | */ 41 | //lzma_nothrow --> nothrow 42 | 43 | 44 | /******************** 45 | * GNU C extensions * 46 | ********************/ 47 | 48 | /* 49 | * GNU C extensions are used conditionally in the public API. It doesn't 50 | * break anything if these are sometimes enabled and sometimes not, only 51 | * affects warnings and optimizations. 52 | */ 53 | 54 | //lzma_attr_pure --> pure 55 | //lzma_attr_const --> const 56 | //lzma_attr_warn_unused_result --> n/a 57 | 58 | 59 | /************** 60 | * Subheaders * 61 | **************/ 62 | public import deimos.lzma_.version_; 63 | public import deimos.lzma_.base; 64 | public import deimos.lzma_.vli; 65 | public import deimos.lzma_.check; 66 | 67 | /* Filters */ 68 | public import deimos.lzma_.filter; 69 | public import deimos.lzma_.bcj; 70 | public import deimos.lzma_.delta; 71 | public import deimos.lzma_.lzma; 72 | 73 | /* Container formats */ 74 | public import deimos.lzma_.container; 75 | 76 | /* Advanced features */ 77 | public import deimos.lzma_.stream_flags; 78 | public import deimos.lzma_.block; 79 | public import deimos.lzma_.index; 80 | public import deimos.lzma_.index_hash; 81 | 82 | /* Hardware information */ 83 | public import deimos.lzma_.hardware; 84 | -------------------------------------------------------------------------------- /deimos/lzma_/bcj.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/bcj.h 3 | * \brief Branch/Call/Jump conversion filters 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.bcj; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | /* Filter IDs for lzma_filter.id */ 21 | 22 | enum LZMA_FILTER_X86 = 0x04UL; 23 | /**< 24 | * Filter for x86 binaries 25 | */ 26 | 27 | 28 | enum LZMA_FILTER_POWERPC = 0x05UL; 29 | /**< 30 | * Filter for Big endian PowerPC binaries 31 | */ 32 | 33 | enum LZMA_FILTER_IA64 = 0x06UL; 34 | /**< 35 | * Filter for IA-64 (Itanium) binaries. 36 | */ 37 | 38 | enum LZMA_FILTER_ARM = 0x07UL; 39 | /**< 40 | * Filter for ARM binaries. 41 | */ 42 | 43 | enum LZMA_FILTER_ARMTHUMB = 0x08UL; 44 | /**< 45 | * Filter for ARM-Thumb binaries. 46 | */ 47 | 48 | enum LZMA_FILTER_SPARC = 0x09UL; 49 | /**< 50 | * Filter for SPARC binaries. 51 | */ 52 | 53 | 54 | /** 55 | * \brief Options for BCJ filters 56 | * 57 | * The BCJ filters never change the size of the data. Specifying options 58 | * for them is optional: if pointer to options is NULL, default value is 59 | * used. You probably never need to specify options to BCJ filters, so just 60 | * set the options pointer to NULL and be happy. 61 | * 62 | * If options with non-default values have been specified when encoding, 63 | * the same options must also be specified when decoding. 64 | * 65 | * \note At the moment, none of the BCJ filters support 66 | * LZMA_SYNC_FLUSH. If LZMA_SYNC_FLUSH is specified, 67 | * LZMA_OPTIONS_ERROR will be returned. If there is need, 68 | * partial support for LZMA_SYNC_FLUSH can be added in future. 69 | * Partial means that flushing would be possible only at 70 | * offsets that are multiple of 2, 4, or 16 depending on 71 | * the filter, except x86 which cannot be made to support 72 | * LZMA_SYNC_FLUSH predictably. 73 | */ 74 | struct lzma_options_bcj 75 | { 76 | /** 77 | * \brief Start offset for conversions 78 | * 79 | * This setting is useful only when the same filter is used 80 | * _separately_ for multiple sections of the same executable file, 81 | * and the sections contain cross-section branch/call/jump 82 | * instructions. In that case it is beneficial to set the start 83 | * offset of the non-first sections so that the relative addresses 84 | * of the cross-section branch/call/jump instructions will use the 85 | * same absolute addresses as in the first section. 86 | * 87 | * When the pointer to options is NULL, the default value (zero) 88 | * is used. 89 | */ 90 | uint start_offset; 91 | } 92 | -------------------------------------------------------------------------------- /deimos/lzma_/block.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/block.h 3 | * \brief .xz Block handling 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.block; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | //TODO: initialize fields to void? 21 | /** 22 | * \brief Options for the Block and Block Header encoders and decoders 23 | * 24 | * Different Block handling functions use different parts of this structure. 25 | * Some read some members, other functions write, and some do both. Only the 26 | * members listed for reading need to be initialized when the specified 27 | * functions are called. The members marked for writing will be assigned 28 | * new values at some point either by calling the given function or by 29 | * later calls to lzma_code(). 30 | */ 31 | struct lzma_block 32 | { 33 | /** 34 | * \brief Block format version 35 | * 36 | * To prevent API and ABI breakages if new features are needed in 37 | * the Block field, a version number is used to indicate which 38 | * fields in this structure are in use. For now, version must always 39 | * be zero. With non-zero version, most Block related functions will 40 | * return LZMA_OPTIONS_ERROR. 41 | * 42 | * Read by: 43 | * - All functions that take pointer to lzma_block as argument, 44 | * including lzma_block_header_decode(). 45 | * 46 | * Written by: 47 | * - lzma_block_header_decode() 48 | */ 49 | uint version_; 50 | 51 | /** 52 | * \brief Size of the Block Header field 53 | * 54 | * This is always a multiple of four. 55 | * 56 | * Read by: 57 | * - lzma_block_header_encode() 58 | * - lzma_block_header_decode() 59 | * - lzma_block_compressed_size() 60 | * - lzma_block_unpadded_size() 61 | * - lzma_block_total_size() 62 | * - lzma_block_decoder() 63 | * - lzma_block_buffer_decode() 64 | * 65 | * Written by: 66 | * - lzma_block_header_size() 67 | * - lzma_block_buffer_encode() 68 | */ 69 | 70 | uint header_size; 71 | enum LZMA_BLOCK_HEADER_SIZE_MIN = 8; 72 | enum LZMA_BLOCK_HEADER_SIZE_MAX = 1024; 73 | 74 | /** 75 | * \brief Type of integrity Check 76 | * 77 | * The Check ID is not stored into the Block Header, thus its value 78 | * must be provided also when decoding. 79 | * 80 | * Read by: 81 | * - lzma_block_header_encode() 82 | * - lzma_block_header_decode() 83 | * - lzma_block_compressed_size() 84 | * - lzma_block_unpadded_size() 85 | * - lzma_block_total_size() 86 | * - lzma_block_encoder() 87 | * - lzma_block_decoder() 88 | * - lzma_block_buffer_encode() 89 | * - lzma_block_buffer_decode() 90 | */ 91 | lzma_check check; 92 | 93 | /** 94 | * \brief Size of the Compressed Data in bytes 95 | * 96 | * Encoding: If this is not LZMA_VLI_UNKNOWN, Block Header encoder 97 | * will store this value to the Block Header. Block encoder doesn't 98 | * care about this value, but will set it once the encoding has been 99 | * finished. 100 | * 101 | * Decoding: If this is not LZMA_VLI_UNKNOWN, Block decoder will 102 | * verify that the size of the Compressed Data field matches 103 | * compressed_size. 104 | * 105 | * Usually you don't know this value when encoding in streamed mode, 106 | * and thus cannot write this field into the Block Header. 107 | * 108 | * In non-streamed mode you can reserve space for this field before 109 | * encoding the actual Block. After encoding the data, finish the 110 | * Block by encoding the Block Header. Steps in detail: 111 | * 112 | * - Set compressed_size to some big enough value. If you don't know 113 | * better, use LZMA_VLI_MAX, but remember that bigger values take 114 | * more space in Block Header. 115 | * 116 | * - Call lzma_block_header_size() to see how much space you need to 117 | * reserve for the Block Header. 118 | * 119 | * - Encode the Block using lzma_block_encoder() and lzma_code(). 120 | * It sets compressed_size to the correct value. 121 | * 122 | * - Use lzma_block_header_encode() to encode the Block Header. 123 | * Because space was reserved in the first step, you don't need 124 | * to call lzma_block_header_size() anymore, because due to 125 | * reserving, header_size has to be big enough. If it is "too big", 126 | * lzma_block_header_encode() will add enough Header Padding to 127 | * make Block Header to match the size specified by header_size. 128 | * 129 | * Read by: 130 | * - lzma_block_header_size() 131 | * - lzma_block_header_encode() 132 | * - lzma_block_compressed_size() 133 | * - lzma_block_unpadded_size() 134 | * - lzma_block_total_size() 135 | * - lzma_block_decoder() 136 | * - lzma_block_buffer_decode() 137 | * 138 | * Written by: 139 | * - lzma_block_header_decode() 140 | * - lzma_block_compressed_size() 141 | * - lzma_block_encoder() 142 | * - lzma_block_decoder() 143 | * - lzma_block_buffer_encode() 144 | * - lzma_block_buffer_decode() 145 | */ 146 | lzma_vli compressed_size; 147 | 148 | /** 149 | * \brief Uncompressed Size in bytes 150 | * 151 | * This is handled very similarly to compressed_size above. 152 | * 153 | * uncompressed_size is needed by fewer functions than 154 | * compressed_size. This is because uncompressed_size isn't 155 | * needed to validate that Block stays within proper limits. 156 | * 157 | * Read by: 158 | * - lzma_block_header_size() 159 | * - lzma_block_header_encode() 160 | * - lzma_block_decoder() 161 | * - lzma_block_buffer_decode() 162 | * 163 | * Written by: 164 | * - lzma_block_header_decode() 165 | * - lzma_block_encoder() 166 | * - lzma_block_decoder() 167 | * - lzma_block_buffer_encode() 168 | * - lzma_block_buffer_decode() 169 | */ 170 | lzma_vli uncompressed_size; 171 | 172 | /** 173 | * \brief Array of filters 174 | * 175 | * There can be 1-4 filters. The end of the array is marked with 176 | * .id = LZMA_VLI_UNKNOWN. 177 | * 178 | * Read by: 179 | * - lzma_block_header_size() 180 | * - lzma_block_header_encode() 181 | * - lzma_block_encoder() 182 | * - lzma_block_decoder() 183 | * - lzma_block_buffer_encode() 184 | * - lzma_block_buffer_decode() 185 | * 186 | * Written by: 187 | * - lzma_block_header_decode(): Note that this does NOT free() 188 | * the old filter options structures. All unused filters[] will 189 | * have .id == LZMA_VLI_UNKNOWN and .options == NULL. If 190 | * decoding fails, all filters[] are guaranteed to be 191 | * LZMA_VLI_UNKNOWN and NULL. 192 | * 193 | * \note Because of the array is terminated with 194 | * .id = LZMA_VLI_UNKNOWN, the actual array must 195 | * have LZMA_FILTERS_MAX + 1 members or the Block 196 | * Header decoder will overflow the buffer. 197 | */ 198 | lzma_filter *filters; 199 | 200 | /** 201 | * \brief Raw value stored in the Check field 202 | * 203 | * After successful coding, the first lzma_check_size(check) bytes 204 | * of this array contain the raw value stored in the Check field. 205 | * 206 | * Note that CRC32 and CRC64 are stored in little endian byte order. 207 | * Take it into account if you display the Check values to the user. 208 | * 209 | * Written by: 210 | * - lzma_block_encoder() 211 | * - lzma_block_decoder() 212 | * - lzma_block_buffer_encode() 213 | * - lzma_block_buffer_decode() 214 | */ 215 | ubyte[LZMA_CHECK_SIZE_MAX] raw_check; 216 | 217 | /* 218 | * Reserved space to allow possible future extensions without 219 | * breaking the ABI. You should not touch these, because the names 220 | * of these variables may change. These are and will never be used 221 | * with the currently supported options, so it is safe to leave these 222 | * uninitialized. 223 | */ 224 | void *reserved_ptr1; 225 | void *reserved_ptr2; 226 | void *reserved_ptr3; 227 | uint reserved_int1; 228 | uint reserved_int2; 229 | lzma_vli reserved_int3; 230 | lzma_vli reserved_int4; 231 | lzma_vli reserved_int5; 232 | lzma_vli reserved_int6; 233 | lzma_vli reserved_int7; 234 | lzma_vli reserved_int8; 235 | lzma_reserved_enum reserved_enum1; 236 | lzma_reserved_enum reserved_enum2; 237 | lzma_reserved_enum reserved_enum3; 238 | lzma_reserved_enum reserved_enum4; 239 | lzma_bool reserved_bool1; 240 | lzma_bool reserved_bool2; 241 | lzma_bool reserved_bool3; 242 | lzma_bool reserved_bool4; 243 | lzma_bool reserved_bool5; 244 | lzma_bool reserved_bool6; 245 | lzma_bool reserved_bool7; 246 | lzma_bool reserved_bool8; 247 | } 248 | 249 | 250 | /** 251 | * \brief Decode the Block Header Size field 252 | * 253 | * To decode Block Header using lzma_block_header_decode(), the size of the 254 | * Block Header has to be known and stored into lzma_block.header_size. 255 | * The size can be calculated from the first byte of a Block using this macro. 256 | * Note that if the first byte is 0x00, it indicates beginning of Index; use 257 | * this macro only when the byte is not 0x00. 258 | * 259 | * There is no encoding macro, because Block Header encoder is enough for that. 260 | */ 261 | template lzma_block_header_size_decode(uint b) 262 | { 263 | enum lzma_block_header_size_decode = (b+1)*4; 264 | } 265 | 266 | 267 | /** 268 | * \brief Calculate Block Header Size 269 | * 270 | * Calculate the minimum size needed for the Block Header field using the 271 | * settings specified in the lzma_block structure. Note that it is OK to 272 | * increase the calculated header_size value as long as it is a multiple of 273 | * four and doesn't exceed LZMA_BLOCK_HEADER_SIZE_MAX. Increasing header_size 274 | * just means that lzma_block_header_encode() will add Header Padding. 275 | * 276 | * \return - LZMA_OK: Size calculated successfully and stored to 277 | * block->header_size. 278 | * - LZMA_OPTIONS_ERROR: Unsupported version, filters or 279 | * filter options. 280 | * - LZMA_PROG_ERROR: Invalid values like compressed_size == 0. 281 | * 282 | * \note This doesn't check that all the options are valid i.e. this 283 | * may return LZMA_OK even if lzma_block_header_encode() or 284 | * lzma_block_encoder() would fail. If you want to validate the 285 | * filter chain, consider using lzma_memlimit_encoder() which as 286 | * a side-effect validates the filter chain. 287 | */ 288 | nothrow lzma_ret lzma_block_header_size(lzma_block *block); 289 | 290 | 291 | /** 292 | * \brief Encode Block Header 293 | * 294 | * The caller must have calculated the size of the Block Header already with 295 | * lzma_block_header_size(). If a value larger than the one calculated by 296 | * lzma_block_header_size() is used, the Block Header will be padded to the 297 | * specified size. 298 | * 299 | * \param out Beginning of the output buffer. This must be 300 | * at least block->header_size bytes. 301 | * \param block Block options to be encoded. 302 | * 303 | * \return - LZMA_OK: Encoding was successful. block->header_size 304 | * bytes were written to output buffer. 305 | * - LZMA_OPTIONS_ERROR: Invalid or unsupported options. 306 | * - LZMA_PROG_ERROR: Invalid arguments, for example 307 | * block->header_size is invalid or block->filters is NULL. 308 | */ 309 | nothrow lzma_ret lzma_block_header_encode(const (lzma_block)* block, ubyte* out_); 310 | 311 | 312 | /** 313 | * \brief Decode Block Header 314 | * 315 | * block->version should be set to the highest value supported by the 316 | * application; currently the only possible version is zero. This function 317 | * will set version to the lowest value that still supports all the features 318 | * required by the Block Header. 319 | * 320 | * The size of the Block Header must have already been decoded with 321 | * lzma_block_header_size_decode() macro and stored to block->header_size. 322 | * 323 | * block->filters must have been allocated, but they don't need to be 324 | * initialized (possible existing filter options are not freed). 325 | * 326 | * \param block Destination for Block options. 327 | * \param allocator lzma_allocator for custom allocator functions. 328 | * Set to NULL to use malloc() (and also free() 329 | * if an error occurs). 330 | * \param in Beginning of the input buffer. This must be 331 | * at least block->header_size bytes. 332 | * 333 | * \return - LZMA_OK: Decoding was successful. block->header_size 334 | * bytes were read from the input buffer. 335 | * - LZMA_OPTIONS_ERROR: The Block Header specifies some 336 | * unsupported options such as unsupported filters. This can 337 | * happen also if block->version was set to a too low value 338 | * compared to what would be required to properly represent 339 | * the information stored in the Block Header. 340 | * - LZMA_DATA_ERROR: Block Header is corrupt, for example, 341 | * the CRC32 doesn't match. 342 | * - LZMA_PROG_ERROR: Invalid arguments, for example 343 | * block->header_size is invalid or block->filters is NULL. 344 | */ 345 | nothrow lzma_ret lzma_block_header_decode(lzma_block* block, 346 | lzma_allocator* allocator, const(ubyte)* in_); 347 | 348 | 349 | /** 350 | * \brief Validate and set Compressed Size according to Unpadded Size 351 | * 352 | * Block Header stores Compressed Size, but Index has Unpadded Size. If the 353 | * application has already parsed the Index and is now decoding Blocks, 354 | * it can calculate Compressed Size from Unpadded Size. This function does 355 | * exactly that with error checking: 356 | * 357 | * - Compressed Size calculated from Unpadded Size must be positive integer, 358 | * that is, Unpadded Size must be big enough that after Block Header and 359 | * Check fields there's still at least one byte for Compressed Size. 360 | * 361 | * - If Compressed Size was present in Block Header, the new value 362 | * calculated from Unpadded Size is compared against the value 363 | * from Block Header. 364 | * 365 | * \note This function must be called _after_ decoding the Block Header 366 | * field so that it can properly validate Compressed Size if it 367 | * was present in Block Header. 368 | * 369 | * \return - LZMA_OK: block->compressed_size was set successfully. 370 | * - LZMA_DATA_ERROR: unpadded_size is too small compared to 371 | * block->header_size and lzma_check_size(block->check). 372 | * - LZMA_PROG_ERROR: Some values are invalid. For example, 373 | * block->header_size must be a multiple of four and 374 | * between 8 and 1024 inclusive. 375 | */ 376 | nothrow lzma_ret lzma_block_compressed_size( 377 | lzma_block* block, lzma_vli unpadded_size); 378 | 379 | 380 | /** 381 | * \brief Calculate Unpadded Size 382 | * 383 | * The Index field stores Unpadded Size and Uncompressed Size. The latter 384 | * can be taken directly from the lzma_block structure after coding a Block, 385 | * but Unpadded Size needs to be calculated from Block Header Size, 386 | * Compressed Size, and size of the Check field. This is where this function 387 | * is needed. 388 | * 389 | * \return Unpadded Size on success, or zero on error. 390 | */ 391 | nothrow lzma_vli lzma_block_unpadded_size(const lzma_block* block); 392 | 393 | 394 | /** 395 | * \brief Calculate the total encoded size of a Block 396 | * 397 | * This is equivalent to lzma_block_unpadded_size() except that the returned 398 | * value includes the size of the Block Padding field. 399 | * 400 | * \return On success, total encoded size of the Block. On error, 401 | * zero is returned. 402 | */ 403 | nothrow pure lzma_vli lzma_block_total_size(const(lzma_block*) block); 404 | 405 | 406 | /** 407 | * \brief Initialize .xz Block encoder 408 | * 409 | * Valid actions for lzma_code() are LZMA_RUN, LZMA_SYNC_FLUSH (only if the 410 | * filter chain supports it), and LZMA_FINISH. 411 | * 412 | * \return - LZMA_OK: All good, continue with lzma_code(). 413 | * - LZMA_MEM_ERROR 414 | * - LZMA_OPTIONS_ERROR 415 | * - LZMA_UNSUPPORTED_CHECK: block->check specifies a Check ID 416 | * that is not supported by this buid of liblzma. Initializing 417 | * the encoder failed. 418 | * - LZMA_PROG_ERROR 419 | */ 420 | nothrow lzma_ret lzma_block_encoder( 421 | lzma_stream* strm, lzma_block* block); 422 | 423 | 424 | /** 425 | * \brief Initialize .xz Block decoder 426 | * 427 | * Valid actions for lzma_code() are LZMA_RUN and LZMA_FINISH. Using 428 | * LZMA_FINISH is not required. It is supported only for convenience. 429 | * 430 | * \return - LZMA_OK: All good, continue with lzma_code(). 431 | * - LZMA_UNSUPPORTED_CHECK: Initialization was successful, but 432 | * the given Check ID is not supported, thus Check will be 433 | * ignored. 434 | * - LZMA_PROG_ERROR 435 | * - LZMA_MEM_ERROR 436 | */ 437 | nothrow lzma_ret lzma_block_decoder( 438 | lzma_stream *strm, lzma_block *block); 439 | 440 | 441 | /** 442 | * \brief Calculate maximum output size for single-call Block encoding 443 | * 444 | * This is equivalent to lzma_stream_buffer_bound() but for .xz Blocks. 445 | * See the documentation of lzma_stream_buffer_bound(). 446 | */ 447 | nothrow size_t lzma_block_buffer_bound(size_t uncompressed_size); 448 | 449 | 450 | /** 451 | * \brief Single-call .xz Block encoder 452 | * 453 | * In contrast to the multi-call encoder initialized with 454 | * lzma_block_encoder(), this function encodes also the Block Header. This 455 | * is required to make it possible to write appropriate Block Header also 456 | * in case the data isn't compressible, and different filter chain has to be 457 | * used to encode the data in uncompressed form using uncompressed chunks 458 | * of the LZMA2 filter. 459 | * 460 | * When the data isn't compressible, header_size, compressed_size, and 461 | * uncompressed_size are set just like when the data was compressible, but 462 | * it is possible that header_size is too small to hold the filter chain 463 | * specified in block->filters, because that isn't necessarily the filter 464 | * chain that was actually used to encode the data. lzma_block_unpadded_size() 465 | * still works normally, because it doesn't read the filters array. 466 | * 467 | * \param block Block options: block->version, block->check, 468 | * and block->filters must have been initialized. 469 | * \param allocator lzma_allocator for custom allocator functions. 470 | * Set to NULL to use malloc() and free(). 471 | * \param in Beginning of the input buffer 472 | * \param in_size Size of the input buffer 473 | * \param out Beginning of the output buffer 474 | * \param out_pos The next byte will be written to out[*out_pos]. 475 | * *out_pos is updated only if encoding succeeds. 476 | * \param out_size Size of the out buffer; the first byte into 477 | * which no data is written to is out[out_size]. 478 | * 479 | * \return - LZMA_OK: Encoding was successful. 480 | * - LZMA_BUF_ERROR: Not enough output buffer space. 481 | * - LZMA_UNSUPPORTED_CHECK 482 | * - LZMA_OPTIONS_ERROR 483 | * - LZMA_MEM_ERROR 484 | * - LZMA_DATA_ERROR 485 | * - LZMA_PROG_ERROR 486 | */ 487 | nothrow lzma_ret lzma_block_buffer_encode( 488 | lzma_block *block, lzma_allocator *allocator, 489 | const(ubyte)* in_, size_t in_size, 490 | ubyte* out_, size_t *out_pos, size_t out_size); 491 | 492 | 493 | /** 494 | * \brief Single-call .xz Block decoder 495 | * 496 | * This is single-call equivalent of lzma_block_decoder(), and requires that 497 | * the caller has already decoded Block Header and checked its memory usage. 498 | * 499 | * \param block Block options just like with lzma_block_decoder(). 500 | * \param allocator lzma_allocator for custom allocator functions. 501 | * Set to NULL to use malloc() and free(). 502 | * \param in Beginning of the input buffer 503 | * \param in_pos The next byte will be read from in[*in_pos]. 504 | * *in_pos is updated only if decoding succeeds. 505 | * \param in_size Size of the input buffer; the first byte that 506 | * won't be read is in[in_size]. 507 | * \param out Beginning of the output buffer 508 | * \param out_pos The next byte will be written to out[*out_pos]. 509 | * *out_pos is updated only if encoding succeeds. 510 | * \param out_size Size of the out buffer; the first byte into 511 | * which no data is written to is out[out_size]. 512 | * 513 | * \return - LZMA_OK: Decoding was successful. 514 | * - LZMA_OPTIONS_ERROR 515 | * - LZMA_DATA_ERROR 516 | * - LZMA_MEM_ERROR 517 | * - LZMA_BUF_ERROR: Output buffer was too small. 518 | * - LZMA_PROG_ERROR 519 | */ 520 | nothrow lzma_ret lzma_block_buffer_decode( 521 | lzma_block *block, lzma_allocator *allocator, 522 | const(ubyte)* in_, size_t *in_pos, size_t in_size, 523 | ubyte* out_, size_t *out_pos, size_t out_size); 524 | -------------------------------------------------------------------------------- /deimos/lzma_/check.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/check.h 3 | * \brief Integrity checks 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.check; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | /** 21 | * \brief Type of the integrity check (Check ID) 22 | * 23 | * The .xz format supports multiple types of checks that are calculated 24 | * from the uncompressed data. They vary in both speed and ability to 25 | * detect errors. 26 | */ 27 | enum lzma_check 28 | { 29 | LZMA_CHECK_NONE = 0, 30 | /**< 31 | * No Check is calculated. 32 | * 33 | * Size of the Check field: 0 bytes 34 | */ 35 | 36 | LZMA_CHECK_CRC32 = 1, 37 | /**< 38 | * CRC32 using the polynomial from the IEEE 802.3 standard 39 | * 40 | * Size of the Check field: 4 bytes 41 | */ 42 | 43 | LZMA_CHECK_CRC64 = 4, 44 | /**< 45 | * CRC64 using the polynomial from the ECMA-182 standard 46 | * 47 | * Size of the Check field: 8 bytes 48 | */ 49 | 50 | LZMA_CHECK_SHA256 = 10 51 | } 52 | 53 | 54 | /** 55 | * \brief Maximum valid Check ID 56 | * 57 | * The .xz file format specification specifies 16 Check IDs (0-15). Some 58 | * of them are only reserved, that is, no actual Check algorithm has been 59 | * assigned. When decoding, liblzma still accepts unknown Check IDs for 60 | * future compatibility. If a valid but unsupported Check ID is detected, 61 | * liblzma can indicate a warning; see the flags LZMA_TELL_NO_CHECK, 62 | * LZMA_TELL_UNSUPPORTED_CHECK, and LZMA_TELL_ANY_CHECK in container.h. 63 | */ 64 | enum LZMA_CHECK_ID_MAX = 15; 65 | 66 | 67 | /** 68 | * \brief Test if the given Check ID is supported 69 | * 70 | * Return true if the given Check ID is supported by this liblzma build. 71 | * Otherwise false is returned. It is safe to call this with a value that 72 | * is not in the range [0, 15]; in that case the return value is always false. 73 | * 74 | * You can assume that LZMA_CHECK_NONE and LZMA_CHECK_CRC32 are always 75 | * supported (even if liblzma is built with limited features). 76 | */ 77 | nothrow lzma_bool lzma_check_is_supported(lzma_check check); 78 | 79 | 80 | /** 81 | * \brief Get the size of the Check field with the given Check ID 82 | * 83 | * Although not all Check IDs have a check algorithm associated, the size of 84 | * every Check is already frozen. This function returns the size (in bytes) of 85 | * the Check field with the specified Check ID. The values are: 86 | * { 0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64 } 87 | * 88 | * If the argument is not in the range [0, 15], UINT32_MAX is returned. 89 | */ 90 | nothrow uint lzma_check_size(lzma_check check); 91 | 92 | 93 | /** 94 | * \brief Maximum size of a Check field 95 | */ 96 | enum LZMA_CHECK_SIZE_MAX = 64; 97 | 98 | 99 | /** 100 | * \brief Calculate CRC32 101 | * 102 | * Calculate CRC32 using the polynomial from the IEEE 802.3 standard. 103 | * 104 | * \param buf Pointer to the input buffer 105 | * \param size Size of the input buffer 106 | * \param crc Previously returned CRC value. This is used to 107 | * calculate the CRC of a big buffer in smaller chunks. 108 | * Set to zero when starting a new calculation. 109 | * 110 | * \return Updated CRC value, which can be passed to this function 111 | * again to continue CRC calculation. 112 | */ 113 | nothrow pure uint lzma_crc32( 114 | const(ubyte)* buf, size_t size, uint crc); 115 | 116 | 117 | /** 118 | * \brief Calculate CRC64 119 | * 120 | * Calculate CRC64 using the polynomial from the ECMA-182 standard. 121 | * 122 | * This function is used similarly to lzma_crc32(). See its documentation. 123 | */ 124 | nothrow pure ulong lzma_crc64( 125 | const(ubyte)* buf, size_t size, ulong crc); 126 | 127 | 128 | /* 129 | * SHA-256 functions are currently not exported to public API. 130 | * Contact Lasse Collin if you think it should be. 131 | */ 132 | 133 | 134 | /** 135 | * \brief Get the type of the integrity check 136 | * 137 | * This function can be called only immediately after lzma_code() has 138 | * returned LZMA_NO_CHECK, LZMA_UNSUPPORTED_CHECK, or LZMA_GET_CHECK. 139 | * Calling this function in any other situation has undefined behavior. 140 | */ 141 | nothrow lzma_check lzma_get_check(const lzma_stream *strm); 142 | -------------------------------------------------------------------------------- /deimos/lzma_/container.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/container.h 3 | * \brief File formats 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.container; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | /************ 21 | * Encoding * 22 | ************/ 23 | 24 | /** 25 | * \brief Default compression preset 26 | * 27 | * It's not straightforward to recommend a default preset, because in some 28 | * cases keeping the resource usage relatively low is more important that 29 | * getting the maximum compression ratio. 30 | */ 31 | enum uint LZMA_PRESET_DEFAULT = 6U; 32 | 33 | 34 | /** 35 | * \brief Mask for preset level 36 | * 37 | * This is useful only if you need to extract the level from the preset 38 | * variable. That should be rare. 39 | */ 40 | enum uint LZMA_PRESET_LEVEL_MASK = 0x1FU; 41 | 42 | 43 | /* 44 | * Preset flags 45 | * 46 | * Currently only one flag is defined. 47 | */ 48 | 49 | /** 50 | * \brief Extreme compression preset 51 | * 52 | * This flag modifies the preset to make the encoding significantly slower 53 | * while improving the compression ratio only marginally. This is useful 54 | * when you don't mind wasting time to get as small result as possible. 55 | * 56 | * This flag doesn't affect the memory usage requirements of the decoder (at 57 | * least not significantly). The memory usage of the encoder may be increased 58 | * a little but only at the lowest preset levels (0-3). 59 | */ 60 | enum uint LZMA_PRESET_EXTREME = (1U << 31); 61 | 62 | 63 | /** 64 | * \brief Calculate approximate memory usage of easy encoder 65 | * 66 | * This function is a wrapper for lzma_raw_encoder_memusage(). 67 | * 68 | * \param preset Compression preset (level and possible flags) 69 | * 70 | * \return Number of bytes of memory required for the given 71 | * preset when encoding. If an error occurs, for example 72 | * due to unsupported preset, UINT64_MAX is returned. 73 | */ 74 | nothrow pure ulong lzma_easy_encoder_memusage(uint preset); 75 | 76 | 77 | /** 78 | * \brief Calculate approximate decoder memory usage of a preset 79 | * 80 | * This function is a wrapper for lzma_raw_decoder_memusage(). 81 | * 82 | * \param preset Compression preset (level and possible flags) 83 | * 84 | * \return Number of bytes of memory required to decompress a file 85 | * that was compressed using the given preset. If an error 86 | * occurs, for example due to unsupported preset, UINT64_MAX 87 | * is returned. 88 | */ 89 | nothrow pure ulong lzma_easy_decoder_memusage(uint preset); 90 | 91 | 92 | /** 93 | * \brief Initialize .xz Stream encoder using a preset number 94 | * 95 | * This function is intended for those who just want to use the basic features 96 | * if liblzma (that is, most developers out there). 97 | * 98 | * \param strm Pointer to lzma_stream that is at least initialized 99 | * with LZMA_STREAM_INIT. 100 | * \param preset Compression preset to use. A preset consist of level 101 | * number and zero or more flags. Usually flags aren't 102 | * used, so preset is simply a number [0, 9] which match 103 | * the options -0 ... -9 of the xz command line tool. 104 | * Additional flags can be be set using bitwise-or with 105 | * the preset level number, e.g. 6 | LZMA_PRESET_EXTREME. 106 | * \param check Integrity check type to use. See check.h for available 107 | * checks. The xz command line tool defaults to 108 | * LZMA_CHECK_CRC64, which is a good choice if you are 109 | * unsure. LZMA_CHECK_CRC32 is good too as long as the 110 | * uncompressed file is not many gigabytes. 111 | * 112 | * \return - LZMA_OK: Initialization succeeded. Use lzma_code() to 113 | * encode your data. 114 | * - LZMA_MEM_ERROR: Memory allocation failed. 115 | * - LZMA_OPTIONS_ERROR: The given compression preset is not 116 | * supported by this build of liblzma. 117 | * - LZMA_UNSUPPORTED_CHECK: The given check type is not 118 | * supported by this liblzma build. 119 | * - LZMA_PROG_ERROR: One or more of the parameters have values 120 | * that will never be valid. For example, strm == NULL. 121 | * 122 | * If initialization fails (return value is not LZMA_OK), all the memory 123 | * allocated for *strm by liblzma is always freed. Thus, there is no need 124 | * to call lzma_end() after failed initialization. 125 | * 126 | * If initialization succeeds, use lzma_code() to do the actual encoding. 127 | * Valid values for `action' (the second argument of lzma_code()) are 128 | * LZMA_RUN, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, and LZMA_FINISH. In future, 129 | * there may be compression levels or flags that don't support LZMA_SYNC_FLUSH. 130 | */ 131 | nothrow lzma_ret lzma_easy_encoder( 132 | lzma_stream *strm, uint preset, lzma_check check); 133 | 134 | 135 | /** 136 | * \brief Single-call .xz Stream encoding using a preset number 137 | * 138 | * The maximum required output buffer size can be calculated with 139 | * lzma_stream_buffer_bound(). 140 | * 141 | * \param preset Compression preset to use. See the description 142 | * in lzma_easy_encoder(). 143 | * \param check Type of the integrity check to calculate from 144 | * uncompressed data. 145 | * \param allocator lzma_allocator for custom allocator functions. 146 | * Set to NULL to use malloc() and free(). 147 | * \param in Beginning of the input buffer 148 | * \param in_size Size of the input buffer 149 | * \param out Beginning of the output buffer 150 | * \param out_pos The next byte will be written to out[*out_pos]. 151 | * *out_pos is updated only if encoding succeeds. 152 | * \param out_size Size of the out buffer; the first byte into 153 | * which no data is written to is out[out_size]. 154 | * 155 | * \return - LZMA_OK: Encoding was successful. 156 | * - LZMA_BUF_ERROR: Not enough output buffer space. 157 | * - LZMA_UNSUPPORTED_CHECK 158 | * - LZMA_OPTIONS_ERROR 159 | * - LZMA_MEM_ERROR 160 | * - LZMA_DATA_ERROR 161 | * - LZMA_PROG_ERROR 162 | */ 163 | nothrow lzma_ret lzma_easy_buffer_encode( 164 | uint preset, lzma_check check, 165 | lzma_allocator *allocator, const(ubyte)* in_, size_t in_size, 166 | ubyte* out_, size_t *out_pos, size_t out_size); 167 | 168 | 169 | /** 170 | * \brief Initialize .xz Stream encoder using a custom filter chain 171 | * 172 | * \param strm Pointer to properly prepared lzma_stream 173 | * \param filters Array of filters. This must be terminated with 174 | * filters[n].id = LZMA_VLI_UNKNOWN. See filter.h for 175 | * more information. 176 | * \param check Type of the integrity check to calculate from 177 | * uncompressed data. 178 | * 179 | * \return - LZMA_OK: Initialization was successful. 180 | * - LZMA_MEM_ERROR 181 | * - LZMA_UNSUPPORTED_CHECK 182 | * - LZMA_OPTIONS_ERROR 183 | * - LZMA_PROG_ERROR 184 | */ 185 | nothrow lzma_ret lzma_stream_encoder(lzma_stream *strm, 186 | const lzma_filter *filters, lzma_check check); 187 | 188 | 189 | /** 190 | * \brief Initialize .lzma encoder (legacy file format) 191 | * 192 | * The .lzma format is sometimes called the LZMA_Alone format, which is the 193 | * reason for the name of this function. The .lzma format supports only the 194 | * LZMA1 filter. There is no support for integrity checks like CRC32. 195 | * 196 | * Use this function if and only if you need to create files readable by 197 | * legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format 198 | * is strongly recommended. 199 | * 200 | * The valid action values for lzma_code() are LZMA_RUN and LZMA_FINISH. 201 | * No kind of flushing is supported, because the file format doesn't make 202 | * it possible. 203 | * 204 | * \return - LZMA_OK 205 | * - LZMA_MEM_ERROR 206 | * - LZMA_OPTIONS_ERROR 207 | * - LZMA_PROG_ERROR 208 | */ 209 | nothrow lzma_ret lzma_alone_encoder( 210 | lzma_stream *strm, const lzma_options_lzma *options); 211 | 212 | 213 | /** 214 | * \brief Calculate output buffer size for single-call Stream encoder 215 | * 216 | * When trying to compress uncompressible data, the encoded size will be 217 | * slightly bigger than the input data. This function calculates how much 218 | * output buffer space is required to be sure that lzma_stream_buffer_encode() 219 | * doesn't return LZMA_BUF_ERROR. 220 | * 221 | * The calculated value is not exact, but it is guaranteed to be big enough. 222 | * The actual maximum output space required may be slightly smaller (up to 223 | * about 100 bytes). This should not be a problem in practice. 224 | * 225 | * If the calculated maximum size doesn't fit into size_t or would make the 226 | * Stream grow past LZMA_VLI_MAX (which should never happen in practice), 227 | * zero is returned to indicate the error. 228 | * 229 | * \note The limit calculated by this function applies only to 230 | * single-call encoding. Multi-call encoding may (and probably 231 | * will) have larger maximum expansion when encoding 232 | * uncompressible data. Currently there is no function to 233 | * calculate the maximum expansion of multi-call encoding. 234 | */ 235 | nothrow size_t lzma_stream_buffer_bound(size_t uncompressed_size); 236 | 237 | 238 | /** 239 | * \brief Single-call .xz Stream encoder 240 | * 241 | * \param filters Array of filters. This must be terminated with 242 | * filters[n].id = LZMA_VLI_UNKNOWN. See filter.h 243 | * for more information. 244 | * \param check Type of the integrity check to calculate from 245 | * uncompressed data. 246 | * \param allocator lzma_allocator for custom allocator functions. 247 | * Set to NULL to use malloc() and free(). 248 | * \param in Beginning of the input buffer 249 | * \param in_size Size of the input buffer 250 | * \param out Beginning of the output buffer 251 | * \param out_pos The next byte will be written to out[*out_pos]. 252 | * *out_pos is updated only if encoding succeeds. 253 | * \param out_size Size of the out buffer; the first byte into 254 | * which no data is written to is out[out_size]. 255 | * 256 | * \return - LZMA_OK: Encoding was successful. 257 | * - LZMA_BUF_ERROR: Not enough output buffer space. 258 | * - LZMA_UNSUPPORTED_CHECK 259 | * - LZMA_OPTIONS_ERROR 260 | * - LZMA_MEM_ERROR 261 | * - LZMA_DATA_ERROR 262 | * - LZMA_PROG_ERROR 263 | */ 264 | nothrow lzma_ret lzma_stream_buffer_encode( 265 | lzma_filter *filters, lzma_check check, 266 | lzma_allocator *allocator, const(ubyte)* in_, size_t in_size, 267 | ubyte* out_, size_t *out_pos, size_t out_size); 268 | 269 | 270 | /************ 271 | * Decoding * 272 | ************/ 273 | 274 | /** 275 | * This flag makes lzma_code() return LZMA_NO_CHECK if the input stream 276 | * being decoded has no integrity check. Note that when used with 277 | * lzma_auto_decoder(), all .lzma files will trigger LZMA_NO_CHECK 278 | * if LZMA_TELL_NO_CHECK is used. 279 | */ 280 | enum uint LZMA_TELL_NO_CHECK = 0x01U; 281 | 282 | 283 | /** 284 | * This flag makes lzma_code() return LZMA_UNSUPPORTED_CHECK if the input 285 | * stream has an integrity check, but the type of the integrity check is not 286 | * supported by this liblzma version or build. Such files can still be 287 | * decoded, but the integrity check cannot be verified. 288 | */ 289 | enum uint LZMA_TELL_UNSUPPORTED_CHECK = 0x02U; 290 | 291 | 292 | /** 293 | * This flag makes lzma_code() return LZMA_GET_CHECK as soon as the type 294 | * of the integrity check is known. The type can then be got with 295 | * lzma_get_check(). 296 | */ 297 | enum uint LZMA_TELL_ANY_CHECK = 0x04U; 298 | 299 | 300 | /** 301 | * This flag enables decoding of concatenated files with file formats that 302 | * allow concatenating compressed files as is. From the formats currently 303 | * supported by liblzma, only the .xz format allows concatenated files. 304 | * Concatenated files are not allowed with the legacy .lzma format. 305 | * 306 | * This flag also affects the usage of the `action' argument for lzma_code(). 307 | * When LZMA_CONCATENATED is used, lzma_code() won't return LZMA_STREAM_END 308 | * unless LZMA_FINISH is used as `action'. Thus, the application has to set 309 | * LZMA_FINISH in the same way as it does when encoding. 310 | * 311 | * If LZMA_CONCATENATED is not used, the decoders still accept LZMA_FINISH 312 | * as `action' for lzma_code(), but the usage of LZMA_FINISH isn't required. 313 | */ 314 | enum uint LZMA_CONCATENATED = 0x08U; 315 | 316 | 317 | /** 318 | * \brief Initialize .xz Stream decoder 319 | * 320 | * \param strm Pointer to properly prepared lzma_stream 321 | * \param memlimit Memory usage limit as bytes. Use UINT64_MAX 322 | * to effectively disable the limiter. 323 | * \param flags Bitwise-or of zero or more of the decoder flags: 324 | * LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK, 325 | * LZMA_TELL_ANY_CHECK, LZMA_CONCATENATED 326 | * 327 | * \return - LZMA_OK: Initialization was successful. 328 | * - LZMA_MEM_ERROR: Cannot allocate memory. 329 | * - LZMA_OPTIONS_ERROR: Unsupported flags 330 | * - LZMA_PROG_ERROR 331 | */ 332 | nothrow lzma_ret lzma_stream_decoder( 333 | lzma_stream *strm, ulong memlimit, uint flags); 334 | 335 | 336 | /** 337 | * \brief Decode .xz Streams and .lzma files with autodetection 338 | * 339 | * This decoder autodetects between the .xz and .lzma file formats, and 340 | * calls lzma_stream_decoder() or lzma_alone_decoder() once the type 341 | * of the input file has been detected. 342 | * 343 | * \param strm Pointer to properly prepared lzma_stream 344 | * \param memlimit Memory usage limit as bytes. Use UINT64_MAX 345 | * to effectively disable the limiter. 346 | * \param flags Bitwise-or of flags, or zero for no flags. 347 | * 348 | * \return - LZMA_OK: Initialization was successful. 349 | * - LZMA_MEM_ERROR: Cannot allocate memory. 350 | * - LZMA_OPTIONS_ERROR: Unsupported flags 351 | * - LZMA_PROG_ERROR 352 | */ 353 | nothrow lzma_ret lzma_auto_decoder( 354 | lzma_stream *strm, ulong memlimit, uint flags); 355 | 356 | 357 | /** 358 | * \brief Initialize .lzma decoder (legacy file format) 359 | * 360 | * Valid `action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH. 361 | * There is no need to use LZMA_FINISH, but allowing it may simplify 362 | * certain types of applications. 363 | * 364 | * \return - LZMA_OK 365 | * - LZMA_MEM_ERROR 366 | * - LZMA_PROG_ERROR 367 | */ 368 | nothrow lzma_ret lzma_alone_decoder( 369 | lzma_stream *strm, ulong memlimit); 370 | 371 | 372 | /** 373 | * \brief Single-call .xz Stream decoder 374 | * 375 | * \param memlimit Pointer to how much memory the decoder is allowed 376 | * to allocate. The value pointed by this pointer is 377 | * modified if and only if LZMA_MEMLIMIT_ERROR is 378 | * returned. 379 | * \param flags Bitwise-or of zero or more of the decoder flags: 380 | * LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK, 381 | * LZMA_CONCATENATED. Note that LZMA_TELL_ANY_CHECK 382 | * is not allowed and will return LZMA_PROG_ERROR. 383 | * \param allocator lzma_allocator for custom allocator functions. 384 | * Set to NULL to use malloc() and free(). 385 | * \param in Beginning of the input buffer 386 | * \param in_pos The next byte will be read from in[*in_pos]. 387 | * *in_pos is updated only if decoding succeeds. 388 | * \param in_size Size of the input buffer; the first byte that 389 | * won't be read is in[in_size]. 390 | * \param out Beginning of the output buffer 391 | * \param out_pos The next byte will be written to out[*out_pos]. 392 | * *out_pos is updated only if decoding succeeds. 393 | * \param out_size Size of the out buffer; the first byte into 394 | * which no data is written to is out[out_size]. 395 | * 396 | * \return - LZMA_OK: Decoding was successful. 397 | * - LZMA_FORMAT_ERROR 398 | * - LZMA_OPTIONS_ERROR 399 | * - LZMA_DATA_ERROR 400 | * - LZMA_NO_CHECK: This can be returned only if using 401 | * the LZMA_TELL_NO_CHECK flag. 402 | * - LZMA_UNSUPPORTED_CHECK: This can be returned only if using 403 | * the LZMA_TELL_UNSUPPORTED_CHECK flag. 404 | * - LZMA_MEM_ERROR 405 | * - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached. 406 | * The minimum required memlimit value was stored to *memlimit. 407 | * - LZMA_BUF_ERROR: Output buffer was too small. 408 | * - LZMA_PROG_ERROR 409 | */ 410 | nothrow lzma_ret lzma_stream_buffer_decode( 411 | ulong *memlimit, uint flags, lzma_allocator *allocator, 412 | const (ubyte)* in_, size_t *in_pos, size_t in_size, 413 | ubyte* out_, size_t *out_pos, size_t out_size); 414 | -------------------------------------------------------------------------------- /deimos/lzma_/delta.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/delta.h 3 | * \brief Delta filter 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.delta; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | /** 21 | * \brief Filter ID 22 | * 23 | * Filter ID of the Delta filter. This is used as lzma_filter.id. 24 | */ 25 | enum LZMA_FILTER_DELTA = 0x03UL; 26 | 27 | 28 | /** 29 | * \brief Type of the delta calculation 30 | * 31 | * Currently only byte-wise delta is supported. Other possible types could 32 | * be, for example, delta of 16/32/64-bit little/big endian integers, but 33 | * these are not currently planned since byte-wise delta is almost as good. 34 | */ 35 | enum lzma_delta_type 36 | { 37 | LZMA_DELTA_TYPE_BYTE 38 | } 39 | 40 | 41 | /** 42 | * \brief Options for the Delta filter 43 | * 44 | * These options are needed by both encoder and decoder. 45 | */ 46 | struct lzma_options_delta 47 | { 48 | /** For now, this must always be LZMA_DELTA_TYPE_BYTE. */ 49 | lzma_delta_type type; 50 | 51 | /** 52 | * \brief Delta distance 53 | * 54 | * With the only currently supported type, LZMA_DELTA_TYPE_BYTE, 55 | * the distance is as bytes. 56 | * 57 | * Examples: 58 | * - 16-bit stereo audio: distance = 4 bytes 59 | * - 24-bit RGB image data: distance = 3 bytes 60 | */ 61 | uint dist; 62 | enum LZMA_DELTA_DIST_MIN = 1; 63 | enum LZMA_DELTA_DIST_MAX = 256; 64 | 65 | /* 66 | * Reserved space to allow possible future extensions without 67 | * breaking the ABI. You should not touch these, because the names 68 | * of these variables may change. These are and will never be used 69 | * when type is LZMA_DELTA_TYPE_BYTE, so it is safe to leave these 70 | * uninitialized. 71 | */ 72 | uint reserved_int1; 73 | uint reserved_int2; 74 | uint reserved_int3; 75 | uint reserved_int4; 76 | void *reserved_ptr1; 77 | void *reserved_ptr2; 78 | 79 | } 80 | -------------------------------------------------------------------------------- /deimos/lzma_/filter.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/filter.h 3 | * \brief Common filter related types and functions 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.filter; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | /** 21 | * \brief Maximum number of filters in a chain 22 | * 23 | * A filter chain can have 1-4 filters, of which three are allowed to change 24 | * the size of the data. Usually only one or two filters are needed. 25 | */ 26 | enum LZMA_FILTERS_MAX = 4; 27 | 28 | 29 | /** 30 | * \brief Filter options 31 | * 32 | * This structure is used to pass Filter ID and a pointer filter's 33 | * options to liblzma. A few functions work with a single lzma_filter 34 | * structure, while most functions expect a filter chain. 35 | * 36 | * A filter chain is indicated with an array of lzma_filter structures. 37 | * The array is terminated with .id = LZMA_VLI_UNKNOWN. Thus, the filter 38 | * array must have LZMA_FILTERS_MAX + 1 elements (that is, five) to 39 | * be able to hold any arbitrary filter chain. This is important when 40 | * using lzma_block_header_decode() from block.h, because too small 41 | * array would make liblzma write past the end of the filters array. 42 | */ 43 | struct lzma_filter 44 | { 45 | /** 46 | * \brief Filter ID 47 | * 48 | * Use constants whose name begin with `LZMA_FILTER_' to specify 49 | * different filters. In an array of lzma_filter structures, use 50 | * LZMA_VLI_UNKNOWN to indicate end of filters. 51 | * 52 | * \note This is not an enum, because on some systems enums 53 | * cannot be 64-bit. 54 | */ 55 | lzma_vli id; 56 | 57 | /** 58 | * \brief Pointer to filter-specific options structure 59 | * 60 | * If the filter doesn't need options, set this to NULL. If id is 61 | * set to LZMA_VLI_UNKNOWN, options is ignored, and thus 62 | * doesn't need be initialized. 63 | */ 64 | void *options; 65 | 66 | } 67 | 68 | 69 | /** 70 | * \brief Test if the given Filter ID is supported for encoding 71 | * 72 | * Return true if the give Filter ID is supported for encoding by this 73 | * liblzma build. Otherwise false is returned. 74 | * 75 | * There is no way to list which filters are available in this particular 76 | * liblzma version and build. It would be useless, because the application 77 | * couldn't know what kind of options the filter would need. 78 | */ 79 | nothrow lzma_bool lzma_filter_encoder_is_supported(lzma_vli id); 80 | 81 | 82 | /** 83 | * \brief Test if the given Filter ID is supported for decoding 84 | * 85 | * Return true if the give Filter ID is supported for decoding by this 86 | * liblzma build. Otherwise false is returned. 87 | */ 88 | nothrow lzma_bool lzma_filter_decoder_is_supported(lzma_vli id); 89 | 90 | 91 | /** 92 | * \brief Copy the filters array 93 | * 94 | * Copy the Filter IDs and filter-specific options from src to dest. 95 | * Up to LZMA_FILTERS_MAX filters are copied, plus the terminating 96 | * .id == LZMA_VLI_UNKNOWN. Thus, dest should have at least 97 | * LZMA_FILTERS_MAX + 1 elements space unless the caller knows that 98 | * src is smaller than that. 99 | * 100 | * Unless the filter-specific options is NULL, the Filter ID has to be 101 | * supported by liblzma, because liblzma needs to know the size of every 102 | * filter-specific options structure. The filter-specific options are not 103 | * validated. If options is NULL, any unsupported Filter IDs are copied 104 | * without returning an error. 105 | * 106 | * Old filter-specific options in dest are not freed, so dest doesn't 107 | * need to be initialized by the caller in any way. 108 | * 109 | * If an error occurs, memory possibly already allocated by this function 110 | * is always freed. 111 | * 112 | * \return - LZMA_OK 113 | * - LZMA_MEM_ERROR 114 | * - LZMA_OPTIONS_ERROR: Unsupported Filter ID and its options 115 | * is not NULL. 116 | * - LZMA_PROG_ERROR: src or dest is NULL. 117 | */ 118 | nothrow lzma_ret lzma_filters_copy(const lzma_filter*src, 119 | lzma_filter *dest, lzma_allocator *allocator); 120 | 121 | 122 | /** 123 | * \brief Calculate approximate memory requirements for raw encoder 124 | * 125 | * This function can be used to calculate the memory requirements for 126 | * Block and Stream encoders too because Block and Stream encoders don't 127 | * need significantly more memory than raw encoder. 128 | * 129 | * \param filters Array of filters terminated with 130 | * .id == LZMA_VLI_UNKNOWN. 131 | * 132 | * \return Number of bytes of memory required for the given 133 | * filter chain when encoding. If an error occurs, 134 | * for example due to unsupported filter chain, 135 | * UINT64_MAX is returned. 136 | */ 137 | pure nothrow ulong lzma_raw_encoder_memusage(const lzma_filter *filters); 138 | 139 | 140 | /** 141 | * \brief Calculate approximate memory requirements for raw decoder 142 | * 143 | * This function can be used to calculate the memory requirements for 144 | * Block and Stream decoders too because Block and Stream decoders don't 145 | * need significantly more memory than raw decoder. 146 | * 147 | * \param filters Array of filters terminated with 148 | * .id == LZMA_VLI_UNKNOWN. 149 | * 150 | * \return Number of bytes of memory required for the given 151 | * filter chain when decoding. If an error occurs, 152 | * for example due to unsupported filter chain, 153 | * UINT64_MAX is returned. 154 | */ 155 | nothrow pure ulong lzma_raw_decoder_memusage(const lzma_filter *filters); 156 | 157 | 158 | /** 159 | * \brief Initialize raw encoder 160 | * 161 | * This function may be useful when implementing custom file formats. 162 | * 163 | * \param strm Pointer to properly prepared lzma_stream 164 | * \param filters Array of lzma_filter structures. The end of the 165 | * array must be marked with .id = LZMA_VLI_UNKNOWN. 166 | * 167 | * The `action' with lzma_code() can be LZMA_RUN, LZMA_SYNC_FLUSH (if the 168 | * filter chain supports it), or LZMA_FINISH. 169 | * 170 | * \return - LZMA_OK 171 | * - LZMA_MEM_ERROR 172 | * - LZMA_OPTIONS_ERROR 173 | * - LZMA_PROG_ERROR 174 | */ 175 | nothrow lzma_ret lzma_raw_encoder( 176 | lzma_stream *strm, const lzma_filter *filters); 177 | 178 | 179 | /** 180 | * \brief Initialize raw decoder 181 | * 182 | * The initialization of raw decoder goes similarly to raw encoder. 183 | * 184 | * The `action' with lzma_code() can be LZMA_RUN or LZMA_FINISH. Using 185 | * LZMA_FINISH is not required, it is supported just for convenience. 186 | * 187 | * \return - LZMA_OK 188 | * - LZMA_MEM_ERROR 189 | * - LZMA_OPTIONS_ERROR 190 | * - LZMA_PROG_ERROR 191 | */ 192 | nothrow lzma_ret lzma_raw_decoder( 193 | lzma_stream *strm, const lzma_filter *filters); 194 | 195 | 196 | /** 197 | * \brief Update the filter chain in the encoder 198 | * 199 | * This function is for advanced users only. This function has two slightly 200 | * different purposes: 201 | * 202 | * - After LZMA_FULL_FLUSH when using Stream encoder: Set a new filter 203 | * chain, which will be used starting from the next Block. 204 | * 205 | * - After LZMA_SYNC_FLUSH using Raw, Block, or Stream encoder: Change 206 | * the filter-specific options in the middle of encoding. The actual 207 | * filters in the chain (Filter IDs) cannot be changed. In the future, 208 | * it might become possible to change the filter options without 209 | * using LZMA_SYNC_FLUSH. 210 | * 211 | * While rarely useful, this function may be called also when no data has 212 | * been compressed yet. In that case, this function will behave as if 213 | * LZMA_FULL_FLUSH (Stream encoder) or LZMA_SYNC_FLUSH (Raw or Block 214 | * encoder) had been used right before calling this function. 215 | * 216 | * \return - LZMA_OK 217 | * - LZMA_MEM_ERROR 218 | * - LZMA_MEMLIMIT_ERROR 219 | * - LZMA_OPTIONS_ERROR 220 | * - LZMA_PROG_ERROR 221 | */ 222 | nothrow lzma_ret lzma_filters_update( 223 | lzma_stream *strm, const lzma_filter *filters); 224 | 225 | 226 | /** 227 | * \brief Single-call raw encoder 228 | * 229 | * \param filters Array of lzma_filter structures. The end of the 230 | * array must be marked with .id = LZMA_VLI_UNKNOWN. 231 | * \param allocator lzma_allocator for custom allocator functions. 232 | * Set to NULL to use malloc() and free(). 233 | * \param in Beginning of the input buffer 234 | * \param in_size Size of the input buffer 235 | * \param out Beginning of the output buffer 236 | * \param out_pos The next byte will be written to out[*out_pos]. 237 | * *out_pos is updated only if encoding succeeds. 238 | * \param out_size Size of the out buffer; the first byte into 239 | * which no data is written to is out[out_size]. 240 | * 241 | * \return - LZMA_OK: Encoding was successful. 242 | * - LZMA_BUF_ERROR: Not enough output buffer space. 243 | * - LZMA_OPTIONS_ERROR 244 | * - LZMA_MEM_ERROR 245 | * - LZMA_DATA_ERROR 246 | * - LZMA_PROG_ERROR 247 | * 248 | * \note There is no function to calculate how big output buffer 249 | * would surely be big enough. (lzma_stream_buffer_bound() 250 | * works only for lzma_stream_buffer_encode(); raw encoder 251 | * won't necessarily meet that bound.) 252 | */ 253 | nothrow lzma_ret lzma_raw_buffer_encode( 254 | const lzma_filter *filters, lzma_allocator *allocator, 255 | const(ubyte) *in_, size_t in_size, ubyte *out_, 256 | size_t *out_pos, size_t out_size); 257 | 258 | 259 | /** 260 | * \brief Single-call raw decoder 261 | * 262 | * \param filters Array of lzma_filter structures. The end of the 263 | * array must be marked with .id = LZMA_VLI_UNKNOWN. 264 | * \param allocator lzma_allocator for custom allocator functions. 265 | * Set to NULL to use malloc() and free(). 266 | * \param in Beginning of the input buffer 267 | * \param in_pos The next byte will be read from in[*in_pos]. 268 | * *in_pos is updated only if decoding succeeds. 269 | * \param in_size Size of the input buffer; the first byte that 270 | * won't be read is in[in_size]. 271 | * \param out Beginning of the output buffer 272 | * \param out_pos The next byte will be written to out[*out_pos]. 273 | * *out_pos is updated only if encoding succeeds. 274 | * \param out_size Size of the out buffer; the first byte into 275 | * which no data is written to is out[out_size]. 276 | */ 277 | nothrow lzma_ret lzma_raw_buffer_decode(const lzma_filter *filters, 278 | lzma_allocator *allocator, 279 | const(ubyte) *in_, size_t *in_pos, size_t in_size, 280 | ubyte *out_, size_t *out_pos, size_t out_size); 281 | 282 | 283 | /** 284 | * \brief Get the size of the Filter Properties field 285 | * 286 | * This function may be useful when implementing custom file formats 287 | * using the raw encoder and decoder. 288 | * 289 | * \param size Pointer to uint32_t to hold the size of the properties 290 | * \param filter Filter ID and options (the size of the properties may 291 | * vary depending on the options) 292 | * 293 | * \return - LZMA_OK 294 | * - LZMA_OPTIONS_ERROR 295 | * - LZMA_PROG_ERROR 296 | * 297 | * \note This function validates the Filter ID, but does not 298 | * necessarily validate the options. Thus, it is possible 299 | * that this returns LZMA_OK while the following call to 300 | * lzma_properties_encode() returns LZMA_OPTIONS_ERROR. 301 | */ 302 | nothrow lzma_ret lzma_properties_size( 303 | uint *size, const lzma_filter *filter); 304 | 305 | 306 | /** 307 | * \brief Encode the Filter Properties field 308 | * 309 | * \param filter Filter ID and options 310 | * \param props Buffer to hold the encoded options. The size of 311 | * buffer must have been already determined with 312 | * lzma_properties_size(). 313 | * 314 | * \return - LZMA_OK 315 | * - LZMA_OPTIONS_ERROR 316 | * - LZMA_PROG_ERROR 317 | * 318 | * \note Even this function won't validate more options than actually 319 | * necessary. Thus, it is possible that encoding the properties 320 | * succeeds but using the same options to initialize the encoder 321 | * will fail. 322 | * 323 | * \note If lzma_properties_size() indicated that the size 324 | * of the Filter Properties field is zero, calling 325 | * lzma_properties_encode() is not required, but it 326 | * won't do any harm either. 327 | */ 328 | nothrow lzma_ret lzma_properties_encode( 329 | const lzma_filter *filter, ubyte *props); 330 | 331 | 332 | /** 333 | * \brief Decode the Filter Properties field 334 | * 335 | * \param filter filter->id must have been set to the correct 336 | * Filter ID. filter->options doesn't need to be 337 | * initialized (it's not freed by this function). The 338 | * decoded options will be stored to filter->options. 339 | * filter->options is set to NULL if there are no 340 | * properties or if an error occurs. 341 | * \param allocator Custom memory allocator used to allocate the 342 | * options. Set to NULL to use the default malloc(), 343 | * and in case of an error, also free(). 344 | * \param props Input buffer containing the properties. 345 | * \param props_size Size of the properties. This must be the exact 346 | * size; giving too much or too little input will 347 | * return LZMA_OPTIONS_ERROR. 348 | * 349 | * \return - LZMA_OK 350 | * - LZMA_OPTIONS_ERROR 351 | * - LZMA_MEM_ERROR 352 | */ 353 | nothrow lzma_ret lzma_properties_decode( 354 | lzma_filter *filter, lzma_allocator *allocator, 355 | const ubyte *props, size_t props_size); 356 | 357 | 358 | /** 359 | * \brief Calculate encoded size of a Filter Flags field 360 | * 361 | * Knowing the size of Filter Flags is useful to know when allocating 362 | * memory to hold the encoded Filter Flags. 363 | * 364 | * \param size Pointer to integer to hold the calculated size 365 | * \param filter Filter ID and associated options whose encoded 366 | * size is to be calculated 367 | * 368 | * \return - LZMA_OK: *size set successfully. Note that this doesn't 369 | * guarantee that filter->options is valid, thus 370 | * lzma_filter_flags_encode() may still fail. 371 | * - LZMA_OPTIONS_ERROR: Unknown Filter ID or unsupported options. 372 | * - LZMA_PROG_ERROR: Invalid options 373 | * 374 | * \note If you need to calculate size of List of Filter Flags, 375 | * you need to loop over every lzma_filter entry. 376 | */ 377 | nothrow lzma_ret lzma_filter_flags_size( 378 | uint *size, const lzma_filter *filter); 379 | 380 | 381 | /** 382 | * \brief Encode Filter Flags into given buffer 383 | * 384 | * In contrast to some functions, this doesn't allocate the needed buffer. 385 | * This is due to how this function is used internally by liblzma. 386 | * 387 | * \param filter Filter ID and options to be encoded 388 | * \param out Beginning of the output buffer 389 | * \param out_pos out[*out_pos] is the next write position. This 390 | * is updated by the encoder. 391 | * \param out_size out[out_size] is the first byte to not write. 392 | * 393 | * \return - LZMA_OK: Encoding was successful. 394 | * - LZMA_OPTIONS_ERROR: Invalid or unsupported options. 395 | * - LZMA_PROG_ERROR: Invalid options or not enough output 396 | * buffer space (you should have checked it with 397 | * lzma_filter_flags_size()). 398 | */ 399 | nothrow lzma_ret lzma_filter_flags_encode(const lzma_filter *filter, 400 | ubyte *out_, size_t *out_pos, size_t out_size); 401 | 402 | 403 | /** 404 | * \brief Decode Filter Flags from given buffer 405 | * 406 | * The decoded result is stored into *filter. The old value of 407 | * filter->options is not free()d. 408 | * 409 | * \return - LZMA_OK 410 | * - LZMA_OPTIONS_ERROR 411 | * - LZMA_MEM_ERROR 412 | * - LZMA_PROG_ERROR 413 | */ 414 | nothrow lzma_ret lzma_filter_flags_decode( 415 | lzma_filter *filter, lzma_allocator *allocator, 416 | const ubyte *in_, size_t *in_pos, size_t in_size); 417 | -------------------------------------------------------------------------------- /deimos/lzma_/hardware.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/hardware.h 3 | * \brief Hardware information 4 | * 5 | * Since liblzma can consume a lot of system resources, it also provides 6 | * ways to limit the resource usage. Applications linking against liblzma 7 | * need to do the actual decisions how much resources to let liblzma to use. 8 | * To ease making these decisions, liblzma provides functions to find out 9 | * the relevant capabilities of the underlaying hardware. Currently there 10 | * is only a function to find out the amount of RAM, but in the future there 11 | * will be also a function to detect how many concurrent threads the system 12 | * can run. 13 | * 14 | * \note On some operating systems, these function may temporarily 15 | * load a shared library or open file descriptor(s) to find out 16 | * the requested hardware information. Unless the application 17 | * assumes that specific file descriptors are not touched by 18 | * other threads, this should have no effect on thread safety. 19 | * Possible operations involving file descriptors will restart 20 | * the syscalls if they return EINTR. 21 | */ 22 | 23 | /* 24 | * Author: Lasse Collin 25 | * 26 | * This file has been put into the public domain. 27 | * You can do whatever you want with this file. 28 | * 29 | * See ../lzma.h for information about liblzma as a whole. 30 | */ 31 | 32 | module deimos.lzma_.hardware; 33 | import deimos.lzma; 34 | 35 | extern(C): 36 | 37 | /** 38 | * \brief Get the total amount of physical memory (RAM) in bytes 39 | * 40 | * This function may be useful when determining a reasonable memory 41 | * usage limit for decompressing or how much memory it is OK to use 42 | * for compressing. 43 | * 44 | * \return On success, the total amount of physical memory in bytes 45 | * is returned. If the amount of RAM cannot be determined, 46 | * zero is returned. This can happen if an error occurs 47 | * or if there is no code in liblzma to detect the amount 48 | * of RAM on the specific operating system. 49 | */ 50 | nothrow ulong lzma_physmem(); 51 | -------------------------------------------------------------------------------- /deimos/lzma_/index_hash.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/index_hash.h 3 | * \brief Validate Index by using a hash function 4 | * 5 | * Hashing makes it possible to use constant amount of memory to validate 6 | * Index of arbitrary size. 7 | */ 8 | 9 | /* 10 | * Author: Lasse Collin 11 | * 12 | * This file has been put into the public domain. 13 | * You can do whatever you want with this file. 14 | * 15 | * See ../lzma.h for information about liblzma as a whole. 16 | */ 17 | 18 | module deimos.lzma_.index_hash; 19 | import deimos.lzma; 20 | 21 | extern(C): 22 | 23 | /** 24 | * \brief Opaque data type to hold the Index hash 25 | */ 26 | struct lzma_index_hash {}; 27 | 28 | 29 | /** 30 | * \brief Allocate and initialize a new lzma_index_hash structure 31 | * 32 | * If index_hash is NULL, a new lzma_index_hash structure is allocated, 33 | * initialized, and a pointer to it returned. If allocation fails, NULL 34 | * is returned. 35 | * 36 | * If index_hash is non-NULL, it is reinitialized and the same pointer 37 | * returned. In this case, return value cannot be NULL or a different 38 | * pointer than the index_hash that was given as an argument. 39 | */ 40 | nothrow lzma_index_hash * lzma_index_hash_init( 41 | lzma_index_hash *index_hash, lzma_allocator *allocator); 42 | 43 | 44 | /** 45 | * \brief Deallocate lzma_index_hash structure 46 | */ 47 | nothrow void lzma_index_hash_end( 48 | lzma_index_hash *index_hash, lzma_allocator *allocator); 49 | 50 | 51 | /** 52 | * \brief Add a new Record to an Index hash 53 | * 54 | * \param index Pointer to a lzma_index_hash structure 55 | * \param unpadded_size Unpadded Size of a Block 56 | * \param uncompressed_size Uncompressed Size of a Block 57 | * 58 | * \return - LZMA_OK 59 | * - LZMA_DATA_ERROR: Compressed or uncompressed size of the 60 | * Stream or size of the Index field would grow too big. 61 | * - LZMA_PROG_ERROR: Invalid arguments or this function is being 62 | * used when lzma_index_hash_decode() has already been used. 63 | */ 64 | nothrow lzma_ret lzma_index_hash_append(lzma_index_hash *index_hash, 65 | lzma_vli unpadded_size, lzma_vli uncompressed_size); 66 | 67 | 68 | /** 69 | * \brief Decode and validate the Index field 70 | * 71 | * After telling the sizes of all Blocks with lzma_index_hash_append(), 72 | * the actual Index field is decoded with this function. Specifically, 73 | * once decoding of the Index field has been started, no more Records 74 | * can be added using lzma_index_hash_append(). 75 | * 76 | * This function doesn't use lzma_stream structure to pass the input data. 77 | * Instead, the input buffer is specified using three arguments. This is 78 | * because it matches better the internal APIs of liblzma. 79 | * 80 | * \param index_hash Pointer to a lzma_index_hash structure 81 | * \param in Pointer to the beginning of the input buffer 82 | * \param in_pos in[*in_pos] is the next byte to process 83 | * \param in_size in[in_size] is the first byte not to process 84 | * 85 | * \return - LZMA_OK: So far good, but more input is needed. 86 | * - LZMA_STREAM_END: Index decoded successfully and it matches 87 | * the Records given with lzma_index_hash_append(). 88 | * - LZMA_DATA_ERROR: Index is corrupt or doesn't match the 89 | * information given with lzma_index_hash_append(). 90 | * - LZMA_BUF_ERROR: Cannot progress because *in_pos >= in_size. 91 | * - LZMA_PROG_ERROR 92 | */ 93 | nothrow lzma_ret lzma_index_hash_decode(lzma_index_hash *index_hash, 94 | const ubyte *in_, size_t *in_pos, size_t in_size); 95 | 96 | 97 | /** 98 | * \brief Get the size of the Index field as bytes 99 | * 100 | * This is needed to verify the Backward Size field in the Stream Footer. 101 | */ 102 | nothrow pure lzma_vli lzma_index_hash_size( 103 | const lzma_index_hash *index_hash); 104 | -------------------------------------------------------------------------------- /deimos/lzma_/lzma.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/lzma.h 3 | * \brief LZMA1 and LZMA2 filters 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.lzma; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | 21 | /** 22 | * \brief LZMA1 Filter ID 23 | * 24 | * LZMA1 is the very same thing as what was called just LZMA in LZMA Utils, 25 | * 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from 26 | * accidentally using LZMA when they actually want LZMA2. 27 | * 28 | * LZMA1 shouldn't be used for new applications unless you _really_ know 29 | * what you are doing. LZMA2 is almost always a better choice. 30 | */ 31 | enum LZMA_FILTER_LZMA1 = 0x4000000000000001UL; 32 | 33 | /** 34 | * \brief LZMA2 Filter ID 35 | * 36 | * Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds 37 | * support for LZMA_SYNC_FLUSH, uncompressed chunks (smaller expansion 38 | * when trying to compress uncompressible data), possibility to change 39 | * lc/lp/pb in the middle of encoding, and some other internal improvements. 40 | */ 41 | enum LZMA_FILTER_LZMA2 = 0x21UL; 42 | 43 | 44 | /** 45 | * \brief Match finders 46 | * 47 | * Match finder has major effect on both speed and compression ratio. 48 | * Usually hash chains are faster than binary trees. 49 | * 50 | * If you will use LZMA_SYNC_FLUSH often, the hash chains may be a better 51 | * choice, because binary trees get much higher compression ratio penalty 52 | * with LZMA_SYNC_FLUSH. 53 | * 54 | * The memory usage formulas are only rough estimates, which are closest to 55 | * reality when dict_size is a power of two. The formulas are more complex 56 | * in reality, and can also change a little between liblzma versions. Use 57 | * lzma_raw_encoder_memusage() to get more accurate estimate of memory usage. 58 | */ 59 | enum lzma_match_finder 60 | { 61 | LZMA_MF_HC3 = 0x03, 62 | /**< 63 | * \brief Hash Chain with 2- and 3-byte hashing 64 | * 65 | * Minimum nice_len: 3 66 | * 67 | * Memory usage: 68 | * - dict_size <= 16 MiB: dict_size * 7.5 69 | * - dict_size > 16 MiB: dict_size * 5.5 + 64 MiB 70 | */ 71 | 72 | LZMA_MF_HC4 = 0x04, 73 | /**< 74 | * \brief Hash Chain with 2-, 3-, and 4-byte hashing 75 | * 76 | * Minimum nice_len: 4 77 | * 78 | * Memory usage: 79 | * - dict_size <= 32 MiB: dict_size * 7.5 80 | * - dict_size > 32 MiB: dict_size * 6.5 81 | */ 82 | 83 | LZMA_MF_BT2 = 0x12, 84 | /**< 85 | * \brief Binary Tree with 2-byte hashing 86 | * 87 | * Minimum nice_len: 2 88 | * 89 | * Memory usage: dict_size * 9.5 90 | */ 91 | 92 | LZMA_MF_BT3 = 0x13, 93 | /**< 94 | * \brief Binary Tree with 2- and 3-byte hashing 95 | * 96 | * Minimum nice_len: 3 97 | * 98 | * Memory usage: 99 | * - dict_size <= 16 MiB: dict_size * 11.5 100 | * - dict_size > 16 MiB: dict_size * 9.5 + 64 MiB 101 | */ 102 | 103 | LZMA_MF_BT4 = 0x14 104 | /**< 105 | * \brief Binary Tree with 2-, 3-, and 4-byte hashing 106 | * 107 | * Minimum nice_len: 4 108 | * 109 | * Memory usage: 110 | * - dict_size <= 32 MiB: dict_size * 11.5 111 | * - dict_size > 32 MiB: dict_size * 10.5 112 | */ 113 | } 114 | 115 | 116 | /** 117 | * \brief Test if given match finder is supported 118 | * 119 | * Return true if the given match finder is supported by this liblzma build. 120 | * Otherwise false is returned. It is safe to call this with a value that 121 | * isn't listed in lzma_match_finder enumeration; the return value will be 122 | * false. 123 | * 124 | * There is no way to list which match finders are available in this 125 | * particular liblzma version and build. It would be useless, because 126 | * a new match finder, which the application developer wasn't aware, 127 | * could require giving additional options to the encoder that the older 128 | * match finders don't need. 129 | */ 130 | nothrow lzma_bool lzma_mf_is_supported(lzma_match_finder match_finder); 131 | 132 | 133 | /** 134 | * \brief Compression modes 135 | * 136 | * This selects the function used to analyze the data produced by the match 137 | * finder. 138 | */ 139 | enum lzma_mode 140 | { 141 | LZMA_MODE_FAST = 1, 142 | /**< 143 | * \brief Fast compression 144 | * 145 | * Fast mode is usually at its best when combined with 146 | * a hash chain match finder. 147 | */ 148 | 149 | LZMA_MODE_NORMAL = 2 150 | /**< 151 | * \brief Normal compression 152 | * 153 | * This is usually notably slower than fast mode. Use this 154 | * together with binary tree match finders to expose the 155 | * full potential of the LZMA1 or LZMA2 encoder. 156 | */ 157 | } 158 | 159 | 160 | /** 161 | * \brief Test if given compression mode is supported 162 | * 163 | * Return true if the given compression mode is supported by this liblzma 164 | * build. Otherwise false is returned. It is safe to call this with a value 165 | * that isn't listed in lzma_mode enumeration; the return value will be false. 166 | * 167 | * There is no way to list which modes are available in this particular 168 | * liblzma version and build. It would be useless, because a new compression 169 | * mode, which the application developer wasn't aware, could require giving 170 | * additional options to the encoder that the older modes don't need. 171 | */ 172 | nothrow lzma_bool lzma_mode_is_supported(lzma_mode mode); 173 | 174 | 175 | /** 176 | * \brief Options specific to the LZMA1 and LZMA2 filters 177 | * 178 | * Since LZMA1 and LZMA2 share most of the code, it's simplest to share 179 | * the options structure too. For encoding, all but the reserved variables 180 | * need to be initialized unless specifically mentioned otherwise. 181 | * lzma_lzma_preset() can be used to get a good starting point. 182 | * 183 | * For raw decoding, both LZMA1 and LZMA2 need dict_size, preset_dict, and 184 | * preset_dict_size (if preset_dict != NULL). LZMA1 needs also lc, lp, and pb. 185 | */ 186 | struct lzma_options_lzma 187 | { 188 | /** 189 | * \brief Dictionary size in bytes 190 | * 191 | * Dictionary size indicates how many bytes of the recently processed 192 | * uncompressed data is kept in memory. One method to reduce size of 193 | * the uncompressed data is to store distance-length pairs, which 194 | * indicate what data to repeat from the dictionary buffer. Thus, 195 | * the bigger the dictionary, the better the compression ratio 196 | * usually is. 197 | * 198 | * Maximum size of the dictionary depends on multiple things: 199 | * - Memory usage limit 200 | * - Available address space (not a problem on 64-bit systems) 201 | * - Selected match finder (encoder only) 202 | * 203 | * Currently the maximum dictionary size for encoding is 1.5 GiB 204 | * (i.e. (UINT32_C(1) << 30) + (UINT32_C(1) << 29)) even on 64-bit 205 | * systems for certain match finder implementation reasons. In the 206 | * future, there may be match finders that support bigger 207 | * dictionaries. 208 | * 209 | * Decoder already supports dictionaries up to 4 GiB - 1 B (i.e. 210 | * UINT32_MAX), so increasing the maximum dictionary size of the 211 | * encoder won't cause problems for old decoders. 212 | * 213 | * Because extremely small dictionaries sizes would have unneeded 214 | * overhead in the decoder, the minimum dictionary size is 4096 bytes. 215 | * 216 | * \note When decoding, too big dictionary does no other harm 217 | * than wasting memory. 218 | */ 219 | uint dict_size; 220 | enum LZMA_DICT_SIZE_MIN = 4096U; 221 | enum LZMA_DICT_SIZE_DEFAULT = (1U << 23); 222 | 223 | /** 224 | * \brief Pointer to an initial dictionary 225 | * 226 | * It is possible to initialize the LZ77 history window using 227 | * a preset dictionary. It is useful when compressing many 228 | * similar, relatively small chunks of data independently from 229 | * each other. The preset dictionary should contain typical 230 | * strings that occur in the files being compressed. The most 231 | * probable strings should be near the end of the preset dictionary. 232 | * 233 | * This feature should be used only in special situations. For 234 | * now, it works correctly only with raw encoding and decoding. 235 | * Currently none of the container formats supported by 236 | * liblzma allow preset dictionary when decoding, thus if 237 | * you create a .xz or .lzma file with preset dictionary, it 238 | * cannot be decoded with the regular decoder functions. In the 239 | * future, the .xz format will likely get support for preset 240 | * dictionary though. 241 | */ 242 | const ubyte *preset_dict; 243 | 244 | /** 245 | * \brief Size of the preset dictionary 246 | * 247 | * Specifies the size of the preset dictionary. If the size is 248 | * bigger than dict_size, only the last dict_size bytes are 249 | * processed. 250 | * 251 | * This variable is read only when preset_dict is not NULL. 252 | * If preset_dict is not NULL but preset_dict_size is zero, 253 | * no preset dictionary is used (identical to only setting 254 | * preset_dict to NULL). 255 | */ 256 | uint preset_dict_size; 257 | 258 | /** 259 | * \brief Number of literal context bits 260 | * 261 | * How many of the highest bits of the previous uncompressed 262 | * eight-bit byte (also known as `literal') are taken into 263 | * account when predicting the bits of the next literal. 264 | * 265 | * E.g. in typical English text, an upper-case letter is 266 | * often followed by a lower-case letter, and a lower-case 267 | * letter is usually followed by another lower-case letter. 268 | * In the US-ASCII character set, the highest three bits are 010 269 | * for upper-case letters and 011 for lower-case letters. 270 | * When lc is at least 3, the literal coding can take advantage of 271 | * this property in the uncompressed data. 272 | * 273 | * There is a limit that applies to literal context bits and literal 274 | * position bits together: lc + lp <= 4. Without this limit the 275 | * decoding could become very slow, which could have security related 276 | * results in some cases like email servers doing virus scanning. 277 | * This limit also simplifies the internal implementation in liblzma. 278 | * 279 | * There may be LZMA1 streams that have lc + lp > 4 (maximum possible 280 | * lc would be 8). It is not possible to decode such streams with 281 | * liblzma. 282 | */ 283 | uint lc; 284 | enum LZMA_LCLP_MIN = 0; 285 | enum LZMA_LCLP_MAX = 4; 286 | enum LZMA_LC_DEFAULT = 3; 287 | 288 | /** 289 | * \brief Number of literal position bits 290 | * 291 | * lp affects what kind of alignment in the uncompressed data is 292 | * assumed when encoding literals. A literal is a single 8-bit byte. 293 | * See pb below for more information about alignment. 294 | */ 295 | uint lp; 296 | enum LZMA_LP_DEFAULT = 0; 297 | 298 | /** 299 | * \brief Number of position bits 300 | * 301 | * pb affects what kind of alignment in the uncompressed data is 302 | * assumed in general. The default means four-byte alignment 303 | * (2^ pb =2^2=4), which is often a good choice when there's 304 | * no better guess. 305 | * 306 | * When the aligment is known, setting pb accordingly may reduce 307 | * the file size a little. E.g. with text files having one-byte 308 | * alignment (US-ASCII, ISO-8859-*, UTF-8), setting pb=0 can 309 | * improve compression slightly. For UTF-16 text, pb=1 is a good 310 | * choice. If the alignment is an odd number like 3 bytes, pb=0 311 | * might be the best choice. 312 | * 313 | * Even though the assumed alignment can be adjusted with pb and 314 | * lp, LZMA1 and LZMA2 still slightly favor 16-byte alignment. 315 | * It might be worth taking into account when designing file formats 316 | * that are likely to be often compressed with LZMA1 or LZMA2. 317 | */ 318 | uint pb; 319 | enum LZMA_PB_MIN = 0; 320 | enum LZMA_PB_MAX = 4; 321 | enum LZMA_PB_DEFAULT = 2; 322 | 323 | /** Compression mode */ 324 | lzma_mode mode; 325 | 326 | /** 327 | * \brief Nice length of a match 328 | * 329 | * This determines how many bytes the encoder compares from the match 330 | * candidates when looking for the best match. Once a match of at 331 | * least nice_len bytes long is found, the encoder stops looking for 332 | * better candidates and encodes the match. (Naturally, if the found 333 | * match is actually longer than nice_len, the actual length is 334 | * encoded; it's not truncated to nice_len.) 335 | * 336 | * Bigger values usually increase the compression ratio and 337 | * compression time. For most files, 32 to 128 is a good value, 338 | * which gives very good compression ratio at good speed. 339 | * 340 | * The exact minimum value depends on the match finder. The maximum 341 | * is 273, which is the maximum length of a match that LZMA1 and 342 | * LZMA2 can encode. 343 | */ 344 | uint nice_len; 345 | 346 | /** Match finder ID */ 347 | lzma_match_finder mf; 348 | 349 | /** 350 | * \brief Maximum search depth in the match finder 351 | * 352 | * For every input byte, match finder searches through the hash chain 353 | * or binary tree in a loop, each iteration going one step deeper in 354 | * the chain or tree. The searching stops if 355 | * - a match of at least nice_len bytes long is found; 356 | * - all match candidates from the hash chain or binary tree have 357 | * been checked; or 358 | * - maximum search depth is reached. 359 | * 360 | * Maximum search depth is needed to prevent the match finder from 361 | * wasting too much time in case there are lots of short match 362 | * candidates. On the other hand, stopping the search before all 363 | * candidates have been checked can reduce compression ratio. 364 | * 365 | * Setting depth to zero tells liblzma to use an automatic default 366 | * value, that depends on the selected match finder and nice_len. 367 | * The default is in the range [4, 200] or so (it may vary between 368 | * liblzma versions). 369 | * 370 | * Using a bigger depth value than the default can increase 371 | * compression ratio in some cases. There is no strict maximum value, 372 | * but high values (thousands or millions) should be used with care: 373 | * the encoder could remain fast enough with typical input, but 374 | * malicious input could cause the match finder to slow down 375 | * dramatically, possibly creating a denial of service attack. 376 | */ 377 | uint depth; 378 | 379 | /* 380 | * Reserved space to allow possible future extensions without 381 | * breaking the ABI. You should not touch these, because the names 382 | * of these variables may change. These are and will never be used 383 | * with the currently supported options, so it is safe to leave these 384 | * uninitialized. 385 | */ 386 | uint reserved_int1; 387 | uint reserved_int2; 388 | uint reserved_int3; 389 | uint reserved_int4; 390 | uint reserved_int5; 391 | uint reserved_int6; 392 | uint reserved_int7; 393 | uint reserved_int8; 394 | lzma_reserved_enum reserved_enum1; 395 | lzma_reserved_enum reserved_enum2; 396 | lzma_reserved_enum reserved_enum3; 397 | lzma_reserved_enum reserved_enum4; 398 | void *reserved_ptr1; 399 | void *reserved_ptr2; 400 | 401 | } 402 | 403 | 404 | /** 405 | * \brief Set a compression preset to lzma_options_lzma structure 406 | * 407 | * 0 is the fastest and 9 is the slowest. These match the switches -0 .. -9 408 | * of the xz command line tool. In addition, it is possible to bitwise-or 409 | * flags to the preset. Currently only LZMA_PRESET_EXTREME is supported. 410 | * The flags are defined in container.h, because the flags are used also 411 | * with lzma_easy_encoder(). 412 | * 413 | * The preset values are subject to changes between liblzma versions. 414 | * 415 | * This function is available only if LZMA1 or LZMA2 encoder has been enabled 416 | * when building liblzma. 417 | * 418 | * \return On success, false is returned. If the preset is not 419 | * supported, true is returned. 420 | */ 421 | nothrow lzma_bool lzma_lzma_preset( 422 | lzma_options_lzma *options, uint preset); 423 | -------------------------------------------------------------------------------- /deimos/lzma_/stream_flags.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/stream_flags.h 3 | * \brief .xz Stream Header and Stream Footer encoder and decoder 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.stream_flags; 16 | import deimos.lzma; 17 | 18 | extern(C): 19 | 20 | 21 | /** 22 | * \brief Size of Stream Header and Stream Footer 23 | * 24 | * Stream Header and Stream Footer have the same size and they are not 25 | * going to change even if a newer version of the .xz file format is 26 | * developed in future. 27 | */ 28 | enum LZMA_STREAM_HEADER_SIZE = 12; 29 | 30 | 31 | /** 32 | * \brief Options for encoding/decoding Stream Header and Stream Footer 33 | */ 34 | struct lzma_stream_flags 35 | { 36 | /** 37 | * \brief Stream Flags format version 38 | * 39 | * To prevent API and ABI breakages if new features are needed in 40 | * Stream Header or Stream Footer, a version number is used to 41 | * indicate which fields in this structure are in use. For now, 42 | * version must always be zero. With non-zero version, the 43 | * lzma_stream_header_encode() and lzma_stream_footer_encode() 44 | * will return LZMA_OPTIONS_ERROR. 45 | * 46 | * lzma_stream_header_decode() and lzma_stream_footer_decode() 47 | * will always set this to the lowest value that supports all the 48 | * features indicated by the Stream Flags field. The application 49 | * must check that the version number set by the decoding functions 50 | * is supported by the application. Otherwise it is possible that 51 | * the application will decode the Stream incorrectly. 52 | */ 53 | uint version_; 54 | 55 | /** 56 | * \brief Backward Size 57 | * 58 | * Backward Size must be a multiple of four bytes. In this Stream 59 | * format version, Backward Size is the size of the Index field. 60 | * 61 | * Backward Size isn't actually part of the Stream Flags field, but 62 | * it is convenient to include in this structure anyway. Backward 63 | * Size is present only in the Stream Footer. There is no need to 64 | * initialize backward_size when encoding Stream Header. 65 | * 66 | * lzma_stream_header_decode() always sets backward_size to 67 | * LZMA_VLI_UNKNOWN so that it is convenient to use 68 | * lzma_stream_flags_compare() when both Stream Header and Stream 69 | * Footer have been decoded. 70 | */ 71 | lzma_vli backward_size; 72 | enum LZMA_BACKWARD_SIZE_MIN = 4; 73 | enum LZMA_BACKWARD_SIZE_MAX = (1UL << 34); 74 | 75 | /** 76 | * \brief Check ID 77 | * 78 | * This indicates the type of the integrity check calculated from 79 | * uncompressed data. 80 | */ 81 | lzma_check check; 82 | 83 | /* 84 | * Reserved space to allow possible future extensions without 85 | * breaking the ABI. You should not touch these, because the 86 | * names of these variables may change. 87 | * 88 | * (We will never be able to use all of these since Stream Flags 89 | * is just two bytes plus Backward Size of four bytes. But it's 90 | * nice to have the proper types when they are needed.) 91 | */ 92 | lzma_reserved_enum reserved_enum1; 93 | lzma_reserved_enum reserved_enum2; 94 | lzma_reserved_enum reserved_enum3; 95 | lzma_reserved_enum reserved_enum4; 96 | lzma_bool reserved_bool1; 97 | lzma_bool reserved_bool2; 98 | lzma_bool reserved_bool3; 99 | lzma_bool reserved_bool4; 100 | lzma_bool reserved_bool5; 101 | lzma_bool reserved_bool6; 102 | lzma_bool reserved_bool7; 103 | lzma_bool reserved_bool8; 104 | uint reserved_int1; 105 | uint reserved_int2; 106 | } 107 | 108 | 109 | /** 110 | * \brief Encode Stream Header 111 | * 112 | * \param options Stream Header options to be encoded. 113 | * options->backward_size is ignored and doesn't 114 | * need to be initialized. 115 | * \param out Beginning of the output buffer of 116 | * LZMA_STREAM_HEADER_SIZE bytes. 117 | * 118 | * \return - LZMA_OK: Encoding was successful. 119 | * - LZMA_OPTIONS_ERROR: options->version is not supported by 120 | * this liblzma version. 121 | * - LZMA_PROG_ERROR: Invalid options. 122 | */ 123 | nothrow lzma_ret lzma_stream_header_encode( 124 | const lzma_stream_flags *options, ubyte *out_); 125 | 126 | 127 | /** 128 | * \brief Encode Stream Footer 129 | * 130 | * \param options Stream Footer options to be encoded. 131 | * \param out Beginning of the output buffer of 132 | * LZMA_STREAM_HEADER_SIZE bytes. 133 | * 134 | * \return - LZMA_OK: Encoding was successful. 135 | * - LZMA_OPTIONS_ERROR: options->version is not supported by 136 | * this liblzma version. 137 | * - LZMA_PROG_ERROR: Invalid options. 138 | */ 139 | nothrow lzma_ret lzma_stream_footer_encode( 140 | const lzma_stream_flags *options, ubyte *out_); 141 | 142 | 143 | /** 144 | * \brief Decode Stream Header 145 | * 146 | * \param options Target for the decoded Stream Header options. 147 | * \param in Beginning of the input buffer of 148 | * LZMA_STREAM_HEADER_SIZE bytes. 149 | * 150 | * options->backward_size is always set to LZMA_VLI_UNKNOWN. This is to 151 | * help comparing Stream Flags from Stream Header and Stream Footer with 152 | * lzma_stream_flags_compare(). 153 | * 154 | * \return - LZMA_OK: Decoding was successful. 155 | * - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given 156 | * buffer cannot be Stream Header. 157 | * - LZMA_DATA_ERROR: CRC32 doesn't match, thus the header 158 | * is corrupt. 159 | * - LZMA_OPTIONS_ERROR: Unsupported options are present 160 | * in the header. 161 | * 162 | * \note When decoding .xz files that contain multiple Streams, it may 163 | * make sense to print "file format not recognized" only if 164 | * decoding of the Stream Header of the _first_ Stream gives 165 | * LZMA_FORMAT_ERROR. If non-first Stream Header gives 166 | * LZMA_FORMAT_ERROR, the message used for LZMA_DATA_ERROR is 167 | * probably more appropriate. 168 | * 169 | * For example, Stream decoder in liblzma uses LZMA_DATA_ERROR if 170 | * LZMA_FORMAT_ERROR is returned by lzma_stream_header_decode() 171 | * when decoding non-first Stream. 172 | */ 173 | nothrow lzma_ret lzma_stream_header_decode( 174 | lzma_stream_flags *options, const ubyte *in_); 175 | 176 | 177 | /** 178 | * \brief Decode Stream Footer 179 | * 180 | * \param options Target for the decoded Stream Header options. 181 | * \param in Beginning of the input buffer of 182 | * LZMA_STREAM_HEADER_SIZE bytes. 183 | * 184 | * \return - LZMA_OK: Decoding was successful. 185 | * - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given 186 | * buffer cannot be Stream Footer. 187 | * - LZMA_DATA_ERROR: CRC32 doesn't match, thus the Stream Footer 188 | * is corrupt. 189 | * - LZMA_OPTIONS_ERROR: Unsupported options are present 190 | * in Stream Footer. 191 | * 192 | * \note If Stream Header was already decoded successfully, but 193 | * decoding Stream Footer returns LZMA_FORMAT_ERROR, the 194 | * application should probably report some other error message 195 | * than "file format not recognized", since the file more likely 196 | * is corrupt (possibly truncated). Stream decoder in liblzma 197 | * uses LZMA_DATA_ERROR in this situation. 198 | */ 199 | nothrow lzma_ret lzma_stream_footer_decode( 200 | lzma_stream_flags *options, const ubyte *in_); 201 | 202 | 203 | /** 204 | * \brief Compare two lzma_stream_flags structures 205 | * 206 | * backward_size values are compared only if both are not 207 | * LZMA_VLI_UNKNOWN. 208 | * 209 | * \return - LZMA_OK: Both are equal. If either had backward_size set 210 | * to LZMA_VLI_UNKNOWN, backward_size values were not 211 | * compared or validated. 212 | * - LZMA_DATA_ERROR: The structures differ. 213 | * - LZMA_OPTIONS_ERROR: version in either structure is greater 214 | * than the maximum supported version (currently zero). 215 | * - LZMA_PROG_ERROR: Invalid value, e.g. invalid check or 216 | * backward_size. 217 | */ 218 | nothrow pure lzma_ret lzma_stream_flags_compare( 219 | const lzma_stream_flags *a, const lzma_stream_flags *b); 220 | -------------------------------------------------------------------------------- /deimos/lzma_/version_.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/version.h 3 | * \brief Version number 4 | */ 5 | 6 | /* 7 | * Author: Lasse Collin 8 | * 9 | * This file has been put into the public domain. 10 | * You can do whatever you want with this file. 11 | * 12 | * See ../lzma.h for information about liblzma as a whole. 13 | */ 14 | 15 | module deimos.lzma_.version_; 16 | import deimos.lzma; 17 | import std.conv; 18 | 19 | extern(C): 20 | 21 | /* 22 | * Version number split into components 23 | */ 24 | enum LZMA_VERSION_MAJOR = 5; 25 | enum LZMA_VERSION_MINOR = 0; 26 | enum LZMA_VERSION_PATCH = 3; 27 | enum LZMA_VERSION_STABILITY = LZMA_VERSION_STABILITY_STABLE; 28 | 29 | /* 30 | #ifndef LZMA_VERSION_COMMIT 31 | # define LZMA_VERSION_COMMIT "" 32 | #endif*/ 33 | enum LZMA_VERSION_COMMIT = ""; 34 | 35 | /* 36 | * Map symbolic stability levels to integers. 37 | */ 38 | enum LZMA_VERSION_STABILITY_ALPHA = 0; 39 | enum LZMA_VERSION_STABILITY_BETA = 1; 40 | enum LZMA_VERSION_STABILITY_STABLE = 2; 41 | 42 | 43 | /** 44 | * \brief Compile-time version number 45 | * 46 | * The version number is of format xyyyzzzs where 47 | * - x = major 48 | * - yyy = minor 49 | * - zzz = revision 50 | * - s indicates stability: 0 = alpha, 1 = beta, 2 = stable 51 | * 52 | * The same xyyyzzz triplet is never reused with different stability levels. 53 | * For example, if 5.1.0alpha has been released, there will never be 5.1.0beta 54 | * or 5.1.0 stable. 55 | * 56 | * \note The version number of liblzma has nothing to with 57 | * the version number of Igor Pavlov's LZMA SDK. 58 | */ 59 | enum LZMA_VERSION = (LZMA_VERSION_MAJOR * 10000000U 60 | + LZMA_VERSION_MINOR * 10000U 61 | + LZMA_VERSION_PATCH * 10U 62 | + LZMA_VERSION_STABILITY); 63 | 64 | 65 | /* 66 | * Macros to construct the compile-time version string 67 | */ 68 | static if(LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_ALPHA) 69 | enum LZMA_VERSION_STABILITY_STRING = "alpha"; 70 | else static if(LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_BETA) 71 | enum LZMA_VERSION_STABILITY_STRING = "beta"; 72 | else static if(LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_STABLE) 73 | enum LZMA_VERSION_STABILITY_STRING = ""; 74 | else 75 | static assert(false, "Incorrect LZMA_VERSION_STABILITY"); 76 | 77 | /** 78 | * \brief Compile-time version as a string 79 | * 80 | * This can be for example "4.999.5alpha", "4.999.8beta", or "5.0.0" (stable 81 | * versions don't have any "stable" suffix). In future, a snapshot built 82 | * from source code repository may include an additional suffix, for example 83 | * "4.999.8beta-21-g1d92". The commit ID won't be available in numeric form 84 | * in LZMA_VERSION macro. 85 | */ 86 | enum LZMA_VERSION_STRING = 87 | to!string(LZMA_VERSION_MAJOR) ~ "." ~ to!string(LZMA_VERSION_MINOR) ~ 88 | "." ~ to!string(LZMA_VERSION_PATCH) ~ LZMA_VERSION_STABILITY_STRING ~ 89 | LZMA_VERSION_COMMIT; 90 | 91 | 92 | /** 93 | * \brief Run-time version number as an integer 94 | * 95 | * Return the value of LZMA_VERSION macro at the compile time of liblzma. 96 | * This allows the application to compare if it was built against the same, 97 | * older, or newer version of liblzma that is currently running. 98 | */ 99 | nothrow uint lzma_version_number(); 100 | 101 | 102 | /** 103 | * \brief Run-time version as a string 104 | * 105 | * This function may be useful if you want to display which version of 106 | * liblzma your application is currently using. 107 | */ 108 | nothrow immutable(char)* lzma_version_string(); 109 | -------------------------------------------------------------------------------- /deimos/lzma_/vli.d: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lzma/vli.h 3 | * \brief Variable-length integer handling 4 | * 5 | * In the .xz format, most integers are encoded in a variable-length 6 | * representation, which is sometimes called little endian base-128 encoding. 7 | * This saves space when smaller values are more likely than bigger values. 8 | * 9 | * The encoding scheme encodes seven bits to every byte, using minimum 10 | * number of bytes required to represent the given value. Encodings that use 11 | * non-minimum number of bytes are invalid, thus every integer has exactly 12 | * one encoded representation. The maximum number of bits in a VLI is 63, 13 | * thus the vli argument must be less than or equal to UINT64_MAX / 2. You 14 | * should use LZMA_VLI_MAX for clarity. 15 | */ 16 | 17 | /* 18 | * Author: Lasse Collin 19 | * 20 | * This file has been put into the public domain. 21 | * You can do whatever you want with this file. 22 | * 23 | * See ../lzma.h for information about liblzma as a whole. 24 | */ 25 | 26 | module deimos.lzma_.vli; 27 | import deimos.lzma; 28 | 29 | extern(C): 30 | 31 | 32 | /** 33 | * \brief Maximum supported value of a variable-length integer 34 | */ 35 | enum LZMA_VLI_MAX = (ulong.max / 2); 36 | 37 | /** 38 | * \brief VLI value to denote that the value is unknown 39 | */ 40 | enum LZMA_VLI_UNKNOWN = ulong.max; 41 | 42 | /** 43 | * \brief Maximum supported encoded length of variable length integers 44 | */ 45 | enum LZMA_VLI_BYTES_MAX = 9; 46 | 47 | /** 48 | * \brief VLI constant suffix 49 | */ 50 | //#define LZMA_VLI_C(n) UINT64_C(n) 51 | 52 | 53 | /** 54 | * \brief Variable-length integer type 55 | * 56 | * Valid VLI values are in the range [0, LZMA_VLI_MAX]. Unknown value is 57 | * indicated with LZMA_VLI_UNKNOWN, which is the maximum value of the 58 | * underlaying integer type. 59 | * 60 | * lzma_vli will be uint64_t for the foreseeable future. If a bigger size 61 | * is needed in the future, it is guaranteed that 2 * LZMA_VLI_MAX will 62 | * not overflow lzma_vli. This simplifies integer overflow detection. 63 | */ 64 | alias ulong lzma_vli; 65 | 66 | 67 | /** 68 | * \brief Validate a variable-length integer 69 | * 70 | * This is useful to test that application has given acceptable values 71 | * for example in the uncompressed_size and compressed_size variables. 72 | * 73 | * \return True if the integer is representable as VLI or if it 74 | * indicates unknown value. 75 | */ 76 | bool lzma_vli_is_valid(lzma_vli vli) 77 | { 78 | return vli <= LZMA_VLI_MAX || (vli) == LZMA_VLI_UNKNOWN; 79 | } 80 | 81 | 82 | /** 83 | * \brief Encode a variable-length integer 84 | * 85 | * This function has two modes: single-call and multi-call. Single-call mode 86 | * encodes the whole integer at once; it is an error if the output buffer is 87 | * too small. Multi-call mode saves the position in *vli_pos, and thus it is 88 | * possible to continue encoding if the buffer becomes full before the whole 89 | * integer has been encoded. 90 | * 91 | * \param vli Integer to be encoded 92 | * \param vli_pos How many VLI-encoded bytes have already been written 93 | * out. When starting to encode a new integer in 94 | * multi-call mode, *vli_pos must be set to zero. 95 | * To use single-call encoding, set vli_pos to NULL. 96 | * \param out Beginning of the output buffer 97 | * \param out_pos The next byte will be written to out[*out_pos]. 98 | * \param out_size Size of the out buffer; the first byte into 99 | * which no data is written to is out[out_size]. 100 | * 101 | * \return Slightly different return values are used in multi-call and 102 | * single-call modes. 103 | * 104 | * Single-call (vli_pos == NULL): 105 | * - LZMA_OK: Integer successfully encoded. 106 | * - LZMA_PROG_ERROR: Arguments are not sane. This can be due 107 | * to too little output space; single-call mode doesn't use 108 | * LZMA_BUF_ERROR, since the application should have checked 109 | * the encoded size with lzma_vli_size(). 110 | * 111 | * Multi-call (vli_pos != NULL): 112 | * - LZMA_OK: So far all OK, but the integer is not 113 | * completely written out yet. 114 | * - LZMA_STREAM_END: Integer successfully encoded. 115 | * - LZMA_BUF_ERROR: No output space was provided. 116 | * - LZMA_PROG_ERROR: Arguments are not sane. 117 | */ 118 | nothrow lzma_ret lzma_vli_encode(lzma_vli vli, size_t *vli_pos, 119 | ubyte* out_, size_t *out_pos, size_t out_size); 120 | 121 | 122 | /** 123 | * \brief Decode a variable-length integer 124 | * 125 | * Like lzma_vli_encode(), this function has single-call and multi-call modes. 126 | * 127 | * \param vli Pointer to decoded integer. The decoder will 128 | * initialize it to zero when *vli_pos == 0, so 129 | * application isn't required to initialize *vli. 130 | * \param vli_pos How many bytes have already been decoded. When 131 | * starting to decode a new integer in multi-call 132 | * mode, *vli_pos must be initialized to zero. To 133 | * use single-call decoding, set vli_pos to NULL. 134 | * \param in Beginning of the input buffer 135 | * \param in_pos The next byte will be read from in[*in_pos]. 136 | * \param in_size Size of the input buffer; the first byte that 137 | * won't be read is in[in_size]. 138 | * 139 | * \return Slightly different return values are used in multi-call and 140 | * single-call modes. 141 | * 142 | * Single-call (vli_pos == NULL): 143 | * - LZMA_OK: Integer successfully decoded. 144 | * - LZMA_DATA_ERROR: Integer is corrupt. This includes hitting 145 | * the end of the input buffer before the whole integer was 146 | * decoded; providing no input at all will use LZMA_DATA_ERROR. 147 | * - LZMA_PROG_ERROR: Arguments are not sane. 148 | * 149 | * Multi-call (vli_pos != NULL): 150 | * - LZMA_OK: So far all OK, but the integer is not 151 | * completely decoded yet. 152 | * - LZMA_STREAM_END: Integer successfully decoded. 153 | * - LZMA_DATA_ERROR: Integer is corrupt. 154 | * - LZMA_BUF_ERROR: No input was provided. 155 | * - LZMA_PROG_ERROR: Arguments are not sane. 156 | */ 157 | nothrow lzma_ret lzma_vli_decode(lzma_vli *vli, size_t *vli_pos, 158 | const(ubyte)* in_, size_t *in_pos, size_t in_size); 159 | 160 | 161 | /** 162 | * \brief Get the number of bytes required to encode a VLI 163 | * 164 | * \return Number of bytes on success (1-9). If vli isn't valid, 165 | * zero is returned. 166 | */ 167 | nothrow pure uint lzma_vli_size(lzma_vli vli); 168 | -------------------------------------------------------------------------------- /liblzma.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberShadow/RABCDAsm/8ed623a3225ec9947f75f50bc78f5d2412a0802d/liblzma.lib -------------------------------------------------------------------------------- /lzma.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012, 2013, 2014, 2016 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module lzma; 20 | 21 | version(HAVE_LZMA) {} else static assert(0, "LZMA is not available (HAVE_LZMA version is not defined)"); 22 | 23 | import deimos.lzma; 24 | import std.conv; 25 | import std.exception; 26 | import std.string : format; 27 | 28 | version (Windows) 29 | { pragma(lib, "liblzma"); } 30 | else 31 | { pragma(lib, "lzma"); } 32 | 33 | align(1) struct LZMAHeader 34 | { 35 | align(1): 36 | ubyte compressionParameters; 37 | uint dictionarySize; 38 | long decompressedSize = -1; 39 | } 40 | static assert(LZMAHeader.sizeof == 13); 41 | 42 | ubyte[] lzmaDecompress(LZMAHeader header, in ubyte[] compressedData) 43 | { 44 | lzma_stream strm; 45 | lzmaEnforce(lzma_alone_decoder(&strm, ulong.max), "lzma_alone_decoder"); 46 | scope(exit) lzma_end(&strm); 47 | 48 | auto outBuf = new ubyte[1024]; 49 | size_t pos = 0; 50 | 51 | void decompress(in ubyte[] chunk) 52 | { 53 | strm.next_in = chunk.ptr; 54 | strm.avail_in = chunk.length; 55 | 56 | again: 57 | strm.next_out = outBuf.ptr + pos; 58 | strm.avail_out = outBuf.length - pos; 59 | auto ret = lzma_code(&strm, lzma_action.LZMA_RUN); 60 | pos = strm.next_out - outBuf.ptr; 61 | 62 | if (ret == lzma_ret.LZMA_OK && strm.avail_in && !strm.avail_out) 63 | { 64 | outBuf.length = outBuf.length * 2; 65 | goto again; 66 | } 67 | lzmaEnforce!true(ret, "lzma_code (LZMA_RUN)"); 68 | enforce(strm.avail_in == 0, "Not all data was read"); 69 | } 70 | 71 | header.decompressedSize = -1; // Required as Flash uses End-of-Stream marker 72 | fixDictSize(header.dictionarySize); 73 | decompress(cast(ubyte[])(&header)[0..1]); 74 | decompress(compressedData); 75 | 76 | lzmaEnforce!true(lzma_code(&strm, lzma_action.LZMA_FINISH), "lzma_code (LZMA_FINISH)"); 77 | 78 | // enforce(strm.avail_out == 0, 79 | // "Decompressed size mismatch (expected %d/0x%X, got %d/0x%X)".format( 80 | // outBuf.length, outBuf.length, 81 | // outBuf.length - strm.avail_out, outBuf.length - strm.avail_out, 82 | // )); 83 | 84 | outBuf = outBuf[0..pos]; 85 | 86 | return outBuf; 87 | } 88 | 89 | ubyte[] lzmaCompress(in ubyte[] decompressedData, LZMAHeader* header) 90 | { 91 | lzma_options_lzma opts; 92 | enforce(lzma_lzma_preset(&opts, 9 | LZMA_PRESET_EXTREME) == false, "lzma_lzma_preset error"); 93 | 94 | lzma_stream strm; 95 | lzmaEnforce(lzma_alone_encoder(&strm, &opts), "lzma_alone_encoder"); 96 | scope(exit) lzma_end(&strm); 97 | 98 | auto outBuf = new ubyte[decompressedData.length * 11 / 10 + 1024]; 99 | strm.next_out = outBuf.ptr; 100 | strm.avail_out = outBuf.length; 101 | strm.next_in = decompressedData.ptr; 102 | strm.avail_in = decompressedData.length; 103 | lzmaEnforce(lzma_code(&strm, lzma_action.LZMA_RUN), "lzma_code (LZMA_RUN)"); 104 | enforce(strm.avail_in == 0, "Not all data was read"); 105 | enforce(strm.avail_out != 0, "Ran out of compression space"); 106 | 107 | lzmaEnforce!true(lzma_code(&strm, lzma_action.LZMA_FINISH), "lzma_code (LZMA_FINISH)"); 108 | 109 | *header = *cast(LZMAHeader*)outBuf.ptr; 110 | return outBuf[LZMAHeader.sizeof..to!size_t(strm.total_out)]; 111 | } 112 | 113 | private void lzmaEnforce(bool STREAM_END_OK=false)(lzma_ret v, string f) 114 | { 115 | if (v != lzma_ret.LZMA_OK && (!STREAM_END_OK || v != lzma_ret.LZMA_STREAM_END)) 116 | throw new Exception(text(f, " error: ", v)); 117 | } 118 | 119 | /// Work around an artificial lzma_alone_decoder limitation in liblzma 120 | /// which prevents it from accepting any streams with a dictionary size 121 | /// that is not 2^n or 2^n + 2^(n-1). 122 | /// See xz\src\liblzma\common\alone_decoder.c (git commit e7b424d267), line 87 123 | private void fixDictSize(ref uint d) 124 | { 125 | --d; 126 | d |= d >> 2; 127 | d |= d >> 3; 128 | d |= d >> 4; 129 | d |= d >> 8; 130 | d |= d >> 16; 131 | ++d; 132 | } 133 | -------------------------------------------------------------------------------- /murmurhash2a.d: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // CMurmurHash2A, by Austin Appleby 3 | 4 | // This is a sample implementation of MurmurHash2A designed to work 5 | // incrementally. 6 | 7 | // Usage - 8 | 9 | // CMurmurHash2A hasher 10 | // hasher.Begin(seed); 11 | // hasher.Add(data1,size1); 12 | // hasher.Add(data2,size2); 13 | // ... 14 | // hasher.Add(dataN,sizeN); 15 | // uint hash = hasher.End() 16 | 17 | module murmurhash2a; 18 | 19 | import std.conv; 20 | 21 | struct MurmurHash2A 22 | { 23 | private static string mmix(string h, string k) { return "{ "~k~" *= m; "~k~" ^= "~k~" >> r; "~k~" *= m; "~h~" *= m; "~h~" ^= "~k~"; }"; } 24 | 25 | 26 | public: 27 | 28 | void Begin ( uint seed = 0 ) 29 | { 30 | m_hash = seed; 31 | m_tail = 0; 32 | m_count = 0; 33 | m_size = 0; 34 | } 35 | 36 | void Add ( const(void) * vdata, int len ) 37 | { 38 | ubyte * data = cast(ubyte*)vdata; 39 | m_size += len; 40 | 41 | MixTail(data,len); 42 | 43 | while(len >= 4) 44 | { 45 | uint k = *cast(uint*)data; 46 | 47 | mixin(mmix("m_hash","k")); 48 | 49 | data += 4; 50 | len -= 4; 51 | } 52 | 53 | MixTail(data,len); 54 | } 55 | 56 | uint End ( ) 57 | { 58 | mixin(mmix("m_hash","m_tail")); 59 | mixin(mmix("m_hash","m_size")); 60 | 61 | m_hash ^= m_hash >> 13; 62 | m_hash *= m; 63 | m_hash ^= m_hash >> 15; 64 | 65 | return m_hash; 66 | } 67 | 68 | // D-specific 69 | void Add(ref ubyte v) { Add(&v, v.sizeof); } 70 | void Add(ref int v) { Add(&v, v.sizeof); } 71 | void Add(ref uint v) { Add(&v, v.sizeof); } 72 | void Add(string s) { Add(s.ptr, to!uint(s.length)); } 73 | void Add(ubyte[] s) { Add(s.ptr, to!uint(s.length)); } 74 | 75 | private: 76 | 77 | static const uint m = 0x5bd1e995; 78 | static const int r = 24; 79 | 80 | void MixTail ( ref ubyte * data, ref int len ) 81 | { 82 | while( len && ((len<4) || m_count) ) 83 | { 84 | m_tail |= (*data++) << (m_count * 8); 85 | 86 | m_count++; 87 | len--; 88 | 89 | if(m_count == 4) 90 | { 91 | mixin(mmix("m_hash","m_tail")); 92 | m_tail = 0; 93 | m_count = 0; 94 | } 95 | } 96 | } 97 | 98 | uint m_hash; 99 | uint m_tail; 100 | uint m_count; 101 | uint m_size; 102 | }; 103 | -------------------------------------------------------------------------------- /rabcasm.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module rabcasm; 20 | 21 | import std.file; 22 | import std.path; 23 | import abcfile; 24 | import asprogram; 25 | import assembler; 26 | 27 | void main(string[] args) 28 | { 29 | if (args.length == 1) 30 | throw new Exception("No arguments specified"); 31 | auto as = new ASProgram; 32 | auto assembler = new Assembler(as); 33 | foreach (arg; args[1..$]) 34 | { 35 | assembler.assemble(arg); 36 | } 37 | auto abc = as.toABC(); 38 | write(setExtension(args[1], "abc"), abc.write()); 39 | } 40 | -------------------------------------------------------------------------------- /rabcdasm.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module rabcdasm; 20 | 21 | import std.file; 22 | import std.path; 23 | import abcfile; 24 | import asprogram; 25 | import disassembler; 26 | 27 | void main(string[] args) 28 | { 29 | if (args.length == 1) 30 | throw new Exception("No arguments specified"); 31 | foreach (arg; args[1..$]) 32 | { 33 | scope abc = ABCFile.read(cast(ubyte[])read(arg)); 34 | scope as = ASProgram.fromABC(abc); 35 | scope disassembler = new Disassembler(as, stripExtension(arg), stripExtension(baseName(arg))); 36 | disassembler.disassemble(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /swf7zcompress.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2016 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module swf7zcompress; 20 | 21 | import std.file; 22 | import std.process; 23 | import std.zlib; 24 | import swffile; 25 | import zlibx; 26 | 27 | ubyte[] gzip2zlib(ubyte[] data, uint adler) 28 | { 29 | enum 30 | { 31 | FTEXT = 1, 32 | FHCRC = 2, 33 | FEXTRA = 4, 34 | FNAME = 8, 35 | FCOMMENT = 16 36 | } 37 | 38 | if (data.length < 10 || data[0] != 0x1F || data[1] != 0x8B || data[2] != 0x08) 39 | throw new Exception("Bad or unsupported gzip format"); 40 | ubyte flags = data[3]; 41 | auto p = data.ptr; 42 | p += 10; // header size 43 | if (flags & (FHCRC | FEXTRA | FCOMMENT)) 44 | throw new Exception("Unsupported gzip flags"); 45 | if (flags & FNAME) 46 | while (*p++) {} 47 | 48 | ubyte[] chdr = [0x78, 0xDA]; // 11011010 49 | return chdr ~ data[p-data.ptr..data.length-8] ~ cast(ubyte[])[adler]; 50 | } 51 | 52 | void main(string[] args) 53 | { 54 | if (args.length == 1) 55 | throw new Exception("No file specified"); 56 | foreach (arg; args[1..$]) 57 | { 58 | auto swf = cast(ubyte[])read(arg); 59 | auto header = cast(SWFFile.Header*)swf.ptr; 60 | ubyte[] data; 61 | if (header.signature[0] == cast(ubyte)'C') 62 | data = exactUncompress(swf[8..$], header.fileLength-8); 63 | else 64 | if (header.signature[0] == cast(ubyte)'F') 65 | { 66 | data = swf[8..$]; 67 | header.signature[0] = cast(ubyte)'C'; 68 | } 69 | else 70 | throw new Exception("Unknown format"); 71 | if (header.fileLength != data.length + 8) 72 | throw new Exception("Incorrect file length in file header"); 73 | write(arg ~ ".tempdata", data); 74 | if (spawnProcess(["7z", "a", "-tgzip", "-mx=9", "-mfb=258", arg ~ ".tempdata.gz", arg ~ ".tempdata"]).wait() || !exists(arg ~ ".tempdata.gz")) 75 | throw new Exception("7-Zip failed"); 76 | remove(arg ~ ".tempdata"); 77 | auto gzipdata = cast(ubyte[])read(arg ~ ".tempdata.gz"); 78 | remove(arg ~ ".tempdata.gz"); 79 | auto zlibdata = gzip2zlib(gzipdata, adler32(0, data)); 80 | swf = swf[0..8] ~ zlibdata; 81 | write(arg, swf); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /swfbinexport.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module swfbinexport; 20 | 21 | import std.file; 22 | import std.path; 23 | import std.string; 24 | import std.stdio; 25 | import std.exception; 26 | import swffile; 27 | 28 | void main(string[] args) 29 | { 30 | if (args.length == 1) 31 | throw new Exception("No file specified"); 32 | foreach (arg; args[1..$]) 33 | try 34 | { 35 | scope swf = SWFFile.read(cast(ubyte[])read(arg)); 36 | bool found; 37 | foreach (ref tag; swf.tags) 38 | if (tag.type == TagType.DefineBinaryData) 39 | { 40 | found = true; 41 | enforce(tag.data.length >= 6); 42 | ushort id = *cast(short*)tag.data.ptr; 43 | ubyte[] bin = tag.data[6..$]; 44 | std.file.write(format("%s-%d.bin", stripExtension(arg), id), bin); 45 | } 46 | enforce(found, "No DefineBinaryData tags found"); 47 | } 48 | catch (Exception e) 49 | writefln("Error while processing %s: %s", arg, e); 50 | } 51 | -------------------------------------------------------------------------------- /swfbinreplace.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2012 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module swfbinreplace; 20 | 21 | import std.file; 22 | import std.conv; 23 | import swffile; 24 | 25 | void main(string[] args) 26 | { 27 | if (args.length != 4) 28 | throw new Exception("Bad arguments. Usage: swfbinreplace file.swf id data.bin"); 29 | auto swf = SWFFile.read(cast(ubyte[])read(args[1])); 30 | auto id = to!ushort(args[2]); 31 | foreach (ref tag; swf.tags) 32 | if (tag.type == TagType.DefineBinaryData && tag.data.length >= 6 && *cast(short*)tag.data.ptr == id) 33 | { 34 | auto bin = cast(ubyte[])read(args[3]); 35 | tag.data = tag.data[0..6] ~ bin; 36 | tag.length = cast(uint)tag.data.length; 37 | write(args[1], swf.write()); 38 | return; 39 | } 40 | throw new Exception("DefineBinaryData tag with specified ID not found in file"); 41 | } 42 | -------------------------------------------------------------------------------- /swfdecompress.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2012 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module swfdecompress; 20 | 21 | import std.file; 22 | import swffile; 23 | 24 | void main(string[] args) 25 | { 26 | if (args.length == 1) 27 | throw new Exception("No file specified"); 28 | foreach (arg; args[1..$]) 29 | { 30 | auto swf = SWFFile.read(cast(ubyte[])read(arg)); 31 | if (swf.header.signature[0] == cast(ubyte)'F') 32 | throw new Exception("Already uncompressed"); 33 | swf.header.signature[0] = cast(ubyte)'F'; // uncompressed 34 | write(arg, swf.write()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /swffile.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2012, 2016 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module swffile; 20 | 21 | import std.conv; 22 | import std.exception; 23 | import std.string : format; 24 | import std.zlib; 25 | import zlibx; 26 | version (HAVE_LZMA) import lzma; 27 | 28 | /** 29 | * Implements a shallow representation of a .swf file. 30 | * Loading and saving a .swf file using this class should produce 31 | * output identical to the input (aside zlib compression differences). 32 | */ 33 | 34 | final class SWFFile 35 | { 36 | Header header; 37 | Rect frameSize; 38 | ushort frameRate, frameCount; 39 | Tag[] tags; 40 | 41 | align(1) struct Header 42 | { 43 | align(1): 44 | char[3] signature; 45 | ubyte ver; 46 | uint fileLength; 47 | static assert(Header.sizeof == 8); 48 | } 49 | 50 | align(1) struct LZMAHeader 51 | { 52 | align(1): 53 | uint compressedLength; 54 | ubyte compressionParameters; 55 | uint dictionarySize; 56 | static assert(LZMAHeader.sizeof == 9); 57 | } 58 | 59 | struct Rect 60 | { 61 | //int xMin, xMax, yMin, yMax; 62 | ubyte[] bytes; 63 | } 64 | 65 | struct Tag 66 | { 67 | ushort type; 68 | ubyte[] data; 69 | uint length; // may be >data.length if file is truncated 70 | bool forceLongLength; 71 | } 72 | 73 | static SWFFile read(ubyte[] data) 74 | { 75 | return (new SWFReader(data)).swf; 76 | } 77 | 78 | ubyte[] write() 79 | { 80 | return SWFWriter.write(this); 81 | } 82 | } 83 | 84 | private final class SWFReader 85 | { 86 | ubyte[] buf; 87 | size_t pos; 88 | SWFFile swf; 89 | 90 | this(ubyte[] data) 91 | { 92 | buf = data; 93 | swf = new SWFFile(); 94 | 95 | readRaw((&swf.header)[0..1]); 96 | enforce(swf.header.signature == "FWS" || swf.header.signature == "CWS" || swf.header.signature == "ZWS", "Invalid file signature"); 97 | if (swf.header.signature[0] == 'C') 98 | buf = buf[0..swf.header.sizeof] ~ exactUncompress(buf[swf.header.sizeof..$], swf.header.fileLength-swf.header.sizeof); 99 | else 100 | if (swf.header.signature[0] == 'Z') 101 | { 102 | version (HAVE_LZMA) 103 | { 104 | SWFFile.LZMAHeader lzHeader; 105 | readRaw((&lzHeader)[0..1]); 106 | 107 | lzma.LZMAHeader lzInfo; 108 | lzInfo.compressionParameters = lzHeader.compressionParameters; 109 | lzInfo.dictionarySize = lzHeader.dictionarySize; 110 | lzInfo.decompressedSize = swf.header.fileLength - swf.header.sizeof; 111 | 112 | enforce(swf.header.sizeof + lzHeader.sizeof + lzHeader.compressedLength == buf.length, "Trailing data in LZMA-compressed SWF file"); 113 | buf = buf[0..swf.header.sizeof] ~ lzmaDecompress(lzInfo, buf[swf.header.sizeof + lzHeader.sizeof .. $]); 114 | pos = swf.header.sizeof; 115 | } 116 | else 117 | enforce(false, "This version was built without LZMA support"); 118 | } 119 | //enforce(swf.header.fileLength == buf.length, 120 | // "Incorrect file length in file header (expected %d, got %d)" 121 | // .format(swf.header.fileLength , buf.length)); 122 | swf.frameSize = readRect(); 123 | swf.frameRate = readU16(); 124 | swf.frameCount = readU16(); 125 | 126 | while (pos < buf.length) 127 | swf.tags ~= readTag(); 128 | } 129 | 130 | void readRaw(void[] raw) 131 | { 132 | raw[] = buf[pos..pos+raw.length]; 133 | pos += raw.length; 134 | } 135 | 136 | /// May read less than len on EOF 137 | void[] readRaw(size_t len) 138 | { 139 | auto end = pos+len; 140 | auto data = buf[pos..end<$?end:$]; 141 | pos = end; 142 | return data; 143 | } 144 | 145 | version(LittleEndian) {} else static assert(0, "Big endian platforms not supported"); 146 | 147 | ushort readU16() 148 | { 149 | ushort r; 150 | readRaw((&r)[0..1]); 151 | return r; 152 | } 153 | 154 | uint readU32() 155 | { 156 | uint r; 157 | readRaw((&r)[0..1]); 158 | return r; 159 | } 160 | 161 | SWFFile.Rect readRect() 162 | { 163 | SWFFile.Rect r; 164 | ubyte b = buf[pos]; 165 | uint nbits = b >> 3; 166 | uint nbytes = ((5 + 4*nbits) + 7) / 8; 167 | r.bytes = cast(ubyte[])readRaw(nbytes); 168 | return r; 169 | } 170 | 171 | SWFFile.Tag readTag() 172 | { 173 | SWFFile.Tag t; 174 | ushort u = readU16(); 175 | t.type = cast(ushort)(u >> 6); 176 | uint length = u & 0x3F; 177 | if (length == 0x3F) 178 | { 179 | length = readU32(); 180 | if (length < 0x3F) 181 | t.forceLongLength = true; 182 | } 183 | t.length = length; 184 | t.data = cast(ubyte[])readRaw(length); 185 | return t; 186 | } 187 | } 188 | 189 | enum TagType 190 | { 191 | End = 0, 192 | ShowFrame = 1, 193 | DefineShape = 2, 194 | FreeCharacter = 3, 195 | PlaceObject = 4, 196 | RemoveObject = 5, 197 | DefineBits = 6, 198 | DefineButton = 7, 199 | JPEGTables = 8, 200 | SetBackgroundColor = 9, 201 | DefineFont = 10, 202 | DefineText = 11, 203 | DoAction = 12, 204 | DefineFontInfo = 13, 205 | DefineSound = 14, 206 | StartSound = 15, 207 | DefineButtonSound = 17, 208 | SoundStreamHead = 18, 209 | SoundStreamBlock = 19, 210 | DefineBitsLossless = 20, 211 | DefineBitsJPEG2 = 21, 212 | DefineShape2 = 22, 213 | DefineButtonCxform = 23, 214 | Protect = 24, 215 | PathsArePostScript = 25, 216 | PlaceObject2 = 26, 217 | RemoveObject2 = 28, 218 | DefineShape3 = 32, 219 | DefineText2 = 33, 220 | DefineButton2 = 34, 221 | DefineBitsJPEG3 = 35, 222 | DefineBitsLossless2 = 36, 223 | DefineSprite = 39, 224 | ProductInfo = 41, 225 | FrameLabel = 43, 226 | SoundStreamHead2 = 45, 227 | DefineMorphShape = 46, 228 | DefineFont2 = 48, 229 | DefineEditText = 37, 230 | ExportAssets = 56, 231 | ImportAssets = 57, 232 | EnableDebugger = 58, 233 | DoInitAction = 59, 234 | DefineVideoStream = 60, 235 | VideoFrame = 61, 236 | DefineFontInfo2 = 62, 237 | DebugID = 63, 238 | EnableDebugger2 = 64, 239 | ScriptLimits = 65, 240 | SetTabIndex = 66, 241 | FileAttributes = 69, 242 | PlaceObject3 = 70, 243 | ImportAssets2 = 71, 244 | DoABC = 72, 245 | DefineFontAlignZones = 73, 246 | CSMTextSettings = 74, 247 | DefineFont3 = 75, 248 | SymbolClass = 76, 249 | Metadata = 77, 250 | DefineScalingGrid = 78, 251 | DoABC2 = 82, 252 | DefineShape4 = 83, 253 | DefineMorphShape2 = 84, 254 | DefineSceneAndFrameLabelData = 86, 255 | DefineBinaryData = 87, 256 | DefineFontName = 88, 257 | DefineFont4 = 91 258 | } 259 | 260 | private final class SWFWriter 261 | { 262 | static ubyte[] write(SWFFile swf) 263 | { 264 | ubyte[] buf; 265 | 266 | buf ~= swf.frameSize.bytes; 267 | buf ~= toArray(swf.frameRate); 268 | buf ~= toArray(swf.frameCount); 269 | 270 | foreach (ref tag; swf.tags) 271 | { 272 | ushort u = cast(ushort)(tag.type << 6); 273 | if (tag.length < 0x3F && !tag.forceLongLength) 274 | { 275 | u |= tag.length; 276 | buf ~= toArray(u); 277 | } 278 | else 279 | { 280 | u |= 0x3F; 281 | buf ~= toArray(u); 282 | uint l = to!uint(tag.length); 283 | buf ~= toArray(l); 284 | } 285 | buf ~= tag.data; 286 | } 287 | 288 | swf.header.fileLength = to!uint(swf.header.sizeof + buf.length); 289 | if (swf.header.signature[0] == 'C') 290 | buf = cast(ubyte[])compress(buf, 9); 291 | else 292 | if (swf.header.signature[0] == 'Z') 293 | { 294 | version (HAVE_LZMA) 295 | { 296 | lzma.LZMAHeader lzInfo; 297 | buf = lzmaCompress(buf, &lzInfo); 298 | 299 | SWFFile.LZMAHeader lzHeader; 300 | lzHeader.compressionParameters = lzInfo.compressionParameters; 301 | lzHeader.dictionarySize = lzInfo.dictionarySize; 302 | lzHeader.compressedLength = to!uint(buf.length); 303 | 304 | buf = cast(ubyte[])(&lzHeader)[0..1] ~ buf; 305 | } 306 | else 307 | enforce(false, "This version was built without LZMA support"); 308 | } 309 | buf = toArray(swf.header) ~ buf; 310 | 311 | return buf; 312 | } 313 | 314 | static ubyte[] toArray(T)(ref T v) 315 | { 316 | return cast(ubyte[])(&v)[0..1]; 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /swflzmacompress.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev 3 | * This file is part of RABCDAsm. 4 | * 5 | * RABCDAsm is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * RABCDAsm is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with RABCDAsm. If not, see . 17 | */ 18 | 19 | module swflzmacompress; 20 | 21 | import std.exception; 22 | import std.file; 23 | import std.getopt; 24 | import std.string; 25 | import swffile; 26 | 27 | void main(string[] args) 28 | { 29 | bool force, updateVersion; 30 | getopt(args, 31 | "--force", &force, 32 | "--update-version", &updateVersion, 33 | ); 34 | 35 | if (args.length == 1) 36 | throw new Exception("No file specified"); 37 | enum MIN_LZMA_VER = 13; 38 | foreach (arg; args[1..$]) 39 | { 40 | auto swf = SWFFile.read(cast(ubyte[])read(arg)); 41 | enforce(swf.header.signature[0] != cast(ubyte)'Z', "Already LZMA-compressed"); 42 | if (swf.header.ver < MIN_LZMA_VER) 43 | { 44 | if (updateVersion) 45 | { 46 | if (swf.header.ver < 8 && !force) 47 | throw new Exception(format( 48 | "SWF version %d has different file format than version %d, " ~ 49 | "required for LZMA. Resulting file may not work. " ~ 50 | "Use --force to override and update version anyway.", 51 | swf.header.ver, MIN_LZMA_VER 52 | )); 53 | swf.header.ver = MIN_LZMA_VER; 54 | } 55 | else 56 | if (!force) 57 | throw new Exception(format( 58 | "SWF version %d is too old to support SWF LZMA compression, " ~ 59 | "which requires version %d. " ~ 60 | "Use --update-version to update the version number, " ~ 61 | "or --force to compress anyway without updating it.", 62 | swf.header.ver, MIN_LZMA_VER 63 | )); 64 | } 65 | swf.header.signature[0] = cast(ubyte)'Z'; // LZMA 66 | write(arg, swf.write()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /zlibx.d: -------------------------------------------------------------------------------- 1 | /// This code is in the public domain. 2 | 3 | module zlibx; 4 | 5 | import core.memory; 6 | import std.string : format; 7 | import std.zlib, etc.c.zlib, std.conv; 8 | static import etc.c.zlib; 9 | alias std.zlib.Z_SYNC_FLUSH Z_SYNC_FLUSH; 10 | debug import std.stdio : stderr; 11 | 12 | /// Avoid bug(?) in D zlib implementation with 7zip-generated zlib streams 13 | ubyte[] exactUncompress(ubyte[] srcbuf, size_t destlen) 14 | { 15 | etc.c.zlib.z_stream zs; 16 | 17 | auto destbuf = new ubyte[destlen]; 18 | uint err; 19 | 20 | zs.next_in = srcbuf.ptr; 21 | zs.avail_in = to!uint(srcbuf.length); 22 | 23 | zs.next_out = destbuf.ptr; 24 | zs.avail_out = to!uint(destbuf.length); 25 | 26 | err = etc.c.zlib.inflateInit2(&zs, 15); 27 | if (err) 28 | { 29 | GC.free(destbuf.ptr); 30 | throw new ZlibException(err); 31 | } 32 | 33 | while (true) 34 | { 35 | err = etc.c.zlib.inflate(&zs, Z_SYNC_FLUSH); 36 | if (err != Z_OK && err != Z_STREAM_END) 37 | { 38 | Lerr: 39 | GC.free(destbuf.ptr); 40 | etc.c.zlib.inflateEnd(&zs); 41 | throw new ZlibException(err); 42 | } 43 | 44 | if (err == Z_STREAM_END) 45 | break; 46 | else 47 | if (zs.avail_out == 0) 48 | { 49 | debug stderr.writefln("Wrong uncompressed file length (read %d/%d bytes and wrote %d/%d bytes)", 50 | srcbuf .length - zs.avail_in , srcbuf .length, 51 | destlen - zs.avail_out, destlen); 52 | auto out_pos = zs.next_out - destbuf.ptr; 53 | destbuf.length = 1024 + destbuf.length * 2; 54 | zs.next_out = destbuf.ptr + out_pos; 55 | zs.avail_out = to!uint(destbuf.length - out_pos); 56 | continue; 57 | } 58 | else 59 | if (zs.avail_in == 0) 60 | { 61 | debug stderr.writefln("Unterminated Zlib stream (read %d/%d bytes and wrote %d/%d bytes)", 62 | srcbuf .length - zs.avail_in , srcbuf .length, 63 | destlen - zs.avail_out, destlen); 64 | break; 65 | } 66 | else 67 | throw new Exception(format("Unexpected zlib state (err=%d, avail_in == %d, avail_out = %d)", 68 | err, zs.avail_in , zs.avail_out)); 69 | } 70 | 71 | if (zs.avail_in != 0 || zs.avail_out != 0) 72 | debug stderr.writefln("Zlib stream incongruity (read %d/%d bytes and wrote %d/%d bytes)", 73 | srcbuf .length - zs.avail_in , srcbuf .length, 74 | destlen - zs.avail_out, destlen); 75 | 76 | err = etc.c.zlib.inflateEnd(&zs); 77 | if (err != Z_OK) 78 | goto Lerr; 79 | 80 | if (zs.avail_out != 0) 81 | debug stderr.writefln("Too little data in zlib stream: expected %d, got %d", destlen, destlen - zs.avail_out); 82 | 83 | return destbuf[0..$-zs.avail_out]; 84 | } 85 | --------------------------------------------------------------------------------