non-ascii.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2012, 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 http://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 "curl_memory.h"
  30. /* The last #include file should be: */
  31. #include "memdebug.h"
  32. #ifdef HAVE_ICONV
  33. #include <iconv.h>
  34. /* set default codesets for iconv */
  35. #ifndef CURL_ICONV_CODESET_OF_NETWORK
  36. #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
  37. #endif
  38. #ifndef CURL_ICONV_CODESET_FOR_UTF8
  39. #define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
  40. #endif
  41. #define ICONV_ERROR (size_t)-1
  42. #endif /* HAVE_ICONV */
  43. /*
  44. * Curl_convert_clone() returns a malloced copy of the source string (if
  45. * returning CURLE_OK), with the data converted to network format.
  46. */
  47. CURLcode Curl_convert_clone(struct SessionHandle *data,
  48. const char *indata,
  49. size_t insize,
  50. char **outbuf)
  51. {
  52. char *convbuf;
  53. CURLcode result;
  54. convbuf = malloc(insize);
  55. if(!convbuf)
  56. return CURLE_OUT_OF_MEMORY;
  57. memcpy(convbuf, indata, insize);
  58. result = Curl_convert_to_network(data, convbuf, insize);
  59. if(result) {
  60. free(convbuf);
  61. return result;
  62. }
  63. *outbuf = convbuf; /* return the converted buffer */
  64. return CURLE_OK;
  65. }
  66. /*
  67. * Curl_convert_to_network() is an internal function for performing ASCII
  68. * conversions on non-ASCII platforms. It convers the buffer _in place_.
  69. */
  70. CURLcode Curl_convert_to_network(struct SessionHandle *data,
  71. char *buffer, size_t length)
  72. {
  73. CURLcode rc;
  74. if(data->set.convtonetwork) {
  75. /* use translation callback */
  76. rc = data->set.convtonetwork(buffer, length);
  77. if(rc != CURLE_OK) {
  78. failf(data,
  79. "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
  80. (int)rc, curl_easy_strerror(rc));
  81. }
  82. return rc;
  83. }
  84. else {
  85. #ifdef HAVE_ICONV
  86. /* do the translation ourselves */
  87. char *input_ptr, *output_ptr;
  88. size_t in_bytes, out_bytes, rc;
  89. int error;
  90. /* open an iconv conversion descriptor if necessary */
  91. if(data->outbound_cd == (iconv_t)-1) {
  92. data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
  93. CURL_ICONV_CODESET_OF_HOST);
  94. if(data->outbound_cd == (iconv_t)-1) {
  95. error = ERRNO;
  96. failf(data,
  97. "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
  98. CURL_ICONV_CODESET_OF_NETWORK,
  99. CURL_ICONV_CODESET_OF_HOST,
  100. error, strerror(error));
  101. return CURLE_CONV_FAILED;
  102. }
  103. }
  104. /* call iconv */
  105. input_ptr = output_ptr = buffer;
  106. in_bytes = out_bytes = length;
  107. rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
  108. &output_ptr, &out_bytes);
  109. if((rc == ICONV_ERROR) || (in_bytes != 0)) {
  110. error = ERRNO;
  111. failf(data,
  112. "The Curl_convert_to_network iconv call failed with errno %i: %s",
  113. error, strerror(error));
  114. return CURLE_CONV_FAILED;
  115. }
  116. #else
  117. failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
  118. return CURLE_CONV_REQD;
  119. #endif /* HAVE_ICONV */
  120. }
  121. return CURLE_OK;
  122. }
  123. /*
  124. * Curl_convert_from_network() is an internal function for performing ASCII
  125. * conversions on non-ASCII platforms. It convers the buffer _in place_.
  126. */
  127. CURLcode Curl_convert_from_network(struct SessionHandle *data,
  128. char *buffer, size_t length)
  129. {
  130. CURLcode rc;
  131. if(data->set.convfromnetwork) {
  132. /* use translation callback */
  133. rc = data->set.convfromnetwork(buffer, length);
  134. if(rc != CURLE_OK) {
  135. failf(data,
  136. "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
  137. (int)rc, curl_easy_strerror(rc));
  138. }
  139. return rc;
  140. }
  141. else {
  142. #ifdef HAVE_ICONV
  143. /* do the translation ourselves */
  144. char *input_ptr, *output_ptr;
  145. size_t in_bytes, out_bytes, rc;
  146. int error;
  147. /* open an iconv conversion descriptor if necessary */
  148. if(data->inbound_cd == (iconv_t)-1) {
  149. data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  150. CURL_ICONV_CODESET_OF_NETWORK);
  151. if(data->inbound_cd == (iconv_t)-1) {
  152. error = ERRNO;
  153. failf(data,
  154. "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
  155. CURL_ICONV_CODESET_OF_HOST,
  156. CURL_ICONV_CODESET_OF_NETWORK,
  157. error, strerror(error));
  158. return CURLE_CONV_FAILED;
  159. }
  160. }
  161. /* call iconv */
  162. input_ptr = output_ptr = buffer;
  163. in_bytes = out_bytes = length;
  164. rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
  165. &output_ptr, &out_bytes);
  166. if((rc == ICONV_ERROR) || (in_bytes != 0)) {
  167. error = ERRNO;
  168. failf(data,
  169. "Curl_convert_from_network iconv call failed with errno %i: %s",
  170. error, strerror(error));
  171. return CURLE_CONV_FAILED;
  172. }
  173. #else
  174. failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
  175. return CURLE_CONV_REQD;
  176. #endif /* HAVE_ICONV */
  177. }
  178. return CURLE_OK;
  179. }
  180. /*
  181. * Curl_convert_from_utf8() is an internal function for performing UTF-8
  182. * conversions on non-ASCII platforms.
  183. */
  184. CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
  185. char *buffer, size_t length)
  186. {
  187. CURLcode rc;
  188. if(data->set.convfromutf8) {
  189. /* use translation callback */
  190. rc = data->set.convfromutf8(buffer, length);
  191. if(rc != CURLE_OK) {
  192. failf(data,
  193. "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
  194. (int)rc, curl_easy_strerror(rc));
  195. }
  196. return rc;
  197. }
  198. else {
  199. #ifdef HAVE_ICONV
  200. /* do the translation ourselves */
  201. const char *input_ptr;
  202. char *output_ptr;
  203. size_t in_bytes, out_bytes, rc;
  204. int error;
  205. /* open an iconv conversion descriptor if necessary */
  206. if(data->utf8_cd == (iconv_t)-1) {
  207. data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  208. CURL_ICONV_CODESET_FOR_UTF8);
  209. if(data->utf8_cd == (iconv_t)-1) {
  210. error = ERRNO;
  211. failf(data,
  212. "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
  213. CURL_ICONV_CODESET_OF_HOST,
  214. CURL_ICONV_CODESET_FOR_UTF8,
  215. error, strerror(error));
  216. return CURLE_CONV_FAILED;
  217. }
  218. }
  219. /* call iconv */
  220. input_ptr = output_ptr = buffer;
  221. in_bytes = out_bytes = length;
  222. rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
  223. &output_ptr, &out_bytes);
  224. if((rc == ICONV_ERROR) || (in_bytes != 0)) {
  225. error = ERRNO;
  226. failf(data,
  227. "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
  228. error, strerror(error));
  229. return CURLE_CONV_FAILED;
  230. }
  231. if(output_ptr < input_ptr) {
  232. /* null terminate the now shorter output string */
  233. *output_ptr = 0x00;
  234. }
  235. #else
  236. failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
  237. return CURLE_CONV_REQD;
  238. #endif /* HAVE_ICONV */
  239. }
  240. return CURLE_OK;
  241. }
  242. /*
  243. * Init conversion stuff for a SessionHandle
  244. */
  245. void Curl_convert_init(struct SessionHandle *data)
  246. {
  247. #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
  248. /* conversion descriptors for iconv calls */
  249. data->outbound_cd = (iconv_t)-1;
  250. data->inbound_cd = (iconv_t)-1;
  251. data->utf8_cd = (iconv_t)-1;
  252. #else
  253. (void)data;
  254. #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
  255. }
  256. /*
  257. * Setup conversion stuff for a SessionHandle
  258. */
  259. void Curl_convert_setup(struct SessionHandle *data)
  260. {
  261. data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  262. CURL_ICONV_CODESET_OF_NETWORK);
  263. data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
  264. CURL_ICONV_CODESET_OF_HOST);
  265. data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
  266. CURL_ICONV_CODESET_FOR_UTF8);
  267. }
  268. /*
  269. * Close conversion stuff for a SessionHandle
  270. */
  271. void Curl_convert_close(struct SessionHandle *data)
  272. {
  273. #ifdef HAVE_ICONV
  274. /* close iconv conversion descriptors */
  275. if(data->inbound_cd != (iconv_t)-1) {
  276. iconv_close(data->inbound_cd);
  277. }
  278. if(data->outbound_cd != (iconv_t)-1) {
  279. iconv_close(data->outbound_cd);
  280. }
  281. if(data->utf8_cd != (iconv_t)-1) {
  282. iconv_close(data->utf8_cd);
  283. }
  284. #else
  285. (void)data;
  286. #endif /* HAVE_ICONV */
  287. }
  288. /*
  289. * Curl_convert_form() is used from http.c, this converts any form items that
  290. need to be sent in the network encoding. Returns CURLE_OK on success.
  291. */
  292. CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form)
  293. {
  294. struct FormData *next;
  295. CURLcode rc;
  296. if(!form)
  297. return CURLE_OK;
  298. if(!data)
  299. return CURLE_BAD_FUNCTION_ARGUMENT;
  300. do {
  301. next=form->next; /* the following form line */
  302. if(form->type == FORM_DATA) {
  303. rc = Curl_convert_to_network(data, form->line, form->length);
  304. /* Curl_convert_to_network calls failf if unsuccessful */
  305. if(rc != CURLE_OK)
  306. return rc;
  307. }
  308. } while((form = next) != NULL); /* continue */
  309. return CURLE_OK;
  310. }
  311. #endif /* CURL_DOES_CONVERSIONS */