struct zip_extra_field * _zip_ef_clone(const struct zip_extra_field *ef, struct zip_error *error) { struct zip_extra_field *head, *prev, *def; head = prev = NULL; while (ef) { if ((def=_zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) { _zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_ef_free(head); return NULL; } if (head == NULL) head = def; if (prev) prev->next = def; prev = def; ef = ef->next; } return head; }
zip_extra_field_t * _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_error_t *error) { zip_buffer_t *buffer; zip_extra_field_t *ef, *ef2, *ef_head; if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } ef_head = ef = NULL; while (_zip_buffer_ok(buffer) && !_zip_buffer_eof(buffer)) { zip_uint16_t fid, flen; zip_uint8_t *ef_data; fid = _zip_buffer_get_16(buffer); flen = _zip_buffer_get_16(buffer); ef_data = _zip_buffer_get(buffer, flen); if (ef_data == NULL) { break; } if ((ef2=_zip_ef_new(fid, flen, ef_data, flags)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return NULL; } if (ef_head) { ef->next = ef2; ef = ef2; } else ef_head = ef = ef2; } if (!_zip_buffer_eof(buffer)) { zip_error_set(error, ZIP_ER_INCONS, 0); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return NULL; } _zip_buffer_free(buffer); return ef_head; }
struct zip_extra_field * _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, struct zip_error *error) { struct zip_extra_field *ef, *ef2, *ef_head; const zip_uint8_t *p; zip_uint16_t fid, flen; ef_head = NULL; for (p=data; p<data+len; p+=flen) { if (p+4 > data+len) { _zip_error_set(error, ZIP_ER_INCONS, 0); _zip_ef_free(ef_head); return NULL; } fid = _zip_read2(&p); flen = _zip_read2(&p); if (p+flen > data+len) { _zip_error_set(error, ZIP_ER_INCONS, 0); _zip_ef_free(ef_head); return NULL; } if ((ef2=_zip_ef_new(fid, flen, p, flags)) == NULL) { _zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_ef_free(ef_head); return NULL; } if (ef_head) { ef->next = ef2; ef = ef2; } else ef_head = ef = ef2; } return ef_head; }
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) { zip_buffer_t *buffer; zip_extra_field_t *ef, *ef2, *ef_head; if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return false; } ef_head = ef = NULL; while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) { zip_uint16_t fid, flen; zip_uint8_t *ef_data; fid = _zip_buffer_get_16(buffer); flen = _zip_buffer_get_16(buffer); ef_data = _zip_buffer_get(buffer, flen); if (ef_data == NULL) { zip_error_set(error, ZIP_ER_INCONS, 0); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return false; } if ((ef2=_zip_ef_new(fid, flen, ef_data, flags)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return false; } if (ef_head) { ef->next = ef2; ef = ef2; } else ef_head = ef = ef2; } if (!_zip_buffer_eof(buffer)) { /* Android APK files align stored file data with padding in extra fields; ignore. */ /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */ size_t glen = _zip_buffer_left(buffer); zip_uint8_t *garbage; garbage = _zip_buffer_get(buffer, glen); if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", glen) != 0) { zip_error_set(error, ZIP_ER_INCONS, 0); _zip_buffer_free(buffer); _zip_ef_free(ef_head); return false; } } _zip_buffer_free(buffer); if (ef_head_p) { *ef_head_p = ef_head; } else { _zip_ef_free(ef_head); } return true; }
ZIP_EXTERN int zip_file_extra_field_set(struct zip *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) { struct zip_dirent *de; zip_uint16_t ls, cs; struct zip_extra_field *ef, *ef_prev, *ef_new; int i, found, new_len; if ((flags & ZIP_EF_BOTH) == 0) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_get_dirent(za, idx, 0, NULL) == NULL) return -1; if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (ZIP_EF_IS_INTERNAL(ef_id)) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_file_extra_field_prepare_for_change(za, idx) < 0) return -1; de = za->entry[idx].changes; ef = de->extra_fields; ef_prev = NULL; i = 0; found = 0; for (; ef; ef=ef->next) { if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) { if (i == ef_idx) { found = 1; break; } i++; } ef_prev = ef; } if (i < ef_idx && ef_idx != ZIP_EXTRA_FIELD_NEW) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (flags & ZIP_EF_LOCAL) ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL); else ls = 0; if (flags & ZIP_EF_CENTRAL) cs = _zip_ef_size(de->extra_fields, ZIP_EF_CENTRAL); else cs = 0; new_len = ls > cs ? ls : cs; if (found) new_len -= ef->size + 4; new_len += len + 4; if (new_len > ZIP_UINT16_MAX) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if ((ef_new=_zip_ef_new(ef_id, len, data, flags)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } if (found) { if ((ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) { ef_new->next = ef->next; ef->next = NULL; _zip_ef_free(ef); if (ef_prev) ef_prev->next = ef_new; else de->extra_fields = ef_new; } else { ef->flags &= ~(flags & ZIP_EF_BOTH); ef_new->next = ef->next; ef->next = ef_new; } } else if (ef_prev) { ef_new->next = ef_prev->next; ef_prev->next = ef_new; } else de->extra_fields = ef_new; return 0; }