non-ascii.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. ***************************************************************************/
  22. #include "curl_setup.h"
  23. #ifdef CURL_DOES_CONVERSIONS
  24. #include <curl/curl.h>
  25. #include "non-ascii.h"
  26. #include "formdata.h"
  27. #include "sendf.h"
  28. #include "urldata.h"
  29. #include "multiif.h"
  30. #include "curl_memory.h"
  31. /* The last #include file should be: */
  32. #include "memdebug.h"
  33. #ifdef HAVE_ICONV
  34. #include <iconv.h>
  35. /* set default codesets for iconv */
  36. #ifndef CURL_ICONV_CODESET_OF_NETWORK
  37. #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
  38. #endif
  39. #ifndef CURL_ICONV_CODESET_FOR_UTF8
  40. #define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
  41. #endif
  42. #define ICONV_ERROR (size_t)-1
  43. #endif /* HAVE_ICONV */
  44. /*
  45. * Curl_convert_clone() returns a malloced copy of the source string (if
  46. * returning CURLE_OK), with the data converted to network format.
  47. */
  48. CURLcode Curl_convert_clone(struct Curl_easy *data,
  49. const char *indata,
  50. size_t insize,
  51. char **outbuf)
  52. {
  53. char *convbuf;
  54. CURLcode result;
  55. convbuf = malloc(insize);
  56. if(!convbuf)
  57. return CURLE_OUT_OF_MEMORY;
  58. memcpy(convbuf, indata, insize);
  59. result = Curl_convert_to_network(data, convbuf, insize);
  60. if(result) {
  61. free(convbuf);
  62. return result;
  63. }
  64. *outbuf = convbuf; /* return the converted buffer */
  65. return CURLE_OK;
  66. }
  67. /*
  68. * Curl_convert_to_network() is an internal function for performing ASCII
  69. * conversions on non-ASCII platforms. It converts the buffer _in place_.
  70. */
  71. CURLcode Curl_convert_to_network(struct Curl_easy *data,
  72. char *buffer, size_t length)
  73. {
  74. if(data && data->set.convtonetwork) {
  75. /* use translation callback */
  76. CURLcode result;
  77. Curl_set_in_callback(data, true);
  78. result = data->set.convtonetwork(buffer, length);
  79. Curl_set_in_callback(data, false);
  80. if(result) {
  81. failf(data,
  82. "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
  83. (int)result, curl_easy_strerror(result));
  84. }
  85. return result;
  86. }
  87. else {
  88. #ifdef HAVE_ICONV
  89. /* do the translation ourselves */
  90. iconv_t tmpcd = (iconv_t) -1;
  91. iconv_t *cd = &tmpcd;
  92. char *input_ptr, *output_ptr;
  93. size_t in_bytes, out_bytes, rc;
  94. /* open an iconv conversion descriptor if necessary */
  95. if(data)
  96. cd = &data->outbound_cd;
  97. if(*cd == (iconv_t)-1) {
  98. *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
  99. CURL_ICONV_CODESET_OF_HOST);
  100. if(*cd == (iconv_t)-1) {
  101. failf(data,
  102. "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
  103. CURL_ICONV_CODESET_OF_NETWORK,
  104. CURL_ICONV_CODESET_OF_HOST,
  105. errno, strerror(errno));
  106. return CURLE_CONV_FAILED;
  107. }
  108. }
  109. /* call iconv */
  110. input_ptr = output_ptr = buffer;
  111. in_bytes = out_bytes = length;
  112. rc = iconv(*cd, &input_ptr, &in_bytes,
  113. &output_ptr, &out_bytes);
  114. if(!data)
  115. iconv_close(tmpcd);
  116. if((rc == ICONV_ERROR) || (in_bytes != 0)) {
  117. failf(data,
  118. "The Curl_convert_to_network iconv call failed with errno %i: %s",
  119. errno, strerror(errno));
  120. return CURLE_CONV_FAILED;
  121. }
  122. #else
  123. failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
  124. return CURLE_CONV_REQD;
  125. #endif /* HAVE_ICONV */
  126. }
  127. return CURLE_OK;
  128. }
  129. /*
  130. * Curl_convert_from_network() is an internal function for performing ASCII
  131. * conversions on non-ASCII platforms. It converts the buffer _in place_.
  132. */
  133. CURLcode Curl_convert_from_network(struct Curl_easy *data,
  134. char *buffer, size_t length)
  135. {
  136. if(data && data->set.convfromnetwork) {
  137. /* use translation callback */
  138. CURLcode result;
  139. Curl_set_in_callback(data, true);
  140. result = data->set.convfromnetwork(buffer, length);
  141. Curl_set_in_callback(data, false);
  142. if(result) {
  143. failf(data,
  144. "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
  145. (int)result, curl_easy_strerror(result));
  146. }
  147. return result;
  148. }
  149. else {
  150. #ifdef HAVE_ICONV
  151. /* do the translation ourselves */
  152. iconv_t tmpcd = (iconv_t) -1;
  153. iconv_t *cd = &tmpcd;
  154. char *input_ptr, *output_ptr;
  155. size_t in_bytes, out_bytes, rc;
  156. /* open an iconv conversion descriptor if necessary */
  157. if(data)
  158. cd = &data->inbound_cd;
  159. if(*cd == (iconv_t)-1) {
  160. *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  161. CURL_ICONV_CODESET_OF_NETWORK);
  162. if(*cd == (iconv_t)-1) {
  163. failf(data,
  164. "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
  165. CURL_ICONV_CODESET_OF_HOST,
  166. CURL_ICONV_CODESET_OF_NETWORK,
  167. errno, strerror(errno));
  168. return CURLE_CONV_FAILED;
  169. }
  170. }
  171. /* call iconv */
  172. input_ptr = output_ptr = buffer;
  173. in_bytes = out_bytes = length;
  174. rc = iconv(*cd, &input_ptr, &in_bytes,
  175. &output_ptr, &out_bytes);
  176. if(!data)
  177. iconv_close(tmpcd);
  178. if((rc == ICONV_ERROR) || (in_bytes != 0)) {
  179. failf(data,
  180. "Curl_convert_from_network iconv call failed with errno %i: %s",
  181. errno, strerror(errno));
  182. return CURLE_CONV_FAILED;
  183. }
  184. #else
  185. failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
  186. return CURLE_CONV_REQD;
  187. #endif /* HAVE_ICONV */
  188. }
  189. return CURLE_OK;
  190. }
  191. /*
  192. * Curl_convert_from_utf8() is an internal function for performing UTF-8
  193. * conversions on non-ASCII platforms.
  194. */
  195. CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
  196. char *buffer, size_t length)
  197. {
  198. if(data && data->set.convfromutf8) {
  199. /* use translation callback */
  200. CURLcode result;
  201. Curl_set_in_callback(data, true);
  202. result = data->set.convfromutf8(buffer, length);
  203. Curl_set_in_callback(data, false);
  204. if(result) {
  205. failf(data,
  206. "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
  207. (int)result, curl_easy_strerror(result));
  208. }
  209. return result;
  210. }
  211. else {
  212. #ifdef HAVE_ICONV
  213. /* do the translation ourselves */
  214. iconv_t tmpcd = (iconv_t) -1;
  215. iconv_t *cd = &tmpcd;
  216. char *input_ptr;
  217. char *output_ptr;
  218. size_t in_bytes, out_bytes, rc;
  219. /* open an iconv conversion descriptor if necessary */
  220. if(data)
  221. cd = &data->utf8_cd;
  222. if(*cd == (iconv_t)-1) {
  223. *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  224. CURL_ICONV_CODESET_FOR_UTF8);
  225. if(*cd == (iconv_t)-1) {
  226. failf(data,
  227. "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
  228. CURL_ICONV_CODESET_OF_HOST,
  229. CURL_ICONV_CODESET_FOR_UTF8,
  230. errno, strerror(errno));
  231. return CURLE_CONV_FAILED;
  232. }
  233. }
  234. /* call iconv */
  235. input_ptr = output_ptr = buffer;
  236. in_bytes = out_bytes = length;
  237. rc = iconv(*cd, &input_ptr, &in_bytes,
  238. &output_ptr, &out_bytes);
  239. if(!data)
  240. iconv_close(tmpcd);
  241. if((rc == ICONV_ERROR) || (in_bytes != 0)) {
  242. failf(data,
  243. "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
  244. errno, strerror(errno));
  245. return CURLE_CONV_FAILED;
  246. }
  247. if(output_ptr < input_ptr) {
  248. /* null terminate the now shorter output string */
  249. *output_ptr = 0x00;
  250. }
  251. #else
  252. failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
  253. return CURLE_CONV_REQD;
  254. #endif /* HAVE_ICONV */
  255. }
  256. return CURLE_OK;
  257. }
  258. /*
  259. * Init conversion stuff for a Curl_easy
  260. */
  261. void Curl_convert_init(struct Curl_easy *data)
  262. {
  263. #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
  264. /* conversion descriptors for iconv calls */
  265. data->outbound_cd = (iconv_t)-1;
  266. data->inbound_cd = (iconv_t)-1;
  267. data->utf8_cd = (iconv_t)-1;
  268. #else
  269. (void)data;
  270. #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
  271. }
  272. /*
  273. * Setup conversion stuff for a Curl_easy
  274. */
  275. void Curl_convert_setup(struct Curl_easy *data)
  276. {
  277. data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  278. CURL_ICONV_CODESET_OF_NETWORK);
  279. data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
  280. CURL_ICONV_CODESET_OF_HOST);
  281. data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  282. CURL_ICONV_CODESET_FOR_UTF8);
  283. }
  284. /*
  285. * Close conversion stuff for a Curl_easy
  286. */
  287. void Curl_convert_close(struct Curl_easy *data)
  288. {
  289. #ifdef HAVE_ICONV
  290. /* close iconv conversion descriptors */
  291. if(data->inbound_cd != (iconv_t)-1) {
  292. iconv_close(data->inbound_cd);
  293. }
  294. if(data->outbound_cd != (iconv_t)-1) {
  295. iconv_close(data->outbound_cd);
  296. }
  297. if(data->utf8_cd != (iconv_t)-1) {
  298. iconv_close(data->utf8_cd);
  299. }
  300. #else
  301. (void)data;
  302. #endif /* HAVE_ICONV */
  303. }
  304. #endif /* CURL_DOES_CONVERSIONS */