Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 137 additions & 81 deletions BtrieveFileSaverLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,48 @@ unsigned short int freeClient (CLIENT_STRUCT *cl, unsigned short int ErrorCode)
* Just swap the bytes of a 32 bit int value
*
*/
static unsigned long int byte_swap(unsigned long int i )
static uint32_t byte_swap(uint32_t i )
{
return ((i>>16)&0xFFFF) | (i<<16);
}

static uint16_t read_le16(const void *data)
{
const unsigned char *bytes = (const unsigned char*)data;
return (uint16_t)(bytes[0] | ((uint16_t)bytes[1] << 8));
}

static uint32_t read_le32(const void *data)
{
const unsigned char *bytes = (const unsigned char*)data;
return (uint32_t)bytes[0] |
((uint32_t)bytes[1] << 8) |
((uint32_t)bytes[2] << 16) |
((uint32_t)bytes[3] << 24);
}

static uint32_t read_word_swapped_u32(const void *data)
{
return (uint32_t)byte_swap(read_le32(data));
}

static void write_le32(void *data, uint32_t value)
{
unsigned char *bytes = (unsigned char*)data;
bytes[0] = (unsigned char)(value & 0xff);
bytes[1] = (unsigned char)((value >> 8) & 0xff);
bytes[2] = (unsigned char)((value >> 16) & 0xff);
bytes[3] = (unsigned char)((value >> 24) & 0xff);
}

static uint32_t read_vrec_page_id_v5(const char *data)
{
uint32_t value = (uint32_t)(unsigned char)data[0] |
((uint32_t)(unsigned char)data[1] << 16) |
((uint32_t)(unsigned char)data[2] << 24);
return value == PAGE_KICK_OFF ? value : byte_swap(value);
}

/*
*
* Function getPageType
Expand All @@ -117,28 +154,38 @@ static unsigned long int byte_swap(unsigned long int i )
* this way.
*
*/
char getPageType (CLIENT_STRUCT *cl, char *tmpPage)
{
switch (cl->fVersion){
case BTRIEVE_FILE_V3:
case BTRIEVE_FILE_V4:
case BTRIEVE_FILE_V5:{
if (*(unsigned short int*)(tmpPage + 4) & 0x8000) return DAT_PAGE_ID;
}break;
case BTRIEVE_FILE_V6:
case BTRIEVE_FILE_V61:
case BTRIEVE_FILE_V7:{
return tmpPage[1];
}break;
case BTRIEVE_FILE_V8:
case BTRIEVE_FILE_V9:
// case BTRIEVE_FILE_V95:
{
return tmpPage[4];
}break;
}
return 0x00;
}
#if defined(_MSC_VER) && _MSC_VER >= 1950
/*
* MSVC 19.50's global optimizer drops the V3/V4/V5 arm from this sparse
* 16-bit switch in the complete library translation unit. Keep the original
* decoder and disable only that optimization pass for this function. The
* WineVDM golden fixtures exercise this path in release builds.
*/
#pragma optimize("g", off)
#endif
char getPageType (CLIENT_STRUCT *cl, char *tmpPage)
{
switch (cl->fVersion){
case BTRIEVE_FILE_V3:
case BTRIEVE_FILE_V4:
case BTRIEVE_FILE_V5:{
if (read_le16(tmpPage + 4) & 0x8000) return DAT_PAGE_ID;
}break;
case BTRIEVE_FILE_V6:
case BTRIEVE_FILE_V61:
case BTRIEVE_FILE_V7:{
return tmpPage[1];
}break;
case BTRIEVE_FILE_V8:
case BTRIEVE_FILE_V9:{
return tmpPage[4];
}break;
}
return 0x00;
}
#if defined(_MSC_VER) && _MSC_VER >= 1950
#pragma optimize("", on)
#endif

/*
*
Expand Down Expand Up @@ -190,13 +237,13 @@ unsigned long int addPage (CLIENT_STRUCT *cl, char *tmpPage, char pageType)
}else return NO_ERROR;

if (cl->fVersion >= BTRIEVE_FILE_V8){
pId = *(short*) tmpPage;
pUsage = (short)*(tmpPage + 6);
pId = read_le16(tmpPage);
pUsage = read_le16(tmpPage + 6);
}else{
pId = *(unsigned long int*)tmpPage;
pId = read_le32(tmpPage);
pId &= PAGE_KICK_OFF;
pId = byte_swap(pId);
pUsage = *(signed short*)(tmpPage + 4);
pUsage = read_le16(tmpPage + 4);
}

/* check if you have allready a page using the same id but lower usage counter */
Expand Down Expand Up @@ -281,7 +328,7 @@ unsigned short int readAllPagesFromFile (CLIENT_STRUCT *cl)
while ((pType = getNextPhysicalPage(cl, cl->CUR_DPAGE)) != 0x00)
addPage (cl, cl->CUR_DPAGE, pType);
/* reset the header of the data page container */
*(unsigned long int*)cl->CUR_DPAGE = 0L;
write_le32(cl->CUR_DPAGE, 0);
return NO_ERROR;
}

Expand Down Expand Up @@ -394,13 +441,13 @@ unsigned short int BF_OPEN (CLIENT_STRUCT *cl, char *fName)
/* read the shadow page to validate both pairs and retrieve the number of records */
if ((fread (&lcFCR_shadow, sizeof(FCR), 1, cl->fHandle)) != 1) return freeClient (cl, IO_ERROR);
if (lcFCR.FCRUsageCount > lcFCR_shadow.FCRUsageCount)
cl->numRecs = byte_swap (*((unsigned long*)&lcFCR.numRecs));
cl->numRecs = read_word_swapped_u32(lcFCR.numRecs);
else
cl->numRecs = byte_swap (*((unsigned long*)&lcFCR_shadow.numRecs));
}else{ /* less then 6x format */
cl->numRecs = read_word_swapped_u32(lcFCR_shadow.numRecs);
}else{ /* less then 6x format */
cl->fPageSize = lcFCR.PageSize;
cl->VFragParam = VFRAG_CUT_V5;
cl->numRecs = byte_swap (*((unsigned long*)&lcFCR.numRecs));
cl->numRecs = read_word_swapped_u32(lcFCR.numRecs);
}

if (cl->fVersion >= BTRIEVE_FILE_V6 && cl->fVersion < BTRIEVE_FILE_V7){
Expand All @@ -409,7 +456,7 @@ unsigned short int BF_OPEN (CLIENT_STRUCT *cl, char *fName)

/* allocate memory to hold the current data page */
if ((cl->CUR_DPAGE = (char*) malloc (cl->fPageSize)) == NULL) return IO_ERROR;
else *(long*)cl->CUR_DPAGE = 0L;
else write_le32(cl->CUR_DPAGE, 0);

/* get the max number of pages */
fseek (cl->fHandle, 0, SEEK_END);
Expand All @@ -423,7 +470,7 @@ unsigned short int BF_OPEN (CLIENT_STRUCT *cl, char *fName)
/* if var-rec's, allocate memory to hold the current var-data page */
if (cl->VarRecsAllowed){
if ((cl->CUR_VPAGE = (char*) malloc (cl->fPageSize)) == NULL) return IO_ERROR;
else *(long*)cl->CUR_VPAGE = 0L;
else write_le32(cl->CUR_VPAGE, 0);
}

return NO_ERROR;
Expand All @@ -436,7 +483,7 @@ unsigned short int BF_OPEN (CLIENT_STRUCT *cl, char *fName)
* *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static long int lp_pp(CLIENT_STRUCT *cl, long int lp )
{
{
unsigned long int ret, pat1, pat2;
unsigned short int u1, u2, pppat;

Expand All @@ -451,20 +498,29 @@ static long int lp_pp(CLIENT_STRUCT *cl, long int lp )

pat1 = ret * (long)cl->fPageSize; // first PAT of pair
pat2 = pat1 + (long)cl->fPageSize; // second right after it
fseek( cl->fHandle, pat1+4L, 0 ); // get both usage counts
fread( &u1, 2, 1, cl->fHandle );
fseek( cl->fHandle, pat2+4L, 0 );
fread( &u2, 2, 1, cl->fHandle );
{
unsigned char rawUsage[2];

fseek( cl->fHandle, pat1+4L, 0 ); // get both usage counts
fread( rawUsage, sizeof(rawUsage), 1, cl->fHandle );
u1 = read_le16(rawUsage);
fseek( cl->fHandle, pat2+4L, 0 );
fread( rawUsage, sizeof(rawUsage), 1, cl->fHandle );
u2 = read_le16(rawUsage);
}
if( u1 > u2 ) // choose most recent one
ret = pat1;
else
ret = pat2;

ret += (long)(( lp << 2 ) + 4L ); // position in PAT
fseek( cl->fHandle, ret, 0 );
fread( &lp, 4, 1, cl->fHandle ); // read it into LP
{
unsigned char rawLp[4] = {0, 0, 0, 0};
fread( rawLp, 4, 1, cl->fHandle ); // read it into LP

lp = byte_swap( lp ); // and un-word-swap it
lp = byte_swap( read_le32(rawLp) ); // and un-word-swap it
}
lp &= 0xFFFFFFL;
}

Expand All @@ -485,32 +541,38 @@ static long int lp_pp(CLIENT_STRUCT *cl, long int lp )
*
*/
unsigned short int getNextDataPage (CLIENT_STRUCT *cl)
{
unsigned short int retval = NO_ERROR;
unsigned long int pOff;
{
unsigned short int retval = NO_ERROR;
long int pOff;
unsigned long int cPId = cl->curDPageID;

memset (cl->CUR_DPAGE, 0x00, cl->fPageSize);

while ((getPageType (cl, cl->CUR_DPAGE)) != DAT_PAGE_ID /*&& cPId < cl->fNumPages-2*/){
while (getPageType (cl, cl->CUR_DPAGE) != DAT_PAGE_ID){
uint64_t fileSize;

if (cPId >= cl->fNumPages)
return END_OF_FILE;

pOff = lp_pp (cl, cPId++);

if (pOff > (cl->fNumPages * cl->fPageSize)) continue;
fileSize = (uint64_t)cl->fNumPages * cl->fPageSize;
if (pOff < 0 || (uint64_t)pOff >= fileSize)
continue;

if ((retval = readPageFromFile (cl, cl->CUR_DPAGE, pOff)) != NO_ERROR) return retval;
if ((retval = readPageFromFile (cl, cl->CUR_DPAGE, (unsigned long)pOff)) != NO_ERROR)
return retval;

if (cl->fVersion == BTRIEVE_FILE_V6 && *(unsigned short*)(cl->CUR_DPAGE+2) != cPId -1){
*(unsigned long*)cl->CUR_DPAGE = 0L;
if (cl->fVersion == BTRIEVE_FILE_V6 && read_le16(cl->CUR_DPAGE + 2) != cPId - 1){
write_le32(cl->CUR_DPAGE, 0);
continue;
}

if (cl->fVersion == BTRIEVE_FILE_V3){
unsigned long usage = 0L;
((unsigned char*)&usage)[2] = cl->CUR_DPAGE[4];
((unsigned char*)&usage)[1] = cl->CUR_DPAGE[6];
((unsigned char*)&usage)[0] = cl->CUR_DPAGE[7];
uint32_t usage = ((uint32_t)(unsigned char)cl->CUR_DPAGE[4] << 16)
| ((uint32_t)(unsigned char)cl->CUR_DPAGE[6] << 8)
| (unsigned char)cl->CUR_DPAGE[7];
if (usage == 0){
memset (cl->CUR_DPAGE, 0x00 , 10);
memset (cl->CUR_DPAGE, 0x00, 10);
continue;
}
}
Expand All @@ -534,7 +596,7 @@ unsigned short int getVariableData (CLIENT_STRUCT *cl, char *dataBuffer, unsigne
{
unsigned short int numFrag = 0;
unsigned short int retval = 0;
unsigned long int VPageId = 0;
uint32_t VPageId = 0;
unsigned short int FragId = 0;
unsigned short int FragOff = 0;
unsigned long int pCnt = 0L;
Expand All @@ -547,15 +609,11 @@ unsigned short int getVariableData (CLIENT_STRUCT *cl, char *dataBuffer, unsigne
memcpy (dataBuffer, curRecAdr + cl->recHeaderSize, (cl->FixRecLen > *dbLen) ? *dbLen : cl->FixRecLen);

if (cl->fVersion >= BTRIEVE_FILE_V8){
VPageId = *(short*)(curRecAdr + cl->FixRecLen + cl->recHeaderSize);
numFrag = *(short*)(curRecAdr + cl->FixRecLen + 10);
VPageId = read_le16(curRecAdr + cl->FixRecLen + cl->recHeaderSize);
numFrag = read_le16(curRecAdr + cl->FixRecLen + 10);
}else{
((unsigned char*)&VPageId)[0] = * (curRecAdr + cl->recHeaderSize + curLen);
((unsigned char*)&VPageId)[1] = 0x00;
((unsigned char*)&VPageId)[2] = *(curRecAdr + cl->recHeaderSize + curLen + 1);
((unsigned char*)&VPageId)[3] = *(curRecAdr + cl->recHeaderSize + curLen + 2);
((unsigned char*)&numFrag)[0] = *(curRecAdr + cl->recHeaderSize + curLen + 3);
if (VPageId != PAGE_KICK_OFF) VPageId = byte_swap (VPageId);
VPageId = read_vrec_page_id_v5(curRecAdr + cl->recHeaderSize + curLen);
numFrag = (unsigned char)*(curRecAdr + cl->recHeaderSize + curLen + 3);
}
while (VPageId != PAGE_KICK_OFF && FragId != MAX_SHORT_INT_VAL){

Expand All @@ -579,30 +637,25 @@ unsigned short int getVariableData (CLIENT_STRUCT *cl, char *dataBuffer, unsigne
|| (fread (cl->CUR_VPAGE, cl->fPageSize, 1, cl->fHandle)) != 1) return IO_ERROR;

FragId = ((cl->fPageSize -1) >> 1) - numFrag;
FragOff = ((short*)cl->CUR_VPAGE)[FragId] & 0x7FFF;
FragOff = read_le16(cl->CUR_VPAGE + (FragId * sizeof(uint16_t))) & 0x7FFF;

/* get to the end of the fragment */
for(fEId = 1; ((short*)cl->CUR_VPAGE)[FragId - fEId] == -1; fEId++);
for(fEId = 1; read_le16(cl->CUR_VPAGE + ((FragId - fEId) * sizeof(uint16_t))) == UINT16_MAX; fEId++);

/* calculate the length of the fragment */
addLen = (((short*)cl->CUR_VPAGE)[ FragId - fEId] & 0x7FFF ) - FragOff - cl->VFragParam;
addLen = (read_le16(cl->CUR_VPAGE + ((FragId - fEId) * sizeof(uint16_t))) & 0x7FFF) - FragOff - cl->VFragParam;

if (addLen > cl->fPageSize * 2 || addLen == 0) break;

if (cl->fVersion >= BTRIEVE_FILE_V8){
VPageId = *(short*)(&((char*)cl->CUR_VPAGE)[ FragOff]);
numFrag = *(short*)(&((char*)cl->CUR_VPAGE)[ FragOff +4]);
VPageId = read_le16(&((char*)cl->CUR_VPAGE)[ FragOff]);
numFrag = read_le16(&((char*)cl->CUR_VPAGE)[ FragOff +4]);
}else{
((unsigned char*)&VPageId)[0] = * (cl->CUR_VPAGE + FragOff);
((unsigned char*)&VPageId)[1] = 0x00;
((unsigned char*)&VPageId)[2] = *(cl->CUR_VPAGE + FragOff + 1);
((unsigned char*)&VPageId)[3] = *(cl->CUR_VPAGE + FragOff + 2);
((unsigned char*)&numFrag)[0] = *(cl->CUR_VPAGE + FragOff + 3);

if (VPageId != PAGE_KICK_OFF) VPageId = byte_swap (VPageId);
VPageId = read_vrec_page_id_v5(cl->CUR_VPAGE + FragOff);
numFrag = (unsigned char)*(cl->CUR_VPAGE + FragOff + 3);

if (cl->fVersion < BTRIEVE_FILE_V6){
if (((short*)cl->CUR_VPAGE)[ FragId] & 0x8000){
if (read_le16(cl->CUR_VPAGE + (FragId * sizeof(uint16_t))) & 0x8000){
FragOff += sizeof (VRECPTR);
addLen -= sizeof(VRECPTR);
}else VPageId = PAGE_KICK_OFF;
Expand Down Expand Up @@ -675,13 +728,13 @@ unsigned short int BF_GET_REC (CLIENT_STRUCT *cl, char *dataBuffer, unsigned lon

if (cl->numRecs == 0L) return END_OF_FILE;
while ((retval = getNextRecord (cl)) == NO_ERROR){
if (cl->fVersion >= BTRIEVE_FILE_V6 && *(unsigned short*)(cl->curRecAdr) != 0x0000){
if (cl->fVersion >= BTRIEVE_FILE_V6 && read_le16(cl->curRecAdr) != 0x0000){
break;
}else if (cl->fVersion < BTRIEVE_FILE_V6){
unsigned long int i = 0;
char isEmpty = true;

if (cl->fVersion == BTRIEVE_FILE_V3 && *(unsigned short int*)cl->curRecAdr == 0x0000) continue;
if (cl->fVersion == BTRIEVE_FILE_V3 && read_le16(cl->curRecAdr) == 0x0000) continue;

for (i = ((cl->fVersion >= BTRIEVE_FILE_V4)? RECORD_HEADER_SIZE_V4 : RECORD_HEADER_SIZE_V3) ;
i < cl->IFixedRecLen ; i++){
Expand All @@ -698,7 +751,10 @@ unsigned short int BF_GET_REC (CLIENT_STRUCT *cl, char *dataBuffer, unsigned lon

if (retval != NO_ERROR) return retval;

cl->curRecordId ++;
if (cl->curRecordId == MAX_LONG_INT_VAL)
cl->curRecordId = 0;
else
cl->curRecordId ++;

if (cl->VarRecsAllowed){
retval = getVariableData (cl, dataBuffer, dbLen, cl->curRecAdr);
Expand Down
Loading