Talk About Network

Google


Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Data Bases > Btrieve > Re: Btrieve leg...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 8 of 11 Topic 981 of 1027
Post > Topic >>

Re: Btrieve legacy migration

by PauLita.PauLora@[EMAIL PROTECTED] Feb 28, 2008 at 03:45 AM

Jim Kyle. Btrieve complete.
A Guide for Developers and System Administrators.
Addison-Wesley Publi****ng Company. 1995.



/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *  DUMPDATA - Jim Kyle - February 1995                      *
 *                                                           *
 *  Lists all data records from any version of Btrieve file  *
 *  without requiring Btrieve engine to be installed in      *
 *  system.                                                  *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <stdio.h>
#include <conio.h>
#ifdef __TURBOC__
#include <alloc.h>      // Borland-specific
#else
#include <malloc.h>     // Microsoft version
#endif
#include <string.h>
#include <ctype.h>

#include "btrieve.h"

FILE *fp;               // global for convenience
FCRTOP Fcr;

int PageSize, RecLen, PhyLen;
char *PgmName =3D "DUMPDATA";
char outbuf[80];

FILE *fpout =3D stdout;
int rectype =3D 0;        // 0 fixed, 1 variable,
                        // 2 var trunc, 3 compressed, 4 uses VAT
VRECPTR Vrec;           // current vrec pointer
int  fragno;            // fragment number from Vrec
long fragpg;            // vrec logical page number from Vrec
long fragfo;            // file offset to physical page
int *fragpp;            // fragment index array base
int  fragi,             // index into fragpp array
     frago,             // offset to start of fragment
     fragl;             // length of fragment
BYTE Vbfr[MAXBTRPG];
char wrkbuf[MAXBTRPG];  // for reading anything into

char *fmt[] =3D {
  "original",
  "new"
};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure undoes Btrieve's word-swapping.       *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static long swap( long n )
{ asm les dx,n;                     // ASM trick for simplicity
  asm mov ax,es;
// return ((n>>16)&0xFFFF) | (n<<16);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure dumps data, translating to ASCII      *
 *      if in printable range, else outputting as hex.       *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void dumpdata( BYTE *data, int nbr )
{ int i, j;
  char *h =3D "0123456789ABCDEF";
  for(i=3D0; i<nbr; i+=3D64)
    { for( j=3D0; j<64; j++ )
        if( (i+j) < nbr )
          putchar( h[ (data[i+j]>>4) & 15] );
      printf( "\n\t  " );
      for( j=3D0; j<64; j++ )
        if( (i+j) < nbr )
          putchar( h[ data[i+j] & 15] );
      printf( "\n\t  " );
      for( j=3D0; j<64; j++ )
        if( (i+j) < nbr )
          putchar( isprint( data[i+j] ) ? data[i+j] : '*' );
      printf( "\n\t  " );
      for( j=3D0; j<64; j++ )
        if( (i+j) < nbr )
          putchar( '-' );
      if( j =3D=3D 64 )
        printf( "\n\t  " );
    }
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure converts a Logical Page number to     *
 *      a file offset, using the PAT for new format files.   *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static long lp_pp( long lp )
{ long ret, pat1, pat2;
  unsigned short u1, u2, pppat;
  if( CurFmt !=3D 1 )                     // only do lookup for new
    { ret =3D 2;                          // first PAT pair on 2, 3
      pppat =3D (PageSize >> 2) - 2;      // pages per PAT

      while( lp > pppat )               // off current page
        { lp -=3D pppat;                  //   so tally down index
          ret +=3D (PageSize >> 2);       //   up the PAT pp nbr
        }

      pat1 =3D ret * (long)PageSize;      // first PAT of pair
      pat2 =3D pat1 + (long)PageSize;     // second right after it
      fseek( fp, pat1+4L, 0 );          // get both usage counts
      fread( &u1, 2, 1, fp );
      fseek( fp, pat2+4L, 0 );
      fread( &u2, 2, 1, fp );
      if( u1 > u2 )                     // choose most recent one
        ret =3D pat1;
      else
        ret =3D pat2;

      ret +=3D (long)(( lp << 2 ) + 4L ); // position in PAT
      fseek( fp, ret, 0 );
      fread( &lp, 4, 1, fp );           // read it into LP

      lp =3D swap( lp );                  // and un-word-swap it
      lp &=3D 0xFFFFFFL;
    }

  if( lp =3D=3D 0xFFFFFFL || lp =3D=3D -1L )    // NULL pointer values
    ret =3D -1L;
  else                                  // convert to offset
    ret =3D lp * PageSize;
  return ret;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure writes a message to CRT and then      *
 *      waits for user to press ENTER key.                   *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void oflomsg( char * p, int r, long cpos )
{ printf( "\07%s buffer overflow!\07\n"
          "Press ENTER to continue\n%d\t  ", p, r );
  while( getch() !=3D 13 )
    /* wait for user */ ;
  dumpdata( (BYTE *)wrkbuf, r );
  fseek( fp, cpos + (long)PhyLen, 0 );
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure checks one record for validity and    *
 *      then outputs its data, expanding as necessary.       *
 *      Flag byte added as promised in text.                 *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DmpRec( void )                     // dumps single record
{ long cpos =3D ftell( fp );              // save position at entry
  int i, b, r =3D RecLen, count, state;

  if( rectype !=3D 3 && CurFmt =3D=3D 2 )     // new format usage test
    { fread( &i, 2, 1, fp );
      if( !i )                          // ignore unused records
        { fseek( fp, cpos + (long)PhyLen, 0 );
          return;
        }
      fread( wrkbuf, PhyLen-2, 1, fp ); // load workbuf with data
    }
  else                                  // test for empty record
    { int empty =3D 1;
      fread( wrkbuf, PhyLen, 1, fp );   // load wrkbuf with data
      for( i=3D4; i<PhyLen; i++ )         // skip over pointer
        if( wrkbuf[i] )                 // something there
          { empty =3D 0;                  // so not empty
            break;
          }
      if( empty )                       // restore file, ignore
        { fseek( fp, cpos + (long)PhyLen, 0 );
          return;
        }
    }

  if( rectype )                         // var, trunc, compr
    { long fps =3D ftell( fp );           // save file position
      int lofs;
      BYTE cmpalg, savect, countflag;

      switch( rectype )
        {
        case 1:                         // VARIABLE LENGTH DATA
        case 2:                         // BLANK TRUNCATION
          memcpy( &Vrec, wrkbuf + r, 4 );
          memcpy( &count, wrkbuf + r + 4, 2 );
          fragpp =3D (int *)Vbfr;         // set pointer

nxvr:     fragno =3D VRFrag( Vrec );      // for multiple frags
          fragpg =3D VRPage( Vrec );
          fragfo =3D lp_pp( fragpg );
          if( fragfo =3D=3D -1L || fragno > 254 )
            goto vrdun;                 // no more to do
          fseek( fp, fragfo, 0 );       // read page into buffer
          fread( &Vbfr, MAXBTRPG, 1, fp );

          fragi =3D ((PageSize - 1) >> 1 ) - fragno;
          frago =3D fragpp[ fragi ] & 0x7FFF;
          for(lofs=3D1; fragpp[fragi - lofs] =3D=3D -1; lofs++)
            /* all done in test! */ ;
          fragl =3D (fragpp[ fragi - lofs ] & 0x7FFF ) - frago;

          if( CurFmt =3D=3D 2 || fragpp[fragi] & 0x8000 )
            { Vrec =3D *(VRECPTR *)(&Vbfr[ frago ]);
              frago +=3D sizeof( VRECPTR );
              fragl -=3D sizeof( VRECPTR );
            }
          else
            { Vrec.lo =3D Vrec.mid =3D Vrec.hi =3D Vrec.frag =3D 0x00FF;
            }
          memcpy( wrkbuf + r, Vbfr + frago, fragl );
          r +=3D fragl;
          goto nxvr;                    // check for next frag

vrdun:    if( rectype =3D=3D 2 )            // restore blanks
            { while( count--  && r < 4095 ) // stay in buffer!
                wrkbuf[ r++ ] =3D ' ';
            }
          break;

        case 3:                         // COMPRESSED DATA
        case 5:                         // COMPRESSED, VARIABLE
          memcpy( &Vrec, wrkbuf + r, 4 );
          fragpp =3D (int *)Vbfr;         // set pointer
          cmpalg =3D wrkbuf[4];
          if( !cmpalg )                 // deleted record, ignore
            { fseek( fp, cpos + (long)PhyLen, 0 );
              return;
            }
          count =3D 0;                    // clear count vars
          savect =3D 0;
          countflag =3D 0;
          r =3D 0;                        // expansion index
          state =3D 1;                    // copy strings first

nxcr:     fragno =3D VRFrag( Vrec );      // for multiple frags
          fragpg =3D VRPage( Vrec );
          fragfo =3D lp_pp( fragpg );     // actual file offset
          if( fragfo =3D=3D -1L || fragno > 254 )
            goto crdun;                 // end of chain
          fseek( fp, fragfo, 0 );       // read page into buffer
          fread( &Vbfr, PageSize, 1, fp );
          fragi =3D ((PageSize - 1) >> 1 ) - fragno;
          frago =3D fragpp[ fragi ] & 0x7FFF;
          fragl =3D (fragpp[ fragi - 1 ] & 0x7FFF ) - frago;

          if( CurFmt =3D=3D 2 || fragpp[fragi] & 0x8000 )
            { Vrec =3D *(VRECPTR *)(&Vbfr[ frago ]);
              frago +=3D sizeof( VRECPTR );
              fragl -=3D sizeof( VRECPTR );
            }
          else
            { Vrec.lo =3D Vrec.mid =3D Vrec.hi =3D Vrec.frag =3D 0x00FF;
            }

          if( countflag )               // count spans frags
            { frago--;                  // adj offset, length
              fragl++;
              Vbfr[frago] =3D savect;     // set first byte in
              count =3D 0;                // clear out count
              savect =3D 0;               // clear save byte
              countflag =3D 0;            // clear flag
            }

          for( i=3D0; i<fragl; )          // decompression loop
            { if( count < 1 )           // get new count
                { count =3D *(int *)(Vbfr + frago + i );
                  i +=3D 2;               // advance pointer
                }
              if( i >=3D fragl )          // at fragment end
                break;                  // so get another

              if( state )               // process data pair
                { while( count-- )      // copy is state 1
                    { wrkbuf[ r++ ] =3D Vbfr[ frago + (i++) ];
                      if( r > 4090 )    // error trap...
                        { oflomsg( "Copy", r, cpos );
                          return;       // skip this record
                        }
                      if( i =3D=3D fragl && // string spans frags
                          count )       //   and isn't done yet
                        break;          // get next fragment
                    }                   // copy loop
                  if( count < 1 )
                    state =3D 0;          // repeat next pair
                }
              else
                { while( count-- )      // repeat is state 0
                    { wrkbuf[ r++ ] =3D Vbfr[ frago + i ];
                      if( r > 4090 )    // error trap...
                        { oflomsg( "Repeat", r, cpos );
                          return;       // skip this record
                        }
                    }                   // repeat loop
                  i++;                  // over repeat byte
                  state =3D 1;            // copy next pair
                }

              if( i =3D=3D fragl-1 )        // count spans frags
                { savect =3D Vbfr[ frago + i++ ];
                  countflag =3D 1;        // flag byte as saved
                  break;                // get next
                }
            }                           // decompression loop
          goto nxcr;                    // to get next fragment

crdun:    break;                        // record complete now
        }
      fseek( fp, fps, 0 );
    }

  Fcr.Nrecs--;                          // tally down count
  if( fpout =3D=3D stdout )
    { printf( "%d,\t  ", r );           // human-readable format
      dumpdata( (BYTE *)wrkbuf, r );
      putchar( '\n' );
    }
  else
    { fprintf( fpout, "%d,", r );       // BUTIL -SAVE format
      for( i=3D0; i<r; i++ )
        { b =3D 255 & wrkbuf[i];
          fprintf( fpout, "%c", b );
        }
      fprintf( fpout, "\r\n" );
    }

  fseek( fp, cpos + (long)PhyLen, 0 );  // restore file position
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure goes through all possible records on  *
 *      a page and calls DmpRec for each.                    *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DumpRecs( void )
{ int recpg =3D (PageSize - 6) / PhyLen;  // page capacity
  int currec;                           // current record

  for( currec=3D0; currec < recpg; currec++ )
    DmpRec();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure cycles through all pages, calling     *
 *      DumpRecs routine for each data page in turn.         *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DoItToIt( void )
{ long x, fps =3D 0L, pgct;
  unsigned u;
  int lpg=3D1;
  char *rt[] =3D { "Fixed Length", "Variable Length",
               "Variable, truncated", "Compressed",
               "Uses VAT, not sup****ted",
               "Compressed variable-length" };

  RecLen =3D Fcr.RecLen;                  // save global values
  PhyLen =3D Fcr.PhyLen;
  pgct =3D swap( Fcr.Npages );            // get number of pages
  Fcr.Nrecs =3D swap( Fcr.Nrecs );

  printf( "File %s is in %s format; pagesize =3D %d, "
          "has %ld pages\n",
          outbuf,
          fmt[CurFmt-1],
          PageSize,
          pgct );
  printf( "Record count =3D %ld (%s).\n\n",
          Fcr.Nrecs, rt[rectype] );
  if( Fcr.Nrecs < 1L || rectype =3D=3D 4 )  // VAT's not sup****ted
    return;

  printf( "Write SAVE file, or VIEW data on CRT (S or V )? " );
  for( u=3D1; u; )
    switch( getch() )
      {
      case 's':
      case 'S':
        printf( "\nSave to filename: " );
        gets( wrkbuf );                 // get filename
        for( u=3D0; wrkbuf[u] > 0x1F; u++ )   // find end of name
          ;
        wrkbuf[u] =3D 0;
        if( strlen(wrkbuf) )            // no name means view
          fpout =3D fopen( wrkbuf, "wb" );
      case 'v':                         // fall through
      case 'V':
        u =3D 0;
        putchar( '\n' );
        break;
      case 27:
      case 3:
        return;
      }

  if( CurFmt > 1 )
    lpg =3D 1;                            // new starts at one
  else
    lpg =3D 0;                            // old starts at zero

  for( ; lpg < (unsigned)pgct; lpg++ )  // do rest of pages
    { fps =3D lp_pp( lpg );               // convert to file offset
      if( fps < 0L )
        break;                          // NULL-pointer, get out
      fseek( fp, fps, 0 );              // seek to start of page
      fread( &x, 4, 1, fp );            // read header & usage
      fread( &u, 2, 1, fp );
      if( (u & 0x8000) )                // dump data records
        DumpRecs();
    }
  if( fpout !=3D stdout )                 // close data file
    { fprintf( fpout, "%c", 0x1A );     // after adding EOF mark
      fclose( fpout );
      fpout =3D stdout;
    }
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure determines a file's type, then        *
 *      loads Fcr, and establishes record type.              *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int GetFormat( void )
{ int fmt =3D 0;                      // 0 not Btrieve
                                    // 1 old, 2 new
  int testbuf[5];                   // test first 10 bytes

  fread( testbuf, 5, 2, fp );
  if( testbuf[1] =3D=3D 0 )             // page sequence must be zero
    { if( testbuf[0] =3D=3D 0 )
        { fmt =3D 1;                  // original format
          fseek( fp, 0L, 0 );
        }
      else if( testbuf[0] =3D=3D 0x4346 )   // 'FC' signature
        { fmt =3D 2;
          fseek( fp, (long)testbuf[4]+4, 0 );   // check next FCR
          fread( &testbuf[0], 2, 1, fp );
          if( testbuf[0] > testbuf[2] ) // second is valid
            fseek( fp, (long)testbuf[4], 0 );
          else                      // use the first
            fseek( fp, 0L, 0 );
        }
    }
  if( fmt )                         // load valid FCR
    { fread( &Fcr, 1, sizeof( FCRTOP ), fp );
      PageSize =3D Fcr.PagSize;
      if( Fcr.UsrFlgs & 8 &&
          ( Fcr.VRecsOkay || Fcr.UsrFlgs & 1 ))
        rectype =3D 5;                // compressed variable data
      else if( fmt =3D=3D 2 && Fcr.UsrFlgs & 0x0800 )
        rectype =3D 4;                // uses VAT's
      else if( Fcr.UsrFlgs & 8 )
        rectype =3D 3;                // compressed fixed data
      else if( Fcr.VRecsOkay || Fcr.UsrFlgs & 1 )
        { if( (BYTE)Fcr.VRecsOkay =3D=3D 0x00FD || Fcr.UsrFlgs & 2 )
            rectype =3D 2;            // var trunc
          else
            rectype =3D 1;            // variable length
        }
      else
        rectype =3D 0;                // fixed length
    }
  else
    PageSize =3D 0;
  return fmt;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure processes a single file.              *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int Do_File( char * fnm )
{ int ret =3D 0;                      // assume success

  strupr( fnm );
  fp =3D fopen( fnm, "rb" );
  if( fp )
    { strcpy( outbuf, fnm );        // save for re****ts
      CurFmt =3D GetFormat();
      switch( CurFmt )
        {
        case 0:
          printf( "%s is not a Btrieve file.\n", fnm );
          ret =3D 1;
          break;
        case 1:
        case 2:
          DoItToIt();
          break;
        default:
          puts( "Undefined format code, should never happen!" );
          ret =3D 99;
          break;
        }
      fclose( fp );
    }
  else
    { perror( fnm );
      ret =3D 2;
    }
  return ret;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure tells how to use the program.         *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Usage( void )
{ printf( "Usage: %s file1 [file2 [...]]\n", PgmName );
  printf( "\t where filenames can continue until command line "
          "is full\n" );
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure displays a standard banner heading    *
 *      each time the program runs.                          *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Banner( void )
{ printf( "\n\t    %s - from \"Btrieve Complete\" by Jim Kyle\n",
          PgmName );
  printf( "\t    Copyright 1995 by Jim Kyle - All Rights"
          " Reserved\n" );
  printf( "\t    Use freely, but do not distribute "
          "commercially.\n\n" );
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 *                                                           *
 *      This procedure is program entry point.               *
 *                                                           *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main( int argc, char **argv )
{ int retval =3D 0;
  Banner();
  if( argc < 2 )
    { Usage();
      retval =3D 255;
    }
  else
    { int i;
      for( i=3D1; i < argc; i++ )
        { retval =3D Do_File( argv[i] );  // process each file
          if( retval )                  // if error, wait
            while( getch() !=3D 13 )
              /* wait right here for CR */  ;
        }
    }
  return retval;
}






daniel.y...@[EMAIL PROTECTED]
 ra=F0=EB:
> Hello,
>
> I am writing an application in C# that I am trying to integrate with a
> legacy program that stores its information in Btrieve databases.  I am
> looking for information on how to do this.
>
> Due to financial constraints, as well as licensing problems,
> purchasing a copy of Progressive Server is not very feasible.
> Basically, my program needs to be able to read the information stored
> in this database without installing Progressive.
>
> I am basically looking for one of two things: an open-source library
> for reading btrieve data files, or a description of the file format.
>
> I have been able to find many descriptions of file.ddf and field.ddf,
> but the program I am integrating with only seems to use an index.ddf.
> Any of the freeware programs I have found require a file.ddf and
> field.ddf file to work.
>
> There have been some hints that the SQL reference manual from the
> Progressive website might have the file format I'm looking for, but I
> have not been able to find any details.
>
> This is all further complicated by the fact that I have no idea what
> version of the file format I am working with, but I suspect it to be
> pre-6.15.
>
> If anyone could point me towards some solutions to any of these
> problems, I would really appreciate it.  I have been banging my head
> against a wall all week.  Thanks.
>
> -Daniel
 




 11 Posts in Topic:
Btrieve legacy migration
daniel.yule@[EMAIL PROTEC  2008-02-24 00:02:54 
Re: Btrieve legacy migration
nelsonsoft <nelsonsoft  2008-02-24 06:31:02 
Re: Btrieve legacy migration
Daniel <daniel.yule@[E  2008-02-24 11:26:14 
Re: Btrieve legacy migration
nelsonsoft <nelsonsoft  2008-02-24 14:27:26 
Re: Btrieve legacy migration
Daniel <daniel.yule@[E  2008-02-24 15:02:57 
Re: Btrieve legacy migration
Guy Dawson <gnues@[EMA  2008-02-25 11:00:08 
Re: Btrieve legacy migration
"Bill Bach" <  2008-02-25 08:10:21 
Re: Btrieve legacy migration
PauLita.PauLora@[EMAIL PR  2008-02-28 03:45:56 
Re: Btrieve legacy migration
Gloria <claudio.benghi  2008-03-03 06:14:04 
Re: Btrieve legacy migration
"Bill Bach" <  2008-03-05 19:28:31 
Re: Btrieve legacy migration
PauLita.PauLora@[EMAIL PR  2008-03-04 02:39:18 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan12V112 Mon Oct 6 19:14:19 CDT 2008.