💾 Archived View for gmi.noulin.net › gitRepositories › zrle › file › zrle.c.gmi captured on 2024-08-18 at 18:56:47. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
zrle.c (5726B)
1 2 #include "libsheepyObject.h" 3 #include "zrle.h" 4 5 zrlebuft zrle(void *buf, size_t len) { 6 zrlebuft r; 7 8 // allocate compressed buffer, twice bigger than b 9 // initialize state 10 // copy bytes 11 // replace anchors with 0xfc+anchor 12 // copy 13 // zero is found, count zeros 14 // check for buffer overflow, error when overflow 15 // zero is found again, count zeros 16 // check if the zero count exceeds the max count (0xfb) 17 // zero count exceeded max, write 0xfc 0xfb in compressed buffer and start a new zero count 18 // non zero is found 19 // when count is less 3, write 0 in compressed buffer 20 // when count is 3, write 0xfe in compressed buffer 21 // when count is 7, write 0xfd in compressed buffer 22 // write 0xfc zcount-4 in compressed buffer 23 // copy byte 24 // when state is ZCOUNT at the end, write last zero string 25 // realloc to fit compress buffer size to data 26 27 if (!buf || len < 3) { 28 // buffer too small 29 r.buf = NULL; 30 return r; 31 } 32 33 u8 *b = buf; 34 35 // allocate compressed buffer, twice bigger than b 36 // (compressed buffer should be smaller than source) 37 r.buf = malloc(len*2); 38 39 // initialize state 40 enum {COPY, ZCOUNT}; 41 u8 state = COPY; 42 43 // offset of first zero in b in current zero string 44 u32 src; 45 // offset in compressed buffer 46 u32 dst = 0; 47 // zero count in current zero string 48 u8 zcount; 49 range(i, len) { 50 if (state == ZCOUNT) { 51 if (!b[i]) { 52 // zero is found again, count zeros 53 zcount++; 54 // check if the zero count exceeds the max count (0xfb) 55 if (zcount-4 == 0xfc) { 56 // zero count exceeded max, write 0xfc 0xfb in compressed buffer and start a new zero count 57 r.buf[dst++] = 0xfc; 58 r.buf[dst++] = 0xfb; 59 zcount = 1; 60 } 61 goto next; 62 } 63 else { 64 // when count is less 3, write 0 in compressed buffer 65 if (zcount < 3) { 66 range(j, zcount) 67 r.buf[dst++] = 0; 68 } 69 // when count is 3, write 0xfe in compressed buffer 70 else if (zcount == 3) 71 r.buf[dst++] = 0xfe; 72 // when count is 7, write 0xfd in compressed buffer 73 else if (zcount == 7) 74 r.buf[dst++] = 0xfd; 75 // write 0xfc zcount-4 in compressed buffer 76 else { 77 r.buf[dst++] = 0xfc; 78 r.buf[dst++] = zcount-4; 79 } 80 // copy byte 81 r.buf[dst++] = b[i]; 82 state = COPY; 83 goto next; 84 } 85 } 86 if (state == COPY) { 87 // copy bytes 88 if (b[i]) { 89 switch (b[i]) { 90 case 0xfe: 91 case 0xfd: 92 case 0xfc: 93 // replace anchors with 0xfc+anchor 94 r.buf[dst++] = 0xfc; 95 r.buf[dst++] = b[i]; 96 break; 97 default: 98 // copy 99 r.buf[dst++] = b[i]; 100 } 101 } 102 else { 103 // zero is found, count zeros 104 zcount = 1; 105 src = i; 106 state = ZCOUNT; 107 } 108 } 109 110 next: 111 // check for buffer overflow 112 if (dst > 2*len-2) { 113 // end of buffer - stop error 114 free(r.buf); 115 r.buf = NULL; 116 break; 117 } 118 } 119 120 // when state is ZCOUNT at the end, write last zero string 121 if (state == ZCOUNT) { 122 // when count is less 3, write 0 in compressed buffer 123 if (zcount < 3) { 124 range(j, zcount) 125 r.buf[dst++] = 0; 126 } 127 // when count is 3, write 0xfe in compressed buffer 128 else if (zcount == 3) 129 r.buf[dst++] = 0xfe; 130 // when count is 7, write 0xfd in compressed buffer 131 else if (zcount == 7) 132 r.buf[dst++] = 0xfd; 133 // write 0xfc zcount-4 in compressed buffer 134 else { 135 r.buf[dst++] = 0xfc; 136 r.buf[dst++] = zcount-4; 137 } 138 } 139 140 r.count = dst; 141 // realloc to fit compress buffer size to data 142 r.buf = realloc(r.buf, dst); 143 144 return r; 145 } 146 147 zrlebuft dezrle(void *buf, size_t len) { 148 zrlebuft r; 149 150 // initialize state 151 // not an anchor, copy byte 152 // expand anchors 153 // reallocate when there is buffer overflow 154 // when count >= 0xfc, copy count as a byte 155 // check for buffer overflow when expanding 156 // realloc to fit buffer size to data 157 158 // initialize state 159 u8 *b = buf; 160 r.buf = malloc(len*2); 161 u32 blen = len*2; 162 u32 dst = 0; 163 enum {COPY, EXPAND}; 164 u8 state = COPY; 165 166 range(i, len) { 167 // expand anchors 168 if (state == EXPAND) { 169 // when count >= 0xfc, copy count as a byte 170 if (b[i] >= 0xfc) 171 r.buf[dst++] = b[i]; 172 else { 173 // check for buffer overflow when expanding 174 if (dst+(u16)(b[i])+4 >= blen) { 175 r.buf = realloc(r.buf, 2*blen + (u16)(b[i])+4); 176 blen = 2*blen + (u16)(b[i])+4; 177 } 178 range(j, (u16)(b[i])+4) 179 r.buf[dst++] = 0; 180 } 181 state = COPY; 182 goto next; 183 } 184 // not an anchor, copy byte 185 if ((b[i] != 0xfe) and (b[i] != 0xfd) and (b[i] != 0xfc)) { 186 r.buf[dst++] = b[i]; 187 } 188 // expand anchors 189 if (b[i] == 0xfe) { 190 if (dst+3 >= blen) { 191 r.buf = realloc(r.buf, 2*blen + 3); 192 blen = 2*blen + 3; 193 } 194 range(j, 3) 195 r.buf[dst++] = 0; 196 } 197 if (b[i] == 0xfd) { 198 if (dst+7 >= blen) { 199 r.buf = realloc(r.buf, 2*blen + 7); 200 blen = 2*blen + 7; 201 } 202 range(j, 7) 203 r.buf[dst++] = 0; 204 } 205 if (b[i] == 0xfc) { 206 state = EXPAND; 207 } 208 next: 209 // reallocate when there is buffer overflow 210 if (dst >= blen) { 211 r.buf = realloc(r.buf, 2*blen); 212 blen = 2*blen; 213 } 214 } 215 216 r.count = dst; 217 // realloc to fit buffer size to data 218 r.buf = realloc(r.buf, dst); 219 220 return r; 221 } 222 223 bool checkLibsheepyVersionZrle(const char *currentLibsheepyVersion) { 224 return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION); 225 } 226