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