├── 6502 └── squish.wiz ├── .gitignore ├── d ├── Makefile ├── test.d └── squish.d ├── c ├── Makefile ├── squish.h ├── test.c └── squish.c ├── gbz80 ├── squish.wiz └── squish.asm ├── js ├── index.html └── squish.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.obj 3 | *.o 4 | *.map 5 | *compressed.* -------------------------------------------------------------------------------- /d/Makefile: -------------------------------------------------------------------------------- 1 | DC = dmd 2 | RM = rm 3 | RMFLAGS = -f 4 | 5 | test.exe: squish.d test.d 6 | $(DC) squish.d test.d -oftest 7 | 8 | clean: 9 | $(RM) $(RMFLAGS) test.exe *.o *.obj *.map *compressed.* 10 | -------------------------------------------------------------------------------- /c/Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | RM = rm 3 | RMFLAGS = -f 4 | 5 | test.exe: squish.h squish.c test.c 6 | $(CC) -ansi -pedantic -Wall -Werror squish.c test.c -otest 7 | 8 | clean: 9 | $(RM) $(RMFLAGS) test.exe *.o *.obj *.map *compressed.* 10 | -------------------------------------------------------------------------------- /gbz80/squish.wiz: -------------------------------------------------------------------------------- 1 | package squish do 2 | let SQUISH_LENGTH_MASK = 0x3F 3 | let SQUISH_LENGTH_BITS = 6 4 | let SQUISH_COMMAND_RAW = 0x0 5 | let SQUISH_COMMAND_RLE8 = 0x1 6 | let SQUISH_COMMAND_RLE16 = 0x2 7 | let SQUISH_COMMAND_REF = 0x3 8 | 9 | func unpack do 10 | // Not tested yet, but should be close to real implementation! 11 | // hl = source 12 | // de = dest 13 | loop 14 | c = [hl] via a 15 | c = c >> SQUISH_LENGTH_BITS 16 | b = a & SQUISH_LENGTH_MASK via a 17 | if compare a is zero then 18 | return 19 | end 20 | 21 | a = c 22 | if compare a to SQUISH_COMMAND_RAW is == then 23 | loop 24 | [de] = [hl++] via a 25 | de++ 26 | b-- 27 | until zero end 28 | elseif compare a to SQUISH_COMMAND_RLE8 is == then 29 | loop 30 | [de] = [hl] via a 31 | de++ 32 | b-- 33 | until zero end 34 | hl++ 35 | elseif compare a to SQUISH_COMMAND_RLE16 is == then 36 | loop 37 | [de] = [hl++] via a 38 | de++ 39 | [de] = [hl--] via a 40 | de++ 41 | b-- 42 | until zero end 43 | hl++ 44 | hl++ 45 | elseif compare a to SQUISH_COMMAND_REF is == then 46 | push hl 47 | a = [hl++] 48 | h = [hl] 49 | l = a 50 | 51 | loop 52 | [de] = [hl++] via a 53 | de++ 54 | b-- 55 | until zero end 56 | 57 | pop hl 58 | hl++ 59 | hl++ 60 | end 61 | end 62 | end 63 | end -------------------------------------------------------------------------------- /js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | squish 5 | 6 | 7 | 8 |

squish

9 |

Input:

10 |

Alternatively, get a file

11 |

Statistics:


12 |     

Uncompressed:


13 |     

Compressed:


14 |     

Decompressed:


15 |     
64 | 
65 | 


--------------------------------------------------------------------------------
/d/test.d:
--------------------------------------------------------------------------------
 1 | // Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack)
 2 | // All rights reserved.
 3 | //
 4 | // Redistribution and use in source and binary forms, with or without
 5 | // modification, are permitted provided that the following conditions are met:
 6 | //
 7 | // 1. Redistributions of source code must retain the above copyright
 8 | //    notice, this list of conditions and the following disclaimer.
 9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | //    notice, this list of conditions and the following disclaimer in the
11 | //    documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of squish nor the names of its contributors may be
13 | //    used to endorse or promote products derived from this software without
14 | //    specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | // DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | 
27 | static import std.stdio;
28 | static import squish;
29 | 
30 | void main()
31 | {
32 |     ubyte[] src;
33 |     ubyte[] compressed;
34 |     ubyte[] decompressed;
35 | 
36 |     auto f = std.stdio.File("squish.d", "rb");
37 |     f.seek(0, std.stdio.SEEK_END);
38 |     decompressed.length = compressed.length = src.length = cast(typeof(src.length)) f.tell();
39 |     f.seek(0, std.stdio.SEEK_SET);
40 |     f.rawRead(src);
41 | 
42 |     compressed.length = squish.pack(src, compressed);
43 |     f = std.stdio.File("squish.compressed.d", "wb");
44 |     f.rawWrite(compressed);
45 | 
46 |     decompressed.length = squish.unpack(compressed, decompressed);
47 |     f = std.stdio.File("squish.decompressed.d", "wb");
48 |     f.rawWrite(decompressed);
49 | 
50 |     std.stdio.writefln("src: %s byte(s)", src.length);
51 |     std.stdio.writefln("compressed: %s byte(s)", compressed.length);
52 |     std.stdio.writefln("ratio: %s%% of original size", compressed.length * 100 / src.length);
53 |     std.stdio.writefln("decompressed: %s byte(s)", decompressed.length);
54 | }


--------------------------------------------------------------------------------
/c/squish.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack)
 3 |  * All rights reserved.
 4 |  *
 5 |  * Redistribution and use in source and binary forms, with or without
 6 |  * modification, are permitted provided that the following conditions are met:
 7 |  *
 8 |  * 1. Redistributions of source code must retain the above copyright
 9 |  *    notice, this list of conditions and the following disclaimer.
10 |  * 2. Redistributions in binary form must reproduce the above copyright
11 |  *    notice, this list of conditions and the following disclaimer in the
12 |  *    documentation and/or other materials provided with the distribution.
13 |  * 3. Neither the name of squish nor the names of its contributors may be
14 |  *    used to endorse or promote products derived from this software without
15 |  *    specific prior written permission.
16 |  *
17 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 |  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 |  * DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY
21 |  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 |  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 |  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 |  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 |  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |  */
28 | 
29 | #ifndef SQUISH_H
30 | #define SQUISH_H
31 | 
32 | #include 
33 | #include 
34 | 
35 | /*
36 |  * Pack raw source data into the given destination buffer.
37 |  *
38 |  * Arguments:
39 |  *      src - pointer to source buffer.
40 |  *      src_length - size of the source buffer.
41 |  *      dest - pointer to destination buffer.
42 |  *      dest_length - size of the destination buffer.
43 |  * Return:
44 |  *      On success, returns the length of the compressed buffer.
45 |  *      On failure, returns 0.
46 |  */
47 | size_t squish_pack(const uint8_t *src, size_t src_length, uint8_t *dest, size_t dest_length);
48 | 
49 | /*
50 |  * Unpack previously packed source data into the given destination buffer.
51 |  * Arguments:
52 |  *      src - pointer to source buffer.
53 |  *      src_length - size of the source buffer.
54 |  *      dest - pointer to destination buffer.
55 |  *      dest_length - size of the destination buffer.
56 |  * Return:
57 |  *      On success, returns the length of the decompressed buffer.
58 |  *      On failure, returns 0.
59 |  */
60 | size_t squish_unpack(const uint8_t *src, size_t src_length, uint8_t *dest, size_t dest_length);
61 | 
62 | #endif
63 | 


--------------------------------------------------------------------------------
/6502/squish.wiz:
--------------------------------------------------------------------------------
 1 | package squish do
 2 |     let SQUISH_LENGTH_MASK = 0x3F
 3 |     let SQUISH_LENGTH_BITS = 6
 4 |     let SQUISH_COMMAND_RAW = 0x0
 5 |     let SQUISH_COMMAND_RLE8 = 0x1
 6 |     let SQUISH_COMMAND_RLE16 = 0x2
 7 |     let SQUISH_COMMAND_REF = 0x3
 8 | 
 9 |     func unpack do
10 |         // Not tested yet, but should be close to real implementation!
11 |         // Arguments:
12 |         // [0], [1] = 16-bit src pointer
13 |         // [2], [3] = 16-bit dest pointer
14 |         // Locals:
15 |         // [4], [5] = temporary 16-bit backref pointer.
16 |         let src = 0
17 |         let dest = 2
18 |         let ref = 4
19 | 
20 |         y = 0
21 |         loop
22 |             x = [[src]:y] & SQUISH_LENGTH_MASK via a
23 |             if is zero then
24 |                 return
25 |             end
26 | 
27 |             a = [[src]:y] >> SQUISH_LENGTH_BITS
28 |             if compare a to SQUISH_COMMAND_RAW is == then
29 |                 [src]++ if zero then [src + 1]++ end
30 |                 loop
31 |                     [[dest]:y] = [[src]:y] via a
32 |                     [src]++ if zero then [src + 1]++ end
33 |                     [dest]++ if zero then [dest + 1]++ end
34 |                     x--
35 |                 until zero end
36 |             elseif compare a to SQUISH_COMMAND_RLE8 is == then
37 |                 [src]++ if zero then [src + 1]++ end
38 |                 loop
39 |                     [[dest]:y] = [[src]:y] via a
40 |                     [dest]++ if zero then [dest + 1]++ end
41 |                     x--
42 |                 until zero end
43 |                 [src]++ if zero then [src + 1]++ end
44 |             elseif compare a to SQUISH_COMMAND_RLE16 is == then
45 |                 [src]++ if zero then [src + 1]++ end
46 |                 loop
47 |                     [[dest]:y] = [[src]:y] via a
48 |                     [dest]++ if zero then [dest + 1]++ end
49 |                     y++
50 |                     a = [[src]:y]
51 |                     y--
52 |                     [[dest]:y] = a
53 |                     [dest]++ if zero then [dest + 1]++ end
54 |                     x--
55 |                 until zero end
56 |                 [src]++ if zero then [src + 1]++ end
57 |                 [src]++ if zero then [src + 1]++ end
58 |             elseif compare a to SQUISH_COMMAND_REF is == then
59 |                 [src]++ if zero then [src + 1]++ end
60 |                 [ref] = [[src]:y] via a
61 |                 [src]++ if zero then [src + 1]++ end
62 |                 [ref + 1] = [[src]:y] via a
63 |                 [src]++ if zero then [src + 1]++ end
64 |                 loop
65 |                     [[dest]:y] = [[ref]:y] via a
66 |                     [ref]++ if zero then [ref + 1]++ end
67 |                     [dest]++ if zero then [dest + 1]++ end
68 |                     x--
69 |                 until zero end
70 |             end
71 |         end
72 |     end
73 | end


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | squish
 2 | ======
 3 | **by Andrew G. Crowell (Overkill / Bananattack)**
 4 | 
 5 | A simple lossless data compression library with very low memory footprint.
 6 | 
 7 | * Compress files of up to 64K. (Designed with embedded systems with 16-bit address space in mind.)
 8 | * Libraries for C, D, JavaScript, 6502 and GBZ80.
 9 | * Mixes simplistic compression algorithms that require very little intermediate state during decompression.
10 | 
11 | Specification
12 | -------------
13 | 
14 | * The **squish** compression format is a stream containing 0 or more sequences of the following data:  
15 |   ```
``` 16 | * Each *header* is an 8-bit byte that contains a 6-bit *length* component and a 2-bit *command* component: 17 | ```
= (( & 3) << 6) | ( & 0x3F)``` 18 | * The *payload* format is determined by the *command* in the header: 19 | * `raw = 0` - Sequence of uncompressed bytes of indicated *length*. 20 | * `rle8 = 1` - Single byte, to be unpacked *length* times. 21 | * `rle16 = 2` - Two-byte pattern, to be unpacked *length* times. 22 | * `ref = 3` - Reference to data earlier in the unpacked stream, a two-byte value specifying an offset in bytes from the beginning of the stream. The amount of bytes being referenced is of the indicated *length*. 23 | * A header byte that has a *length* of zero is considered an end-of-file marker. 24 | 25 | License 26 | ------- 27 | 28 | 29 | Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack) 30 | All rights reserved. 31 | 32 | Redistribution and use in source and binary forms, with or without 33 | modification, are permitted provided that the following conditions are met: 34 | 35 | 1. Redistributions of source code must retain the above copyright 36 | notice, this list of conditions and the following disclaimer. 37 | 2. Redistributions in binary form must reproduce the above copyright 38 | notice, this list of conditions and the following disclaimer in the 39 | documentation and/or other materials provided with the distribution. 40 | 3. Neither the name of squish nor the names of its contributors may be 41 | used to endorse or promote products derived from this software without 42 | specific prior written permission. 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 45 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 46 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 47 | DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY 48 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 49 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 50 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 51 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 53 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | 55 | -------------------------------------------------------------------------------- /c/test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of squish nor the names of its contributors may be 14 | * used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY 21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include 30 | #include 31 | #include "squish.h" 32 | 33 | int main(int argc, char **argv) { 34 | uint8_t* src; 35 | uint8_t* compressed; 36 | uint8_t* decompressed; 37 | size_t src_size; 38 | size_t compressed_size; 39 | size_t decompressed_size; 40 | 41 | FILE* f; 42 | 43 | f = fopen("squish.c", "rb"); 44 | if(!f) { 45 | fputs("failed to open", stderr); 46 | return 1; 47 | } 48 | 49 | fseek(f, 0, SEEK_END); 50 | src_size = ftell(f); 51 | fseek(f, 0, SEEK_SET); 52 | 53 | src = malloc(src_size); 54 | compressed = malloc(src_size); 55 | decompressed = malloc(src_size); 56 | if(!src || !compressed || !decompressed) { 57 | fputs("failed to allocate buffer memory", stderr); 58 | return 1; 59 | } 60 | fread(src, 1, src_size, f); 61 | fclose(f); 62 | 63 | compressed_size = squish_pack(src, src_size, compressed, src_size); 64 | f = fopen("squish.compressed.c", "wb"); 65 | if(!f) { 66 | fputs("failed to open compressed file for writing", stderr); 67 | return 1; 68 | } 69 | fwrite(compressed, 1, compressed_size, f); 70 | fclose(f); 71 | 72 | decompressed_size = squish_unpack(compressed, compressed_size, decompressed, src_size); 73 | f = fopen("squish.decompressed.c", "wb"); 74 | if(!f) { 75 | fputs("failed to open decompressed file for writing", stderr); 76 | return 1; 77 | } 78 | fwrite(decompressed, 1, decompressed_size, f); 79 | fclose(f); 80 | 81 | printf("src: %u byte(s)\n", (uint32_t) src_size); 82 | printf("compressed: %u byte(s)\n", (uint32_t) compressed_size); 83 | printf("ratio: %u%% of original size\n\n", (uint32_t) (compressed_size * 100 / src_size)); 84 | printf("decompressed: %u byte(s)\n", (uint32_t) decompressed_size); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /gbz80/squish.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack) 2 | ; All rights reserved. 3 | ; 4 | ; Redistribution and use in source and binary forms, with or without 5 | ; modification, are permitted provided that the following conditions are met: 6 | ; 7 | ; 1. Redistributions of source code must retain the above copyright 8 | ; notice, this list of conditions and the following disclaimer. 9 | ; 2. Redistributions in binary form must reproduce the above copyright 10 | ; notice, this list of conditions and the following disclaimer in the 11 | ; documentation and/or other materials provided with the distribution. 12 | ; 3. Neither the name of squish nor the names of its contributors may be 13 | ; used to endorse or promote products derived from this software without 14 | ; specific prior written permission. 15 | ; 16 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | ; DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY 20 | ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | SQUISH_LENGTH_MASK EQU $3F 28 | SQUISH_LENGTH_BITS EQU 6 29 | SQUISH_COMMAND_RAW EQU $0 30 | SQUISH_COMMAND_RLE8 EQU $1 31 | SQUISH_COMMAND_RLE16 EQU $2 32 | SQUISH_COMMAND_REF EQU $3 33 | 34 | ; Unpack previously packed source data at [hl] into the given destination buffer at [de]. 35 | ; Arguments: 36 | ; hl = source 37 | ; de = dest 38 | squish_unpack: 39 | ; Read header. 40 | ld a, [hl] 41 | 42 | ; extract command bits in c. 43 | ld c, a 44 | REPT SQUISH_LENGTH_BITS 45 | srl c 46 | ENDR 47 | 48 | ; length = 0 indicates EOF. 49 | and a, SQUISH_LENGTH_MASK 50 | or a, a 51 | ret z 52 | 53 | ; b = length 54 | ; a = command 55 | ld b, a 56 | ld a, c 57 | ; Is this a raw chunk of binary data? 58 | .check_raw: 59 | cp a, SQUISH_COMMAND_RAW 60 | ; If not, skip. 61 | jr nz, .check_rle8 62 | .raw_loop: 63 | ld a, [hl+] 64 | ld [de], a 65 | inc de 66 | dec b 67 | jr nz, .raw_loop 68 | 69 | jr squish_unpack 70 | 71 | ; Is this an 8-bit RLE value? 72 | .check_rle8: 73 | cp a, SQUISH_COMMAND_RLE8 74 | ; If not, skip. 75 | jr nz, .check_rle16 76 | .rle8_loop: 77 | ld a, [hl] 78 | ld [de], a 79 | inc de 80 | dec b 81 | jr nz, .rle8_loop 82 | 83 | inc hl 84 | jr squish_unpack 85 | 86 | ; Is this a 16-bit RLE value? 87 | .check_rle16: 88 | cp a, SQUISH_COMMAND_RLE16 89 | ; If not, skip. 90 | jr nz, .handle_ref 91 | .rle16_loop: 92 | ld a, [hl+] 93 | ld [de], a 94 | inc de 95 | ld a, [hl-] 96 | ld [de], a 97 | inc de 98 | dec b 99 | jr nz, .rle16_loop 100 | 101 | inc hl 102 | inc hl 103 | jr squish_unpack 104 | 105 | ; This is an LZ77-style backref. 106 | .handle_ref: 107 | push hl 108 | ld a, [hl+] 109 | ld h, [hl] 110 | ld l, a 111 | .ref_loop: 112 | ld a, [hl+] 113 | ld [de], a 114 | inc de 115 | dec b 116 | jr nz, .ref_loop 117 | 118 | pop hl 119 | inc hl 120 | inc hl 121 | jr squish_unpack 122 | 123 | -------------------------------------------------------------------------------- /js/squish.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack) 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 2. Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // 3. Neither the name of squish nor the names of its contributors may be 13 | // used to endorse or promote products derived from this software without 14 | // specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY 20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | var squish = (function(lib) { 28 | var SQUISH_LENGTH_MASK = 0x3F; 29 | var SQUISH_LENGTH_BITS = 6; 30 | var SQUISH_COMMAND_RAW = 0x0; 31 | var SQUISH_COMMAND_RLE8 = 0x1; 32 | var SQUISH_COMMAND_RLE16 = 0x2; 33 | var SQUISH_COMMAND_REF = 0x3; 34 | 35 | function flush_raw(raw, dest) { 36 | if(raw.length > 0) { 37 | dest.push(raw.length | (SQUISH_COMMAND_RAW << SQUISH_LENGTH_BITS)); 38 | for(var i = 0; i < raw.length; i++) { 39 | dest.push(raw[i]); 40 | } 41 | raw.length = 0; 42 | } 43 | } 44 | 45 | lib.pack = function(src) { 46 | var dest = []; 47 | var raw = []; 48 | 49 | var input_position = 0; 50 | while(input_position < src.length) { 51 | var rle8_length = 0; 52 | var j = 0; 53 | while(input_position + j < src.length 54 | && j < SQUISH_LENGTH_MASK 55 | && src[input_position + j] == src[input_position]) { 56 | rle8_length++; 57 | j++; 58 | } 59 | 60 | var rle16_length = 0; 61 | j = 0; 62 | while(input_position + j + 1 < src.length 63 | && j < SQUISH_LENGTH_MASK 64 | && src[input_position + j] == src[input_position] 65 | && src[input_position + j + 1] == src[input_position + 1]) { 66 | rle16_length++; 67 | j += 2; 68 | } 69 | 70 | var ref_index = 0; 71 | var ref_length = 0; 72 | for(var i = 0; i < input_position; ++i) { 73 | j = 0; 74 | while(i + j < input_position 75 | && input_position + j < src.length 76 | && j < SQUISH_LENGTH_MASK 77 | && src[i + j] == src[input_position + j]) { 78 | j++; 79 | } 80 | if(j > ref_length) { 81 | ref_index = i; 82 | ref_length = j; 83 | } 84 | } 85 | 86 | if(ref_length > 2 && ref_length > rle16_length && ref_length > rle8_length) { 87 | flush_raw(raw, dest); 88 | dest.push((ref_length | (SQUISH_COMMAND_REF << SQUISH_LENGTH_BITS)) & 0xFF); 89 | dest.push((ref_index >> 8) & 0xFF); 90 | dest.push(ref_index & 0xFF); 91 | 92 | input_position += ref_length; 93 | } else if(rle16_length > 2) { 94 | flush_raw(raw, dest); 95 | dest.push((rle16_length | (SQUISH_COMMAND_RLE16 << SQUISH_LENGTH_BITS)) & 0xFF); 96 | dest.push(src[input_position] & 0xFF); 97 | dest.push(src[input_position + 1] & 0xFF); 98 | 99 | input_position += rle16_length * 2; 100 | } else if(rle8_length > 1) { 101 | flush_raw(raw, dest); 102 | dest.push((rle8_length | (SQUISH_COMMAND_RLE8 << SQUISH_LENGTH_BITS)) & 0xFF); 103 | dest.push(src[input_position] & 0xFF); 104 | 105 | input_position += rle8_length; 106 | } else { 107 | raw.push(src[input_position++] & 0xFF); 108 | if(raw.length == SQUISH_LENGTH_MASK) { 109 | flush_raw(raw, dest); 110 | } 111 | } 112 | } 113 | flush_raw(raw, dest); 114 | dest.push(0); 115 | 116 | return dest; 117 | } 118 | 119 | lib.unpack = function(src) { 120 | var dest = []; 121 | var input_position = 0; 122 | 123 | while(input_position < src.length) { 124 | var length = src[input_position] & SQUISH_LENGTH_MASK; 125 | var command = (src[input_position++] & 0xFF) >> SQUISH_LENGTH_BITS; 126 | 127 | if(length == 0) { 128 | return dest; 129 | } 130 | switch(command) { 131 | case SQUISH_COMMAND_RAW: 132 | for(var i = 0; i < length; i++) { 133 | dest.push(src[input_position++] & 0xFF); 134 | } 135 | break; 136 | case SQUISH_COMMAND_RLE8: 137 | for(var i = 0; i < length; i++) { 138 | dest.push(src[input_position] & 0xFF); 139 | } 140 | input_position++; 141 | break; 142 | case SQUISH_COMMAND_RLE16: 143 | for(var i = 0; i < length; i++) { 144 | dest.push(src[input_position] & 0xFF); 145 | dest.push(src[input_position + 1] & 0xFF); 146 | } 147 | input_position += 2; 148 | break; 149 | case SQUISH_COMMAND_REF: 150 | var offset = (src[input_position] & 0xFF) << 8 | (src[input_position + 1] & 0xFF); 151 | for(var i = 0; i < length; i++) { 152 | dest.push(dest[offset + i] & 0xFF); 153 | } 154 | input_position += 2; 155 | break; 156 | default: throw new Error("unhandled command type"); 157 | } 158 | } 159 | return dest; 160 | } 161 | 162 | 163 | return lib; 164 | })({}); -------------------------------------------------------------------------------- /c/squish.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of squish nor the names of its contributors may be 14 | * used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY 21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "squish.h" 30 | 31 | enum { 32 | SQUISH_LENGTH_MASK = 0x3F, 33 | SQUISH_LENGTH_BITS = 6, 34 | SQUISH_COMMAND_RAW = 0x0, 35 | SQUISH_COMMAND_RLE8 = 0x1, 36 | SQUISH_COMMAND_RLE16 = 0x2, 37 | SQUISH_COMMAND_REF = 0x3 38 | }; 39 | 40 | static char flush_raw(const uint8_t *raw, size_t *raw_length, size_t *output_position, uint8_t *dest, size_t dest_length) { 41 | size_t i; 42 | size_t p = *output_position; 43 | size_t rl = *raw_length; 44 | if(rl > 0) { 45 | if(p + 1 + rl > dest_length) { 46 | return 0; 47 | } 48 | 49 | dest[p++] = rl | (SQUISH_COMMAND_RAW << SQUISH_LENGTH_BITS); 50 | for(i = 0; i < rl; i++) { 51 | dest[p++] = raw[i]; 52 | } 53 | 54 | *output_position = p; 55 | *raw_length = 0; 56 | } 57 | return 1; 58 | } 59 | 60 | size_t squish_pack(const uint8_t *src, size_t src_length, uint8_t *dest, size_t dest_length) { 61 | size_t i, j; 62 | size_t input_position; 63 | size_t output_position; 64 | size_t ref_index; 65 | size_t ref_length; 66 | size_t rle8_length; 67 | size_t rle16_length; 68 | 69 | uint8_t raw[SQUISH_LENGTH_MASK]; 70 | size_t raw_length = 0; 71 | 72 | input_position = 0; 73 | output_position = 0; 74 | while(input_position < src_length) { 75 | rle8_length = 0; 76 | j = 0; 77 | while(input_position + j < src_length 78 | && j < SQUISH_LENGTH_MASK 79 | && src[input_position + j] == src[input_position]) { 80 | rle8_length++; 81 | j++; 82 | } 83 | 84 | rle16_length = 0; 85 | j = 0; 86 | while(input_position + j + 1 < src_length 87 | && j < SQUISH_LENGTH_MASK 88 | && src[input_position + j] == src[input_position] 89 | && src[input_position + j + 1] == src[input_position + 1]) { 90 | rle16_length++; 91 | j += 2; 92 | } 93 | 94 | ref_index = 0; 95 | ref_length = 0; 96 | for(i = 0; i < input_position; ++i) { 97 | j = 0; 98 | while(i + j < input_position 99 | && input_position + j < src_length 100 | && j < SQUISH_LENGTH_MASK 101 | && src[i + j] == src[input_position + j]) { 102 | j++; 103 | } 104 | if(j > ref_length) { 105 | ref_index = i; 106 | ref_length = j; 107 | } 108 | } 109 | 110 | if(ref_length > 2 && ref_length > rle16_length && ref_length > rle8_length) { 111 | if(!flush_raw(raw, &raw_length, &output_position, dest, dest_length)) { 112 | return 0; 113 | } 114 | if(output_position + 3 > dest_length) { 115 | return 0; 116 | } 117 | dest[output_position++] = ref_length | (SQUISH_COMMAND_REF << SQUISH_LENGTH_BITS); 118 | dest[output_position++] = ref_index >> 8; 119 | dest[output_position++] = ref_index & 0xFF; 120 | 121 | input_position += ref_length; 122 | } else if(rle16_length > 2) { 123 | if(!flush_raw(raw, &raw_length, &output_position, dest, dest_length)) { 124 | return 0; 125 | } 126 | if(output_position + 3 > dest_length) { 127 | return 0; 128 | } 129 | 130 | dest[output_position++] = rle16_length | (SQUISH_COMMAND_RLE16 << SQUISH_LENGTH_BITS); 131 | dest[output_position++] = src[input_position]; 132 | dest[output_position++] = src[input_position + 1]; 133 | 134 | input_position += rle16_length * 2; 135 | } else if(rle8_length > 1) { 136 | if(!flush_raw(raw, &raw_length, &output_position, dest, dest_length)) { 137 | return 0; 138 | } 139 | if(output_position + 2 > dest_length) { 140 | return 0; 141 | } 142 | 143 | dest[output_position++] = rle8_length | (SQUISH_COMMAND_RLE8 << SQUISH_LENGTH_BITS); 144 | dest[output_position++] = src[input_position]; 145 | 146 | input_position += rle8_length; 147 | } else { 148 | raw[raw_length++] = src[input_position++]; 149 | if(raw_length == SQUISH_LENGTH_MASK) { 150 | if(!flush_raw(raw, &raw_length, &output_position, dest, dest_length)) { 151 | return 0; 152 | } 153 | } 154 | } 155 | } 156 | if(!flush_raw(raw, &raw_length, &output_position, dest, dest_length)) { 157 | return 0; 158 | } 159 | if(output_position + 1 > dest_length) { 160 | return 0; 161 | } 162 | dest[output_position++] = 0; 163 | 164 | return output_position; 165 | } 166 | 167 | size_t squish_unpack(const uint8_t *src, size_t src_length, uint8_t *dest, size_t dest_length) { 168 | size_t i; 169 | size_t ref; 170 | size_t length; 171 | uint8_t command; 172 | 173 | size_t input_position; 174 | size_t output_position; 175 | 176 | 177 | input_position = 0; 178 | output_position = 0; 179 | while(input_position < src_length) { 180 | length = src[input_position] & SQUISH_LENGTH_MASK; 181 | command = src[input_position++] >> SQUISH_LENGTH_BITS; 182 | 183 | if(length == 0) { 184 | return output_position; 185 | } 186 | switch(command) { 187 | case SQUISH_COMMAND_RAW: 188 | if(output_position + length > dest_length) { 189 | return 0; 190 | } 191 | for(i = 0; i < length; i++) { 192 | dest[output_position++] = src[input_position++]; 193 | } 194 | break; 195 | case SQUISH_COMMAND_RLE8: 196 | if(output_position + length > dest_length) { 197 | return 0; 198 | } 199 | for(i = 0; i < length; i++) { 200 | dest[output_position++] = src[input_position]; 201 | } 202 | input_position++; 203 | break; 204 | case SQUISH_COMMAND_RLE16: 205 | if(output_position + length * 2 > dest_length) { 206 | return 0; 207 | } 208 | for(i = 0; i < length; i++) { 209 | dest[output_position++] = src[input_position]; 210 | dest[output_position++] = src[input_position + 1]; 211 | } 212 | input_position += 2; 213 | break; 214 | case SQUISH_COMMAND_REF: 215 | if(output_position + length > dest_length) { 216 | return 0; 217 | } 218 | ref = src[input_position] << 8 | src[input_position + 1]; 219 | for(i = 0; i < length; i++) { 220 | dest[output_position++] = dest[ref + i]; 221 | } 222 | input_position += 2; 223 | break; 224 | } 225 | } 226 | return output_position; 227 | } 228 | 229 | 230 | -------------------------------------------------------------------------------- /d/squish.d: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Andrew G. Crowell (Overkill / Bananattack) 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 2. Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // 3. Neither the name of squish nor the names of its contributors may be 13 | // used to endorse or promote products derived from this software without 14 | // specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL SQUISH CONTRIBUTORS BE LIABLE FOR ANY 20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | private enum SQUISH_LENGTH_MASK = 0x3F; 28 | private enum SQUISH_LENGTH_BITS = 6; 29 | private enum SQUISH_COMMAND_RAW = 0x0; 30 | private enum SQUISH_COMMAND_RLE8 = 0x1; 31 | private enum SQUISH_COMMAND_RLE16 = 0x2; 32 | private enum SQUISH_COMMAND_REF = 0x3; 33 | 34 | private bool flush_raw(in ubyte[] raw, ref size_t raw_length, ref size_t output_position, ubyte[] dest) 35 | { 36 | if(raw_length > 0) 37 | { 38 | if(output_position + 1 + raw_length > dest.length) 39 | { 40 | return false; 41 | } 42 | 43 | dest[output_position++] = cast(ubyte) (raw_length | (SQUISH_COMMAND_RAW << SQUISH_LENGTH_BITS)); 44 | for(size_t i = 0; i < raw_length; i++) 45 | { 46 | dest[output_position++] = raw[i]; 47 | } 48 | raw_length = 0; 49 | } 50 | return true; 51 | } 52 | 53 | size_t pack(in ubyte[] src, ubyte[] dest) 54 | { 55 | ubyte[SQUISH_LENGTH_MASK] raw; 56 | size_t raw_length = 0; 57 | 58 | size_t input_position = 0; 59 | size_t output_position = 0; 60 | while(input_position < src.length) 61 | { 62 | size_t rle8_length = 0; 63 | size_t j = 0; 64 | while(input_position + j < src.length 65 | && j < SQUISH_LENGTH_MASK 66 | && src[input_position + j] == src[input_position]) 67 | { 68 | rle8_length++; 69 | j++; 70 | } 71 | 72 | size_t rle16_length = 0; 73 | j = 0; 74 | while(input_position + j + 1 < src.length 75 | && j < SQUISH_LENGTH_MASK 76 | && src[input_position + j] == src[input_position] 77 | && src[input_position + j + 1] == src[input_position + 1]) 78 | { 79 | rle16_length++; 80 | j += 2; 81 | } 82 | 83 | size_t ref_index = 0; 84 | size_t ref_length = 0; 85 | for(size_t i = 0; i < input_position; ++i) 86 | { 87 | j = 0; 88 | while(i + j < input_position 89 | && input_position + j < src.length 90 | && j < SQUISH_LENGTH_MASK 91 | && src[i + j] == src[input_position + j]) 92 | { 93 | j++; 94 | } 95 | if(j > ref_length) 96 | { 97 | ref_index = i; 98 | ref_length = j; 99 | } 100 | } 101 | 102 | if(ref_length > 2 && ref_length > rle16_length && ref_length > rle8_length) 103 | { 104 | if(!flush_raw(raw, raw_length, output_position, dest)) 105 | { 106 | return 0; 107 | } 108 | if(output_position + 3 > dest.length) 109 | { 110 | return 0; 111 | } 112 | dest[output_position++] = cast(ubyte) (ref_length | (SQUISH_COMMAND_REF << SQUISH_LENGTH_BITS)); 113 | dest[output_position++] = cast(ubyte) (ref_index >> 8); 114 | dest[output_position++] = ref_index & 0xFF; 115 | 116 | input_position += ref_length; 117 | } 118 | else if(rle16_length > 2) 119 | { 120 | if(!flush_raw(raw, raw_length, output_position, dest)) 121 | { 122 | return 0; 123 | } 124 | if(output_position + 3 > dest.length) 125 | { 126 | return 0; 127 | } 128 | 129 | dest[output_position++] = cast(ubyte) (rle16_length | (SQUISH_COMMAND_RLE16 << SQUISH_LENGTH_BITS)); 130 | dest[output_position++] = src[input_position]; 131 | dest[output_position++] = src[input_position + 1]; 132 | 133 | input_position += rle16_length * 2; 134 | } 135 | else if(rle8_length > 1) 136 | { 137 | if(!flush_raw(raw, raw_length, output_position, dest)) 138 | { 139 | return 0; 140 | } 141 | if(output_position + 2 > dest.length) 142 | { 143 | return 0; 144 | } 145 | 146 | dest[output_position++] = cast(ubyte) (rle8_length | (SQUISH_COMMAND_RLE8 << SQUISH_LENGTH_BITS)); 147 | dest[output_position++] = src[input_position]; 148 | 149 | input_position += rle8_length; 150 | } 151 | else 152 | { 153 | raw[raw_length++] = src[input_position++]; 154 | if(raw_length == SQUISH_LENGTH_MASK) 155 | { 156 | if(!flush_raw(raw, raw_length, output_position, dest)) 157 | { 158 | return 0; 159 | } 160 | } 161 | } 162 | } 163 | if(!flush_raw(raw, raw_length, output_position, dest)) 164 | { 165 | return 0; 166 | } 167 | if(output_position + 1 > dest.length) 168 | { 169 | return 0; 170 | } 171 | dest[output_position++] = 0; 172 | 173 | return output_position; 174 | } 175 | 176 | size_t unpack(in ubyte[] src, ubyte[] dest) 177 | { 178 | size_t input_position = 0; 179 | size_t output_position = 0; 180 | 181 | while(input_position < src.length) 182 | { 183 | size_t length = src[input_position] & SQUISH_LENGTH_MASK; 184 | ubyte command = src[input_position++] >> SQUISH_LENGTH_BITS; 185 | 186 | if(length == 0) 187 | { 188 | return output_position; 189 | } 190 | switch(command) 191 | { 192 | case SQUISH_COMMAND_RAW: 193 | if(output_position + length > dest.length) 194 | { 195 | return 0; 196 | } 197 | for(size_t i = 0; i < length; i++) 198 | { 199 | dest[output_position++] = src[input_position++]; 200 | } 201 | break; 202 | case SQUISH_COMMAND_RLE8: 203 | if(output_position + length > dest.length) 204 | { 205 | return 0; 206 | } 207 | for(size_t i = 0; i < length; i++) 208 | { 209 | dest[output_position++] = src[input_position]; 210 | } 211 | input_position++; 212 | break; 213 | case SQUISH_COMMAND_RLE16: 214 | if(output_position + length * 2 > dest.length) 215 | { 216 | return 0; 217 | } 218 | for(size_t i = 0; i < length; i++) 219 | { 220 | dest[output_position++] = src[input_position]; 221 | dest[output_position++] = src[input_position + 1]; 222 | } 223 | input_position += 2; 224 | break; 225 | case SQUISH_COMMAND_REF: 226 | if(output_position + length > dest.length) 227 | { 228 | return 0; 229 | } 230 | size_t offset = src[input_position] << 8 | src[input_position + 1]; 231 | for(size_t i = 0; i < length; i++) 232 | { 233 | dest[output_position++] = dest[offset + i]; 234 | } 235 | input_position += 2; 236 | break; 237 | default: assert(0); 238 | } 239 | } 240 | return output_position; 241 | } 242 | 243 | 244 | --------------------------------------------------------------------------------