summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar shane2013-10-17 15:02:23 -0400
committerGravatar shane2013-10-17 15:02:23 -0400
commit95d1d0cc91f36ece9da39270cd1ca0536d0cf02d (patch)
tree9d2431f1bfa3c4a562cd006bc22ef2b7280d7b66 /src
parente9995aee384bdbac6c6afc0f4548a080eb4241bc (diff)
downloadlibplist-95d1d0cc91f36ece9da39270cd1ca0536d0cf02d.tar.gz
libplist-95d1d0cc91f36ece9da39270cd1ca0536d0cf02d.tar.bz2
UTF-16 surrogate pair fix
Handle UTF-16 surrogate pair conversion to/from UTF-8
Diffstat (limited to 'src')
-rw-r--r--src/bplist.c41
1 files changed, 37 insertions, 4 deletions
diff --git a/src/bplist.c b/src/bplist.c
index 5db7096..d825fc8 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -286,15 +286,38 @@ static plist_t parse_string_node(char *bnode, uint64_t size)
286static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, long *items_written) 286static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, long *items_written)
287{ 287{
288 if (!unistr || (len <= 0)) return NULL; 288 if (!unistr || (len <= 0)) return NULL;
289 char *outbuf = (char*)malloc(3*(len+1)); 289 char *outbuf = (char*)malloc(4*(len+1));
290 int p = 0; 290 int p = 0;
291 int i = 0; 291 int i = 0;
292 292
293 uint16_t wc; 293 uint16_t wc;
294 uint32_t w;
295 int read_lead_surrogate = 0;
294 296
295 while (i < len) { 297 while (i < len) {
296 wc = unistr[i++]; 298 wc = unistr[i++];
297 if (wc >= 0x800) { 299 if (wc >= 0xD800 && wc <= 0xDBFF) {
300 if (!read_lead_surrogate) {
301 read_lead_surrogate = 1;
302 w = 0x010000 + ((wc & 0x3FF) << 10);
303 } else {
304 // This is invalid, the next 16 bit char should be a trail surrogate.
305 // Handling error by skipping.
306 read_lead_surrogate = 0;
307 }
308 } else if (wc >= 0xDC00 && wc <= 0xDFFF) {
309 if (read_lead_surrogate) {
310 read_lead_surrogate = 0;
311 w = w | (wc & 0x3FF);
312 outbuf[p++] = (char)(0xF0 + ((w >> 18) & 0x3));
313 outbuf[p++] = (char)(0x80 + ((w >> 12) & 0x3F));
314 outbuf[p++] = (char)(0x80 + ((w >> 6) & 0x3F));
315 outbuf[p++] = (char)(0x80 + (w & 0x3F));
316 } else {
317 // This is invalid. A trail surrogate should always follow a lead surrogate.
318 // Handling error by skipping
319 }
320 } else if (wc >= 0x800) {
298 outbuf[p++] = (char)(0xE0 + ((wc >> 12) & 0xF)); 321 outbuf[p++] = (char)(0xE0 + ((wc >> 12) & 0xF));
299 outbuf[p++] = (char)(0x80 + ((wc >> 6) & 0x3F)); 322 outbuf[p++] = (char)(0x80 + ((wc >> 6) & 0x3F));
300 outbuf[p++] = (char)(0x80 + (wc & 0x3F)); 323 outbuf[p++] = (char)(0x80 + (wc & 0x3F));
@@ -988,19 +1011,29 @@ static int is_ascii_string(char* s, int len)
988 1011
989uint16_t *plist_utf8_to_utf16(char *unistr, long size, long *items_read, long *items_written) 1012uint16_t *plist_utf8_to_utf16(char *unistr, long size, long *items_read, long *items_written)
990{ 1013{
991 uint16_t *outbuf = (uint16_t*)malloc((size+1)*sizeof(uint16_t)); 1014 uint16_t *outbuf = (uint16_t*)malloc(((size*2)+1)*sizeof(uint16_t));
992 int p = 0; 1015 int p = 0;
993 int i = 0; 1016 int i = 0;
994 1017
995 unsigned char c0; 1018 unsigned char c0;
996 unsigned char c1; 1019 unsigned char c1;
997 unsigned char c2; 1020 unsigned char c2;
1021 unsigned char c3;
1022
1023 uint32_t w;
998 1024
999 while (i < size) { 1025 while (i < size) {
1000 c0 = unistr[i]; 1026 c0 = unistr[i];
1001 c1 = (i < size-1) ? unistr[i+1] : 0; 1027 c1 = (i < size-1) ? unistr[i+1] : 0;
1002 c2 = (i < size-2) ? unistr[i+2] : 0; 1028 c2 = (i < size-2) ? unistr[i+2] : 0;
1003 if ((c0 >= 0xE0) && (i < size-2) && (c1 >= 0x80) && (c2 >= 0x80)) { 1029 c3 = (i < size-3) ? unistr[i+3] : 0;
1030 if ((c0 >= 0xF0) && (i < size-3) && (c1 >= 0x80) && (c2 >= 0x80) && (c3 >= 0x80)) {
1031 // 4 byte sequence. Need to generate UTF-16 surrogate pair
1032 w = ((((c0 & 7) << 18) + ((c1 & 0x3F) << 12) + ((c2 & 0x3F) << 6) + (c3 & 0x3F)) & 0x0FFFFF) - 0x010000;
1033 outbuf[p++] = 0xD800 + (w >> 10);
1034 outbuf[p++] = 0xDC00 + (w & 0x3FF);
1035 i+=4;
1036 } else if ((c0 >= 0xE0) && (i < size-2) && (c1 >= 0x80) && (c2 >= 0x80)) {
1004 // 3 byte sequence 1037 // 3 byte sequence
1005 outbuf[p++] = ((c2 & 0x3F) + ((c1 & 3) << 6)) + (((c1 >> 2) & 15) << 8) + ((c0 & 15) << 12); 1038 outbuf[p++] = ((c2 & 0x3F) + ((c1 & 3) << 6)) + (((c1 >> 2) & 15) << 8) + ((c0 & 15) << 12);
1006 i+=3; 1039 i+=3;