diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:28:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:28:19 +0000 |
commit | 18657a960e125336f704ea058e25c27bd3900dcb (patch) | |
tree | 17b438b680ed45a996d7b59951e6aa34023783f2 /tool/dbtotxt.c | |
parent | Initial commit. (diff) | |
download | sqlite3-18657a960e125336f704ea058e25c27bd3900dcb.tar.xz sqlite3-18657a960e125336f704ea058e25c27bd3900dcb.zip |
Adding upstream version 3.40.1.upstream/3.40.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tool/dbtotxt.c')
-rw-r--r-- | tool/dbtotxt.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/tool/dbtotxt.c b/tool/dbtotxt.c new file mode 100644 index 0000000..fbd6e3d --- /dev/null +++ b/tool/dbtotxt.c @@ -0,0 +1,188 @@ +/* +** 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 [OPTIONS] FILENAME +** +** where OPTIONS are zero or more of: +** +** --for-cli prepending '.open --hexdb' to the output +** +** --script The input file is expected to start with a +** zero-terminated SQL string. Output the +** ".open --hexdb" header, then the database +** then the SQL. +** +** --pagesize N set the database page size for later reading +** +** 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 */ + int forCli = 0; /* whether to prepend with .open */ + int bSQL = 0; /* Expect and SQL prefix */ + long szFile; /* Size of the input file in bytes */ + FILE *in; /* Input file */ + int nSQL; /* Number of bytes of script */ + 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 *aData = 0; /* All data */ + unsigned char *aLine; /* A single line of the file */ + unsigned char *aHdr; /* 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] = (unsigned char)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; + }else if( strcmp(z,"for-cli")==0 ){ + forCli = 1; + continue; + }else if( strcmp(z,"script")==0 ){ + forCli = 1; + bSQL = 1; + 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] [--script] [--for-cli] 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); + } + aData = malloc( szFile+16 ); + if( aData==0 ){ + fprintf(stderr, "Failed to allocate %ld bytes\n", szFile); + exit(1); + } + if( fread(aData, szFile, 1, in)!=1 ){ + fprintf(stderr, "Cannot read file info memory\n"); + exit(1); + } + memset(aData+szFile, 0, 16); + fclose(in); + if( bSQL ){ + for(i=0; i<szFile && aData[i]!=0; i++){} + if( i==szFile ){ + fprintf(stderr, "No zero terminator on SQL script\n"); + exit(1); + } + nSQL = i+1; + if( szFile - nSQL<100 ){ + fprintf(stderr, "Less than 100 bytes in the database\n"); + exit(1); + } + }else{ + nSQL = 0; + } + aHdr = aData + nSQL; + 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; + } + if( forCli ){ + printf(".open --hexdb\n"); + } + printf("| size %d pagesize %d filename %s\n",(int)szFile,pgsz,zBaseName); + for(i=nSQL; i<szFile; i+=16){ + aLine = aData+i; + 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); + } + printf("| end %s\n", zBaseName); + if( nSQL>0 ){ + printf("%s\n", aData); + } + free( aData ); + return 0; +} |