💾 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

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

zrle

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