| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
|
|
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <assert.h> |
|
|
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
|
|
| #ifdef HAVE_SYS_TYPES_H |
| #include <sys/types.h> |
| #endif |
|
|
| #ifdef HAVE_SYS_STAT_H |
| #include <sys/stat.h> |
| #endif |
|
|
| #if defined(_WIN32) && !defined(CYGWIN) |
| #include <direct.h> |
| #endif |
|
|
| #include <pocketsphinx/err.h> |
|
|
| #include "util/pio.h" |
| #include "util/filename.h" |
| #include "util/strfuncs.h" |
| #include "util/ckd_alloc.h" |
|
|
| #ifndef EXEEXT |
| #define EXEEXT "" |
| #endif |
|
|
| enum { |
| COMP_NONE, |
| COMP_COMPRESS, |
| COMP_GZIP, |
| COMP_BZIP2 |
| }; |
|
|
| static void |
| guess_comptype(char const *file, int32 *ispipe, int32 *isgz) |
| { |
| size_t k; |
|
|
| k = strlen(file); |
| *ispipe = 0; |
| *isgz = COMP_NONE; |
| if ((k > 2) |
| && ((strcmp(file + k - 2, ".Z") == 0) |
| || (strcmp(file + k - 2, ".z") == 0))) { |
| *ispipe = 1; |
| *isgz = COMP_COMPRESS; |
| } |
| else if ((k > 3) && ((strcmp(file + k - 3, ".gz") == 0) |
| || (strcmp(file + k - 3, ".GZ") == 0))) { |
| *ispipe = 1; |
| *isgz = COMP_GZIP; |
| } |
| else if ((k > 4) && ((strcmp(file + k - 4, ".bz2") == 0) |
| || (strcmp(file + k - 4, ".BZ2") == 0))) { |
| *ispipe = 1; |
| *isgz = COMP_BZIP2; |
| } |
| } |
|
|
| FILE * |
| fopen_comp(const char *file, const char *mode, int32 * ispipe) |
| { |
| FILE *fp; |
|
|
| #ifndef HAVE_POPEN |
| *ispipe = 0; |
| #else |
| int32 isgz; |
| guess_comptype(file, ispipe, &isgz); |
| #endif |
|
|
| if (*ispipe) { |
| #ifndef HAVE_POPEN |
| |
| E_FATAL("No popen() on WinCE\n"); |
| #else |
| if (strcmp(mode, "r") == 0) { |
| char *command; |
| switch (isgz) { |
| case COMP_GZIP: |
| command = string_join("gunzip" EXEEXT, " -c ", file, NULL); |
| break; |
| case COMP_COMPRESS: |
| command = string_join("zcat" EXEEXT, " ", file, NULL); |
| break; |
| case COMP_BZIP2: |
| command = string_join("bunzip2" EXEEXT, " -c ", file, NULL); |
| break; |
| default: |
| command = NULL; |
| E_FATAL("Unknown compression type %d\n", isgz); |
| } |
| if ((fp = popen(command, mode)) == NULL) { |
| E_ERROR_SYSTEM("Failed to open a pipe for a command '%s' mode '%s'", command, mode); |
| ckd_free(command); |
| return NULL; |
| } |
| ckd_free(command); |
| } |
| else if (strcmp(mode, "w") == 0) { |
| char *command; |
| switch (isgz) { |
| case COMP_GZIP: |
| command = string_join("gzip" EXEEXT, " > ", file, NULL); |
| break; |
| case COMP_COMPRESS: |
| command = string_join("compress" EXEEXT, " -c > ", file, NULL); |
| break; |
| case COMP_BZIP2: |
| command = string_join("bzip2" EXEEXT, " > ", file, NULL); |
| break; |
| default: |
| command = NULL; |
| E_FATAL("Unknown compression type %d\n", isgz); |
| } |
| if ((fp = popen(command, mode)) == NULL) { |
| E_ERROR_SYSTEM("Failed to open a pipe for a command '%s' mode '%s'", command, mode); |
| ckd_free(command); |
| return NULL; |
| } |
| ckd_free(command); |
| } |
| else { |
| E_ERROR("Compressed file operation for mode %s is not supported\n", mode); |
| return NULL; |
| } |
| #endif |
| } |
| else { |
| fp = fopen(file, mode); |
| } |
|
|
| return (fp); |
| } |
|
|
|
|
| void |
| fclose_comp(FILE * fp, int32 ispipe) |
| { |
| if (ispipe) { |
| #ifdef HAVE_POPEN |
| #if defined(_WIN32) && (!defined(__SYMBIAN32__)) |
| _pclose(fp); |
| #else |
| pclose(fp); |
| #endif |
| #endif |
| } |
| else |
| fclose(fp); |
| } |
|
|
|
|
| FILE * |
| fopen_compchk(const char *file, int32 * ispipe) |
| { |
| #ifndef HAVE_POPEN |
| *ispipe = 0; |
| |
| return (fopen_comp(file, "r", ispipe)); |
| #else |
| int32 isgz; |
| FILE *fh; |
|
|
| |
| if ((fh = fopen_comp(file, "r", ispipe)) != NULL) |
| return fh; |
| else { |
| char *tmpfile; |
| size_t k; |
|
|
| |
| guess_comptype(file, ispipe, &isgz); |
| k = strlen(file); |
| tmpfile = ckd_calloc(k+5, 1); |
| strcpy(tmpfile, file); |
| switch (isgz) { |
| case COMP_GZIP: |
| tmpfile[k - 3] = '\0'; |
| break; |
| case COMP_BZIP2: |
| tmpfile[k - 4] = '\0'; |
| break; |
| case COMP_COMPRESS: |
| tmpfile[k - 2] = '\0'; |
| break; |
| case COMP_NONE: |
| strcpy(tmpfile + k, ".gz"); |
| if ((fh = fopen_comp(tmpfile, "r", ispipe)) != NULL) { |
| E_WARN("Using %s instead of %s\n", tmpfile, file); |
| ckd_free(tmpfile); |
| return fh; |
| } |
| strcpy(tmpfile + k, ".bz2"); |
| if ((fh = fopen_comp(tmpfile, "r", ispipe)) != NULL) { |
| E_WARN("Using %s instead of %s\n", tmpfile, file); |
| ckd_free(tmpfile); |
| return fh; |
| } |
| strcpy(tmpfile + k, ".Z"); |
| if ((fh = fopen_comp(tmpfile, "r", ispipe)) != NULL) { |
| E_WARN("Using %s instead of %s\n", tmpfile, file); |
| ckd_free(tmpfile); |
| return fh; |
| } |
| ckd_free(tmpfile); |
| return NULL; |
| } |
| E_WARN("Using %s instead of %s\n", tmpfile, file); |
| fh = fopen_comp(tmpfile, "r", ispipe); |
| ckd_free(tmpfile); |
| return NULL; |
| } |
| #endif |
| } |
|
|
| lineiter_t * |
| lineiter_start(FILE *fh) |
| { |
| lineiter_t *li; |
|
|
| li = (lineiter_t *)ckd_calloc(1, sizeof(*li)); |
| li->buf = (char *)ckd_malloc(128); |
| li->buf[0] = '\0'; |
| li->bsiz = 128; |
| li->len = 0; |
| li->fh = fh; |
|
|
| li = lineiter_next(li); |
| |
| |
| |
| if (li && 0 == strncmp(li->buf, "\xef\xbb\xbf", 3)) { |
| memmove(li->buf, li->buf + 3, strlen(li->buf + 1)); |
| li->len -= 3; |
| } |
| |
| return li; |
| } |
|
|
| lineiter_t * |
| lineiter_start_clean(FILE *fh) |
| { |
| lineiter_t *li; |
| |
| li = lineiter_start(fh); |
| |
| if (li == NULL) |
| return li; |
| |
| li->clean = TRUE; |
| |
| if (li->buf && li->buf[0] == '#') { |
| li = lineiter_next(li); |
| } else { |
| string_trim(li->buf, STRING_BOTH); |
| } |
| |
| return li; |
| } |
|
|
|
|
| static lineiter_t * |
| lineiter_next_plain(lineiter_t *li) |
| { |
| |
| li->lineno++; |
| |
| |
| if (fgets(li->buf, li->bsiz, li->fh) == NULL) { |
| lineiter_free(li); |
| return NULL; |
| } |
| |
| |
| li->len = (int32)strlen(li->buf); |
| if (li->len < li->bsiz - 1 || li->buf[li->len - 1] == '\n') |
| return li; |
|
|
| |
| while (1) { |
| li->bsiz *= 2; |
| li->buf = (char *)ckd_realloc(li->buf, li->bsiz); |
| |
| if (fgets(li->buf + li->len, li->bsiz - li->len, li->fh) == NULL) { |
| li->len += strlen(li->buf + li->len); |
| return li; |
| } |
| li->len += strlen(li->buf + li->len); |
| |
| if (li->len < li->bsiz - 1 || li->buf[li->len - 1] == '\n') |
| return li; |
| } |
|
|
| |
| return li; |
| } |
|
|
|
|
| lineiter_t * |
| lineiter_next(lineiter_t *li) |
| { |
| if (!li->clean) |
| return lineiter_next_plain(li); |
| |
| for (li = lineiter_next_plain(li); li; li = lineiter_next_plain(li)) { |
| if (li->buf) { |
| li->buf = string_trim(li->buf, STRING_BOTH); |
| if (li->buf[0] != 0 && li->buf[0] != '#') |
| break; |
| } |
| } |
| return li; |
| } |
|
|
| int lineiter_lineno(lineiter_t *li) |
| { |
| return li->lineno; |
| } |
|
|
| void |
| lineiter_free(lineiter_t *li) |
| { |
| if (li == NULL) |
| return; |
| ckd_free(li->buf); |
| ckd_free(li); |
| } |
|
|
| char * |
| fread_line(FILE *stream, size_t *out_len) |
| { |
| char *output, *outptr; |
| char buf[128]; |
|
|
| output = outptr = NULL; |
| while (fgets(buf, sizeof(buf), stream)) { |
| size_t len = strlen(buf); |
| |
| if (output == NULL) { |
| output = (char *)ckd_malloc(len + 1); |
| outptr = output; |
| } |
| else { |
| size_t cur = outptr - output; |
| output = (char *)ckd_realloc(output, cur + len + 1); |
| outptr = output + cur; |
| } |
| memcpy(outptr, buf, len + 1); |
| outptr += len; |
| |
| if (len < sizeof(buf)-1 || buf[len-1] == '\n') |
| break; |
| } |
| if (out_len) *out_len = outptr - output; |
| return output; |
| } |
|
|
| #define FREAD_RETRY_COUNT 60 |
|
|
| int32 |
| fread_retry(void *pointer, int32 size, int32 num_items, FILE * stream) |
| { |
| char *data; |
| size_t n_items_read; |
| size_t n_items_rem; |
| uint32 n_retry_rem; |
| int32 loc; |
|
|
| n_retry_rem = FREAD_RETRY_COUNT; |
|
|
| data = (char *)pointer; |
| loc = 0; |
| n_items_rem = num_items; |
|
|
| do { |
| n_items_read = fread(&data[loc], size, n_items_rem, stream); |
|
|
| n_items_rem -= n_items_read; |
|
|
| if (n_items_rem > 0) { |
| |
|
|
| if (n_retry_rem == 0) |
| return -1; |
|
|
| if (n_retry_rem == FREAD_RETRY_COUNT) { |
| E_ERROR_SYSTEM("fread() failed; retrying...\n"); |
| } |
|
|
| --n_retry_rem; |
|
|
| loc += n_items_read * size; |
| #if !defined(_WIN32) && defined(HAVE_UNISTD_H) |
| sleep(1); |
| #endif |
| } |
| } while (n_items_rem > 0); |
|
|
| return num_items; |
| } |
|
|
|
|
| #ifdef _WIN32_WCE |
| int32 |
| stat_retry(const char *file, struct stat * statbuf) |
| { |
| WIN32_FIND_DATAW file_data; |
| HANDLE *h; |
| wchar_t *wfile; |
| size_t len; |
|
|
| len = mbstowcs(NULL, file, 0) + 1; |
| wfile = ckd_calloc(len, sizeof(*wfile)); |
| mbstowcs(wfile, file, len); |
| if ((h = FindFirstFileW(wfile, &file_data)) == INVALID_HANDLE_VALUE) { |
| ckd_free(wfile); |
| return -1; |
| } |
| ckd_free(wfile); |
| memset(statbuf, 0, sizeof(*statbuf)); |
| statbuf->st_mtime = file_data.ftLastWriteTime.dwLowDateTime; |
| statbuf->st_size = file_data.nFileSizeLow; |
| FindClose(h); |
|
|
| return 0; |
| } |
|
|
|
|
| int32 |
| stat_mtime(const char *file) |
| { |
| struct stat statbuf; |
|
|
| if (stat_retry(file, &statbuf) != 0) |
| return -1; |
|
|
| return ((int32) statbuf.st_mtime); |
| } |
| #else |
| #define STAT_RETRY_COUNT 10 |
| int32 |
| stat_retry(const char *file, struct stat * statbuf) |
| { |
| int32 i; |
|
|
| for (i = 0; i < STAT_RETRY_COUNT; i++) { |
| #ifndef HAVE_SYS_STAT_H |
| FILE *fp; |
|
|
| if ((fp = (FILE *)fopen(file, "r")) != 0) { |
| fseek(fp, 0, SEEK_END); |
| statbuf->st_size = ftell(fp); |
| fclose(fp); |
| return 0; |
| } |
| #else |
| if (stat(file, statbuf) == 0) |
| return 0; |
| #endif |
| if (i == 0) { |
| E_ERROR_SYSTEM("Failed to stat file '%s'; retrying...", file); |
| } |
| #ifdef HAVE_UNISTD_H |
| sleep(1); |
| #endif |
| } |
|
|
| return -1; |
| } |
|
|
| int32 |
| stat_mtime(const char *file) |
| { |
| struct stat statbuf; |
|
|
| #ifdef HAVE_SYS_STAT_H |
| if (stat(file, &statbuf) != 0) |
| return -1; |
| #else |
| if (stat_retry(file, &statbuf) != 0) |
| return -1; |
| #endif |
|
|
| return ((int32) statbuf.st_mtime); |
| } |
| #endif |
|
|
| struct bit_encode_s { |
| FILE *fh; |
| unsigned char buf, bbits; |
| int16 refcount; |
| }; |
|
|
| bit_encode_t * |
| bit_encode_attach(FILE *outfh) |
| { |
| bit_encode_t *be; |
|
|
| be = (bit_encode_t *)ckd_calloc(1, sizeof(*be)); |
| be->refcount = 1; |
| be->fh = outfh; |
| return be; |
| } |
|
|
| bit_encode_t * |
| bit_encode_retain(bit_encode_t *be) |
| { |
| ++be->refcount; |
| return be; |
| } |
|
|
| int |
| bit_encode_free(bit_encode_t *be) |
| { |
| if (be == NULL) |
| return 0; |
| if (--be->refcount > 0) |
| return be->refcount; |
| ckd_free(be); |
|
|
| return 0; |
| } |
|
|
| int |
| bit_encode_write(bit_encode_t *be, unsigned char const *bits, int nbits) |
| { |
| int tbits; |
|
|
| tbits = nbits + be->bbits; |
| if (tbits < 8) { |
| |
| be->buf |= ((bits[0] >> (8 - nbits)) << (8 - tbits)); |
| } |
| else { |
| int i = 0; |
| while (tbits >= 8) { |
| |
| fputc(be->buf | ((bits[i]) >> be->bbits), be->fh); |
| |
| be->buf = (bits[i] << (8 - be->bbits)) & 0xff; |
| tbits -= 8; |
| ++i; |
| } |
| } |
| |
| be->bbits = tbits; |
|
|
| return nbits; |
| } |
|
|
| int |
| bit_encode_write_cw(bit_encode_t *be, uint32 codeword, int nbits) |
| { |
| unsigned char bits[4]; |
| codeword <<= (32 - nbits); |
| bits[0] = (codeword >> 24) & 0xff; |
| bits[1] = (codeword >> 16) & 0xff; |
| bits[2] = (codeword >> 8) & 0xff; |
| bits[3] = codeword & 0xff; |
| return bit_encode_write(be, bits, nbits); |
| } |
|
|
| int |
| bit_encode_flush(bit_encode_t *be) |
| { |
| if (be->bbits) { |
| fputc(be->buf, be->fh); |
| be->bbits = 0; |
| } |
| return 0; |
| } |
|
|
| int |
| build_directory(const char *path) |
| { |
| int rv; |
|
|
| |
| if (strlen(path) == 0) |
| return -1; |
|
|
| #if defined(_WIN32) && !defined(CYGWIN) |
| else if ((rv = _mkdir(path)) == 0) |
| return 0; |
| #elif defined(HAVE_SYS_STAT_H) |
| else if ((rv = mkdir(path, 0777)) == 0) |
| return 0; |
| #endif |
|
|
| |
| else if (errno == EEXIST) |
| return 0; |
| else if (errno != ENOENT) { |
| E_ERROR_SYSTEM("Failed to create %s", path); |
| return -1; |
| } |
| else { |
| char *dirname = ckd_salloc(path); |
| path2dirname(path, dirname); |
| build_directory(dirname); |
| ckd_free(dirname); |
|
|
| #if defined(_WIN32) && !defined(CYGWIN) |
| return _mkdir(path); |
| #elif defined(HAVE_SYS_STAT_H) |
| return mkdir(path, 0777); |
| #endif |
| } |
| return -1; |
| } |
|
|