| 1 | /* |
| 2 | * Copyright (C) 2013 nu774 |
| 3 | * For conditions of distribution and use, see copyright notice in COPYING |
| 4 | */ |
| 5 | #if HAVE_CONFIG_H |
| 6 | # include "config.h" |
| 7 | #endif |
| 8 | #if HAVE_STDINT_H |
| 9 | # include <stdint.h> |
| 10 | #endif |
| 11 | #include <stdio.h> |
| 12 | #include <stdlib.h> |
| 13 | #include <string.h> |
| 14 | #include <stdarg.h> |
| 15 | #include <sys/time.h> |
| 16 | #include "compat.h" |
| 17 | |
| 18 | int64_t aacenc_timer(void) |
| 19 | { |
| 20 | struct timeval tv = { 0 }; |
| 21 | gettimeofday(&tv, 0); |
| 22 | return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; |
| 23 | } |
| 24 | |
| 25 | FILE *aacenc_fopen(const char *name, const char *mode) |
| 26 | { |
| 27 | FILE *fp; |
| 28 | if (strcmp(name, "-") == 0) |
| 29 | fp = (mode[0] == 'r') ? stdin : stdout; |
| 30 | else |
| 31 | fp = fopen(name, mode); |
| 32 | return fp; |
| 33 | } |
| 34 | |
| 35 | int aacenc_seekable(FILE *fp) |
| 36 | { |
| 37 | return fseek(fp, 0, SEEK_CUR) == 0; |
| 38 | } |
| 39 | |
| 40 | /* |
| 41 | * Different from POSIX basename() when path ends with /. |
| 42 | * Since we use this only for a regular file, the difference doesn't matter. |
| 43 | */ |
| 44 | const char *aacenc_basename(const char *path) |
| 45 | { |
| 46 | const char *p = strrchr(path, '/'); |
| 47 | return p ? p + 1: path; |
| 48 | } |
| 49 | |
| 50 | #ifndef HAVE_ICONV |
| 51 | char *aacenc_to_utf8(const char *s) |
| 52 | { |
| 53 | return strdup(s); |
| 54 | } |
| 55 | #else /* HAVE_ICONV */ |
| 56 | |
| 57 | #include <sys/types.h> |
| 58 | #include <stddef.h> |
| 59 | #include <errno.h> |
| 60 | #include <iconv.h> |
| 61 | |
| 62 | #if HAVE_LOCALCHARSET_H |
| 63 | #include <localcharset.h> |
| 64 | #elif HAVE_LANGINFO_H |
| 65 | #include <langinfo.h> |
| 66 | static const char *locale_charset(void) |
| 67 | { |
| 68 | return nl_langinfo(CODESET); |
| 69 | } |
| 70 | #else |
| 71 | static const char *locale_charset(void) |
| 72 | { |
| 73 | return 0; |
| 74 | } |
| 75 | #endif |
| 76 | |
| 77 | static |
| 78 | int utf8_from_charset(const char *charset, const char *from, char **to) |
| 79 | { |
| 80 | iconv_t cd; |
| 81 | size_t fromlen, obsize, ibleft, obleft; |
| 82 | char *ip, *op; |
| 83 | |
| 84 | cd = iconv_open("UTF-8", charset); |
| 85 | if (cd == (iconv_t)-1) |
| 86 | return -1; |
| 87 | |
| 88 | fromlen = strlen(from); |
| 89 | ibleft = fromlen; |
| 90 | obsize = 2; |
| 91 | obleft = obsize - 1; |
| 92 | *to = malloc(obsize); |
| 93 | ip = (char *)from; |
| 94 | op = *to; |
| 95 | |
| 96 | while (ibleft > 0) { |
| 97 | if (iconv(cd, &ip, &ibleft, &op, &obleft) != (size_t)-1) |
| 98 | break; |
| 99 | else { |
| 100 | if (errno == E2BIG || obleft == 0) { |
| 101 | ptrdiff_t offset = op - *to; |
| 102 | obsize *= 2; |
| 103 | *to = realloc(*to, obsize); |
| 104 | op = *to + offset; |
| 105 | obleft = obsize - offset - 1; |
| 106 | } |
| 107 | if (errno == EILSEQ) { |
| 108 | ++ip; |
| 109 | --ibleft; |
| 110 | *op++ = '?'; |
| 111 | --obleft; |
| 112 | } |
| 113 | if (errno != E2BIG && errno != EILSEQ) |
| 114 | break; |
| 115 | } |
| 116 | } |
| 117 | iconv_close(cd); |
| 118 | *op = 0; |
| 119 | if (fromlen > 0 && op == *to) { |
| 120 | free(op); |
| 121 | return -1; |
| 122 | } |
| 123 | return 0; |
| 124 | } |
| 125 | |
| 126 | char *aacenc_to_utf8(const char *s) |
| 127 | { |
| 128 | char *result; |
| 129 | const char *charset; |
| 130 | |
| 131 | if ((charset = locale_charset()) == 0) |
| 132 | charset = "US-ASCII"; |
| 133 | if (utf8_from_charset(charset, s, &result) < 0) |
| 134 | result = strdup(s); |
| 135 | return result; |
| 136 | } |
| 137 | #endif /* HAVE_ICONV */ |