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 }