Skip to content

Commit a400ba6

Browse files
committed
Refactor time-related helper functions into a separate file
1 parent 33cbf3a commit a400ba6

2 files changed

Lines changed: 70 additions & 113 deletions

File tree

src/lib/otezip.c

Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <unistd.h>
1919
#include "otezip.h"
2020
#include "../include/zstream.h"
21+
#include "time.inc.c"
2122

2223
#if defined(_WIN32) || defined(_WIN64)
2324
/* Ensure we have thread-safe fallback for localtime on Windows builds */
@@ -84,119 +85,6 @@ int otezip_ignore_zipbomb = 0;
8485

8586
/* helper: little-endian readers/writers (ZIP format is little-endian) */
8687

87-
/* Date/time conversion for ZIP entries */
88-
/* Convert current time to DOS date/time fields.
89-
* The DOS date format stores year as an offset from 1980 in 7 bits
90-
*(0..127 -> 1980..2107). To avoid generating out-of-range values or
91-
* relying on unchecked `time_t` behaviour on 32-bit platforms, this
92-
* implementation validates and clamps fields. If time retrieval or
93-
* conversion fails, it falls back to 1980-01-01 00:00:00.
94-
*/
95-
/* Provide a small portable wrapper for thread-safe localtime when possible.
96-
* On POSIX systems prefer `localtime_r`; on Windows or when not available,
97-
* fall back to `localtime ()` and copy the result into the caller buffer. */
98-
static struct tm *otezip_localtime_r(const time_t *t, struct tm *out) {
99-
/* Portable fallback: use non-reentrant `localtime ()` and copy the result.
100-
* This avoids implicit declaration issues on platforms that don't expose
101-
* `localtime_r` while remaining simple for this small utility. */
102-
struct tm *tmp = localtime (t);
103-
if (!tmp) {
104-
return NULL;
105-
}
106-
*out = *tmp;
107-
return out;
108-
}
109-
110-
static void otezip_get_dostime(uint16_t *dos_time, uint16_t *dos_date) {
111-
time_t now = time (NULL);
112-
struct tm tm_buf;
113-
struct tm *tm_ptr = NULL;
114-
115-
/* Prefer reentrant version when available */
116-
if (now != (time_t)-1 && otezip_localtime_r (&now, &tm_buf) != NULL) {
117-
tm_ptr = &tm_buf;
118-
}
119-
if (!tm_ptr && now != (time_t)-1) {
120-
struct tm *tmp = localtime (&now);
121-
if (tmp) {
122-
/* copy into stack buffer to have a consistent pointer */
123-
tm_buf = *tmp;
124-
tm_ptr = &tm_buf;
125-
}
126-
}
127-
128-
/* Default to DOS epoch start if anything fails */
129-
if (!tm_ptr) {
130-
*dos_time = 0; /* 00:00:00 -> all zero */
131-
*dos_date = 0; /* 1980-01-01 -> year offset 0, month 1, day 1 */
132-
/* encode date: year offset 0, month 1, day 1 */
133-
*dos_date = (uint16_t) (((0) << 9) | ((1) << 5) | 1);
134-
return;
135-
}
136-
137-
/* Extract and clamp fields to valid ranges to avoid overflow or
138-
* nonsensical dates on platforms with limited time_t ranges. */
139-
int year = tm_ptr->tm_year + 1900; /* full year */
140-
int year_off = year - 1980;
141-
if (year_off < 0) {
142-
year_off = 0;
143-
}
144-
if (year_off > 127) {
145-
year_off = 127; /* DOS stores 7 bits */
146-
}
147-
148-
int mon = tm_ptr->tm_mon + 1;
149-
if (mon < 1) {
150-
mon = 1;
151-
}
152-
if (mon > 12) {
153-
mon = 12;
154-
}
155-
156-
int day = tm_ptr->tm_mday;
157-
if (day < 1) {
158-
day = 1;
159-
}
160-
if (day > 31) {
161-
day = 31;
162-
}
163-
164-
int hour = tm_ptr->tm_hour;
165-
if (hour < 0) {
166-
hour = 0;
167-
}
168-
if (hour > 23) {
169-
hour = 23;
170-
}
171-
172-
int min = tm_ptr->tm_min;
173-
if (min < 0) {
174-
min = 0;
175-
}
176-
if (min > 59) {
177-
min = 59;
178-
}
179-
180-
int sec = tm_ptr->tm_sec;
181-
if (sec < 0) {
182-
sec = 0;
183-
}
184-
if (sec > 59) {
185-
sec = 59;
186-
}
187-
188-
/* DOS time stores seconds divided by 2 */
189-
int sec2 = sec / 2;
190-
if (sec2 < 0) {
191-
sec2 = 0;
192-
}
193-
if (sec2 > 29) {
194-
sec2 = 29;
195-
}
196-
197-
*dos_time = (uint16_t) ((hour << 11) | (min << 5) | sec2);
198-
*dos_date = (uint16_t) ((year_off << 9) | (mon << 5) | day);
199-
}
20088
static uint16_t otezip_rd16(const uint8_t *p) {
20189
return (uint16_t) (p[0] | (p[1] << 8));
20290
}

src/lib/time.inc.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include <stdint.h>
2+
#include <time.h>
3+
4+
#if defined(_WIN32) || defined(_WIN64)
5+
/* Ensure we have thread-safe fallback for localtime on Windows builds */
6+
#include <time.h>
7+
#endif
8+
9+
/* Provide a small portable wrapper for thread-safe localtime when possible.
10+
* On POSIX systems prefer `localtime_r`; on Windows or when not available,
11+
* fall back to `localtime ()` and copy the result into the caller buffer. */
12+
static struct tm *otezip_localtime_r(const time_t *t, struct tm *out) {
13+
/* Portable fallback: use non-reentrant `localtime ()` and copy the result.
14+
* This avoids implicit declaration issues on platforms that don't expose
15+
* `localtime_r` while remaining simple for this small utility. */
16+
struct tm *tmp = localtime (t);
17+
if (!tmp) {
18+
return NULL;
19+
}
20+
*out = *tmp;
21+
return out;
22+
}
23+
24+
static inline int dim(int value, int min, int max) {
25+
return value < min? min: value > max? max : value;
26+
}
27+
28+
static void otezip_get_dostime(uint16_t *dos_time, uint16_t *dos_date) {
29+
time_t now = time (NULL);
30+
struct tm tm_buf;
31+
struct tm *tm_ptr = NULL;
32+
33+
/* Prefer reentrant version when available */
34+
if (now != (time_t)-1 && otezip_localtime_r (&now, &tm_buf) != NULL) {
35+
tm_ptr = &tm_buf;
36+
}
37+
if (!tm_ptr && now != (time_t)-1) {
38+
struct tm *tmp = localtime (&now);
39+
if (tmp) {
40+
/* copy into stack buffer to have a consistent pointer */
41+
tm_buf = *tmp;
42+
tm_ptr = &tm_buf;
43+
}
44+
}
45+
46+
/* Default to DOS epoch start if anything fails */
47+
if (!tm_ptr) {
48+
*dos_time = 0; /* 00:00:00 -> all zero */
49+
*dos_date = 0; /* 1980-01-01 -> year offset 0, month 1, day 1 */
50+
/* encode date: year offset 0, month 1, day 1 */
51+
*dos_date = (uint16_t) (((0) << 9) | ((1) << 5) | 1);
52+
return;
53+
}
54+
55+
/* Extract and clamp fields to valid ranges to avoid overflow or
56+
* nonsensical dates on platforms with limited time_t ranges. */
57+
int year = tm_ptr->tm_year + 1900; /* full year */
58+
int year_off = dim (year - 1980, 0, 127); /* DOS stores 7 bits */
59+
int mon = dim (tm_ptr->tm_mon + 1, 1, 12);
60+
int day = dim (tm_ptr->tm_mday, 1, 31);
61+
int hour = dim (tm_ptr->tm_hour, 0, 23);
62+
int min = dim (tm_ptr->tm_min, 0, 59);
63+
int sec = dim (tm_ptr->tm_sec, 0, 59);
64+
/* DOS time stores seconds divided by 2 */
65+
int sec2 = dim (sec / 2, 0, 29);
66+
67+
*dos_time = (uint16_t) ((hour << 11) | (min << 5) | sec2);
68+
*dos_date = (uint16_t) ((year_off << 9) | (mon << 5) | day);
69+
}

0 commit comments

Comments
 (0)