Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-text-host-encoding.c
4 : : * Date: Fri Jan 11 21:09:23 2008
5 : : *
6 : : * GNU PDF Library - Encoded Text handling utilities - Host Encodings
7 : : *
8 : : */
9 : :
10 : : /* Copyright (C) 2008-2011 Free Software Foundation, Inc. */
11 : :
12 : : /* This program is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU General Public License as published by
14 : : * the Free Software Foundation, either version 3 of the License, or
15 : : * (at your option) any later version.
16 : : *
17 : : * This program is distributed in the hope that it will be useful,
18 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : * GNU General Public License for more details.
21 : : *
22 : : * You should have received a copy of the GNU General Public License
23 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : : */
25 : :
26 : : #include <config.h>
27 : :
28 : : #include <string.h>
29 : : #ifdef PDF_HOST_WIN32
30 : : #include <windows.h>
31 : : #else
32 : : #include <iconv.h>
33 : : #include <errno.h>
34 : : #endif
35 : :
36 : : #include <pdf-types.h>
37 : : #include <pdf-text.h>
38 : : #include <pdf-text-context.h>
39 : : #include <pdf-text-encoding.h>
40 : : #include <pdf-text-host-encoding.h>
41 : :
42 : : /*
43 : : * ICONV API
44 : : * -----------
45 : : * iconv_t iconv_open (const char* tocode, const char* fromcode)
46 : : *
47 : : * size_t iconv (iconv_t cd,
48 : : * const char **inbuf, size_t *inbytesleft,
49 : : * char **outbuf, size_t *outbytesleft);
50 : : *
51 : : * int iconv_close (iconv_t cd);
52 : : */
53 : :
54 : : /*
55 : : * WINDOWS API
56 : : * -------------
57 : : * int MultiByteToWideChar(UINT CodePage,
58 : : * DWORD dwFlags,
59 : : * LPCSTR lpMultiByteStr,
60 : : * int cbMultiByte,
61 : : * LPWSTR lpWideCharStr,
62 : : * int cchWideChar);
63 : : *
64 : : * int WideCharToMultiByte(UINT CodePage,
65 : : * DWORD dwFlags,
66 : : * LPCWSTR lpWideCharStr,
67 : : * int cchWideChar,
68 : : * LPSTR lpMultiByteStr,
69 : : * int cbMultiByte,
70 : : * LPCSTR lpDefaultChar,
71 : : * LPBOOL lpUsedDefaultChar);
72 : : *
73 : : * UINT GetACP(void);
74 : : *
75 : : */
76 : :
77 : : #ifdef PDF_HOST_WIN32
78 : : static DWORD
79 : : pdf_text_get_dwflags_for_cp (UINT CodePage,
80 : : DWORD def_dwflags)
81 : : {
82 : : /* dwFlags has some restrictions */
83 : : switch(CodePage)
84 : : {
85 : : case 50220:
86 : : case 50221:
87 : : case 50222:
88 : : case 50225:
89 : : case 50227:
90 : : case 50229:
91 : : case 52936:
92 : : case 54936:
93 : : case 57002:
94 : : case 57003:
95 : : case 57004:
96 : : case 57005:
97 : : case 57006:
98 : : case 57007:
99 : : case 57008:
100 : : case 57009:
101 : : case 57010:
102 : : case 57011:
103 : : case 65000:
104 : : case 42:
105 : : return 0;
106 : : default:
107 : : return def_dwflags;
108 : : }
109 : : }
110 : :
111 : : static pdf_bool_t
112 : : pdf_text_convert_encoding_name_to_CP (const pdf_char_t *encoding_name,
113 : : UINT *pCP,
114 : : pdf_error_t **error)
115 : : {
116 : : UINT CodePage;
117 : : char *end_char;
118 : :
119 : : /* In windows, the charset name is stored as a string, in the following
120 : : * format: "CPn", where 'n' is the code page number (unsigned integer)
121 : : * obtained with GetACP() */
122 : :
123 : : /* So first of all, check windows host encoding */
124 : : if ((strlen (encoding_name) < 3) ||
125 : : (strncmp (encoding_name, "CP", 2) != 0))
126 : : {
127 : : pdf_set_error (error,
128 : : PDF_EDOMAIN_BASE_TEXT,
129 : : PDF_EBADDATA,
130 : : "host encoding received (%s) seems not valid",
131 : : encoding_name);
132 : : return PDF_FALSE;
133 : : }
134 : :
135 : : /* Get codepage as unsigned integer. `strtol' will return 0 if it was not
136 : : * able to correctly parse the string. BTW, 0 is not a valid code page. */
137 : : CodePage = (UINT) strtol (&encoding_name[2],
138 : : &end_char,
139 : : 10);
140 : : if (CodePage == 0)
141 : : {
142 : : pdf_set_error (error,
143 : : PDF_EDOMAIN_BASE_TEXT,
144 : : PDF_ETEXTENC,
145 : : "Problem converting input CP value '%s'",
146 : : encoding_name);
147 : : return PDF_FALSE;
148 : : }
149 : :
150 : : *pCP = CodePage;
151 : : return PDF_TRUE;
152 : : }
153 : :
154 : : pdf_bool_t
155 : : pdf_text_host_encoding_is_available (const pdf_char_t *encoding_name,
156 : : pdf_error_t **error)
157 : : {
158 : : UINT CodePage;
159 : :
160 : : if (!pdf_text_convert_encoding_name_to_CP (encoding_name,
161 : : &CodePage,
162 : : error))
163 : : return PDF_FALSE;
164 : :
165 : : /* Check given code page in the system */
166 : : return ((IsValidCodePage (CodePage)) ? PDF_TRUE : PDF_FALSE);
167 : : }
168 : :
169 : : static pdf_bool_t
170 : : pdf_text_utf32he_to_host_win32 (const pdf_char_t *input_data,
171 : : const pdf_size_t input_length,
172 : : const pdf_char_t *enc,
173 : : pdf_char_t **p_output_data,
174 : : pdf_size_t *p_output_length,
175 : : pdf_error_t **error)
176 : : {
177 : : pdf_char_t *temp_data;
178 : : pdf_size_t temp_size;
179 : : UINT CodePage;
180 : : DWORD dwFlags;
181 : : int output_nmbyte;
182 : : BOOL default_used = 0;
183 : :
184 : : /* Firstly, convert from UTF-32HE to UTF-16LE */
185 : : if (!pdf_text_utf32he_to_utf16le (input_data,
186 : : input_length,
187 : : &temp_data,
188 : : &temp_size,
189 : : error))
190 : : return PDF_FALSE;
191 : :
192 : : /* So check windows host encoding */
193 : : if (!pdf_text_convert_encoding_name_to_CP (enc,
194 : : &CodePage,
195 : : error))
196 : : {
197 : : pdf_dealloc (temp_data);
198 : : return PDF_FALSE;
199 : : }
200 : :
201 : : /* Get dwFlags value */
202 : : dwFlags = 0;
203 : :
204 : : /* First of all, query the length of the output string */
205 : : SetLastError (0);
206 : : output_nmbyte = WideCharToMultiByte (CodePage, /* CodePage */
207 : : dwFlags, /* dwFlags */
208 : : (LPCWSTR)temp_data, /* lpWideCharStr */
209 : : (temp_size/sizeof(WCHAR)), /* cbWideChar */
210 : : NULL, /* lpMultiByteStr */
211 : : 0, /* ccMultiByte */
212 : : NULL, /* lpDefaultChar */
213 : : &default_used); /* lpUsedDefaultChar */
214 : :
215 : : /* Check if we got an error with the call to WideCharToMultiByte */
216 : : if (output_nmbyte == 0 || default_used)
217 : : {
218 : : switch (GetLastError ())
219 : : {
220 : : case ERROR_INVALID_FLAGS:
221 : : pdf_set_error (error,
222 : : PDF_EDOMAIN_BASE_TEXT,
223 : : PDF_EBADTEXT,
224 : : "cannot convert to host encoding: invalid flags");
225 : : break;
226 : : default:
227 : : pdf_set_error (error,
228 : : PDF_EDOMAIN_BASE_TEXT,
229 : : PDF_EBADTEXT,
230 : : "cannot convert to host encoding: invalid data");
231 : : break;
232 : : }
233 : :
234 : : pdf_dealloc (temp_data);
235 : : return PDF_FALSE;
236 : : }
237 : :
238 : : /* Allocate memory for output buffer */
239 : : *p_output_length = output_nmbyte;
240 : : *p_output_data = (pdf_char_t *) pdf_alloc (*p_output_length);
241 : : if (*p_output_data == NULL)
242 : : {
243 : : pdf_set_error (error,
244 : : PDF_EDOMAIN_BASE_TEXT,
245 : : PDF_ENOMEM,
246 : : "cannot convert to host encoding: "
247 : : "couldn't allocate %lu bytes",
248 : : (unsigned long)*p_output_length);
249 : : pdf_dealloc (temp_data);
250 : : return PDF_FALSE;
251 : : }
252 : :
253 : : /* Launch the conversion to host encoding */
254 : : SetLastError (0);
255 : : default_used = 0;
256 : : if ((WideCharToMultiByte (CodePage, /* CodePage */
257 : : dwFlags, /* dwFlags */
258 : : (LPCWSTR)temp_data, /* lpWideCharStr */
259 : : (temp_size/sizeof(WCHAR)), /* cbWideChar */
260 : : *p_output_data, /* lpMultiByteStr */
261 : : *p_output_length, /* ccMultiByte */
262 : : NULL, /* lpDefaultChar */
263 : : &default_used) != output_nmbyte) || \
264 : : (default_used))
265 : : {
266 : : pdf_set_error (error,
267 : : PDF_EDOMAIN_BASE_TEXT,
268 : : PDF_ETEXTENC,
269 : : "cannot convert to host encoding: "
270 : : "wide char to multibyte conversion failed");
271 : : pdf_dealloc (*p_output_data);
272 : : pdf_dealloc (temp_data);
273 : : return PDF_FALSE;
274 : : }
275 : :
276 : : /* Check last byte... could be NUL and we don't want it */
277 : : if ((*p_output_data)[*p_output_length -1] == '\0')
278 : : {
279 : : pdf_char_t *temp;
280 : :
281 : : temp = pdf_realloc ((*p_output_data), (*p_output_length -1));
282 : : if (temp)
283 : : {
284 : : *p_output_data = temp;
285 : : *p_output_length = *p_output_length - 1;
286 : : }
287 : : }
288 : :
289 : : pdf_dealloc (temp_data);
290 : : return PDF_TRUE;
291 : : }
292 : :
293 : : static pdf_bool_t
294 : : pdf_text_host_to_utf32he_win32 (const pdf_char_t *input_data,
295 : : const pdf_size_t input_length,
296 : : const pdf_char_t *enc,
297 : : pdf_char_t **p_output_data,
298 : : pdf_size_t *p_output_length,
299 : : pdf_error_t **error)
300 : : {
301 : : UINT CodePage;
302 : : DWORD dwFlags;
303 : : int output_nwchars;
304 : : pdf_char_t *temp_data;
305 : : pdf_size_t temp_size;
306 : :
307 : : /* So first of all, check windows host encoding */
308 : : if (!pdf_text_convert_encoding_name_to_CP (enc,
309 : : &CodePage,
310 : : error))
311 : : return PDF_FALSE;
312 : :
313 : : /* Get dwFlags value */
314 : : dwFlags = pdf_text_get_dwflags_for_cp (CodePage, MB_ERR_INVALID_CHARS);
315 : :
316 : : /* For ASCII-7, check MSB... MultiByteToWideChar doesn't do it, and the
317 : : * behaviour should be equal to that of iconv() */
318 : : if (CodePage == 20127 &&
319 : : !pdf_text_is_ascii7 (input_data, input_length))
320 : : {
321 : : pdf_set_error (error,
322 : : PDF_EDOMAIN_BASE_TEXT,
323 : : PDF_ETEXTENC,
324 : : "cannot convert from host encoding: "
325 : : "not ASCII-7");
326 : : return PDF_FALSE;
327 : : }
328 : :
329 : : /* First of all, query the length of the output string */
330 : : SetLastError (0);
331 : : output_nwchars = MultiByteToWideChar (CodePage, /* CodePage */
332 : : dwFlags, /* dwFlags */
333 : : input_data, /* lpMultiByteStr */
334 : : input_length, /* cbMultiByte */
335 : : NULL, /* lpWideCharStr */
336 : : 0); /* cchWideChar */
337 : :
338 : : /* Check if we got an error with the call to MultiByteToWideChar*/
339 : : if (output_nwchars == 0)
340 : : {
341 : : switch (GetLastError ())
342 : : {
343 : : case ERROR_INVALID_FLAGS:
344 : : pdf_set_error (error,
345 : : PDF_EDOMAIN_BASE_TEXT,
346 : : PDF_EBADTEXT,
347 : : "cannot convert from host encoding: invalid flags");
348 : : break;
349 : : case ERROR_NO_UNICODE_TRANSLATION:
350 : : pdf_set_error (error,
351 : : PDF_EDOMAIN_BASE_TEXT,
352 : : PDF_EBADTEXT,
353 : : "cannot convert from host encoding:"
354 : : " no unicode translation");
355 : : break;
356 : : default:
357 : : pdf_set_error (error,
358 : : PDF_EDOMAIN_BASE_TEXT,
359 : : PDF_EBADTEXT,
360 : : "cannot convert from host encoding: invalid data");
361 : : break;
362 : : }
363 : : return PDF_FALSE;
364 : : }
365 : :
366 : : /* Allocate memory for output buffer */
367 : : temp_size = output_nwchars * sizeof (WCHAR);
368 : : temp_data = (pdf_char_t *) pdf_alloc (temp_size);
369 : : if (temp_data == NULL)
370 : : {
371 : : pdf_set_error (error,
372 : : PDF_EDOMAIN_BASE_TEXT,
373 : : PDF_ENOMEM,
374 : : "cannot convert from host encoding: "
375 : : "couldn't allocate %lu bytes",
376 : : (unsigned long)temp_size);
377 : : return PDF_FALSE;
378 : : }
379 : :
380 : : /* Launch the conversion to UTF-16LE */
381 : : SetLastError (0);
382 : : if (MultiByteToWideChar (CodePage, /* CodePage */
383 : : dwFlags, /* dwFlags */
384 : : input_data, /* lpMultiByteStr */
385 : : input_length, /* cbMultiByte */
386 : : (LPWSTR)temp_data, /* lpWideCharStr */
387 : : output_nwchars) != output_nwchars) /* cchWideChar */
388 : : {
389 : : pdf_set_error (error,
390 : : PDF_EDOMAIN_BASE_TEXT,
391 : : PDF_ETEXTENC,
392 : : "cannot convert from host encoding: "
393 : : "multibyte to wide char conversion failed");
394 : : pdf_dealloc (temp_data);
395 : : return PDF_FALSE;
396 : : }
397 : :
398 : : /* Finally, convert to UTF-32HE */
399 : : if (!pdf_text_utf16le_to_utf32he (temp_data,
400 : : temp_size,
401 : : p_output_data,
402 : : p_output_length,
403 : : error))
404 : : {
405 : : pdf_dealloc (temp_data);
406 : : return PDF_FALSE;
407 : : }
408 : : pdf_dealloc (temp_data);
409 : : return PDF_TRUE;
410 : : }
411 : :
412 : : #else
413 : :
414 : : pdf_bool_t
415 : 3 : pdf_text_host_encoding_is_available (const pdf_char_t *encoding_name,
416 : : pdf_error_t **error)
417 : : {
418 : : iconv_t check;
419 : :
420 : : /* Check conversion from Host Encoding to UTF-32HE */
421 : 3 : check = iconv_open (encoding_name,
422 : : (PDF_IS_BIG_ENDIAN ? "UTF-32BE" : "UTF-32LE"));
423 [ + + ]: 3 : if (check == (iconv_t)-1)
424 : : {
425 : : /* No need to set any error here */
426 : 1 : return PDF_FALSE;
427 : : }
428 : 2 : iconv_close (check);
429 : :
430 : : /* Check conversion from UTF-32HE to Host Encoding */
431 : 2 : check = iconv_open ((PDF_IS_BIG_ENDIAN ? "UTF-32BE" : "UTF-32LE"),
432 : : encoding_name);
433 [ - + ]: 2 : if (check == (iconv_t)-1)
434 : : {
435 : : /* No need to set any error here */
436 : 0 : return PDF_FALSE;
437 : : }
438 : 2 : iconv_close (check);
439 : :
440 : 3 : return PDF_TRUE;
441 : : }
442 : :
443 : : static pdf_bool_t
444 : 33 : pdf_text_utf32he_to_host_iconv (const pdf_char_t *input_data,
445 : : const pdf_size_t input_length,
446 : : const pdf_char_t *enc,
447 : : pdf_char_t **p_output_data,
448 : : pdf_size_t *p_output_length,
449 : : pdf_error_t **error)
450 : : {
451 : : iconv_t to_host;
452 : : size_t n_conv;
453 : : pdf_char_t *in_str;
454 : : size_t n_in;
455 : : size_t n_out;
456 : : pdf_char_t *new_data;
457 : : pdf_char_t *out_str;
458 : : pdf_size_t worst_length;
459 : : pdf_size_t new_length;
460 : :
461 : : /* Check if conversion is available. If we just specify "UTF-32" as the
462 : : * input encoding requested, iconv will expect the BOM by default, and
463 : : * we don't want it, so we specify directly the endianness required in the
464 : : * name of the encoding, depending on the host endianness */
465 : 33 : to_host = iconv_open (enc,
466 : : (PDF_IS_BIG_ENDIAN ? "UTF-32BE" : "UTF-32LE"));
467 [ + + ]: 33 : if (to_host == (iconv_t)-1)
468 : : {
469 : 3 : pdf_set_error (error,
470 : : PDF_EDOMAIN_BASE_TEXT,
471 : : PDF_ETEXTENC,
472 : : "cannot convert to host encoding: "
473 : : "conversion from UTF-32 to '%s' not available: '%s'",
474 : : enc,
475 : : strerror (errno));
476 : 3 : return PDF_FALSE;
477 : : }
478 : :
479 : : /* Prepare lengths and locations.
480 : : * The worst length is computed as having one single output byte for each
481 : : * input single byte */
482 : 30 : worst_length = input_length + 4;
483 : 30 : new_data = (pdf_char_t *) pdf_alloc (worst_length);
484 [ - + ]: 30 : if (new_data == NULL)
485 : : {
486 : 0 : pdf_set_error (error,
487 : : PDF_EDOMAIN_BASE_TEXT,
488 : : PDF_ENOMEM,
489 : : "cannot convert to host encoding: "
490 : : "couldn't allocate %lu bytes",
491 : : (unsigned long)worst_length);
492 : 0 : iconv_close (to_host);
493 : 0 : return PDF_FALSE;
494 : : }
495 : :
496 : 30 : n_out = worst_length;
497 : :
498 : : /* This cast is legit because
499 : : * iconv increments the pointer
500 : : * but does not change the
501 : : * pointed memory. */
502 : 30 : in_str = (char *)input_data;
503 : 30 : out_str = new_data;
504 : 30 : n_in = input_length;
505 : :
506 [ + + ]: 60 : while (n_in > 0)
507 : : {
508 : : /* Convert */
509 : 30 : n_conv = iconv (to_host, &in_str, &n_in, &out_str, &n_out);
510 : :
511 : : /* Check conversion output status. We check errno to see if the problem
512 : : * is that more buffer is needed in the output. If this is the case,
513 : : * we just give a second try to the worst length and reallocate memory.
514 : : * There is no problem to use errno in multi-threaded applications
515 : : * if the library is compiled with -D_REENTRANT */
516 [ - + ]: 30 : if (n_conv == (size_t)-1)
517 : : {
518 [ # # ]: 0 : if (errno == E2BIG)
519 : : {
520 : 0 : pdf_size_t n_bytes_generated = 0;
521 : :
522 : : /* Compute the number of bytes actually generated in the
523 : : * output buffer. */
524 : 0 : n_bytes_generated = (pdf_size_t) (worst_length - n_out);
525 : :
526 : : /* We need more output buffer */
527 : 0 : worst_length += (n_in);
528 : :
529 : : PDF_DEBUG_BASE ("Reallocating to '%lu'. "
530 : : "'%lu' bytes are already generated",
531 : : (unsigned long) worst_length,
532 : : (unsigned long) n_bytes_generated);
533 : :
534 : : /* Reallocate buffer with greater size */
535 : 0 : new_data = (pdf_char_t *) pdf_realloc (new_data, worst_length);
536 [ # # ]: 0 : if (new_data == NULL)
537 : : {
538 : 0 : iconv_close (to_host);
539 : 0 : pdf_set_error (error,
540 : : PDF_EDOMAIN_BASE_TEXT,
541 : : PDF_ENOMEM,
542 : : "cannot convert to host encoding: "
543 : : "couldn't rellocate '%lu' bytes",
544 : : (unsigned long)worst_length);
545 : 0 : return PDF_FALSE;
546 : : }
547 : :
548 : : /* The re-allocated new data does not have to be in the same
549 : : * memory place as the original one, so the `out_str' pointer
550 : : * must be reset */
551 : 0 : out_str = &new_data[n_bytes_generated];
552 : :
553 : : /* The number of bytes available in the buffer must also be
554 : : * reset */
555 : 0 : n_out = (worst_length - n_bytes_generated);
556 : : }
557 : : else
558 : : {
559 : 0 : iconv_close (to_host);
560 : 0 : pdf_set_error (error,
561 : : PDF_EDOMAIN_BASE_TEXT,
562 : : PDF_ETEXTENC,
563 : : "cannot convert to host encoding: "
564 : : "invalid data to convert to host encoding, '%s'",
565 : : strerror (errno));
566 : 0 : return PDF_FALSE;
567 : : }
568 : : }
569 : : }
570 : :
571 : : /* Compute new final length */
572 : 30 : new_length = worst_length - n_out;
573 : :
574 : : /* Finally, reset the buffer length to its correct size */
575 [ + - ]: 30 : if (new_length != worst_length)
576 : : {
577 : 30 : new_data = (pdf_char_t *) pdf_realloc (new_data, new_length);
578 [ - + ]: 30 : if (new_data == NULL)
579 : : {
580 : 0 : iconv_close (to_host);
581 : 0 : pdf_set_error (error,
582 : : PDF_EDOMAIN_BASE_TEXT,
583 : : PDF_ENOMEM,
584 : : "cannot convert to host encoding: "
585 : : "couldn't rellocate '%lu' bytes",
586 : : (unsigned long)new_length);
587 : 0 : return PDF_FALSE;
588 : : }
589 : : }
590 : :
591 : : /* And set the output values */
592 : 30 : *p_output_data = new_data;
593 : 30 : *p_output_length = new_length;
594 : :
595 : 30 : iconv_close (to_host);
596 : 33 : return PDF_TRUE;
597 : : }
598 : :
599 : : static pdf_bool_t
600 : 10 : pdf_text_host_to_utf32he_iconv (const pdf_char_t *input_data,
601 : : const pdf_size_t input_length,
602 : : const pdf_char_t *enc,
603 : : pdf_char_t **p_output_data,
604 : : pdf_size_t *p_output_length,
605 : : pdf_error_t **error)
606 : : {
607 : : iconv_t from_host;
608 : : size_t n_conv;
609 : : pdf_char_t *in_str;
610 : : size_t n_in;
611 : : size_t n_out;
612 : : pdf_char_t *new_data;
613 : : pdf_char_t *out_str;
614 : : pdf_size_t worst_length;
615 : : pdf_size_t new_length;
616 : :
617 : : /* Check if conversion is available. If we just specify "UTF-32" as the
618 : : * output encoding requested, iconv will insert the BOM by default, and
619 : : * we don't want it, so we specify directly the endianness required in the
620 : : * name of the encoding, depending on the host endianness */
621 : 10 : from_host = iconv_open ((PDF_IS_BIG_ENDIAN ? "UTF-32BE" : "UTF-32LE"),
622 : : enc);
623 [ + + ]: 10 : if (from_host == (iconv_t)-1)
624 : : {
625 : 2 : pdf_set_error (error,
626 : : PDF_EDOMAIN_BASE_TEXT,
627 : : PDF_ETEXTENC,
628 : : "cannot convert from host encoding: "
629 : : "conversion from '%s' to UTF-32 not available",
630 : : enc);
631 : 2 : return PDF_FALSE;
632 : : }
633 : :
634 : : /* Prepare lengths and locations.
635 : : * The worst length is computed as having 4 output bytes for each input
636 : : * single byte, taking into account that iconv adds an extra 32-bit NUL
637 : : * value (4 bytes equal to 0) at the end of the converted string. */
638 : 8 : worst_length = (input_length + 1) * 4;
639 : 8 : new_data = (pdf_char_t *) pdf_alloc (worst_length);
640 [ - + ]: 8 : if (new_data == NULL)
641 : : {
642 : 0 : pdf_set_error (error,
643 : : PDF_EDOMAIN_BASE_TEXT,
644 : : PDF_ENOMEM,
645 : : "cannot convert from host encoding: "
646 : : "couldn't allocate %lu bytes",
647 : : (unsigned long)worst_length);
648 : 0 : iconv_close (from_host);
649 : 0 : return PDF_FALSE;
650 : : }
651 : :
652 : 8 : n_out = worst_length;
653 : :
654 : : /* This cast is legit because
655 : : * iconv increments the pointer
656 : : * but does not change the
657 : : * pointed memory. */
658 : 8 : in_str = (char *)input_data;
659 : 8 : out_str = new_data;
660 : 8 : n_in = input_length;
661 : :
662 [ + + ]: 14 : while (n_in > 0)
663 : : {
664 : : /* Convert */
665 : 8 : n_conv = iconv (from_host, &in_str, &n_in, &out_str, &n_out);
666 : :
667 : : /* Check conversion output status. We check errno to see if the problem
668 : : * is that more buffer is needed in the output. If this is the case,
669 : : * we just give a second try to the worst length and reallocate memory.
670 : : * There is no problem to use errno in multi-threaded applications
671 : : * if the library is compiled with -D_REENTRANT */
672 [ + + ]: 8 : if (n_conv == (size_t)-1)
673 : : {
674 [ - + ]: 2 : if (errno == E2BIG)
675 : : {
676 : 0 : pdf_size_t n_bytes_generated = 0;
677 : :
678 : : /* Compute the number of bytes actually generated in the
679 : : * output buffer. `n_out' stores the number of bytes still
680 : : * available in the output buffer. As the number of bytes
681 : : * allocated is multiple of four, and UTF-32 always uses 4
682 : : * bytes for each character, this value should always be 0 */
683 : 0 : n_bytes_generated = (pdf_size_t) (worst_length - n_out);
684 : :
685 : : /* We need more output buffer */
686 : 0 : worst_length += (n_in * 4);
687 : : PDF_DEBUG_BASE ("Reallocating to '%lu'. "
688 : : "'%lu' bytes are already generated",
689 : : (unsigned long) worst_length,
690 : : (unsigned long) n_bytes_generated);
691 : :
692 : : /* Reallocate buffer with greater size */
693 : 0 : new_data = (pdf_char_t *) pdf_realloc (new_data, worst_length);
694 [ # # ]: 0 : if (new_data == NULL)
695 : : {
696 : 0 : pdf_set_error (error,
697 : : PDF_EDOMAIN_BASE_TEXT,
698 : : PDF_ENOMEM,
699 : : "cannot convert from host encoding: "
700 : : "couldn't allocate %lu bytes",
701 : : (unsigned long)worst_length);
702 : 0 : iconv_close (from_host);
703 : 0 : return PDF_FALSE;
704 : : }
705 : :
706 : : /* The re-allocated new data does not have to be in the same
707 : : * memory place as the original one, so the `out_str' pointer
708 : : * must be reset */
709 : 0 : out_str = &new_data[n_bytes_generated];
710 : :
711 : : /* The number of bytes available in the buffer must also be
712 : : * reset */
713 : 0 : n_out = (worst_length - n_bytes_generated);
714 : : }
715 : : else
716 : : {
717 : 2 : iconv_close (from_host);
718 : 2 : pdf_dealloc (new_data);
719 : 2 : pdf_set_error (error,
720 : : PDF_EDOMAIN_BASE_TEXT,
721 : : PDF_EBADTEXT,
722 : : "cannot convert to host encoding: "
723 : : "invalid data to convert from host encoding, '%s'",
724 : : strerror (errno));
725 : 2 : return PDF_FALSE;
726 : : }
727 : : }
728 : : }
729 : :
730 : : /* Compute new final length */
731 : 6 : new_length = worst_length - n_out;
732 : :
733 : : /* Remove from the length the bytes related to the 4-byte NUL UTF-32 char */
734 [ + - ][ + - ]: 6 : if ((new_data[new_length-1] == '\0') &&
[ + - ][ - + ]
735 : 6 : (new_data[new_length-2] == '\0') &&
736 : 6 : (new_data[new_length-3] == '\0') &&
737 : 6 : (new_data[new_length-4] == '\0'))
738 : : {
739 : 0 : new_length -= 4;
740 : : }
741 : :
742 : : /* Finally, reset the buffer length to its correct size */
743 [ + - ]: 6 : if (new_length != worst_length)
744 : : {
745 : 6 : new_data = (pdf_char_t *) pdf_realloc (new_data, new_length);
746 [ - + ]: 6 : if (new_data == NULL)
747 : : {
748 : 0 : pdf_set_error (error,
749 : : PDF_EDOMAIN_BASE_TEXT,
750 : : PDF_ENOMEM,
751 : : "cannot convert from host encoding: "
752 : : "couldn't rellocate '%lu' bytes",
753 : : (unsigned long)new_length);
754 : 0 : return PDF_FALSE;
755 : : }
756 : : }
757 : :
758 : : /* And set the output values within pdf_text_t */
759 : 6 : *p_output_data = new_data;
760 : 6 : *p_output_length = new_length;
761 : :
762 : 6 : iconv_close (from_host);
763 : 10 : return PDF_TRUE;
764 : : }
765 : :
766 : : #endif /* PDF_HOST_WIN32 */
767 : :
768 : : pdf_bool_t
769 : 33 : pdf_text_utf32he_to_host (const pdf_char_t *input_data,
770 : : const pdf_size_t input_length,
771 : : const pdf_char_t *enc,
772 : : pdf_char_t **p_output_data,
773 : : pdf_size_t *p_output_length,
774 : : pdf_error_t **error)
775 : : {
776 : : #ifdef PDF_HOST_WIN32
777 : : return pdf_text_utf32he_to_host_win32 (input_data,
778 : : input_length,
779 : : enc,
780 : : p_output_data,
781 : : p_output_length,
782 : : error);
783 : : #else
784 : 33 : return pdf_text_utf32he_to_host_iconv (input_data,
785 : : input_length,
786 : : enc,
787 : : p_output_data,
788 : : p_output_length,
789 : : error);
790 : : #endif /* PDF_HOST_WIN32 */
791 : : }
792 : :
793 : : pdf_bool_t
794 : 10 : pdf_text_host_to_utf32he (const pdf_char_t *input_data,
795 : : const pdf_size_t input_length,
796 : : const pdf_char_t *enc,
797 : : pdf_char_t **p_output_data,
798 : : pdf_size_t *p_output_length,
799 : : pdf_error_t **error)
800 : : {
801 : : #ifdef PDF_HOST_WIN32
802 : : return pdf_text_host_to_utf32he_win32 (input_data,
803 : : input_length,
804 : : enc,
805 : : p_output_data,
806 : : p_output_length,
807 : : error);
808 : : #else
809 : 10 : return pdf_text_host_to_utf32he_iconv (input_data,
810 : : input_length,
811 : : enc,
812 : : p_output_data,
813 : : p_output_length,
814 : : error);
815 : : #endif
816 : : }
817 : :
818 : : /* End of pdf-text-host-encoding.c */
|