Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-text-encoding.c
4 : : * Date: Fri Jan 11 21:09:56 2008
5 : : *
6 : : * GNU PDF Library - Encoded Text handling utilities - Encoding
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 : : #include <stdio.h>
30 : :
31 : : #include <pdf-text-encoding.h>
32 : : #include <pdf-text-context.h>
33 : :
34 : : #define PDF_TEXT_CHANGE_ENDIANNESS_16BIT(number) \
35 : : ((0x00FF & number) << 8) | ((0xFF00 & number) >> 8)
36 : :
37 : : #define PDF_TEXT_CHANGE_ENDIANNESS_32BIT(number) \
38 : : (((0x000000FF & number) << 24) | \
39 : : ((0x0000FF00 & number) << 8 ) | \
40 : : ((0x00FF0000 & number) >> 8 ) | \
41 : : ((0xFF000000 & number) >> 24))
42 : :
43 : : /* Mapping between PDF Doc Encoding and UNICODE UTF32 (Host Endian!)
44 : : * Obtained from PDF Reference v1.7, appendix D.2 */
45 : : #define PDFDOCENC_MAX 256
46 : : static const pdf_u32_t pdfdocenc_map [PDFDOCENC_MAX] = { /* INDEXES */
47 : : 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 00, 07 */
48 : : 0x0000, 0x0009, 0x000A, 0x0000, 0x0000, 0x000D, 0x0000, 0x0000, /* 08, 0F */
49 : : 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10, 17 */
50 : : 0x02D8, 0x02C7, 0x02C6, 0x02D9, 0x02DD, 0x02DB, 0x02DA, 0x02DC, /* 18, 1F */
51 : : 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, /* 20, 27 */
52 : : 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, /* 28, 2F */
53 : : 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, /* 30, 37 */
54 : : 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, /* 38, 3F */
55 : : 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, /* 40, 47 */
56 : : 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, /* 48, 4F */
57 : : 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, /* 50, 57 */
58 : : 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, /* 58, 5F */
59 : : 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, /* 60, 67 */
60 : : 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, /* 68, 6F */
61 : : 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, /* 70, 77 */
62 : : 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x0000, /* 78, 7F */
63 : : 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, /* 80, 87 */
64 : : 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, /* 88, 8F */
65 : : 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x0141, 0x0152, 0x0160, /* 90, 97 */
66 : : 0x0178, 0x017D, 0x0131, 0x0142, 0x0153, 0x0161, 0x017E, 0x0000, /* 98, 9F */
67 : : 0x20AC, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, /* A0, A7 */
68 : : 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x0000, 0x00AE, 0x00AF, /* A8, AF */
69 : : 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, /* B0, B7 */
70 : : 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, /* B8, BF */
71 : : 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, /* C0, C7 */
72 : : 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, /* C8, CF */
73 : : 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, /* D0, D7 */
74 : : 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, /* D8, DF */
75 : : 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, /* E0, E7 */
76 : : 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, /* E8, EF */
77 : : 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, /* F0, F7 */
78 : : 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF /* F8, FF */
79 : : };
80 : :
81 : : /* Definition of the interval type */
82 : : struct pdfdocenc_map_interval_s {
83 : : pdf_u8_t interval_start;
84 : : pdf_u8_t interval_stop;
85 : : };
86 : : typedef struct pdfdocenc_map_interval_s pdfdocenc_map_interval_t;
87 : :
88 : : /* Direct intervals */
89 : : #define PDFDOCENC_MDI 10
90 : : static const pdfdocenc_map_interval_t pdfdocenc_map_direct[PDFDOCENC_MDI] = {
91 : : { 0x09, 0x0A },
92 : : { 0x0D, 0x0D },
93 : : { 0x20, 0x7E },
94 : : { 0xA1, 0xAC },
95 : : { 0xAE, 0xFF }
96 : : };
97 : :
98 : : /* Indirect intervals */
99 : : #define PDFDOCENC_MII 10
100 : : static const pdfdocenc_map_interval_t pdfdocenc_map_indirect[PDFDOCENC_MII] = {
101 : : { 0x18, 0x1F },
102 : : { 0x80, 0x9E },
103 : : { 0xA0, 0xA0 }
104 : : };
105 : :
106 : : /* Undefined intervals, probably not really needed */
107 : : /* #define PDFDOCENC_MUI 10 */
108 : : /* static const pdfdocenc_map_interval_t pdfdocenc_map_undefined[PDFDOCENC_MUI] = { */
109 : : /* { 0x00, 0x08 }, */
110 : : /* { 0x0B, 0x0C }, */
111 : : /* { 0x0E, 0x17 }, */
112 : : /* { 0x7F, 0x7F }, */
113 : : /* { 0x9F, 0x9F }, */
114 : : /* { 0xAD, 0xAD } */
115 : : /* }; */
116 : :
117 : : /* Mapping of the first char in a UTF-8 character representation, which
118 : : * determines the number of bytes that will be needed to represent the
119 : : * character:
120 : : * 0xxx xxxx -> 1 byte [00,7F]
121 : : * 110x xxxx -> 2 bytes [C0,DF]
122 : : * 1110 xxxx -> 3 bytes [E0,EF]
123 : : * 1111 0xxx -> 4 bytes [F0,F7]
124 : : * Longer byte sequences are not allowed to represent Unicode points.
125 : : */
126 : : static const pdf_uchar_t n_bytes_in_utf8_char[256] = {
127 : : 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 00, 1F */
128 : : 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 20, 3F */
129 : : 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 40, 5F */
130 : : 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 60, 7F */
131 : : 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80, 9F */
132 : : 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0, BF */
133 : : 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* C0, DF */
134 : : 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0 /* E0, FF */
135 : : };
136 : :
137 : : /* UNICODE BOM bytes encoded in the different built-in UNICODE encodings */
138 : : static const pdf_text_bom_t unicode_bom[PDF_TEXT_MAX_UNICODE_ENC] = {
139 : : { {239,187,191, 0}, 3 }, /* PDF_TEXT_UTF8 */
140 : : { {254,255, 0, 0}, 2 }, /* PDF_TEXT_UTF16_BE */
141 : : { {255,254, 0, 0}, 2 }, /* PDF_TEXT_UTF16_LE */
142 : : { { 0, 0, 0, 0}, 0 }, /* N/A (UTF-16 HE) */
143 : : { { 0, 0,254,255}, 4 }, /* PDF_TEXT_UTF32_BE */
144 : : { {255,254, 0, 0}, 4 }, /* PDF_TEXT_UTF32_LE */
145 : : { { 0, 0, 0, 0}, 0 } /* N/A (UTF-32HE) */
146 : : };
147 : :
148 : : /* Name of the different Unicode encodings */
149 : : static const pdf_char_t *unicode_encoding_name[PDF_TEXT_MAX_UNICODE_ENC] = {
150 : : "UTF-8", /* PDF_TEXT_UTF8 */
151 : : "UTF-16BE", /* PDF_TEXT_UTF16_BE */
152 : : "UTF-16LE", /* PDF_TEXT_UTF16_LE */
153 : : "UTF-16HE", /* PDF_TEXT_UTF16_HE */
154 : : "UTF-32BE", /* PDF_TEXT_UTF32_BE */
155 : : "UTF-32LE", /* PDF_TEXT_UTF32_LE */
156 : : "UTF-32HE" /* PDF_TEXT_UTF32_HE */
157 : : };
158 : :
159 : : /******************** PDF Doc Encoding to UTF-32 conversion *******************/
160 : :
161 : : static pdf_text_utf32_char_t
162 : : pdf_text_pdfdocenc_point_to_utf32he_point (const pdf_char_t pdfdocenc_val)
163 : : {
164 : : pdf_text_utf32_char_t utf32val;
165 : :
166 : 262 : utf32val.i = pdfdocenc_map[(pdf_uchar_t)pdfdocenc_val];
167 : 262 : return utf32val;
168 : : }
169 : :
170 : : /* Static function to convert from PDF Doc Encoding to UTF-32HE, lossless */
171 : : pdf_bool_t
172 : 34 : pdf_text_pdfdocenc_to_utf32he (const pdf_char_t *input_data,
173 : : const pdf_size_t input_length,
174 : : pdf_char_t **p_output_data,
175 : : pdf_size_t *p_output_length,
176 : : pdf_error_t **error)
177 : : {
178 : : /* Note: PDF Doc Encoding has always 8 bits per character.
179 : : * This means that, if length of origin string is N bytes, the number of
180 : : * required bytes for the UTF32 representation of the string is 4N.
181 : : * (Each PDFDocEncoding byte is expanded to 4 bytes in UTF32. */
182 : :
183 : : pdf_size_t i; /* index for the origin string data */
184 : : pdf_size_t j; /* index for the destination string data */
185 : : pdf_char_t *data;
186 : : pdf_size_t new_length;
187 : :
188 : : /* Get new string length... */
189 : 34 : new_length = 4 * input_length;
190 : :
191 : : /* Create destination string with correct size (but empty!) */
192 : 34 : data = (pdf_char_t *) pdf_alloc (new_length);
193 [ - + ]: 34 : if (data == NULL)
194 : : {
195 : 0 : pdf_set_error (error,
196 : : PDF_EDOMAIN_BASE_TEXT,
197 : : PDF_ENOMEM,
198 : : "cannot convert PDF doc encoding to UTF-32HE: "
199 : : "couldn't allocate %lu bytes",
200 : : (unsigned long)new_length);
201 : 0 : return PDF_FALSE;
202 : : }
203 : :
204 [ + + ]: 284 : for (i = 0, j = 0; i < input_length; i++, j += 4)
205 : : {
206 : : pdf_text_utf32_char_t utf32val;
207 : :
208 : : /* Get value... */
209 : 524 : utf32val = pdf_text_pdfdocenc_point_to_utf32he_point (input_data[i]);
210 [ + + ]: 262 : if (utf32val.i == 0)
211 : : {
212 : 12 : pdf_dealloc (data);
213 : 12 : pdf_set_error (error,
214 : : PDF_EDOMAIN_BASE_TEXT,
215 : : PDF_EBADDATA,
216 : : "cannot convert PDF doc encoding to UTF-32HE: "
217 : : "input byte '%d' is undefined in PDF Doc encoding",
218 : 12 : input_data[i]);
219 : 12 : return PDF_FALSE;
220 : : }
221 : : /* Copy converted value to output */
222 : 250 : memcpy (&(data[j]), &(utf32val), 4);
223 : : }
224 : :
225 : : /* Everything went ok, set output data */
226 : 22 : *p_output_data = data;
227 : 22 : *p_output_length = new_length;
228 : :
229 : 34 : return PDF_TRUE;
230 : : }
231 : :
232 : : /******************** UTF-32 to PDF Doc Encoding conversion *******************/
233 : :
234 : : static pdf_char_t
235 : : pdf_text_utf32he_point_to_pdfdocenc_point (const pdf_text_utf32_char_t utf32val)
236 : : {
237 : : pdf_u8_t i;
238 : :
239 : : /* If the given UTF-32 point is encoded in a single byte, then direct
240 : : * conversion is possible */
241 [ + + ]: 180 : if (utf32val.i <= 0xFF)
242 : : {
243 : : /* Check if direct conversion is possible */
244 [ + - ]: 534 : for (i = 0; i < PDFDOCENC_MDI; ++i)
245 : : {
246 [ + + ][ + - ]: 534 : if ((utf32val.i <= pdfdocenc_map_direct[i].interval_stop) &&
247 : 178 : (utf32val.i >= pdfdocenc_map_direct[i].interval_start))
248 : : {
249 : : /* If the unicode char is among this intervals, direct conversion
250 : : * is possible (single byte!) */
251 : 178 : return (pdf_char_t)utf32val.i;
252 : : }
253 : : }
254 : : }
255 : : else
256 : : {
257 : : /* Check if indirect conversion is possible */
258 [ + + ]: 22 : for (i = 0; i < PDFDOCENC_MII; ++i)
259 : : {
260 : : /* Simple search in the interval */
261 : : pdf_size_t search_index;
262 : :
263 : 20 : search_index = pdfdocenc_map_indirect[i].interval_start;
264 [ + + ]: 114 : while ((search_index <= pdfdocenc_map_indirect[i].interval_stop) )
265 : : {
266 [ - + ]: 94 : if (pdfdocenc_map[search_index] == utf32val.i)
267 : : {
268 : : /* Directly apply search index as character */
269 : 0 : return (pdf_char_t)search_index;
270 : : }
271 : 94 : search_index++;
272 : : }
273 : : }
274 : : }
275 : :
276 : : /* If neither Direct conversion nor Indirect conversion are available,
277 : : * the given character is UNDEFINED. Set default character when there is no
278 : : * direct mapping to PDF Doc Encoding. This means that every conversion
279 : : * to PDF Doc Encoding will NEVER fail if there is no mapping of a code point
280 : : * in PDF Doc Encoding */
281 : 2 : return (pdf_char_t)'?';
282 : : }
283 : :
284 : : /* Static function to convert from UTF-32HE to PDF Doc Encoding, with loss of
285 : : information */
286 : : pdf_bool_t
287 : 20 : pdf_text_utf32he_to_pdfdocenc (const pdf_char_t *input_data,
288 : : const pdf_size_t input_length,
289 : : pdf_char_t **p_output_data,
290 : : pdf_size_t *p_output_length,
291 : : pdf_error_t **error)
292 : : {
293 : : /* Note: UTF-32 has always 32 bits per character.
294 : : This means that, if length of origin string is 4N bytes, the number of
295 : : required bytes for the PDFDocEncoding representation of the string is N.
296 : : (Each UNICODE 4-byte character is represented as 1-byte character in
297 : : PDFDocEncoding). This means that LOSS of information could happen */
298 : :
299 : : int i; /* index for the origin string data */
300 : : int j; /* index for the destination string data */
301 : :
302 : : /* Check if the length of the origin string is multiple of 4 bytes */
303 [ - + ]: 20 : if (input_length % 4 != 0)
304 : : {
305 : 0 : pdf_set_error (error,
306 : : PDF_EDOMAIN_BASE_TEXT,
307 : : PDF_EBADDATA,
308 : : "cannot convert from UTF-32HE to PDF Doc encoding: "
309 : : "invalid input data length: %lu",
310 : : (unsigned long)input_length);
311 : 0 : return PDF_FALSE;
312 : : }
313 : :
314 : : /* Get new string length... */
315 : 20 : *p_output_length = input_length / 4;
316 : :
317 : : /* Create destination string with correct size (but empty!) */
318 : 20 : *p_output_data = (pdf_char_t *) pdf_alloc (*p_output_length);
319 [ - + ]: 20 : if (*p_output_data == NULL)
320 : : {
321 : 0 : pdf_set_error (error,
322 : : PDF_EDOMAIN_BASE_TEXT,
323 : : PDF_ENOMEM,
324 : : "cannot convert from UTF-32HE to PDF Doc encoding: "
325 : : "couldn't allocate %lu bytes",
326 : : (unsigned long)*p_output_length);
327 : 0 : return PDF_FALSE;
328 : : }
329 : :
330 [ + + ]: 200 : for (i = 0, j = 0; i < input_length; i += 4, j++)
331 : : {
332 : : pdf_text_utf32_char_t utf32val; /* UNICODE char */
333 : :
334 : : /* Get UTF-32 char to convert */
335 : 180 : memcpy (&utf32val, &input_data[i], 4);
336 : : /* Convert character to PDF Doc Encoding */
337 : 360 : (*p_output_data)[j] = pdf_text_utf32he_point_to_pdfdocenc_point (utf32val);
338 : : }
339 : :
340 : 20 : return PDF_TRUE;
341 : : }
342 : :
343 : : /*********************** UTF-32 to UTF-32 conversions *************************/
344 : :
345 : : /* Function to convert from UTF-32HE to UTF-32HE, lossless */
346 : : pdf_bool_t
347 : 759 : pdf_text_utf32he_to_utf32he (const pdf_char_t *input_data,
348 : : const pdf_size_t input_length,
349 : : const pdf_bool_t swap,
350 : : const pdf_bool_t check_input_he,
351 : : const pdf_bool_t check_output_he,
352 : : pdf_char_t **p_output_data,
353 : : pdf_size_t *p_output_length,
354 : : pdf_error_t **error)
355 : : {
356 : : pdf_size_t walker;
357 : 759 : pdf_size_t bom_bytes = 0;
358 : 759 : pdf_char_t *new_data = NULL;
359 : 759 : pdf_size_t new_size = 0;
360 : :
361 [ + + ]: 759 : if (input_length % 4 != 0)
362 : : {
363 : 60 : pdf_set_error (error,
364 : : PDF_EDOMAIN_BASE_TEXT,
365 : : PDF_EBADDATA,
366 : : "cannot convert from UTF-32HE to UTF-32HE: "
367 : : "invalid input data length: %lu",
368 : : (unsigned long)input_length);
369 : 60 : return PDF_FALSE;
370 : : }
371 : :
372 : : /* Check if BOM is present... and skip it if so */
373 [ + + ]: 699 : if (pdf_text_check_unicode_bom (input_data,
374 : : input_length,
375 : : PDF_TEXT_UTF32_HE,
376 : : swap))
377 : : {
378 : : /* Skip BOM */
379 : 30 : bom_bytes = 4;
380 : : }
381 : :
382 : : /* Allocate memory */
383 : 699 : new_size = input_length - bom_bytes;
384 : : /* Create destination string with correct size (but empty!) */
385 : 699 : new_data = (pdf_char_t *) pdf_alloc (new_size);
386 [ - + ]: 699 : if (new_data == NULL)
387 : : {
388 : 0 : pdf_set_error (error,
389 : : PDF_EDOMAIN_BASE_TEXT,
390 : : PDF_ENOMEM,
391 : : "cannot convert from UTF-32HE to UTF-32HE: "
392 : : "couldn't allocate %lu bytes",
393 : : (unsigned long)new_size);
394 : 0 : return PDF_FALSE;
395 : : }
396 : :
397 : : /* Change endianness of each 32bit value... */
398 [ + + ]: 8793 : for (walker = bom_bytes; walker < input_length; walker += 4)
399 : : {
400 : : pdf_text_utf32_char_t utf32val;
401 : :
402 : 8094 : memcpy (&utf32val, &input_data[walker], 4);
403 : :
404 : : /* Check code point validity (if the input is Host Endian) */
405 : : /* Code point must not be a surrogate code unit, and must be in the
406 : : * U+00000000 - U+0010FFFF range */
407 [ + + ][ - + ]: 8094 : if ((check_input_he) &&
408 : 3367 : ((utf32val.i > 0x10FFFF) ||
409 : : ((utf32val.i >= 0xD800) &&
410 : : (utf32val.i <= 0xDFFF))))
411 : : {
412 : : /* Invalid UTF-32 code point received */
413 : 0 : pdf_set_error (error,
414 : : PDF_EDOMAIN_BASE_TEXT,
415 : : PDF_EBADTEXT,
416 : : "cannot convert from UTF-32HE to UTF-32HE: "
417 : : "invalid input code point: "
418 : : "%.2X:%.2X:%.2X:%.2X",
419 : 0 : utf32val.c[0],
420 : 0 : utf32val.c[1],
421 : 0 : utf32val.c[2],
422 : 0 : utf32val.c[3]);
423 : 0 : return PDF_FALSE;
424 : : }
425 : :
426 : : /* Swap bytes */
427 [ + + ]: 8094 : if (swap)
428 : : {
429 : 4768 : utf32val.i = PDF_TEXT_CHANGE_ENDIANNESS_32BIT (utf32val.i);
430 : : }
431 : :
432 : : /* Check code point validity (if the output is Host Endian) */
433 : : /* Code point must not be a surrogate code unit, and must be in the
434 : : * U+00000000 - U+0010FFFF range */
435 [ + + ][ - + ]: 8094 : if ((check_output_he) &&
436 : 4727 : ((utf32val.i > 0x10FFFF) ||
437 : : ((utf32val.i >= 0xD800) &&
438 : : (utf32val.i <= 0xDFFF))))
439 : : {
440 : : /* Invalid output UTF-32 code point */
441 : 0 : pdf_set_error (error,
442 : : PDF_EDOMAIN_BASE_TEXT,
443 : : PDF_EBADTEXT,
444 : : "cannot convert from UTF-32HE to UTF-32HE: "
445 : : "invalid output code point: "
446 : : "%.2X:%.2X:%.2X:%.2X",
447 : 0 : utf32val.c[0],
448 : 0 : utf32val.c[1],
449 : 0 : utf32val.c[2],
450 : 0 : utf32val.c[3]);
451 : 0 : return PDF_FALSE;
452 : : }
453 : :
454 : : /* Copy value */
455 : 8094 : memcpy (&(new_data[walker-bom_bytes]), &utf32val, 4);
456 : : }
457 : :
458 : : /* Really set output data */
459 : 699 : *p_output_data = new_data;
460 : 699 : *p_output_length = new_size;
461 : :
462 : 759 : return PDF_TRUE;
463 : : }
464 : :
465 : : /*********************** UTF-16 to UTF-32 conversions *************************/
466 : :
467 : : /* Static function to convert a given UTF-16HE character (with one or two words)
468 : : * to UTF-32HE. The number of bytes (2 or 4) used from the input UTF-16BE point
469 : : * is returned (or 0 if the UTF-16HE point is not valid */
470 : : static pdf_size_t
471 : : pdf_text_utf16he_point_to_utf32he_point (pdf_text_utf16_char_t utf16val[2],
472 : : pdf_text_utf32_char_t *p_utf32val,
473 : : pdf_error_t **error)
474 : : {
475 : : pdf_size_t n_bytes;
476 : :
477 : : /* Ok, so how can we know if the UTF16 character is encoded using 2 or
478 : : * 4 bytes? A surrogate pair consists on two 16-bit values of the
479 : : * UTF16 encoding. Each word (16bit-value) within the surrogate pair
480 : : * doesn't represent a valid character, as it is enclosed in the
481 : : * following interval: U+D800 - U+DFFF. This means that if the first
482 : : * word analysed is outside this interval, it will be treated
483 : : * separately. If the first word is within this interval, it is
484 : : * expected to have the second word within the interval as well. If
485 : : * this doesn't happen it will be treated as a badly formatted UTF16
486 : : * string. In fact, there are two different intervals within the surrogate
487 : : * points themselves: the High surrogate point will be in the U+D800 -
488 : : * U+DBFF interval, and the Low surrogate point will be in the U+DC00 -
489 : : * U+DFFF interval. */
490 : :
491 [ + + ]: 1339 : if (((utf16val[0].i) >= 0xD800) &&
492 : : ((utf16val[0].i) <= 0xDFFF))
493 : : {
494 : : /* To have a valid surrogate pair, the first UTF-16 value must be the High
495 : : * surrogate code unit, and the second UTF-16 value must be the Low
496 : : * surrogate code unit. */
497 [ + - ][ + - ]: 40 : if (((utf16val[0].i) <= 0xDFFF) &&
[ + - ]
498 : 40 : ((utf16val[1].i) >= 0xDC00) &&
499 : 40 : ((utf16val[1].i) <= 0xDFFF))
500 : : {
501 : : /* Yes, second word is within the validity interval, it seems a
502 : : * correct 32-bit representation of a character in UTF16BE */
503 : 40 : n_bytes = 4;
504 : 40 : (*p_utf32val).i = (0x10000 +
505 : 40 : (((utf16val[0].i) - 0xD800) << 10) +
506 : 40 : ((utf16val[1].i) - 0xDC00));
507 : : }
508 : : /* else Oops, invalid UTF-16HE surrogate pair! Input data is not well
509 : : * formed... */
510 : : else
511 : : {
512 : 0 : pdf_set_error (error,
513 : : PDF_EDOMAIN_BASE_TEXT,
514 : : PDF_EBADTEXT,
515 : : "cannot convert from UTF-16HE to UTF-32HE: "
516 : : "invalid input code point: "
517 : : "%.2X:%.2X:%.2X:%.2X",
518 : 0 : utf16val[0].c[0], utf16val[0].c[1],
519 : 0 : utf16val[1].c[0], utf16val[1].c[1]);
520 : 0 : n_bytes = 0;
521 : : }
522 : : }
523 : : else
524 : : {
525 : : /* No multiword representation, just 16bits for this character
526 : : * So conversion is direct... */
527 : 1299 : n_bytes = 2;
528 : 1299 : (*p_utf32val).i = (utf16val[0]).i;
529 : : }
530 : :
531 : 1339 : return n_bytes;
532 : : }
533 : :
534 : : /* Function to convert from UTF-16HE to UTF-32HE, lossless */
535 : : pdf_bool_t
536 : 163 : pdf_text_utf16he_to_utf32he (const pdf_char_t *input_data,
537 : : const pdf_size_t input_length,
538 : : const pdf_bool_t swap,
539 : : pdf_char_t **p_output_data,
540 : : pdf_size_t *p_output_length,
541 : : pdf_char_t **p_remaining_data,
542 : : pdf_size_t *p_remaining_length,
543 : : pdf_error_t **error)
544 : : {
545 : : /* Note: UTF-16 has either 16 or 32 bits per character.
546 : : * This means that, if length of origin string is N bytes, the number of
547 : : * required bytes for the UTF-32 representation of the string is 2N in
548 : : * the worst case (in the case of having all the UTF-16 characters encoded
549 : : * with 16bits).
550 : : * (Each UTF-16 is expanded to 4 bytes in UTF-32. */
551 : :
552 : : pdf_char_t *data;
553 : : pdf_size_t new_string_length;
554 : : pdf_size_t new_string_length_worst;
555 : : pdf_size_t delta_in_utf16be;
556 : : int i; /* index for the origin string data */
557 : : int j; /* index for the destination string data */
558 : : pdf_text_utf16_char_t utf16val[2];
559 : : pdf_text_utf32_char_t utf32val;
560 : 163 : short stop_conversion = PDF_FALSE;
561 : 163 : short check_lang_code = PDF_FALSE;
562 : 163 : int bom_bytes = 0;
563 : :
564 : : /* Check if length is multiple of 2 (data must come in pairs of bytes!) */
565 [ + - ][ + + ]: 163 : if ((input_length < 2) ||
566 : 163 : (input_length % 2) != 0)
567 : : {
568 : 60 : pdf_set_error (error,
569 : : PDF_EDOMAIN_BASE_TEXT,
570 : : PDF_EBADDATA,
571 : : "cannot convert from UTF-16HE to UTF-32HE: "
572 : : "invalid input data length: %lu",
573 : : (unsigned long)input_length);
574 : 60 : return PDF_FALSE;
575 : : }
576 : :
577 : : /* Check if BOM is present... and skip it if so */
578 [ + + ]: 103 : if (pdf_text_check_unicode_bom (input_data,
579 : : input_length,
580 : : PDF_TEXT_UTF16_HE,
581 : : swap))
582 : : {
583 : : /* Skip BOM */
584 : 35 : bom_bytes = 2;
585 : : }
586 : :
587 : : /* Get new string worst length... (don't consider BOM bytes) */
588 : 103 : new_string_length_worst = 2 * (input_length - bom_bytes);
589 : : /* Create destination string with worst size (but empty!) */
590 : 103 : data = (pdf_char_t *) pdf_alloc (new_string_length_worst);
591 [ - + ]: 103 : if (data == NULL)
592 : : {
593 : 0 : pdf_set_error (error,
594 : : PDF_EDOMAIN_BASE_TEXT,
595 : : PDF_ENOMEM,
596 : : "cannot convert from UTF-16HE to UTF-32HE: "
597 : : "couldn't allocate %lu bytes",
598 : : (unsigned long)new_string_length_worst);
599 : 0 : return PDF_FALSE;
600 : : }
601 : :
602 : : /* Initiate final string length */
603 : 103 : new_string_length = 0;
604 : :
605 : : /* Initiate indexes */
606 : 103 : i = bom_bytes; /* Skipping BOM if present... */
607 : 103 : j = 0;
608 : :
609 : : /* Check if specific country/language could be found */
610 [ + + ]: 103 : if ((p_remaining_length != NULL) &&
611 : 103 : (p_remaining_data != NULL))
612 : : {
613 : 33 : check_lang_code = PDF_TRUE;
614 : : }
615 : :
616 : : /* This while loop will be done until the end of the input data OR until
617 : : * the moment a new country/language code identifier is found. But, this
618 : : * extra stop condition will only be available if valid `p_remaining_data'
619 : : * and `p_remaining_length' pointers are given as input. */
620 [ + + ]: 1454 : while ((i < input_length) &&
621 : 1454 : (!stop_conversion))
622 : : {
623 [ + + ][ + + ]: 1351 : if ((check_lang_code) &&
[ + - ]
624 : 429 : (input_data[i+1] == PDF_TEXT_LCI_1) &&
625 : 12 : (input_data[i] == PDF_TEXT_LCI_0))
626 : : {
627 : : /* Stop conversion... due to new lang/code initializer */
628 : 12 : stop_conversion = PDF_TRUE;
629 : : /* Set the output remaining data... */
630 : 12 : *p_remaining_length = input_length - i;
631 : 12 : *p_remaining_data = (pdf_char_t *)&input_data[i];
632 : : }
633 : : else
634 : : {
635 : : /* Store the UTF-16(BE/LE) data in the intermediate variable */
636 : 1339 : utf16val[0].c[0] = input_data[i];
637 : 1339 : utf16val[0].c[1] = input_data[i+1];
638 [ + + ]: 1339 : if ((i+3) < input_length)
639 : : {
640 : 1286 : utf16val[1].c[0] = input_data[i+2];
641 : 1286 : utf16val[1].c[1] = input_data[i+3];
642 : : }
643 : : /* else, last point should be only 1-word length */
644 : : else
645 : : {
646 : 53 : utf16val[1].c[0] = 0x00;
647 : 53 : utf16val[1].c[1] = 0x00;
648 : : }
649 : :
650 [ + + ]: 1339 : if (swap)
651 : : {
652 : : /* Input data must be swapped in order to convert it to
653 : : * host endian */
654 : 835 : utf16val[0].i = PDF_TEXT_CHANGE_ENDIANNESS_16BIT (utf16val[0].i);
655 : 835 : utf16val[1].i = PDF_TEXT_CHANGE_ENDIANNESS_16BIT (utf16val[1].i);
656 : : }
657 : :
658 : : /* Change UTF-16HE point to UTF-32HE point */
659 : 1339 : delta_in_utf16be = pdf_text_utf16he_point_to_utf32he_point (utf16val,
660 : : &utf32val,
661 : : error);
662 [ - + ]: 1339 : if (delta_in_utf16be == 0)
663 : : {
664 : : /* Oops, invalid UTF-16HE point found! */
665 : 0 : pdf_dealloc (data);
666 : 0 : return PDF_FALSE;
667 : : }
668 : :
669 : : /* Finally, store the UTF-32 representation of the char in the output
670 : : * string... */
671 : 1339 : data[j] = utf32val.c[0];
672 : 1339 : data[j+1] = utf32val.c[1];
673 : 1339 : data[j+2] = utf32val.c[2];
674 : 1339 : data[j+3] = utf32val.c[3];
675 : :
676 : : /* Update final string length after having added this character */
677 : 1339 : new_string_length += 4;
678 : :
679 : : /* Update indexes */
680 : 1339 : i += delta_in_utf16be;
681 : 1339 : j += 4;
682 : : }
683 : : }
684 : :
685 : : /* Everything went ok, set output data */
686 : 103 : *p_output_data = data;
687 : : /* Set output length... */
688 : 103 : *p_output_length = new_string_length;
689 : :
690 : : /* Check if the stop flag was set due to finding lang/country code
691 : : * initializer. If not found, set zero remaining length and NULL
692 : : * remaining str */
693 [ + + ][ + - ]: 103 : if ((!stop_conversion) &&
694 : 103 : (p_remaining_length != NULL) &&
695 : : (p_remaining_data != NULL))
696 : : {
697 : 21 : *p_remaining_length = 0;
698 : 21 : *p_remaining_data = NULL;
699 : : }
700 : :
701 : : /* Now, if the real output string length is not equal to the worst string
702 : : * length, we will reallocate memory for the correct size. This will only
703 : : * happen when at least one character is not encoded with 32bits in UTF-16. */
704 [ + + ]: 103 : if (new_string_length != new_string_length_worst)
705 : : {
706 : : /* Recreate object with correct size... */
707 : 50 : *p_output_data = (pdf_char_t *) pdf_realloc (*p_output_data,
708 : : new_string_length);
709 [ - + ]: 50 : if (*p_output_data == NULL)
710 : : {
711 : 0 : pdf_set_error (error,
712 : : PDF_EDOMAIN_BASE_TEXT,
713 : : PDF_ENOMEM,
714 : : "cannot convert from UTF-16HE to UTF-32HE: "
715 : : "couldn't reallocate %lu bytes",
716 : : (unsigned long)new_string_length);
717 : 0 : return PDF_FALSE;
718 : : }
719 : : }
720 : :
721 : 163 : return PDF_TRUE;
722 : : }
723 : :
724 : : /*********************** UTF-32 to UTF-16 conversions *************************/
725 : :
726 : : /* Static function to convert a given UTF-32HE character to UTF-16HE. The number
727 : : * of bytes used in the output UTF-16HE point is returned (or 0 if the UTF-16HE
728 : : * point is not valid */
729 : : static pdf_size_t
730 : : pdf_text_utf32he_point_to_utf16he_point (pdf_text_utf32_char_t utf32val,
731 : : pdf_text_utf16_char_t utf16val[2],
732 : : pdf_error_t **error)
733 : : {
734 : : pdf_size_t n_bytes;
735 : :
736 [ - + ]: 1008 : if ((utf32val.i >= 0xD800) &&
737 : : (utf32val.i <= 0xDFFF))
738 : : {
739 : 0 : pdf_set_error (error,
740 : : PDF_EDOMAIN_BASE_TEXT,
741 : : PDF_EBADTEXT,
742 : : "cannot convert from UTF-32HE to UTF-16HE: "
743 : : "invalid input code point (surrogate pair found): "
744 : : "%.2X:%.2X:%.2X:%.2X",
745 : 0 : utf32val.c[0], utf32val.c[1],
746 : 0 : utf32val.c[2], utf32val.c[3]);
747 : 0 : n_bytes = 0;
748 : : }
749 : : /* Check if multiword (32bits) representation is needed */
750 [ + + ]: 1008 : else if (utf32val.i >= 0x10000)
751 : : {
752 : : /* Ok so it seems a multiword representation...
753 : : * Now check input UTF-32HE representation to see if it really is a
754 : : * Unicode point (from 0x00000 to 0x10FFFF) */
755 [ + - ]: 32 : if (utf32val.i <= 0x10FFFF)
756 : : {
757 : : /* 32 bits are required for this char */
758 : 32 : n_bytes = 4;
759 : 32 : utf32val.i -= 0x10000;
760 : : /* Process higher 10 bits, by shifting to the right 10 bits */
761 : 32 : (utf16val[0]).i = (utf32val.i >> 10) + 0xD800;
762 : : /* Process lower 10 bits, by masking the value with 0x03FF */
763 : 32 : (utf16val[1]).i = (utf32val.i & 0x03FF) + 0xDC00;
764 : : }
765 : : else
766 : : {
767 : : /* else Oops, invalid 32-bit character! Input data is not well
768 : : * formed... */
769 : 0 : pdf_set_error (error,
770 : : PDF_EDOMAIN_BASE_TEXT,
771 : : PDF_EBADTEXT,
772 : : "cannot convert from UTF-32HE to UTF-16HE: "
773 : : "invalid input code point: "
774 : : "%.2X:%.2X:%.2X:%.2X",
775 : 0 : utf32val.c[0], utf32val.c[1],
776 : 0 : utf32val.c[2], utf32val.c[3]);
777 : 0 : n_bytes = 0;
778 : : }
779 : : }
780 : : else
781 : : {
782 : 976 : n_bytes = 2;
783 : : /* No multiword representation, just 16bits for this character
784 : : * So conversion is direct.... */
785 : 976 : (utf16val[0]).i = utf32val.i;
786 : 976 : (utf16val[1]).i = 0x0000;
787 : : }
788 : :
789 : 1008 : return n_bytes;
790 : : }
791 : :
792 : : /* Function to convert from UTF-32HE to UTF-16, lossless */
793 : : pdf_bool_t
794 : 80 : pdf_text_utf32he_to_utf16he (const pdf_char_t *input_data,
795 : : const pdf_size_t input_length,
796 : : pdf_char_t **p_output_data,
797 : : pdf_size_t *p_output_length,
798 : : pdf_bool_t swap,
799 : : pdf_error_t **error)
800 : : {
801 : : /* Note: UTF-16BE has either 16 or 32 bits per character.
802 : : This means that, if length of origin string is 4N bytes, the number of
803 : : required bytes for the UTF16BE representation of the string is 4N in
804 : : the worst case. (When all the UTF16be representations have 32bits)
805 : : */
806 : : pdf_size_t new_string_length;
807 : : pdf_size_t new_string_length_worst;
808 : : pdf_size_t delta_in_utf16be;
809 : : int i; /* index for the origin string data */
810 : : int j; /* index for the destination string data */
811 : : pdf_text_utf16_char_t utf16val[2];
812 : : pdf_text_utf32_char_t utf32val;
813 : : pdf_char_t *data;
814 : :
815 : : /* Get new string length (worst case)... */
816 : 80 : new_string_length_worst = input_length;
817 : : /* Create destination string with correct size (but empty!) */
818 : 80 : data = (pdf_char_t *) pdf_alloc (new_string_length_worst);
819 [ - + ]: 80 : if (data == NULL)
820 : : {
821 : 0 : pdf_set_error (error,
822 : : PDF_EDOMAIN_BASE_TEXT,
823 : : PDF_ENOMEM,
824 : : "cannot convert UTF-32HE to UTF-16HE: "
825 : : "couldn't allocate %lu bytes",
826 : : (unsigned long)new_string_length_worst);
827 : 0 : return PDF_FALSE;
828 : : }
829 : :
830 : : /* Initiate real string length, without considering marker bytes */
831 : 80 : new_string_length = 0;
832 : :
833 [ + + ]: 1088 : for (i = 0, j = 0; i < input_length; i += 4, j += delta_in_utf16be)
834 : : {
835 : : /* Get UCS4 char, as a direct memory copy from the input array */
836 : 1008 : memcpy (&utf32val, &(input_data[i]), 4);
837 : :
838 : 1008 : delta_in_utf16be = pdf_text_utf32he_point_to_utf16he_point (utf32val,
839 : : utf16val,
840 : : error);
841 [ - + ]: 1008 : if (delta_in_utf16be == 0)
842 : : {
843 : : /* Oops, invalid UTF-16HE point found! */
844 : 0 : pdf_dealloc (data);
845 : 0 : return PDF_FALSE;
846 : : }
847 : :
848 : : /* Change endianness of each output word if required */
849 [ + + ]: 1008 : if (swap)
850 : : {
851 : : /* Change to BE */
852 : 756 : (utf16val[0]).i = PDF_TEXT_CHANGE_ENDIANNESS_16BIT ((utf16val[0]).i);
853 : 756 : (utf16val[1]).i = PDF_TEXT_CHANGE_ENDIANNESS_16BIT ((utf16val[1]).i);
854 : : }
855 : :
856 : : /* Finally, store the UTF16BE representation of the char in the output
857 : : * string... */
858 : 1008 : memcpy (&(data[j]), &utf16val[0], delta_in_utf16be);
859 : : /* Update new string legth... */
860 : 1008 : new_string_length += delta_in_utf16be;
861 : : }
862 : :
863 : : /* If everything went ok, set output data */
864 : 80 : *p_output_data = data;
865 : : /* Set final output length of the generated string */
866 : 80 : *p_output_length = new_string_length;
867 : :
868 : : /* If the real required string length is not equal to the initial worst length
869 : : * then update string with correct length. */
870 [ + - ]: 80 : if (new_string_length != new_string_length_worst)
871 : : {
872 : : /* Recreate object with correct smaller size... */
873 : 80 : *p_output_data = (pdf_char_t *) pdf_realloc (*p_output_data,
874 : : new_string_length);
875 [ - + ]: 80 : if (*p_output_data == NULL)
876 : : {
877 : 0 : pdf_set_error (error,
878 : : PDF_EDOMAIN_BASE_TEXT,
879 : : PDF_ENOMEM,
880 : : "cannot convert from UTF-16HE to UTF-32HE: "
881 : : "couldn't allocate %lu bytes",
882 : : (unsigned long)new_string_length);
883 : 0 : return PDF_FALSE;
884 : : }
885 : : }
886 : :
887 : 80 : return PDF_TRUE;
888 : : }
889 : :
890 : : /************************ UTF-8 to UTF-32 conversions *************************/
891 : :
892 : : /* Static function to convert a given UTF-8 character to UTF-32HE. The number
893 : : * of bytes used in the input UTF-8 point is returned (or 0 if the UTF-8 point
894 : : * is not valid */
895 : : static pdf_size_t
896 : 2749 : pdf_text_utf8_point_to_utf32he_point (const pdf_uchar_t utf8val[4],
897 : : const pdf_size_t n_bytes,
898 : : pdf_text_utf32_char_t *p_utf32val,
899 : : pdf_error_t **error)
900 : : {
901 : : int c; /* index for the utf-8 representation of every char */
902 : :
903 : : /* Check validity of the UTF-8 bytes:
904 : : * - First byte can be neither 0xFF nor 0xFE
905 : : * - The following bytes must be in the [80-BF] range! (10xxxxxx) */
906 [ + + ]: 5540 : for (c = 0; c < n_bytes; c++)
907 : : {
908 [ + + ][ + - ]: 2791 : if (((c == 0) && ((utf8val[0] == 0xFF) || (utf8val[0] == 0xFE))) ||
[ + + ][ - + ]
909 : 42 : ((c != 0) && ((utf8val[c] < 0x80) || (utf8val[c] > 0xBF))))
910 : : {
911 [ # # ][ # # ]: 0 : pdf_set_error (error,
[ # # ]
912 : : PDF_EDOMAIN_BASE_TEXT,
913 : : PDF_EBADTEXT,
914 : : "cannot convert from UTF-8 to UTF-32HE: "
915 : : "invalid input code point: "
916 : : "%.2X:%.2X:%.2X:%.2X",
917 : 0 : (pdf_uchar_t)utf8val[0],
918 : 0 : ((n_bytes>1)?((pdf_uchar_t)utf8val[1]):0),
919 : 0 : ((n_bytes>2)?((pdf_uchar_t)utf8val[2]):0),
920 : 0 : ((n_bytes>3)?((pdf_uchar_t)utf8val[3]):0));
921 : 0 : return 0;
922 : : }
923 : : }
924 : :
925 : : /* Load all the bytes of the UTF-8 representation in the UTF-32HE var */
926 [ + + + + : 2749 : switch (n_bytes)
- ]
927 : : {
928 : : case 1:
929 : 2727 : (*p_utf32val).i = (utf8val[0] & 0x7F); /* 0111 1111 */
930 : 2727 : break;
931 : : case 2:
932 : 20 : (*p_utf32val).i = ((utf8val[0] & 0x1F) << 6) + /* 0001 1111 */
933 : 10 : (utf8val[1] & 0x3F); /* 0011 1111 */
934 : 10 : break;
935 : : case 3:
936 : 8 : (*p_utf32val).i = ((utf8val[0] & 0x0F) << 12) + /* 0000 1111 */
937 : 4 : ((utf8val[1] & 0x3F) << 6) + /* 0011 1111 */
938 : 4 : (utf8val[2] & 0x3F); /* 0011 1111 */
939 : 4 : break;
940 : : case 4:
941 : 16 : (*p_utf32val).i = ((utf8val[0] & 0x07) << 18) + /* 0000 1111 */
942 : 8 : ((utf8val[1] & 0x3F) << 12) + /* 0000 1111 */
943 : 8 : ((utf8val[2] & 0x3F) << 6) + /* 0011 1111 */
944 : 8 : (utf8val[3] & 0x3F); /* 0011 1111 */
945 : 8 : break;
946 : : default:
947 : : /* Should never happen! */
948 : 0 : PDF_ASSERT_TRACE_NOT_REACHED ();
949 : 0 : return 0;
950 : : }
951 : :
952 : 2749 : return n_bytes;
953 : : }
954 : :
955 : : /* Function to convert from UTF-8 to UTF-32HE, lossless */
956 : : pdf_bool_t
957 : 950 : pdf_text_utf8_to_utf32he (const pdf_char_t *input_data,
958 : : const pdf_size_t input_length,
959 : : pdf_char_t **p_output_data,
960 : : pdf_size_t *p_output_length,
961 : : pdf_error_t **error)
962 : : {
963 : : /* Note: PDF Doc Encoding has always 8 bits per character.
964 : : * This means that, if length of origin string is N bytes, the number of
965 : : * required bytes for the UTF32 representation of the string is 4N.
966 : : * (Each PDFDocEncoding byte is expanded to 4 bytes in UTF32. */
967 : : pdf_size_t new_string_length;
968 : : pdf_size_t new_string_length_worst;
969 : : pdf_size_t bom_bytes;
970 : : int i; /* index for the origin string data */
971 : : int j; /* index for the destination string data */
972 : : pdf_size_t delta_in_utf8;
973 : : pdf_char_t *data;
974 : :
975 : : /* Check if BOM is present... and skip it if so */
976 : 950 : bom_bytes = 0;
977 [ + + ]: 950 : if (pdf_text_check_unicode_bom (input_data, input_length, PDF_TEXT_UTF8, 0))
978 : : {
979 : : /* Skip BOM in UTF-8 */
980 : 30 : bom_bytes = 3;
981 : : }
982 : :
983 : : /* Get new string length... */
984 : 950 : new_string_length_worst = 4 * (input_length - bom_bytes);
985 : :
986 : : /* Create destination string with worst size (but empty!) */
987 : 950 : data = (pdf_char_t *) pdf_alloc (new_string_length_worst);
988 [ - + ]: 950 : if (data == NULL)
989 : : {
990 : 0 : pdf_set_error (error,
991 : : PDF_EDOMAIN_BASE_TEXT,
992 : : PDF_ENOMEM,
993 : : "cannot convert from UTF-8 to UTF-32HE: "
994 : : "couldn't allocate %lu bytes",
995 : : (unsigned long)new_string_length_worst);
996 : 0 : return PDF_FALSE;
997 : : }
998 : :
999 : 950 : new_string_length = 0;
1000 [ + + ]: 3699 : for (i = bom_bytes, j = 0; i < input_length; i += delta_in_utf8, j += 4)
1001 : : {
1002 : : pdf_text_utf32_char_t utf32val;
1003 : : pdf_uchar_t utf8val[4];
1004 : :
1005 : : /* Check number of bytes needed for the UTF-8 char */
1006 : 2789 : delta_in_utf8 = n_bytes_in_utf8_char[(pdf_uchar_t)input_data[i]];
1007 : :
1008 : : /* Check validity of first byte in UTF-8 */
1009 : : /* Check if the required bytes are outside the input data stream */
1010 [ + + ][ - + ]: 2789 : if ((delta_in_utf8 == 0) ||
1011 : 2749 : ((input_length - i) < delta_in_utf8))
1012 : : {
1013 : 40 : pdf_dealloc (data);
1014 : 40 : pdf_set_error (error,
1015 : : PDF_EDOMAIN_BASE_TEXT,
1016 : : PDF_EBADDATA,
1017 : : "cannot convert UTF-8 to UTF-32HE: "
1018 : : "wrong UTF-8 data received (UTF-8 length: %d, "
1019 : : "remaining length: %d)",
1020 : : delta_in_utf8,
1021 : : (input_length - i));
1022 : 40 : return PDF_FALSE;
1023 : : }
1024 : :
1025 : : /* Store data in intermediate UTF-8 variable */
1026 : 2749 : memcpy (&utf8val[0], &input_data[i], delta_in_utf8);
1027 : :
1028 [ - + ]: 2749 : if (pdf_text_utf8_point_to_utf32he_point (utf8val,
1029 : : delta_in_utf8,
1030 : : &utf32val,
1031 : : error) == 0)
1032 : : {
1033 : 0 : pdf_dealloc (data);
1034 : 0 : return PDF_FALSE;
1035 : : }
1036 : :
1037 : : /* Copy converted value (in UTF-32HE) to output */
1038 : 2749 : memcpy (&(data[j]), &(utf32val), 4);
1039 : :
1040 : : /* Update new string length */
1041 : 2749 : new_string_length += 4;
1042 : : }
1043 : :
1044 : : /* If everything went ok, set output data */
1045 : 910 : *p_output_data = data;
1046 : : /* Set final output length of the generated string */
1047 : 910 : *p_output_length = new_string_length;
1048 : :
1049 : : /* If the real required string length is not equal to the initial worst length
1050 : : * then update string with correct length. */
1051 [ + + ]: 910 : if (new_string_length != new_string_length_worst)
1052 : : {
1053 : : /* Recreate object with correct smaller size... */
1054 : 14 : *p_output_data = (pdf_char_t *) pdf_realloc (*p_output_data,
1055 : : new_string_length);
1056 [ - + ]: 14 : if (*p_output_data == NULL)
1057 : : {
1058 : 0 : pdf_set_error (error,
1059 : : PDF_EDOMAIN_BASE_TEXT,
1060 : : PDF_ENOMEM,
1061 : : "cannot convert from UTF-8 to UTF-32HE: "
1062 : : "couldn't reallocate %lu bytes",
1063 : : (unsigned long)new_string_length);
1064 : 0 : return PDF_FALSE;
1065 : : }
1066 : : }
1067 : :
1068 : 950 : return PDF_TRUE;
1069 : : }
1070 : :
1071 : : /************************ UTF-32 to UTF-8 conversions *************************/
1072 : :
1073 : : /* Static function to convert a given UTF-32HE character to UTF-8. The number
1074 : : * of bytes used in the output UTF-8 point is returned (or 0 if the UTF-8 point
1075 : : * is not valid */
1076 : : static pdf_size_t
1077 : : pdf_text_utf32he_point_to_utf8_point (const pdf_text_utf32_char_t utf32val,
1078 : : pdf_uchar_t utf8val[4],
1079 : : pdf_error_t **error)
1080 : : {
1081 : : pdf_size_t n_bytes;
1082 : :
1083 [ + + ]: 1597 : if (utf32val.i < 0x80)
1084 : : {
1085 : : /* Output is 1 byte */
1086 : 1581 : n_bytes = 1;
1087 : 1581 : utf8val[0] = (pdf_uchar_t)utf32val.i;
1088 : : }
1089 [ + + ]: 16 : else if (utf32val.i < 0x800)
1090 : : {
1091 : : /* Output is 2 bytes */
1092 : 4 : n_bytes = 2;
1093 : : /* Get first byte, using upper 5 bits --> 110xxxxx */
1094 : 4 : utf8val[0] = ((pdf_uchar_t)(utf32val.i >> 6)) | 0xC0;
1095 : : /* Get second byte, using lower 6 bits --> 10xxxxxx */
1096 : 4 : utf8val[1] = ((pdf_uchar_t)(utf32val.i & 0x3F)) | 0x80;
1097 : : }
1098 [ + + ]: 12 : else if (utf32val.i < 0x10000)
1099 : : {
1100 : : /* Output is 3 bytes */
1101 : 4 : n_bytes = 3;
1102 : : /* Get first byte, using upper 4 bits --> 1110xxxx */
1103 : 4 : utf8val[0] = ((pdf_uchar_t)(utf32val.i >> 12)) | 0xE0;
1104 : : /* Get second byte, using middle 6 bits --> 10xxxxxx */
1105 : 4 : utf8val[1] = ((pdf_uchar_t)((utf32val.i >> 6) & 0x3F)) | 0x80;
1106 : : /* Get third byte, using lower 6 bits --> 10xxxxxx */
1107 : 4 : utf8val[2] = ((pdf_uchar_t)(utf32val.i & 0x3F)) | 0x80;
1108 : : }
1109 [ + - ]: 8 : else if (utf32val.i < 0x0010FFFF)
1110 : : {
1111 : : /* Output is 4 bytes */
1112 : 8 : n_bytes = 4;
1113 : : /* Get first byte, using upper 3 bits --> 11110xxx */
1114 : 8 : utf8val[0] = ((pdf_uchar_t)(utf32val.i >> 18)) | 0xF0;
1115 : : /* Get second byte, using upper-middle 6 bits --> 10xxxxxx */
1116 : 8 : utf8val[1] = (((pdf_uchar_t)(utf32val.i >> 12)) & 0x3F) | 0x80;
1117 : : /* Get second byte, using lower-middle 6 bits --> 10xxxxxx */
1118 : 8 : utf8val[2] = (((pdf_uchar_t)(utf32val.i >> 6)) & 0x3F) | 0x80;
1119 : : /* Get third byte, using lower 6 bits --> 10xxxxxx */
1120 : 8 : utf8val[3] = ((pdf_uchar_t)(utf32val.i & 0x3F)) | 0x80;
1121 : : }
1122 : : else
1123 : : {
1124 : 0 : pdf_set_error (error,
1125 : : PDF_EDOMAIN_BASE_TEXT,
1126 : : PDF_EBADTEXT,
1127 : : "cannot convert from UTF-32HE to UTF-8: "
1128 : : "invalid input code point: "
1129 : : "%.2X:%.2X:%.2X:%.2X",
1130 : 0 : utf32val.c[0],
1131 : 0 : utf32val.c[1],
1132 : 0 : utf32val.c[2],
1133 : 0 : utf32val.c[3]);
1134 : 0 : n_bytes = 0;
1135 : : }
1136 : :
1137 : 1597 : return n_bytes;
1138 : : }
1139 : :
1140 : : /* Function to convert from UTF-32HE to UTF-8, lossless */
1141 : : pdf_bool_t
1142 : 86 : pdf_text_utf32he_to_utf8 (const pdf_char_t *input_data,
1143 : : const pdf_size_t input_length,
1144 : : pdf_char_t **p_output_data,
1145 : : pdf_size_t *p_output_length,
1146 : : pdf_error_t **error)
1147 : : {
1148 : : /* Note: UTF-8 has either 8, 16, 24 or 32 bits per character.
1149 : : This means that, if length of origin string is 4N bytes, the number of
1150 : : required bytes for the UTF-8 representation of the string is 4N in
1151 : : the worst case. (When all the UTF-8 representations have 32bits)
1152 : : */
1153 : : pdf_size_t new_string_length;
1154 : : pdf_size_t new_string_length_worst;
1155 : : int i; /* index for the origin string data */
1156 : : int j; /* index for the destination string data */
1157 : : pdf_char_t *data;
1158 : : pdf_size_t delta_in_utf8;
1159 : :
1160 : : /* Get new string length (worst case)... */
1161 : 86 : new_string_length_worst = input_length;
1162 : : /* Create destination string with correct size (but empty!) */
1163 : 86 : data = (pdf_char_t *) pdf_alloc (new_string_length_worst);
1164 [ - + ]: 86 : if (data == NULL)
1165 : : {
1166 : 0 : pdf_set_error (error,
1167 : : PDF_EDOMAIN_BASE_TEXT,
1168 : : PDF_ENOMEM,
1169 : : "cannot convert UTF-32HE to UTF-8: "
1170 : : "couldn't allocate %lu bytes",
1171 : : (unsigned long)new_string_length_worst);
1172 : 0 : return PDF_FALSE;
1173 : : }
1174 : :
1175 : : /* Initiate real string length, without considering marker bytes */
1176 : 86 : new_string_length = 0;
1177 : :
1178 [ + + ]: 1683 : for (i = 0, j = 0; i < input_length; i += 4, j += delta_in_utf8)
1179 : : {
1180 : : pdf_text_utf32_char_t utf32val;
1181 : : pdf_uchar_t utf8val[4];
1182 : :
1183 : : /* Get UTF-32 char, as a direct memory copy from the input array */
1184 : 1597 : memcpy (&utf32val, &(input_data[i]), 4);
1185 : :
1186 : 1597 : delta_in_utf8 = pdf_text_utf32he_point_to_utf8_point (utf32val,
1187 : : utf8val,
1188 : : error);
1189 [ - + ]: 1597 : if (delta_in_utf8 == 0)
1190 : : {
1191 : 0 : pdf_dealloc (data);
1192 : 0 : return PDF_FALSE;
1193 : : }
1194 : :
1195 : : /* Store UTF-8 val in output array */
1196 : 1597 : memcpy (&data[j], &(utf8val[0]), delta_in_utf8);
1197 : :
1198 : : /* Update new_string_length, depending on the bytes used to represent
1199 : : * this character in UTF-8 */
1200 : 1597 : new_string_length += delta_in_utf8;
1201 : : }
1202 : :
1203 : : /* If everything went ok, set output data */
1204 : 86 : *p_output_data = data;
1205 : : /* Set final output length of the generated string */
1206 : 86 : *p_output_length = new_string_length;
1207 : :
1208 : : /* If the real required string length is not equal to the initial worst length
1209 : : * then update string with correct length. */
1210 [ + + ]: 86 : if (new_string_length != new_string_length_worst)
1211 : : {
1212 : : /* Recreate object with correct smaller size... */
1213 : 82 : *p_output_data = (pdf_char_t *) pdf_realloc (*p_output_data,
1214 : : new_string_length);
1215 [ - + ]: 82 : if (*p_output_data == NULL)
1216 : : {
1217 : 0 : pdf_set_error (error,
1218 : : PDF_EDOMAIN_BASE_TEXT,
1219 : : PDF_ENOMEM,
1220 : : "cannot convert from UTF-32HE to UTF-8: "
1221 : : "couldn't allocate %lu bytes",
1222 : : (unsigned long)new_string_length);
1223 : 0 : return PDF_FALSE;
1224 : : }
1225 : : }
1226 : :
1227 : 86 : return PDF_TRUE;
1228 : : }
1229 : :
1230 : : /*************************** BOM-related functions ****************************/
1231 : :
1232 : : pdf_text_bom_t
1233 : 108 : pdf_text_get_unicode_bom (enum pdf_text_unicode_encoding_e unicode_encoding)
1234 : : {
1235 : 108 : return unicode_bom[unicode_encoding];
1236 : : }
1237 : :
1238 : : pdf_bool_t
1239 : 1799 : pdf_text_check_unicode_bom (const pdf_char_t *data,
1240 : : const pdf_size_t size,
1241 : : enum pdf_text_unicode_encoding_e enc,
1242 : : int swap)
1243 : : {
1244 [ + + - ]: 1799 : switch(enc)
1245 : : {
1246 : : case PDF_TEXT_UTF16_HE:
1247 : : case PDF_TEXT_UTF32_HE:
1248 : : {
1249 [ + + ]: 802 : enc += ((PDF_IS_BIG_ENDIAN ^ swap) ? PDF_TEXT_HE_TO_BE:PDF_TEXT_HE_TO_LE);
1250 : : }
1251 : : case PDF_TEXT_UTF8:
1252 : : case PDF_TEXT_UTF16_BE:
1253 : : case PDF_TEXT_UTF16_LE:
1254 : : case PDF_TEXT_UTF32_BE:
1255 : : case PDF_TEXT_UTF32_LE:
1256 : : {
1257 [ + + ][ + + ]: 1799 : if ((size >= unicode_bom[enc].bom_bytes) &&
1258 : 2052 : (memcmp (data,
1259 : 1026 : unicode_bom[enc].bom_data,
1260 : : unicode_bom[enc].bom_bytes) == 0))
1261 : : {
1262 : 116 : return PDF_TRUE;
1263 : : }
1264 : : }
1265 : : default:
1266 : 1799 : return PDF_FALSE;
1267 : : }
1268 : : }
1269 : :
1270 : : /*************************** Other helper functions ****************************/
1271 : :
1272 : : const pdf_char_t *
1273 : 80 : pdf_text_get_unicode_encoding_name (enum pdf_text_unicode_encoding_e unicode_encoding)
1274 : : {
1275 : 80 : return unicode_encoding_name[unicode_encoding];
1276 : : }
1277 : :
1278 : : /* End of pdf-text-encoding.c */
|