diff tools/lib64gfx.c @ 1707:a0986cfd6f9d

More consistently use DMGrowBuf in the lib64gfx APIs, and implement "backwards" RLE decoding and encoding (optionally regards input/output). Not tested very much yet, there may be bugs.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 05 Jun 2018 21:58:10 +0300
parents 1036b0dcccb5
children 1f0fac3af8e3
line wrap: on
line diff
--- a/tools/lib64gfx.c	Tue Jun 05 19:57:08 2018 +0300
+++ b/tools/lib64gfx.c	Tue Jun 05 21:58:10 2018 +0300
@@ -282,7 +282,7 @@
 }
 
 
-void dmGenericRLEAnalyze(const Uint8 *buf, const size_t len, DMCompParams *cfg)
+void dmGenericRLEAnalyze(const DMGrowBuf *buf, DMCompParams *cfg)
 {
 #define DM_STAT_MAX 256
     size_t *stats;
@@ -292,8 +292,8 @@
         return;
 
     // Get statistics on the data
-    for (size_t offs = 0; offs < len; offs++)
-        stats[buf[offs]]++;
+    for (size_t offs = 0; offs < buf->len; offs++)
+        stats[buf->data[offs]]++;
 
     // According to compression type ..
     switch (cfg->type)
@@ -301,7 +301,7 @@
         case DM_COMP_RLE_MARKER:
             {
                 size_t selected = 0,
-                    smallest = len;
+                    smallest = buf->len;
 
                 // Find least used byte value
                 for (size_t n = 0; n < DM_STAT_MAX; n++)
@@ -327,63 +327,83 @@
 }
 
 
-int dmDecodeGenericRLE(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg)
+static void dmSetupRLEBuffers(DMGrowBuf *dst, DMGrowBuf *src, const DMCompParams *cfg)
+{
+    if (cfg->flags & DM_RLE_BACKWARDS_INPUT)
+    {
+        src->offs = src->len - 1;
+        src->backwards = TRUE;
+    }
+
+    if (cfg->flags & DM_RLE_BACKWARDS_OUTPUT)
+    {
+        dst->backwards = TRUE;
+        dst->offs = dst->size - 1;
+    }
+}
+
+
+int dmDecodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *psrc, const DMCompParams *cfg)
 {
     int res;
+    Uint8 tmp1, tmp2, tmp3, data;
+    DMGrowBuf src;
 
-    // Perform RLE decode
-    while (src < srcEnd)
+    // As we need to modify the offs, etc. but not the data,
+    // we will just make a shallow copy of the DMGrowBuf struct
+    dmGrowBufConstCopy(&src, psrc);
+    dmSetupRLEBuffers(dst, &src, cfg);
+
+    while (dmGrowBufGetU8(&src, &data))
     {
-        Uint8 data = *src++;
-        int count = 1;
+        unsigned int count = 1;
 
         if (cfg->type == DM_COMP_RLE_MARKER)
         {
             // A simple marker byte RLE variant: [Marker] [count] [data]
             if (data == cfg->rleMarkerB && (cfg->flags & DM_RLE_BYTE_RUNS))
             {
-                if (srcEnd - src + 1 < 2)
+                if (!dmGrowBufGetU8(&src, &tmp1) ||
+                    !dmGrowBufGetU8(&src, &tmp2))
                 {
                     res = DMERR_INVALID_DATA;
-                    goto err;
+                    goto out;
                 }
-
                 switch (cfg->flags & DM_RLE_ORDER_MASK)
                 {
                     case DM_RLE_ORDER_1:
-                        count = src[0];
-                        data = src[1];
+                        count = tmp1;
+                        data  = tmp2;
                         break;
 
                     case DM_RLE_ORDER_2:
-                        data = src[0];
-                        count = src[1];
+                        data  = tmp1;
+                        count = tmp2;
                         break;
                 }
-                src += 2;
             }
             else
             if (data == cfg->rleMarkerW && (cfg->flags & DM_RLE_WORD_RUNS))
             {
-                if (srcEnd - src + 1 < 3)
+                if (!dmGrowBufGetU8(&src, &tmp1) ||
+                    !dmGrowBufGetU8(&src, &tmp2) ||
+                    !dmGrowBufGetU8(&src, &tmp3))
                 {
                     res = DMERR_INVALID_DATA;
-                    goto err;
+                    goto out;
                 }
-
                 switch (cfg->flags & DM_RLE_ORDER_MASK)
                 {
                     case DM_RLE_ORDER_1:
-                        count = (src[1] << 8) | src[0];
-                        data = src[2];
+                        count = (tmp2 << 8) | tmp1;
+                        data = tmp3;
                         break;
 
                     case DM_RLE_ORDER_2:
-                        data = src[0];
-                        count = (src[2] << 8) | src[1];
+                        data = tmp1;
+                        count = (tmp3 << 8) | tmp2;
                         break;
                 }
-                src += 3;
             }
         }
         else
@@ -393,14 +413,14 @@
             // and the lower bits contain the count: [Mask + count] [data]
             if ((data & cfg->rleMarkerMask) == cfg->rleMarkerBits)
             {
-                if (srcEnd - src + 1 < 1)
+                if (!dmGrowBufGetU8(&src, &tmp1))
                 {
                     res = DMERR_INVALID_DATA;
-                    goto err;
+                    goto out;
                 }
 
                 count = data & cfg->rleCountMask;
-                data = *src++;
+                data = tmp1;
             }
         }
 
@@ -409,29 +429,29 @@
             if (!dmGrowBufPutU8(dst, data))
             {
                 res = DMERR_MALLOC;
-                goto err;
+                goto out;
             }
         }
     }
 
     res = DMERR_OK;
 
-err:
+out:
     return res;
 }
 
 
-int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg)
+int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg)
 {
     int res;
     if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK)
         return res;
 
-    return dmDecodeGenericRLE(dst, src, srcEnd, cfg);
+    return dmDecodeGenericRLE(dst, src, cfg);
 }
 
 
-static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, int count, const DMCompParams *cfg)
+static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, unsigned int count, const DMCompParams *cfg)
 {
     BOOL copyOnly = FALSE;
 
@@ -514,14 +534,20 @@
 }
 
 
-int dmEncodeGenericRLE(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg)
+int dmEncodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *psrc, const DMCompParams *cfg)
 {
-    // Perform RLE encoding
-    int count = 0, prev = -1;
-    while (src < srcEnd)
+    DMGrowBuf src;
+    unsigned int count = 0;
+    int prev = -1;
+    Uint8 data;
+
+    // As we need to modify the offs, etc. but not the data,
+    // we will just make a shallow copy of the DMGrowBuf struct
+    dmGrowBufConstCopy(&src, psrc);
+    dmSetupRLEBuffers(dst, &src, cfg);
+
+    while (dmGrowBufGetU8(&src, &data))
     {
-        Uint8 data = *src++;
-
         // If new data byte is different, or we exceed the rleMaxCount
         // for the active runs mode(s) .. then encode the run.
         if (data != prev ||
@@ -546,17 +572,17 @@
 
 err:
      return dmError(DMERR_MALLOC,
-        "Could reallocate memory for RLE encoding buffer.\n");
+        "Could not reallocate memory for RLE encoding buffer.\n");
 }
 
 
-int dmEncodeGenericRLEAlloc(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg)
+int dmEncodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg)
 {
     int res;
     if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK)
         return res;
 
-    return dmEncodeGenericRLE(dst, src, srcEnd, cfg);
+    return dmEncodeGenericRLE(dst, src, cfg);
 }
 
 
@@ -707,12 +733,11 @@
 }
 
 
-int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf,
-    const size_t len, const DMC64ImageFormat *fmt)
+int dmC64DecodeGenericBMP(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt)
 {
     int res = DMERR_OK;
 
-    if (buf == NULL || img == NULL || fmt == NULL)
+    if (buf == NULL || buf->data == NULL || img == NULL || fmt == NULL)
         return DMERR_NULLPTR;
 
     // Clear the image structure, set basics
@@ -751,15 +776,16 @@
         }
 
         // Is the operation inside the bounds?
-        if (op->offs + size > len + 1)
+        if (op->offs + size > buf->len + 1)
         {
             return dmError(DMERR_INVALID_DATA,
                 "Decode DATA out of bounds, op #%d type=%d, subj=%d, offs=%d ($%04x), "
                 "bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                i, op->type, op->subject, op->offs, op->offs, op->bank, size, size, len, len);
+                i, op->type, op->subject, op->offs, op->offs, op->bank,
+                size, size, buf->len, buf->len);
         }
 
-        src = buf + op->offs;
+        src = buf->data + op->offs;
 
         // Perform operation
         switch (op->type)
@@ -781,7 +807,7 @@
                             return dmError(DMERR_MALLOC,
                                 "Could not allocate '%s' block! "
                                 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                                blkname, i, op->offs, op->offs, op->bank, size, size, len, len);
+                                blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
                         }
                         switch (op->type)
                         {
@@ -832,7 +858,7 @@
                         return dmError(DMERR_INTERNAL,
                             "Unhandled subject %d in "
                             "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                            op->subject, i, op->offs, op->offs, op->bank, size, size, len, len);
+                            op->subject, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
                 }
                 break;
 
@@ -854,7 +880,7 @@
                         return dmError(DMERR_INTERNAL,
                             "Unhandled DO_CHAR_CFG mode %d in ",
                             "op #%d, bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                            op->subject, i, op->bank, size, size, len, len);
+                            op->subject, i, op->bank, size, size, buf->len, buf->len);
                 }
                 break;
 
@@ -864,14 +890,14 @@
                     return dmError(DMERR_INTERNAL,
                         "Decode op is a function, but function ptr is NULL: "
                         "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                        i, op->offs, op->offs, op->bank, size, size, len, len);
+                        i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
                 }
-                if (!op->decFunction(img, op, buf, len, fmt))
+                if (!op->decFunction(img, op, buf, fmt))
                 {
                     return dmError(DMERR_INTERNAL,
                         "Decode op custom function failed: op #%d, "
                         "offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                        i, op->offs, op->offs, op->bank, size, size, len, len);
+                        i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
                 }
                 break;
         }
@@ -935,7 +961,7 @@
             res = dmError(DMERR_INVALID_DATA,
                 "Encode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), "
                 "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n",
-                i, op->type, op->offs, op->offs, op->bank, size, size, op->size, op->size);
+                i, op->type, op->offs, op->offs, op->bank, size, size, buf->size, buf->size);
             goto err;
         }
 
@@ -949,9 +975,6 @@
             goto err;
         }
 
-        if (chksize > buf->len)
-            buf->len = chksize;
-
         // Perform operation
         Uint8 *dst = buf->data + buf->offs + op->offs;
         switch (op->type)
@@ -967,35 +990,31 @@
                     case DS_CHAR_DATA:
                     case DS_EXTRA_DATA:
                         dmC64GetOpMemBlockAndName(img, op->subject, op->bank, &blk, &blkname);
-                        if (blk->data == NULL)
-                        {
-                            res = dmError(DMERR_NULLPTR,
-                                "'%s' block is NULL in "
-                                "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                                blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
-                            goto err;
-                        }
-                        if (size > blk->size)
-                        {
-                            res = dmError(DMERR_INTERNAL,
-                                "'%s' size mismatch %d <> %d in "
-                                "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                                blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
-                            goto err;
-                        }
                         switch (op->type)
                         {
                             case DO_COPY:
+                                if (blk->data == NULL)
+                                {
+                                    res = dmError(DMERR_NULLPTR,
+                                        "'%s' block is NULL in "
+                                        "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
+                                        blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
+                                    goto err;
+                                }
+                                if (size > blk->size)
+                                {
+                                    res = dmError(DMERR_INTERNAL,
+                                        "'%s' size mismatch %d <> %d in "
+                                        "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
+                                        blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
+                                    goto err;
+                                }
                                 memcpy(dst, blk->data, size);
                                 break;
 
                             case DO_SET_MEM:
-                                // This operation makes no sense
-                                res = dmError(DMERR_INTERNAL,
-                                    "'%s' block DO_SET_MEM (which makes no sense) in "
-                                    "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                                    blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
-                                goto err;
+                                // This operation makes no sense, so do nothing
+                                break;
 
                             case DO_SET_OP:
                                 memset(dst, op->offs, size);
@@ -1026,12 +1045,8 @@
                                 break;
 
                             case DO_SET_OP:
-                                // This operation makes no sense
-                                res = dmError(DMERR_INTERNAL,
-                                    "'%s' block DO_SET_OP (which makes no sense) in "
-                                    "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                                    blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len);
-                                goto err;
+                                // Do nothing in this case
+                                break;
                         }
                         break;
 
@@ -1234,11 +1249,13 @@
 }
 
 
-int dmC64DecodeBMP(DMC64Image **img, const Uint8 *buf, const size_t len,
+int dmC64DecodeBMP(DMC64Image **img, const DMGrowBuf *buf,
     const size_t probeOffs, const size_t loadOffs,
     const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced)
 {
-    if (img == NULL)
+    DMGrowBuf tmp;
+
+    if (img == NULL || buf == NULL)
         return DMERR_NULLPTR;
 
     // Check for forced format
@@ -1247,19 +1264,21 @@
     else
     {
         // Nope, perform a generic probe
-        if (probeOffs >= len)
+        if (probeOffs >= buf->len)
             return DMERR_OUT_OF_DATA;
 
-        if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE)
+        dmGrowBufCreateFromOffs(&tmp, buf, probeOffs);
+        if (dmC64ProbeBMP(tmp.data, tmp.len, fmt) == DM_PROBE_SCORE_FALSE)
             return DMERR_NOT_SUPPORTED;
     }
 
-    if (loadOffs >= len)
+    if (loadOffs >= tmp.len)
         return DMERR_INVALID_ARGS;
 
     if (*fmt == NULL)
         return DMERR_NOT_SUPPORTED;
 
+    // Format supports only reading?
     if (((*fmt)->flags & DM_FMT_RD) == 0)
         return DMERR_NOT_SUPPORTED;
 
@@ -1267,11 +1286,13 @@
     if ((*img = dmC64ImageAlloc(*fmt)) == NULL)
         return DMERR_MALLOC;
 
+    dmGrowBufCreateFromOffs(&tmp, buf, loadOffs);
+
     // Decode the bitmap to memory layout
     if ((*fmt)->decode != NULL)
-        return (*fmt)->decode(*img, buf + loadOffs, len - loadOffs, *fmt);
+        return (*fmt)->decode(*img, &tmp, *fmt);
     else
-        return dmC64DecodeGenericBMP(*img, buf + loadOffs, len - loadOffs, *fmt);
+        return dmC64DecodeGenericBMP(*img, &tmp, *fmt);
 }