/src/ghostpdl/brotli/c/common/shared_dictionary.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2017 Google Inc. All Rights Reserved. |
2 | | |
3 | | Distributed under MIT license. |
4 | | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT |
5 | | */ |
6 | | |
7 | | /* Shared Dictionary definition and utilities. */ |
8 | | |
9 | | #include <brotli/shared_dictionary.h> |
10 | | |
11 | | #include <memory.h> |
12 | | #include <stdlib.h> /* malloc, free */ |
13 | | #include <stdio.h> |
14 | | |
15 | | #include "dictionary.h" |
16 | | #include "platform.h" |
17 | | #include "shared_dictionary_internal.h" |
18 | | |
19 | | #if defined(__cplusplus) || defined(c_plusplus) |
20 | | extern "C" { |
21 | | #endif |
22 | | |
23 | 0 | #define BROTLI_NUM_ENCODED_LENGTHS (SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH \ |
24 | 0 | - SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH + 1) |
25 | | |
26 | | /* Max allowed by spec */ |
27 | 0 | #define BROTLI_MAX_SIZE_BITS 15u |
28 | | |
29 | | /* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ |
30 | | static BROTLI_BOOL ReadBool(const uint8_t* encoded, size_t size, size_t* pos, |
31 | 0 | BROTLI_BOOL* result) { |
32 | 0 | uint8_t value; |
33 | 0 | size_t position = *pos; |
34 | 0 | if (position >= size) return BROTLI_FALSE; /* past file end */ |
35 | 0 | value = encoded[position++]; |
36 | 0 | if (value > 1) return BROTLI_FALSE; /* invalid bool */ |
37 | 0 | *result = TO_BROTLI_BOOL(value); |
38 | 0 | *pos = position; |
39 | 0 | return BROTLI_TRUE; /* success */ |
40 | 0 | } |
41 | | |
42 | | /* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ |
43 | | static BROTLI_BOOL ReadUint8(const uint8_t* encoded, size_t size, size_t* pos, |
44 | 0 | uint8_t* result) { |
45 | 0 | size_t position = *pos; |
46 | 0 | if (position + sizeof(uint8_t) > size) return BROTLI_FALSE; |
47 | 0 | *result = encoded[position++]; |
48 | 0 | *pos = position; |
49 | 0 | return BROTLI_TRUE; |
50 | 0 | } |
51 | | |
52 | | /* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ |
53 | | static BROTLI_BOOL ReadUint16(const uint8_t* encoded, size_t size, size_t* pos, |
54 | 0 | uint16_t* result) { |
55 | 0 | size_t position = *pos; |
56 | 0 | if (position + sizeof(uint16_t) > size) return BROTLI_FALSE; |
57 | 0 | *result = BROTLI_UNALIGNED_LOAD16LE(&encoded[position]); |
58 | 0 | position += 2; |
59 | 0 | *pos = position; |
60 | 0 | return BROTLI_TRUE; |
61 | 0 | } |
62 | | |
63 | | /* Reads a varint into a uint32_t, and returns error if it's too large */ |
64 | | /* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ |
65 | | static BROTLI_BOOL ReadVarint32(const uint8_t* encoded, size_t size, |
66 | 0 | size_t* pos, uint32_t* result) { |
67 | 0 | int num = 0; |
68 | 0 | uint8_t byte; |
69 | 0 | *result = 0; |
70 | 0 | for (;;) { |
71 | 0 | if (*pos >= size) return BROTLI_FALSE; |
72 | 0 | byte = encoded[(*pos)++]; |
73 | 0 | if (num == 4 && byte > 15) return BROTLI_FALSE; |
74 | 0 | *result |= (uint32_t)(byte & 127) << (num * 7); |
75 | 0 | if (byte < 128) return BROTLI_TRUE; |
76 | 0 | num++; |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | | /* Returns the total length of word list. */ |
81 | | static size_t BrotliSizeBitsToOffsets(const uint8_t* size_bits_by_length, |
82 | 0 | uint32_t* offsets_by_length) { |
83 | 0 | uint32_t pos = 0; |
84 | 0 | uint32_t i; |
85 | 0 | for (i = 0; i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) { |
86 | 0 | offsets_by_length[i] = pos; |
87 | 0 | if (size_bits_by_length[i] != 0) { |
88 | 0 | pos += i << size_bits_by_length[i]; |
89 | 0 | } |
90 | 0 | } |
91 | 0 | return pos; |
92 | 0 | } |
93 | | |
94 | | static BROTLI_BOOL ParseWordList(size_t size, const uint8_t* encoded, |
95 | 0 | size_t* pos, BrotliDictionary* out) { |
96 | 0 | size_t offset; |
97 | 0 | size_t i; |
98 | 0 | size_t position = *pos; |
99 | 0 | if (position + BROTLI_NUM_ENCODED_LENGTHS > size) { |
100 | 0 | return BROTLI_FALSE; |
101 | 0 | } |
102 | | |
103 | 0 | memset(out->size_bits_by_length, 0, SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH); |
104 | 0 | memcpy(out->size_bits_by_length + SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH, |
105 | 0 | &encoded[position], BROTLI_NUM_ENCODED_LENGTHS); |
106 | 0 | for (i = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH; |
107 | 0 | i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) { |
108 | 0 | if (out->size_bits_by_length[i] > BROTLI_MAX_SIZE_BITS) { |
109 | 0 | return BROTLI_FALSE; |
110 | 0 | } |
111 | 0 | } |
112 | 0 | position += BROTLI_NUM_ENCODED_LENGTHS; |
113 | 0 | offset = BrotliSizeBitsToOffsets( |
114 | 0 | out->size_bits_by_length, out->offsets_by_length); |
115 | |
|
116 | 0 | out->data = &encoded[position]; |
117 | 0 | out->data_size = offset; |
118 | 0 | position += offset; |
119 | 0 | if (position > size) return BROTLI_FALSE; |
120 | 0 | *pos = position; |
121 | 0 | return BROTLI_TRUE; |
122 | 0 | } |
123 | | |
124 | | /* Computes the cutOffTransforms of a BrotliTransforms which already has the |
125 | | transforms data correctly filled in. */ |
126 | 0 | static void ComputeCutoffTransforms(BrotliTransforms* transforms) { |
127 | 0 | uint32_t i; |
128 | 0 | for (i = 0; i < BROTLI_TRANSFORMS_MAX_CUT_OFF + 1; i++) { |
129 | 0 | transforms->cutOffTransforms[i] = -1; |
130 | 0 | } |
131 | 0 | for (i = 0; i < transforms->num_transforms; i++) { |
132 | 0 | const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, i); |
133 | 0 | uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, i); |
134 | 0 | const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, i); |
135 | 0 | if (type <= BROTLI_TRANSFORM_OMIT_LAST_9 && *prefix == 0 && *suffix == 0 && |
136 | 0 | transforms->cutOffTransforms[type] == -1) { |
137 | 0 | transforms->cutOffTransforms[type] = (int16_t)i; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | | static BROTLI_BOOL ParsePrefixSuffixTable(size_t size, const uint8_t* encoded, |
143 | | size_t* pos, BrotliTransforms* out, uint16_t* out_table, |
144 | 0 | size_t* out_table_size) { |
145 | 0 | size_t position = *pos; |
146 | 0 | size_t offset = 0; |
147 | 0 | size_t stringlet_count = 0; /* NUM_PREFIX_SUFFIX */ |
148 | 0 | size_t data_length = 0; |
149 | | |
150 | | /* PREFIX_SUFFIX_LENGTH */ |
151 | 0 | if (!ReadUint16(encoded, size, &position, &out->prefix_suffix_size)) { |
152 | 0 | return BROTLI_FALSE; |
153 | 0 | } |
154 | 0 | data_length = out->prefix_suffix_size; |
155 | | |
156 | | /* Must at least have space for null terminator. */ |
157 | 0 | if (data_length < 1) return BROTLI_FALSE; |
158 | 0 | out->prefix_suffix = &encoded[position]; |
159 | 0 | if (position + data_length >= size) return BROTLI_FALSE; |
160 | 0 | while (BROTLI_TRUE) { |
161 | | /* STRING_LENGTH */ |
162 | 0 | size_t stringlet_len = encoded[position + offset]; |
163 | 0 | out_table[stringlet_count] = (uint16_t)offset; |
164 | 0 | stringlet_count++; |
165 | 0 | offset++; |
166 | 0 | if (stringlet_len == 0) { |
167 | 0 | if (offset == data_length) { |
168 | 0 | break; |
169 | 0 | } else { |
170 | 0 | return BROTLI_FALSE; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | if (stringlet_count > 255) return BROTLI_FALSE; |
174 | 0 | offset += stringlet_len; |
175 | 0 | if (offset >= data_length) return BROTLI_FALSE; |
176 | 0 | } |
177 | | |
178 | 0 | position += data_length; |
179 | 0 | *pos = position; |
180 | 0 | *out_table_size = (uint16_t)stringlet_count; |
181 | 0 | return BROTLI_TRUE; |
182 | 0 | } |
183 | | |
184 | | static BROTLI_BOOL ParseTransformsList(size_t size, const uint8_t* encoded, |
185 | | size_t* pos, BrotliTransforms* out, uint16_t* prefix_suffix_table, |
186 | 0 | size_t* prefix_suffix_count) { |
187 | 0 | uint32_t i; |
188 | 0 | BROTLI_BOOL has_params = BROTLI_FALSE; |
189 | 0 | BROTLI_BOOL prefix_suffix_ok = BROTLI_FALSE; |
190 | 0 | size_t position = *pos; |
191 | 0 | size_t stringlet_cnt = 0; |
192 | 0 | if (position >= size) return BROTLI_FALSE; |
193 | | |
194 | 0 | prefix_suffix_ok = ParsePrefixSuffixTable( |
195 | 0 | size, encoded, &position, out, prefix_suffix_table, &stringlet_cnt); |
196 | 0 | if (!prefix_suffix_ok) return BROTLI_FALSE; |
197 | 0 | out->prefix_suffix_map = prefix_suffix_table; |
198 | 0 | *prefix_suffix_count = stringlet_cnt; |
199 | |
|
200 | 0 | out->num_transforms = encoded[position++]; |
201 | 0 | out->transforms = &encoded[position]; |
202 | 0 | position += (size_t)out->num_transforms * 3; |
203 | 0 | if (position > size) return BROTLI_FALSE; |
204 | | /* Check for errors and read extra parameters. */ |
205 | 0 | for (i = 0; i < out->num_transforms; i++) { |
206 | 0 | uint8_t prefix_id = BROTLI_TRANSFORM_PREFIX_ID(out, i); |
207 | 0 | uint8_t type = BROTLI_TRANSFORM_TYPE(out, i); |
208 | 0 | uint8_t suffix_id = BROTLI_TRANSFORM_SUFFIX_ID(out, i); |
209 | 0 | if (prefix_id >= stringlet_cnt) return BROTLI_FALSE; |
210 | 0 | if (type >= BROTLI_NUM_TRANSFORM_TYPES) return BROTLI_FALSE; |
211 | 0 | if (suffix_id >= stringlet_cnt) return BROTLI_FALSE; |
212 | 0 | if (type == BROTLI_TRANSFORM_SHIFT_FIRST || |
213 | 0 | type == BROTLI_TRANSFORM_SHIFT_ALL) { |
214 | 0 | has_params = BROTLI_TRUE; |
215 | 0 | } |
216 | 0 | } |
217 | 0 | if (has_params) { |
218 | 0 | out->params = &encoded[position]; |
219 | 0 | position += (size_t)out->num_transforms * 2; |
220 | 0 | if (position > size) return BROTLI_FALSE; |
221 | 0 | for (i = 0; i < out->num_transforms; i++) { |
222 | 0 | uint8_t type = BROTLI_TRANSFORM_TYPE(out, i); |
223 | 0 | if (type != BROTLI_TRANSFORM_SHIFT_FIRST && |
224 | 0 | type != BROTLI_TRANSFORM_SHIFT_ALL) { |
225 | 0 | if (out->params[i * 2] != 0 || out->params[i * 2 + 1] != 0) { |
226 | 0 | return BROTLI_FALSE; |
227 | 0 | } |
228 | 0 | } |
229 | 0 | } |
230 | 0 | } else { |
231 | 0 | out->params = NULL; |
232 | 0 | } |
233 | 0 | ComputeCutoffTransforms(out); |
234 | 0 | *pos = position; |
235 | 0 | return BROTLI_TRUE; |
236 | 0 | } |
237 | | |
238 | | static BROTLI_BOOL DryParseDictionary(const uint8_t* encoded, |
239 | 0 | size_t size, uint32_t* num_prefix, BROTLI_BOOL* is_custom_static_dict) { |
240 | 0 | size_t pos = 0; |
241 | 0 | uint32_t chunk_size = 0; |
242 | 0 | uint8_t num_word_lists; |
243 | 0 | uint8_t num_transform_lists; |
244 | 0 | *is_custom_static_dict = BROTLI_FALSE; |
245 | 0 | *num_prefix = 0; |
246 | | |
247 | | /* Skip magic header bytes. */ |
248 | 0 | pos += 2; |
249 | | |
250 | | /* LZ77_DICTIONARY_LENGTH */ |
251 | 0 | if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE; |
252 | 0 | if (chunk_size != 0) { |
253 | | /* This limitation is not specified but the 32-bit Brotli decoder for now */ |
254 | 0 | if (chunk_size > 1073741823) return BROTLI_FALSE; |
255 | 0 | *num_prefix = 1; |
256 | 0 | if (pos + chunk_size > size) return BROTLI_FALSE; |
257 | 0 | pos += chunk_size; |
258 | 0 | } |
259 | | |
260 | 0 | if (!ReadUint8(encoded, size, &pos, &num_word_lists)) { |
261 | 0 | return BROTLI_FALSE; |
262 | 0 | } |
263 | 0 | if (!ReadUint8(encoded, size, &pos, &num_transform_lists)) { |
264 | 0 | return BROTLI_FALSE; |
265 | 0 | } |
266 | | |
267 | 0 | if (num_word_lists > 0 || num_transform_lists > 0) { |
268 | 0 | *is_custom_static_dict = BROTLI_TRUE; |
269 | 0 | } |
270 | |
|
271 | 0 | return BROTLI_TRUE; |
272 | 0 | } |
273 | | |
274 | | static BROTLI_BOOL ParseDictionary(const uint8_t* encoded, size_t size, |
275 | 0 | BrotliSharedDictionary* dict) { |
276 | 0 | uint32_t i; |
277 | 0 | size_t pos = 0; |
278 | 0 | uint32_t chunk_size = 0; |
279 | 0 | size_t total_prefix_suffix_count = 0; |
280 | 0 | size_t trasform_list_start[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS]; |
281 | 0 | uint16_t temporary_prefix_suffix_table[256]; |
282 | | |
283 | | /* Skip magic header bytes. */ |
284 | 0 | pos += 2; |
285 | | |
286 | | /* LZ77_DICTIONARY_LENGTH */ |
287 | 0 | if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE; |
288 | 0 | if (chunk_size != 0) { |
289 | 0 | if (pos + chunk_size > size) return BROTLI_FALSE; |
290 | 0 | dict->prefix_size[dict->num_prefix] = chunk_size; |
291 | 0 | dict->prefix[dict->num_prefix] = &encoded[pos]; |
292 | 0 | dict->num_prefix++; |
293 | | /* LZ77_DICTIONARY_LENGTH bytes. */ |
294 | 0 | pos += chunk_size; |
295 | 0 | } |
296 | | |
297 | | /* NUM_WORD_LISTS */ |
298 | 0 | if (!ReadUint8(encoded, size, &pos, &dict->num_word_lists)) { |
299 | 0 | return BROTLI_FALSE; |
300 | 0 | } |
301 | 0 | if (dict->num_word_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) { |
302 | 0 | return BROTLI_FALSE; |
303 | 0 | } |
304 | | |
305 | 0 | if (dict->num_word_lists != 0) { |
306 | 0 | dict->words_instances = (BrotliDictionary*)dict->alloc_func( |
307 | 0 | dict->memory_manager_opaque, |
308 | 0 | dict->num_word_lists * sizeof(*dict->words_instances)); |
309 | 0 | if (!dict->words_instances) return BROTLI_FALSE; /* OOM */ |
310 | 0 | } |
311 | 0 | for (i = 0; i < dict->num_word_lists; i++) { |
312 | 0 | if (!ParseWordList(size, encoded, &pos, &dict->words_instances[i])) { |
313 | 0 | return BROTLI_FALSE; |
314 | 0 | } |
315 | 0 | } |
316 | | |
317 | | /* NUM_TRANSFORM_LISTS */ |
318 | 0 | if (!ReadUint8(encoded, size, &pos, &dict->num_transform_lists)) { |
319 | 0 | return BROTLI_FALSE; |
320 | 0 | } |
321 | 0 | if (dict->num_transform_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) { |
322 | 0 | return BROTLI_FALSE; |
323 | 0 | } |
324 | | |
325 | 0 | if (dict->num_transform_lists != 0) { |
326 | 0 | dict->transforms_instances = (BrotliTransforms*)dict->alloc_func( |
327 | 0 | dict->memory_manager_opaque, |
328 | 0 | dict->num_transform_lists * sizeof(*dict->transforms_instances)); |
329 | 0 | if (!dict->transforms_instances) return BROTLI_FALSE; /* OOM */ |
330 | 0 | } |
331 | 0 | for (i = 0; i < dict->num_transform_lists; i++) { |
332 | 0 | BROTLI_BOOL ok = BROTLI_FALSE; |
333 | 0 | size_t prefix_suffix_count = 0; |
334 | 0 | trasform_list_start[i] = pos; |
335 | 0 | dict->transforms_instances[i].prefix_suffix_map = |
336 | 0 | temporary_prefix_suffix_table; |
337 | 0 | ok = ParseTransformsList( |
338 | 0 | size, encoded, &pos, &dict->transforms_instances[i], |
339 | 0 | temporary_prefix_suffix_table, &prefix_suffix_count); |
340 | 0 | if (!ok) return BROTLI_FALSE; |
341 | 0 | total_prefix_suffix_count += prefix_suffix_count; |
342 | 0 | } |
343 | 0 | if (total_prefix_suffix_count != 0) { |
344 | 0 | dict->prefix_suffix_maps = (uint16_t*)dict->alloc_func( |
345 | 0 | dict->memory_manager_opaque, |
346 | 0 | total_prefix_suffix_count * sizeof(*dict->prefix_suffix_maps)); |
347 | 0 | if (!dict->prefix_suffix_maps) return BROTLI_FALSE; /* OOM */ |
348 | 0 | } |
349 | 0 | total_prefix_suffix_count = 0; |
350 | 0 | for (i = 0; i < dict->num_transform_lists; i++) { |
351 | 0 | size_t prefix_suffix_count = 0; |
352 | 0 | size_t position = trasform_list_start[i]; |
353 | 0 | uint16_t* prefix_suffix_map = |
354 | 0 | &dict->prefix_suffix_maps[total_prefix_suffix_count]; |
355 | 0 | BROTLI_BOOL ok = ParsePrefixSuffixTable( |
356 | 0 | size, encoded, &position, &dict->transforms_instances[i], |
357 | 0 | prefix_suffix_map, &prefix_suffix_count); |
358 | 0 | if (!ok) return BROTLI_FALSE; |
359 | 0 | dict->transforms_instances[i].prefix_suffix_map = prefix_suffix_map; |
360 | 0 | total_prefix_suffix_count += prefix_suffix_count; |
361 | 0 | } |
362 | | |
363 | 0 | if (dict->num_word_lists != 0 || dict->num_transform_lists != 0) { |
364 | 0 | if (!ReadUint8(encoded, size, &pos, &dict->num_dictionaries)) { |
365 | 0 | return BROTLI_FALSE; |
366 | 0 | } |
367 | 0 | if (dict->num_dictionaries == 0 || |
368 | 0 | dict->num_dictionaries > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) { |
369 | 0 | return BROTLI_FALSE; |
370 | 0 | } |
371 | 0 | for (i = 0; i < dict->num_dictionaries; i++) { |
372 | 0 | uint8_t words_index; |
373 | 0 | uint8_t transforms_index; |
374 | 0 | if (!ReadUint8(encoded, size, &pos, &words_index)) { |
375 | 0 | return BROTLI_FALSE; |
376 | 0 | } |
377 | 0 | if (words_index > dict->num_word_lists) return BROTLI_FALSE; |
378 | 0 | if (!ReadUint8(encoded, size, &pos, &transforms_index)) { |
379 | 0 | return BROTLI_FALSE; |
380 | 0 | } |
381 | 0 | if (transforms_index > dict->num_transform_lists) return BROTLI_FALSE; |
382 | 0 | dict->words[i] = words_index == dict->num_word_lists ? |
383 | 0 | BrotliGetDictionary() : &dict->words_instances[words_index]; |
384 | 0 | dict->transforms[i] = transforms_index == dict->num_transform_lists ? |
385 | 0 | BrotliGetTransforms(): &dict->transforms_instances[transforms_index]; |
386 | 0 | } |
387 | | /* CONTEXT_ENABLED */ |
388 | 0 | if (!ReadBool(encoded, size, &pos, &dict->context_based)) { |
389 | 0 | return BROTLI_FALSE; |
390 | 0 | } |
391 | | |
392 | | /* CONTEXT_MAP */ |
393 | 0 | if (dict->context_based) { |
394 | 0 | for (i = 0; i < SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS; i++) { |
395 | 0 | if (!ReadUint8(encoded, size, &pos, &dict->context_map[i])) { |
396 | 0 | return BROTLI_FALSE; |
397 | 0 | } |
398 | 0 | if (dict->context_map[i] >= dict->num_dictionaries) { |
399 | 0 | return BROTLI_FALSE; |
400 | 0 | } |
401 | 0 | } |
402 | 0 | } |
403 | 0 | } else { |
404 | 0 | dict->context_based = BROTLI_FALSE; |
405 | 0 | dict->num_dictionaries = 1; |
406 | 0 | dict->words[0] = BrotliGetDictionary(); |
407 | 0 | dict->transforms[0] = BrotliGetTransforms(); |
408 | 0 | } |
409 | | |
410 | 0 | return BROTLI_TRUE; |
411 | 0 | } |
412 | | |
413 | | /* Decodes shared dictionary and verifies correctness. |
414 | | Returns BROTLI_TRUE if dictionary is valid, BROTLI_FALSE otherwise. |
415 | | The BrotliSharedDictionary must already have been initialized. If the |
416 | | BrotliSharedDictionary already contains data, compound dictionaries |
417 | | will be appended, but an error will be returned if it already has |
418 | | custom words or transforms. |
419 | | TODO(lode): link to RFC for shared brotli once published. */ |
420 | | static BROTLI_BOOL DecodeSharedDictionary( |
421 | 0 | const uint8_t* encoded, size_t size, BrotliSharedDictionary* dict) { |
422 | 0 | uint32_t num_prefix = 0; |
423 | 0 | BROTLI_BOOL is_custom_static_dict = BROTLI_FALSE; |
424 | 0 | BROTLI_BOOL has_custom_static_dict = |
425 | 0 | dict->num_word_lists > 0 || dict->num_transform_lists > 0; |
426 | | |
427 | | /* Check magic header bytes. */ |
428 | 0 | if (size < 2) return BROTLI_FALSE; |
429 | 0 | if (encoded[0] != 0x91 || encoded[1] != 0) return BROTLI_FALSE; |
430 | | |
431 | 0 | if (!DryParseDictionary(encoded, size, &num_prefix, &is_custom_static_dict)) { |
432 | 0 | return BROTLI_FALSE; |
433 | 0 | } |
434 | | |
435 | 0 | if (num_prefix + dict->num_prefix > SHARED_BROTLI_MAX_COMPOUND_DICTS) { |
436 | 0 | return BROTLI_FALSE; |
437 | 0 | } |
438 | | |
439 | | /* Cannot combine different static dictionaries, only prefix dictionaries */ |
440 | 0 | if (has_custom_static_dict && is_custom_static_dict) return BROTLI_FALSE; |
441 | | |
442 | 0 | return ParseDictionary(encoded, size, dict); |
443 | 0 | } |
444 | | |
445 | | void BrotliSharedDictionaryDestroyInstance( |
446 | 0 | BrotliSharedDictionary* dict) { |
447 | 0 | if (!dict) { |
448 | 0 | return; |
449 | 0 | } else { |
450 | 0 | brotli_free_func free_func = dict->free_func; |
451 | 0 | void* opaque = dict->memory_manager_opaque; |
452 | | /* Cleanup. */ |
453 | 0 | free_func(opaque, dict->words_instances); |
454 | 0 | free_func(opaque, dict->transforms_instances); |
455 | 0 | free_func(opaque, dict->prefix_suffix_maps); |
456 | | /* Self-destruction. */ |
457 | 0 | free_func(opaque, dict); |
458 | 0 | } |
459 | 0 | } |
460 | | |
461 | | BROTLI_BOOL BrotliSharedDictionaryAttach( |
462 | | BrotliSharedDictionary* dict, BrotliSharedDictionaryType type, |
463 | 0 | size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]) { |
464 | 0 | if (!dict) { |
465 | 0 | return BROTLI_FALSE; |
466 | 0 | } |
467 | 0 | if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) { |
468 | 0 | return DecodeSharedDictionary(data, data_size, dict); |
469 | 0 | } else if (type == BROTLI_SHARED_DICTIONARY_RAW) { |
470 | 0 | if (dict->num_prefix >= SHARED_BROTLI_MAX_COMPOUND_DICTS) { |
471 | 0 | return BROTLI_FALSE; |
472 | 0 | } |
473 | 0 | dict->prefix_size[dict->num_prefix] = data_size; |
474 | 0 | dict->prefix[dict->num_prefix] = data; |
475 | 0 | dict->num_prefix++; |
476 | 0 | return BROTLI_TRUE; |
477 | 0 | } else { |
478 | 0 | return BROTLI_FALSE; |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | BrotliSharedDictionary* BrotliSharedDictionaryCreateInstance( |
483 | 0 | brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { |
484 | 0 | BrotliSharedDictionary* dict = 0; |
485 | 0 | if (!alloc_func && !free_func) { |
486 | 0 | dict = (BrotliSharedDictionary*)malloc(sizeof(BrotliSharedDictionary)); |
487 | 0 | } else if (alloc_func && free_func) { |
488 | 0 | dict = (BrotliSharedDictionary*)alloc_func( |
489 | 0 | opaque, sizeof(BrotliSharedDictionary)); |
490 | 0 | } |
491 | 0 | if (dict == 0) { |
492 | 0 | return 0; |
493 | 0 | } |
494 | | |
495 | | /* TODO(eustas): explicitly initialize all the fields? */ |
496 | 0 | memset(dict, 0, sizeof(BrotliSharedDictionary)); |
497 | |
|
498 | 0 | dict->context_based = BROTLI_FALSE; |
499 | 0 | dict->num_dictionaries = 1; |
500 | 0 | dict->num_word_lists = 0; |
501 | 0 | dict->num_transform_lists = 0; |
502 | |
|
503 | 0 | dict->words[0] = BrotliGetDictionary(); |
504 | 0 | dict->transforms[0] = BrotliGetTransforms(); |
505 | |
|
506 | 0 | dict->alloc_func = alloc_func ? alloc_func : BrotliDefaultAllocFunc; |
507 | 0 | dict->free_func = free_func ? free_func : BrotliDefaultFreeFunc; |
508 | 0 | dict->memory_manager_opaque = opaque; |
509 | |
|
510 | 0 | return dict; |
511 | 0 | } |
512 | | |
513 | | #if defined(__cplusplus) || defined(c_plusplus) |
514 | | } /* extern "C" */ |
515 | | #endif |