Document that mz_zip_tm_to_time_t requires a year-1900 indexed time struct. (#951)

This commit is contained in:
Cœur 2026-02-03 04:19:56 +01:00 committed by GitHub
parent 12cd14990b
commit 333bb8e84a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 23 additions and 11 deletions

View file

@ -2669,24 +2669,35 @@ int32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length) {
/***************************************************************************/ /***************************************************************************/
/**
This is mostly validating a given time struct is convertible to and from a valid dos date.
This does not however perform a calendar validation (like February 31).
*/
static int32_t mz_zip_invalid_date(const struct tm *ptm) { static int32_t mz_zip_invalid_date(const struct tm *ptm) {
#define datevalue_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) #define datevalue_in_range(min, max, value) ((min) <= (value) && (value) <= (max))
return (!datevalue_in_range(0, 127 + 80, ptm->tm_year) || /* 1980-based year, allow 80 extra */ return (!datevalue_in_range(0, 127 + 80, ptm->tm_year) || /* 1980-based year, allow 80 extra */
!datevalue_in_range(0, 11, ptm->tm_mon) || !datevalue_in_range(1, 31, ptm->tm_mday) || !datevalue_in_range(0, 11, ptm->tm_mon) || /* allowing months 0-11 in a year */
!datevalue_in_range(0, 23, ptm->tm_hour) || !datevalue_in_range(0, 59, ptm->tm_min) || !datevalue_in_range(1, 31, ptm->tm_mday) || /* allowing days 1-31 in a month */
!datevalue_in_range(0, 59, ptm->tm_sec)); !datevalue_in_range(0, 23, ptm->tm_hour) || /* allowing hours 0-23 in a day */
!datevalue_in_range(0, 59, ptm->tm_min) || /* allowing minutes 0-59 in an hour */
!datevalue_in_range(0, 59, ptm->tm_sec)); /* allowing seconds 0-59 in a minute */
#undef datevalue_in_range #undef datevalue_in_range
} }
/**
Returns a year-1900 indexed time struct.
This may produce slightly out-of-range months, hours, minutes, seconds.
This may also produce invalid calendar days (like the 31st of February).
*/
static void mz_zip_dosdate_to_raw_tm(uint64_t dos_date, struct tm *ptm) { static void mz_zip_dosdate_to_raw_tm(uint64_t dos_date, struct tm *ptm) {
uint64_t date = (uint64_t)(dos_date >> 16); uint64_t date = (uint64_t)(dos_date >> 16);
ptm->tm_mday = (int16_t)(date & 0x1f); ptm->tm_year = (int16_t)(((date & 0x0FE00) / 0x0200) + 80); /* result in 80..207 */
ptm->tm_mon = (int16_t)(((date & 0x1E0) / 0x20) - 1); ptm->tm_mon = (int16_t)(((date & 0x1E0) / 0x20) - 1); /* result in -1..14 */
ptm->tm_year = (int16_t)(((date & 0x0FE00) / 0x0200) + 80); ptm->tm_mday = (int16_t)(date & 0x1f); /* result in 0..31 */
ptm->tm_hour = (int16_t)((dos_date & 0xF800) / 0x800); ptm->tm_hour = (int16_t)((dos_date & 0xF800) / 0x800); /* result in 0..31 */
ptm->tm_min = (int16_t)((dos_date & 0x7E0) / 0x20); ptm->tm_min = (int16_t)((dos_date & 0x7E0) / 0x20); /* result in 0..63 */
ptm->tm_sec = (int16_t)(2 * (dos_date & 0x1f)); ptm->tm_sec = (int16_t)(2 * (dos_date & 0x1f)); /* result in 0..62 */
ptm->tm_isdst = -1; ptm->tm_isdst = -1;
} }
@ -2711,6 +2722,7 @@ time_t mz_zip_dosdate_to_time_t(uint64_t dos_date) {
} }
time_t mz_zip_tm_to_time_t(struct tm *ptm) { time_t mz_zip_tm_to_time_t(struct tm *ptm) {
// `ptm->tm_year` must be 1900-indexed.
return mktime(ptm); return mktime(ptm);
} }

View file

@ -221,7 +221,7 @@ time_t mz_zip_dosdate_to_time_t(uint64_t dos_date);
/* Convert dos date/time format to time_t */ /* Convert dos date/time format to time_t */
time_t mz_zip_tm_to_time_t(struct tm *ptm); time_t mz_zip_tm_to_time_t(struct tm *ptm);
/* Convert time struct to time_t */ /* Convert year-1900 indexed time struct to time_t */
int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm); int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm);
/* Convert time_t to time struct */ /* Convert time_t to time struct */

View file

@ -18,7 +18,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#ifdef HAVE_ZLIB #if defined(HAVE_ZLIB) || defined(HAVE_LIBCOMP)
static void test_zip_compat(zipFile zip, const char *filename, int32_t level) { static void test_zip_compat(zipFile zip, const char *filename, int32_t level) {
int32_t err = ZIP_OK; int32_t err = ZIP_OK;
zip_fileinfo file_info; zip_fileinfo file_info;