2 ** Copyright 2008 D. Richard Hipp and Hipp, Wyrick & Company, Inc.
5 ******************************************************************************
7 ** This file implements a stand-alone utility program that converts
8 ** a binary file (usually an SQLite database) into a text format that
9 ** is compact and friendly to human-readers.
13 ** dbtotxt [OPTIONS] FILENAME
15 ** where OPTIONS are zero or more of:
17 ** --for-cli prepending '.open --hexdb' to the output
19 ** --script The input file is expected to start with a
20 ** zero-terminated SQL string. Output the
21 ** ".open --hexdb" header, then the database
24 ** --pagesize N set the database page size for later reading
26 ** The translation of the database appears on standard output. If the
27 ** --pagesize command-line option is omitted, then the page size is taken
28 ** from the database header.
30 ** Compactness is achieved by suppressing lines of all zero bytes. This
31 ** works well at compressing test databases that are mostly empty. But
32 ** the output will probably be lengthy for a real database containing lots
33 ** of real content. For maximum compactness, it is suggested that test
34 ** databases be constructed with "zeroblob()" rather than "randomblob()"
35 ** used for filler content and with "PRAGMA secure_delete=ON" selected to
36 ** zero-out deleted content.
43 /* Return true if the line is all zeros */
44 static int allZero(unsigned char *aLine
){
46 for(i
=0; i
<16 && aLine
[i
]==0; i
++){}
50 int main(int argc
, char **argv
){
51 int pgsz
= 0; /* page size */
52 int forCli
= 0; /* whether to prepend with .open */
53 int bSQL
= 0; /* Expect and SQL prefix */
54 long szFile
; /* Size of the input file in bytes */
55 FILE *in
; /* Input file */
56 int nSQL
; /* Number of bytes of script */
57 int i
, j
; /* Loop counters */
58 int nErr
= 0; /* Number of errors */
59 const char *zInputFile
= 0; /* Name of the input file */
60 const char *zBaseName
= 0; /* Base name of the file */
61 int lastPage
= 0; /* Last page number shown */
62 int iPage
; /* Current page number */
63 unsigned char *aData
= 0; /* All data */
64 unsigned char *aLine
; /* A single line of the file */
65 unsigned char *aHdr
; /* File header */
66 unsigned char bShow
[256]; /* Characters ok to display */
67 memset(bShow
, '.', sizeof(bShow
));
68 for(i
=' '; i
<='~'; i
++){
69 if( i
!='{' && i
!='}' && i
!='"' && i
!='\\' ) bShow
[i
] = (unsigned char)i
;
71 for(i
=1; i
<argc
; i
++){
72 if( argv
[i
][0]=='-' ){
73 const char *z
= argv
[i
];
76 if( strcmp(z
,"pagesize")==0 ){
79 if( pgsz
<512 || pgsz
>65536 || (pgsz
&(pgsz
-1))!=0 ){
80 fprintf(stderr
, "Page size must be a power of two between"
85 }else if( strcmp(z
,"for-cli")==0 ){
88 }else if( strcmp(z
,"script")==0 ){
93 fprintf(stderr
, "Unknown option: %s\n", argv
[i
]);
95 }else if( zInputFile
){
96 fprintf(stderr
, "Already using a different input file: [%s]\n", argv
[i
]);
103 fprintf(stderr
, "No input file specified.\n");
108 "Usage: %s [--pagesize N] [--script] [--for-cli] FILENAME\n", argv
[0]);
111 in
= fopen(zInputFile
, "rb");
113 fprintf(stderr
, "Cannot open input file [%s]\n", zInputFile
);
116 fseek(in
, 0, SEEK_END
);
120 fprintf(stderr
, "File too short. Minimum size is 100 bytes.\n");
123 aData
= malloc( szFile
+16 );
125 fprintf(stderr
, "Failed to allocate %ld bytes\n", szFile
);
128 if( fread(aData
, szFile
, 1, in
)!=1 ){
129 fprintf(stderr
, "Cannot read file info memory\n");
132 memset(aData
+szFile
, 0, 16);
135 for(i
=0; i
<szFile
&& aData
[i
]!=0; i
++){}
137 fprintf(stderr
, "No zero terminator on SQL script\n");
141 if( szFile
- nSQL
<100 ){
142 fprintf(stderr
, "Less than 100 bytes in the database\n");
150 pgsz
= (aHdr
[16]<<8) | aHdr
[17];
151 if( pgsz
==1 ) pgsz
= 65536;
152 if( pgsz
<512 || (pgsz
&(pgsz
-1))!=0 ){
153 fprintf(stderr
, "Invalid page size in header: %d\n", pgsz
);
157 zBaseName
= zInputFile
;
158 for(i
=0; zInputFile
[i
]; i
++){
159 if( zInputFile
[i
]=='/' && zInputFile
[i
+1]!=0 ) zBaseName
= zInputFile
+i
+1;
162 printf(".open --hexdb\n");
164 printf("| size %d pagesize %d filename %s\n",(int)szFile
,pgsz
,zBaseName
);
165 for(i
=nSQL
; i
<szFile
; i
+=16){
167 if( allZero(aLine
) ) continue;
169 if( lastPage
!=iPage
){
170 printf("| page %d offset %d\n", iPage
, (iPage
-1)*pgsz
);
173 printf("| %5d:", i
-(iPage
-1)*pgsz
);
174 for(j
=0; j
<16; j
++) printf(" %02x", aLine
[j
]);
177 unsigned char c
= (unsigned char)aLine
[j
];
178 fputc( bShow
[c
], stdout
);
182 printf("| end %s\n", zBaseName
);
184 printf("%s\n", aData
);