Skip to content

Commit c3b7bca

Browse files
committed
Use opaque structs where possible
1 parent 5c83b74 commit c3b7bca

4 files changed

Lines changed: 198 additions & 132 deletions

File tree

src/include/otezip/zip.h

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -74,40 +74,10 @@ typedef uint32_t zip_uint32_t;
7474
typedef uint16_t zip_uint16_t;
7575
typedef uint8_t zip_uint8_t;
7676

77-
/* an in-memory representation of a single directory entry */
78-
struct otezip_entry {
79-
char *name; /* zero-terminated filename */
80-
uint32_t local_hdr_ofs; /* offset of corresponding LFH */
81-
uint32_t comp_size;
82-
uint32_t uncomp_size;
83-
uint16_t method; /* 0=store, 8=deflate */
84-
uint32_t crc32; /* CRC-32 checksum of uncompressed data */
85-
uint16_t file_time; /* DOS format file time */
86-
uint16_t file_date; /* DOS format file date */
87-
uint32_t external_attr; /* External file attributes (permissions) */
88-
};
89-
90-
/* Use libzip-compatible struct names for full compatibility */
91-
struct zip {
92-
FILE *fp;
93-
struct otezip_entry *entries;
94-
zip_uint64_t n_entries;
95-
int mode; /* 0=read-only, 1=write */
96-
zip_uint64_t next_index; /* Next available index for adding files */
97-
uint16_t default_method; /* Default compression method for new entries */
98-
};
99-
100-
struct zip_file {
101-
uint8_t *data; /* complete uncompressed data */
102-
uint32_t size;
103-
zip_uint64_t pos; /* current read position for zip_fread */
104-
};
105-
106-
struct zip_source {
107-
const void *buf;
108-
zip_uint64_t len;
109-
int freep;
110-
};
77+
/* libzip-compatible opaque handles */
78+
struct zip;
79+
struct zip_file;
80+
struct zip_source;
11181

11282
/* Error information structure */
11383
struct otezip_error {
@@ -203,6 +173,7 @@ zip_int64_t zip_fread (zip_file_t *zf, void *buf, zip_uint64_t nbytes
203173

204174
zip_source_t * zip_source_buffer (zip_t *za, const void *data, zip_uint64_t len, int freep);
205175
zip_source_t * zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error);
176+
int zip_file_get_external_attributes(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_uint8_t *opsys, zip_uint32_t *attributesp);
206177
void zip_source_free (zip_source_t *src);
207178
zip_int64_t zip_file_add (zip_t *za, const char *name, zip_source_t *src, zip_flags_t flags);
208179
int zip_file_replace (zip_t *za, zip_uint64_t index, zip_source_t *src, zip_flags_t flags);

src/lib/otezip.c

Lines changed: 150 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,43 @@ static int otezip_mkstemp(const char *prefix) {
6060
#include "../include/otezip/zstream.h"
6161
#include "time.inc.c"
6262

63+
struct otezip_entry {
64+
char *name;
65+
uint32_t local_hdr_ofs;
66+
uint32_t comp_size;
67+
uint32_t uncomp_size;
68+
uint16_t method;
69+
uint32_t crc32;
70+
uint16_t file_time;
71+
uint16_t file_date;
72+
uint32_t external_attr;
73+
const void *pending_buf;
74+
zip_uint64_t pending_len;
75+
int pending_freep;
76+
int dirty;
77+
};
78+
79+
struct zip {
80+
FILE *fp;
81+
struct otezip_entry *entries;
82+
zip_uint64_t n_entries;
83+
int mode;
84+
zip_uint64_t next_index;
85+
uint16_t default_method;
86+
};
87+
88+
struct zip_file {
89+
uint8_t *data;
90+
uint32_t size;
91+
zip_uint64_t pos;
92+
};
93+
94+
struct zip_source {
95+
const void *buf;
96+
zip_uint64_t len;
97+
int freep;
98+
};
99+
63100
#if defined(_WIN32) || defined(_WIN64)
64101
/* Ensure we have thread-safe fallback for localtime on Windows builds */
65102
#include <time.h>
@@ -106,6 +143,10 @@ static uint32_t otezip_write_local_header(FILE *fp, const char *name, uint32_t c
106143
static uint32_t otezip_write_central_header(FILE *fp, const char *name, uint32_t comp_method, uint32_t comp_size, uint32_t uncomp_size, uint32_t crc32, uint32_t local_header_offset, uint16_t file_time, uint16_t file_date, uint32_t external_attr);
107144
static void otezip_write_end_of_central_directory(FILE *fp, uint32_t num_entries, uint32_t central_dir_size, uint32_t central_dir_offset);
108145
static int otezip_finalize_archive(zip_t *za);
146+
static int otezip_is_valid(const zip_t *za);
147+
static int otezip_compress_data(uint8_t *in_buf, size_t in_size, uint8_t **out_buf, uint32_t *out_size, uint16_t *method);
148+
static void otezip_discard_pending_source(struct otezip_entry *e);
149+
static int otezip_materialize_entry(zip_t *za, struct otezip_entry *e);
109150

110151
/* Helper function to get compression method ID from string name.
111152
* Returns the OTEZIP_METHOD_* value or -1 if invalid/not supported. */
@@ -683,6 +724,53 @@ static int otezip_extract_entry(zip_t *za, struct otezip_entry *e, uint8_t **out
683724
return 0;
684725
}
685726

727+
static void otezip_discard_pending_source(struct otezip_entry *e) {
728+
if (!e) {
729+
return;
730+
}
731+
if (e->pending_freep && e->pending_buf) {
732+
free ((void *)e->pending_buf);
733+
}
734+
e->pending_buf = NULL;
735+
e->pending_len = 0;
736+
e->pending_freep = 0;
737+
e->dirty = 0;
738+
}
739+
740+
static int otezip_materialize_entry(zip_t *za, struct otezip_entry *e) {
741+
if (!otezip_is_valid (za) || !e || !e->dirty) {
742+
return 0;
743+
}
744+
if (e->pending_len > OTEZIP_MAX_PAYLOAD || e->pending_len > (zip_uint64_t)UINT32_MAX) {
745+
return -1;
746+
}
747+
748+
long current_pos = ftell (za->fp);
749+
if (current_pos < 0 || (uint64_t)current_pos > (uint64_t)UINT32_MAX) {
750+
return -1;
751+
}
752+
e->local_hdr_ofs = (uint32_t)current_pos;
753+
e->uncomp_size = (uint32_t)e->pending_len;
754+
e->crc32 = otezip_crc32 (0, e->pending_buf, e->pending_len);
755+
756+
uint8_t *comp_buf = NULL;
757+
uint32_t comp_size = 0;
758+
if (otezip_compress_data ((uint8_t *)e->pending_buf, e->pending_len, &comp_buf, &comp_size, &e->method) != 0) {
759+
return -1;
760+
}
761+
if ((uint64_t)comp_size > OTEZIP_MAX_PAYLOAD) {
762+
free (comp_buf);
763+
return -1;
764+
}
765+
e->comp_size = comp_size;
766+
767+
otezip_write_local_header (za->fp, e->name, e->method, e->comp_size, e->uncomp_size, e->crc32);
768+
fwrite (comp_buf, 1, comp_size, za->fp);
769+
free (comp_buf);
770+
otezip_discard_pending_source (e);
771+
return 0;
772+
}
773+
686774
/* Helper function to validate archive state */
687775
static int otezip_is_valid(const zip_t *za) {
688776
return (za != NULL && za->fp != NULL);
@@ -1128,50 +1216,10 @@ zip_int64_t zip_file_add(zip_t *za, const char *name, zip_source_t *src, zip_fla
11281216

11291217
/* Set default permissions: 0644 for files */
11301218
e->external_attr = 0100644 << 16; /* S_IFREG | 0644 << 16 */
1131-
1132-
/* Get current position for local header offset */
1133-
long current_pos = ftell (za->fp);
1134-
if (current_pos < 0) {
1135-
free (e->name);
1136-
return -1;
1137-
}
1138-
1139-
/* Ensure local header offset fits into ZIP 32-bit field */
1140-
if ((uint64_t)current_pos > (uint64_t)UINT32_MAX) {
1141-
free (e->name);
1142-
return -1;
1143-
}
1144-
e->local_hdr_ofs = (uint32_t)current_pos;
1145-
1146-
/* Compress the data using the selected method */
1147-
uint8_t *comp_buf = NULL;
1148-
uint32_t comp_size = 0;
1149-
1150-
/* Compress the data using the selected method */
1151-
if (otezip_compress_data ((uint8_t *)src->buf, src->len, &comp_buf, &comp_size, &e->method) != 0) {
1152-
free (e->name);
1153-
return -1;
1154-
}
1155-
1156-
/* Validate compressed size too */
1157-
if ((uint64_t)comp_size > OTEZIP_MAX_PAYLOAD) {
1158-
free (e->name);
1159-
free (comp_buf);
1160-
return -1;
1161-
}
1162-
e->comp_size = comp_size;
1163-
1164-
/* Write local file header */
1165-
otezip_write_local_header (za->fp, e->name, e->method, e->comp_size, e->uncomp_size, e->crc32);
1166-
1167-
/* Write compressed data */
1168-
fwrite (comp_buf, 1, comp_size, za->fp);
1169-
free (comp_buf);
1170-
1171-
/* Free source data if requested */
1172-
if (src->freep) {
1173-
free ((void *)src->buf);
1174-
}
1219+
e->pending_buf = src->buf;
1220+
e->pending_len = src->len;
1221+
e->pending_freep = src->freep;
1222+
e->dirty = 1;
11751223
free (src);
11761224

11771225
/* Increment entry count */
@@ -1231,8 +1279,19 @@ int zip_set_file_compression(zip_t *za, zip_uint64_t index, zip_int32_t comp, zi
12311279
return -1;
12321280
}
12331281

1234-
/* Set the method for next files that will be added */
1235-
za->entries[index].method = (uint16_t)comp;
1282+
struct otezip_entry *e = &za->entries[index];
1283+
if (!e->dirty) {
1284+
uint8_t *buf = NULL;
1285+
uint32_t sz = 0;
1286+
if (otezip_extract_entry (za, e, &buf, &sz) != 0) {
1287+
return -1;
1288+
}
1289+
e->pending_buf = buf;
1290+
e->pending_len = sz;
1291+
e->pending_freep = 1;
1292+
e->dirty = 1;
1293+
}
1294+
e->method = (uint16_t)comp;
12361295
return 0;
12371296
}
12381297

@@ -1241,6 +1300,14 @@ static int otezip_finalize_archive(zip_t *za) {
12411300
if (!otezip_is_valid (za) || !za->fp || za->mode != 1) {
12421301
return -1;
12431302
}
1303+
if (fseek (za->fp, 0, SEEK_END) != 0) {
1304+
return -1;
1305+
}
1306+
for (zip_uint64_t i = 0; i < za->n_entries; i++) {
1307+
if (otezip_materialize_entry (za, &za->entries[i]) != 0) {
1308+
return -1;
1309+
}
1310+
}
12441311
/* Get offset for central directory */
12451312
long cd_offset = ftell (za->fp);
12461313
if (cd_offset < 0) {
@@ -1276,22 +1343,24 @@ int zip_close(zip_t *za) {
12761343
return -1;
12771344
}
12781345
/* Finalize archive if in write mode */
1346+
int rc = 0;
12791347
if (za->mode == 1) {
1280-
otezip_finalize_archive (za);
1348+
rc = otezip_finalize_archive (za);
12811349
}
12821350

12831351
if (za->fp) {
12841352
fclose (za->fp);
12851353
}
12861354
zip_uint64_t i;
12871355
for (i = 0; i < za->n_entries; i++) {
1356+
otezip_discard_pending_source (&za->entries[i]);
12881357
if (za->entries[i].name) {
12891358
free (za->entries[i].name);
12901359
}
12911360
}
12921361
free (za->entries);
12931362
free (za);
1294-
return 0;
1363+
return rc;
12951364
}
12961365

12971366
zip_uint64_t zip_get_num_files(zip_t *za) {
@@ -1319,7 +1388,17 @@ zip_file_t *zip_fopen_index(zip_t *za, zip_uint64_t index, zip_flags_t flags) {
13191388
}
13201389
uint8_t *buf = NULL;
13211390
uint32_t sz = 0;
1322-
if (otezip_extract_entry (za, &za->entries[index], &buf, &sz) != 0) {
1391+
struct otezip_entry *e = &za->entries[index];
1392+
if (e->dirty) {
1393+
sz = (uint32_t)e->pending_len;
1394+
buf = (uint8_t *)malloc (sz ? sz : 1u);
1395+
if (!buf) {
1396+
return NULL;
1397+
}
1398+
if (sz > 0) {
1399+
memcpy (buf, e->pending_buf, sz);
1400+
}
1401+
} else if (otezip_extract_entry (za, e, &buf, &sz) != 0) {
13231402
return NULL;
13241403
}
13251404
zip_file_t *zf = (zip_file_t *)malloc (sizeof (zip_file_t));
@@ -1603,6 +1682,18 @@ zip_source_t *zip_source_buffer_create(const void *data, zip_uint64_t len, int f
16031682
return zip_source_buffer (NULL, data, len, freep);
16041683
}
16051684

1685+
int zip_file_get_external_attributes(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_uint8_t *opsys, zip_uint32_t *attributesp) {
1686+
(void)flags;
1687+
if (!otezip_is_valid (za) || index >= za->n_entries || !attributesp) {
1688+
return -1;
1689+
}
1690+
if (opsys) {
1691+
*opsys = 3;
1692+
}
1693+
*attributesp = za->entries[index].external_attr;
1694+
return 0;
1695+
}
1696+
16061697
void zip_source_free(zip_source_t *src) {
16071698
if (!src) {
16081699
return;
@@ -1622,30 +1713,19 @@ static int otezip_replace_entry_data(zip_t *za, zip_uint64_t index, zip_source_t
16221713
return -1;
16231714
}
16241715
struct otezip_entry *e = &za->entries[index];
1716+
if ((uint64_t)src->len > OTEZIP_MAX_PAYLOAD || (uint64_t)src->len > (uint64_t)UINT32_MAX) {
1717+
return -1;
1718+
}
1719+
otezip_discard_pending_source (e);
16251720
/* Update entry with new source data */
16261721
e->uncomp_size = (uint32_t)src->len;
16271722
e->crc32 = otezip_crc32 (0, src->buf, src->len);
1628-
/* Compress the data using the selected method */
1629-
uint8_t *comp_buf = NULL;
1630-
uint32_t comp_size = 0;
1631-
if (otezip_compress_data ((uint8_t *)src->buf, src->len, &comp_buf, &comp_size, &e->method) != 0) {
1632-
return -1;
1633-
}
1634-
if ((uint64_t)comp_size > OTEZIP_MAX_PAYLOAD) {
1635-
free (comp_buf);
1636-
return -1;
1637-
}
1638-
e->comp_size = comp_size;
1639-
/* Write the updated entry */
1640-
long current_pos = ftell (za->fp);
1641-
if (current_pos < 0) {
1642-
free (comp_buf);
1643-
return -1;
1644-
}
1645-
e->local_hdr_ofs = (uint32_t)current_pos;
1646-
otezip_write_local_header (za->fp, e->name, e->method, e->comp_size, e->uncomp_size, e->crc32);
1647-
fwrite (comp_buf, 1, comp_size, za->fp);
1648-
free (comp_buf);
1723+
otezip_get_dostime (&e->file_time, &e->file_date);
1724+
e->pending_buf = src->buf;
1725+
e->pending_len = src->len;
1726+
e->pending_freep = src->freep;
1727+
e->dirty = 1;
1728+
free (src);
16491729
return 0;
16501730
}
16511731

0 commit comments

Comments
 (0)