/src/libzip/lib/zip_extra_field.c
Line | Count | Source |
1 | | /* |
2 | | zip_extra_field.c -- manipulate extra fields |
3 | | Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner |
4 | | |
5 | | This file is part of libzip, a library to manipulate ZIP archives. |
6 | | The authors can be contacted at <info@libzip.org> |
7 | | |
8 | | Redistribution and use in source and binary forms, with or without |
9 | | modification, are permitted provided that the following conditions |
10 | | are met: |
11 | | 1. Redistributions of source code must retain the above copyright |
12 | | notice, this list of conditions and the following disclaimer. |
13 | | 2. Redistributions in binary form must reproduce the above copyright |
14 | | notice, this list of conditions and the following disclaimer in |
15 | | the documentation and/or other materials provided with the |
16 | | distribution. |
17 | | 3. The names of the authors may not be used to endorse or promote |
18 | | products derived from this software without specific prior |
19 | | written permission. |
20 | | |
21 | | THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS |
22 | | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
23 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
25 | | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
27 | | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
29 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
30 | | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
31 | | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | | */ |
33 | | |
34 | | #include <stdlib.h> |
35 | | #include <string.h> |
36 | | |
37 | | #include "zipint.h" |
38 | | |
39 | | |
40 | 0 | zip_extra_field_t *_zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error) { |
41 | 0 | zip_extra_field_t *head, *prev, *def; |
42 | |
|
43 | 0 | head = prev = NULL; |
44 | |
|
45 | 0 | while (ef) { |
46 | 0 | if ((def = _zip_ef_new(ef->id, ef->size, ef->data)) == NULL) { |
47 | 0 | zip_error_set(error, ZIP_ER_MEMORY, 0); |
48 | 0 | _zip_ef_free(head); |
49 | 0 | return NULL; |
50 | 0 | } |
51 | | |
52 | 0 | if (head == NULL) { |
53 | 0 | head = def; |
54 | 0 | } |
55 | 0 | if (prev) { |
56 | 0 | prev->next = def; |
57 | 0 | } |
58 | 0 | prev = def; |
59 | |
|
60 | 0 | ef = ef->next; |
61 | 0 | } |
62 | | |
63 | 0 | return head; |
64 | 0 | } |
65 | | |
66 | | |
67 | 0 | zip_extra_field_t *_zip_ef_delete_by_id(zip_extra_field_t *ef, zip_uint16_t id, zip_uint16_t id_idx) { |
68 | 0 | zip_extra_field_t *head, *prev; |
69 | 0 | int i; |
70 | |
|
71 | 0 | i = 0; |
72 | 0 | head = ef; |
73 | 0 | prev = NULL; |
74 | 0 | for (; ef; ef = (prev ? prev->next : head)) { |
75 | 0 | if ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL)) { |
76 | 0 | if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) { |
77 | 0 | if (prev) { |
78 | 0 | prev->next = ef->next; |
79 | 0 | } |
80 | 0 | else { |
81 | 0 | head = ef->next; |
82 | 0 | } |
83 | 0 | ef->next = NULL; |
84 | 0 | _zip_ef_free(ef); |
85 | |
|
86 | 0 | if (id_idx == ZIP_EXTRA_FIELD_ALL) { |
87 | 0 | continue; |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | 0 | i++; |
92 | 0 | if (i > id_idx) { |
93 | 0 | break; |
94 | 0 | } |
95 | 0 | } |
96 | 0 | prev = ef; |
97 | 0 | } |
98 | |
|
99 | 0 | return head; |
100 | 0 | } |
101 | | |
102 | | |
103 | 63.0k | void _zip_ef_free(zip_extra_field_t *ef) { |
104 | 63.0k | zip_extra_field_t *ef2; |
105 | | |
106 | 68.0k | while (ef) { |
107 | 4.96k | ef2 = ef->next; |
108 | 4.96k | free(ef->data); |
109 | 4.96k | free(ef); |
110 | 4.96k | ef = ef2; |
111 | 4.96k | } |
112 | 63.0k | } |
113 | | |
114 | 122k | zip_extra_field_t *_zip_ef_find(zip_extra_field_t *ef_head, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_extra_field_t **prev) { |
115 | 122k | zip_extra_field_t *ef; |
116 | 122k | zip_uint16_t i; |
117 | | |
118 | 122k | i = 0; |
119 | 131k | for (ef = ef_head; ef; ef = ef->next) { |
120 | 9.07k | if (ef->id == ef_id) { |
121 | 244 | if (i == ef_idx) { |
122 | 244 | return ef; |
123 | 244 | } |
124 | 0 | i++; |
125 | 0 | } |
126 | 8.83k | if (prev) { |
127 | 0 | *prev = ef; |
128 | 0 | } |
129 | 8.83k | } |
130 | | |
131 | 122k | return NULL; |
132 | 122k | } |
133 | | |
134 | | |
135 | 122k | const zip_uint8_t *_zip_ef_get_by_id(const zip_extra_field_t *ef_head, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags) { |
136 | 122k | static const zip_uint8_t empty[1] = {'\0'}; |
137 | | |
138 | 122k | zip_extra_field_t *ef = _zip_ef_find((zip_extra_field_t *)ef_head, id, id_idx, NULL); |
139 | | |
140 | 122k | if (ef) { |
141 | 244 | if (lenp) { |
142 | 244 | *lenp = ef->size; |
143 | 244 | } |
144 | 244 | if (ef->size > 0) { |
145 | 175 | return ef->data; |
146 | 175 | } |
147 | 69 | else { |
148 | 69 | return empty; |
149 | 69 | } |
150 | 244 | } |
151 | | |
152 | 122k | return NULL; |
153 | 122k | } |
154 | | |
155 | 4.96k | zip_extra_field_t *_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data) { |
156 | 4.96k | zip_extra_field_t *ef; |
157 | | |
158 | 4.96k | if ((ef = (zip_extra_field_t *)malloc(sizeof(*ef))) == NULL) { |
159 | 0 | return NULL; |
160 | 0 | } |
161 | | |
162 | 4.96k | ef->next = NULL; |
163 | 4.96k | ef->id = id; |
164 | 4.96k | ef->size = size; |
165 | 4.96k | if (size > 0) { |
166 | 2.89k | if ((ef->data = (zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) { |
167 | 0 | free(ef); |
168 | 0 | return NULL; |
169 | 0 | } |
170 | 2.89k | } |
171 | 2.06k | else { |
172 | 2.06k | ef->data = NULL; |
173 | 2.06k | } |
174 | | |
175 | 4.96k | return ef; |
176 | 4.96k | } |
177 | | |
178 | | |
179 | 1.83k | bool _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_extra_field_t **ef_head_p, zip_error_t *error) { |
180 | 1.83k | zip_buffer_t *buffer; |
181 | 1.83k | zip_extra_field_t *ef, *ef2, *ef_head; |
182 | | |
183 | 1.83k | if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) { |
184 | 0 | zip_error_set(error, ZIP_ER_MEMORY, 0); |
185 | 0 | return false; |
186 | 0 | } |
187 | | |
188 | 1.83k | ef_head = ef = NULL; |
189 | | |
190 | 6.80k | while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) { |
191 | 5.10k | zip_uint16_t fid, flen; |
192 | 5.10k | zip_uint8_t *ef_data; |
193 | | |
194 | 5.10k | fid = _zip_buffer_get_16(buffer); |
195 | 5.10k | flen = _zip_buffer_get_16(buffer); |
196 | 5.10k | ef_data = _zip_buffer_get(buffer, flen); |
197 | | |
198 | 5.10k | if (ef_data == NULL) { |
199 | 140 | zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_EF_LENGTH); |
200 | 140 | _zip_buffer_free(buffer); |
201 | 140 | _zip_ef_free(ef_head); |
202 | 140 | return false; |
203 | 140 | } |
204 | | |
205 | 4.96k | if ((ef2 = _zip_ef_new(fid, flen, ef_data)) == NULL) { |
206 | 0 | zip_error_set(error, ZIP_ER_MEMORY, 0); |
207 | 0 | _zip_buffer_free(buffer); |
208 | 0 | _zip_ef_free(ef_head); |
209 | 0 | return false; |
210 | 0 | } |
211 | | |
212 | 4.96k | if (ef_head) { |
213 | 3.24k | ef->next = ef2; |
214 | 3.24k | ef = ef2; |
215 | 3.24k | } |
216 | 1.72k | else { |
217 | 1.72k | ef_head = ef = ef2; |
218 | 1.72k | } |
219 | 4.96k | } |
220 | | |
221 | 1.69k | if (!_zip_buffer_eof(buffer)) { |
222 | | /* Android APK files align stored file data with padding in extra fields; ignore. */ |
223 | | /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */ |
224 | | /* buffer is at most 64k long, so this can't overflow. */ |
225 | 361 | size_t glen = _zip_buffer_left(buffer); |
226 | 361 | zip_uint8_t *garbage; |
227 | 361 | garbage = _zip_buffer_get(buffer, glen); |
228 | 361 | if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", (size_t)glen) != 0) { |
229 | 71 | zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EF_TRAILING_GARBAGE); |
230 | 71 | _zip_buffer_free(buffer); |
231 | 71 | _zip_ef_free(ef_head); |
232 | 71 | return false; |
233 | 71 | } |
234 | 361 | } |
235 | | |
236 | 1.62k | _zip_buffer_free(buffer); |
237 | | |
238 | 1.62k | if (ef_head_p) { |
239 | 1.62k | *ef_head_p = ef_head; |
240 | 1.62k | } |
241 | 0 | else { |
242 | 0 | _zip_ef_free(ef_head); |
243 | 0 | } |
244 | | |
245 | 1.62k | return true; |
246 | 1.69k | } |
247 | | |
248 | | |
249 | 30.3k | zip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *ef) { |
250 | 30.3k | zip_extra_field_t *ef_head; |
251 | 30.3k | zip_extra_field_t *prev, *next; |
252 | | |
253 | 30.3k | ef_head = ef; |
254 | 30.3k | prev = NULL; |
255 | | |
256 | 33.8k | while (ef) { |
257 | 3.53k | if (ZIP_EF_IS_INTERNAL(ef->id)) { |
258 | 113 | next = ef->next; |
259 | 113 | if (ef_head == ef) { |
260 | 36 | ef_head = next; |
261 | 36 | } |
262 | 113 | ef->next = NULL; |
263 | 113 | _zip_ef_free(ef); |
264 | 113 | if (prev) { |
265 | 77 | prev->next = next; |
266 | 77 | } |
267 | 113 | ef = next; |
268 | 113 | } |
269 | 3.42k | else { |
270 | 3.42k | prev = ef; |
271 | 3.42k | ef = ef->next; |
272 | 3.42k | } |
273 | 3.53k | } |
274 | | |
275 | 30.3k | return ef_head; |
276 | 30.3k | } |
277 | | |
278 | | |
279 | | /** |
280 | | * Calculate the size of the extra fields in bytes. |
281 | | * |
282 | | * @param ef the extra fields |
283 | | * @param flags which extra fields to include (ZIP_EF_LOCAL, ZIP_EF_CENTRAL, or both) |
284 | | * @return the size of the extra fields in bytes, or -1 if the size exceeds ZIP_UINT16_MAX. |
285 | | */ |
286 | 0 | zip_int32_t _zip_ef_size(const zip_extra_field_t *ef) { |
287 | 0 | zip_uint32_t size; |
288 | |
|
289 | 0 | size = 0; |
290 | 0 | for (; ef; ef = ef->next) { |
291 | 0 | size = (zip_uint32_t)(size + 4 + ef->size); |
292 | 0 | if (size > ZIP_UINT16_MAX) { |
293 | 0 | return -1; |
294 | 0 | } |
295 | 0 | } |
296 | | |
297 | 0 | return (zip_int32_t)size; |
298 | 0 | } |
299 | | |
300 | | |
301 | 0 | int _zip_ef_write(zip_t *za, const zip_extra_field_t *ef) { |
302 | 0 | zip_uint8_t b[4]; |
303 | 0 | zip_buffer_t *buffer = _zip_buffer_new(b, sizeof(b)); |
304 | |
|
305 | 0 | if (buffer == NULL) { |
306 | 0 | return -1; |
307 | 0 | } |
308 | | |
309 | 0 | for (; ef; ef = ef->next) { |
310 | 0 | _zip_buffer_set_offset(buffer, 0); |
311 | 0 | _zip_buffer_put_16(buffer, ef->id); |
312 | 0 | _zip_buffer_put_16(buffer, ef->size); |
313 | 0 | if (!_zip_buffer_ok(buffer)) { |
314 | 0 | zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); |
315 | 0 | _zip_buffer_free(buffer); |
316 | 0 | return -1; |
317 | 0 | } |
318 | 0 | if (_zip_write(za, b, 4) < 0) { |
319 | 0 | _zip_buffer_free(buffer); |
320 | 0 | return -1; |
321 | 0 | } |
322 | 0 | if (ef->size > 0) { |
323 | 0 | if (_zip_write(za, ef->data, ef->size) < 0) { |
324 | 0 | _zip_buffer_free(buffer); |
325 | 0 | return -1; |
326 | 0 | } |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | 0 | _zip_buffer_free(buffer); |
331 | 0 | return 0; |
332 | 0 | } |
333 | | |
334 | | |
335 | 0 | int _zip_read_local_ef(zip_t *za, zip_uint64_t idx) { |
336 | 0 | zip_entry_t *e; |
337 | 0 | unsigned char b[4]; |
338 | 0 | zip_buffer_t *buffer; |
339 | 0 | zip_uint16_t fname_len, ef_len; |
340 | |
|
341 | 0 | if (idx >= za->nentry) { |
342 | 0 | zip_error_set(&za->error, ZIP_ER_INVAL, 0); |
343 | 0 | return -1; |
344 | 0 | } |
345 | | |
346 | 0 | e = za->entry + idx; |
347 | |
|
348 | 0 | if (e->orig == NULL || e->orig->local_extra_fields_read) { |
349 | 0 | return 0; |
350 | 0 | } |
351 | | |
352 | 0 | if (e->orig->offset + 26 > ZIP_INT64_MAX) { |
353 | 0 | zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG); |
354 | 0 | return -1; |
355 | 0 | } |
356 | | |
357 | 0 | if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) { |
358 | 0 | zip_error_set_from_source(&za->error, za->src); |
359 | 0 | return -1; |
360 | 0 | } |
361 | | |
362 | 0 | if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) { |
363 | 0 | return -1; |
364 | 0 | } |
365 | | |
366 | 0 | fname_len = _zip_buffer_get_16(buffer); |
367 | 0 | ef_len = _zip_buffer_get_16(buffer); |
368 | |
|
369 | 0 | if (!_zip_buffer_eof(buffer)) { |
370 | 0 | _zip_buffer_free(buffer); |
371 | 0 | zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); |
372 | 0 | return -1; |
373 | 0 | } |
374 | | |
375 | 0 | _zip_buffer_free(buffer); |
376 | |
|
377 | 0 | if (ef_len > 0) { |
378 | 0 | zip_extra_field_t *ef; |
379 | 0 | zip_uint8_t *ef_raw; |
380 | |
|
381 | 0 | if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) { |
382 | 0 | zip_error_set(&za->error, ZIP_ER_SEEK, errno); |
383 | 0 | return -1; |
384 | 0 | } |
385 | | |
386 | 0 | ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error); |
387 | |
|
388 | 0 | if (ef_raw == NULL) { |
389 | 0 | return -1; |
390 | 0 | } |
391 | | |
392 | 0 | if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) { |
393 | 0 | free(ef_raw); |
394 | 0 | return -1; |
395 | 0 | } |
396 | 0 | free(ef_raw); |
397 | |
|
398 | 0 | if (ef) { |
399 | 0 | ef = _zip_ef_remove_internal(ef); |
400 | 0 | e->orig->extra_fields.local = ef; |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | 0 | e->orig->local_extra_fields_read = 1; |
405 | |
|
406 | 0 | if (e->changes && e->changes->local_extra_fields_read == 0) { |
407 | 0 | e->changes->extra_fields = e->orig->extra_fields; |
408 | 0 | e->changes->local_extra_fields_read = 1; |
409 | 0 | } |
410 | |
|
411 | 0 | return 0; |
412 | 0 | } |
413 | | |
414 | 0 | void _zip_extrafields_delete_by_id(zip_extra_fields_t *fields, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags) { |
415 | 0 | if (flags & ZIP_EF_LOCAL) { |
416 | 0 | fields->local = _zip_ef_delete_by_id(fields->local, ef_id, ef_idx); |
417 | 0 | } |
418 | 0 | if (flags & ZIP_EF_CENTRAL) { |
419 | 0 | fields->central = _zip_ef_delete_by_id(fields->central, ef_id, ef_idx); |
420 | 0 | } |
421 | 0 | } |
422 | | |
423 | 61.7k | const zip_uint8_t *_zip_extra_fields_get_by_id(const zip_extra_fields_t *extra_fields, zip_uint16_t *lenp, zip_uint16_t extra_field_id, zip_uint16_t extra_field_index, zip_flags_t flags, zip_error_t *error) { |
424 | 61.7k | const zip_uint8_t *data; |
425 | | |
426 | 61.7k | if (flags & ZIP_EF_LOCAL) { |
427 | 61.1k | data = _zip_ef_get_by_id(extra_fields->local, lenp, extra_field_id, extra_field_index, flags); |
428 | 61.1k | if (data) { |
429 | 0 | return data; |
430 | 0 | } |
431 | 61.1k | } |
432 | | |
433 | 61.7k | if (flags & ZIP_EF_CENTRAL) { |
434 | 61.7k | data = _zip_ef_get_by_id(extra_fields->central, lenp, extra_field_id, extra_field_index, flags); |
435 | 61.7k | if (data) { |
436 | 244 | return data; |
437 | 244 | } |
438 | 61.7k | } |
439 | | |
440 | 61.4k | zip_error_set(error, ZIP_ER_NOENT, 0); |
441 | 61.4k | return NULL; |
442 | 61.7k | } |
443 | | |
444 | 0 | zip_int16_t _zip_ef_count(const zip_extra_field_t *ef, zip_int32_t id) { |
445 | 0 | zip_int16_t n; |
446 | |
|
447 | 0 | n = 0; |
448 | 0 | for (; ef; ef = ef->next) { |
449 | 0 | if (id < 0 || ef->id == id) { |
450 | 0 | n++; |
451 | 0 | } |
452 | 0 | } |
453 | |
|
454 | 0 | return n; |
455 | 0 | } |
456 | | |
457 | 0 | zip_int16_t _zip_extra_fields_count(const zip_extra_fields_t *extra_fields, zip_int32_t id, zip_flags_t flags) { |
458 | 0 | zip_int16_t n; |
459 | |
|
460 | 0 | n = 0; |
461 | 0 | if (flags & ZIP_EF_LOCAL) { |
462 | 0 | n += _zip_ef_count(extra_fields->local, id); |
463 | 0 | } |
464 | 0 | if (flags & ZIP_EF_CENTRAL) { |
465 | 0 | n += _zip_ef_count(extra_fields->central, id); |
466 | 0 | } |
467 | |
|
468 | 0 | return n; |
469 | 0 | } |
470 | | |
471 | | |
472 | 0 | zip_extra_field_t *_zip_ef_set(zip_extra_field_t *ef_head, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_error_t *error) { |
473 | 0 | zip_extra_field_t *ef_prev = NULL; |
474 | 0 | zip_extra_field_t *ef_new, *ef; |
475 | 0 | zip_int32_t new_len; |
476 | |
|
477 | 0 | ef = _zip_ef_find(ef_head, ef_id, ef_idx, &ef_prev); |
478 | |
|
479 | 0 | if (ef == NULL && ef_idx != ZIP_EXTRA_FIELD_NEW) { |
480 | 0 | zip_error_set(error, ZIP_ER_INVAL, 0); |
481 | 0 | return NULL; |
482 | 0 | } |
483 | | |
484 | 0 | new_len = _zip_ef_size(ef_head); |
485 | | /* This should not happen, but we want to assume lengths are >= 0 later. */ |
486 | 0 | if (new_len < 0) { |
487 | 0 | zip_error_set(error, ZIP_ER_EF_TOO_LARGE, 0); |
488 | 0 | return NULL; |
489 | 0 | } |
490 | | |
491 | 0 | if (ef != NULL) { |
492 | 0 | new_len -= ef->size + 4; |
493 | 0 | } |
494 | 0 | new_len += len + 4; |
495 | |
|
496 | 0 | if (new_len > ZIP_UINT16_MAX) { |
497 | 0 | zip_error_set(error, ZIP_ER_EF_TOO_LARGE, 0); |
498 | 0 | return NULL; |
499 | 0 | } |
500 | | |
501 | 0 | if ((ef_new = _zip_ef_new(ef_id, len, data)) == NULL) { |
502 | 0 | zip_error_set(error, ZIP_ER_MEMORY, 0); |
503 | 0 | return NULL; |
504 | 0 | } |
505 | | |
506 | 0 | if (ef != NULL) { |
507 | 0 | ef_new->next = ef->next; |
508 | 0 | ef->next = NULL; |
509 | 0 | _zip_ef_free(ef); |
510 | 0 | } |
511 | 0 | else if (ef_prev) { |
512 | 0 | ef_new->next = ef_prev->next; |
513 | 0 | } |
514 | |
|
515 | 0 | if (ef_prev) { |
516 | 0 | ef_prev->next = ef_new; |
517 | 0 | } |
518 | 0 | else { |
519 | 0 | ef_head = ef_new; |
520 | 0 | } |
521 | |
|
522 | 0 | return ef_head; |
523 | 0 | } |
524 | | |
525 | 0 | bool _zip_extra_fields_set(zip_extra_fields_t *extra_fields, zip_flags_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_error_t *error) { |
526 | 0 | zip_extra_field_t *ef; |
527 | |
|
528 | 0 | if (flags & ZIP_EF_LOCAL) { |
529 | 0 | ef = _zip_ef_set(extra_fields->local, ef_id, ef_idx, data, len, error); |
530 | 0 | if (ef == NULL) { |
531 | 0 | return false; |
532 | 0 | } |
533 | 0 | extra_fields->local = ef; |
534 | 0 | } |
535 | 0 | if (flags & ZIP_EF_CENTRAL) { |
536 | 0 | ef = _zip_ef_set(extra_fields->central, ef_id, ef_idx, data, len, error); |
537 | 0 | if (ef == NULL) { |
538 | 0 | return false; |
539 | 0 | } |
540 | 0 | extra_fields->central = ef; |
541 | 0 | } |
542 | | |
543 | 0 | return true; |
544 | 0 | } |
545 | | |
546 | 0 | bool _zip_extra_fields_clone(zip_extra_fields_t *extra_fields, zip_error_t *error) { |
547 | 0 | if (extra_fields->local) { |
548 | 0 | if ((extra_fields->local = _zip_ef_clone(extra_fields->local, error)) == NULL) { |
549 | | /* Clear central so we don't refer to the original. */ |
550 | 0 | extra_fields->central = NULL; |
551 | 0 | return false; |
552 | 0 | } |
553 | 0 | } |
554 | 0 | if (extra_fields->central) { |
555 | 0 | if ((extra_fields->central = _zip_ef_clone(extra_fields->central, error)) == NULL) { |
556 | 0 | return false; |
557 | 0 | } |
558 | 0 | } |
559 | | |
560 | 0 | return true; |
561 | 0 | } |
562 | | |
563 | | |
564 | 31.3k | void _zip_extra_fields_fini(zip_extra_fields_t *extra_fields) { |
565 | 31.3k | _zip_ef_free(extra_fields->local); |
566 | 31.3k | extra_fields->local = NULL; |
567 | 31.3k | _zip_ef_free(extra_fields->central); |
568 | 31.3k | extra_fields->central = NULL; |
569 | 31.3k | } |
570 | | |
571 | 93.4k | void _zip_extra_fields_init(zip_extra_fields_t *extra_fields) { |
572 | 93.4k | extra_fields->local = NULL; |
573 | 93.4k | extra_fields->central = NULL; |
574 | 93.4k | } |
575 | | |
576 | | |
577 | 0 | void _zip_extra_fields_delete_by_id(zip_extra_fields_t *extra_fields, zip_uint16_t extra_field_id, zip_uint16_t extra_field_index, zip_flags_t flags) { |
578 | 0 | if (flags & ZIP_EF_LOCAL) { |
579 | 0 | extra_fields->local = _zip_ef_delete_by_id(extra_fields->local, extra_field_id, extra_field_index); |
580 | 0 | } |
581 | 0 | if (flags & ZIP_EF_CENTRAL) { |
582 | 0 | extra_fields->central = _zip_ef_delete_by_id(extra_fields->central, extra_field_id, extra_field_index); |
583 | 0 | } |
584 | 0 | } |