summaryrefslogtreecommitdiffstats
path: root/tool/dbtotxt.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 17:28:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 17:28:19 +0000
commit18657a960e125336f704ea058e25c27bd3900dcb (patch)
tree17b438b680ed45a996d7b59951e6aa34023783f2 /tool/dbtotxt.c
parentInitial commit. (diff)
downloadsqlite3-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.c188
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;
+}