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 [--pagesize N] FILENAME
15 ** The translation of the database appears on standard output. If the
16 ** --pagesize command-line option is omitted, then the page size is taken
17 ** from the database header.
19 ** Compactness is achieved by suppressing lines of all zero bytes. This
20 ** works well at compressing test databases that are mostly empty. But
21 ** the output will probably be lengthy for a real database containing lots
22 ** of real content. For maximum compactness, it is suggested that test
23 ** databases be constructed with "zeroblob()" rather than "randomblob()"
24 ** used for filler content and with "PRAGMA secure_delete=ON" selected to
25 ** zero-out deleted content.
32 /* Return true if the line is all zeros */
33 static int allZero(unsigned char *aLine
){
35 for(i
=0; i
<16 && aLine
[i
]==0; i
++){}
39 int main(int argc
, char **argv
){
40 int pgsz
= 0; /* page size */
41 long szFile
; /* Size of the input file in bytes */
42 FILE *in
; /* Input file */
43 int i
, j
; /* Loop counters */
44 int nErr
= 0; /* Number of errors */
45 const char *zInputFile
= 0; /* Name of the input file */
46 const char *zBaseName
= 0; /* Base name of the file */
47 int lastPage
= 0; /* Last page number shown */
48 int iPage
; /* Current page number */
49 unsigned char aLine
[16]; /* A single line of the file */
50 unsigned char aHdr
[100]; /* File header */
51 unsigned char bShow
[256]; /* Characters ok to display */
52 memset(bShow
, '.', sizeof(bShow
));
53 for(i
=' '; i
<='~'; i
++){
54 if( i
!='{' && i
!='}' && i
!='"' && i
!='\\' ) bShow
[i
] = (unsigned char)i
;
56 for(i
=1; i
<argc
; i
++){
57 if( argv
[i
][0]=='-' ){
58 const char *z
= argv
[i
];
61 if( strcmp(z
,"pagesize")==0 ){
64 if( pgsz
<512 || pgsz
>65536 || (pgsz
&(pgsz
-1))!=0 ){
65 fprintf(stderr
, "Page size must be a power of two between"
71 fprintf(stderr
, "Unknown option: %s\n", argv
[i
]);
73 }else if( zInputFile
){
74 fprintf(stderr
, "Already using a different input file: [%s]\n", argv
[i
]);
81 fprintf(stderr
, "No input file specified.\n");
85 fprintf(stderr
, "Usage: %s [--pagesize N] FILENAME\n", argv
[0]);
88 in
= fopen(zInputFile
, "rb");
90 fprintf(stderr
, "Cannot open input file [%s]\n", zInputFile
);
93 fseek(in
, 0, SEEK_END
);
97 fprintf(stderr
, "File too short. Minimum size is 100 bytes.\n");
100 if( fread(aHdr
, 100, 1, in
)!=1 ){
101 fprintf(stderr
, "Cannot read file header\n");
106 pgsz
= (aHdr
[16]<<8) | aHdr
[17];
107 if( pgsz
==1 ) pgsz
= 65536;
108 if( pgsz
<512 || (pgsz
&(pgsz
-1))!=0 ){
109 fprintf(stderr
, "Invalid page size in header: %d\n", pgsz
);
113 zBaseName
= zInputFile
;
114 for(i
=0; zInputFile
[i
]; i
++){
115 if( zInputFile
[i
]=='/' && zInputFile
[i
+1]!=0 ) zBaseName
= zInputFile
+i
+1;
117 printf("| size %d pagesize %d filename %s\n",(int)szFile
,pgsz
,zBaseName
);
118 for(i
=0; i
<szFile
; i
+=16){
119 int got
= (int)fread(aLine
, 1, 16, in
);
123 fprintf(stderr
, "Could not read input file starting at byte %d\n",
126 memset(aLine
+got
, 0, 16-got
);
128 if( allZero(aLine
) ) continue;
130 if( lastPage
!=iPage
){
131 printf("| page %d offset %d\n", iPage
, (iPage
-1)*pgsz
);
134 printf("| %5d:", i
-(iPage
-1)*pgsz
);
135 for(j
=0; j
<16; j
++) printf(" %02x", aLine
[j
]);
138 unsigned char c
= (unsigned char)aLine
[j
];
139 fputc( bShow
[c
], stdout
);
144 printf("| end %s\n", zBaseName
);