xref: /sqlite-3.40.0/test/zipfile2.test (revision 6ab91a7a)
1# 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
13package require Tcl 8.6
14
15set 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') }
59  lindex [catchsql {
60    SELECT * FROM hhh;
61    INSERT INTO hhh(name, data) VALUES('1.txt', 'file data');
62  }] 0
63} 1
64
65
66set archive {
67  504B0304140000080000D4A52BEC09F3B6E0110000001100000005000900612E
68  747874555405000140420F00636F6E74656E7473206F6620612E747874504B03
69  04140000080000D4A52BECD98916A7110000001100000005000900622E747874
70  555405000140420F00636F6E74656E7473206F6620622E747874504B01021E03
71  140000080000D4A52BEC09F3B6E0110000001100000005000900000000000000
72  0000A48100000000612E747874555405000140420F00504B01021E0314000008
73  0000D4A52BECD98916A71100000011000000050009000000000000000000A481
74  3D000000622E747874555405000140420F00504B050600000000020002007800
75  00007A0000000000
76}
77
78if 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
89
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
111# Change the "extra info id" for all extended-timestamp fields.
112set 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
137# 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
149
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
164set 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)
170} {1 {inflate() failed (0)}}
171
172# 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}
210
211#-------------------------------------------------------------------------
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
235forcedelete 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}
242
243finish_test
244