147 lines
4.5 KiB
C
147 lines
4.5 KiB
C
/*
|
|
** Copyright 2008 D. Richard Hipp and Hipp, Wyrick & Company, Inc.
|
|
** All Rights Reserved
|
|
**
|
|
******************************************************************************
|
|
**
|
|
** This file implements a stand-alone utility program that converts
|
|
** a binary file (usually an SQLite database) into a text format that
|
|
** is compact and friendly to human-readers.
|
|
**
|
|
** Usage:
|
|
**
|
|
** dbtotxt [--pagesize N] FILENAME
|
|
**
|
|
** The translation of the database appears on standard output. If the
|
|
** --pagesize command-line option is omitted, then the page size is taken
|
|
** from the database header.
|
|
**
|
|
** Compactness is achieved by suppressing lines of all zero bytes. This
|
|
** works well at compressing test databases that are mostly empty. But
|
|
** the output will probably be lengthy for a real database containing lots
|
|
** of real content. For maximum compactness, it is suggested that test
|
|
** databases be constructed with "zeroblob()" rather than "randomblob()"
|
|
** used for filler content and with "PRAGMA secure_delete=ON" selected to
|
|
** zero-out deleted content.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
/* Return true if the line is all zeros */
|
|
static int allZero(unsigned char *aLine){
|
|
int i;
|
|
for(i=0; i<16 && aLine[i]==0; i++){}
|
|
return i==16;
|
|
}
|
|
|
|
int main(int argc, char **argv){
|
|
int pgsz = 0; /* page size */
|
|
long szFile; /* Size of the input file in bytes */
|
|
FILE *in; /* Input file */
|
|
int i, j; /* Loop counters */
|
|
int nErr = 0; /* Number of errors */
|
|
const char *zInputFile = 0; /* Name of the input file */
|
|
const char *zBaseName = 0; /* Base name of the file */
|
|
int lastPage = 0; /* Last page number shown */
|
|
int iPage; /* Current page number */
|
|
unsigned char aLine[16]; /* A single line of the file */
|
|
unsigned char aHdr[100]; /* File header */
|
|
unsigned char bShow[256]; /* Characters ok to display */
|
|
memset(bShow, '.', sizeof(bShow));
|
|
for(i=' '; i<='~'; i++){
|
|
if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = i;
|
|
}
|
|
for(i=1; i<argc; i++){
|
|
if( argv[i][0]=='-' ){
|
|
const char *z = argv[i];
|
|
z++;
|
|
if( z[0]=='-' ) z++;
|
|
if( strcmp(z,"pagesize")==0 ){
|
|
i++;
|
|
pgsz = atoi(argv[i]);
|
|
if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ){
|
|
fprintf(stderr, "Page size must be a power of two between"
|
|
" 512 and 65536.\n");
|
|
nErr++;
|
|
}
|
|
continue;
|
|
}
|
|
fprintf(stderr, "Unknown option: %s\n", argv[i]);
|
|
nErr++;
|
|
}else if( zInputFile ){
|
|
fprintf(stderr, "Already using a different input file: [%s]\n", argv[i]);
|
|
nErr++;
|
|
}else{
|
|
zInputFile = argv[i];
|
|
}
|
|
}
|
|
if( zInputFile==0 ){
|
|
fprintf(stderr, "No input file specified.\n");
|
|
nErr++;
|
|
}
|
|
if( nErr ){
|
|
fprintf(stderr, "Usage: %s [--pagesize N] FILENAME\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
in = fopen(zInputFile, "rb");
|
|
if( in==0 ){
|
|
fprintf(stderr, "Cannot open input file [%s]\n", zInputFile);
|
|
exit(1);
|
|
}
|
|
fseek(in, 0, SEEK_END);
|
|
szFile = ftell(in);
|
|
rewind(in);
|
|
if( szFile<100 ){
|
|
fprintf(stderr, "File too short. Minimum size is 100 bytes.\n");
|
|
exit(1);
|
|
}
|
|
if( fread(aHdr, 100, 1, in)!=1 ){
|
|
fprintf(stderr, "Cannot read file header\n");
|
|
exit(1);
|
|
}
|
|
rewind(in);
|
|
if( pgsz==0 ){
|
|
pgsz = (aHdr[16]<<8) | aHdr[17];
|
|
if( pgsz==1 ) pgsz = 65536;
|
|
if( pgsz<512 || (pgsz&(pgsz-1))!=0 ){
|
|
fprintf(stderr, "Invalid page size in header: %d\n", pgsz);
|
|
exit(1);
|
|
}
|
|
}
|
|
zBaseName = zInputFile;
|
|
for(i=0; zInputFile[i]; i++){
|
|
if( zInputFile[i]=='/' && zInputFile[i+1]!=0 ) zBaseName = zInputFile+i+1;
|
|
}
|
|
printf("| size %d pagesize %d filename %s\n",(int)szFile,pgsz,zBaseName);
|
|
for(i=0; i<szFile; i+=16){
|
|
int got = (int)fread(aLine, 1, 16, in);
|
|
if( got!=16 ){
|
|
static int once = 1;
|
|
if( once ){
|
|
fprintf(stderr, "Could not read input file starting at byte %d\n",
|
|
i+got);
|
|
}
|
|
memset(aLine+got, 0, 16-got);
|
|
}
|
|
if( allZero(aLine) ) continue;
|
|
iPage = i/pgsz + 1;
|
|
if( lastPage!=iPage ){
|
|
printf("| page %d offset %d\n", iPage, (iPage-1)*pgsz);
|
|
lastPage = iPage;
|
|
}
|
|
printf("| %5d:", i-(iPage-1)*pgsz);
|
|
for(j=0; j<16; j++) printf(" %02x", aLine[j]);
|
|
printf(" ");
|
|
for(j=0; j<16; j++){
|
|
unsigned char c = (unsigned char)aLine[j];
|
|
fputc( bShow[c], stdout);
|
|
}
|
|
fputc('\n', stdout);
|
|
}
|
|
fclose(in);
|
|
printf("| end %s\n", zBaseName);
|
|
return 0;
|
|
}
|