**
** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx
*/
-static time_t zipfileMtime(ZipfileCDS *pCDS){
- struct tm t;
- memset(&t, 0, sizeof(t));
- t.tm_sec = (pCDS->mTime & 0x1F)*2;
- t.tm_min = (pCDS->mTime >> 5) & 0x2F;
- t.tm_hour = (pCDS->mTime >> 11) & 0x1F;
-
- t.tm_mday = (pCDS->mDate & 0x1F);
- t.tm_mon = ((pCDS->mDate >> 5) & 0x0F) - 1;
- t.tm_year = 80 + ((pCDS->mDate >> 9) & 0x7F);
-
- return mktime(&t);
+static u32 zipfileMtime(ZipfileCDS *pCDS){
+ int Y = (1980 + ((pCDS->mDate >> 9) & 0x7F));
+ int M = ((pCDS->mDate >> 5) & 0x0F);
+ int D = (pCDS->mDate & 0x1F);
+ int B = -13;
+
+ int sec = (pCDS->mTime & 0x1F)*2;
+ int min = (pCDS->mTime >> 5) & 0x3F;
+ int hr = (pCDS->mTime >> 11) & 0x1F;
+
+ /* JD = INT(365.25 * (Y+4716)) + INT(30.6001 * (M+1)) + D + B - 1524.5 */
+
+ /* Calculate the JD in seconds for noon on the day in question */
+ if( M<3 ){
+ Y = Y-1;
+ M = M+12;
+ }
+ i64 JD = (i64)(24*60*60) * (
+ (int)(365.25 * (Y + 4716))
+ + (int)(30.6001 * (M + 1))
+ + D + B - 1524
+ );
+
+ /* Correct the JD for the time within the day */
+ JD += (hr-12) * 3600 + min * 60 + sec;
+
+ /* Convert JD to unix timestamp (the JD epoch is 2440587.5) */
+ return (u32)(JD - (i64)(24405875) * 24*60*6);
}
/*
** to the UNIX timestamp value passed as the second.
*/
static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){
- time_t t = (time_t)mUnixTime;
- struct tm res;
-
-#if !defined(_WIN32) && !defined(WIN32)
- localtime_r(&t, &res);
-#else
- memcpy(&res, localtime(&t), sizeof(struct tm));
-#endif
-
- pCds->mTime = (u16)(
- (res.tm_sec / 2) +
- (res.tm_min << 5) +
- (res.tm_hour << 11));
-
- pCds->mDate = (u16)(
- (res.tm_mday-1) +
- ((res.tm_mon+1) << 5) +
- ((res.tm_year-80) << 9));
+ /* Convert unix timestamp to JD (2440588 is noon on 1/1/1970) */
+ i64 JD = (i64)2440588 + mUnixTime / (24*60*60);
+
+ int A, B, C, D, E;
+ int yr, mon, day;
+ int hr, min, sec;
+
+ A = (int)((JD - 1867216.25)/36524.25);
+ A = JD + 1 + A - (A/4);
+ B = A + 1524;
+ C = (int)((B - 122.1)/365.25);
+ D = (36525*(C&32767))/100;
+ E = (int)((B-D)/30.6001);
+
+ day = B - D - (int)(30.6001*E);
+ mon = (E<14 ? E-1 : E-13);
+ yr = mon>2 ? C-4716 : C-4715;
+
+ hr = (mUnixTime % (24*60*60)) / (60*60);
+ min = (mUnixTime % (60*60)) / 60;
+ sec = (mUnixTime % 60);
+
+ pCds->mDate = (u16)(day + (mon << 5) + ((yr-1980) << 9));
+ pCds->mTime = (u16)(sec/2 + (min<<5) + (hr<<11));
+
+ assert( mUnixTime<315507600
+ || mUnixTime==zipfileMtime(pCds)
+ || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds))
+ /* || (mUnixTime % 2) */
+ );
}
/*
-C Improve\sthe\somit-left-join\soptimization\sso\sthat\sit\sworks\sin\ssome\scases\s\nwhen\sthe\sRHS\sis\ssubject\sto\sa\sUNIQUE\sbut\snot\sNOT\sNULL\sconstraint.
-D 2018-01-31T16:50:27.186
+C When\screating\sa\snew\sarchive\sentry,\shave\szipfile\sstore\sUTC\sinstead\sof\slocal\ntime\sin\sthe\slegacy\sMS-DOS\sformat\stimestamp\sfield.
+D 2018-01-31T19:13:31.142
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 7a3f714b4fcf793108042b7b0a5c720b0b310ec84314d61ba7f3f49f27e550ea
F ext/misc/vtablog.c 31d0d8f4406795679dcd3a67917c213d3a2a5fb3ea5de35f6e773491ed7e13c9
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
-F ext/misc/zipfile.c aa10ec6a235030cd368b511e7c78e40251008dddddeb0eb006ad1f344f78b690
+F ext/misc/zipfile.c 56028f7e74d948b7bef834624d128f563eb63f5950248d538afa9d0f6c3365dc
F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
F ext/rbu/rbu10.test 1846519a438697f45e9dcb246908af81b551c29e1078d0304fae83f1fed7e9ee
F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501ddd910cc
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
F test/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc
-F test/zipfile.test 368a5a0c97be0caaf8c3efa8293bfe18436d546805678fa00b6aa81bc98727ec
-F test/zipfile2.test 1066dd9769028d6f0bf1c87303b24f087cc064d9bbcacefc95613380f642de18
+F test/zipfile.test 3695ab6d731720ca0b542fe21ded39d4a34891f4a590b2e6c909c9ff07e13148
+F test/zipfile2.test 5f93611307c131e83f226a471231d769b794b9e8c6a675cfa3d34b1a79df23fe
F test/zipfilefault.test df4fa9e16116e0cb21d09037a6b0a7d93fecd8767d82154b66044b4ca43fca58
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
F tool/GetTclKit.bat 8995df40c4209808b31f24de0b58f90930239a234f7591e3675d45bfbb990c5d
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 32ed9c106710c74a12d60ec33027fd6a9335627c95642ba608593b2735714da6 74d857d178dfadea7e07ba47439fe11aa9d282b54caf78cd6961e593b37406d0
-R ee3ce7babbd6fba601d683cb41b035ba
-T +closed 74d857d178dfadea7e07ba47439fe11aa9d282b54caf78cd6961e593b37406d0
-U drh
-Z 20db364b7139e3a10e7c112d48b03b80
+P 02ba8a7ba7ba71cd7abd5dd3093ea486f53a025f6972bb444f2da37e0e2fc3b2
+R 4025431a2ff076723fc2f621d10c0c47
+T *branch * zipfile-timestamp-fix
+T *sym-zipfile-timestamp-fix *
+T -sym-trunk *
+U dan
+Z 7679dfe9f8ef39802f520b9ec5eb4496
-02ba8a7ba7ba71cd7abd5dd3093ea486f53a025f6972bb444f2da37e0e2fc3b2
\ No newline at end of file
+e2114df18383d111dd5fbac902e08b42a7f4b2b2d6f7bf29574a3722e4a4dad5
\ No newline at end of file
}
}
+
+# The argument is a blob (not a hex string) containing a zip archive.
+# This proc removes the extended timestamp fields from the archive
+# and returns the result.
+#
+proc remove_timestamps {blob} {
+ set hex [binary encode hex $blob]
+ set hex [string map {55540500 00000500} $hex]
+ binary decode hex $hex
+}
+
+
# Argument $file is the name of a zip archive on disk. This function
# executes test cases to check that the results of each of the following
# are the same:
CREATE VIRTUAL TABLE yyy USING zipfile('test.zip', 'test.zip');
} {1 {zipfile constructor requires one argument}}
+#--------------------------------------------------------------------------
+
+db func rt remove_timestamps
+do_execsql_test 5.0 {
+ WITH c(name,mtime,data) AS (
+ SELECT 'a.txt', 946684800, 'abc'
+ )
+ SELECT name,mtime,data FROM zipfile(
+ ( SELECT rt( zipfile(name,NULL,mtime,data) ) FROM c )
+ )
+} {
+ a.txt 946684800 abc
+}
+
+if {[info vars ::UNZIP]!=""} {
+ load_static_extension db fileio
+ forcedelete test.zip
+ do_test 6.0 {
+ execsql {
+ WITH c(name,mtime,data) AS (
+ SELECT 'a.txt', 946684800, 'abc' UNION ALL
+ SELECT 'b.txt', 1000000000, 'abc' UNION ALL
+ SELECT 'c.txt', 1111111000, 'abc'
+ )
+ SELECT writefile('test.zip',
+ ( SELECT rt ( zipfile(name,NULL,mtime,data) ) FROM c )
+ );
+ }
+ forcedelete test_unzip
+ file mkdir test_unzip
+ exec unzip -d test_unzip test.zip
+
+ db eval {
+ SELECT name, mtime FROM fsdir('test_unzip') WHERE name!='test_unzip'
+ ORDER BY name
+ }
+ } [list {*}{
+ test_unzip/a.txt 946684800
+ test_unzip/b.txt 1000000000
+ test_unzip/c.txt 1111111000
+ }]
+}
finish_test
00007A0000000000
}
-do_execsql_test 3.1 {
- WITH contents(name,mtime,data) AS (
- VALUES('a.txt', 1000000, 'contents of a.txt') UNION ALL
- VALUES('b.txt', 1000000, 'contents of b.txt')
- ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
-} [blobliteral $archive]
+if 0 {
+ # This test is broken - the archive generated is slightly different
+ # depending on the zlib version used.
+ do_execsql_test 3.1 {
+ WITH contents(name,mtime,data) AS (
+ VALUES('a.txt', 1000000, 'contents of a.txt') UNION ALL
+ VALUES('b.txt', 1000000, 'contents of b.txt')
+ ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
+ } [blobliteral $archive]
+}
+
set blob [blob $archive]
do_execsql_test 3.2 {
} {/1 .*/}
}
+# Change the "extra info id" for all extended-timestamp fields.
set L [findall 5554 $archive]
for {set i 0} {$i < [llength $L]} {incr i} {
set idx [lindex $L $i]
}
}
-if 0 {
-set blob [db one {
- WITH contents(name,mtime,data) AS (
- VALUES('a.txt', 1000000, 'aaaaaaaaaaaaaaaaaaaaaaa')
- ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
-}]
-set blob [string range $blob 2 end]
-set blob [string range $blob 0 end-1]
-while {[string length $blob]>0} {
- puts [string range $blob 0 63]
- set blob [string range $blob 64 end]
-}
-exit
-}
+# set blob [db one {
+# WITH contents(name,mtime,data) AS (
+# VALUES('a.txt', 1000000, 'aaaaaaaaaaaaaaaaaaaaaaa')
+# ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
+# }]
+# set blob [string range $blob 2 end]
+# set blob [string range $blob 0 end-1]
+# while {[string length $blob]>0} {
+# puts [string range $blob 0 63]
+# set blob [string range $blob 64 end]
+# }
+# exit
set archive2 {
504B0304140000080800D4A52BEC08F54C6E050000001700000005000900612E
} {1 {inflate() failed (0)}}
+
finish_test