|
|
/*****************************************************************************
* * * FILEOFF.C * * * * Copyright (C) Microsoft Corporation 1995. * * All Rights reserved. * * * ****************************************************************************** * * * Module Intent * * * * File Offset data type to replace using LONG for file offsets to handle * * files larger than 4 gigs in size. * * WARNING: To support 68K retail version, some functions don't have the * Pascal keyword. MSVC 4.0 had a bug that caused structure parameter to * * destroyed * * * ****************************************************************************** * * * Current Owner: davej * *****************************************************************************/
/*****************************************************************************
* * Created 07/28/95 - davej * 3/05/97 erinfox Change errors to HRESULTS * *****************************************************************************/
static char s_aszModule[] = __FILE__; /* For error report */
#include <mvopsys.h>
#include <orkin.h>
#include <fileoff.h>
/*****************************************************************************
* * * Globals * * * *****************************************************************************/
FILEOFFSET EXPORT_API foNil = {0L, 0L}; FILEOFFSET EXPORT_API foMax = {0xffffffffL,0x7ffffffeL}; FILEOFFSET EXPORT_API foMin = {0x00000000L,0x80000001L}; FILEOFFSET EXPORT_API foInvalid = {0xffffffffL, 0xffffffffL};
/*****************************************************************************
* * * Defines * * * *****************************************************************************/
/*****************************************************************************
* * * Prototypes * * * *****************************************************************************/
/***************************************************************************
* * * Private Functions * * * ***************************************************************************/
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET PASCAL FAR | MakeFo | * Make a file offset from two dwords * * @parm DWORD | dwLo | * Low order dword * * @parm DWORD | dwHi | * High order dword * * @rdesc Returns a double DWORD file offset struct * * @comm * Use this function to build file offsets that can be passed to other * functions that need them as input. * ***************************************************************************/ FILEOFFSET PASCAL FAR EXPORT_API MakeFo(DWORD dwLo, DWORD dwHi) { FILEOFFSET fo; fo.dwOffset=dwLo; fo.dwHigh=dwHi; return fo; }
/***************************************************************************
* * @doc PRIVATE * * @func FILEOFFSET PASCAL FAR | FoFromSz | * Convert a variable byte value to a FILEOFFSET * * @parm LPBYTE | szBytes | * Byte array containing variable byte length * * @rdesc Returns a double DWORD file offset struct from data of the form: * If High Bit Set, more bits follow (up to 9 bytes for 64 bits). * max for: 1 byte = 127 * 2 bytes = 16384 * 3 bytes = 2 M * 4 bytes = 268 M * 5 bytes = 34 G * 6 bytes = 4 T * 7 bytes = 562 T * 8 bytes = 72 Q * 9 bytes = 9223 Q (virtually infinite) * * @comm * Only a maximum of 9 bytes will be read from szBytes in the worst * case (or likely if szBytes points to invalid data). Use <f LenSzFo> * to get the length of a byte array for advancing to the next encoded * offset for example. * ***************************************************************************/
FILEOFFSET PASCAL FAR EXPORT_API FoFromSz(LPBYTE sz) { register DWORD offset; register FILEOFFSET fo; register DWORD high=0L;
for (;;) { offset=*sz; // Insert Segment A
if (!(*(sz++)&0x80)) break; offset&=0x7f; offset|=((DWORD)(*sz))<<7; // Insert Segment B
if (!(*(sz++)&0x80)) break; offset&=0x3fff; offset|=((DWORD)(*sz))<<14; // Insert Segment C
if (!(*(sz++)&0x80)) break; offset&=0x1fffff; offset|=(((DWORD)*sz))<<21; // Insert Segment D
if (!(*(sz++)&0x80)) break; offset&=0xfffffff; offset|=((DWORD)(*sz))<<28; // Insert Segment E
high|=(*sz)>>4; if (!(*(sz++)&0x80)) break; high&=0x7; high|=(((DWORD)*sz))<<3; // Insert Segment F;
if (!(*(sz++)&0x80)) break; high&=0x3ff; high|=((DWORD)(*sz))<<10; // Insert Segment G
if (!(*(sz++)&0x80)) break; high&=0x1ffff; high|=((DWORD)(*sz))<<17; // Insert Segment H
if (!(*(sz++)&0x80)) break; high&=0xffffff; high|=((DWORD)(*sz))<<24; // Segment I
break; }
fo.dwOffset=offset; fo.dwHigh=high; return fo; }
/***************************************************************************
* * @doc PRIVATE * * @func WORD PASCAL FAR | FoToSz | * Convert a file offset to a string * * @parm FILEOFFSET | fo | * File offset to convert to string representation * * @parm LPBYTE | szBytes | * Byte array to contain variable byte address * * @rdesc Returns number of bytes copied. * See <f LcbFromSz> for description of byte array format * * @comm * The byte array should contain at least 9 valid bytes should be allocated, * since at most the 9 bytes starting at <p szBytes> may be filled in. * ***************************************************************************/
WORD PASCAL FAR EXPORT_API FoToSz(FILEOFFSET fo, LPBYTE sz) { register DWORD offset = fo.dwOffset; register DWORD high = fo.dwHigh; WORD wSize=1; for (;;) { *sz=(BYTE)(offset&0x7f); // A byte
offset>>=7; if (!(offset|high)) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)(offset&0x7f); // B byte
offset>>=7; if (!(offset|high)) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)(offset&0x7f); // C byte
offset>>=7; if (!(offset|high)) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)(offset&0x7f); // D byte
offset>>=7; if (!(offset|high)) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)(offset&0x0f); // E byte
*sz|=(BYTE)((high&0x07)<<4); high>>=3; if (!high) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)(high&0x7f); // F Byte
high>>=7; if (!high) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)(high&0x7f); // G Byte
high>>=7; if (!high) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)(high&0x7f); // H Byte
high>>=7; if (!high) break; wSize++; *(sz++)|=0x80; *sz=(BYTE)high; // I byte
break; }
return wSize; }
/***************************************************************************
* * @doc PRIVATE * * @func WORD PASCAL FAR | LenSzFo | * Find number of bytes comprising this byte-array address code * * @parm LPBYTE | szBytes | * Byte array containing variable byte address * * @rdesc Returns number of bytes in byte-array for this address * ***************************************************************************/
WORD PASCAL FAR EXPORT_API LenSzFo(LPBYTE sz) { register WORD wLen=1; while ((*(sz++))&0x80) wLen++; return wLen; }
/***************************************************************************
* * @doc PRIVATE * * @func FILEOFFSET FAR | FoAddDw | * Add a dword to a file offset * * @parm FILEOFFSET | fo | * Byte array containing variable byte length * * @parm DWORD | dwAdd | * Add this amount to the file offset * * @rdesc Returns the sum of the file offset fo and dwAdd as a FILEOFFSET. * Since only a dword is added, the dwHigh dword will never increase * more than one. * * ***************************************************************************/
FILEOFFSET FAR EXPORT_API FoAddDw(FILEOFFSET fo, DWORD dwAdd) { register FILEOFFSET foSum = fo;
foSum.dwOffset+=dwAdd; if (foSum.dwOffset<fo.dwOffset) foSum.dwHigh++; return foSum; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET FAR | FoAddFo | * Add a file offset to another file offset * * @parm FILEOFFSET | fo1 | * File Offset 1 * * @parm FILEOFFSET | fo2 | * File Offset 2 * * @rdesc Returns the sum fo1 + fo2 as a FILEOFFSET. * * ***************************************************************************/
FILEOFFSET FAR EXPORT_API FoAddFo(FILEOFFSET fo1, FILEOFFSET fo2) { FILEOFFSET foSum; foSum.dwOffset=fo1.dwOffset+fo2.dwOffset; foSum.dwHigh=fo2.dwHigh+fo1.dwHigh+((foSum.dwOffset<fo1.dwOffset)?1:0); return foSum; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET FAR | FoSubFo | * Subtract file offsets, return a file offset * * @parm FILEOFFSET | fo1 | * File Offset 1 * * @parm FILEOFFSET | fo2 | * File Offset 2 * * @rdesc Returns fo1 - fo2 as a FILEOFFSET. * * @comm A Negative result will have 0xffffffff for the the dwHigh * member, and the dwOffset should be interpreted as a signed * value. * ***************************************************************************/
FILEOFFSET FAR EXPORT_API FoSubFo(FILEOFFSET fo1, FILEOFFSET fo2) { FILEOFFSET foSum; foSum.dwOffset=fo1.dwOffset-fo2.dwOffset; foSum.dwHigh=fo1.dwHigh-fo2.dwHigh-((fo1.dwOffset<fo2.dwOffset)?1:0);
return foSum; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET FAR | FoMultFo | * Multiply two offset values * * @parm FILEOFFSET | fo1 | * File Offset 1 * * @parm FILEOFFSET | fo2 | * File Offset 2 * * @rdesc Returns fo1 * fo2 as a FILEOFFSET. * * @comm If both fo1 and fo2 are less than 0xffffffff, then the result * is guaranteed to fit in a FILEOFFSET, otherwise, the result may * not be correct if overflow occurs. * ***************************************************************************/
FILEOFFSET FAR EXPORT_API FoMultFo(FILEOFFSET fo1, FILEOFFSET fo2) { DWORD dwTop0,dwTop1,dwTop2,dwTop3; DWORD dwBot0,dwBot1,dwBot2,dwBot3; DWORD dwRes0=0; DWORD dwRes1=0; DWORD dwRes2=0; DWORD dwRes3=0; DWORD dwTemp; FILEOFFSET foResult;
// Get terms
dwTop0=(DWORD)HIWORD(fo1.dwHigh); dwTop1=(DWORD)LOWORD(fo1.dwHigh); dwTop2=(DWORD)HIWORD(fo1.dwOffset); dwTop3=(DWORD)LOWORD(fo1.dwOffset);
dwBot0=(DWORD)HIWORD(fo2.dwHigh); dwBot1=(DWORD)LOWORD(fo2.dwHigh); dwBot2=(DWORD)HIWORD(fo2.dwOffset); dwBot3=(DWORD)LOWORD(fo2.dwOffset);
// Do term by term multiplication and accumulate column results
dwTemp=dwTop3*dwBot3; dwRes3+=LOWORD(dwTemp); dwRes2+=HIWORD(dwTemp);
dwTemp=dwTop2*dwBot3; dwRes2+=LOWORD(dwTemp); dwRes1+=HIWORD(dwTemp);
dwTemp=dwTop1*dwBot3; dwRes1+=LOWORD(dwTemp); dwRes0+=HIWORD(dwTemp);
dwTemp=dwTop0*dwBot3; dwRes0+=LOWORD(dwTemp); dwTemp=dwTop3*dwBot2; dwRes2+=LOWORD(dwTemp); dwRes1+=HIWORD(dwTemp);
dwTemp=dwTop2*dwBot2; dwRes1+=LOWORD(dwTemp); dwRes0+=HIWORD(dwTemp);
dwTemp=dwTop1*dwBot2; dwRes0+=LOWORD(dwTemp);
dwTemp=dwTop3*dwBot1; dwRes1+=LOWORD(dwTemp); dwRes0+=HIWORD(dwTemp);
dwTemp=dwTop2*dwBot1; dwRes0+=LOWORD(dwTemp);
dwTemp=dwTop3*dwBot0; dwRes0+=LOWORD(dwTemp); // Do the carry
dwRes2+=HIWORD(dwRes3); dwRes1+=HIWORD(dwRes2); dwRes0+=HIWORD(dwRes1); // Make the result
foResult.dwOffset=MAKELONG((dwRes3&0xffff),(dwRes2&0xffff)); foResult.dwHigh=MAKELONG((dwRes1&0xffff),(dwRes0&0xffff));
return foResult; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET PASCAL FAR | FoMultFo | * Multiply two offset values * * @parm DWORD | dw1 | * Mutplicand * * @parm FILEOFFSET | dw2 | * Multplier * * @rdesc Returns dw1 * dw2 as a FILEOFFSET. * ***************************************************************************/
FILEOFFSET PASCAL FAR EXPORT_API FoMultDw(DWORD dw1, DWORD dw2) { DWORD dwTop2,dwTop3; DWORD dwBot2,dwBot3; DWORD dwRes0=0; DWORD dwRes1=0; DWORD dwRes2=0; DWORD dwRes3=0; DWORD dwTemp; FILEOFFSET foResult;
// Get terms
dwTop2=(DWORD)HIWORD(dw1); dwTop3=(DWORD)LOWORD(dw1);
dwBot2=(DWORD)HIWORD(dw2); dwBot3=(DWORD)LOWORD(dw2);
// Do term by term multiplication and accumulate column results
dwTemp=dwTop3*dwBot3; dwRes3+=LOWORD(dwTemp); dwRes2+=HIWORD(dwTemp);
dwTemp=dwTop2*dwBot3; dwRes2+=LOWORD(dwTemp); dwRes1+=HIWORD(dwTemp); dwTemp=dwTop3*dwBot2; dwRes2+=LOWORD(dwTemp); dwRes1+=HIWORD(dwTemp);
dwTemp=dwTop2*dwBot2; dwRes1+=LOWORD(dwTemp); dwRes0+=HIWORD(dwTemp); // Do the carry
dwRes2+=HIWORD(dwRes3); dwRes1+=HIWORD(dwRes2); dwRes0+=HIWORD(dwRes1); // Make the result
foResult.dwOffset=MAKELONG((dwRes3&0xffff),(dwRes2&0xffff)); foResult.dwHigh=MAKELONG((dwRes1&0xffff),(dwRes0&0xffff));
return foResult; }
/***************************************************************************
* * @doc INTERNAL * * @func DWORD PASCAL FAR | DwSubFo | * Return the difference of two file offsets * * @parm FILEOFFSET | foA | * File offset * * @parm FILEOFFSET | foB | * File offset to subtract from foA * * @rdesc Returns the difference foA - foB as a DWORD. Result undefined * for differences greater than the dword size of a long. * * @comm * If a negative value is expected, the returned dword may be interpreted * as a signed value. * ***************************************************************************/
DWORD FAR EXPORT_API DwSubFo(FILEOFFSET foA, FILEOFFSET foB) { // When foA.dwHigh = foB.dwHigh+1, it still works.
return foA.dwOffset-foB.dwOffset; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET PASCAL FAR | FoIsNil | * Check whether the file offset is Nil. Nil is defined to be {0L,0L}. * * @parm FILEOFFSET | fo | * File offset to check * * @rdesc Returns TRUE if the file offset is equivalent to Nil. * ***************************************************************************/
BOOL PASCAL FAR EXPORT_API FoIsNil(FILEOFFSET fo) { return ((fo.dwOffset==foNil.dwOffset) && (fo.dwHigh==foNil.dwHigh))?TRUE:FALSE; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET PASCAL FAR | FoEquals | * Compare any two file offsets for equality * * @parm FILEOFFSET | fo1 | * File offset to check * * @parm FILEOFFSET | fo2 | * File offset to check against * * @rdesc Returns TRUE if fo1 == fo2 * ***************************************************************************/
BOOL PASCAL FAR EXPORT_API FoEquals(FILEOFFSET fo1, FILEOFFSET fo2) { return ((fo1.dwOffset==fo2.dwOffset) && (fo1.dwHigh==fo2.dwHigh))?TRUE:FALSE; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET PASCAL FAR | FoCompare | * Compare any two file offsets * * @parm FILEOFFSET | fo1 | * File offset to check * * @parm FILEOFFSET | fo2 | * File offset to check against * * @rdesc Returns negative if fo1 <lt> fo2, 0 if fo1 == fo2, positive if * fo1 > fo2 * ***************************************************************************/
short int PASCAL FAR EXPORT_API FoCompare(FILEOFFSET foLeft, FILEOFFSET foRight) { if (foLeft.dwHigh==foRight.dwHigh) { if (foLeft.dwOffset<foRight.dwOffset) return -1; else if (foLeft.dwOffset>foRight.dwOffset) return 1; else return 0; } else if ((long)foLeft.dwHigh<(long)foRight.dwHigh) return -1; else return 1; }
|