PageRenderTime 26ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/steghide-0.5.1/intl/localcharset.c

https://bitbucket.org/th3flyboy/steghide
C | 369 lines | 255 code | 48 blank | 66 comment | 94 complexity | 54183f6a5f12589a5fa1fa389af46046 MD5 | raw file
  1. /* Determine a canonical name for the current locale's character encoding.
  2. Copyright (C) 2000-2002 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published
  5. by the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  14. USA. */
  15. /* Written by Bruno Haible <bruno@clisp.org>. */
  16. #ifdef HAVE_CONFIG_H
  17. # include <config.h>
  18. #endif
  19. #if HAVE_STDDEF_H
  20. # include <stddef.h>
  21. #endif
  22. #include <stdio.h>
  23. #if HAVE_STRING_H
  24. # include <string.h>
  25. #else
  26. # include <strings.h>
  27. #endif
  28. #if HAVE_STDLIB_H
  29. # include <stdlib.h>
  30. #endif
  31. #if defined _WIN32 || defined __WIN32__
  32. # undef WIN32 /* avoid warning on mingw32 */
  33. # define WIN32
  34. #endif
  35. #if defined __EMX__
  36. /* Assume EMX program runs on OS/2, even if compiled under DOS. */
  37. # define OS2
  38. #endif
  39. #if !defined WIN32
  40. # if HAVE_LANGINFO_CODESET
  41. # include <langinfo.h>
  42. # else
  43. # if HAVE_SETLOCALE
  44. # include <locale.h>
  45. # endif
  46. # endif
  47. #elif defined WIN32
  48. # define WIN32_LEAN_AND_MEAN
  49. # include <windows.h>
  50. #endif
  51. #if defined OS2
  52. # define INCL_DOS
  53. # include <os2.h>
  54. #endif
  55. #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
  56. /* Win32, OS/2, DOS */
  57. # define ISSLASH(C) ((C) == '/' || (C) == '\\')
  58. #endif
  59. #ifndef DIRECTORY_SEPARATOR
  60. # define DIRECTORY_SEPARATOR '/'
  61. #endif
  62. #ifndef ISSLASH
  63. # define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
  64. #endif
  65. #ifdef HAVE_GETC_UNLOCKED
  66. # undef getc
  67. # define getc getc_unlocked
  68. #endif
  69. #ifdef __cplusplus
  70. /* When compiling with "gcc -x c++", produce a function with C linkage. */
  71. extern "C" const char * locale_charset (void);
  72. #endif
  73. /* The following static variable is declared 'volatile' to avoid a
  74. possible multithread problem in the function get_charset_aliases. If we
  75. are running in a threaded environment, and if two threads initialize
  76. 'charset_aliases' simultaneously, both will produce the same value,
  77. and everything will be ok if the two assignments to 'charset_aliases'
  78. are atomic. But I don't know what will happen if the two assignments mix. */
  79. #if __STDC__ != 1
  80. # define volatile /* empty */
  81. #endif
  82. /* Pointer to the contents of the charset.alias file, if it has already been
  83. read, else NULL. Its format is:
  84. ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */
  85. static const char * volatile charset_aliases;
  86. /* Return a pointer to the contents of the charset.alias file. */
  87. static const char *
  88. get_charset_aliases ()
  89. {
  90. const char *cp;
  91. cp = charset_aliases;
  92. if (cp == NULL)
  93. {
  94. #if !defined WIN32
  95. FILE *fp;
  96. const char *dir = LIBDIR;
  97. const char *base = "charset.alias";
  98. char *file_name;
  99. /* Concatenate dir and base into freshly allocated file_name. */
  100. {
  101. size_t dir_len = strlen (dir);
  102. size_t base_len = strlen (base);
  103. int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
  104. file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
  105. if (file_name != NULL)
  106. {
  107. memcpy (file_name, dir, dir_len);
  108. if (add_slash)
  109. file_name[dir_len] = DIRECTORY_SEPARATOR;
  110. memcpy (file_name + dir_len + add_slash, base, base_len + 1);
  111. }
  112. }
  113. if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
  114. /* Out of memory or file not found, treat it as empty. */
  115. cp = "";
  116. else
  117. {
  118. /* Parse the file's contents. */
  119. int c;
  120. char buf1[50+1];
  121. char buf2[50+1];
  122. char *res_ptr = NULL;
  123. size_t res_size = 0;
  124. size_t l1, l2;
  125. for (;;)
  126. {
  127. c = getc (fp);
  128. if (c == EOF)
  129. break;
  130. if (c == '\n' || c == ' ' || c == '\t')
  131. continue;
  132. if (c == '#')
  133. {
  134. /* Skip comment, to end of line. */
  135. do
  136. c = getc (fp);
  137. while (!(c == EOF || c == '\n'));
  138. if (c == EOF)
  139. break;
  140. continue;
  141. }
  142. ungetc (c, fp);
  143. if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
  144. break;
  145. l1 = strlen (buf1);
  146. l2 = strlen (buf2);
  147. if (res_size == 0)
  148. {
  149. res_size = l1 + 1 + l2 + 1;
  150. res_ptr = (char *) malloc (res_size + 1);
  151. }
  152. else
  153. {
  154. res_size += l1 + 1 + l2 + 1;
  155. res_ptr = (char *) realloc (res_ptr, res_size + 1);
  156. }
  157. if (res_ptr == NULL)
  158. {
  159. /* Out of memory. */
  160. res_size = 0;
  161. break;
  162. }
  163. strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
  164. strcpy (res_ptr + res_size - (l2 + 1), buf2);
  165. }
  166. fclose (fp);
  167. if (res_size == 0)
  168. cp = "";
  169. else
  170. {
  171. *(res_ptr + res_size) = '\0';
  172. cp = res_ptr;
  173. }
  174. }
  175. if (file_name != NULL)
  176. free (file_name);
  177. #else
  178. /* To avoid the troubles of installing a separate file in the same
  179. directory as the DLL and of retrieving the DLL's directory at
  180. runtime, simply inline the aliases here. */
  181. # if defined WIN32
  182. cp = "CP936" "\0" "GBK" "\0"
  183. "CP1361" "\0" "JOHAB" "\0"
  184. "CP20127" "\0" "ASCII" "\0"
  185. "CP20866" "\0" "KOI8-R" "\0"
  186. "CP21866" "\0" "KOI8-RU" "\0"
  187. "CP28591" "\0" "ISO-8859-1" "\0"
  188. "CP28592" "\0" "ISO-8859-2" "\0"
  189. "CP28593" "\0" "ISO-8859-3" "\0"
  190. "CP28594" "\0" "ISO-8859-4" "\0"
  191. "CP28595" "\0" "ISO-8859-5" "\0"
  192. "CP28596" "\0" "ISO-8859-6" "\0"
  193. "CP28597" "\0" "ISO-8859-7" "\0"
  194. "CP28598" "\0" "ISO-8859-8" "\0"
  195. "CP28599" "\0" "ISO-8859-9" "\0"
  196. "CP28605" "\0" "ISO-8859-15" "\0";
  197. # endif
  198. #endif
  199. charset_aliases = cp;
  200. }
  201. return cp;
  202. }
  203. /* Determine the current locale's character encoding, and canonicalize it
  204. into one of the canonical names listed in config.charset.
  205. The result must not be freed; it is statically allocated.
  206. If the canonical name cannot be determined, the result is a non-canonical
  207. name. */
  208. #ifdef STATIC
  209. STATIC
  210. #endif
  211. const char *
  212. locale_charset ()
  213. {
  214. const char *codeset;
  215. const char *aliases;
  216. #if !(defined WIN32 || defined OS2)
  217. # if HAVE_LANGINFO_CODESET
  218. /* Most systems support nl_langinfo (CODESET) nowadays. */
  219. codeset = nl_langinfo (CODESET);
  220. # else
  221. /* On old systems which lack it, use setlocale or getenv. */
  222. const char *locale = NULL;
  223. /* But most old systems don't have a complete set of locales. Some
  224. (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't
  225. use setlocale here; it would return "C" when it doesn't support the
  226. locale name the user has set. */
  227. # if HAVE_SETLOCALE && 0
  228. locale = setlocale (LC_CTYPE, NULL);
  229. # endif
  230. if (locale == NULL || locale[0] == '\0')
  231. {
  232. locale = getenv ("LC_ALL");
  233. if (locale == NULL || locale[0] == '\0')
  234. {
  235. locale = getenv ("LC_CTYPE");
  236. if (locale == NULL || locale[0] == '\0')
  237. locale = getenv ("LANG");
  238. }
  239. }
  240. /* On some old systems, one used to set locale = "iso8859_1". On others,
  241. you set it to "language_COUNTRY.charset". In any case, we resolve it
  242. through the charset.alias file. */
  243. codeset = locale;
  244. # endif
  245. #elif defined WIN32
  246. static char buf[2 + 10 + 1];
  247. /* Woe32 has a function returning the locale's codepage as a number. */
  248. sprintf (buf, "CP%u", GetACP ());
  249. codeset = buf;
  250. #elif defined OS2
  251. const char *locale;
  252. static char buf[2 + 10 + 1];
  253. ULONG cp[3];
  254. ULONG cplen;
  255. /* Allow user to override the codeset, as set in the operating system,
  256. with standard language environment variables. */
  257. locale = getenv ("LC_ALL");
  258. if (locale == NULL || locale[0] == '\0')
  259. {
  260. locale = getenv ("LC_CTYPE");
  261. if (locale == NULL || locale[0] == '\0')
  262. locale = getenv ("LANG");
  263. }
  264. if (locale != NULL && locale[0] != '\0')
  265. {
  266. /* If the locale name contains an encoding after the dot, return it. */
  267. const char *dot = strchr (locale, '.');
  268. if (dot != NULL)
  269. {
  270. const char *modifier;
  271. dot++;
  272. /* Look for the possible @... trailer and remove it, if any. */
  273. modifier = strchr (dot, '@');
  274. if (modifier == NULL)
  275. return dot;
  276. if (modifier - dot < sizeof (buf))
  277. {
  278. memcpy (buf, dot, modifier - dot);
  279. buf [modifier - dot] = '\0';
  280. return buf;
  281. }
  282. }
  283. /* Resolve through the charset.alias file. */
  284. codeset = locale;
  285. }
  286. else
  287. {
  288. /* OS/2 has a function returning the locale's codepage as a number. */
  289. if (DosQueryCp (sizeof (cp), cp, &cplen))
  290. codeset = "";
  291. else
  292. {
  293. sprintf (buf, "CP%u", cp[0]);
  294. codeset = buf;
  295. }
  296. }
  297. #endif
  298. if (codeset == NULL)
  299. /* The canonical name cannot be determined. */
  300. codeset = "";
  301. /* Resolve alias. */
  302. for (aliases = get_charset_aliases ();
  303. *aliases != '\0';
  304. aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
  305. if (strcmp (codeset, aliases) == 0
  306. || (aliases[0] == '*' && aliases[1] == '\0'))
  307. {
  308. codeset = aliases + strlen (aliases) + 1;
  309. break;
  310. }
  311. /* Don't return an empty string. GNU libc and GNU libiconv interpret
  312. the empty string as denoting "the locale's character encoding",
  313. thus GNU libiconv would call this function a second time. */
  314. if (codeset[0] == '\0')
  315. codeset = "ASCII";
  316. return codeset;
  317. }