"Fossies" - the Fresh Open Source Software Archive 
1 /*
2 zip_extra_field_api.c -- public extra fields API functions
3 Copyright (C) 2012-2014 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 <libzip@nih.at>
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
35 #include "zipint.h"
36
37
38 ZIP_EXTERN int
39 zip_file_extra_field_delete(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_flags_t flags) {
40 zip_dirent_t *de;
41
42 if ((flags & ZIP_EF_BOTH) == 0) {
43 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
44 return -1;
45 }
46
47 if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) {
48 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
49 return -1;
50 }
51
52 if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
53 return -1;
54
55 if (ZIP_IS_RDONLY(za)) {
56 zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
57 return -1;
58 }
59
60 if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)
61 return -1;
62
63 de = za->entry[idx].changes;
64
65 de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ZIP_EXTRA_FIELD_ALL, ef_idx, flags);
66 return 0;
67 }
68
69
70 ZIP_EXTERN int
71 zip_file_extra_field_delete_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags) {
72 zip_dirent_t *de;
73
74 if ((flags & ZIP_EF_BOTH) == 0) {
75 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
76 return -1;
77 }
78
79 if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) {
80 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
81 return -1;
82 }
83
84 if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
85 return -1;
86
87 if (ZIP_IS_RDONLY(za)) {
88 zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
89 return -1;
90 }
91
92 if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)
93 return -1;
94
95 de = za->entry[idx].changes;
96
97 de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ef_id, ef_idx, flags);
98 return 0;
99 }
100
101
102 ZIP_EXTERN const zip_uint8_t *
103 zip_file_extra_field_get(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp, zip_flags_t flags) {
104 static const zip_uint8_t empty[1] = {'\0'};
105
106 zip_dirent_t *de;
107 zip_extra_field_t *ef;
108 int i;
109
110 if ((flags & ZIP_EF_BOTH) == 0) {
111 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
112 return NULL;
113 }
114
115 if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)
116 return NULL;
117
118 if (flags & ZIP_FL_LOCAL)
119 if (_zip_read_local_ef(za, idx) < 0)
120 return NULL;
121
122 i = 0;
123 for (ef = de->extra_fields; ef; ef = ef->next) {
124 if (ef->flags & flags & ZIP_EF_BOTH) {
125 if (i < ef_idx) {
126 i++;
127 continue;
128 }
129
130 if (idp)
131 *idp = ef->id;
132 if (lenp)
133 *lenp = ef->size;
134 if (ef->size > 0)
135 return ef->data;
136 else
137 return empty;
138 }
139 }
140
141 zip_error_set(&za->error, ZIP_ER_NOENT, 0);
142 return NULL;
143 }
144
145
146 ZIP_EXTERN const zip_uint8_t *
147 zip_file_extra_field_get_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp, zip_flags_t flags) {
148 zip_dirent_t *de;
149
150 if ((flags & ZIP_EF_BOTH) == 0) {
151 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
152 return NULL;
153 }
154
155 if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)
156 return NULL;
157
158 if (flags & ZIP_FL_LOCAL)
159 if (_zip_read_local_ef(za, idx) < 0)
160 return NULL;
161
162 return _zip_ef_get_by_id(de->extra_fields, lenp, ef_id, ef_idx, flags, &za->error);
163 }
164
165
166 ZIP_EXTERN zip_int16_t
167 zip_file_extra_fields_count(zip_t *za, zip_uint64_t idx, zip_flags_t flags) {
168 zip_dirent_t *de;
169 zip_extra_field_t *ef;
170 zip_uint16_t n;
171
172 if ((flags & ZIP_EF_BOTH) == 0) {
173 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
174 return -1;
175 }
176
177 if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)
178 return -1;
179
180 if (flags & ZIP_FL_LOCAL)
181 if (_zip_read_local_ef(za, idx) < 0)
182 return -1;
183
184 n = 0;
185 for (ef = de->extra_fields; ef; ef = ef->next)
186 if (ef->flags & flags & ZIP_EF_BOTH)
187 n++;
188
189 return (zip_int16_t)n;
190 }
191
192
193 ZIP_EXTERN zip_int16_t
194 zip_file_extra_fields_count_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_flags_t flags) {
195 zip_dirent_t *de;
196 zip_extra_field_t *ef;
197 zip_uint16_t n;
198
199 if ((flags & ZIP_EF_BOTH) == 0) {
200 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
201 return -1;
202 }
203
204 if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)
205 return -1;
206
207 if (flags & ZIP_FL_LOCAL)
208 if (_zip_read_local_ef(za, idx) < 0)
209 return -1;
210
211 n = 0;
212 for (ef = de->extra_fields; ef; ef = ef->next)
213 if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH))
214 n++;
215
216 return (zip_int16_t)n;
217 }
218
219
220 ZIP_EXTERN int
221 zip_file_extra_field_set(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags) {
222 zip_dirent_t *de;
223 zip_uint16_t ls, cs;
224 zip_extra_field_t *ef, *ef_prev, *ef_new;
225 int i, found, new_len;
226
227 if ((flags & ZIP_EF_BOTH) == 0) {
228 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
229 return -1;
230 }
231
232 if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
233 return -1;
234
235 if (ZIP_IS_RDONLY(za)) {
236 zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
237 return -1;
238 }
239
240 if (ZIP_EF_IS_INTERNAL(ef_id)) {
241 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
242 return -1;
243 }
244
245 if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)
246 return -1;
247
248 de = za->entry[idx].changes;
249
250 ef = de->extra_fields;
251 ef_prev = NULL;
252 i = 0;
253 found = 0;
254
255 for (; ef; ef = ef->next) {
256 if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) {
257 if (i == ef_idx) {
258 found = 1;
259 break;
260 }
261 i++;
262 }
263 ef_prev = ef;
264 }
265
266 if (i < ef_idx && ef_idx != ZIP_EXTRA_FIELD_NEW) {
267 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
268 return -1;
269 }
270
271 if (flags & ZIP_EF_LOCAL)
272 ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL);
273 else
274 ls = 0;
275 if (flags & ZIP_EF_CENTRAL)
276 cs = _zip_ef_size(de->extra_fields, ZIP_EF_CENTRAL);
277 else
278 cs = 0;
279
280 new_len = ls > cs ? ls : cs;
281 if (found)
282 new_len -= ef->size + 4;
283 new_len += len + 4;
284
285 if (new_len > ZIP_UINT16_MAX) {
286 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
287 return -1;
288 }
289
290 if ((ef_new = _zip_ef_new(ef_id, len, data, flags)) == NULL) {
291 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
292 return -1;
293 }
294
295 if (found) {
296 if ((ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) {
297 ef_new->next = ef->next;
298 ef->next = NULL;
299 _zip_ef_free(ef);
300 if (ef_prev)
301 ef_prev->next = ef_new;
302 else
303 de->extra_fields = ef_new;
304 }
305 else {
306 ef->flags &= ~(flags & ZIP_EF_BOTH);
307 ef_new->next = ef->next;
308 ef->next = ef_new;
309 }
310 }
311 else if (ef_prev) {
312 ef_new->next = ef_prev->next;
313 ef_prev->next = ef_new;
314 }
315 else
316 de->extra_fields = ef_new;
317
318 return 0;
319 }
320
321
322 int
323 _zip_file_extra_field_prepare_for_change(zip_t *za, zip_uint64_t idx) {
324 zip_entry_t *e;
325
326 if (idx >= za->nentry) {
327 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
328 return -1;
329 }
330
331 e = za->entry + idx;
332
333 if (e->changes && (e->changes->changed & ZIP_DIRENT_EXTRA_FIELD))
334 return 0;
335
336 if (e->orig) {
337 if (_zip_read_local_ef(za, idx) < 0)
338 return -1;
339 }
340
341 if (e->changes == NULL) {
342 if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {
343 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
344 return -1;
345 }
346 }
347
348 if (e->orig && e->orig->extra_fields) {
349 if ((e->changes->extra_fields = _zip_ef_clone(e->orig->extra_fields, &za->error)) == NULL)
350 return -1;
351 }
352 e->changes->changed |= ZIP_DIRENT_EXTRA_FIELD;
353
354 return 0;
355 }