├── README.md
├── pithy.c
└── pithy.h
/README.md:
--------------------------------------------------------------------------------
1 | # pithy
2 |
3 | pithy is licensed under the terms of the BSD license.
4 | Copyright © 2011, John Engelhart.
5 |
6 | ### Notes
7 |
8 | pithys roots can be traced back to Googles [snappy][] compression library, but has diverged quite a bit.
9 |
10 | pithy can not read or write the [snappy][] compression format, and vice versa.
11 |
12 | ### TODO
13 |
14 | Write the `README.md` :).
15 |
16 | ### Benchmarks
17 |
18 | - Benchmarks were performed on an iPhone 4 (not S) and compiled with `clang` version 3.0 using `-Os`.
19 | - Compression and decompression speed numbers are in megabytes per second.
20 | - The files used are from the [snappy][] distributions test suite.
21 | - `zlib 1` and `zlib 6` correspond to the `zlib` tunable compression effort, with `1` being fastest, and `6` being the default.
22 | - `pithy 0` and `pithy 2` correspond to the `pithy` tunable compression effort.
23 |
24 | #### Size
25 |
26 | Name | Uncompressed | pithy 0 | pithy 2 | snappy | lzf | lzo | zlib 1 | zlib 6
27 | ---------------------|-------------:|--------:|--------:|-------:|-------:|-------:|--------:|-------:
28 | alice29.txt | 152089 | 93270 | 87767 | 90965 | 82985 | 83568 | 65148 | 54416
29 | asyoulik.txt | 125179 | 83039 | 78170 | 80207 | 72081 | 73849 | 56809 | 48909
30 | baddata1.snappy | 27512 | 27521 | 27521 | 26675 | 26228 | 26491 | 23151 | 22953
31 | baddata2.snappy | 27483 | 27495 | 27495 | 26724 | 26272 | 26531 | 23214 | 23035
32 | baddata3.snappy | 28384 | 28346 | 28346 | 27476 | 27105 | 27388 | 23927 | 23730
33 | cp.html | 24603 | 12398 | 11990 | 11838 | 11869 | 11677 | 9046 | 7973
34 | fields.c | 11150 | 4960 | 4790 | 4728 | 4667 | 4680 | 3665 | 3134
35 | geo.protodata | 118588 | 19984 | 19524 | 27459 | 27748 | 20170 | 18845 | 15143
36 | grammar.lsp | 3721 | 1859 | 1839 | 1800 | 1768 | 1783 | 1344 | 1234
37 | house.jpg | 126958 | 126846 | 126843 | 126803 | 130003 | 127169 | 126488 | 126525
38 | html | 102400 | 21725 | 21077 | 24140 | 22534 | 21059 | 17049 | 13711
39 | html_x_4 | 409600 | 21753 | 21105 | 96472 | 89962 | 82730 | 67470 | 53379
40 | kennedy.xls | 1029744 | 427736 | 425992 | 425735 | 402525 | 359590 | 242311 | 204004
41 | kppkn.gtb | 184320 | 73768 | 68287 | 70535 | 75486 | 72623 | 49877 | 38763
42 | lcet10.txt | 426754 | 247515 | 230250 | 243710 | 225007 | 223028 | 174142 | 144916
43 | mapreduce-osdi-1.pdf | 94330 | 79281 | 79331 | 77477 | 79684 | 77241 | 76414 | 74940
44 | plrabn12.txt | 481861 | 340325 | 317582 | 329339 | 290030 | 297444 | 228901 | 195273
45 | ptt5 | 513216 | 87776 | 83676 | 93455 | 80756 | 86277 | 65571 | 56477
46 | sum | 38240 | 19018 | 18728 | 19837 | 20274 | 17609 | 14130 | 13002
47 | urls.10K | 702087 | 343976 | 316942 | 357267 | 350981 | 312748 | 253275 | 222625
48 | xargs.1 | 4227 | 2603 | 2545 | 2509 | 2441 | 2451 | 1864 | 1748
49 |
50 | #### Compression Speed in MB/s
51 |
52 | Name | pithy 0 | pithy 2 | snappy | lzf | lzo | zlib 1 | zlib 6
53 | ---------------------|--------:|--------:|-------:|-------:|-------:|-------:|------:
54 | alice29.txt | 34.31 | 30.48 | 26.92 | 18.46 | 27.91 | 5.01 | 1.36
55 | asyoulik.txt | 32.67 | 29.09 | 25.63 | 17.52 | 25.91 | 4.60 | 1.24
56 | baddata1.snappy | 332.22 | 236.41 | 37.59 | 12.61 | 13.20 | 3.33 | 2.79
57 | baddata2.snappy | 287.97 | 213.15 | 40.39 | 12.58 | 13.12 | 3.45 | 2.87
58 | baddata3.snappy | 287.98 | 213.21 | 34.57 | 12.57 | 13.03 | 3.38 | 2.82
59 | cp.html | 44.02 | 37.66 | 29.81 | 22.54 | 29.00 | 6.32 | 3.36
60 | fields.c | 43.06 | 35.57 | 26.45 | 25.68 | 39.53 | 6.03 | 3.56
61 | geo.protodata | 90.33 | 82.31 | 63.04 | 37.91 | 60.77 | 12.47 | 5.42
62 | grammar.lsp | 35.15 | 33.17 | 23.19 | 24.99 | 36.98 | 3.73 | 2.93
63 | house.jpg | 712.25 | 450.11 | 209.48 | 11.53 | 10.41 | 2.67 | 2.46
64 | html | 77.14 | 69.61 | 58.09 | 41.57 | 57.68 | 11.02 | 4.65
65 | html_x_4 | 171.03 | 131.75 | 56.00 | 37.63 | 51.18 | 11.18 | 4.36
66 | kennedy.xls | 45.41 | 37.88 | 36.68 | 34.34 | 40.08 | 7.97 | 1.76
67 | kppkn.gtb | 47.66 | 42.32 | 37.38 | 31.08 | 40.32 | 6.80 | 1.23
68 | lcet10.txt | 33.98 | 29.69 | 27.15 | 17.84 | 23.87 | 4.92 | 1.37
69 | mapreduce-osdi-1.pdf | 165.96 | 147.48 | 90.87 | 14.25 | 13.31 | 3.47 | 2.91
70 | plrabn12.txt | 29.28 | 24.61 | 22.84 | 15.80 | 20.64 | 4.14 | 1.03
71 | ptt5 | 80.67 | 70.76 | 68.08 | 41.08 | 49.54 | 11.46 | 3.53
72 | sum | 44.91 | 38.59 | 30.31 | 22.71 | 32.02 | 5.93 | 1.97
73 | urls.10K | 39.15 | 31.68 | 31.11 | 20.44 | 23.31 | 5.71 | 2.47
74 | xargs.1 | 33.60 | 25.68 | 19.67 | 20.26 | 30.31 | 3.77 | 2.99
75 |
76 |
77 | #### Decompression Speed in MB/s
78 |
79 | Name | pithy 0 | pithy 2 | snappy | lzf | lzo | zlib 1 | zlib 6
80 | ---------------------|--------:|--------:|--------:|-------:|-------:|-------:|------:
81 | alice29.txt | 115.76 | 114.84 | 48.92 | 69.53 | 68.74 | 28.71 | 33.94
82 | asyoulik.txt | 112.63 | 110.95 | 47.17 | 66.92 | 65.92 | 27.99 | 31.66
83 | baddata1.snappy | 1544.53 | 1642.51 | 228.20 | 114.57 | 143.39 | 20.58 | 21.42
84 | baddata2.snappy | 1093.85 | 1049.47 | 251.99 | 115.96 | 144.84 | 20.60 | 20.77
85 | baddata3.snappy | 1355.65 | 1355.65 | 213.21 | 114.71 | 143.99 | 20.19 | 21.67
86 | cp.html | 172.58 | 172.58 | 76.19 | 74.72 | 100.70 | 30.83 | 32.77
87 | fields.c | 154.19 | 156.49 | 67.73 | 81.80 | 100.34 | 33.76 | 37.18
88 | geo.protodata | 340.65 | 343.80 | 135.29 | 150.60 | 156.64 | 54.24 | 58.54
89 | grammar.lsp | 154.64 | 154.24 | 72.43 | 78.96 | 104.45 | 22.32 | 23.19
90 | house.jpg | 1985.66 | 897.23 | 1017.70 | 230.62 | 229.32 | 27.60 | 36.28
91 | html | 279.83 | 280.60 | 115.30 | 130.03 | 136.39 | 50.97 | 55.11
92 | html_x_4 | 832.94 | 847.38 | 108.72 | 122.60 | 129.39 | 46.41 | 50.31
93 | kennedy.xls | 147.34 | 147.61 | 52.08 | 56.72 | 95.54 | 32.96 | 36.43
94 | kppkn.gtb | 132.47 | 115.95 | 56.02 | 85.62 | 84.27 | 34.07 | 41.23
95 | lcet10.txt | 109.02 | 107.61 | 45.58 | 60.34 | 61.26 | 27.58 | 30.86
96 | mapreduce-osdi-1.pdf | 478.53 | 463.82 | 257.78 | 182.13 | 185.10 | 29.29 | 30.33
97 | plrabn12.txt | 94.13 | 90.73 | 37.60 | 55.46 | 52.74 | 23.68 | 26.55
98 | ptt5 | 241.46 | 182.63 | 116.23 | 131.32 | 133.36 | 49.16 | 52.61
99 | sum | 162.12 | 147.64 | 67.91 | 74.89 | 98.04 | 29.18 | 33.77
100 | urls.10K | 156.08 | 153.04 | 68.10 | 62.93 | 77.84 | 29.52 | 31.03
101 | xargs.1 | 149.63 | 144.20 | 63.98 | 72.03 | 93.80 | 22.03 | 23.30
102 |
103 |
104 | [snappy]: http://code.google.com/p/snappy/
105 |
--------------------------------------------------------------------------------
/pithy.c:
--------------------------------------------------------------------------------
1 | //
2 | // pithy.c
3 | // http://github.com/johnezang/pithy
4 | // Licensed under the terms of the BSD License, as specified below.
5 | //
6 |
7 | /*
8 | Copyright (c) 2011, John Engelhart
9 |
10 | All rights reserved.
11 |
12 | Redistribution and use in source and binary forms, with or without
13 | modification, are permitted provided that the following conditions are met:
14 |
15 | * Redistributions of source code must retain the above copyright
16 | notice, this list of conditions and the following disclaimer.
17 |
18 | * Redistributions in binary form must reproduce the above copyright
19 | notice, this list of conditions and the following disclaimer in the
20 | documentation and/or other materials provided with the distribution.
21 |
22 | * Neither the name of the Zang Industries nor the names of its
23 | contributors may be used to endorse or promote products derived from
24 | this software without specific prior written permission.
25 |
26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 | */
38 |
39 | #include
40 | #include
41 | #include
42 | #include
43 |
44 | #if defined(__arm__) && defined(__ARM_NEON__)
45 | #include
46 | #endif
47 |
48 | #include "pithy.h"
49 |
50 | #define kBlockLog 20ul
51 | #define kBlockSize ((size_t)(1 << kBlockLog))
52 |
53 | // The maximum size that can be compressed while still allowing for the worst case compression expansion.
54 | #define PITHY_UNCOMPRESSED_MAX_LENGTH 0xdb6db6bfu // 0xdb6db6bf == 3681400511, or 3510.857 Mbytes.
55 |
56 | #if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || defined(__arm__)
57 | #define PITHY_UNALIGNED_LOADS_AND_STORES
58 | #endif
59 |
60 | typedef const char * pithy_hashOffset_t;
61 |
62 | enum {
63 | PITHY_LITERAL = 0,
64 | PITHY_COPY_1_BYTE_OFFSET = 1,
65 | PITHY_COPY_2_BYTE_OFFSET = 2,
66 | PITHY_COPY_3_BYTE_OFFSET = 3
67 | };
68 |
69 |
70 | #if defined (__GNUC__) && (__GNUC__ >= 3)
71 | #define PITHY_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__))
72 | #define PITHY_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect))
73 | #define PITHY_EXPECT_T(cond) PITHY_EXPECTED(cond, 1u)
74 | #define PITHY_EXPECT_F(cond) PITHY_EXPECTED(cond, 0u)
75 | #define PITHY_PREFETCH(ptr) __builtin_prefetch(ptr)
76 | #else // defined (__GNUC__) && (__GNUC__ >= 3)
77 | #define PITHY_ATTRIBUTES(attr, ...)
78 | #define PITHY_EXPECTED(cond, expect) (cond)
79 | #define PITHY_EXPECT_T(cond) (cond)
80 | #define PITHY_EXPECT_F(cond) (cond)
81 | #define PITHY_PREFETCH(ptr)
82 | #endif // defined (__GNUC__) && (__GNUC__ >= 3)
83 |
84 | #define PITHY_STATIC_INLINE static __inline__ PITHY_ATTRIBUTES(always_inline)
85 | #define PITHY_ALIGNED(x) PITHY_ATTRIBUTES(aligned(x))
86 |
87 | #if defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG)
88 | #define NDEBUG
89 | #endif
90 |
91 | #ifdef NDEBUG
92 | #define DCHECK(condition)
93 | #else
94 | #define DCHECK(condition) do { if(PITHY_EXPECT_F(!(condition))) { fprintf(stderr, "%s / %s @ %ld: Invalid parameter not satisfying: %s", __FILE__, __PRETTY_FUNCTION__, (long)__LINE__, #condition); fflush(stderr); abort(); } } while(0)
95 | #endif
96 |
97 |
98 | PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *OUTPUT);
99 | PITHY_STATIC_INLINE char *pithy_Encode32(char *ptr, uint32_t v);
100 |
101 | PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset);
102 | PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift);
103 | PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit);
104 | PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path);
105 | PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len);
106 | PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len);
107 | PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len);
108 |
109 |
110 | #ifdef PITHY_UNALIGNED_LOADS_AND_STORES
111 |
112 | #define pithy_Load16(_p) (*((uint16_t *)(_p)))
113 | #define pithy_Load32(_p) (*((uint32_t *)(_p)))
114 | #define pithy_Store16(_p, _val) (*((uint16_t *)(_p)) = (_val))
115 | #define pithy_Store32(_p, _val) (*((uint32_t *)(_p)) = (_val))
116 |
117 | #if defined(__arm__)
118 |
119 | #if defined(__ARM_NEON__)
120 | #define pithy_Load64(_p) ((uint64_t)vld1_u64(_p))
121 | #define pithy_Store64(_p, _val) vst1_u64(_p, (uint64x1_t)_val)
122 | #else
123 | #define PITHY_32BIT_MOVE64
124 | PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return(t); }
125 | PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); }
126 | #endif
127 |
128 | #else // not __arm__
129 | #define pithy_Load64(_p) (*((uint64_t *)(_p)))
130 | #define pithy_Store64(_p, _val) (*((uint64_t *)(_p)) = (_val))
131 | #endif // __arm__
132 |
133 | #else
134 |
135 | PITHY_STATIC_INLINE uint16_t pithy_Load16(const void *p) { uint16_t t; memcpy(&t, p, sizeof(t)); return(t); }
136 | PITHY_STATIC_INLINE uint32_t pithy_Load32(const void *p) { uint32_t t; memcpy(&t, p, sizeof(t)); return(t); }
137 | PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return(t); }
138 | PITHY_STATIC_INLINE void pithy_Store16(void *p, uint16_t v) { memcpy(p, &v, sizeof(v)); }
139 | PITHY_STATIC_INLINE void pithy_Store32(void *p, uint32_t v) { memcpy(p, &v, sizeof(v)); }
140 | PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); }
141 |
142 | #endif
143 |
144 |
145 | #ifdef PITHY_32BIT_MOVE64
146 | #define pithy_Move64(dst,src) pithy_Store32(dst, pithy_Load32(src)); pithy_Store32(dst + 4ul, pithy_Load32(src + 4ul));
147 | #else
148 | #define pithy_Move64(dst,src) pithy_Store64(dst, pithy_Load64(src));
149 | #endif
150 |
151 |
152 | #if defined(__arm__) && defined(__ARM_NEON__) && defined(PITHY_UNALIGNED_LOADS_AND_STORES)
153 | #define pithy_Move128(_dst,_src) ({ asm ("vld1.64 {d0-d1}, [%[src]]\n\tvst1.64 {d0-d1}, [%[dst]]" : : [src]"r"(_src), [dst]"r"(_dst) : "d0", "d1", "memory"); })
154 | #else
155 | #define pithy_Move128(dst,src) pithy_Move64(dst, src); pithy_Move64(dst + 8ul, src + 8ul);
156 | #endif
157 |
158 | #ifdef __BIG_ENDIAN__
159 |
160 | #ifdef _MSC_VER
161 | #include
162 | #define pithy_bswap_16(x) _byteswap_ushort(x)
163 | #define pithy_bswap_32(x) _byteswap_ulong(x)
164 | #define pithy_bswap_64(x) _byteswap_uint64(x)
165 |
166 | #elif defined(__APPLE__)
167 |
168 | // Mac OS X / Darwin features
169 | #include
170 | #define pithy_bswap_16(x) OSSwapInt16(x)
171 | #define pithy_bswap_32(x) OSSwapInt32(x)
172 | #define pithy_bswap_64(x) OSSwapInt64(x)
173 | #else
174 | #include
175 | #endif
176 |
177 | #endif // __BIG_ENDIAN__
178 |
179 | // Conversion functions.
180 | #ifdef __BIG_ENDIAN__
181 | #define pithy_FromHost16(x) ((uint16_t)pithy_bswap_16(x))
182 | #define pithy_ToHost16(x) ((uint16_t)pithy_bswap_16(x))
183 | #define pithy_FromHost32(x) ((uint32_t)pithy_bswap_32(x))
184 | #define pithy_ToHost32(x) ((uint32_t)pithy_bswap_32(x))
185 | #define pithy_IsLittleEndian() (0)
186 |
187 | #else // !defined(__BIG_ENDIAN__)
188 | #define pithy_FromHost16(x) ((uint16_t)(x))
189 | #define pithy_ToHost16(x) ((uint16_t)(x))
190 | #define pithy_FromHost32(x) ((uint32_t)(x))
191 | #define pithy_ToHost32(x) ((uint32_t)(x))
192 | #define pithy_IsLittleEndian() (1)
193 |
194 | #endif // !defined(__BIG_ENDIAN__)
195 |
196 | #define pithy_LoadHost16(p) pithy_ToHost16(pithy_Load16((const void *)(p)))
197 | #define pithy_StoreHost16(p, v) pithy_Store16((void *)(p), pithy_FromHost16(v))
198 | #define pithy_LoadHost32(p) pithy_ToHost32(pithy_Load32((p)))
199 | #define pithy_StoreHost32(p, v) pithy_Store32((p), pithy_FromHost32(v))
200 |
201 | PITHY_STATIC_INLINE void pithy_StoreHost24(char *p, uint32_t v) { *p++ = (v & 0xffu); *p++ = ((v >> 8) & 0xffu); *p++ = ((v >> 16) & 0xffu); }
202 |
203 | #if defined (__GNUC__) && (__GNUC__ >= 3)
204 |
205 | #define pithy_Log2Floor(n) ({typeof(n) _n = (n); _n == 0 ? (int)-1 : (int)(31 ^ __builtin_clz(_n));})
206 | #define pithy_FindLSBSetNonZero32(n) ((int)__builtin_ctz((uint32_t)(n)))
207 | #define pithy_FindLSBSetNonZero64(n) ((int)__builtin_ctzll((uint64_t)(n)))
208 | #define pithy_FindMSBSetNonZero32(n) ((int)__builtin_clz((uint32_t)(n)))
209 | #define pithy_FindMSBSetNonZero64(n) ((int)__builtin_clzll((uint64_t)(n)))
210 |
211 | #else // Portable versions, !GNUC || GNUC < 3
212 |
213 | PITHY_STATIC_INLINE int pithy_Log2Floor(uint32_t n) {
214 | if(n == 0u) { return(-1); }
215 | int i = 0, log = 0;
216 | uint32_t value = n;
217 | for(i = 4; i >= 0; --i) { int shift = (1 << i); uint32_t x = value >> shift; if(x != 0u) { value = x; log += shift; } }
218 | DCHECK(value == 1);
219 | return(log);
220 | }
221 |
222 | PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero32(uint32_t n) {
223 | int i = 0, rc = 31;
224 | for(i = 4, shift = 1 << 4; i >= 0; --i) { const uint32_t x = n << shift; if(x != 0u) { n = x; rc -= shift; } shift >>= 1; }
225 | return(rc);
226 | }
227 |
228 | PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero64(uint64_t n) {
229 | const uint32_t bottomBits = n;
230 | if(bottomBits == 0u) { return(32 + pithy_FindLSBSetNonZero32((n >> 32))); } else { return(pithy_FindLSBSetNonZero32(bottomBits)); }
231 | }
232 |
233 | PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero32(uint32_t n) {
234 | int i;
235 | uint32_t x, rc = 32, shift = 1 << 4;
236 | for(i = 3; i >= 0; --i) { x = n >> shift; if(x != 0) { rc -= shift; n = x; } shift >>= 1; }
237 | x = n >> shift;
238 | return(rc - ((x != 0) ? 2 : n));
239 | }
240 |
241 | PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero64(uint64_t n) {
242 | const uint32_t upperBits = n >> 32;
243 | if(upperBits == 0u) { return(32 + pithy_FindMSBSetNonZero32((n))); } else { return(pithy_FindMSBSetNonZero32(upperBits)); }
244 | }
245 |
246 | #endif // End portable versions.
247 |
248 |
249 |
250 |
251 |
252 |
253 | PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *resultOut) {
254 | const unsigned char *ptr = (const unsigned char *)p, *limit = (const unsigned char *)l;
255 | size_t resultShift = 0ul, result = 0ul;
256 | uint32_t encodedByte = 0u;
257 |
258 | for(resultShift = 0ul; resultShift <= 28ul; resultShift += 7ul) { if(ptr >= limit) { return(NULL); } encodedByte = *(ptr++); result |= (encodedByte & 127u) << resultShift; if(encodedByte < ((resultShift == 28ul) ? 16u : 128u)) { goto done; } }
259 | return(NULL);
260 | done:
261 | *resultOut = result;
262 | return((const char *)ptr);
263 | }
264 |
265 | PITHY_STATIC_INLINE char *pithy_Encode32(char *sptr, uint32_t v) {
266 | unsigned char *ptr = (unsigned char *)sptr;
267 | if(v < (1u << 7)) { *(ptr++) = v; }
268 | else if(v < (1u << 14)) { *(ptr++) = v | 0x80u; *(ptr++) = (v>>7); }
269 | else if(v < (1u << 21)) { *(ptr++) = v | 0x80u; *(ptr++) = (v>>7) | 0x80u; *(ptr++) = (v>>14); }
270 | else if(v < (1u << 28)) { *(ptr++) = v | 0x80u; *(ptr++) = (v>>7) | 0x80u; *(ptr++) = (v>>14) | 0x80u; *(ptr++) = (v>>21); }
271 | else { *(ptr++) = v | 0x80u; *(ptr++) = (v>>7) | 0x80u; *(ptr++) = (v>>14) | 0x80u; *(ptr++) = (v>>21) | 0x80u; *(ptr++) = (v>>28); }
272 | return((char *)ptr);
273 | }
274 |
275 |
276 |
277 |
278 | PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset) {
279 | DCHECK(offset <= 4);
280 | return(v >> (pithy_IsLittleEndian() ? (8u * offset) : (32u - (8u * offset))));
281 | }
282 |
283 |
284 | PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift) { uint32_t kMul = 0x1e35a7bdU; return((bytes * kMul) >> shift); }
285 |
286 |
287 | PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit) {
288 | DCHECK(s2_limit >= s2);
289 | const char *ms1 = s1, *ms2 = s2;
290 |
291 | #if defined(__LP64__)
292 | while(PITHY_EXPECT_T(ms2 < (s2_limit - 8ul))) { uint64_t x = pithy_Load64(ms1) ^ pithy_Load64(ms2); if(PITHY_EXPECT_F(x == 0ul)) { ms1 += 8ul; ms2 += 8ul; } else { return((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero64(x) >> 3) : (pithy_FindMSBSetNonZero64(x) >> 3)))); } }
293 | #else
294 | while(PITHY_EXPECT_T(ms2 < (s2_limit - 4u ))) { uint32_t x = pithy_Load32(ms1) ^ pithy_Load32(ms2); if(PITHY_EXPECT_F(x == 0u )) { ms1 += 4u; ms2 += 4u; } else { return((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero32(x) >> 3) : (pithy_FindMSBSetNonZero32(x) >> 3)))); } }
295 | #endif
296 | while(PITHY_EXPECT_T(ms2 < s2_limit)) { if(PITHY_EXPECT_T(*ms1 == *ms2)) { ms1++; ms2++; } else { return( ms1 - s1); } }
297 | return(ms1 - s1);
298 | }
299 |
300 |
301 |
302 | PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path) {
303 | ssize_t n = len - 1l;
304 | if(PITHY_EXPECT_T(n < 60l)) { *op++ = PITHY_LITERAL | (n << 2); if(PITHY_EXPECT_T(allow_fast_path) && PITHY_EXPECT_T(len <= 16ul)) { pithy_Move128(op, literal); return(op + len); } }
305 | else { char *base = op; int count = 0; op++; while(n > 0l) { *op++ = n & 0xff; n >>= 8; count++; } DCHECK((count >= 1) && (count <= 4)); *base = PITHY_LITERAL | ((59 + count) << 2); }
306 | memcpy(op, literal, len);
307 | return(op + len);
308 | }
309 |
310 | PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len) {
311 | DCHECK((len < 65536ul) && (len >= 63ul) && (offset < kBlockSize));
312 | if(PITHY_EXPECT_T(offset < 65536ul)) { if(PITHY_EXPECT_T(len < (256ul + 63ul))) { *op++ = PITHY_COPY_2_BYTE_OFFSET | (62 << 2); pithy_StoreHost16(op, offset); op += 2ul; *op++ = (len - 63ul); }
313 | else { *op++ = PITHY_COPY_2_BYTE_OFFSET | (63 << 2); pithy_StoreHost16(op, offset); op += 2ul; pithy_StoreHost16(op, len); op += 2ul; } }
314 | else { if(PITHY_EXPECT_T(len < (256ul + 63ul))) { *op++ = PITHY_COPY_3_BYTE_OFFSET | (62 << 2); pithy_StoreHost24(op, offset); op += 3ul; *op++ = (len - 63ul); }
315 | else { *op++ = PITHY_COPY_3_BYTE_OFFSET | (63 << 2); pithy_StoreHost24(op, offset); op += 3ul; pithy_StoreHost16(op, len); op += 2ul; } }
316 | return(op);
317 | }
318 |
319 | PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len) {
320 | DCHECK((len < 63ul) && (len >= 4ul) && (offset < kBlockSize));
321 | if(PITHY_EXPECT_T(len < 12ul) && PITHY_EXPECT_T(offset < 2048ul)) { ssize_t lenMinus4 = len - 4l; DCHECK(lenMinus4 < 8l); *op++ = PITHY_COPY_1_BYTE_OFFSET | (lenMinus4 << 2) | ((offset >> 8) << 5); *op++ = offset & 0xff; }
322 | else { if(PITHY_EXPECT_T(offset < 65536ul)) { *op++ = PITHY_COPY_2_BYTE_OFFSET | ((len - 1ul) << 2); pithy_StoreHost16(op, offset); op += 2ul; }
323 | else { *op++ = PITHY_COPY_3_BYTE_OFFSET | ((len - 1ul) << 2); pithy_StoreHost24(op, offset); op += 3ul; } }
324 | return(op);
325 | }
326 |
327 | PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len) {
328 | while(PITHY_EXPECT_F(len >= 63ul)) { op = pithy_EmitCopyGreaterThan63(op, offset, (len >= 65539ul) ? 65535ul : len); len -= (len >= 65539ul) ? 65535ul : len; }
329 | DCHECK((len > 0ul) ? ((len >= 4ul) && (len < 63ul)) : 1);
330 | if( PITHY_EXPECT_T(len > 0ul)) { op = pithy_EmitCopyLessThan63( op, offset, len); len -= len; }
331 | return(op);
332 | }
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 | size_t pithy_MaxCompressedLength(size_t inputLength) {
343 | return((inputLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ? 0ul : 32ul + inputLength + (inputLength / 6ul));
344 | }
345 |
346 | size_t pithy_Compress(const char *uncompressed, size_t uncompressedLength, char *compressedOut, size_t compressedOutLength, int compressionLevel) {
347 | if((pithy_MaxCompressedLength(uncompressedLength) > compressedOutLength) || (uncompressedLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) || (uncompressedLength == 0ul)) { return(0ul); }
348 | char *compressedPtr = compressedOut;
349 |
350 | size_t hashTableSize = 0x100ul, maxHashTableSize = 1 << (12ul + (((compressionLevel < 0) ? 0 : (compressionLevel > 9) ? 9 : compressionLevel) / 2ul));
351 | while((hashTableSize < maxHashTableSize) && (hashTableSize < uncompressedLength)) { hashTableSize <<= 1; }
352 | pithy_hashOffset_t stackHashTable[hashTableSize], *heapHashTable = NULL, *hashTable = stackHashTable;
353 | if((sizeof(pithy_hashOffset_t) * hashTableSize) >= (1024ul * 128ul)) { if((heapHashTable = malloc(sizeof(pithy_hashOffset_t) * hashTableSize)) == NULL) { return(0ul); } hashTable = heapHashTable; }
354 | size_t x = 0ul;
355 | for(x = 0ul; x < hashTableSize; x++) { hashTable[x] = uncompressed; }
356 |
357 | #ifndef NDEBUG
358 | char * const compressedOutEnd = compressedOut + compressedOutLength;
359 | #endif
360 | compressedPtr = pithy_Encode32(compressedPtr, uncompressedLength);
361 | DCHECK(compressedPtr <= compressedOutEnd);
362 |
363 | {
364 | const char *uncompressedPtr = uncompressed, *uncompressedEnd = uncompressed + uncompressedLength, *nextEmitUncompressedPtr = uncompressedPtr;
365 | DCHECK((hashTableSize & (hashTableSize - 1l)) == 0);
366 | const int shift = 32 - pithy_Log2Floor(hashTableSize);
367 | DCHECK((UINT32_MAX >> shift) == (hashTableSize - 1l));
368 | size_t skip = 32ul;
369 |
370 | if(PITHY_EXPECT_T(uncompressedLength >= 15ul)) {
371 | const char *uncompressedEndLimit = uncompressed + uncompressedLength - 15ul;
372 | uint32_t uncompressedBytes, nextUncompressedBytes = pithy_Load32(++uncompressedPtr), nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
373 |
374 | while(1) {
375 | DCHECK(nextEmitUncompressedPtr < uncompressedPtr);
376 | const char *nextUncompressedPtr = uncompressedPtr, *matchCandidatePtr = NULL;
377 |
378 | skip = (((skip - 32ul) * 184ul) >> 8) + 32ul;
379 |
380 | do {
381 | uncompressedPtr = nextUncompressedPtr;
382 | uncompressedBytes = nextUncompressedBytes;
383 | uint32_t uncompressedBytesHash = nextUncompressedBytesHash;
384 | DCHECK(uncompressedBytesHash == pithy_HashBytes(uncompressedBytes, shift));
385 | size_t skipBytesBetweenHashLookups = skip >> 5;
386 | skip += ((skip * 7ul) >> 11) + 1ul;
387 | nextUncompressedPtr = uncompressedPtr + skipBytesBetweenHashLookups;
388 | if(PITHY_EXPECT_F(nextUncompressedPtr > uncompressedEndLimit)) { goto emit_remainder; }
389 | nextUncompressedBytes = pithy_Load32(nextUncompressedPtr);
390 | nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
391 | matchCandidatePtr = hashTable[uncompressedBytesHash];
392 | DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
393 | hashTable[uncompressedBytesHash] = uncompressedPtr;
394 | } while((PITHY_EXPECT_T(uncompressedBytes != pithy_Load32(matchCandidatePtr))) || PITHY_EXPECT_F((uncompressedPtr - matchCandidatePtr) >= ((ssize_t)(kBlockSize - 2ul))));
395 |
396 | DCHECK((nextEmitUncompressedPtr + 16ul) <= uncompressedEnd);
397 | compressedPtr = pithy_EmitLiteral(compressedPtr, nextEmitUncompressedPtr, uncompressedPtr - nextEmitUncompressedPtr, 1);
398 | DCHECK(compressedPtr <= compressedOutEnd);
399 | uint64_t uncompressedBytes64 = 0ul;
400 |
401 | do {
402 | if(compressionLevel > 2) {
403 | DCHECK((uncompressedPtr + 5ul) <= uncompressedEnd);
404 | uncompressedBytes64 = pithy_Load64(uncompressedPtr + 1ul);
405 | hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = uncompressedPtr + 1ul;
406 | if(compressionLevel > 4) { hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = uncompressedPtr + 2ul; }
407 | }
408 |
409 | DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr <= uncompressedPtr) && ((matchCandidatePtr + 4ul) <= uncompressedEnd) && ((uncompressedPtr + 4ul) <= uncompressedEnd));
410 | size_t matchCandidateLength = 4ul + pithy_FindMatchLength(matchCandidatePtr + 4ul, uncompressedPtr + 4ul, uncompressedEnd);
411 | DCHECK(((matchCandidatePtr + matchCandidateLength) >= uncompressed) && ((matchCandidatePtr + matchCandidateLength) <= uncompressedEnd));
412 | DCHECK(0 == memcmp(uncompressedPtr, matchCandidatePtr, matchCandidateLength));
413 | compressedPtr = pithy_EmitCopy(compressedPtr, uncompressedPtr - matchCandidatePtr, matchCandidateLength);
414 | DCHECK(compressedPtr <= compressedOutEnd);
415 | uncompressedPtr += matchCandidateLength;
416 | DCHECK(uncompressedPtr <= uncompressedEnd);
417 | nextEmitUncompressedPtr = uncompressedPtr;
418 | if(PITHY_EXPECT_F(uncompressedPtr >= uncompressedEndLimit)) { goto emit_remainder; }
419 |
420 | DCHECK(((uncompressedPtr - 3ul) >= uncompressed) && (uncompressedPtr <= uncompressedEnd));
421 |
422 | uncompressedBytes64 = pithy_Load64(uncompressedPtr - 3ul);
423 |
424 | if(compressionLevel > 0) {
425 | if(compressionLevel > 8) { hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = uncompressedPtr - 3ul; }
426 | if(compressionLevel > 6) { hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = uncompressedPtr - 2ul; }
427 | hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 2u), shift)] = uncompressedPtr - 1ul;
428 | }
429 |
430 | uncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 3u);
431 | uint32_t uncompressedBytesHash = pithy_HashBytes(uncompressedBytes, shift);
432 | matchCandidatePtr = hashTable[uncompressedBytesHash];
433 | DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
434 | hashTable[uncompressedBytesHash] = uncompressedPtr;
435 | } while(PITHY_EXPECT_F(uncompressedBytes == pithy_Load32(matchCandidatePtr)) && PITHY_EXPECT_T((uncompressedPtr - matchCandidatePtr) < ((ssize_t)(kBlockSize - 2ul))));
436 |
437 | nextUncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 4u);
438 | nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
439 | uncompressedPtr++;
440 | }
441 | }
442 |
443 | emit_remainder:
444 | if(nextEmitUncompressedPtr < uncompressedEnd) { compressedPtr = pithy_EmitLiteral(compressedPtr, nextEmitUncompressedPtr, uncompressedEnd - nextEmitUncompressedPtr, 0); }
445 | }
446 |
447 | pithy_Store32(compressedPtr, 0); compressedPtr += 4;
448 |
449 | DCHECK((size_t)(compressedPtr - compressedOut) <= compressedOutLength);
450 | if(heapHashTable != NULL) { free(heapHashTable); heapHashTable = NULL; hashTable = NULL; }
451 | return(compressedPtr - compressedOut);
452 | }
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 | static const uint32_t pithy_wordmask[] = {
461 | 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu
462 | };
463 |
464 | static const uint16_t pithy_charTable[256] = {
465 | 0x0001, 0x0804, 0x1001, 0x1801, 0x0002, 0x0805, 0x1002, 0x1802,
466 | 0x0003, 0x0806, 0x1003, 0x1803, 0x0004, 0x0807, 0x1004, 0x1804,
467 | 0x0005, 0x0808, 0x1005, 0x1805, 0x0006, 0x0809, 0x1006, 0x1806,
468 | 0x0007, 0x080a, 0x1007, 0x1807, 0x0008, 0x080b, 0x1008, 0x1808,
469 | 0x0009, 0x0904, 0x1009, 0x1809, 0x000a, 0x0905, 0x100a, 0x180a,
470 | 0x000b, 0x0906, 0x100b, 0x180b, 0x000c, 0x0907, 0x100c, 0x180c,
471 | 0x000d, 0x0908, 0x100d, 0x180d, 0x000e, 0x0909, 0x100e, 0x180e,
472 | 0x000f, 0x090a, 0x100f, 0x180f, 0x0010, 0x090b, 0x1010, 0x1810,
473 | 0x0011, 0x0a04, 0x1011, 0x1811, 0x0012, 0x0a05, 0x1012, 0x1812,
474 | 0x0013, 0x0a06, 0x1013, 0x1813, 0x0014, 0x0a07, 0x1014, 0x1814,
475 | 0x0015, 0x0a08, 0x1015, 0x1815, 0x0016, 0x0a09, 0x1016, 0x1816,
476 | 0x0017, 0x0a0a, 0x1017, 0x1817, 0x0018, 0x0a0b, 0x1018, 0x1818,
477 | 0x0019, 0x0b04, 0x1019, 0x1819, 0x001a, 0x0b05, 0x101a, 0x181a,
478 | 0x001b, 0x0b06, 0x101b, 0x181b, 0x001c, 0x0b07, 0x101c, 0x181c,
479 | 0x001d, 0x0b08, 0x101d, 0x181d, 0x001e, 0x0b09, 0x101e, 0x181e,
480 | 0x001f, 0x0b0a, 0x101f, 0x181f, 0x0020, 0x0b0b, 0x1020, 0x1820,
481 | 0x0021, 0x0c04, 0x1021, 0x1821, 0x0022, 0x0c05, 0x1022, 0x1822,
482 | 0x0023, 0x0c06, 0x1023, 0x1823, 0x0024, 0x0c07, 0x1024, 0x1824,
483 | 0x0025, 0x0c08, 0x1025, 0x1825, 0x0026, 0x0c09, 0x1026, 0x1826,
484 | 0x0027, 0x0c0a, 0x1027, 0x1827, 0x0028, 0x0c0b, 0x1028, 0x1828,
485 | 0x0029, 0x0d04, 0x1029, 0x1829, 0x002a, 0x0d05, 0x102a, 0x182a,
486 | 0x002b, 0x0d06, 0x102b, 0x182b, 0x002c, 0x0d07, 0x102c, 0x182c,
487 | 0x002d, 0x0d08, 0x102d, 0x182d, 0x002e, 0x0d09, 0x102e, 0x182e,
488 | 0x002f, 0x0d0a, 0x102f, 0x182f, 0x0030, 0x0d0b, 0x1030, 0x1830,
489 | 0x0031, 0x0e04, 0x1031, 0x1831, 0x0032, 0x0e05, 0x1032, 0x1832,
490 | 0x0033, 0x0e06, 0x1033, 0x1833, 0x0034, 0x0e07, 0x1034, 0x1834,
491 | 0x0035, 0x0e08, 0x1035, 0x1835, 0x0036, 0x0e09, 0x1036, 0x1836,
492 | 0x0037, 0x0e0a, 0x1037, 0x1837, 0x0038, 0x0e0b, 0x1038, 0x1838,
493 | 0x0039, 0x0f04, 0x1039, 0x1839, 0x003a, 0x0f05, 0x103a, 0x183a,
494 | 0x003b, 0x0f06, 0x103b, 0x183b, 0x003c, 0x0f07, 0x103c, 0x183c,
495 | 0x0801, 0x0f08, 0x103d, 0x183d, 0x1001, 0x0f09, 0x103e, 0x183e,
496 | 0x1801, 0x0f0a, 0x103f, 0x183f, 0x2001, 0x0f0b, 0x1040, 0x1840
497 | };
498 |
499 |
500 | int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult) {
501 | const char *compressedEnd = compressed + compressedLength;
502 | size_t decompressedLength = 0ul;
503 | if(pithy_Parse32WithLimit(compressed, compressedEnd, &decompressedLength) != NULL) { *decompressedOutLengthResult = decompressedLength; return(1); } else { return(0); }
504 | }
505 |
506 |
507 | int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut, size_t decompressedOutLength) {
508 | const char *nextCompressedPtr = NULL, *compressedEnd = (compressed + compressedLength);
509 | size_t parsedDecompressedLength = 0ul;
510 | if(((nextCompressedPtr = pithy_Parse32WithLimit(compressed, compressedEnd, &parsedDecompressedLength)) == NULL) || (parsedDecompressedLength > decompressedOutLength)) { return(0); }
511 |
512 | char *decompressedPtr = decompressedOut, *decompressedEnd = decompressedOut + parsedDecompressedLength;
513 |
514 | while(1) {
515 | const char *compressedPtr = nextCompressedPtr;
516 | DCHECK(compressedPtr <= compressedEnd);
517 | if(PITHY_EXPECT_F(compressedPtr >= compressedEnd)) { break; }
518 |
519 | const unsigned char c = *((const unsigned char *)(compressedPtr++));
520 | const unsigned char cLowerBits = (c & 0x3u);
521 | const ssize_t spaceLeft = (decompressedEnd - decompressedPtr);
522 |
523 | if((cLowerBits == PITHY_LITERAL)) {
524 | size_t literalLength = (c >> 2) + 1;
525 | if(PITHY_EXPECT_T(literalLength <= 16ul) && PITHY_EXPECT_T((compressedEnd - compressedPtr) >= 16l) && PITHY_EXPECT_T(spaceLeft >= 16l)) { pithy_Move128(decompressedPtr, compressedPtr); }
526 | else {
527 | if(PITHY_EXPECT_F(literalLength > 60)) {
528 | if(PITHY_EXPECT_F((compressedPtr + 4) > compressedEnd)) { break; }
529 | size_t literalLengthBytes = literalLength - 60;
530 | literalLength = (pithy_LoadHost32(compressedPtr) & pithy_wordmask[literalLengthBytes]) + 1;
531 | compressedPtr += literalLengthBytes;
532 | }
533 | if(PITHY_EXPECT_F(spaceLeft < (ssize_t)literalLength) || PITHY_EXPECT_F((compressedPtr + literalLength) > compressedEnd)) { break; }
534 | memcpy(decompressedPtr, compressedPtr, literalLength);
535 | }
536 | nextCompressedPtr = compressedPtr + literalLength;
537 | decompressedPtr += literalLength;
538 | } else {
539 | const uint32_t entry = pithy_charTable[c];
540 | const size_t trailer = pithy_LoadHost32(compressedPtr) & pithy_wordmask[cLowerBits];
541 | size_t length = entry & 0xffu;
542 | const size_t copyOffset = ((entry & 0x700u) + trailer);
543 |
544 | compressedPtr += cLowerBits;
545 |
546 | DCHECK((compressedPtr <= compressedEnd) && (copyOffset > 0ul) && (spaceLeft > 0l) && (length > 0ul));
547 |
548 | if(PITHY_EXPECT_F((decompressedPtr - decompressedOut) <= ((ssize_t)copyOffset - 1l))) { break; }
549 | if(PITHY_EXPECT_T(length <= 16ul) && PITHY_EXPECT_T(copyOffset >= 16ul) && PITHY_EXPECT_T(spaceLeft >= 16l)) { pithy_Move128(decompressedPtr, decompressedPtr - copyOffset); }
550 | else {
551 | if(PITHY_EXPECT_F(length >= 63ul)) { if(PITHY_EXPECT_T(length == 63ul)) { if(PITHY_EXPECT_F((compressedPtr + 1) > compressedEnd)) { break; } length = (*((unsigned char *)compressedPtr++)) + 63ul; }
552 | else { if(PITHY_EXPECT_F((compressedPtr + 2) > compressedEnd)) { break; } length = pithy_LoadHost16(compressedPtr); compressedPtr += 2ul; } }
553 |
554 | char *copyFrom = decompressedPtr - copyOffset, *copyTo = decompressedPtr;
555 | ssize_t copyLength = (ssize_t)length;
556 |
557 | if(PITHY_EXPECT_F(copyLength > 256l) && PITHY_EXPECT_T(copyOffset > (size_t)copyLength)) { if(PITHY_EXPECT_F(spaceLeft < copyLength)) { break; } memcpy(copyTo, copyFrom, copyLength); }
558 | else {
559 | if(PITHY_EXPECT_T(spaceLeft >= (copyLength + 24)) && PITHY_EXPECT_T(copyLength > 0l)) {
560 | while((copyTo - copyFrom) < 16l) { pithy_Move128(copyTo, copyFrom); copyLength -= copyTo - copyFrom; copyTo += copyTo - copyFrom; }
561 | while(copyLength > 0l) { pithy_Move128(copyTo, copyFrom); copyFrom += 16l; copyTo += 16l; copyLength -= 16l; }
562 | } else { if(PITHY_EXPECT_F(spaceLeft < copyLength) || PITHY_EXPECT_F(copyLength <= 0l)) { break; } do { *copyTo++ = *copyFrom++; } while(--copyLength > 0l); }
563 | }
564 | }
565 | nextCompressedPtr = compressedPtr;
566 | decompressedPtr += length;
567 | }
568 | }
569 |
570 | return(decompressedPtr == decompressedEnd);
571 | }
572 |
--------------------------------------------------------------------------------
/pithy.h:
--------------------------------------------------------------------------------
1 | //
2 | // pithy.h
3 | // http://github.com/johnezang/pithy
4 | // Licensed under the terms of the BSD License, as specified below.
5 | //
6 |
7 | /*
8 | Copyright (c) 2011, John Engelhart
9 |
10 | All rights reserved.
11 |
12 | Redistribution and use in source and binary forms, with or without
13 | modification, are permitted provided that the following conditions are met:
14 |
15 | * Redistributions of source code must retain the above copyright
16 | notice, this list of conditions and the following disclaimer.
17 |
18 | * Redistributions in binary form must reproduce the above copyright
19 | notice, this list of conditions and the following disclaimer in the
20 | documentation and/or other materials provided with the distribution.
21 |
22 | * Neither the name of the Zang Industries nor the names of its
23 | contributors may be used to endorse or promote products derived from
24 | this software without specific prior written permission.
25 |
26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 | */
38 |
39 | #include
40 | #include
41 |
42 | #ifdef __cplusplus
43 | extern "C" {
44 | #endif
45 |
46 | #ifndef _PITHY_H_
47 | #define _PITHY_H_
48 |
49 | // compressionLevel >= 0 && compressionLevel <= 9. Values out side this range will be clamped to this range.
50 | size_t pithy_Compress (const char *uncompressed, size_t uncompressedLength, char *compressedOut, size_t compressedOutLength, int compressionLevel);
51 | int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut, size_t decompressedOutLength);
52 |
53 | size_t pithy_MaxCompressedLength(size_t inputLength);
54 | int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult);
55 |
56 | #endif // _PITHY_H_
57 |
58 | #ifdef __cplusplus
59 | } // extern "C"
60 | #endif
61 |
--------------------------------------------------------------------------------