/ Check-in [13b786da]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add tests cases for the zipfile extension.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:13b786dafd308b7aef42328f26fe64981c83d524e4bf82ceb7d58afc7146c7d3
User & Date: dan 2018-01-30 17:43:22
Context
2018-01-30
18:33
If a virtual table xColumn method sets an error message using sqlite3_result_error(), use that message in preference to any error message left in the sqlite3_vtab object. check-in: 71e3b715 user: dan tags: trunk
17:43
Add tests cases for the zipfile extension. check-in: 13b786da user: dan tags: trunk
14:07
Prevent users from creating zipfile() virtual tables without an argument. check-in: 81fdbe0c user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/misc/zipfile.c.

44
45
46
47
48
49
50

51
52
53
54
55










56


57
58
59
60
61
62
63
...
279
280
281
282
283
284
285
286
287
288
289

290
291
292
293
294
295
296
297
298
299
300
...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
...
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
....
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
#include <errno.h>

#include <zlib.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

#ifndef SQLITE_AMALGAMATION

typedef sqlite3_int64 i64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
#define MIN(a,b) ((a)<(b) ? (a) : (b))










#endif



static const char ZIPFILE_SCHEMA[] = 
  "CREATE TABLE y("
    "name PRIMARY KEY,"  /* 0: Name of file in zip archive */
    "mode,"              /* 1: POSIX mode for file */
    "mtime,"             /* 2: Last modification time (secs since 1970)*/
    "sz,"                /* 3: Size of object */
................................................................................
/*
** If string zIn is quoted, dequote it in place. Otherwise, if the string
** is not quoted, do nothing.
*/
static void zipfileDequote(char *zIn){
  char q = zIn[0];
  if( q=='"' || q=='\'' || q=='`' || q=='[' ){
    char c;
    int iIn = 1;
    int iOut = 0;
    if( q=='[' ) q = ']';

    while( (c = zIn[iIn++]) ){
      if( c==q ){
        if( zIn[iIn++]!=q ) break;
      }
      zIn[iOut++] = c;
    }
    zIn[iOut] = '\0';
  }
}

/*
................................................................................
static int zipfileClose(sqlite3_vtab_cursor *cur){
  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab);
  ZipfileCsr **pp;
  zipfileResetCursor(pCsr);

  /* Remove this cursor from the ZipfileTab.pCsrList list. */
  for(pp=&pTab->pCsrList; *pp; pp=&((*pp)->pCsrNext)){
    if( *pp==pCsr ){ 
      *pp = pCsr->pCsrNext;
      break;
    }
  }

  sqlite3_free(pCsr);
  return SQLITE_OK;
}

/*
** Set the error message for the virtual table associated with cursor
................................................................................
** Buffer aIn (size nIn bytes) contains compressed data. Uncompressed, the
** size is nOut bytes. This function uncompresses the data and sets the
** return value in context pCtx to the result (a blob).
**
** If an error occurs, an error code is left in pCtx instead.
*/
static void zipfileInflate(
  sqlite3_context *pCtx,          /* Store error here, if any */
  const u8 *aIn,                  /* Compressed data */
  int nIn,                        /* Size of buffer aIn[] in bytes */
  int nOut                        /* Expected output size */
){
  u8 *aRes = sqlite3_malloc(nOut);
  if( aRes==0 ){
    sqlite3_result_error_nomem(pCtx);
................................................................................
    pEOCD->iFirstDisk = zipfileRead16(aRead);
    pEOCD->nEntry = zipfileRead16(aRead);
    pEOCD->nEntryTotal = zipfileRead16(aRead);
    pEOCD->nSize = zipfileRead32(aRead);
    pEOCD->iOffset = zipfileRead32(aRead);
  }

  return SQLITE_OK;
}

/*
** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry 
** and ends with pLastEntry. If argument pBefore is NULL, then pNew is added
** to the end of the list. Otherwise, it is added to the list immediately
** before pBefore (which is guaranteed to be a part of said list).







>





>
>
>
>
>
>
>
>
>
>

>
>







 







<



>
|
<
|
<







 







|
<
|
<
<
<







 







|







 







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
292
293
294
295
296
297
298

299
300
301
302
303

304

305
306
307
308
309
310
311
...
452
453
454
455
456
457
458
459

460



461
462
463
464
465
466
467
...
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
....
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
#include <errno.h>

#include <zlib.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

#ifndef SQLITE_AMALGAMATION

typedef sqlite3_int64 i64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
#define MIN(a,b) ((a)<(b) ? (a) : (b))

#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
# define NEVER(X)       (X)
#endif

#endif   /* SQLITE_AMALGAMATION */

static const char ZIPFILE_SCHEMA[] = 
  "CREATE TABLE y("
    "name PRIMARY KEY,"  /* 0: Name of file in zip archive */
    "mode,"              /* 1: POSIX mode for file */
    "mtime,"             /* 2: Last modification time (secs since 1970)*/
    "sz,"                /* 3: Size of object */
................................................................................
/*
** If string zIn is quoted, dequote it in place. Otherwise, if the string
** is not quoted, do nothing.
*/
static void zipfileDequote(char *zIn){
  char q = zIn[0];
  if( q=='"' || q=='\'' || q=='`' || q=='[' ){

    int iIn = 1;
    int iOut = 0;
    if( q=='[' ) q = ']';
    while( ALWAYS(zIn[iIn]) ){
      char c = zIn[iIn++];

      if( c==q && zIn[iIn++]!=q ) break;

      zIn[iOut++] = c;
    }
    zIn[iOut] = '\0';
  }
}

/*
................................................................................
static int zipfileClose(sqlite3_vtab_cursor *cur){
  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab);
  ZipfileCsr **pp;
  zipfileResetCursor(pCsr);

  /* Remove this cursor from the ZipfileTab.pCsrList list. */
  for(pp=&pTab->pCsrList; *pp!=pCsr; pp=&((*pp)->pCsrNext));

  *pp = pCsr->pCsrNext;




  sqlite3_free(pCsr);
  return SQLITE_OK;
}

/*
** Set the error message for the virtual table associated with cursor
................................................................................
** Buffer aIn (size nIn bytes) contains compressed data. Uncompressed, the
** size is nOut bytes. This function uncompresses the data and sets the
** return value in context pCtx to the result (a blob).
**
** If an error occurs, an error code is left in pCtx instead.
*/
static void zipfileInflate(
  sqlite3_context *pCtx,          /* Store result here */
  const u8 *aIn,                  /* Compressed data */
  int nIn,                        /* Size of buffer aIn[] in bytes */
  int nOut                        /* Expected output size */
){
  u8 *aRes = sqlite3_malloc(nOut);
  if( aRes==0 ){
    sqlite3_result_error_nomem(pCtx);
................................................................................
    pEOCD->iFirstDisk = zipfileRead16(aRead);
    pEOCD->nEntry = zipfileRead16(aRead);
    pEOCD->nEntryTotal = zipfileRead16(aRead);
    pEOCD->nSize = zipfileRead32(aRead);
    pEOCD->iOffset = zipfileRead32(aRead);
  }

  return rc;
}

/*
** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry 
** and ends with pLastEntry. If argument pBefore is NULL, then pNew is added
** to the end of the list. Otherwise, it is added to the list immediately
** before pBefore (which is guaranteed to be a part of said list).

Added test/zipfile2.test.















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# 2018 January 30
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix zipfile2

ifcapable !vtab {
  finish_test; return
}
if {[catch {load_static_extension db zipfile} error]} {
  puts "Skipping zipfile2 tests, hit load error: $error"
  finish_test; return
}

proc blobliteral {str} {
  set concat [string map {" " "" "\n" ""} $str]
  return "X'$concat'"
}

proc blob {str} {
  binary decode hex $str
}

proc findall {needle haystack} {
  set L [list]
  set start 0
  while { [set idx [string first $needle $haystack $start]]>=0 } {
    lappend L $idx
    set start [expr $idx+1]
  }
  set L
}

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE aaa USING zipfile('testzip');
  CREATE VIRTUAL TABLE bbb USING zipfile("testzip");
  CREATE VIRTUAL TABLE ccc USING zipfile(`testzip`);
  CREATE VIRTUAL TABLE ddd USING zipfile([testzip]);
  CREATE VIRTUAL TABLE eee USING zipfile(testzip);
  CREATE VIRTUAL TABLE fff USING zipfile('test''zip');
}

do_test 2.0 {
  forcedelete testdir
  file mkdir testdir
  execsql { CREATE VIRTUAL TABLE hhh USING zipfile('testdir') }
  catchsql { SELECT * FROM hhh } 
} {1 {error in fread()}}


set archive {
  504B0304140000080000D4A52BEC09F3B6E0110000001100000005000900612E
  747874555405000140420F00636F6E74656E7473206F6620612E747874504B03
  04140000080000D4A52BECD98916A7110000001100000005000900622E747874
  555405000140420F00636F6E74656E7473206F6620622E747874504B01021E03
  140000080000D4A52BEC09F3B6E0110000001100000005000900000000000000
  0000A48100000000612E747874555405000140420F00504B01021E0314000008
  0000D4A52BECD98916A71100000011000000050009000000000000000000A481
  3D000000622E747874555405000140420F00504B050600000000020002007800
  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]

set blob [blob $archive]
do_execsql_test 3.2 {
  SELECT name,mtime,data FROM zipfile($blob)
} {
  a.txt 1000000 {contents of a.txt} 
  b.txt 1000000 {contents of b.txt}
}

# Corrupt each of the 0x50 0x4B (ascii "PK") headers in the file
# Test that in each case this causes an error.
#
set L [findall 504B $archive]
for {set i 0} {$i < [llength $L]} {incr i} {
  set idx [lindex $L $i]
  set a [string replace $archive $idx [expr $idx+3] 0000]
  set blob [blob $a]
  do_catchsql_test 3.3.$i {
    SELECT name,mtime,data FROM zipfile($blob)
  } {/1 .*/}
}

set L [findall 5554 $archive]
for {set i 0} {$i < [llength $L]} {incr i} {
  set idx [lindex $L $i]
  set a [string replace $archive $idx [expr $idx+3] 1234]
  set blob [blob $a]
  do_execsql_test 3.4.$i {
    SELECT name,data FROM zipfile($blob)
  } {
    a.txt {contents of a.txt} 
    b.txt {contents of b.txt}
  }
}

for {set i 0} {$i < [llength $L]} {incr i} {
  set idx [lindex $L $i]
  set a [string replace $archive [expr $idx+8] [expr $idx+9] 00]
  set blob [blob $a]
  do_execsql_test 3.5.$i {
    SELECT name,data FROM zipfile($blob)
  } {
    a.txt {contents of a.txt} 
    b.txt {contents of b.txt}
  }
}

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 archive2 {
  504B0304140000080800D4A52BEC08F54C6E050000001700000005000900612E
  747874555405000140420F004B4CC40A00504B01021E03140000080800D4A52B
  EC08F54C6E0500000017000000050009000000000000000000A4810000000061
  2E747874555405000140420F00504B050600000000010001003C000000310000
  000000
}
set blob [blob $archive2]
do_execsql_test 4.0 {
  SELECT name,mtime,data,method FROM zipfile($blob)
} {
  a.txt 1000000 aaaaaaaaaaaaaaaaaaaaaaa 8
}

breakpoint
set L [findall 17000000 $archive2]
set a $archive2
foreach i $L { set a [string replace $a $i [expr $i+7] 16000000] }
set blob [blob $a]
do_catchsql_test 4.1 {
  SELECT name,mtime,data,method FROM zipfile($blob)
} {1 {SQL logic error}}



finish_test

Added test/zipfilefault.test.







































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 2018 January 30
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix zipfilefault

ifcapable !vtab {
  finish_test; return
}
if {[catch {load_static_extension db zipfile} error]} {
  puts "Skipping zipfile2 tests, hit load error: $error"
  finish_test; return
}

faultsim_save_and_close
do_faultsim_test 1 -prep {
  faultsim_restore_and_reopen
  load_static_extension db zipfile
  execsql { DROP TABLE IF EXISTS aaa }
} -body {
  execsql { CREATE VIRTUAL TABLE aaa USING zipfile('test.zip') }
} -test {
  faultsim_test_result {0 {}} 
}

forcedelete test.zip
sqlite3 db test.db
load_static_extension db zipfile
do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE setup USING zipfile('test.zip');
  INSERT INTO setup(name, data) VALUES('a.txt', '1234567890');
}

do_faultsim_test 2 -faults oom* -body {
  execsql { SELECT name,data FROM zipfile('test.zip') }
} -test {
  faultsim_test_result {0 {a.txt 1234567890}} 
}

forcedelete test.zip
reset_db
load_static_extension db zipfile
do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE setup USING zipfile('test.zip');
  INSERT INTO setup(name, data) VALUES('a.txt', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa');
}

do_faultsim_test 2 -faults oom* -body {
  execsql { SELECT name,data FROM zipfile('test.zip') }
} -test {
  faultsim_test_result {0 {a.txt aaaaaaaaaaaaaaaaaaaaaaaaaaaa}} 
}


finish_test