about summary refs log tree commit diff
path: root/converter/other/srf.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/srf.c')
-rw-r--r--converter/other/srf.c653
1 files changed, 653 insertions, 0 deletions
diff --git a/converter/other/srf.c b/converter/other/srf.c
new file mode 100644
index 00000000..b0f97242
--- /dev/null
+++ b/converter/other/srf.c
@@ -0,0 +1,653 @@
+/*
+ * Funcs for working with SRF (Garmin vehicle) files
+ *
+ * Written by Mike Frysinger <vapier@gentoo.org>
+ * Released into the public domain
+ */
+
+#include <stdio.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "srf.h"
+
+
+static unsigned char
+csumRaw(void * const p,
+       size_t const len) {
+
+    unsigned char retval;
+
+    unsigned int i;
+    unsigned char * c;
+
+    for (i = 0, retval = 0, c = p; i < len; ++i)
+        retval += *c++;
+    
+    return retval;
+}
+
+
+
+static unsigned char
+csumPstring(struct srf_pstring * const pstringP) {
+
+  return
+      csumRaw(&pstringP->len, 4) + csumRaw(pstringP->val, pstringP->len);
+}
+
+
+
+static bool
+readPstring(FILE *               const ifP,
+            struct srf_pstring * const pstringP) {
+
+    size_t bytesRead;
+
+    pm_readlittlelong2u(ifP, &pstringP->len);
+
+    MALLOCARRAY(pstringP->val, pstringP->len + 1);
+
+    if (!pstringP->val)
+        pm_error("Failed to allocate buffer to read %u-byte pstring",
+                 pstringP->len);
+
+    bytesRead = fread(pstringP->val, 1, pstringP->len, ifP);
+    if (bytesRead != pstringP->len)
+        pm_error("Failed to read pstring.  Requested %u bytes, got %u",
+                 (unsigned)pstringP->len,  (unsigned)bytesRead);
+
+    pstringP->val[pstringP->len] = '\0';
+
+    return true;
+}
+
+
+
+static bool
+writePstring(FILE *               const ofP,
+             struct srf_pstring * const pstringP) {
+
+    bool retval;
+    size_t bytesWritten;
+
+    pm_writelittlelongu(ofP, pstringP->len);
+
+    bytesWritten = fwrite(pstringP->val, 1, pstringP->len, ofP);
+
+    if (bytesWritten == pstringP->len)
+        retval = true;
+    else
+        retval = false;
+
+    return retval;
+}
+
+
+
+static size_t
+lenHeader(struct srf_header * const headerP) {
+
+    return 16 + (4 * 4) + 4 + headerP->s578.len
+        + 4 + 4 + headerP->ver.len
+        + 4 + 4 + headerP->prod.len;
+}
+
+
+
+static unsigned char
+csumHeader(struct srf_header * const headerP) {
+
+    return
+        csumRaw(headerP->magic, 16) +
+        csumRaw(&headerP->_int4, 2 * 4) +
+        csumRaw(&headerP->img_cnt, 4) +
+        csumRaw(&headerP->_int5, 4) +
+        csumPstring(&headerP->s578) +
+        csumRaw(&headerP->_int6, 4) +
+        csumPstring(&headerP->ver) +
+        csumRaw(&headerP->_int7, 4) +
+        csumPstring(&headerP->prod);
+}
+
+
+
+static bool
+readHeader(FILE *              const ifP,
+           struct srf_header * const headerP) {
+
+    bool const retval =
+        fread(headerP->magic, 1, 16, ifP) == 16 &&
+        pm_readlittlelong2u(ifP, &headerP->_int4[0]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_int4[1]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->img_cnt) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_int5) == 0 &&
+        readPstring(ifP, &headerP->s578) &&
+        pm_readlittlelong2u(ifP, &headerP->_int6) == 0 &&
+        readPstring(ifP, &headerP->ver) &&
+        pm_readlittlelong2u(ifP, &headerP->_int7) == 0 &&
+        readPstring(ifP, &headerP->prod);
+
+    headerP->magic[16] = '\0';
+
+    return retval;
+}
+
+
+
+static bool
+writeHeader(FILE *              const ofP,
+            struct srf_header * const headerP) {
+
+    return
+        fwrite(headerP->magic, 1, 16, ofP) == 16 &&
+        pm_writelittlelongu(ofP, headerP->_int4[0]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_int4[1]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->img_cnt) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_int5) == 0 &&
+        writePstring(ofP, &headerP->s578) &&
+        pm_writelittlelongu(ofP, headerP->_int6) == 0 &&
+        writePstring(ofP, &headerP->ver) &&
+        pm_writelittlelongu(ofP, headerP->_int7) == 0 &&
+        writePstring(ofP, &headerP->prod);
+}
+
+
+
+static bool
+checkHeader(struct srf_header * const headerP) {
+
+    return
+        streq(headerP->magic, SRF_MAGIC) &&
+        headerP->_int4[0] == 4 &&
+        headerP->_int4[1] == 4 &&
+        /* Should we require img_cnt to be multiple of 2 ? */
+        headerP->img_cnt > 0 &&
+        headerP->_int5 == 5 &&
+        headerP->s578.len == 3 &&
+        strcmp(headerP->s578.val, "578") == 0 &&
+        headerP->_int6 == 6 &&
+        headerP->ver.len == 4 &&
+        /* Allow any headerP->ver value */
+        headerP->_int7 == 7 &&
+        headerP->prod.len == 12;
+    /* Allow any headerP->prod value */
+}
+
+
+
+static size_t
+lenImg(struct srf_img * const imgP) {
+
+    return
+        (4 * 3) + (2 * 2) + (1 * 2) + 2 + 4 +
+        4 + 4 + imgP->alpha.data_len +
+        4 + 4 + imgP->data.data_len;
+}
+
+
+
+static unsigned char
+csumImg(struct srf_img * const imgP) {
+
+    struct srf_img_header * const headerP = &imgP->header;
+    struct srf_img_alpha *  const alphaP  = &imgP->alpha;
+    struct srf_img_data *   const dataP   = &imgP->data;
+
+    return
+        csumRaw(&headerP->_ints, 4 * 3) +
+        csumRaw(&headerP->height, 2) +
+        csumRaw(&headerP->width, 2) +
+        csumRaw(headerP->_bytes, 2) +
+        csumRaw(&headerP->line_len, 2) +
+        csumRaw(&headerP->zeros, 4) +
+        csumRaw(&alphaP->type, 4) +
+        csumRaw(&alphaP->data_len, 4) +
+        csumRaw(alphaP->data, alphaP->data_len) +
+        csumRaw(&dataP->type, 4) +
+        csumRaw(&dataP->data_len, 4) +
+        csumRaw(dataP->data, dataP->data_len);
+}
+
+
+
+static bool
+readImgHeader(FILE *                  const ifP,
+              struct srf_img_header * const headerP) {
+    return
+        pm_readlittlelong2u(ifP, &headerP->_ints[0]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_ints[1]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_ints[2]) == 0 &&
+        pm_readlittleshortu(ifP, &headerP->height) == 0 &&
+        pm_readlittleshortu(ifP, &headerP->width) == 0 &&
+        fread(&headerP->_bytes[0], 1, 1, ifP) == 1 &&
+        fread(&headerP->_bytes[1], 1, 1, ifP) == 1 &&
+        pm_readlittleshortu(ifP, &headerP->line_len) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->zeros) == 0;
+}
+
+
+
+static bool
+writeImgHeader(FILE *                  const ofP,
+               struct srf_img_header * const headerP) {
+    return
+        pm_writelittlelongu(ofP, headerP->_ints[0]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_ints[1]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_ints[2]) == 0 &&
+        pm_writelittleshortu(ofP, headerP->height) == 0 &&
+        pm_writelittleshortu(ofP, headerP->width) == 0 &&
+        fwrite(&headerP->_bytes[0], 1, 1, ofP) == 1 &&
+        fwrite(&headerP->_bytes[1], 1, 1, ofP) == 1 &&
+        pm_writelittleshortu(ofP, headerP->line_len) == 0 &&
+        pm_writelittlelongu(ofP, headerP->zeros) == 0;
+}
+
+
+
+static bool
+checkImgHeader(struct srf_img_header * const headerP) {
+
+    return
+        headerP->_ints[0] == 0 &&
+        headerP->_ints[1] == 16 &&
+        headerP->_ints[2] == 0 &&
+        headerP->_bytes[0] == 16 &&
+        headerP->_bytes[1] == 8 &&
+        headerP->line_len == headerP->width * 2 &&
+        headerP->zeros == 0;
+}
+
+
+
+static bool
+readImgAlpha(FILE *                 const ifP,
+                   struct srf_img_alpha * const alphaP) {
+
+    bool retval;
+
+    pm_readlittlelong2u(ifP, &alphaP->type);
+    pm_readlittlelong2u(ifP, &alphaP->data_len);
+
+    MALLOCARRAY(alphaP->data, alphaP->data_len);
+
+    if (!alphaP->data)
+        retval = false;
+    else {
+        size_t bytesRead;
+
+        bytesRead = fread(alphaP->data, 1, alphaP->data_len, ifP);
+        retval = (bytesRead ==alphaP->data_len);
+    }
+    return retval;
+}
+
+
+
+static bool
+writeImageAlpha(FILE *                 const ofP,
+                    struct srf_img_alpha * const alphaP) {
+
+    return
+        pm_writelittlelongu(ofP, alphaP->type) == 0 &&
+        pm_writelittlelongu(ofP, alphaP->data_len) == 0 &&
+        fwrite(alphaP->data, 1, alphaP->data_len, ofP) == alphaP->data_len;
+}
+
+
+
+static bool
+checkImgAlpha(struct srf_img_alpha * const alphaP) {
+
+    return (alphaP->type == 11);
+}
+
+
+
+static bool
+readImgData(FILE *                const ifP,
+                  struct srf_img_data * const dataP) {
+
+    bool retval;
+
+    pm_readlittlelong2u(ifP, &dataP->type);
+    pm_readlittlelong2u(ifP, &dataP->data_len);
+
+    MALLOCARRAY(dataP->data, dataP->data_len / 2);
+
+    if (!dataP->data)
+        retval = false;
+    else {
+        size_t bytesRead;
+        bytesRead = fread(dataP->data, 2, dataP->data_len / 2, ifP);
+
+        retval = (bytesRead == dataP->data_len / 2);
+    }
+    return retval;
+}
+
+
+
+static bool
+writeImgData(FILE *                const ofP,
+                   struct srf_img_data * const dataP) {
+
+    return
+        pm_writelittlelongu(ofP, dataP->type) == 0 &&
+        pm_writelittlelongu(ofP, dataP->data_len) == 0 &&
+        fwrite(dataP->data, 2, dataP->data_len / 2, ofP)
+        == dataP->data_len / 2;
+}
+
+
+
+static bool
+checkImgData(struct srf_img_data * const dataP) {
+  return dataP->type == 1;
+}
+
+
+
+static bool
+readImg(FILE *           const ifP,
+             bool             const verbose,
+             uint32_t         const i,
+             struct srf_img * const imgP) {
+
+    if (!readImgHeader(ifP, &imgP->header))
+        pm_error("short srf image %u header", i);
+    if (!checkImgHeader(&imgP->header))
+        pm_error("invalid srf image %u header", i);
+
+    if (verbose)
+        pm_message("reading srf 16-bit RGB %ux%u image %u",
+                   imgP->header.width, imgP->header.height, i);
+
+    if (!readImgAlpha(ifP, &imgP->alpha))
+        pm_error("short srf image %u alpha mask", i);
+    if (!checkImgAlpha(&imgP->alpha))
+        pm_error("invalid srf image %u alpha mask", i);
+
+    if (!readImgData(ifP, &imgP->data))
+        pm_error("short srf image %u data", i);
+    if (!checkImgData(&imgP->data))
+        pm_error("invalid srf image %u data", i);
+
+    return true;
+}
+
+
+
+static bool
+writeImg(FILE *           const ofP,
+              uint32_t         const i,
+              struct srf_img * const imgP) {
+
+    if (!checkImgHeader(&imgP->header))
+        pm_error("invalid srf image %u header", i);
+    if (!writeImgHeader(ofP, &imgP->header))
+        pm_error("short srf image %u header", i);
+
+    if (!checkImgAlpha(&imgP->alpha))
+        pm_error("invalid srf image %u alpha mask", i);
+    if (!writeImageAlpha(ofP, &imgP->alpha))
+        pm_error("short srf image %u alpha mask", i);
+
+    if (!checkImgData(&imgP->data))
+        pm_error("invalid srf image %u data", i);
+    if (!writeImgData(ofP, &imgP->data))
+        pm_error("short srf image %u data", i);
+
+    return true;
+}
+
+
+
+static uint8_t
+csum(struct srf * const srfP,
+     size_t       const padLen) {
+/*----------------------------------------------------------------------------
+   The sum of everything in the SRF image except the checksum byte.  The
+   checksum byte is supposed to be the arithmetic opposite of this so that the
+   sum of everything is zero.
+-----------------------------------------------------------------------------*/
+    unsigned char retval;
+    unsigned int i;
+
+    retval = csumHeader(&srfP->header);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i)
+        retval += csumImg(&srfP->imgs[i]);
+    
+    for (i = 0; i < padLen; ++i)
+        retval += 0xff;
+    
+    return retval;
+}
+
+
+
+void
+srf_read(FILE *       const ifP,
+         bool         const verbose,
+         struct srf * const srfP) {
+
+    uint8_t       trialCsum;
+    size_t        padLen;
+    unsigned char pad[256];
+    unsigned int  i;
+
+    if (!readHeader(ifP, &srfP->header))
+        pm_error("short srf header");
+    if (!checkHeader(&srfP->header))
+        pm_error("invalid srf header");
+
+    if (verbose)
+        pm_message("reading srf ver %s with prod code %s and %u images",
+                   srfP->header.ver.val, srfP->header.prod.val,
+                   srfP->header.img_cnt);
+
+    MALLOCARRAY(srfP->imgs, srfP->header.img_cnt);
+
+    if (!srfP->imgs)
+        pm_error("Could not allocate memory for %u images",
+                 srfP->header.img_cnt);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i)
+        if (!readImg(ifP, verbose, i, &srfP->imgs[i]))
+            pm_error("invalid srf image %u", i);
+
+    padLen = fread(pad, 1, sizeof(pad), ifP);
+    if (!feof(ifP)) {
+        pm_errormsg("excess data at end of file");
+        return;
+    }
+
+    trialCsum = csum(srfP, 0);  /* initial value */
+    for (i = 0; i < padLen; ++i)
+        trialCsum += pad[i];
+    if (trialCsum != 0)
+        pm_errormsg("checksum does not match");
+}
+
+
+
+void
+srf_write(FILE *       const ofP,
+          struct srf * const srfP) {
+
+    uint8_t      srfCsum;    /* checksum value in SRF image */
+    size_t       padLen;
+    unsigned int i;
+    size_t       bytesWritten;
+
+    padLen = 1;  /* initial value */
+
+    if (!checkHeader(&srfP->header))
+        pm_error("invalid srf header");
+    if (!writeHeader(ofP, &srfP->header))
+        pm_error("write srf header");
+    padLen += lenHeader(&srfP->header);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i) {
+        if (!writeImg(ofP, i, &srfP->imgs[i]))
+            pm_error("invalid srf image %u", i);
+        padLen += lenImg(&srfP->imgs[i]);
+    }
+
+    /* Pad to 256 bytes */
+    padLen = 256 - (padLen % 256);
+    if (padLen) {
+        char * d;
+        size_t bytesWritten;
+
+        MALLOCARRAY(d, padLen);
+
+        if (!d)
+            pm_error("Could not allocate memory for %u bytes of padding",
+                     (unsigned)padLen);
+
+        memset(d, 0xff, padLen);
+
+        bytesWritten = fwrite(d, 1, padLen, ofP);
+
+        if (bytesWritten != padLen)
+            pm_error("unable to 0xff pad file");
+
+        free(d);
+    }
+
+    /* Write out checksum byte */
+    srfCsum = 0xff - csum(srfP, padLen) + 1;
+    bytesWritten = fwrite(&srfCsum, 1, 1, ofP);
+    if (bytesWritten != 1)
+        pm_error("unable to write checksum");
+}
+
+
+
+static void
+freeImg(struct srf_img * const imgP) {
+
+    free(imgP->alpha.data);
+    free(imgP->data.data);
+}
+
+
+
+void
+srf_term(struct srf * const srfP) {
+
+    unsigned int i;
+    
+    free(srfP->header.s578.val);
+    free(srfP->header.ver.val);
+    free(srfP->header.prod.val);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i)
+        freeImg(&srfP->imgs[i]);
+
+    free(srfP->imgs);
+}
+
+
+
+static void
+srf_img_init(struct srf_img * const imgP,
+             uint16_t         const width,
+             uint16_t         const height) {
+
+    struct srf_img_header * const headerP = &imgP->header;
+    struct srf_img_alpha *  const alphaP  = &imgP->alpha;
+    struct srf_img_data *   const dataP   = &imgP->data;
+
+    headerP->_ints[0]   = 0;
+    headerP->_ints[1]   = 16;
+    headerP->_ints[2]   = 0;
+    headerP->height     = height;
+    headerP->width      = width;
+    headerP->_bytes[0]  = 16;
+    headerP->_bytes[1]  = 8;
+    headerP->line_len   = width * 2;
+    headerP->zeros      = 0;
+
+    alphaP->type     = 11;
+    alphaP->data_len = height * width;
+    MALLOCARRAY(alphaP->data, alphaP->data_len);
+
+    if (!alphaP->data)
+        pm_error("Could not allocate buffer for %u bytes of alpha",
+                 alphaP->data_len);
+
+    dataP->type     = 1;
+    dataP->data_len = height * width * 2;
+    MALLOCARRAY(dataP->data, dataP->data_len / 2);
+
+    if (!dataP->data)
+        pm_error("Could not allocation buffer for %u units of data",
+                 dataP->data_len);
+}
+
+
+
+static void
+initPstring(struct srf_pstring * const pstringP,
+            const char *         const s) {
+
+    pstringP->len = strlen(s);
+
+    MALLOCARRAY(pstringP->val, pstringP->len + 1);
+
+    if (!pstringP->val)
+        pm_error("Could not allocate memory for string of length %u",
+                 pstringP->len);
+
+    memcpy(pstringP->val, s, pstringP->len + 1);
+}
+
+
+
+void
+srf_init(struct srf * const srfP) {
+
+    struct srf_header * const headerP = &srfP->header;
+
+    strcpy(headerP->magic, SRF_MAGIC);
+    headerP->_int4[0] = 4;
+    headerP->_int4[1] = 4;
+    headerP->img_cnt = 0;
+    headerP->_int5 = 5;
+    initPstring(&headerP->s578, "578");
+    headerP->_int6 = 6;
+    initPstring(&headerP->ver, "1.00");
+    headerP->_int7 = 7;
+    initPstring(&headerP->prod, "006-D0578-XX");
+
+    srfP->imgs = NULL;
+}
+
+
+
+void
+srf_create_img(struct srf * const srfP,
+               uint16_t     const width,
+               uint16_t     const height) {
+/*----------------------------------------------------------------------------
+   Add an "image" to the SRF.  An image is a horizontal series of 36 
+   square frames, each showing a different angle view of an object, 10
+   degrees about.  At least that's what it's supposed to be.  We don't
+   really care -- it's just an arbitrary rectangular raster image to us.
+-----------------------------------------------------------------------------*/
+    
+    ++srfP->header.img_cnt;
+
+    REALLOCARRAY(srfP->imgs, srfP->header.img_cnt);
+
+    if (!srfP->imgs)
+        pm_error("Could not allocate memory for %u images",
+                 srfP->header.img_cnt);
+
+    srf_img_init(&srfP->imgs[srfP->header.img_cnt-1], width, height);
+}
+