summaryrefslogtreecommitdiff
path: root/src/stringcode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stringcode.c')
-rw-r--r--src/stringcode.c783
1 files changed, 783 insertions, 0 deletions
diff --git a/src/stringcode.c b/src/stringcode.c
new file mode 100644
index 0000000..d3cc4f8
--- /dev/null
+++ b/src/stringcode.c
@@ -0,0 +1,783 @@
+/*====================================================================*
+ - Copyright (C) 2001 Leptonica. All rights reserved.
+ -
+ - Redistribution and use in source and binary forms, with or without
+ - modification, are permitted provided that the following conditions
+ - are met:
+ - 1. Redistributions of source code must retain the above copyright
+ - notice, this list of conditions and the following disclaimer.
+ - 2. Redistributions in binary form must reproduce the above
+ - copyright notice, this list of conditions and the following
+ - disclaimer in the documentation and/or other materials
+ - provided with the distribution.
+ -
+ - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
+ - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *====================================================================*/
+
+/*
+ * stringcode.c
+ *
+ * Generation of code for storing and extracting serializable
+ * leptonica objects (such as pixa, recog, ...).
+ *
+ * The input is a set of files with serialized data.
+ * The output is two files, that must be compiled and linked:
+ * - autogen.*.c: code for base64 unencoding the strings and
+ * deserializing the result.
+ * - autogen.*.h: function prototypes and base64 encoded strings
+ * of the input data
+ *
+ * This should work for any data structures in leptonica that have
+ * *Write() and *Read() serialization functions. An array of 20
+ * of these, including the Pix, is given below. (The Pix is a special
+ * case, because it is serialized by standardized compression
+ * techniques, instead of a file format determined by leptonica.)
+ *
+ * Each time the generator function is invoked, three sets of strings are
+ * produced, which are written into their respective string arrays:
+ * - string of serialized, gzipped and base 64 encoded data
+ * - case string for base64 decoding, gunzipping and deserialization,
+ * to return the data struct in memory
+ * - description string for selecting which struct to return
+ * To create the two output files, a finalize function is invoked.
+ *
+ * There are two ways to do this, both shown in prog/autogentest1.c.
+ * - Explicitly call strcodeGenerate() for each file with the
+ * serialized data structure, followed by strcodeFinalize().
+ * - Put the filenames of the serialized data structures in a file,
+ * and call strcodeCreateFromFile().
+ *
+ * The generated code in autogen.X.c and autogen.X.h (where X is an
+ * integer supplied to strcodeCreate()) is then compiled, and the
+ * original data can be regenerated using the function l_autodecode_X().
+ * A test example is found in the two prog files:
+ * prog/autogentest1.c -- generates autogen.137.c, autogen.137.h
+ * prog/autogentest2.c -- uses autogen.137.c, autogen.137.h
+ * In general, the generator (e.g., autogentest1) would be compiled and
+ * run before compiling and running the application (e.g., autogentest2).
+ *
+ * L_STRCODE *strcodeCreate()
+ * static void strcodeDestroy() (called as part of finalize)
+ * void strcodeCreateFromFile()
+ * l_int32 strcodeGenerate()
+ * void strcodeFinalize()
+ * l_int32 l_getStructnameFromFile() (useful externally)
+ *
+ * Static helpers
+ * static l_int32 l_getIndexFromType()
+ * static l_int32 l_getIndexFromStructname()
+ * static l_int32 l_getIndexFromFile()
+ * static char *l_genDataString()
+ * static char *l_genCaseString()
+ * static char *l_genDescrString()
+ */
+
+#include <string.h>
+#include "allheaders.h"
+#include "stringcode.h"
+
+#define TEMPLATE1 "stringtemplate1.txt" /* for assembling autogen.*.c */
+#define TEMPLATE2 "stringtemplate2.txt" /* for assembling autogen.*.h */
+
+ /* Associations between names and functions */
+struct L_GenAssoc
+{
+ l_int32 index;
+ char type[16]; /* e.g., "PIXA" */
+ char structname[16]; /* e.g., "Pixa" */
+ char reader[16]; /* e.g., "pixaRead" */
+};
+
+ /* Serializable data types */
+static const l_int32 l_ntypes = 20;
+static const struct L_GenAssoc l_assoc[] = {
+ {0, "INVALID", "invalid", "invalid" },
+ {1, "BOXA", "Boxa", "boxaRead" },
+ {2, "BOXAA", "Boxaa", "boxaaRead" },
+ {3, "L_DEWARP", "Dewarp", "dewarpRead" },
+ {4, "L_DEWARPA", "Dewarpa", "dewarpaRead" },
+ {5, "L_DNA", "L_Dna", "l_dnaRead" },
+ {6, "L_DNAA", "L_Dnaa", "l_dnaaRead" },
+ {7, "DPIX", "DPix", "dpixRead" },
+ {8, "FPIX", "FPix", "fpixRead" },
+ {9, "NUMA", "Numa", "numaRead" },
+ {10, "NUMAA", "Numaa", "numaaRead" },
+ {11, "PIX", "Pix", "pixRead" },
+ {12, "PIXA", "Pixa", "pixaRead" },
+ {13, "PIXAA", "Pixaa", "pixaaRead" },
+ {14, "PIXACOMP", "Pixacomp", "pixacompRead" },
+ {15, "PIXCMAP", "Pixcmap", "pixcmapRead" },
+ {16, "PTA", "Pta", "ptaRead" },
+ {17, "PTAA", "Ptaa", "ptaaRead" },
+ {18, "RECOG", "Recog", "recogRead" },
+ {19, "RECOGA", "Recoga", "recogaRead" },
+ {20, "SARRAY", "Sarray", "sarrayRead" }
+};
+
+static l_int32 l_getIndexFromType(const char *type, l_int32 *pindex);
+static l_int32 l_getIndexFromStructname(const char *sn, l_int32 *pindex);
+static l_int32 l_getIndexFromFile(const char *file, l_int32 *pindex);
+static char *l_genDataString(const char *filein, l_int32 ifunc);
+static char *l_genCaseString(l_int32 ifunc, l_int32 itype);
+static char *l_genDescrString(const char *filein, l_int32 ifunc, l_int32 itype);
+
+
+/*---------------------------------------------------------------------*/
+/* Stringcode functions */
+/*---------------------------------------------------------------------*/
+/*!
+ * strcodeCreate()
+ *
+ * Input: fileno (integer that labels the two output files)
+ * Return: initialized L_StrCode, or null on error
+ *
+ * Notes:
+ * (1) This struct exists to build two files containing code for
+ * any number of data objects. The two files are named
+ * autogen.<fileno>.c
+ * autogen.<fileno>.h
+ */
+L_STRCODE *
+strcodeCreate(l_int32 fileno)
+{
+L_STRCODE *strcode;
+
+ PROCNAME("strcodeCreate");
+
+ lept_mkdir("lept/auto");
+
+ if ((strcode = (L_STRCODE *)LEPT_CALLOC(1, sizeof(L_STRCODE))) == NULL)
+ return (L_STRCODE *)ERROR_PTR("strcode not made", procName, NULL);
+
+ strcode->fileno = fileno;
+ strcode->function = sarrayCreate(0);
+ strcode->data = sarrayCreate(0);
+ strcode->descr = sarrayCreate(0);
+ return strcode;
+}
+
+
+/*!
+ * strcodeDestroy()
+ *
+ * Input: &strcode (strcode is set to null after destroying the sarrays)
+ * Return: void
+ */
+static void
+strcodeDestroy(L_STRCODE **pstrcode)
+{
+L_STRCODE *strcode;
+
+ PROCNAME("strcodeDestroy");
+
+ if (pstrcode == NULL) {
+ L_WARNING("ptr address is null!\n", procName);
+ return;
+ }
+
+ if ((strcode = *pstrcode) == NULL)
+ return;
+
+ sarrayDestroy(&strcode->function);
+ sarrayDestroy(&strcode->data);
+ sarrayDestroy(&strcode->descr);
+ LEPT_FREE(strcode);
+ *pstrcode = NULL;
+ return;
+}
+
+
+/*!
+ * strcodeCreateFromFile()
+ *
+ * Input: filein (containing filenames of serialized data)
+ * fileno (integer that labels the two output files)
+ * outdir (<optional> if null, files are made in /tmp/lept/auto)
+ * Return: 0 if OK, 1 on error
+ *
+ * Notes:
+ * (1) The @filein has one filename on each line.
+ * Comment lines begin with "#".
+ * (2) The output is 2 files:
+ * autogen.<fileno>.c
+ * autogen.<fileno>.h
+ */
+l_int32
+strcodeCreateFromFile(const char *filein,
+ l_int32 fileno,
+ const char *outdir)
+{
+char *fname;
+const char *type;
+l_uint8 *data;
+size_t nbytes;
+l_int32 i, n, index;
+SARRAY *sa;
+L_STRCODE *strcode;
+
+ PROCNAME("strcodeCreateFromFile");
+
+ if (!filein)
+ return ERROR_INT("filein not defined", procName, 1);
+
+ if ((data = l_binaryRead(filein, &nbytes)) == NULL)
+ return ERROR_INT("data not read from file", procName, 1);
+ sa = sarrayCreateLinesFromString((char *)data, 0);
+ LEPT_FREE(data);
+ if (!sa)
+ return ERROR_INT("sa not made", procName, 1);
+ if ((n = sarrayGetCount(sa)) == 0) {
+ sarrayDestroy(&sa);
+ return ERROR_INT("no filenames in the file", procName, 1);
+ }
+
+ strcode = strcodeCreate(fileno);
+
+ for (i = 0; i < n; i++) {
+ fname = sarrayGetString(sa, i, L_NOCOPY);
+ if (fname[0] == '#') continue;
+ if (l_getIndexFromFile(fname, &index)) {
+ L_ERROR("File %s has no recognizable type\n", procName, fname);
+ } else {
+ type = l_assoc[index].type;
+ L_INFO("File %s is type %s\n", procName, fname, type);
+ strcodeGenerate(strcode, fname, type);
+ }
+ }
+ strcodeFinalize(&strcode, outdir);
+ return 0;
+}
+
+
+/*!
+ * strcodeGenerate()
+ *
+ * Input: strcode (for accumulating data)
+ * filein (input file with serialized data)
+ * type (of data; use the typedef string)
+ * Return: 0 if OK, 1 on error.
+ *
+ * Notes:
+ * (1) The generated function name is
+ * l_autodecode_<fileno>()
+ * where <fileno> is the index label for the pair of output files.
+ * (2) To deserialize this data, the function is called with the
+ * argument 'ifunc', which increments each time strcodeGenerate()
+ * is called.
+ */
+l_int32
+strcodeGenerate(L_STRCODE *strcode,
+ const char *filein,
+ const char *type)
+{
+char *strdata, *strfunc, *strdescr;
+l_int32 itype;
+
+ PROCNAME("strcodeGenerate");
+
+ if (!strcode)
+ return ERROR_INT("strcode not defined", procName, 1);
+ if (!filein)
+ return ERROR_INT("filein not defined", procName, 1);
+ if (!type)
+ return ERROR_INT("type not defined", procName, 1);
+
+ /* Get the index corresponding to type and validate */
+ if (l_getIndexFromType(type, &itype) == 1)
+ return ERROR_INT("data type unknown", procName, 1);
+
+ /* Generate the encoded data string */
+ if ((strdata = l_genDataString(filein, strcode->ifunc)) == NULL)
+ return ERROR_INT("strdata not made", procName, 1);
+ sarrayAddString(strcode->data, strdata, L_INSERT);
+
+ /* Generate the case data for the decoding function */
+ strfunc = l_genCaseString(strcode->ifunc, itype);
+ sarrayAddString(strcode->function, strfunc, L_INSERT);
+
+ /* Generate row of table for function type selection */
+ strdescr = l_genDescrString(filein, strcode->ifunc, itype);
+ sarrayAddString(strcode->descr, strdescr, L_INSERT);
+
+ strcode->n++;
+ strcode->ifunc++;
+ return 0;
+}
+
+
+/*!
+ * strcodeFinalize()
+ *
+ * Input: &strcode (destroys after .c and .h files have been generated)
+ * outdir (<optional> if null, files are made in /tmp/lept/auto)
+ * Return: void
+ */
+l_int32
+strcodeFinalize(L_STRCODE **pstrcode,
+ const char *outdir)
+{
+char buf[256];
+char *filestr, *casestr, *descr, *datastr, *realoutdir;
+l_int32 actstart, end, newstart, fileno, nbytes;
+size_t size;
+L_STRCODE *strcode;
+SARRAY *sa1, *sa2, *sa3;
+
+ PROCNAME("strcodeFinalize");
+
+ lept_mkdir("lept/auto");
+
+ if (!pstrcode || *pstrcode == NULL)
+ return ERROR_INT("No input data", procName, 1);
+ strcode = *pstrcode;
+ if (!outdir) {
+ L_INFO("no outdir specified; writing to /tmp/lept/auto\n", procName);
+ realoutdir = stringNew("/tmp/lept/auto");
+ } else {
+ realoutdir = stringNew(outdir);
+ }
+
+ /* ------------------------------------------------------- */
+ /* Make the output autogen.*.c file */
+ /* ------------------------------------------------------- */
+
+ /* Make array of textlines from TEMPLATE1 */
+ if ((filestr = (char *)l_binaryRead(TEMPLATE1, &size)) == NULL)
+ return ERROR_INT("filestr not made", procName, 1);
+ if ((sa1 = sarrayCreateLinesFromString(filestr, 1)) == NULL)
+ return ERROR_INT("sa1 not made", procName, 1);
+ LEPT_FREE(filestr);
+
+ if ((sa3 = sarrayCreate(0)) == NULL)
+ return ERROR_INT("sa3 not made", procName, 1);
+
+ /* Copyright notice */
+ sarrayParseRange(sa1, 0, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+
+ /* File name comment */
+ fileno = strcode->fileno;
+ snprintf(buf, sizeof(buf), " * autogen.%d.c", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* More text */
+ sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+
+ /* Description of function types by index */
+ descr = sarrayToString(strcode->descr, 1);
+ descr[strlen(descr) - 1] = '\0';
+ sarrayAddString(sa3, descr, L_INSERT);
+
+ /* Includes */
+ sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+ snprintf(buf, sizeof(buf), "#include \"autogen.%d.h\"", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Header for auto-generated deserializers */
+ sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+
+ /* Function name (as comment) */
+ snprintf(buf, sizeof(buf), " * l_autodecode_%d()", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Input and return values */
+ sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+
+ /* Function name */
+ snprintf(buf, sizeof(buf), "l_autodecode_%d(l_int32 index)", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Stack vars */
+ sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+
+ /* Declaration of nfunc on stack */
+ snprintf(buf, sizeof(buf), "l_int32 nfunc = %d;\n", strcode->n);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Declaration of PROCNAME */
+ snprintf(buf, sizeof(buf), " PROCNAME(\"l_autodecode_%d\");", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Test input variables */
+ sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+
+ /* Insert case string */
+ casestr = sarrayToString(strcode->function, 0);
+ casestr[strlen(casestr) - 1] = '\0';
+ sarrayAddString(sa3, casestr, L_INSERT);
+
+ /* End of function */
+ sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa1, actstart, end);
+
+ /* Flatten to string and output to autogen*.c file */
+ if ((filestr = sarrayToString(sa3, 1)) == NULL)
+ return ERROR_INT("filestr from sa3 not made", procName, 1);
+ nbytes = strlen(filestr);
+ snprintf(buf, sizeof(buf), "%s/autogen.%d.c", realoutdir, fileno);
+ l_binaryWrite(buf, "w", filestr, nbytes);
+ LEPT_FREE(filestr);
+ sarrayDestroy(&sa1);
+ sarrayDestroy(&sa3);
+
+ /* ------------------------------------------------------- */
+ /* Make the output autogen.*.h file */
+ /* ------------------------------------------------------- */
+
+ /* Make array of textlines from TEMPLATE2 */
+ if ((filestr = (char *)l_binaryRead(TEMPLATE2, &size)) == NULL)
+ return ERROR_INT("filestr not made", procName, 1);
+ if ((sa2 = sarrayCreateLinesFromString(filestr, 1)) == NULL)
+ return ERROR_INT("sa2 not made", procName, 1);
+ LEPT_FREE(filestr);
+
+ if ((sa3 = sarrayCreate(0)) == NULL)
+ return ERROR_INT("sa3 not made", procName, 1);
+
+ /* Copyright notice */
+ sarrayParseRange(sa2, 0, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa2, actstart, end);
+
+ /* File name comment */
+ snprintf(buf, sizeof(buf), " * autogen.%d.h", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* More text */
+ sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa2, actstart, end);
+
+ /* Beginning header protection */
+ snprintf(buf, sizeof(buf), "#ifndef LEPTONICA_AUTOGEN_%d_H\n"
+ "#define LEPTONICA_AUTOGEN_%d_H",
+ fileno, fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Prototype header text */
+ sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa2, actstart, end);
+
+ /* Prototype declaration */
+ snprintf(buf, sizeof(buf), "void *l_autodecode_%d(l_int32 index);", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Prototype trailer text */
+ sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
+ sarrayAppendRange(sa3, sa2, actstart, end);
+
+ /* Insert serialized data strings */
+ datastr = sarrayToString(strcode->data, 1);
+ datastr[strlen(datastr) - 1] = '\0';
+ sarrayAddString(sa3, datastr, L_INSERT);
+
+ /* End header protection */
+ snprintf(buf, sizeof(buf), "#endif /* LEPTONICA_AUTOGEN_%d_H */", fileno);
+ sarrayAddString(sa3, buf, L_COPY);
+
+ /* Flatten to string and output to autogen*.h file */
+ if ((filestr = sarrayToString(sa3, 1)) == NULL)
+ return ERROR_INT("filestr from sa3 not made", procName, 1);
+ nbytes = strlen(filestr);
+ snprintf(buf, sizeof(buf), "%s/autogen.%d.h", realoutdir, fileno);
+ l_binaryWrite(buf, "w", filestr, nbytes);
+ LEPT_FREE(filestr);
+ LEPT_FREE(realoutdir);
+ sarrayDestroy(&sa2);
+ sarrayDestroy(&sa3);
+
+ /* Cleanup */
+ strcodeDestroy(pstrcode);
+ return 0;
+}
+
+
+/*!
+ * l_getStructnameFromFile()
+ *
+ * Input: filename
+ * &sn (<return> structname; e.g., "Pixa")
+ * Return: 0 if found, 1 on error.
+ */
+l_int32
+l_getStructnameFromFile(const char *filename,
+ char **psn)
+{
+l_int32 index;
+
+
+ PROCNAME("l_getStructnameFromFile");
+
+ if (!psn)
+ return ERROR_INT("&sn not defined", procName, 1);
+ *psn = NULL;
+ if (!filename)
+ return ERROR_INT("filename not defined", procName, 1);
+
+ if (l_getIndexFromFile(filename, &index))
+ return ERROR_INT("index not retrieved", procName, 1);
+ *psn = stringNew(l_assoc[index].structname);
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*/
+/* Static helpers */
+/*---------------------------------------------------------------------*/
+/*!
+ * l_getIndexFromType()
+ *
+ * Input: type (e.g., "PIXA")
+ * &index (<return>)
+ * Return: 0 if found, 1 if not.
+ *
+ * Notes:
+ * (1) For valid type, @found == true and @index > 0.
+ */
+static l_int32
+l_getIndexFromType(const char *type,
+ l_int32 *pindex)
+{
+l_int32 i, found;
+
+ PROCNAME("l_getIndexFromType");
+
+ if (!pindex)
+ return ERROR_INT("&index not defined", procName, 1);
+ *pindex = 0;
+ if (!type)
+ return ERROR_INT("type string not defined", procName, 1);
+
+ found = 0;
+ for (i = 1; i <= l_ntypes; i++) {
+ if (strcmp(type, l_assoc[i].type) == 0) {
+ found = 1;
+ *pindex = i;
+ break;
+ }
+ }
+ return !found;
+}
+
+
+/*!
+ * l_getIndexFromStructname()
+ *
+ * Input: structname (e.g., "Pixa")
+ * &index (<return>)
+ * Return: 0 if found, 1 if not.
+ *
+ * Notes:
+ * (1) This is used to identify the type of serialized file;
+ * the first word in the file is the structname.
+ * (2) For valid structname, @found == true and @index > 0.
+ */
+static l_int32
+l_getIndexFromStructname(const char *sn,
+ l_int32 *pindex)
+{
+l_int32 i, found;
+
+ PROCNAME("l_getIndexFromStructname");
+
+ if (!pindex)
+ return ERROR_INT("&index not defined", procName, 1);
+ *pindex = 0;
+ if (!sn)
+ return ERROR_INT("sn string not defined", procName, 1);
+
+ found = 0;
+ for (i = 1; i <= l_ntypes; i++) {
+ if (strcmp(sn, l_assoc[i].structname) == 0) {
+ found = 1;
+ *pindex = i;
+ break;
+ }
+ }
+ return !found;
+}
+
+
+/*!
+ * l_getIndexFromFile()
+ *
+ * Input: filename
+ * &index (<return>)
+ * Return: 0 if found, 1 on error.
+ */
+static l_int32
+l_getIndexFromFile(const char *filename,
+ l_int32 *pindex)
+{
+char buf[256];
+char *word;
+FILE *fp;
+l_int32 notfound, format;
+SARRAY *sa;
+
+ PROCNAME("l_getIndexFromFile");
+
+ if (!pindex)
+ return ERROR_INT("&index not defined", procName, 1);
+ *pindex = 0;
+ if (!filename)
+ return ERROR_INT("filename not defined", procName, 1);
+
+ /* Open the stream, read lines until you find one with more
+ * than a newline, and grab the first word. */
+ if ((fp = fopenReadStream(filename)) == NULL)
+ return ERROR_INT("stream not opened", procName, 1);
+ do {
+ if ((fgets(buf, sizeof(buf), fp)) == NULL) {
+ fclose(fp);
+ return ERROR_INT("fgets read fail", procName, 1);
+ }
+ } while (buf[0] == '\n');
+ fclose(fp);
+ sa = sarrayCreateWordsFromString(buf);
+ word = sarrayGetString(sa, 0, L_NOCOPY);
+
+ /* Find the index associated with the word. If it is not
+ * found, test to see if the file is a compressed pix. */
+ notfound = l_getIndexFromStructname(word, pindex);
+ sarrayDestroy(&sa);
+ if (notfound) { /* maybe a Pix */
+ if (findFileFormat(filename, &format) == 0) {
+ l_getIndexFromStructname("Pix", pindex);
+ } else {
+ return ERROR_INT("no file type identified", procName, 1);
+ }
+ }
+
+ return 0;
+}
+
+
+/*!
+ * l_genDataString()
+ *
+ * Input: filein (input file of serialized data)
+ * ifunc (index into set of functions in output file)
+ * Return: encoded ascii data string, or null on error reading from file
+ */
+static char *
+l_genDataString(const char *filein,
+ l_int32 ifunc)
+{
+char buf[80];
+char *cdata1, *cdata2, *cdata3;
+l_uint8 *data1, *data2;
+l_int32 csize1, csize2;
+size_t size1, size2;
+SARRAY *sa;
+
+ PROCNAME("l_genDataString");
+
+ if (!filein)
+ return (char *)ERROR_PTR("filein not defined", procName, NULL);
+
+ /* Read it in, gzip it, encode, and reformat. We gzip because some
+ * serialized data has a significant amount of ascii content. */
+ if ((data1 = l_binaryRead(filein, &size1)) == NULL)
+ return (char *)ERROR_PTR("bindata not returned", procName, NULL);
+ data2 = zlibCompress(data1, size1, &size2);
+ cdata1 = encodeBase64(data2, size2, &csize1);
+ cdata2 = reformatPacked64(cdata1, csize1, 4, 72, 1, &csize2);
+ LEPT_FREE(data1);
+ LEPT_FREE(data2);
+ LEPT_FREE(cdata1);
+
+ /* Prepend the string declaration signature and put it together */
+ sa = sarrayCreate(3);
+ snprintf(buf, sizeof(buf), "static const char *l_strdata_%d =\n", ifunc);
+ sarrayAddString(sa, buf, L_COPY);
+ sarrayAddString(sa, cdata2, L_INSERT);
+ sarrayAddString(sa, (char *)";\n", L_COPY);
+ cdata3 = sarrayToString(sa, 0);
+ sarrayDestroy(&sa);
+ return cdata3;
+}
+
+
+/*!
+ * l_genCaseString()
+ *
+ * Input: ifunc (index into set of functions in generated file)
+ * itype (index into type of function to be used)
+ * Return: case string for this decoding function
+ *
+ * Notes:
+ * (1) @ifunc and @itype have been validated, so no error can occur
+ */
+static char *
+l_genCaseString(l_int32 ifunc,
+ l_int32 itype)
+{
+char buf[256];
+char *code = NULL;
+
+ snprintf(buf, sizeof(buf), " case %d:\n", ifunc);
+ stringJoinIP(&code, buf);
+ snprintf(buf, sizeof(buf),
+ " data1 = decodeBase64(l_strdata_%d, strlen(l_strdata_%d), "
+ "&size1);\n", ifunc, ifunc);
+ stringJoinIP(&code, buf);
+ stringJoinIP(&code,
+ " data2 = zlibUncompress(data1, size1, &size2);\n");
+ stringJoinIP(&code,
+ " l_binaryWrite(\"/tmp/lept/auto/data.bin\","
+ "\"w\", data2, size2);\n");
+ snprintf(buf, sizeof(buf),
+ " result = (void *)%s(\"/tmp/lept/auto/data.bin\");\n",
+ l_assoc[itype].reader);
+ stringJoinIP(&code, buf);
+ stringJoinIP(&code, " lept_free(data1);\n");
+ stringJoinIP(&code, " lept_free(data2);\n");
+ stringJoinIP(&code, " break;\n");
+ return code;
+}
+
+
+/*!
+ * l_genDescrString()
+ *
+ * Input: filein (input file of serialized data)
+ * ifunc (index into set of functions in generated file)
+ * itype (index into type of function to be used)
+ * Return: description string for this decoding function
+ */
+static char *
+l_genDescrString(const char *filein,
+ l_int32 ifunc,
+ l_int32 itype)
+{
+char buf[256];
+char *tail;
+
+ PROCNAME("l_genDescrString");
+
+ if (!filein)
+ return (char *)ERROR_PTR("filein not defined", procName, NULL);
+
+ splitPathAtDirectory(filein, NULL, &tail);
+ snprintf(buf, sizeof(buf), " * %-2d %-10s %-14s %s",
+ ifunc, l_assoc[itype].type, l_assoc[itype].reader, tail);
+
+ LEPT_FREE(tail);
+ return stringNew(buf);
+}
+