Initial import to Tizen
[profile/ivi/sphinxbase.git] / src / libsphinxbase / util / bio.c
1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3  * Copyright (c) 1999-2004 Carnegie Mellon University.  All rights
4  * reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * This work was supported in part by funding from the Defense Advanced 
19  * Research Projects Agency and the National Science Foundation of the 
20  * United States of America, and the CMU Sphinx Speech Consortium.
21  *
22  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
23  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
26  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * ====================================================================
35  *
36  */
37 /*
38  * bio.c -- Sphinx-3 binary file I/O functions.
39  * 
40  * **********************************************
41  * CMU ARPA Speech Project
42  *
43  * Copyright (c) 1996 Carnegie Mellon University.
44  * ALL RIGHTS RESERVED.
45  * **********************************************
46  * 
47  * HISTORY
48  * $Log$
49  * Revision 1.4  2005/06/21  20:40:46  arthchan2003
50  * 1, Fixed doxygen documentation, 2, Add the $ keyword.
51  * 
52  * Revision 1.3  2005/03/30 01:22:46  archan
53  * Fixed mistakes in last updates. Add
54  *
55  * 
56  * 02-Jul-1997  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
57  *              Bugfix: Added byteswapping in bio_verify_chksum().
58  * 
59  * 18-Dec-1996  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
60  *              Created.
61  */
62
63 #include <stdio.h>
64 #include <string.h>
65 #include <assert.h>
66
67 #ifdef _MSC_VER
68 #pragma warning (disable: 4996)
69 #endif
70
71 #include "sphinxbase/bio.h"
72 #include "sphinxbase/err.h"
73 #include "sphinxbase/ckd_alloc.h"
74
75
76 #define BIO_HDRARG_MAX  32
77 #define END_COMMENT     "*end_comment*\n"
78
79
80 static void
81 bcomment_read(FILE * fp)
82 {
83     __BIGSTACKVARIABLE__ char iline[16384];
84
85     while (fgets(iline, sizeof(iline), fp) != NULL) {
86         if (strcmp(iline, END_COMMENT) == 0)
87             return;
88     }
89     E_FATAL("Missing %s marker\n", END_COMMENT);
90 }
91
92
93 static int32
94 swap_check(FILE * fp)
95 {
96     uint32 magic;
97
98     if (fread(&magic, sizeof(uint32), 1, fp) != 1) {
99         E_ERROR("Cannot read BYTEORDER MAGIC NO.\n");
100         return -1;
101     }
102
103     if (magic != BYTE_ORDER_MAGIC) {
104         /* either need to swap or got bogus magic number */
105         SWAP_INT32(&magic);
106
107         if (magic == BYTE_ORDER_MAGIC)
108             return 1;
109
110         SWAP_INT32(&magic);
111         E_ERROR("Bad BYTEORDER MAGIC NO: %08x, expecting %08x\n",
112                 magic, BYTE_ORDER_MAGIC);
113         return -1;
114     }
115
116     return 0;
117 }
118
119
120 void
121 bio_hdrarg_free(char **argname, char **argval)
122 {
123     int32 i;
124
125     if (argname == NULL)
126         return;
127     for (i = 0; argname[i]; i++) {
128         ckd_free(argname[i]);
129         ckd_free(argval[i]);
130     }
131     ckd_free(argname);
132     ckd_free(argval);
133 }
134
135
136 int32
137 bio_writehdr_version(FILE * fp, char *version)
138 {
139     uint32 b;
140
141     fprintf(fp, "s3\n");
142     fprintf(fp, "version %s\n", version);
143     fprintf(fp, "endhdr\n");
144     fflush(fp);
145
146     b = (uint32) BYTE_ORDER_MAGIC;
147     fwrite(&b, sizeof(uint32), 1, fp);
148     fflush(fp);
149
150     return 0;
151 }
152
153
154 int32
155 bio_writehdr(FILE *fp, ...)
156 {
157     char const *key;
158     va_list args;
159     uint32 b;
160
161     fprintf(fp, "s3\n");
162     va_start(args, fp);
163     while ((key = va_arg(args, char const *)) != NULL) {
164         char const *val = va_arg(args, char const *);
165         if (val == NULL) {
166             E_ERROR("Wrong number of arguments\n");
167             va_end(args);
168             return -1;
169         }
170         fprintf(fp, "%s %s\n", key, val);
171     }
172     va_end(args);
173
174     fprintf(fp, "endhdr\n");
175     fflush(fp);
176
177     b = (uint32) BYTE_ORDER_MAGIC;
178     if (fwrite(&b, sizeof(uint32), 1, fp) != 1)
179         return -1;
180     fflush(fp);
181
182     return 0;
183 }
184
185
186 int32
187 bio_readhdr(FILE * fp, char ***argname, char ***argval, int32 * swap)
188 {
189     __BIGSTACKVARIABLE__ char line[16384], word[4096];
190     int32 i, l;
191     int32 lineno;
192
193     *argname = (char **) ckd_calloc(BIO_HDRARG_MAX + 1, sizeof(char *));
194     *argval = (char **) ckd_calloc(BIO_HDRARG_MAX, sizeof(char *));
195
196     lineno = 0;
197     if (fgets(line, sizeof(line), fp) == NULL){
198         E_ERROR("Premature EOF, line %d\n", lineno);
199         goto error_out;
200     }
201     lineno++;
202
203     if ((line[0] == 's') && (line[1] == '3') && (line[2] == '\n')) {
204         /* New format (post Dec-1996, including checksums); read argument-value pairs */
205         for (i = 0;;) {
206             if (fgets(line, sizeof(line), fp) == NULL) {
207                 E_ERROR("Premature EOF, line %d\n", lineno);
208                 goto error_out;
209             }
210             lineno++;
211
212             if (sscanf(line, "%s%n", word, &l) != 1) {
213                 E_ERROR("Header format error, line %d\n", lineno);
214                 goto error_out;
215             }
216             if (strcmp(word, "endhdr") == 0)
217                 break;
218             if (word[0] == '#') /* Skip comments */
219                 continue;
220
221             if (i >= BIO_HDRARG_MAX) {
222                 E_ERROR
223                     ("Max arg-value limit(%d) exceeded; increase BIO_HDRARG_MAX\n",
224                      BIO_HDRARG_MAX);
225                 goto error_out;
226             }
227
228             (*argname)[i] = ckd_salloc(word);
229             if (sscanf(line + l, "%s", word) != 1) {      /* Multi-word values not allowed */
230                 E_ERROR("Header format error, line %d\n", lineno);
231                 goto error_out;
232             }
233             (*argval)[i] = ckd_salloc(word);
234             i++;
235         }
236     }
237     else {
238         /* Old format (without checksums); the first entry must be the version# */
239         if (sscanf(line, "%s", word) != 1) {
240             E_ERROR("Header format error, line %d\n", lineno);
241             goto error_out;
242         }
243
244         (*argname)[0] = ckd_salloc("version");
245         (*argval)[0] = ckd_salloc(word);
246         i = 1;
247
248         bcomment_read(fp);
249     }
250     (*argname)[i] = NULL;
251
252     if ((*swap = swap_check(fp)) < 0) {
253         E_ERROR("swap_check failed\n");
254         goto error_out;
255     }
256
257     return 0;
258 error_out:
259     bio_hdrarg_free(*argname, *argval);
260     *argname = *argval = NULL;
261     return -1;
262 }
263
264
265 static uint32
266 chksum_accum(void *buf, int32 el_sz, int32 n_el, uint32 sum)
267 {
268     int32 i;
269     uint8 *i8;
270     uint16 *i16;
271     uint32 *i32;
272
273     switch (el_sz) {
274     case 1:
275         i8 = (uint8 *) buf;
276         for (i = 0; i < n_el; i++)
277             sum = (sum << 5 | sum >> 27) + i8[i];
278         break;
279     case 2:
280         i16 = (uint16 *) buf;
281         for (i = 0; i < n_el; i++)
282             sum = (sum << 10 | sum >> 22) + i16[i];
283         break;
284     case 4:
285         i32 = (uint32 *) buf;
286         for (i = 0; i < n_el; i++)
287             sum = (sum << 20 | sum >> 12) + i32[i];
288         break;
289     default:
290         E_FATAL("Unsupported elemsize for checksum: %d\n", el_sz);
291         break;
292     }
293
294     return sum;
295 }
296
297
298 static void
299 swap_buf(void *buf, int32 el_sz, int32 n_el)
300 {
301     int32 i;
302     uint16 *buf16;
303     uint32 *buf32;
304
305     switch (el_sz) {
306     case 1:
307         break;
308     case 2:
309         buf16 = (uint16 *) buf;
310         for (i = 0; i < n_el; i++)
311             SWAP_INT16(buf16 + i);
312         break;
313     case 4:
314         buf32 = (uint32 *) buf;
315         for (i = 0; i < n_el; i++)
316             SWAP_INT32(buf32 + i);
317         break;
318     default:
319         E_FATAL("Unsupported elemsize for byteswapping: %d\n", el_sz);
320         break;
321     }
322 }
323
324
325 int32
326 bio_fread(void *buf, int32 el_sz, int32 n_el, FILE * fp, int32 swap,
327           uint32 * chksum)
328 {
329     if (fread(buf, el_sz, n_el, fp) != (size_t) n_el)
330         return -1;
331
332     if (swap)
333         swap_buf(buf, el_sz, n_el);
334
335     if (chksum)
336         *chksum = chksum_accum(buf, el_sz, n_el, *chksum);
337
338     return n_el;
339 }
340
341 int32
342 bio_fwrite(void *buf, int32 el_sz, int32 n_el, FILE *fp,
343            int32 swap, uint32 *chksum)
344 {
345     if (chksum)
346         *chksum = chksum_accum(buf, el_sz, n_el, *chksum);
347     if (swap) {
348         void *nbuf;
349         int rv;
350
351         nbuf = ckd_calloc(n_el, el_sz);
352         memcpy(nbuf, buf, n_el * el_sz);
353         swap_buf(nbuf, el_sz, n_el);
354         rv = fwrite(nbuf, el_sz, n_el, fp);
355         ckd_free(nbuf);
356         return rv;
357     }
358     else {
359         return fwrite(buf, el_sz, n_el, fp);
360     }
361 }
362
363 int32
364 bio_fread_1d(void **buf, size_t el_sz, uint32 * n_el, FILE * fp,
365              int32 sw, uint32 * ck)
366 {
367     /* Read 1-d array size */
368     if (bio_fread(n_el, sizeof(int32), 1, fp, sw, ck) != 1)
369         E_FATAL("fread(arraysize) failed\n");
370     if (*n_el <= 0)
371         E_FATAL("Bad arraysize: %d\n", *n_el);
372
373     /* Allocate memory for array data */
374     *buf = (void *) ckd_calloc(*n_el, el_sz);
375
376     /* Read array data */
377     if (bio_fread(*buf, el_sz, *n_el, fp, sw, ck) != *n_el)
378         E_FATAL("fread(arraydata) failed\n");
379
380     return *n_el;
381 }
382
383 int32
384 bio_fread_2d(void ***arr,
385              size_t e_sz,
386              uint32 *d1,
387              uint32 *d2,
388              FILE *fp,
389              uint32 swap,
390              uint32 *chksum)
391 {
392     uint32 l_d1, l_d2;
393     uint32 n;
394     size_t ret;
395     void *raw;
396     
397     ret = bio_fread(&l_d1, sizeof(uint32), 1, fp, swap, chksum);
398     if (ret != 1) {
399         if (ret == 0) {
400             E_ERROR_SYSTEM("Unable to read complete data");
401         }
402         else {
403             E_ERROR_SYSTEM("OS error in bio_fread_2d");
404         }
405         return -1;
406     }
407     ret = bio_fread(&l_d2, sizeof(uint32), 1, fp, swap, chksum);
408     if (ret != 1) {
409         if (ret == 0) {
410             E_ERROR_SYSTEM("Unable to read complete data");
411         }
412         else {
413             E_ERROR_SYSTEM("OS error in bio_fread_2d");
414         }
415         return -1;
416     }
417     if (bio_fread_1d(&raw, e_sz, &n, fp, swap, chksum) != n)
418         return -1;
419
420     assert(n == l_d1*l_d2);
421
422     *d1 = l_d1;
423     *d2 = l_d2;
424     *arr = ckd_alloc_2d_ptr(l_d1, l_d2, raw, e_sz);
425
426     return n;
427 }
428
429 int32
430 bio_fread_3d(void ****arr,
431              size_t e_sz,
432              uint32 *d1,
433              uint32 *d2,
434              uint32 *d3,
435              FILE *fp,
436              uint32 swap,
437              uint32 *chksum)
438 {
439     uint32 l_d1;
440     uint32 l_d2;
441     uint32 l_d3;
442     uint32 n;
443     void *raw;
444     size_t ret;
445
446     ret = bio_fread(&l_d1, sizeof(uint32), 1, fp, swap, chksum);
447     if (ret != 1) {
448         if (ret == 0) {
449             E_ERROR_SYSTEM("Unable to read complete data");
450         }
451         else {
452             E_ERROR_SYSTEM("OS error in bio_fread_3d");
453         }
454         return -1;
455     }
456     ret = bio_fread(&l_d2, sizeof(uint32), 1, fp, swap, chksum);
457     if (ret != 1) {
458         if (ret == 0) {
459             E_ERROR_SYSTEM("Unable to read complete data");
460         }
461         else {
462             E_ERROR_SYSTEM("OS error in bio_fread_3d");
463         }
464         return -1;
465     }
466     ret = bio_fread(&l_d3, sizeof(uint32), 1, fp, swap, chksum);
467     if (ret != 1) {
468         if (ret == 0) {
469             E_ERROR_SYSTEM("Unable to read complete data");
470         }
471         else {
472             E_ERROR_SYSTEM("OS error in bio_fread_3d");
473         }
474         return -1;
475     }
476
477     if (bio_fread_1d(&raw, e_sz, &n, fp, swap, chksum) != n) {
478         return -1;
479     }
480
481     assert(n == l_d1 * l_d2 * l_d3);
482
483     *arr = ckd_alloc_3d_ptr(l_d1, l_d2, l_d3, raw, e_sz);
484     *d1 = l_d1;
485     *d2 = l_d2;
486     *d3 = l_d3;
487     
488     return n;
489 }
490
491 void
492 bio_verify_chksum(FILE * fp, int32 byteswap, uint32 chksum)
493 {
494     uint32 file_chksum;
495
496     if (fread(&file_chksum, sizeof(uint32), 1, fp) != 1)
497         E_FATAL("fread(chksum) failed\n");
498     if (byteswap)
499         SWAP_INT32(&file_chksum);
500     if (file_chksum != chksum)
501         E_FATAL
502             ("Checksum error; file-checksum %08x, computed %08x\n",
503              file_chksum, chksum);
504 }
505
506 int16*
507 bio_read_wavfile(char const *directory,
508                  char const *filename,
509                  char const *extension,
510                  int32 header,
511                  int32 endian,
512                  int32 *nsamps)
513 {
514     FILE *uttfp;
515     char *inputfile;
516     int32 n, l;
517     int16 *data;
518
519     n = strlen(extension);
520     l = strlen(filename);
521     if ((n <= l) && (0 == strcmp(filename + l - n, extension)))
522         extension = "";
523     inputfile = ckd_calloc(strlen(directory) + l + n + 2, 1);
524     if (directory) {
525         sprintf(inputfile, "%s/%s%s", directory, filename, extension);
526     } else {
527         sprintf(inputfile, "%s%s", filename, extension);
528     }
529
530     if ((uttfp = fopen(inputfile, "rb")) == NULL) {
531         E_FATAL("fopen(%s,rb) failed\n", inputfile);
532     }
533     fseek(uttfp, 0, SEEK_END);
534     n = ftell(uttfp);
535     fseek(uttfp, 0, SEEK_SET);
536     if (header > 0) {
537         if (fseek(uttfp, header, SEEK_SET) < 0) {
538             E_ERROR("fseek(%s,%d) failed\n", inputfile, header);
539             fclose(uttfp);
540             ckd_free(inputfile);
541             return NULL;
542         }
543         n -= header;
544     }
545     n /= sizeof(int16);
546     data = ckd_calloc(n, sizeof(*data));
547     if ((l = fread(data, sizeof(int16), n, uttfp)) < n) {
548         E_ERROR_SYSTEM("Failed to read %d samples from %s: %d", n, inputfile, l);
549         ckd_free(data);
550         ckd_free(inputfile);
551         fclose(uttfp);
552         return NULL;
553     }
554     ckd_free(inputfile);
555     fclose(uttfp);
556     if (nsamps) *nsamps = n;
557
558     return data;
559 }