diff options
| -rw-r--r-- | src/bplist.c | 160 |
1 files changed, 72 insertions, 88 deletions
diff --git a/src/bplist.c b/src/bplist.c index 1ecbd66..c4fe3df 100644 --- a/src/bplist.c +++ b/src/bplist.c | |||
| @@ -315,7 +315,7 @@ static plist_t parse_string_node(const char **bnode, uint64_t size) | |||
| 315 | return node_create(NULL, data); | 315 | return node_create(NULL, data); |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, long *items_written) | 318 | static char *plist_utf16be_to_utf8(uint16_t *unistr, long len, long *items_read, long *items_written) |
| 319 | { | 319 | { |
| 320 | if (!unistr || (len <= 0)) return NULL; | 320 | if (!unistr || (len <= 0)) return NULL; |
| 321 | char *outbuf; | 321 | char *outbuf; |
| @@ -333,7 +333,8 @@ static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, l | |||
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | while (i < len) { | 335 | while (i < len) { |
| 336 | wc = unistr[i++]; | 336 | wc = be16toh(get_unaligned(unistr + i)); |
| 337 | i++; | ||
| 337 | if (wc >= 0xD800 && wc <= 0xDBFF) { | 338 | if (wc >= 0xD800 && wc <= 0xDBFF) { |
| 338 | if (!read_lead_surrogate) { | 339 | if (!read_lead_surrogate) { |
| 339 | read_lead_surrogate = 1; | 340 | read_lead_surrogate = 1; |
| @@ -380,24 +381,13 @@ static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, l | |||
| 380 | static plist_t parse_unicode_node(const char **bnode, uint64_t size) | 381 | static plist_t parse_unicode_node(const char **bnode, uint64_t size) |
| 381 | { | 382 | { |
| 382 | plist_data_t data = plist_new_plist_data(); | 383 | plist_data_t data = plist_new_plist_data(); |
| 383 | uint64_t i = 0; | ||
| 384 | uint16_t *unicodestr = NULL; | ||
| 385 | char *tmpstr = NULL; | 384 | char *tmpstr = NULL; |
| 386 | long items_read = 0; | 385 | long items_read = 0; |
| 387 | long items_written = 0; | 386 | long items_written = 0; |
| 388 | 387 | ||
| 389 | data->type = PLIST_STRING; | 388 | data->type = PLIST_STRING; |
| 390 | unicodestr = (uint16_t*) malloc(sizeof(uint16_t) * size); | ||
| 391 | if (!unicodestr) { | ||
| 392 | plist_free_data(data); | ||
| 393 | PLIST_BIN_ERR("%s: Could not allocate %" PRIu64 " bytes\n", __func__, sizeof(uint16_t) * size); | ||
| 394 | return NULL; | ||
| 395 | } | ||
| 396 | for (i = 0; i < size; i++) | ||
| 397 | unicodestr[i] = be16toh(get_unaligned((uint16_t*)(*bnode+(i<<1)))); | ||
| 398 | 389 | ||
| 399 | tmpstr = plist_utf16_to_utf8(unicodestr, size, &items_read, &items_written); | 390 | tmpstr = plist_utf16be_to_utf8((uint16_t*)(*bnode), size, &items_read, &items_written); |
| 400 | free(unicodestr); | ||
| 401 | if (!tmpstr) { | 391 | if (!tmpstr) { |
| 402 | plist_free_data(data); | 392 | plist_free_data(data); |
| 403 | return NULL; | 393 | return NULL; |
| @@ -1028,14 +1018,74 @@ static void write_string(bytearray_t * bplist, char *val, uint64_t size) | |||
| 1028 | write_raw_data(bplist, BPLIST_STRING, (uint8_t *) val, size); | 1018 | write_raw_data(bplist, BPLIST_STRING, (uint8_t *) val, size); |
| 1029 | } | 1019 | } |
| 1030 | 1020 | ||
| 1031 | static void write_unicode(bytearray_t * bplist, uint16_t * val, uint64_t size) | 1021 | static uint16_t *plist_utf8_to_utf16be(char *unistr, long size, long *items_read, long *items_written) |
| 1032 | { | 1022 | { |
| 1033 | uint64_t i = 0; | 1023 | uint16_t *outbuf; |
| 1034 | uint16_t *buff = (uint16_t*)malloc(size << 1); | 1024 | int p = 0; |
| 1035 | for (i = 0; i < size; i++) | 1025 | long i = 0; |
| 1036 | buff[i] = be16toh(val[i]); | 1026 | |
| 1037 | write_raw_data(bplist, BPLIST_UNICODE, (uint8_t*)buff, size); | 1027 | unsigned char c0; |
| 1038 | free(buff); | 1028 | unsigned char c1; |
| 1029 | unsigned char c2; | ||
| 1030 | unsigned char c3; | ||
| 1031 | |||
| 1032 | uint32_t w; | ||
| 1033 | |||
| 1034 | outbuf = (uint16_t*)malloc(((size*2)+1)*sizeof(uint16_t)); | ||
| 1035 | if (!outbuf) { | ||
| 1036 | PLIST_BIN_ERR("%s: Could not allocate %" PRIu64 " bytes\n", __func__, (uint64_t)((size*2)+1)*sizeof(uint16_t)); | ||
| 1037 | return NULL; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | while (i < size) { | ||
| 1041 | c0 = unistr[i]; | ||
| 1042 | c1 = (i < size-1) ? unistr[i+1] : 0; | ||
| 1043 | c2 = (i < size-2) ? unistr[i+2] : 0; | ||
| 1044 | c3 = (i < size-3) ? unistr[i+3] : 0; | ||
| 1045 | if ((c0 >= 0xF0) && (i < size-3) && (c1 >= 0x80) && (c2 >= 0x80) && (c3 >= 0x80)) { | ||
| 1046 | // 4 byte sequence. Need to generate UTF-16 surrogate pair | ||
| 1047 | w = ((((c0 & 7) << 18) + ((c1 & 0x3F) << 12) + ((c2 & 0x3F) << 6) + (c3 & 0x3F)) & 0x1FFFFF) - 0x010000; | ||
| 1048 | outbuf[p++] = be16toh(0xD800 + (w >> 10)); | ||
| 1049 | outbuf[p++] = be16toh(0xDC00 + (w & 0x3FF)); | ||
| 1050 | i+=4; | ||
| 1051 | } else if ((c0 >= 0xE0) && (i < size-2) && (c1 >= 0x80) && (c2 >= 0x80)) { | ||
| 1052 | // 3 byte sequence | ||
| 1053 | outbuf[p++] = be16toh(((c2 & 0x3F) + ((c1 & 3) << 6)) + (((c1 >> 2) & 15) << 8) + ((c0 & 15) << 12)); | ||
| 1054 | i+=3; | ||
| 1055 | } else if ((c0 >= 0xC0) && (i < size-1) && (c1 >= 0x80)) { | ||
| 1056 | // 2 byte sequence | ||
| 1057 | outbuf[p++] = be16toh(((c1 & 0x3F) + ((c0 & 3) << 6)) + (((c0 >> 2) & 7) << 8)); | ||
| 1058 | i+=2; | ||
| 1059 | } else if (c0 < 0x80) { | ||
| 1060 | // 1 byte sequence | ||
| 1061 | outbuf[p++] = be16toh(c0); | ||
| 1062 | i+=1; | ||
| 1063 | } else { | ||
| 1064 | // invalid character | ||
| 1065 | PLIST_BIN_ERR("%s: invalid utf8 sequence in string at index %lu\n", __func__, i); | ||
| 1066 | break; | ||
| 1067 | } | ||
| 1068 | } | ||
| 1069 | if (items_read) { | ||
| 1070 | *items_read = i; | ||
| 1071 | } | ||
| 1072 | if (items_written) { | ||
| 1073 | *items_written = p; | ||
| 1074 | } | ||
| 1075 | outbuf[p] = 0; | ||
| 1076 | |||
| 1077 | return outbuf; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | static void write_unicode(bytearray_t * bplist, char *val, uint64_t size) | ||
| 1081 | { | ||
| 1082 | long items_read = 0; | ||
| 1083 | long items_written = 0; | ||
| 1084 | uint16_t *unicodestr = NULL; | ||
| 1085 | |||
| 1086 | unicodestr = plist_utf8_to_utf16be(val, size, &items_read, &items_written); | ||
| 1087 | write_raw_data(bplist, BPLIST_UNICODE, (uint8_t*)unicodestr, items_written); | ||
| 1088 | free(unicodestr); | ||
| 1039 | } | 1089 | } |
| 1040 | 1090 | ||
| 1041 | static void write_array(bytearray_t * bplist, node_t* node, hashtable_t* ref_table, uint8_t ref_size) | 1091 | static void write_array(bytearray_t * bplist, node_t* node, hashtable_t* ref_table, uint8_t ref_size) |
| @@ -1111,66 +1161,6 @@ static int is_ascii_string(char* s, int len) | |||
| 1111 | return ret; | 1161 | return ret; |
| 1112 | } | 1162 | } |
| 1113 | 1163 | ||
| 1114 | static uint16_t *plist_utf8_to_utf16(char *unistr, long size, long *items_read, long *items_written) | ||
| 1115 | { | ||
| 1116 | uint16_t *outbuf; | ||
| 1117 | int p = 0; | ||
| 1118 | long i = 0; | ||
| 1119 | |||
| 1120 | unsigned char c0; | ||
| 1121 | unsigned char c1; | ||
| 1122 | unsigned char c2; | ||
| 1123 | unsigned char c3; | ||
| 1124 | |||
| 1125 | uint32_t w; | ||
| 1126 | |||
| 1127 | outbuf = (uint16_t*)malloc(((size*2)+1)*sizeof(uint16_t)); | ||
| 1128 | if (!outbuf) { | ||
| 1129 | PLIST_BIN_ERR("%s: Could not allocate %" PRIu64 " bytes\n", __func__, (uint64_t)((size*2)+1)*sizeof(uint16_t)); | ||
| 1130 | return NULL; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | while (i < size) { | ||
| 1134 | c0 = unistr[i]; | ||
| 1135 | c1 = (i < size-1) ? unistr[i+1] : 0; | ||
| 1136 | c2 = (i < size-2) ? unistr[i+2] : 0; | ||
| 1137 | c3 = (i < size-3) ? unistr[i+3] : 0; | ||
| 1138 | if ((c0 >= 0xF0) && (i < size-3) && (c1 >= 0x80) && (c2 >= 0x80) && (c3 >= 0x80)) { | ||
| 1139 | // 4 byte sequence. Need to generate UTF-16 surrogate pair | ||
| 1140 | w = ((((c0 & 7) << 18) + ((c1 & 0x3F) << 12) + ((c2 & 0x3F) << 6) + (c3 & 0x3F)) & 0x1FFFFF) - 0x010000; | ||
| 1141 | outbuf[p++] = 0xD800 + (w >> 10); | ||
| 1142 | outbuf[p++] = 0xDC00 + (w & 0x3FF); | ||
| 1143 | i+=4; | ||
| 1144 | } else if ((c0 >= 0xE0) && (i < size-2) && (c1 >= 0x80) && (c2 >= 0x80)) { | ||
| 1145 | // 3 byte sequence | ||
| 1146 | outbuf[p++] = ((c2 & 0x3F) + ((c1 & 3) << 6)) + (((c1 >> 2) & 15) << 8) + ((c0 & 15) << 12); | ||
| 1147 | i+=3; | ||
| 1148 | } else if ((c0 >= 0xC0) && (i < size-1) && (c1 >= 0x80)) { | ||
| 1149 | // 2 byte sequence | ||
| 1150 | outbuf[p++] = ((c1 & 0x3F) + ((c0 & 3) << 6)) + (((c0 >> 2) & 7) << 8); | ||
| 1151 | i+=2; | ||
| 1152 | } else if (c0 < 0x80) { | ||
| 1153 | // 1 byte sequence | ||
| 1154 | outbuf[p++] = c0; | ||
| 1155 | i+=1; | ||
| 1156 | } else { | ||
| 1157 | // invalid character | ||
| 1158 | PLIST_BIN_ERR("%s: invalid utf8 sequence in string at index %lu\n", __func__, i); | ||
| 1159 | break; | ||
| 1160 | } | ||
| 1161 | } | ||
| 1162 | if (items_read) { | ||
| 1163 | *items_read = i; | ||
| 1164 | } | ||
| 1165 | if (items_written) { | ||
| 1166 | *items_written = p; | ||
| 1167 | } | ||
| 1168 | outbuf[p] = 0; | ||
| 1169 | |||
| 1170 | return outbuf; | ||
| 1171 | |||
| 1172 | } | ||
| 1173 | |||
| 1174 | PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | 1164 | PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) |
| 1175 | { | 1165 | { |
| 1176 | ptrarray_t* objects = NULL; | 1166 | ptrarray_t* objects = NULL; |
| @@ -1186,10 +1176,6 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 1186 | uint8_t *buff = NULL; | 1176 | uint8_t *buff = NULL; |
| 1187 | uint64_t *offsets = NULL; | 1177 | uint64_t *offsets = NULL; |
| 1188 | bplist_trailer_t trailer; | 1178 | bplist_trailer_t trailer; |
| 1189 | //for string | ||
| 1190 | long items_read = 0; | ||
| 1191 | long items_written = 0; | ||
| 1192 | uint16_t *unicodestr = NULL; | ||
| 1193 | uint64_t objects_len = 0; | 1179 | uint64_t objects_len = 0; |
| 1194 | uint64_t buff_len = 0; | 1180 | uint64_t buff_len = 0; |
| 1195 | 1181 | ||
| @@ -1260,9 +1246,7 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 1260 | } | 1246 | } |
| 1261 | else | 1247 | else |
| 1262 | { | 1248 | { |
| 1263 | unicodestr = plist_utf8_to_utf16(data->strval, data->length, &items_read, &items_written); | 1249 | write_unicode(bplist_buff, data->strval, data->length); |
| 1264 | write_unicode(bplist_buff, unicodestr, items_written); | ||
| 1265 | free(unicodestr); | ||
| 1266 | } | 1250 | } |
| 1267 | break; | 1251 | break; |
| 1268 | case PLIST_DATA: | 1252 | case PLIST_DATA: |
