15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A utility for printing all or part of an SQLite database file.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pagesize = 1024;     /* Size of a database page */
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int db = -1;             /* File descriptor for reading the DB */
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mxPage = 0;          /* Last page number */
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int perLine = 16;        /* HEX elements to print per line */
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef long long int i64;      /* Datatype for 64-bit integers */
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Convert the var-int format into i64.  Return the number of bytes
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** in the var-int.  Write the var-int value into *pVal.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int decodeVarint(const unsigned char *z, i64 *pVal){
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  i64 v = 0;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<8; i++){
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    v = (v<<7) + (z[i]&0x7f);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  v = (v<<8) + (z[i]&0xff);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pVal = v;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 9;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Extract a big-endian 32-bit integer
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned int decodeInt32(const unsigned char *z){
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Report an out-of-memory error and die.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void out_of_memory(void){
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf(stderr,"Out of memory...\n");
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exit(1);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Read content from the file.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Space to hold the content is obtained from malloc() and needs to be
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** freed by the caller.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned char *getContent(int ofst, int nByte){
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *aData;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aData = malloc(nByte+32);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( aData==0 ) out_of_memory();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(aData, 0, nByte+32);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lseek(db, ofst, SEEK_SET);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read(db, aData, nByte);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return aData;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Print a range of bytes as hex and as ascii.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned char *print_byte_range(
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ofst,          /* First byte in the range of bytes to print */
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nByte,         /* Number of bytes to print */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int printOfst      /* Add this amount to the index on the left column */
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *aData;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i, j;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zOfstFmt;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( ((printOfst+nByte)&~0xfff)==0 ){
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zOfstFmt = " %03x: ";
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( ((printOfst+nByte)&~0xffff)==0 ){
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zOfstFmt = " %04x: ";
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( ((printOfst+nByte)&~0xfffff)==0 ){
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zOfstFmt = " %05x: ";
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( ((printOfst+nByte)&~0xffffff)==0 ){
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zOfstFmt = " %06x: ";
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zOfstFmt = " %08x: ";
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aData = getContent(ofst, nByte);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<nByte; i += perLine){
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stdout, zOfstFmt, i+printOfst);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(j=0; j<perLine; j++){
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( i+j>nByte ){
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fprintf(stdout, "   ");
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fprintf(stdout,"%02x ", aData[i+j]);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(j=0; j<perLine; j++){
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( i+j>nByte ){
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fprintf(stdout, " ");
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stdout,"\n");
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return aData;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Print an entire page of content as hex
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static print_page(int iPg){
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int iStart;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *aData;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iStart = (iPg-1)*pagesize;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf(stdout, "Page %d:   (offsets 0x%x..0x%x)\n",
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          iPg, iStart, iStart+pagesize-1);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aData = print_byte_range(iStart, pagesize, 0);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  free(aData);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Print a line of decode output showing a 4-byte integer.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static print_decode_line(
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *aData,      /* Content being decoded */
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ofst, int nByte,       /* Start and size of decode */
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zMsg           /* Message to append */
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i, j;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int val = aData[ofst];
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char zBuf[100];
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  i = strlen(zBuf);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(j=1; j<4; j++){
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( j>=nByte ){
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(&zBuf[i], "   ");
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(&zBuf[i], " %02x", aData[ofst+j]);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      val = val*256 + aData[ofst+j];
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i += strlen(&zBuf[i]);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sprintf(&zBuf[i], "   %9d", val);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("%s  %s\n", zBuf, zMsg);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Decode the database header.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void print_db_header(void){
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *aData;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aData = print_byte_range(0, 100, 0);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Decoded:\n");
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 16, 2, "Database page size");
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 18, 1, "File format write version");
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 19, 1, "File format read version");
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 20, 1, "Reserved space at end of page");
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 24, 4, "File change counter");
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 28, 4, "Size of database in pages");
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 32, 4, "Page number of first freelist page");
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 36, 4, "Number of freelist pages");
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 40, 4, "Schema cookie");
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 44, 4, "Schema format version");
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 48, 4, "Default page cache size");
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 52, 4, "Largest auto-vac root page");
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 56, 4, "Text encoding");
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 60, 4, "User version");
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 64, 4, "Incremental-vacuum mode");
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 68, 4, "meta[7]");
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 72, 4, "meta[8]");
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 76, 4, "meta[9]");
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 80, 4, "meta[10]");
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 84, 4, "meta[11]");
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 88, 4, "meta[12]");
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 92, 4, "Change counter for version number");
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(aData, 96, 4, "SQLite version number");
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Describe cell content.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int describeContent(
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *a,       /* Cell content */
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nLocal,             /* Bytes in a[] */
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zDesc             /* Write description here */
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nDesc = 0;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n, i, j;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  i64 x, v;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned char *pData;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned char *pLimit;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char sep = ' ';
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pLimit = &a[nLocal];
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  n = decodeVarint(a, &x);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pData = &a[x];
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  a += n;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  i = x - n;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( i>0 && pData<=pLimit ){
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n = decodeVarint(a, &x);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a += n;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i -= n;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nLocal -= n;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zDesc[0] = sep;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sep = ',';
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nDesc++;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zDesc++;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( x==0 ){
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(zDesc, "*");     /* NULL is a "*" */
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else if( x>=1 && x<=6 ){
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      v = (signed char)pData[0];
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pData++;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch( x ){
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 6:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 5:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 4:  v = (v<<8) + pData[0];  pData++;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 3:  v = (v<<8) + pData[0];  pData++;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 2:  v = (v<<8) + pData[0];  pData++;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(zDesc, "%lld", v);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else if( x==7 ){
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(zDesc, "real");
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pData += 8;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else if( x==8 ){
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(zDesc, "0");
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else if( x==9 ){
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(zDesc, "1");
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else if( x>=12 ){
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int size = (x-12)/2;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( (x&1)==0 ){
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sprintf(zDesc, "blob(%d)", size);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sprintf(zDesc, "txt(%d)", size);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pData += size;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    j = strlen(zDesc);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zDesc += j;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nDesc += j;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nDesc;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Compute the local payload size given the total payload size and
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the page size.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int localPayload(i64 nPayload, char cType){
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int maxLocal;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int minLocal;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int surplus;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nLocal;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( cType==13 ){
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Table leaf */
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    maxLocal = pagesize-35;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    minLocal = (pagesize-12)*32/255-23;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    maxLocal = (pagesize-12)*64/255-23;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    minLocal = (pagesize-12)*32/255-23;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( nPayload>maxLocal ){
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    surplus = minLocal + (nPayload-minLocal)%(pagesize-4);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( surplus<=maxLocal ){
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nLocal = surplus;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nLocal = minLocal;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nLocal = nPayload;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nLocal;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Create a description for a single cell.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The return value is the local cell size.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int describeCell(
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char cType,    /* Page type */
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *a,       /* Cell content */
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int showCellContent,    /* Show cell content if true */
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **pzDesc           /* Store description here */
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nDesc = 0;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n = 0;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int leftChild;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  i64 nPayload;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  i64 rowid;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nLocal;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static char zDesc[1000];
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  i = 0;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( cType<=5 ){
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a += 4;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n += 4;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sprintf(zDesc, "lx: %d ", leftChild);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nDesc = strlen(zDesc);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( cType!=5 ){
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = decodeVarint(a, &nPayload);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a += i;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n += i;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sprintf(&zDesc[nDesc], "n: %lld ", nPayload);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nDesc += strlen(&zDesc[nDesc]);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nLocal = localPayload(nPayload, cType);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nPayload = nLocal = 0;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( cType==5 || cType==13 ){
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = decodeVarint(a, &rowid);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a += i;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n += i;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sprintf(&zDesc[nDesc], "r: %lld ", rowid);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nDesc += strlen(&zDesc[nDesc]);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( nLocal<nPayload ){
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ovfl;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char *b = &a[nLocal];
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3];
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sprintf(&zDesc[nDesc], "ov: %d ", ovfl);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nDesc += strlen(&zDesc[nDesc]);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n += 4;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( showCellContent && cType!=5 ){
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pzDesc = zDesc;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nLocal+n;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Decode a btree page
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void decode_btree_page(
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *a,   /* Page content */
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pgno,           /* Page number */
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int hdrSize,        /* Size of the page header.  0 or 100 */
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zArgs         /* Flags to control formatting */
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zType = "unknown";
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nCell;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i, j;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int iCellPtr;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int showCellContent = 0;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int showMap = 0;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zMap = 0;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch( a[0] ){
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 2:  zType = "index interior node";  break;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 5:  zType = "table interior node";  break;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 10: zType = "index leaf";           break;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 13: zType = "table leaf";           break;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( zArgs[0] ){
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch( zArgs[0] ){
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'c': showCellContent = 1;  break;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'm': showMap = 1;          break;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zArgs++;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Decode of btree page %d:\n", pgno);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(a, 0, 1, zType);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(a, 1, 2, "Offset to first freeblock");
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(a, 3, 2, "Number of cells on this page");
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nCell = a[3]*256 + a[4];
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(a, 5, 2, "Offset to cell content area");
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_decode_line(a, 7, 1, "Fragmented byte count");
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( a[0]==2 || a[0]==5 ){
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print_decode_line(a, 8, 4, "Right child");
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iCellPtr = 12;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iCellPtr = 8;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( nCell>0 ){
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf(" key: lx=left-child n=payload-size r=rowid\n");
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( showMap ){
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zMap = malloc(pagesize);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(zMap, '.', pagesize);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(zMap, '1', hdrSize);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&zMap[hdrSize], 'H', iCellPtr);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<nCell; i++){
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int cofst = iCellPtr + i*2;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zDesc;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int n;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cofst = a[cofst]*256 + a[cofst+1];
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( showMap ){
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char zBuf[30];
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memset(&zMap[cofst], '*', n);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zMap[cofst] = '[';
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zMap[cofst+n-1] = ']';
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sprintf(zBuf, "%d", i);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      j = strlen(zBuf);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( showMap ){
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=0; i<pagesize; i+=64){
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(" %03x: %.64s\n", i, &zMap[i]);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(zMap);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Decode a freelist trunk page.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void decode_trunk_page(
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pgno,             /* The page number */
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pagesize,         /* Size of each page */
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int detail,           /* Show leaf pages if true */
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int recursive         /* Follow the trunk change if true */
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n, i, k;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *a;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pgno>0 ){
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a = getContent((pgno-1)*pagesize, pagesize);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("Decode of freelist trunk page %d:\n", pgno);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print_decode_line(a, 0, 4, "Next freelist trunk page");
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print_decode_line(a, 4, 4, "Number of entries on this page");
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( detail ){
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      n = (int)decodeInt32(&a[4]);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for(i=0; i<n; i++){
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned int x = decodeInt32(&a[8+4*i]);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        char zIdx[10];
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sprintf(zIdx, "[%d]", i);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        printf("  %5s %7u", zIdx, x);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( i%5==4 ) printf("\n");
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( i%5!=0 ) printf("\n");
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !recursive ){
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pgno = 0;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pgno = (int)decodeInt32(&a[0]);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(a);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Print a usage comment
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void usage(const char *argv0){
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf(stderr,
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "args:\n"
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    dbheader        Show database header\n"
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNN..MMM        Show hex of pages NNN through MMM\n"
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNN..end        Show hex of pages NNN through end of file\n"
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNNb            Decode btree page NNN\n"
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNNbc           Decode btree page NNN and show content\n"
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNNbm           Decode btree page NNN and show a layout map\n"
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNNt            Decode freelist trunk page NNN\n"
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNNtd           Show leave freelist pages on the decode\n"
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "    NNNtr           Recurisvely decode freelist starting at NNN\n"
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  );
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char **argv){
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct stat sbuf;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char zPgSz[2];
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( argc<2 ){
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usage(argv[0]);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exit(1);
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db = open(argv[1], O_RDONLY);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( db<0 ){
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exit(1);
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zPgSz[0] = 0;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zPgSz[1] = 0;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lseek(db, 16, SEEK_SET);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read(db, zPgSz, 2);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pagesize==0 ) pagesize = 1024;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Pagesize: %d\n", pagesize);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fstat(db, &sbuf);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mxPage = sbuf.st_size/pagesize;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Available pages: 1..%d\n", mxPage);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( argc==2 ){
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int i;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=1; i<=mxPage; i++) print_page(i);
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int i;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=2; i<argc; i++){
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int iStart, iEnd;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char *zLeft;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( strcmp(argv[i], "dbheader")==0 ){
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print_db_header();
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( !isdigit(argv[i][0]) ){
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iStart = strtol(argv[i], &zLeft, 0);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( zLeft && strcmp(zLeft,"..end")==0 ){
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        iEnd = mxPage;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        iEnd = strtol(&zLeft[2], 0, 0);
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else if( zLeft && zLeft[0]=='b' ){
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int ofst, nByte, hdrSize;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned char *a;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( iStart==1 ){
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ofst = hdrSize = 100;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nByte = pagesize-100;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }else{
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          hdrSize = 0;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ofst = (iStart-1)*pagesize;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nByte = pagesize;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a = getContent(ofst, nByte);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        decode_btree_page(a, iStart, hdrSize, &zLeft[1]);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        free(a);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else if( zLeft && zLeft[0]=='t' ){
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned char *a;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int detail = 0;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int recursive = 0;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int i;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for(i=1; zLeft[i]; i++){
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if( zLeft[i]=='r' ) recursive = 1;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if( zLeft[i]=='d' ) detail = 1;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        decode_trunk_page(iStart, pagesize, detail, recursive);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        iEnd = iStart;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( iStart<1 || iEnd<iStart || iEnd>mxPage ){
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fprintf(stderr,
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "Page argument should be LOWER?..UPPER?.  Range 1 to %d\n",
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mxPage);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        exit(1);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while( iStart<=iEnd ){
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print_page(iStart);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        iStart++;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close(db);
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
558