12f7260deSdan# 2018 January 30 22f7260deSdan# 32f7260deSdan# The author disclaims copyright to this source code. In place of 42f7260deSdan# a legal notice, here is a blessing: 52f7260deSdan# 62f7260deSdan# May you do good and not evil. 72f7260deSdan# May you find forgiveness for yourself and forgive others. 82f7260deSdan# May you share freely, never taking more than you give. 92f7260deSdan# 102f7260deSdan#*********************************************************************** 112f7260deSdan# 122f7260deSdan 13b5a4a705Smistachkinpackage require Tcl 8.6 14b5a4a705Smistachkin 152f7260deSdanset testdir [file dirname $argv0] 162f7260deSdansource $testdir/tester.tcl 172f7260deSdanset testprefix zipfile2 182f7260deSdan 192f7260deSdanifcapable !vtab { 202f7260deSdan finish_test; return 212f7260deSdan} 222f7260deSdanif {[catch {load_static_extension db zipfile} error]} { 232f7260deSdan puts "Skipping zipfile2 tests, hit load error: $error" 242f7260deSdan finish_test; return 252f7260deSdan} 262f7260deSdan 272f7260deSdanproc blobliteral {str} { 282f7260deSdan set concat [string map {" " "" "\n" ""} $str] 292f7260deSdan return "X'$concat'" 302f7260deSdan} 312f7260deSdan 322f7260deSdanproc blob {str} { 332f7260deSdan binary decode hex $str 342f7260deSdan} 352f7260deSdan 362f7260deSdanproc findall {needle haystack} { 372f7260deSdan set L [list] 382f7260deSdan set start 0 392f7260deSdan while { [set idx [string first $needle $haystack $start]]>=0 } { 402f7260deSdan lappend L $idx 412f7260deSdan set start [expr $idx+1] 422f7260deSdan } 432f7260deSdan set L 442f7260deSdan} 452f7260deSdan 462f7260deSdando_execsql_test 1.0 { 472f7260deSdan CREATE VIRTUAL TABLE aaa USING zipfile('testzip'); 482f7260deSdan CREATE VIRTUAL TABLE bbb USING zipfile("testzip"); 492f7260deSdan CREATE VIRTUAL TABLE ccc USING zipfile(`testzip`); 502f7260deSdan CREATE VIRTUAL TABLE ddd USING zipfile([testzip]); 512f7260deSdan CREATE VIRTUAL TABLE eee USING zipfile(testzip); 522f7260deSdan CREATE VIRTUAL TABLE fff USING zipfile('test''zip'); 532f7260deSdan} 542f7260deSdan 552f7260deSdando_test 2.0 { 562f7260deSdan forcedelete testdir 572f7260deSdan file mkdir testdir 582f7260deSdan execsql { CREATE VIRTUAL TABLE hhh USING zipfile('testdir') } 59*a67d02f5Sdan lindex [catchsql { 60*a67d02f5Sdan SELECT * FROM hhh; 61*a67d02f5Sdan INSERT INTO hhh(name, data) VALUES('1.txt', 'file data'); 62*a67d02f5Sdan }] 0 63*a67d02f5Sdan} 1 642f7260deSdan 652f7260deSdan 662f7260deSdanset archive { 672f7260deSdan 504B0304140000080000D4A52BEC09F3B6E0110000001100000005000900612E 682f7260deSdan 747874555405000140420F00636F6E74656E7473206F6620612E747874504B03 692f7260deSdan 04140000080000D4A52BECD98916A7110000001100000005000900622E747874 702f7260deSdan 555405000140420F00636F6E74656E7473206F6620622E747874504B01021E03 712f7260deSdan 140000080000D4A52BEC09F3B6E0110000001100000005000900000000000000 722f7260deSdan 0000A48100000000612E747874555405000140420F00504B01021E0314000008 732f7260deSdan 0000D4A52BECD98916A71100000011000000050009000000000000000000A481 742f7260deSdan 3D000000622E747874555405000140420F00504B050600000000020002007800 752f7260deSdan 00007A0000000000 762f7260deSdan} 772f7260deSdan 7844091ed3Sdanif 0 { 7944091ed3Sdan # This test is broken - the archive generated is slightly different 8044091ed3Sdan # depending on the zlib version used. 812f7260deSdan do_execsql_test 3.1 { 822f7260deSdan WITH contents(name,mtime,data) AS ( 832f7260deSdan VALUES('a.txt', 1000000, 'contents of a.txt') UNION ALL 842f7260deSdan VALUES('b.txt', 1000000, 'contents of b.txt') 852f7260deSdan ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents; 862f7260deSdan } [blobliteral $archive] 8744091ed3Sdan} 8844091ed3Sdan 892f7260deSdan 902f7260deSdanset blob [blob $archive] 912f7260deSdando_execsql_test 3.2 { 922f7260deSdan SELECT name,mtime,data FROM zipfile($blob) 932f7260deSdan} { 942f7260deSdan a.txt 1000000 {contents of a.txt} 952f7260deSdan b.txt 1000000 {contents of b.txt} 962f7260deSdan} 972f7260deSdan 982f7260deSdan# Corrupt each of the 0x50 0x4B (ascii "PK") headers in the file 992f7260deSdan# Test that in each case this causes an error. 1002f7260deSdan# 1012f7260deSdanset L [findall 504B $archive] 1022f7260deSdanfor {set i 0} {$i < [llength $L]} {incr i} { 1032f7260deSdan set idx [lindex $L $i] 1042f7260deSdan set a [string replace $archive $idx [expr $idx+3] 0000] 1052f7260deSdan set blob [blob $a] 1062f7260deSdan do_catchsql_test 3.3.$i { 1072f7260deSdan SELECT name,mtime,data FROM zipfile($blob) 1082f7260deSdan } {/1 .*/} 1092f7260deSdan} 1102f7260deSdan 11144091ed3Sdan# Change the "extra info id" for all extended-timestamp fields. 1122f7260deSdanset L [findall 5554 $archive] 1132f7260deSdanfor {set i 0} {$i < [llength $L]} {incr i} { 1142f7260deSdan set idx [lindex $L $i] 1152f7260deSdan set a [string replace $archive $idx [expr $idx+3] 1234] 1162f7260deSdan set blob [blob $a] 1172f7260deSdan do_execsql_test 3.4.$i { 1182f7260deSdan SELECT name,data FROM zipfile($blob) 1192f7260deSdan } { 1202f7260deSdan a.txt {contents of a.txt} 1212f7260deSdan b.txt {contents of b.txt} 1222f7260deSdan } 1232f7260deSdan} 1242f7260deSdan 1252f7260deSdanfor {set i 0} {$i < [llength $L]} {incr i} { 1262f7260deSdan set idx [lindex $L $i] 1272f7260deSdan set a [string replace $archive [expr $idx+8] [expr $idx+9] 00] 1282f7260deSdan set blob [blob $a] 1292f7260deSdan do_execsql_test 3.5.$i { 1302f7260deSdan SELECT name,data FROM zipfile($blob) 1312f7260deSdan } { 1322f7260deSdan a.txt {contents of a.txt} 1332f7260deSdan b.txt {contents of b.txt} 1342f7260deSdan } 1352f7260deSdan} 1362f7260deSdan 13744091ed3Sdan# set blob [db one { 13844091ed3Sdan# WITH contents(name,mtime,data) AS ( 13944091ed3Sdan# VALUES('a.txt', 1000000, 'aaaaaaaaaaaaaaaaaaaaaaa') 14044091ed3Sdan# ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents; 14144091ed3Sdan# }] 14244091ed3Sdan# set blob [string range $blob 2 end] 14344091ed3Sdan# set blob [string range $blob 0 end-1] 14444091ed3Sdan# while {[string length $blob]>0} { 14544091ed3Sdan# puts [string range $blob 0 63] 14644091ed3Sdan# set blob [string range $blob 64 end] 14744091ed3Sdan# } 14844091ed3Sdan# exit 1492f7260deSdan 1502f7260deSdanset archive2 { 1512f7260deSdan 504B0304140000080800D4A52BEC08F54C6E050000001700000005000900612E 1522f7260deSdan 747874555405000140420F004B4CC40A00504B01021E03140000080800D4A52B 1532f7260deSdan EC08F54C6E0500000017000000050009000000000000000000A4810000000061 1542f7260deSdan 2E747874555405000140420F00504B050600000000010001003C000000310000 1552f7260deSdan 000000 1562f7260deSdan} 1572f7260deSdanset blob [blob $archive2] 1582f7260deSdando_execsql_test 4.0 { 1592f7260deSdan SELECT name,mtime,data,method FROM zipfile($blob) 1602f7260deSdan} { 1612f7260deSdan a.txt 1000000 aaaaaaaaaaaaaaaaaaaaaaa 8 1622f7260deSdan} 1632f7260deSdan 1642f7260deSdanset L [findall 17000000 $archive2] 1652f7260deSdanset a $archive2 1662f7260deSdanforeach i $L { set a [string replace $a $i [expr $i+7] 16000000] } 1672f7260deSdanset blob [blob $a] 1682f7260deSdando_catchsql_test 4.1 { 1692f7260deSdan SELECT name,mtime,data,method FROM zipfile($blob) 170099fa847Sdan} {1 {inflate() failed (0)}} 1712f7260deSdan 17215daa6b5Sdan# Check the response to an unknown compression method (set data to NULL). 17315daa6b5Sdanset blob [blob [string map {0800 0900} $archive2]] 17415daa6b5Sdando_execsql_test 4.2 { 17515daa6b5Sdan SELECT name,mtime,data IS NULL,method FROM zipfile($blob) 17615daa6b5Sdan} {a.txt 1000000 1 9} 17715daa6b5Sdan 17815daa6b5Sdan# Corrupt the EOCDS signature bytes in various ways. 17915daa6b5Sdanforeach {tn sub} { 18015daa6b5Sdan 1 {504B0500} 18115daa6b5Sdan 2 {504B0006} 18215daa6b5Sdan 3 {50000506} 18315daa6b5Sdan 4 {004B0506} 18415daa6b5Sdan} { 18515daa6b5Sdan set blob [blob [string map [list 504B0506 $sub] $archive2]] 18615daa6b5Sdan do_catchsql_test 4.3.$tn { 18715daa6b5Sdan SELECT * FROM zipfile($blob) 18815daa6b5Sdan } {1 {cannot find end of central directory record}} 18915daa6b5Sdan} 19015daa6b5Sdan 19115daa6b5Sdan#------------------------------------------------------------------------- 19215daa6b5Sdan# Test that a zero-length file with a '/' at the end is treated as 19315daa6b5Sdan# a directory (data IS NULL). Even if the mode doesn't indicate 19415daa6b5Sdan# that it is a directory. 19515daa6b5Sdan 19615daa6b5Sdando_test 5.0 { 19715daa6b5Sdan set blob [db one { 19815daa6b5Sdan WITH c(n, d) AS ( 19915daa6b5Sdan SELECT 'notadir', '' 20015daa6b5Sdan ) 20115daa6b5Sdan SELECT zipfile(n, d) FROM c 20215daa6b5Sdan }] 20315daa6b5Sdan 20415daa6b5Sdan set hex [binary encode hex $blob] 20515daa6b5Sdan set hex [string map {6e6f7461646972 6e6f746164692f} $hex] 20615daa6b5Sdan set blob2 [binary decode hex $hex] 20715daa6b5Sdan 20815daa6b5Sdan execsql { SELECT name, data IS NULL FROM zipfile($blob2) } 20915daa6b5Sdan} {notadi/ 1} 2102f7260deSdan 211d30830e4Sdan#------------------------------------------------------------------------- 212d30830e4Sdan# Test that duplicate entries may not be created using UPDATE 213d30830e4Sdan# statements. 214d30830e4Sdan# 215d30830e4Sdanforcedelete test.zip 216d30830e4Sdando_execsql_test 6.0 { 217d30830e4Sdan CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip'); 218d30830e4Sdan INSERT INTO temp.zip (name,data) VALUES ('test1','test'); 219d30830e4Sdan INSERT INTO temp.zip (name,data) VALUES ('test2','test'); 220d30830e4Sdan} 221d30830e4Sdando_catchsql_test 6.1 { 222d30830e4Sdan UPDATE temp.zip SET name='test1' WHERE name='test2' 223d30830e4Sdan} {1 {duplicate name: "test1"}} 224d30830e4Sdan 225d30830e4Sdanforcedelete test.zip 226d30830e4Sdando_catchsql_test 6.2 { 227d30830e4Sdan DROP TABLE zip; 228d30830e4Sdan CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip'); 229d30830e4Sdan INSERT INTO temp.zip (name,data) VALUES ('test','test'); 230d30830e4Sdan UPDATE temp.zip set name=name||'new' where name='test'; 231d30830e4Sdan INSERT INTO temp.zip (name,data) VALUES ('test','test'); 232d30830e4Sdan UPDATE temp.zip set name=name||'new' where name='test'; 233d30830e4Sdan} {1 {duplicate name: "testnew"}} 234d30830e4Sdan 23593c803e9Sdanforcedelete test.zip 23693c803e9Sdando_execsql_test 6.3 { 23793c803e9Sdan INSERT INTO temp.zip (name,data) VALUES ('test1','test'); 23893c803e9Sdan INSERT INTO temp.zip (name,data) VALUES ('test2','test'); 23993c803e9Sdan UPDATE OR REPLACE zip SET name='test2' WHERE name='test1'; 24093c803e9Sdan SELECT name FROM zip; 24193c803e9Sdan} {test2} 24244091ed3Sdan 2432f7260deSdanfinish_test 244