Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/stringcode.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*====================================================================* | |
| 2 - Copyright (C) 2001 Leptonica. All rights reserved. | |
| 3 - | |
| 4 - Redistribution and use in source and binary forms, with or without | |
| 5 - modification, are permitted provided that the following conditions | |
| 6 - are met: | |
| 7 - 1. Redistributions of source code must retain the above copyright | |
| 8 - notice, this list of conditions and the following disclaimer. | |
| 9 - 2. Redistributions in binary form must reproduce the above | |
| 10 - copyright notice, this list of conditions and the following | |
| 11 - disclaimer in the documentation and/or other materials | |
| 12 - provided with the distribution. | |
| 13 - | |
| 14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY | |
| 18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 *====================================================================*/ | |
| 26 | |
| 27 /*! | |
| 28 * \file stringcode.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * Generation of code for storing and extracting serializable | |
| 32 * leptonica objects (such as pixa, recog, ...). | |
| 33 * | |
| 34 * The input is a set of files with serialized data. | |
| 35 * The output is two files, that must be compiled and linked: | |
| 36 * ~ autogen.*.c: code for base64 unencoding the strings and | |
| 37 * deserializing the result. | |
| 38 * ~ autogen.*.h: function prototypes and base64 encoded strings | |
| 39 * of the input data | |
| 40 * | |
| 41 * This should work for any data structures in leptonica that have | |
| 42 * *Write() and *Read() serialization functions. An array of 20 | |
| 43 * of these, including the Pix, is given below. (The Pix is a special | |
| 44 * case, because it is serialized by standardized compression | |
| 45 * techniques, instead of a file format determined by leptonica.) | |
| 46 * | |
| 47 * Each time the generator function is invoked, three sets of strings are | |
| 48 * produced, which are written into their respective string arrays: | |
| 49 * ~ string of serialized, gzipped and base 64 encoded data | |
| 50 * ~ case string for base64 decoding, gunzipping and deserialization, | |
| 51 * to return the data struct in memory | |
| 52 * ~ description string for selecting which struct to return | |
| 53 * To create the two output files, a finalize function is invoked. | |
| 54 * | |
| 55 * There are two ways to do this, both shown in prog/autogentest1.c. | |
| 56 * ~ Explicitly call strcodeGenerate() for each file with the | |
| 57 * serialized data structure, followed by strcodeFinalize(). | |
| 58 * ~ Put the filenames of the serialized data structures in a file, | |
| 59 * and call strcodeCreateFromFile(). | |
| 60 * | |
| 61 * The generated code in autogen.X.c and autogen.X.h (where X is an | |
| 62 * integer supplied to strcodeCreate()) is then compiled, and the | |
| 63 * original data can be regenerated using the function l_autodecode_X(). | |
| 64 * A test example is found in the two prog files: | |
| 65 * prog/autogentest1.c -- generates autogen.137.c, autogen.137.h | |
| 66 * prog/autogentest2.c -- uses autogen.137.c, autogen.137.h | |
| 67 * In general, the generator (e.g., autogentest1) would be compiled and | |
| 68 * run before compiling and running the application (e.g., autogentest2). | |
| 69 * | |
| 70 * L_STRCODE *strcodeCreate() | |
| 71 * static void strcodeDestroy() (called as part of finalize) | |
| 72 * void strcodeCreateFromFile() | |
| 73 * l_int32 strcodeGenerate() | |
| 74 * l_int32 strcodeFinalize() | |
| 75 * l_int32 l_getStructStrFromFile() (useful externally) | |
| 76 * | |
| 77 * Static helpers | |
| 78 * static l_int32 l_getIndexFromType() | |
| 79 * static l_int32 l_getIndexFromStructname() | |
| 80 * static l_int32 l_getIndexFromFile() | |
| 81 * static char *l_genDataString() | |
| 82 * static char *l_genCaseString() | |
| 83 * static char *l_genDescrString() | |
| 84 * </pre> | |
| 85 */ | |
| 86 | |
| 87 #ifdef HAVE_CONFIG_H | |
| 88 #include <config_auto.h> | |
| 89 #endif /* HAVE_CONFIG_H */ | |
| 90 | |
| 91 #include <string.h> | |
| 92 #include "allheaders.h" | |
| 93 #include "stringcode.h" | |
| 94 | |
| 95 #define TEMPLATE1 "stringtemplate1.txt" /* for assembling autogen.*.c */ | |
| 96 #define TEMPLATE2 "stringtemplate2.txt" /* for assembling autogen.*.h */ | |
| 97 | |
| 98 /*! Associations between names and functions */ | |
| 99 struct L_GenAssoc | |
| 100 { | |
| 101 l_int32 index; | |
| 102 char type[16]; /* e.g., "PIXA" */ | |
| 103 char structname[16]; /* e.g., "Pixa" */ | |
| 104 char reader[16]; /* e.g., "pixaRead" */ | |
| 105 char memreader[20]; /* e.g., "pixaReadMem" */ | |
| 106 }; | |
| 107 | |
| 108 /*! Number of serializable data types */ | |
| 109 static const l_int32 l_ntypes = 19; | |
| 110 /*! Serializable data types */ | |
| 111 static const struct L_GenAssoc l_assoc[] = { | |
| 112 {0, "INVALID", "invalid", "invalid", "invalid" }, | |
| 113 {1, "BOXA", "Boxa", "boxaRead", "boxaReadMem" }, | |
| 114 {2, "BOXAA", "Boxaa", "boxaaRead", "boxaaReadMem" }, | |
| 115 {3, "L_DEWARP", "Dewarp", "dewarpRead", "dewarpReadMem" }, | |
| 116 {4, "L_DEWARPA", "Dewarpa", "dewarpaRead", "dewarpaReadMem" }, | |
| 117 {5, "L_DNA", "L_Dna", "l_dnaRead", "l_dnaReadMem" }, | |
| 118 {6, "L_DNAA", "L_Dnaa", "l_dnaaRead", "l_dnaaReadMem" }, | |
| 119 {7, "DPIX", "DPix", "dpixRead", "dpixReadMem" }, | |
| 120 {8, "FPIX", "FPix", "fpixRead", "fpixReadMem" }, | |
| 121 {9, "NUMA", "Numa", "numaRead", "numaReadMem" }, | |
| 122 {10, "NUMAA", "Numaa", "numaaRead", "numaaReadMem" }, | |
| 123 {11, "PIX", "Pix", "pixRead", "pixReadMem" }, | |
| 124 {12, "PIXA", "Pixa", "pixaRead", "pixaReadMem" }, | |
| 125 {13, "PIXAA", "Pixaa", "pixaaRead", "pixaaReadMem" }, | |
| 126 {14, "PIXACOMP", "Pixacomp", "pixacompRead", "pixacompReadMem" }, | |
| 127 {15, "PIXCMAP", "Pixcmap", "pixcmapRead", "pixcmapReadMem" }, | |
| 128 {16, "PTA", "Pta", "ptaRead", "ptaReadMem" }, | |
| 129 {17, "PTAA", "Ptaa", "ptaaRead", "ptaaReadMem" }, | |
| 130 {18, "RECOG", "Recog", "recogRead", "recogReadMem" }, | |
| 131 {19, "SARRAY", "Sarray", "sarrayRead", "sarrayReadMem" } | |
| 132 }; | |
| 133 | |
| 134 static l_int32 l_getIndexFromType(const char *type, l_int32 *pindex); | |
| 135 static l_int32 l_getIndexFromStructname(const char *sn, l_int32 *pindex); | |
| 136 static l_int32 l_getIndexFromFile(const char *file, l_int32 *pindex); | |
| 137 static char *l_genDataString(const char *filein, l_int32 ifunc); | |
| 138 static char *l_genCaseString(l_int32 ifunc, l_int32 itype); | |
| 139 static char *l_genDescrString(const char *filein, l_int32 ifunc, l_int32 itype); | |
| 140 | |
| 141 /*---------------------------------------------------------------------*/ | |
| 142 /* Stringcode functions */ | |
| 143 /*---------------------------------------------------------------------*/ | |
| 144 /*! | |
| 145 * \brief strcodeCreate() | |
| 146 * | |
| 147 * \param[in] fileno integer that labels the two output files | |
| 148 * \return initialized L_StrCode, or NULL on error | |
| 149 * | |
| 150 * <pre> | |
| 151 * Notes: | |
| 152 * (1) This struct exists to build two files containing code for | |
| 153 * any number of data objects. The two files are named | |
| 154 * autogen.[fileno].c | |
| 155 * autogen.[fileno].h | |
| 156 * </pre> | |
| 157 */ | |
| 158 L_STRCODE * | |
| 159 strcodeCreate(l_int32 fileno) | |
| 160 { | |
| 161 L_STRCODE *strcode; | |
| 162 | |
| 163 lept_mkdir("lept/auto"); | |
| 164 | |
| 165 if ((strcode = (L_STRCODE *)LEPT_CALLOC(1, sizeof(L_STRCODE))) == NULL) | |
| 166 return (L_STRCODE *)ERROR_PTR("strcode not made", __func__, NULL); | |
| 167 | |
| 168 strcode->fileno = fileno; | |
| 169 strcode->function = sarrayCreate(0); | |
| 170 strcode->data = sarrayCreate(0); | |
| 171 strcode->descr = sarrayCreate(0); | |
| 172 return strcode; | |
| 173 } | |
| 174 | |
| 175 | |
| 176 /*! | |
| 177 * \brief strcodeDestroy() | |
| 178 * | |
| 179 * \param[out] pstrcode will be set to null after destroying the sarrays | |
| 180 * \return void | |
| 181 */ | |
| 182 static void | |
| 183 strcodeDestroy(L_STRCODE **pstrcode) | |
| 184 { | |
| 185 L_STRCODE *strcode; | |
| 186 | |
| 187 if (pstrcode == NULL) { | |
| 188 L_WARNING("ptr address is null!\n", __func__); | |
| 189 return; | |
| 190 } | |
| 191 | |
| 192 if ((strcode = *pstrcode) == NULL) | |
| 193 return; | |
| 194 | |
| 195 sarrayDestroy(&strcode->function); | |
| 196 sarrayDestroy(&strcode->data); | |
| 197 sarrayDestroy(&strcode->descr); | |
| 198 LEPT_FREE(strcode); | |
| 199 *pstrcode = NULL; | |
| 200 } | |
| 201 | |
| 202 | |
| 203 /*! | |
| 204 * \brief strcodeCreateFromFile() | |
| 205 * | |
| 206 * \param[in] filein containing filenames of serialized data | |
| 207 * \param[in] fileno integer that labels the two output files | |
| 208 * \param[in] outdir [optional] if null, files are made in /tmp/lept/auto | |
| 209 * \return 0 if OK, 1 on error | |
| 210 * | |
| 211 * <pre> | |
| 212 * Notes: | |
| 213 * (1) The %filein has one filename on each line. | |
| 214 * Comment lines begin with "#". | |
| 215 * (2) The output is 2 files: | |
| 216 * autogen.[fileno].c | |
| 217 * autogen.[fileno].h | |
| 218 * </pre> | |
| 219 */ | |
| 220 l_ok | |
| 221 strcodeCreateFromFile(const char *filein, | |
| 222 l_int32 fileno, | |
| 223 const char *outdir) | |
| 224 { | |
| 225 char *fname; | |
| 226 const char *type; | |
| 227 l_uint8 *data; | |
| 228 size_t nbytes; | |
| 229 l_int32 i, n, index; | |
| 230 SARRAY *sa; | |
| 231 L_STRCODE *strcode; | |
| 232 | |
| 233 if (!filein) | |
| 234 return ERROR_INT("filein not defined", __func__, 1); | |
| 235 | |
| 236 if ((data = l_binaryRead(filein, &nbytes)) == NULL) | |
| 237 return ERROR_INT("data not read from file", __func__, 1); | |
| 238 sa = sarrayCreateLinesFromString((char *)data, 0); | |
| 239 LEPT_FREE(data); | |
| 240 if (!sa) | |
| 241 return ERROR_INT("sa not made", __func__, 1); | |
| 242 if ((n = sarrayGetCount(sa)) == 0) { | |
| 243 sarrayDestroy(&sa); | |
| 244 return ERROR_INT("no filenames in the file", __func__, 1); | |
| 245 } | |
| 246 | |
| 247 strcode = strcodeCreate(fileno); | |
| 248 | |
| 249 for (i = 0; i < n; i++) { | |
| 250 fname = sarrayGetString(sa, i, L_NOCOPY); | |
| 251 if (fname[0] == '#') continue; | |
| 252 if (l_getIndexFromFile(fname, &index)) { | |
| 253 L_ERROR("File %s has no recognizable type\n", __func__, fname); | |
| 254 } else { | |
| 255 type = l_assoc[index].type; | |
| 256 L_INFO("File %s is type %s\n", __func__, fname, type); | |
| 257 strcodeGenerate(strcode, fname, type); | |
| 258 } | |
| 259 } | |
| 260 strcodeFinalize(&strcode, outdir); | |
| 261 sarrayDestroy(&sa); | |
| 262 return 0; | |
| 263 } | |
| 264 | |
| 265 | |
| 266 /*! | |
| 267 * \brief strcodeGenerate() | |
| 268 * | |
| 269 * \param[in] strcode for accumulating data | |
| 270 * \param[in] filein input file with serialized data | |
| 271 * \param[in] type of data; use the typedef string | |
| 272 * \return 0 if OK, 1 on error. | |
| 273 * | |
| 274 * <pre> | |
| 275 * Notes: | |
| 276 * (1) The generated function name is | |
| 277 * l_autodecode_[fileno]() | |
| 278 * where [fileno] is the index label for the pair of output files. | |
| 279 * (2) To deserialize this data, the function is called with the | |
| 280 * argument 'ifunc', which increments each time strcodeGenerate() | |
| 281 * is called. | |
| 282 * </pre> | |
| 283 */ | |
| 284 l_ok | |
| 285 strcodeGenerate(L_STRCODE *strcode, | |
| 286 const char *filein, | |
| 287 const char *type) | |
| 288 { | |
| 289 char *strdata, *strfunc, *strdescr; | |
| 290 l_int32 itype; | |
| 291 | |
| 292 if (!strcode) | |
| 293 return ERROR_INT("strcode not defined", __func__, 1); | |
| 294 if (!filein) | |
| 295 return ERROR_INT("filein not defined", __func__, 1); | |
| 296 if (!type) | |
| 297 return ERROR_INT("type not defined", __func__, 1); | |
| 298 | |
| 299 /* Get the index corresponding to type and validate */ | |
| 300 if (l_getIndexFromType(type, &itype) == 1) | |
| 301 return ERROR_INT("data type unknown", __func__, 1); | |
| 302 | |
| 303 /* Generate the encoded data string */ | |
| 304 if ((strdata = l_genDataString(filein, strcode->ifunc)) == NULL) | |
| 305 return ERROR_INT("strdata not made", __func__, 1); | |
| 306 sarrayAddString(strcode->data, strdata, L_INSERT); | |
| 307 | |
| 308 /* Generate the case data for the decoding function */ | |
| 309 strfunc = l_genCaseString(strcode->ifunc, itype); | |
| 310 sarrayAddString(strcode->function, strfunc, L_INSERT); | |
| 311 | |
| 312 /* Generate row of table for function type selection */ | |
| 313 strdescr = l_genDescrString(filein, strcode->ifunc, itype); | |
| 314 sarrayAddString(strcode->descr, strdescr, L_INSERT); | |
| 315 | |
| 316 strcode->n++; | |
| 317 strcode->ifunc++; | |
| 318 return 0; | |
| 319 } | |
| 320 | |
| 321 | |
| 322 /*! | |
| 323 * \brief strcodeFinalize() | |
| 324 * | |
| 325 * \param[in,out] pstrcode destroys and sets to null after .c and .h files | |
| 326 * have been generated | |
| 327 * \param[in] outdir [optional] if NULL, make files in /tmp/lept/auto | |
| 328 * \return 0 if OK; 1 on error | |
| 329 */ | |
| 330 l_int32 | |
| 331 strcodeFinalize(L_STRCODE **pstrcode, | |
| 332 const char *outdir) | |
| 333 { | |
| 334 char buf[256]; | |
| 335 char *filestr, *casestr, *descr, *datastr, *realoutdir; | |
| 336 l_int32 actstart, end, newstart, fileno, nbytes; | |
| 337 size_t size; | |
| 338 L_STRCODE *strcode; | |
| 339 SARRAY *sa1, *sa2, *sa3; | |
| 340 | |
| 341 lept_mkdir("lept/auto"); | |
| 342 | |
| 343 if (!pstrcode || *pstrcode == NULL) | |
| 344 return ERROR_INT("No input data", __func__, 1); | |
| 345 strcode = *pstrcode; | |
| 346 if (!outdir) { | |
| 347 L_INFO("no outdir specified; writing to /tmp/lept/auto\n", __func__); | |
| 348 realoutdir = stringNew("/tmp/lept/auto"); | |
| 349 } else { | |
| 350 realoutdir = stringNew(outdir); | |
| 351 } | |
| 352 | |
| 353 /* ------------------------------------------------------- */ | |
| 354 /* Make the output autogen.*.c file */ | |
| 355 /* ------------------------------------------------------- */ | |
| 356 | |
| 357 /* Make array of textlines from TEMPLATE1 */ | |
| 358 filestr = (char *)l_binaryRead(TEMPLATE1, &size); | |
| 359 sa1 = sarrayCreateLinesFromString(filestr, 1); | |
| 360 LEPT_FREE(filestr); | |
| 361 sa3 = sarrayCreate(0); | |
| 362 | |
| 363 /* Copyright notice */ | |
| 364 sarrayParseRange(sa1, 0, &actstart, &end, &newstart, "--", 0); | |
| 365 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 366 | |
| 367 /* File name comment */ | |
| 368 fileno = strcode->fileno; | |
| 369 snprintf(buf, sizeof(buf), " * autogen.%d.c", fileno); | |
| 370 sarrayAddString(sa3, buf, L_COPY); | |
| 371 | |
| 372 /* More text */ | |
| 373 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0); | |
| 374 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 375 | |
| 376 /* Description of function types by index */ | |
| 377 descr = sarrayToString(strcode->descr, 1); | |
| 378 descr[strlen(descr) - 1] = '\0'; | |
| 379 sarrayAddString(sa3, descr, L_INSERT); | |
| 380 | |
| 381 /* Includes */ | |
| 382 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0); | |
| 383 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 384 snprintf(buf, sizeof(buf), "#include \"autogen.%d.h\"", fileno); | |
| 385 sarrayAddString(sa3, buf, L_COPY); | |
| 386 | |
| 387 /* Header for auto-generated deserializers */ | |
| 388 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0); | |
| 389 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 390 | |
| 391 /* Function name (as comment) */ | |
| 392 snprintf(buf, sizeof(buf), " * \\brief l_autodecode_%d()", fileno); | |
| 393 sarrayAddString(sa3, buf, L_COPY); | |
| 394 | |
| 395 /* Input and return values */ | |
| 396 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0); | |
| 397 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 398 | |
| 399 /* Function name */ | |
| 400 snprintf(buf, sizeof(buf), "l_autodecode_%d(l_int32 index)", fileno); | |
| 401 sarrayAddString(sa3, buf, L_COPY); | |
| 402 | |
| 403 /* Stack vars */ | |
| 404 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0); | |
| 405 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 406 | |
| 407 /* Declaration of nfunc on stack */ | |
| 408 snprintf(buf, sizeof(buf), "l_int32 nfunc = %d;\n", strcode->n); | |
| 409 sarrayAddString(sa3, buf, L_COPY); | |
| 410 | |
| 411 /* Declaration of PROCNAME */ | |
| 412 snprintf(buf, sizeof(buf), " PROCNAME(\"l_autodecode_%d\");", fileno); | |
| 413 sarrayAddString(sa3, buf, L_COPY); | |
| 414 | |
| 415 /* Test input variables */ | |
| 416 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0); | |
| 417 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 418 | |
| 419 /* Insert case string */ | |
| 420 casestr = sarrayToString(strcode->function, 0); | |
| 421 casestr[strlen(casestr) - 1] = '\0'; | |
| 422 sarrayAddString(sa3, casestr, L_INSERT); | |
| 423 | |
| 424 /* End of function */ | |
| 425 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0); | |
| 426 sarrayAppendRange(sa3, sa1, actstart, end); | |
| 427 | |
| 428 /* Flatten to string and output to autogen*.c file */ | |
| 429 filestr = sarrayToString(sa3, 1); | |
| 430 nbytes = strlen(filestr); | |
| 431 snprintf(buf, sizeof(buf), "%s/autogen.%d.c", realoutdir, fileno); | |
| 432 l_binaryWrite(buf, "w", filestr, nbytes); | |
| 433 LEPT_FREE(filestr); | |
| 434 sarrayDestroy(&sa1); | |
| 435 sarrayDestroy(&sa3); | |
| 436 | |
| 437 /* ------------------------------------------------------- */ | |
| 438 /* Make the output autogen.*.h file */ | |
| 439 /* ------------------------------------------------------- */ | |
| 440 | |
| 441 /* Make array of textlines from TEMPLATE2 */ | |
| 442 filestr = (char *)l_binaryRead(TEMPLATE2, &size); | |
| 443 sa2 = sarrayCreateLinesFromString(filestr, 1); | |
| 444 LEPT_FREE(filestr); | |
| 445 sa3 = sarrayCreate(0); | |
| 446 | |
| 447 /* Copyright notice */ | |
| 448 sarrayParseRange(sa2, 0, &actstart, &end, &newstart, "--", 0); | |
| 449 sarrayAppendRange(sa3, sa2, actstart, end); | |
| 450 | |
| 451 /* File name comment */ | |
| 452 snprintf(buf, sizeof(buf), " * autogen.%d.h", fileno); | |
| 453 sarrayAddString(sa3, buf, L_COPY); | |
| 454 | |
| 455 /* More text */ | |
| 456 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0); | |
| 457 sarrayAppendRange(sa3, sa2, actstart, end); | |
| 458 | |
| 459 /* Beginning header protection */ | |
| 460 snprintf(buf, sizeof(buf), "#ifndef LEPTONICA_AUTOGEN_%d_H\n" | |
| 461 "#define LEPTONICA_AUTOGEN_%d_H", | |
| 462 fileno, fileno); | |
| 463 sarrayAddString(sa3, buf, L_COPY); | |
| 464 | |
| 465 /* Prototype header text */ | |
| 466 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0); | |
| 467 sarrayAppendRange(sa3, sa2, actstart, end); | |
| 468 | |
| 469 /* Prototype declaration */ | |
| 470 snprintf(buf, sizeof(buf), "void *l_autodecode_%d(l_int32 index);", fileno); | |
| 471 sarrayAddString(sa3, buf, L_COPY); | |
| 472 | |
| 473 /* Prototype trailer text */ | |
| 474 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0); | |
| 475 sarrayAppendRange(sa3, sa2, actstart, end); | |
| 476 | |
| 477 /* Insert serialized data strings */ | |
| 478 datastr = sarrayToString(strcode->data, 1); | |
| 479 datastr[strlen(datastr) - 1] = '\0'; | |
| 480 sarrayAddString(sa3, datastr, L_INSERT); | |
| 481 | |
| 482 /* End header protection */ | |
| 483 snprintf(buf, sizeof(buf), "#endif /* LEPTONICA_AUTOGEN_%d_H */", fileno); | |
| 484 sarrayAddString(sa3, buf, L_COPY); | |
| 485 | |
| 486 /* Flatten to string and output to autogen*.h file */ | |
| 487 filestr = sarrayToString(sa3, 1); | |
| 488 nbytes = strlen(filestr); | |
| 489 snprintf(buf, sizeof(buf), "%s/autogen.%d.h", realoutdir, fileno); | |
| 490 l_binaryWrite(buf, "w", filestr, nbytes); | |
| 491 LEPT_FREE(filestr); | |
| 492 LEPT_FREE(realoutdir); | |
| 493 sarrayDestroy(&sa2); | |
| 494 sarrayDestroy(&sa3); | |
| 495 | |
| 496 /* Cleanup */ | |
| 497 strcodeDestroy(pstrcode); | |
| 498 return 0; | |
| 499 } | |
| 500 | |
| 501 | |
| 502 /*! | |
| 503 * \brief l_getStructStrFromFile() | |
| 504 * | |
| 505 * \param[in] filename | |
| 506 * \param[in] field (L_STR_TYPE, L_STR_NAME, L_STR_READER, L_STR_MEMREADER) | |
| 507 * \param[out] pstr struct string for this file | |
| 508 * \return 0 if found, 1 on error. | |
| 509 * | |
| 510 * <pre> | |
| 511 * Notes: | |
| 512 * (1) For example, if %field == L_STR_NAME, and the file is a serialized | |
| 513 * pixa, this will return "Pixa", the name of the struct. | |
| 514 * (2) Caller must free the returned string. | |
| 515 * </pre> | |
| 516 */ | |
| 517 l_int32 | |
| 518 l_getStructStrFromFile(const char *filename, | |
| 519 l_int32 field, | |
| 520 char **pstr) | |
| 521 { | |
| 522 l_int32 index; | |
| 523 | |
| 524 if (!pstr) | |
| 525 return ERROR_INT("&str not defined", __func__, 1); | |
| 526 *pstr = NULL; | |
| 527 if (!filename) | |
| 528 return ERROR_INT("filename not defined", __func__, 1); | |
| 529 if (field != L_STR_TYPE && field != L_STR_NAME && | |
| 530 field != L_STR_READER && field != L_STR_MEMREADER) | |
| 531 return ERROR_INT("invalid field", __func__, 1); | |
| 532 | |
| 533 if (l_getIndexFromFile(filename, &index)) | |
| 534 return ERROR_INT("index not retrieved", __func__, 1); | |
| 535 if (field == L_STR_TYPE) | |
| 536 *pstr = stringNew(l_assoc[index].type); | |
| 537 else if (field == L_STR_NAME) | |
| 538 *pstr = stringNew(l_assoc[index].structname); | |
| 539 else if (field == L_STR_READER) | |
| 540 *pstr = stringNew(l_assoc[index].reader); | |
| 541 else /* field == L_STR_MEMREADER */ | |
| 542 *pstr = stringNew(l_assoc[index].memreader); | |
| 543 return 0; | |
| 544 } | |
| 545 | |
| 546 | |
| 547 /*---------------------------------------------------------------------*/ | |
| 548 /* Static helpers */ | |
| 549 /*---------------------------------------------------------------------*/ | |
| 550 /*! | |
| 551 * \brief l_getIndexFromType() | |
| 552 * | |
| 553 * \param[in] type e.g., "PIXA" | |
| 554 * \param[out] pindex found index | |
| 555 * \return 0 if found, 1 if not. | |
| 556 * | |
| 557 * <pre> | |
| 558 * Notes: | |
| 559 * (1) For valid type, %found == true and %index > 0. | |
| 560 * </pre> | |
| 561 */ | |
| 562 static l_int32 | |
| 563 l_getIndexFromType(const char *type, | |
| 564 l_int32 *pindex) | |
| 565 { | |
| 566 l_int32 i, found; | |
| 567 | |
| 568 if (!pindex) | |
| 569 return ERROR_INT("&index not defined", __func__, 1); | |
| 570 *pindex = 0; | |
| 571 if (!type) | |
| 572 return ERROR_INT("type string not defined", __func__, 1); | |
| 573 | |
| 574 found = 0; | |
| 575 for (i = 1; i <= l_ntypes; i++) { | |
| 576 if (strcmp(type, l_assoc[i].type) == 0) { | |
| 577 found = 1; | |
| 578 *pindex = i; | |
| 579 break; | |
| 580 } | |
| 581 } | |
| 582 return !found; | |
| 583 } | |
| 584 | |
| 585 | |
| 586 /*! | |
| 587 * \brief l_getIndexFromStructname() | |
| 588 * | |
| 589 * \param[in] sn structname e.g., "Pixa" | |
| 590 * \param[out] pindex found index | |
| 591 * \return 0 if found, 1 if not. | |
| 592 * | |
| 593 * <pre> | |
| 594 * Notes: | |
| 595 * (1) This is used to identify the type of serialized file; | |
| 596 * the first word in the file is the structname. | |
| 597 * (2) For valid structname, %found == true and %index > 0. | |
| 598 * </pre> | |
| 599 */ | |
| 600 static l_int32 | |
| 601 l_getIndexFromStructname(const char *sn, | |
| 602 l_int32 *pindex) | |
| 603 { | |
| 604 l_int32 i, found; | |
| 605 | |
| 606 if (!pindex) | |
| 607 return ERROR_INT("&index not defined", __func__, 1); | |
| 608 *pindex = 0; | |
| 609 if (!sn) | |
| 610 return ERROR_INT("sn string not defined", __func__, 1); | |
| 611 | |
| 612 found = 0; | |
| 613 for (i = 1; i <= l_ntypes; i++) { | |
| 614 if (strcmp(sn, l_assoc[i].structname) == 0) { | |
| 615 found = 1; | |
| 616 *pindex = i; | |
| 617 break; | |
| 618 } | |
| 619 } | |
| 620 return !found; | |
| 621 } | |
| 622 | |
| 623 | |
| 624 /*! | |
| 625 * \brief l_getIndexFromFile() | |
| 626 * | |
| 627 * \param[in] filename | |
| 628 * \param[out] pindex found index | |
| 629 * \return 0 if found, 1 on error. | |
| 630 */ | |
| 631 static l_int32 | |
| 632 l_getIndexFromFile(const char *filename, | |
| 633 l_int32 *pindex) | |
| 634 { | |
| 635 char buf[256]; | |
| 636 char *word; | |
| 637 FILE *fp; | |
| 638 l_int32 notfound, format; | |
| 639 SARRAY *sa; | |
| 640 | |
| 641 if (!pindex) | |
| 642 return ERROR_INT("&index not defined", __func__, 1); | |
| 643 *pindex = 0; | |
| 644 if (!filename) | |
| 645 return ERROR_INT("filename not defined", __func__, 1); | |
| 646 | |
| 647 /* Open the stream, read lines until you find one with more | |
| 648 * than a newline, and grab the first word. */ | |
| 649 if ((fp = fopenReadStream(filename)) == NULL) | |
| 650 return ERROR_INT_1("stream not opened", filename, __func__, 1); | |
| 651 do { | |
| 652 if ((fgets(buf, sizeof(buf), fp)) == NULL) { | |
| 653 fclose(fp); | |
| 654 return ERROR_INT_1("fgets read fail", filename, __func__, 1); | |
| 655 } | |
| 656 } while (buf[0] == '\n'); | |
| 657 fclose(fp); | |
| 658 sa = sarrayCreateWordsFromString(buf); | |
| 659 word = sarrayGetString(sa, 0, L_NOCOPY); | |
| 660 | |
| 661 /* Find the index associated with the word. If it is not | |
| 662 * found, test to see if the file is a compressed pix. */ | |
| 663 notfound = l_getIndexFromStructname(word, pindex); | |
| 664 sarrayDestroy(&sa); | |
| 665 if (notfound) { /* maybe a Pix */ | |
| 666 if (findFileFormat(filename, &format) == 0) { | |
| 667 l_getIndexFromStructname("Pix", pindex); | |
| 668 } else { | |
| 669 return ERROR_INT_1("no file type identified", | |
| 670 filename, __func__, 1); | |
| 671 } | |
| 672 } | |
| 673 | |
| 674 return 0; | |
| 675 } | |
| 676 | |
| 677 | |
| 678 /*! | |
| 679 * \brief l_genDataString() | |
| 680 * | |
| 681 * \param[in] filein input file of serialized data | |
| 682 * \param[in] ifunc index into set of functions in output file | |
| 683 * \return encoded ascii data string, or NULL on error reading from file | |
| 684 */ | |
| 685 static char * | |
| 686 l_genDataString(const char *filein, | |
| 687 l_int32 ifunc) | |
| 688 { | |
| 689 char buf[80]; | |
| 690 char *cdata1, *cdata2, *cdata3; | |
| 691 l_uint8 *data1, *data2; | |
| 692 l_int32 csize1, csize2; | |
| 693 size_t size1, size2; | |
| 694 SARRAY *sa; | |
| 695 | |
| 696 if (!filein) | |
| 697 return (char *)ERROR_PTR("filein not defined", __func__, NULL); | |
| 698 | |
| 699 /* Read it in, gzip it, encode, and reformat. We gzip because some | |
| 700 * serialized data has a significant amount of ascii content. */ | |
| 701 if ((data1 = l_binaryRead(filein, &size1)) == NULL) | |
| 702 return (char *)ERROR_PTR("bindata not returned", __func__, NULL); | |
| 703 data2 = zlibCompress(data1, size1, &size2); | |
| 704 cdata1 = encodeBase64(data2, size2, &csize1); | |
| 705 cdata2 = reformatPacked64(cdata1, csize1, 4, 72, 1, &csize2); | |
| 706 LEPT_FREE(data1); | |
| 707 LEPT_FREE(data2); | |
| 708 LEPT_FREE(cdata1); | |
| 709 | |
| 710 /* Prepend the string declaration signature and put it together */ | |
| 711 sa = sarrayCreate(3); | |
| 712 snprintf(buf, sizeof(buf), "static const char *l_strdata_%d =\n", ifunc); | |
| 713 sarrayAddString(sa, buf, L_COPY); | |
| 714 sarrayAddString(sa, cdata2, L_INSERT); | |
| 715 sarrayAddString(sa, ";\n", L_COPY); | |
| 716 cdata3 = sarrayToString(sa, 0); | |
| 717 sarrayDestroy(&sa); | |
| 718 return cdata3; | |
| 719 } | |
| 720 | |
| 721 | |
| 722 /*! | |
| 723 * \brief l_genCaseString() | |
| 724 * | |
| 725 * \param[in] ifunc index into set of functions in generated file | |
| 726 * \param[in] itype index into type of function to be used | |
| 727 * \return case string for this decoding function | |
| 728 * | |
| 729 * <pre> | |
| 730 * Notes: | |
| 731 * (1) %ifunc and %itype have been validated, so no error can occur | |
| 732 * </pre> | |
| 733 */ | |
| 734 static char * | |
| 735 l_genCaseString(l_int32 ifunc, | |
| 736 l_int32 itype) | |
| 737 { | |
| 738 char buf[256]; | |
| 739 char *code = NULL; | |
| 740 | |
| 741 snprintf(buf, sizeof(buf), " case %d:\n", ifunc); | |
| 742 stringJoinIP(&code, buf); | |
| 743 snprintf(buf, sizeof(buf), | |
| 744 " data1 = decodeBase64(l_strdata_%d, strlen(l_strdata_%d), " | |
| 745 "&size1);\n", ifunc, ifunc); | |
| 746 stringJoinIP(&code, buf); | |
| 747 stringJoinIP(&code, | |
| 748 " data2 = zlibUncompress(data1, size1, &size2);\n"); | |
| 749 snprintf(buf, sizeof(buf), | |
| 750 " result = (void *)%s(data2, size2);\n", | |
| 751 l_assoc[itype].memreader); | |
| 752 stringJoinIP(&code, buf); | |
| 753 stringJoinIP(&code, " lept_free(data1);\n"); | |
| 754 stringJoinIP(&code, " lept_free(data2);\n"); | |
| 755 stringJoinIP(&code, " break;\n"); | |
| 756 return code; | |
| 757 } | |
| 758 | |
| 759 | |
| 760 /*! | |
| 761 * \brief l_genDescrString() | |
| 762 * | |
| 763 * \param[in] filein input file of serialized data | |
| 764 * \param[in] ifunc index into set of functions in generated file | |
| 765 * \param[in] itype index into type of function to be used | |
| 766 * \return description string for this decoding function | |
| 767 */ | |
| 768 static char * | |
| 769 l_genDescrString(const char *filein, | |
| 770 l_int32 ifunc, | |
| 771 l_int32 itype) | |
| 772 { | |
| 773 char buf[256]; | |
| 774 char *tail; | |
| 775 | |
| 776 if (!filein) | |
| 777 return (char *)ERROR_PTR("filein not defined", __func__, NULL); | |
| 778 | |
| 779 splitPathAtDirectory(filein, NULL, &tail); | |
| 780 snprintf(buf, sizeof(buf), " * %-2d %-10s %-14s %s", | |
| 781 ifunc, l_assoc[itype].type, l_assoc[itype].reader, tail); | |
| 782 | |
| 783 LEPT_FREE(tail); | |
| 784 return stringNew(buf); | |
| 785 } |
