zrle

Compress zeros using Run Length Encoding
git clone https://noulin.net/git/zrle.git
Log | Files | Refs | LICENSE

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