OLD | NEW |
1 /* | 1 /* |
2 ******************************************************************************* | 2 ******************************************************************************* |
3 * | 3 * |
4 * Copyright (C) 2000-2012, International Business Machines | 4 * Copyright (C) 2000-2014, International Business Machines |
5 * Corporation and others. All Rights Reserved. | 5 * Corporation and others. All Rights Reserved. |
6 * | 6 * |
7 ******************************************************************************* | 7 ******************************************************************************* |
8 * | 8 * |
9 * File reslist.c | 9 * File reslist.c |
10 * | 10 * |
11 * Modification History: | 11 * Modification History: |
12 * | 12 * |
13 * Date Name Description | 13 * Date Name Description |
14 * 02/21/00 weiv Creation. | 14 * 02/21/00 weiv Creation. |
15 ******************************************************************************* | 15 ******************************************************************************* |
16 */ | 16 */ |
17 | 17 |
18 #include <assert.h> | 18 #include <assert.h> |
19 #include <stdio.h> | 19 #include <stdio.h> |
20 #include "reslist.h" | 20 #include "reslist.h" |
21 #include "unewdata.h" | 21 #include "unewdata.h" |
22 #include "unicode/ures.h" | 22 #include "unicode/ures.h" |
23 #include "unicode/putil.h" | 23 #include "unicode/putil.h" |
24 #include "errmsg.h" | 24 #include "errmsg.h" |
25 | 25 |
26 #include "uarrsort.h" | 26 #include "uarrsort.h" |
27 #include "uelement.h" | 27 #include "uelement.h" |
| 28 #include "uhash.h" |
28 #include "uinvchar.h" | 29 #include "uinvchar.h" |
29 #include "ustr_imp.h" | 30 #include "ustr_imp.h" |
30 #include "unicode/utf16.h" | 31 #include "unicode/utf16.h" |
31 /* | 32 /* |
32 * Align binary data at a 16-byte offset from the start of the resource bundle, | 33 * Align binary data at a 16-byte offset from the start of the resource bundle, |
33 * to be safe for any data type it may contain. | 34 * to be safe for any data type it may contain. |
34 */ | 35 */ |
35 #define BIN_ALIGNMENT 16 | 36 #define BIN_ALIGNMENT 16 |
36 | 37 |
37 static UBool gIncludeCopyright = FALSE; | 38 static UBool gIncludeCopyright = FALSE; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 void setUsePoolBundle(UBool use) { | 99 void setUsePoolBundle(UBool use) { |
99 gUsePoolBundle = use; | 100 gUsePoolBundle = use; |
100 } | 101 } |
101 | 102 |
102 static void | 103 static void |
103 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status); | 104 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status); |
104 | 105 |
105 /* Writing Functions */ | 106 /* Writing Functions */ |
106 | 107 |
107 /* | 108 /* |
| 109 * Preflight strings. |
| 110 * Find duplicates and count the total number of string code units |
| 111 * so that they can be written first to the 16-bit array, |
| 112 * for minimal string and container storage. |
| 113 * |
| 114 * We walk the final parse tree, rather than collecting this information while b
uilding it, |
| 115 * so that we need not deal with changes to the parse tree (especially removing
resources). |
| 116 */ |
| 117 static void |
| 118 res_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable *
stringSet, |
| 119 UErrorCode *status); |
| 120 |
| 121 /* |
108 * type_write16() functions write resource values into f16BitUnits | 122 * type_write16() functions write resource values into f16BitUnits |
109 * and determine the resource item word, if possible. | 123 * and determine the resource item word, if possible. |
110 */ | 124 */ |
111 static void | 125 static void |
112 res_write16(struct SRBRoot *bundle, struct SResource *res, | 126 res_write16(struct SRBRoot *bundle, struct SResource *res, |
113 UErrorCode *status); | 127 UErrorCode *status); |
114 | 128 |
115 /* | 129 /* |
116 * type_preWrite() functions calculate ("preflight") and advance the *byteOffset | 130 * type_preWrite() functions calculate ("preflight") and advance the *byteOffset |
117 * by the size of their data in the binary file and | 131 * by the size of their data in the binary file and |
(...skipping 16 matching lines...) Expand all Loading... |
134 /* | 148 /* |
135 * type_write() functions write their data to mem and update the byteOffset | 149 * type_write() functions write their data to mem and update the byteOffset |
136 * in parallel. | 150 * in parallel. |
137 * (A kingdom for C++ and polymorphism...) | 151 * (A kingdom for C++ and polymorphism...) |
138 */ | 152 */ |
139 static void | 153 static void |
140 res_write(UNewDataMemory *mem, uint32_t *byteOffset, | 154 res_write(UNewDataMemory *mem, uint32_t *byteOffset, |
141 struct SRBRoot *bundle, struct SResource *res, | 155 struct SRBRoot *bundle, struct SResource *res, |
142 UErrorCode *status); | 156 UErrorCode *status); |
143 | 157 |
| 158 static void |
| 159 string_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtabl
e *stringSet, |
| 160 UErrorCode *status) { |
| 161 res->u.fString.fSame = uhash_get(stringSet, res); |
| 162 if (res->u.fString.fSame != NULL) { |
| 163 return; /* This is a duplicate of an earlier-visited string. */ |
| 164 } |
| 165 /* Put this string into the set for finding duplicates. */ |
| 166 uhash_put(stringSet, res, res, status); |
| 167 |
| 168 if (bundle->fStringsForm != STRINGS_UTF16_V1) { |
| 169 const UChar *s = res->u.fString.fChars; |
| 170 int32_t len = res->u.fString.fLength; |
| 171 if (len <= MAX_IMPLICIT_STRING_LENGTH && !U16_IS_TRAIL(s[0]) && len == u
_strlen(s)) { |
| 172 /* |
| 173 * This string will be stored without an explicit length. |
| 174 * Runtime will detect !U16_IS_TRAIL(s[0]) and call u_strlen(). |
| 175 */ |
| 176 res->u.fString.fNumCharsForLength = 0; |
| 177 } else if (len <= 0x3ee) { |
| 178 res->u.fString.fNumCharsForLength = 1; |
| 179 } else if (len <= 0xfffff) { |
| 180 res->u.fString.fNumCharsForLength = 2; |
| 181 } else { |
| 182 res->u.fString.fNumCharsForLength = 3; |
| 183 } |
| 184 bundle->f16BitUnitsLength += res->u.fString.fNumCharsForLength + len + 1
; /* +1 for the NUL */ |
| 185 } |
| 186 } |
| 187 |
| 188 static void |
| 189 array_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable
*stringSet, |
| 190 UErrorCode *status) { |
| 191 struct SResource *current; |
| 192 |
| 193 if (U_FAILURE(*status)) { |
| 194 return; |
| 195 } |
| 196 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNe
xt) { |
| 197 res_preflightStrings(bundle, current, stringSet, status); |
| 198 } |
| 199 } |
| 200 |
| 201 static void |
| 202 table_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable
*stringSet, |
| 203 UErrorCode *status) { |
| 204 struct SResource *current; |
| 205 |
| 206 if (U_FAILURE(*status)) { |
| 207 return; |
| 208 } |
| 209 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNe
xt) { |
| 210 res_preflightStrings(bundle, current, stringSet, status); |
| 211 } |
| 212 } |
| 213 |
| 214 static void |
| 215 res_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable *
stringSet, |
| 216 UErrorCode *status) { |
| 217 if (U_FAILURE(*status) || res == NULL) { |
| 218 return; |
| 219 } |
| 220 if (res->fRes != RES_BOGUS) { |
| 221 /* |
| 222 * The resource item word was already precomputed, which means |
| 223 * no further data needs to be written. |
| 224 * This might be an integer, or an empty string/binary/etc. |
| 225 */ |
| 226 return; |
| 227 } |
| 228 switch (res->fType) { |
| 229 case URES_STRING: |
| 230 string_preflightStrings(bundle, res, stringSet, status); |
| 231 break; |
| 232 case URES_ARRAY: |
| 233 array_preflightStrings(bundle, res, stringSet, status); |
| 234 break; |
| 235 case URES_TABLE: |
| 236 table_preflightStrings(bundle, res, stringSet, status); |
| 237 break; |
| 238 default: |
| 239 /* Neither a string nor a container. */ |
| 240 break; |
| 241 } |
| 242 } |
| 243 |
144 static uint16_t * | 244 static uint16_t * |
145 reserve16BitUnits(struct SRBRoot *bundle, int32_t length, UErrorCode *status) { | 245 reserve16BitUnits(struct SRBRoot *bundle, int32_t length, UErrorCode *status) { |
146 if (U_FAILURE(*status)) { | 246 if (U_FAILURE(*status)) { |
147 return NULL; | 247 return NULL; |
148 } | 248 } |
149 if ((bundle->f16BitUnitsLength + length) > bundle->f16BitUnitsCapacity) { | 249 if ((bundle->f16BitUnitsLength + length) > bundle->f16BitUnitsCapacity) { |
150 uint16_t *newUnits; | 250 uint16_t *newUnits; |
151 int32_t capacity = 2 * bundle->f16BitUnitsCapacity + length + 1024; | 251 int32_t capacity = 2 * bundle->f16BitUnitsCapacity + length + 1024; |
152 capacity &= ~1; /* ensures padding fits if f16BitUnitsLength needs it *
/ | 252 capacity &= ~1; /* ensures padding fits if f16BitUnitsLength needs it *
/ |
153 newUnits = (uint16_t *)uprv_malloc(capacity * 2); | 253 newUnits = (uint16_t *)uprv_malloc(capacity * 2); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 /* | 314 /* |
215 * Only called for UTF-16 v1 strings and duplicate UTF-16 v2 strings. | 315 * Only called for UTF-16 v1 strings and duplicate UTF-16 v2 strings. |
216 * For unique UTF-16 v2 strings, res_write16() sees fRes != RES_BOGUS | 316 * For unique UTF-16 v2 strings, res_write16() sees fRes != RES_BOGUS |
217 * and exits early. | 317 * and exits early. |
218 */ | 318 */ |
219 static void | 319 static void |
220 string_write16(struct SRBRoot *bundle, struct SResource *res, UErrorCode *status
) { | 320 string_write16(struct SRBRoot *bundle, struct SResource *res, UErrorCode *status
) { |
221 struct SResource *same; | 321 struct SResource *same; |
222 if ((same = res->u.fString.fSame) != NULL) { | 322 if ((same = res->u.fString.fSame) != NULL) { |
223 /* This is a duplicate. */ | 323 /* This is a duplicate. */ |
224 if (same->fRes == RES_BOGUS) { | 324 assert(same->fRes != RES_BOGUS && same->fWritten); |
225 /* The original has not been visited yet. */ | |
226 string_write16(bundle, same, status); | |
227 } | |
228 res->fRes = same->fRes; | 325 res->fRes = same->fRes; |
229 res->fWritten = same->fWritten; | 326 res->fWritten = same->fWritten; |
230 } | 327 } |
231 } | 328 } |
232 | 329 |
233 static void | 330 static void |
234 array_write16(struct SRBRoot *bundle, struct SResource *res, | 331 array_write16(struct SRBRoot *bundle, struct SResource *res, |
235 UErrorCode *status) { | 332 UErrorCode *status) { |
236 struct SResource *current; | 333 struct SResource *current; |
237 int32_t res16 = 0; | 334 int32_t res16 = 0; |
(...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 | 990 |
894 static UBool U_CALLCONV | 991 static UBool U_CALLCONV |
895 string_comp(const UElement key1, const UElement key2) { | 992 string_comp(const UElement key1, const UElement key2) { |
896 const struct SResource *res1 = (struct SResource *)key1.pointer; | 993 const struct SResource *res1 = (struct SResource *)key1.pointer; |
897 const struct SResource *res2 = (struct SResource *)key2.pointer; | 994 const struct SResource *res2 = (struct SResource *)key2.pointer; |
898 return 0 == u_strCompare(res1->u.fString.fChars, res1->u.fString.fLength, | 995 return 0 == u_strCompare(res1->u.fString.fChars, res1->u.fString.fLength, |
899 res2->u.fString.fChars, res2->u.fString.fLength, | 996 res2->u.fString.fChars, res2->u.fString.fLength, |
900 FALSE); | 997 FALSE); |
901 } | 998 } |
902 | 999 |
903 struct SResource *string_open(struct SRBRoot *bundle, const char *tag, const UCh
ar *value, int32_t len, const struct UString* comment, UErrorCode *status) { | 1000 static struct SResource * |
| 1001 stringbase_open(struct SRBRoot *bundle, const char *tag, int8_t type, |
| 1002 const UChar *value, int32_t len, const struct UString* comment, |
| 1003 UErrorCode *status) { |
904 struct SResource *res = res_open(bundle, tag, comment, status); | 1004 struct SResource *res = res_open(bundle, tag, comment, status); |
905 if (U_FAILURE(*status)) { | 1005 if (U_FAILURE(*status)) { |
906 return NULL; | 1006 return NULL; |
907 } | 1007 } |
908 res->fType = URES_STRING; | 1008 res->fType = type; |
909 | 1009 |
910 if (len == 0 && gFormatVersion > 1) { | 1010 if (len == 0 && gFormatVersion > 1) { |
911 res->u.fString.fChars = &gEmptyString; | 1011 res->u.fString.fChars = &gEmptyString; |
912 res->fRes = 0; | 1012 res->fRes = URES_MAKE_EMPTY_RESOURCE(type); |
913 res->fWritten = TRUE; | 1013 res->fWritten = TRUE; |
914 return res; | 1014 return res; |
915 } | 1015 } |
916 | 1016 |
917 res->u.fString.fLength = len; | 1017 res->u.fString.fLength = len; |
918 | 1018 res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1)); |
919 if (gFormatVersion > 1) { | |
920 /* check for duplicates */ | |
921 res->u.fString.fChars = (UChar *)value; | |
922 if (bundle->fStringSet == NULL) { | |
923 UErrorCode localStatus = U_ZERO_ERROR; /* if failure: just don't de
tect dups */ | |
924 bundle->fStringSet = uhash_open(string_hash, string_comp, string_com
p, &localStatus); | |
925 } else { | |
926 res->u.fString.fSame = uhash_get(bundle->fStringSet, res); | |
927 } | |
928 } | |
929 if (res->u.fString.fSame == NULL) { | |
930 /* this is a new string */ | |
931 res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1))
; | |
932 | |
933 if (res->u.fString.fChars == NULL) { | |
934 *status = U_MEMORY_ALLOCATION_ERROR; | |
935 uprv_free(res); | |
936 return NULL; | |
937 } | |
938 | |
939 uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * len); | |
940 res->u.fString.fChars[len] = 0; | |
941 if (bundle->fStringSet != NULL) { | |
942 /* put it into the set for finding duplicates */ | |
943 uhash_put(bundle->fStringSet, res, res, status); | |
944 } | |
945 | |
946 if (bundle->fStringsForm != STRINGS_UTF16_V1) { | |
947 if (len <= MAX_IMPLICIT_STRING_LENGTH && !U16_IS_TRAIL(value[0]) &&
len == u_strlen(value)) { | |
948 /* | |
949 * This string will be stored without an explicit length. | |
950 * Runtime will detect !U16_IS_TRAIL(value[0]) and call u_strlen
(). | |
951 */ | |
952 res->u.fString.fNumCharsForLength = 0; | |
953 } else if (len <= 0x3ee) { | |
954 res->u.fString.fNumCharsForLength = 1; | |
955 } else if (len <= 0xfffff) { | |
956 res->u.fString.fNumCharsForLength = 2; | |
957 } else { | |
958 res->u.fString.fNumCharsForLength = 3; | |
959 } | |
960 bundle->f16BitUnitsLength += res->u.fString.fNumCharsForLength + len
+ 1; /* +1 for the NUL */ | |
961 } | |
962 } else { | |
963 /* this is a duplicate of fSame */ | |
964 struct SResource *same = res->u.fString.fSame; | |
965 res->u.fString.fChars = same->u.fString.fChars; | |
966 } | |
967 return res; | |
968 } | |
969 | |
970 /* TODO: make alias_open and string_open use the same code */ | |
971 struct SResource *alias_open(struct SRBRoot *bundle, const char *tag, UChar *val
ue, int32_t len, const struct UString* comment, UErrorCode *status) { | |
972 struct SResource *res = res_open(bundle, tag, comment, status); | |
973 if (U_FAILURE(*status)) { | |
974 return NULL; | |
975 } | |
976 res->fType = URES_ALIAS; | |
977 if (len == 0 && gFormatVersion > 1) { | |
978 res->u.fString.fChars = &gEmptyString; | |
979 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_ALIAS); | |
980 res->fWritten = TRUE; | |
981 return res; | |
982 } | |
983 | |
984 res->u.fString.fLength = len; | |
985 res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1)); | |
986 if (res->u.fString.fChars == NULL) { | 1019 if (res->u.fString.fChars == NULL) { |
987 *status = U_MEMORY_ALLOCATION_ERROR; | 1020 *status = U_MEMORY_ALLOCATION_ERROR; |
988 uprv_free(res); | 1021 uprv_free(res); |
989 return NULL; | 1022 return NULL; |
990 } | 1023 } |
991 uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len + 1)); | 1024 uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * len); |
| 1025 res->u.fString.fChars[len] = 0; |
992 return res; | 1026 return res; |
993 } | 1027 } |
994 | 1028 |
| 1029 struct SResource *string_open(struct SRBRoot *bundle, const char *tag, const UCh
ar *value, int32_t len, const struct UString* comment, UErrorCode *status) { |
| 1030 return stringbase_open(bundle, tag, URES_STRING, value, len, comment, status
); |
| 1031 } |
| 1032 |
| 1033 struct SResource *alias_open(struct SRBRoot *bundle, const char *tag, UChar *val
ue, int32_t len, const struct UString* comment, UErrorCode *status) { |
| 1034 return stringbase_open(bundle, tag, URES_ALIAS, value, len, comment, status)
; |
| 1035 } |
| 1036 |
995 | 1037 |
996 struct SResource* intvector_open(struct SRBRoot *bundle, const char *tag, const
struct UString* comment, UErrorCode *status) { | 1038 struct SResource* intvector_open(struct SRBRoot *bundle, const char *tag, const
struct UString* comment, UErrorCode *status) { |
997 struct SResource *res = res_open(bundle, tag, comment, status); | 1039 struct SResource *res = res_open(bundle, tag, comment, status); |
998 if (U_FAILURE(*status)) { | 1040 if (U_FAILURE(*status)) { |
999 return NULL; | 1041 return NULL; |
1000 } | 1042 } |
1001 res->fType = URES_INT_VECTOR; | 1043 res->fType = URES_INT_VECTOR; |
1002 | 1044 |
1003 res->u.fIntVector.fCount = 0; | 1045 res->u.fIntVector.fCount = 0; |
1004 res->u.fIntVector.fArray = (uint32_t *) uprv_malloc(sizeof(uint32_t) * RESLI
ST_MAX_INT_VECTOR); | 1046 res->u.fIntVector.fArray = (uint32_t *) uprv_malloc(sizeof(uint32_t) * RESLI
ST_MAX_INT_VECTOR); |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1135 prev = current; | 1177 prev = current; |
1136 current = current->fNext; | 1178 current = current->fNext; |
1137 | 1179 |
1138 res_close(prev); | 1180 res_close(prev); |
1139 } | 1181 } |
1140 array->u.fArray.fFirst = NULL; | 1182 array->u.fArray.fFirst = NULL; |
1141 } | 1183 } |
1142 | 1184 |
1143 static void string_close(struct SResource *string) { | 1185 static void string_close(struct SResource *string) { |
1144 if (string->u.fString.fChars != NULL && | 1186 if (string->u.fString.fChars != NULL && |
1145 string->u.fString.fChars != &gEmptyString && | 1187 string->u.fString.fChars != &gEmptyString) { |
1146 string->u.fString.fSame == NULL | |
1147 ) { | |
1148 uprv_free(string->u.fString.fChars); | 1188 uprv_free(string->u.fString.fChars); |
1149 string->u.fString.fChars =NULL; | 1189 string->u.fString.fChars =NULL; |
1150 } | 1190 } |
1151 } | 1191 } |
1152 | 1192 |
1153 static void alias_close(struct SResource *alias) { | 1193 static void alias_close(struct SResource *alias) { |
1154 if (alias->u.fString.fChars != NULL) { | 1194 if (alias->u.fString.fChars != NULL) { |
1155 uprv_free(alias->u.fString.fChars); | 1195 uprv_free(alias->u.fString.fChars); |
1156 alias->u.fString.fChars =NULL; | 1196 alias->u.fString.fChars =NULL; |
1157 } | 1197 } |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1211 ustr_deinit(&res->fComment); | 1251 ustr_deinit(&res->fComment); |
1212 uprv_free(res); | 1252 uprv_free(res); |
1213 } | 1253 } |
1214 } | 1254 } |
1215 | 1255 |
1216 void bundle_close(struct SRBRoot *bundle, UErrorCode *status) { | 1256 void bundle_close(struct SRBRoot *bundle, UErrorCode *status) { |
1217 res_close(bundle->fRoot); | 1257 res_close(bundle->fRoot); |
1218 uprv_free(bundle->fLocale); | 1258 uprv_free(bundle->fLocale); |
1219 uprv_free(bundle->fKeys); | 1259 uprv_free(bundle->fKeys); |
1220 uprv_free(bundle->fKeyMap); | 1260 uprv_free(bundle->fKeyMap); |
1221 uhash_close(bundle->fStringSet); | |
1222 uprv_free(bundle->f16BitUnits); | 1261 uprv_free(bundle->f16BitUnits); |
1223 uprv_free(bundle); | 1262 uprv_free(bundle); |
1224 } | 1263 } |
1225 | 1264 |
1226 void bundle_closeString(struct SRBRoot *bundle, struct SResource *string) { | |
1227 if (bundle->fStringSet != NULL) { | |
1228 uhash_remove(bundle->fStringSet, string); | |
1229 } | |
1230 string_close(string); | |
1231 } | |
1232 | |
1233 /* Adding Functions */ | 1265 /* Adding Functions */ |
1234 void table_add(struct SResource *table, struct SResource *res, int linenumber, U
ErrorCode *status) { | 1266 void table_add(struct SResource *table, struct SResource *res, int linenumber, U
ErrorCode *status) { |
1235 struct SResource *current = NULL; | 1267 struct SResource *current = NULL; |
1236 struct SResource *prev = NULL; | 1268 struct SResource *prev = NULL; |
1237 struct SResTable *list; | 1269 struct SResTable *list; |
1238 const char *resKeyString; | 1270 const char *resKeyString; |
1239 | 1271 |
1240 if (U_FAILURE(*status)) { | 1272 if (U_FAILURE(*status)) { |
1241 return; | 1273 return; |
1242 } | 1274 } |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1657 break; | 1689 break; |
1658 default: | 1690 default: |
1659 break; /* will not occur */ | 1691 break; /* will not occur */ |
1660 } | 1692 } |
1661 u_memcpy(bundle->f16BitUnits + utf16Length, res->u.fString.fChars, length +
1); | 1693 u_memcpy(bundle->f16BitUnits + utf16Length, res->u.fString.fChars, length +
1); |
1662 return utf16Length + length + 1; | 1694 return utf16Length + length + 1; |
1663 } | 1695 } |
1664 | 1696 |
1665 static void | 1697 static void |
1666 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status) { | 1698 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status) { |
| 1699 UHashtable *stringSet; |
| 1700 if (gFormatVersion > 1) { |
| 1701 stringSet = uhash_open(string_hash, string_comp, string_comp, status); |
| 1702 res_preflightStrings(bundle, bundle->fRoot, stringSet, status); |
| 1703 } else { |
| 1704 stringSet = NULL; |
| 1705 } |
1667 if (U_FAILURE(*status)) { | 1706 if (U_FAILURE(*status)) { |
| 1707 uhash_close(stringSet); |
1668 return; | 1708 return; |
1669 } | 1709 } |
1670 switch(bundle->fStringsForm) { | 1710 switch(bundle->fStringsForm) { |
1671 case STRINGS_UTF16_V2: | 1711 case STRINGS_UTF16_V2: |
1672 if (bundle->f16BitUnitsLength > 0) { | 1712 if (bundle->f16BitUnitsLength > 0) { |
1673 struct SResource **array; | 1713 struct SResource **array; |
1674 int32_t count = uhash_count(bundle->fStringSet); | 1714 int32_t count = uhash_count(stringSet); |
1675 int32_t i, pos; | 1715 int32_t i, pos; |
1676 /* | 1716 /* |
1677 * Allocate enough space for the initial NUL and the UTF-16 v2 strin
gs, | 1717 * Allocate enough space for the initial NUL and the UTF-16 v2 strin
gs, |
1678 * and some extra for URES_TABLE16 and URES_ARRAY16 values. | 1718 * and some extra for URES_TABLE16 and URES_ARRAY16 values. |
1679 * Round down to an even number. | 1719 * Round down to an even number. |
1680 */ | 1720 */ |
1681 int32_t utf16Length = (bundle->f16BitUnitsLength + 20000) & ~1; | 1721 int32_t utf16Length = (bundle->f16BitUnitsLength + 20000) & ~1; |
1682 bundle->f16BitUnits = (UChar *)uprv_malloc(utf16Length * U_SIZEOF_UC
HAR); | 1722 bundle->f16BitUnits = (UChar *)uprv_malloc(utf16Length * U_SIZEOF_UC
HAR); |
1683 array = (struct SResource **)uprv_malloc(count * sizeof(struct SReso
urce **)); | 1723 array = (struct SResource **)uprv_malloc(count * sizeof(struct SReso
urce **)); |
1684 if (bundle->f16BitUnits == NULL || array == NULL) { | 1724 if (bundle->f16BitUnits == NULL || array == NULL) { |
1685 uprv_free(bundle->f16BitUnits); | 1725 uprv_free(bundle->f16BitUnits); |
1686 bundle->f16BitUnits = NULL; | 1726 bundle->f16BitUnits = NULL; |
1687 uprv_free(array); | 1727 uprv_free(array); |
| 1728 uhash_close(stringSet); |
1688 *status = U_MEMORY_ALLOCATION_ERROR; | 1729 *status = U_MEMORY_ALLOCATION_ERROR; |
1689 return; | 1730 return; |
1690 } | 1731 } |
1691 bundle->f16BitUnitsCapacity = utf16Length; | 1732 bundle->f16BitUnitsCapacity = utf16Length; |
1692 /* insert the initial NUL */ | 1733 /* insert the initial NUL */ |
1693 bundle->f16BitUnits[0] = 0; | 1734 bundle->f16BitUnits[0] = 0; |
1694 utf16Length = 1; | 1735 utf16Length = 1; |
1695 ++bundle->f16BitUnitsLength; | 1736 ++bundle->f16BitUnitsLength; |
1696 for (pos = -1, i = 0; i < count; ++i) { | 1737 for (pos = -1, i = 0; i < count; ++i) { |
1697 array[i] = (struct SResource *)uhash_nextElement(bundle->fString
Set, &pos)->key.pointer; | 1738 array[i] = (struct SResource *)uhash_nextElement(stringSet, &pos
)->key.pointer; |
1698 } | 1739 } |
1699 /* Sort the strings so that each one is immediately followed by all
of its suffixes. */ | 1740 /* Sort the strings so that each one is immediately followed by all
of its suffixes. */ |
1700 uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **), | 1741 uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **), |
1701 compareStringSuffixes, NULL, FALSE, status); | 1742 compareStringSuffixes, NULL, FALSE, status); |
1702 /* | 1743 /* |
1703 * Make suffixes point into earlier, longer strings that contain the
m. | 1744 * Make suffixes point into earlier, longer strings that contain the
m. |
1704 * Temporarily use fSame and fSuffixOffset for suffix strings to | 1745 * Temporarily use fSame and fSuffixOffset for suffix strings to |
1705 * refer to the remaining ones. | 1746 * refer to the remaining ones. |
1706 */ | 1747 */ |
1707 if (U_SUCCESS(*status)) { | 1748 if (U_SUCCESS(*status)) { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1762 } | 1803 } |
1763 } | 1804 } |
1764 assert(utf16Length <= bundle->f16BitUnitsLength); | 1805 assert(utf16Length <= bundle->f16BitUnitsLength); |
1765 bundle->f16BitUnitsLength = utf16Length; | 1806 bundle->f16BitUnitsLength = utf16Length; |
1766 uprv_free(array); | 1807 uprv_free(array); |
1767 } | 1808 } |
1768 break; | 1809 break; |
1769 default: | 1810 default: |
1770 break; | 1811 break; |
1771 } | 1812 } |
| 1813 uhash_close(stringSet); |
1772 } | 1814 } |
OLD | NEW |