blob: 987e4f0cfdc81962e41df701b0c5301ede9d580d [file] [log] [blame]
dan2f7260d2018-01-30 17:43:22 +00001# 2018 January 30
2#
3# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
5#
6# May you do good and not evil.
7# May you find forgiveness for yourself and forgive others.
8# May you share freely, never taking more than you give.
9#
10#***********************************************************************
11#
12
mistachkinb5a4a702018-03-16 23:54:26 +000013package require Tcl 8.6
14
dan2f7260d2018-01-30 17:43:22 +000015set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17set testprefix zipfile2
18
19ifcapable !vtab {
20 finish_test; return
21}
22if {[catch {load_static_extension db zipfile} error]} {
23 puts "Skipping zipfile2 tests, hit load error: $error"
24 finish_test; return
25}
26
27proc blobliteral {str} {
28 set concat [string map {" " "" "\n" ""} $str]
29 return "X'$concat'"
30}
31
32proc blob {str} {
33 binary decode hex $str
34}
35
36proc findall {needle haystack} {
37 set L [list]
38 set start 0
39 while { [set idx [string first $needle $haystack $start]]>=0 } {
40 lappend L $idx
41 set start [expr $idx+1]
42 }
43 set L
44}
45
46do_execsql_test 1.0 {
47 CREATE VIRTUAL TABLE aaa USING zipfile('testzip');
48 CREATE VIRTUAL TABLE bbb USING zipfile("testzip");
49 CREATE VIRTUAL TABLE ccc USING zipfile(`testzip`);
50 CREATE VIRTUAL TABLE ddd USING zipfile([testzip]);
51 CREATE VIRTUAL TABLE eee USING zipfile(testzip);
52 CREATE VIRTUAL TABLE fff USING zipfile('test''zip');
53}
54
55do_test 2.0 {
56 forcedelete testdir
57 file mkdir testdir
58 execsql { CREATE VIRTUAL TABLE hhh USING zipfile('testdir') }
dana67d02f2018-04-19 20:06:10 +000059 lindex [catchsql {
60 SELECT * FROM hhh;
61 INSERT INTO hhh(name, data) VALUES('1.txt', 'file data');
62 }] 0
63} 1
dan2f7260d2018-01-30 17:43:22 +000064
65
66set archive {
67 504B0304140000080000D4A52BEC09F3B6E0110000001100000005000900612E
68 747874555405000140420F00636F6E74656E7473206F6620612E747874504B03
69 04140000080000D4A52BECD98916A7110000001100000005000900622E747874
70 555405000140420F00636F6E74656E7473206F6620622E747874504B01021E03
71 140000080000D4A52BEC09F3B6E0110000001100000005000900000000000000
72 0000A48100000000612E747874555405000140420F00504B01021E0314000008
73 0000D4A52BECD98916A71100000011000000050009000000000000000000A481
74 3D000000622E747874555405000140420F00504B050600000000020002007800
75 00007A0000000000
76}
77
dan44091ed2018-01-31 19:13:31 +000078if 0 {
79 # This test is broken - the archive generated is slightly different
80 # depending on the zlib version used.
81 do_execsql_test 3.1 {
82 WITH contents(name,mtime,data) AS (
83 VALUES('a.txt', 1000000, 'contents of a.txt') UNION ALL
84 VALUES('b.txt', 1000000, 'contents of b.txt')
85 ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
86 } [blobliteral $archive]
87}
88
dan2f7260d2018-01-30 17:43:22 +000089
90set blob [blob $archive]
91do_execsql_test 3.2 {
92 SELECT name,mtime,data FROM zipfile($blob)
93} {
94 a.txt 1000000 {contents of a.txt}
95 b.txt 1000000 {contents of b.txt}
96}
97
98# Corrupt each of the 0x50 0x4B (ascii "PK") headers in the file
99# Test that in each case this causes an error.
100#
101set L [findall 504B $archive]
102for {set i 0} {$i < [llength $L]} {incr i} {
103 set idx [lindex $L $i]
104 set a [string replace $archive $idx [expr $idx+3] 0000]
105 set blob [blob $a]
106 do_catchsql_test 3.3.$i {
107 SELECT name,mtime,data FROM zipfile($blob)
108 } {/1 .*/}
109}
110
dan44091ed2018-01-31 19:13:31 +0000111# Change the "extra info id" for all extended-timestamp fields.
dan2f7260d2018-01-30 17:43:22 +0000112set L [findall 5554 $archive]
113for {set i 0} {$i < [llength $L]} {incr i} {
114 set idx [lindex $L $i]
115 set a [string replace $archive $idx [expr $idx+3] 1234]
116 set blob [blob $a]
117 do_execsql_test 3.4.$i {
118 SELECT name,data FROM zipfile($blob)
119 } {
120 a.txt {contents of a.txt}
121 b.txt {contents of b.txt}
122 }
123}
124
125for {set i 0} {$i < [llength $L]} {incr i} {
126 set idx [lindex $L $i]
127 set a [string replace $archive [expr $idx+8] [expr $idx+9] 00]
128 set blob [blob $a]
129 do_execsql_test 3.5.$i {
130 SELECT name,data FROM zipfile($blob)
131 } {
132 a.txt {contents of a.txt}
133 b.txt {contents of b.txt}
134 }
135}
136
dan44091ed2018-01-31 19:13:31 +0000137# set blob [db one {
138# WITH contents(name,mtime,data) AS (
139# VALUES('a.txt', 1000000, 'aaaaaaaaaaaaaaaaaaaaaaa')
140# ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
141# }]
142# set blob [string range $blob 2 end]
143# set blob [string range $blob 0 end-1]
144# while {[string length $blob]>0} {
145# puts [string range $blob 0 63]
146# set blob [string range $blob 64 end]
147# }
148# exit
dan2f7260d2018-01-30 17:43:22 +0000149
150set archive2 {
151 504B0304140000080800D4A52BEC08F54C6E050000001700000005000900612E
152 747874555405000140420F004B4CC40A00504B01021E03140000080800D4A52B
153 EC08F54C6E0500000017000000050009000000000000000000A4810000000061
154 2E747874555405000140420F00504B050600000000010001003C000000310000
155 000000
156}
157set blob [blob $archive2]
158do_execsql_test 4.0 {
159 SELECT name,mtime,data,method FROM zipfile($blob)
160} {
161 a.txt 1000000 aaaaaaaaaaaaaaaaaaaaaaa 8
162}
163
dan2f7260d2018-01-30 17:43:22 +0000164set L [findall 17000000 $archive2]
165set a $archive2
166foreach i $L { set a [string replace $a $i [expr $i+7] 16000000] }
167set blob [blob $a]
168do_catchsql_test 4.1 {
169 SELECT name,mtime,data,method FROM zipfile($blob)
dan099fa842018-01-30 18:33:23 +0000170} {1 {inflate() failed (0)}}
dan2f7260d2018-01-30 17:43:22 +0000171
dan15daa6b2018-02-01 19:41:23 +0000172# Check the response to an unknown compression method (set data to NULL).
173set blob [blob [string map {0800 0900} $archive2]]
174do_execsql_test 4.2 {
175 SELECT name,mtime,data IS NULL,method FROM zipfile($blob)
176} {a.txt 1000000 1 9}
177
178# Corrupt the EOCDS signature bytes in various ways.
179foreach {tn sub} {
180 1 {504B0500}
181 2 {504B0006}
182 3 {50000506}
183 4 {004B0506}
184} {
185 set blob [blob [string map [list 504B0506 $sub] $archive2]]
186 do_catchsql_test 4.3.$tn {
187 SELECT * FROM zipfile($blob)
188 } {1 {cannot find end of central directory record}}
189}
190
191#-------------------------------------------------------------------------
192# Test that a zero-length file with a '/' at the end is treated as
193# a directory (data IS NULL). Even if the mode doesn't indicate
194# that it is a directory.
195
196do_test 5.0 {
197 set blob [db one {
198 WITH c(n, d) AS (
199 SELECT 'notadir', ''
200 )
201 SELECT zipfile(n, d) FROM c
202 }]
203
204 set hex [binary encode hex $blob]
205 set hex [string map {6e6f7461646972 6e6f746164692f} $hex]
206 set blob2 [binary decode hex $hex]
207
208 execsql { SELECT name, data IS NULL FROM zipfile($blob2) }
209} {notadi/ 1}
dan2f7260d2018-01-30 17:43:22 +0000210
dand30830e2018-03-20 12:12:06 +0000211#-------------------------------------------------------------------------
212# Test that duplicate entries may not be created using UPDATE
213# statements.
214#
215forcedelete test.zip
216do_execsql_test 6.0 {
217 CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip');
218 INSERT INTO temp.zip (name,data) VALUES ('test1','test');
219 INSERT INTO temp.zip (name,data) VALUES ('test2','test');
220}
221do_catchsql_test 6.1 {
222 UPDATE temp.zip SET name='test1' WHERE name='test2'
223} {1 {duplicate name: "test1"}}
224
225forcedelete test.zip
226do_catchsql_test 6.2 {
227 DROP TABLE zip;
228 CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip');
229 INSERT INTO temp.zip (name,data) VALUES ('test','test');
230 UPDATE temp.zip set name=name||'new' where name='test';
231 INSERT INTO temp.zip (name,data) VALUES ('test','test');
232 UPDATE temp.zip set name=name||'new' where name='test';
233} {1 {duplicate name: "testnew"}}
234
dan93c803e2018-03-20 13:26:01 +0000235forcedelete test.zip
236do_execsql_test 6.3 {
237 INSERT INTO temp.zip (name,data) VALUES ('test1','test');
238 INSERT INTO temp.zip (name,data) VALUES ('test2','test');
239 UPDATE OR REPLACE zip SET name='test2' WHERE name='test1';
240 SELECT name FROM zip;
241} {test2}
dan44091ed2018-01-31 19:13:31 +0000242
dan2f7260d2018-01-30 17:43:22 +0000243finish_test