├── 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 |
--------------------------------------------------------------------------------