void LFA_Move ( LFA_FileRef srcFile, XMP_Int64 srcOffset, LFA_FileRef dstFile, XMP_Int64 dstOffset, XMP_Int64 length, XMP_AbortProc abortProc /* = 0 */, void * abortArg /* = 0 */ ) { enum { kBufferLen = 64*1024 }; XMP_Uns8 buffer [kBufferLen]; const bool checkAbort = (abortProc != 0); if ( srcOffset > dstOffset ) { // avoiding shadow effects // move down -> shift lowest packet first ! while ( length > 0 ) { if ( checkAbort && abortProc(abortArg) ) LFA_Throw ( "LFA_Move - User abort", kLFAErr_UserAbort ); XMP_Int32 ioCount = kBufferLen; if ( length < kBufferLen ) ioCount = (XMP_Int32)length; //smartly avoids 32/64 bit issues LFA_Seek ( srcFile, srcOffset, SEEK_SET ); LFA_Read ( srcFile, buffer, ioCount, kLFA_RequireAll ); LFA_Seek ( dstFile, dstOffset, SEEK_SET ); LFA_Write ( dstFile, buffer, ioCount ); length -= ioCount; srcOffset += ioCount; dstOffset += ioCount; } } else { // move up -> shift highest packet first srcOffset += length; //move to end dstOffset += length; while ( length > 0 ) { if ( checkAbort && abortProc(abortArg) ) LFA_Throw ( "LFA_Move - User abort", kLFAErr_UserAbort ); XMP_Int32 ioCount = kBufferLen; if ( length < kBufferLen ) ioCount = (XMP_Int32)length; //smartly avoids 32/64 bit issues srcOffset -= ioCount; dstOffset -= ioCount; LFA_Seek ( srcFile, srcOffset, SEEK_SET ); LFA_Read ( srcFile, buffer, ioCount, kLFA_RequireAll ); LFA_Seek ( dstFile, dstOffset, SEEK_SET ); LFA_Write ( dstFile, buffer, ioCount ); length -= ioCount; } } } // LFA_Move
XMP_Uns64 TagTree::digest64u(LFA_FileRef file,const std::string key /* ="" */, bool BigEndian /*=false*/,bool hexDisplay /*=false*/ ) { XMP_Uns64 r; if (8 != LFA_Read ( file, &r, 8, false)) // require all == false => leave the throwing to this routine Log::error("could not read 8-byte value from file (end of file?)"); if ( ((kBigEndianHost==1) && !BigEndian ) || ((kBigEndianHost==0) && BigEndian )) // "XOR" Flip8(&r); if (!key.empty()) { char out[25]; //largets 64 bit no: 18446744073709551616 -1 (20 digits) if (!hexDisplay) { //not working, 0x1244e7780 ==> 609122176 decimal (== 0x244e7780) #if WIN_ENV snprintf(out , 24 , "%I64u" , r); #else // MAC, UNIX snprintf(out , 24 , "%llu" , r); #endif } else { //not working, upper 32 bit empty: #if WIN_ENV snprintf( out , 24 , "0x%.16I64X" , r ); #else snprintf( out , 24 , "0x%.16llX" , r ); #endif } setKeyValue(key,out); } return r; }
// ================================================================================================= // MP3_CheckFormat // =============== // For MP3 we check parts .... See the MP3 spec for offset info. bool MP3_CheckFormat ( XMP_FileFormat format, XMP_StringPtr filePath, LFA_FileRef file, XMPFiles * parent ) { IgnoreParam(filePath); IgnoreParam(parent); //supress warnings XMP_Assert ( format == kXMP_MP3File ); //standard assert LFA_Rewind( file ); XMP_Uns8 header[3]; LFA_Read( file, header, 3, true ); if ( !CheckBytes( &header[0], "ID3", 3 )) return (parent->format == kXMP_MP3File); // No ID3 signature -> depend on first call hint. XMP_Uns8 major = LFA_ReadUns8( file ); XMP_Uns8 minor = LFA_ReadUns8( file ); if ( (major<3 || major>4) || (minor == 0xFF) ) return false; // only support IDv2.3 and ID3v2.4, minor must not be 0xFF XMP_Uns8 flags = LFA_ReadUns8( file ); //TODO if ( flags & 0x10 ) XMP_Throw("no support for MP3 with footer",kXMPErr_Unimplemented); //no support for MP3 with footer if ( flags & 0x80 ) return false; //no support for unsynchronized MP3 (as before, also see [1219125]) if ( flags & 0x0F ) XMP_Throw("illegal header lower bits",kXMPErr_Unimplemented); XMP_Uns32 size = LFA_ReadUns32_BE( file ); if ( size & 0x80808080 ) return false; //if any bit survives -> not a valid synchsafe 32 bit integer return true; } // MP3_CheckFormat
static bool ReadChunk ( LFA_FileRef inFileRef, UInt64 & pos, UInt32 len, char * outBuffer ) { if ( (inFileRef == 0) || (outBuffer == 0) ) return false; LFA_Seek (inFileRef, pos, SEEK_SET ); UInt32 bytesRead = LFA_Read ( inFileRef, outBuffer, len ); if ( bytesRead != len ) return false; return true; }
bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, XMP_Uns8* outBuffer ) { try { if ( (fileRef == 0) || (outBuffer == 0) ) return false; LFA_Seek ( fileRef, pos, SEEK_SET ); long bytesRead = LFA_Read ( fileRef, outBuffer, len ); return ( (XMP_Uns32)bytesRead == len ); } catch ( ... ) {} return false; } // ReadBuffer
XMP_Int16 TagTree::digest16s(LFA_FileRef file,const std::string key /* ="" */ , bool BigEndian /*=false*/ ) { XMP_Int16 r; if (2 != LFA_Read ( file, &r, 2, false)) // require all == false => leave the throwing to this routine Log::error("could not read 2-byte value from file (end of file?)"); if ( ((kBigEndianHost==1) && !BigEndian ) || ((kBigEndianHost==0) && BigEndian )) // "XOR" Flip2(&r); if (!key.empty()) { char out[10]; //longest signed int is "�768", 6 chars snprintf(out,9,"%d",r); setKeyValue(key,out); } return r; }
XMP_Int32 TagTree::digest32s(LFA_FileRef file,const std::string key /* ="" */ , bool BigEndian /*=false*/ ) { XMP_Int32 r; if (4 != LFA_Read ( file, &r, 4, false)) // require all == false => leave the throwing to this routine Log::error("could not read 4-byte value from file (end of file?)"); if ( ((kBigEndianHost==1) && !BigEndian ) || ((kBigEndianHost==0) && BigEndian )) // "XOR" Flip4(&r); if (!key.empty()) { char out[15]; //longest signed int is "�47483648", 11 chars snprintf(out,14,"%d",r); //signed, mind the trailing \0 on Mac btw setKeyValue(key,out); } return r; }
//////////////////////////////////////////////////////////////////////////////////// // numeric digest routines // XMP_Int64 TagTree::digest64s(LFA_FileRef file,const std::string key /* ="" */ , bool BigEndian /*=false*/ ) { XMP_Int64 r; if (8 != LFA_Read ( file, &r, 8, false)) // require all == false => leave the throwing to this routine Log::error("could not read 8-byte value from file (end of file?)"); if ( ((kBigEndianHost==1) && !BigEndian ) || ((kBigEndianHost==0) && BigEndian )) // "XOR" Flip8(&r); if (!key.empty()) { char out[25]; //longest is "18446744073709551615", 21 chars ==> 25 snprintf(out,24,"%lld",r); //signed, mind the trailing \0 on Mac btw setKeyValue(key,out); } return r; }
XMP_Uns16 TagTree::digest16u(LFA_FileRef file,const std::string key /* ="" */, bool BigEndian /*=false*/,bool hexDisplay /*=false*/ ) { XMP_Uns16 r; if (2 != LFA_Read ( file, &r, 2, false)) // require all == false => leave the throwing to this routine Log::error("could not read 2-byte value from file (end of file?)"); if ( ((kBigEndianHost==1) && !BigEndian ) || ((kBigEndianHost==0) && BigEndian )) // "XOR" Flip2(&r); if (!key.empty()) { char out[15]; //longest unsigned int is "65536", 5 chars resp. 0xFFFF = 6 chars if (!hexDisplay) snprintf(out,14,"%u",r); else snprintf(out,14,"0x%.4X",r); setKeyValue(key,out); } return r; }
XMP_Uns32 TagTree::digest32u(LFA_FileRef file,const std::string key /* ="" */, bool BigEndian /*=false*/,bool hexDisplay /*=false*/ ) { XMP_Uns32 r; if (4 != LFA_Read ( file, &r, 4, false)) // require all == false => leave the throwing to this routine Log::error("could not read 4-byte value from file (end of file?)"); if ( ((kBigEndianHost==1) && !BigEndian ) || ((kBigEndianHost==0) && BigEndian )) // "XOR" Flip4(&r); if (!key.empty()) { char out[19]; //longest unsigned int is "2147483648", 10 chars resp. 0xFFFFFFFF 10 chars if (!hexDisplay) snprintf(out,18,"%u",r); //unsigned, mind the trailing \0 on Mac btw else snprintf(out,18,"0x%.8X",r); //unsigned, mind the trailing \0 on Mac btw setKeyValue(key,out); } return r; }
void TagTree::digest(LFA_FileRef file,const std::string key /*=NULL*/, void* returnValue /*=""*/, XMP_Int32 numOfBytes /*=0*/ ) { if (numOfBytes==0) { //0-byte requests *are* legitimate, reducing codeforks for the caller if ( !key.empty() ) setKeyValue(key,"(0 bytes)"); return; } //do we need own space or will it be provided? char* value; if (returnValue) value=(char*)returnValue; else value=new char[numOfBytes+1]; // require all == false => leave the throwing to this routine if (numOfBytes != LFA_Read ( file, value, numOfBytes, false)) // saying 1,4 guarantes read as ordered (4,1 would not) Log::error("could not read %d number of files (End of File reached?)",numOfBytes); #if !IOS_ENV char* out=new char[2 + numOfBytes*3 + 5]; //'0x12 34 45 78 ' length formula: 2 ("0x") + numOfBytes x 3 + 5 (padding) if (!key.empty()) { snprintf(out,3,"0x"); XMP_Int64 i; // *) for (i=0; i < numOfBytes; i++) snprintf(&out[2+i*3],4,"%.2X ",value[i]); //always must allow that extra 0-byte on mac (overwritten again and again) snprintf(&out[2+i*3],1,"%c",'\0'); // *) using i one more time (needed while bug 1613297 regarding snprintf not fixed) setKeyValue(key,out); } #else char* out=new char[2 + numOfBytes*9 + 5]; //'0x12 34 45 78 ' length formula: 2 ("0x") + numOfBytes x 3 + 5 (padding) if (!key.empty()) { snprintf(out,3,"0x"); XMP_Int64 i; // *) for (i=0; i < numOfBytes; i++) snprintf(&out[2+i*9],10,"%.8X ",value[i]); //always must allow that extra 0-byte on mac (overwritten again and again) snprintf(&out[2+i*9],1,"%c",'\0'); // *) using i one more time (needed while bug 1613297 regarding snprintf not fixed) setKeyValue(key,out); } #endif delete [] out; if (!returnValue) delete [] value; //if we own it, we delete it }
void FileInfo::CheckFormat ( LFA_FileRef fileRef ) { IOBuffer ioBuf; LFA_Seek ( fileRef, 0, SEEK_SET ); if ( CheckFileSpace ( fileRef, &ioBuf, SWF_SIGNATURE_LEN ) ) { if ( CheckBytes ( ioBuf.ptr, SWF_F_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) { this->compressedFile = false; } else if ( CheckBytes ( ioBuf.ptr, SWF_C_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) { this->compressedFile = true; } LFA_Seek ( fileRef, 4, SEEK_SET ); XMP_Uns8 buffer[4]; LFA_Read ( fileRef, buffer, 4 ); iSize = GetUns32LE ( buffer ); } LFA_Seek ( fileRef, 0, SEEK_SET ); } // FileInfo::CheckFormat
/* note! function does not rewind (LFA_Seek)) */ void LFA_Copy ( LFA_FileRef sourceFile, LFA_FileRef destFile, XMP_Int64 length, XMP_AbortProc abortProc /* = 0 */, void * abortArg /* = 0 */ ) { enum { kBufferLen = 64*1024 }; XMP_Uns8 buffer [kBufferLen]; const bool checkAbort = (abortProc != 0); while ( length > 0 ) { if ( checkAbort && abortProc(abortArg) ) { LFA_Throw ( "LFA_Copy - User abort", kLFAErr_UserAbort ); } XMP_Int32 ioCount = kBufferLen; if ( length < kBufferLen ) ioCount = (XMP_Int32)length; LFA_Read ( sourceFile, buffer, ioCount, kLFA_RequireAll ); LFA_Write ( destFile, buffer, ioCount ); length -= ioCount; } } // LFA_Copy
int FileInfo::Inf ( LFA_FileRef source, LFA_FileRef dest ) { int ret; unsigned have; z_stream strm; unsigned char in[CHUNK]; unsigned char out[CHUNK]; XMP_Uns64 allBytes = 0; // allocate inflate state strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit ( &strm ); if ( ret != Z_OK ) return ret; // decompress until deflate stream ends or end of file LFA_Seek ( source, SWF_COMPRESSION_BEGIN, SEEK_SET ); XMP_Uns64 outPos = SWF_COMPRESSION_BEGIN; try { do { strm.avail_in = LFA_Read ( source, in, CHUNK ); if ( strm.avail_in == 0 ) { ret = Z_STREAM_END; break; } strm.next_in = in; // run inflate() on input until output buffer not full do { strm.avail_out = CHUNK; strm.next_out = out; ret = inflate ( &strm, Z_NO_FLUSH ); XMP_Assert ( ret != Z_STREAM_ERROR ); // state not clobbered switch ( ret ) { case Z_NEED_DICT: ret = Z_DATA_ERROR; // and fall through case Z_DATA_ERROR: case Z_MEM_ERROR: inflateEnd ( &strm ); return ret; } have = CHUNK - strm.avail_out; LFA_Seek ( dest, outPos, SEEK_SET ); LFA_Write ( dest, out, have ); outPos += have; } while ( strm.avail_out == 0 ); // done when inflate() says it's done } while ( ret != Z_STREAM_END ); } catch ( ... ) { inflateEnd ( &strm ); return Z_ERRNO; } // clean up and return inflateEnd ( &strm ); return ( (ret == Z_STREAM_END) ? Z_OK : Z_DATA_ERROR ); } // FileInfo::Inf
void PSIR_FileWriter::ParseFileResources ( LFA_FileRef fileRef, XMP_Uns32 length ) { bool ok; this->DeleteExistingInfo(); this->fileParsed = true; if ( length == 0 ) return; // Parse the image resource block. IOBuffer ioBuf; ioBuf.filePos = LFA_Seek ( fileRef, 0, SEEK_CUR ); XMP_Int64 psirOrigin = ioBuf.filePos; // Need this to determine the resource data offsets. XMP_Int64 fileEnd = ioBuf.filePos + length; std::string rsrcPName; while ( (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)) < fileEnd ) { ok = CheckFileSpace ( fileRef, &ioBuf, 12 ); // The minimal image resource takes 12 bytes. if ( ! ok ) break; // Bad image resource. Throw instead? XMP_Int64 thisRsrcPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data); XMP_Uns32 type = GetUns32BE(ioBuf.ptr); XMP_Uns16 id = GetUns16BE(ioBuf.ptr+4); ioBuf.ptr += 6; // Advance to the resource name. XMP_Uns16 nameLen = ioBuf.ptr[0]; // ! The length for the Pascal string. XMP_Uns16 paddedLen = (nameLen + 2) & 0xFFFE; // ! Round up to an even total. Yes, +2! ok = CheckFileSpace ( fileRef, &ioBuf, paddedLen+4 ); // Get the name text and the data length. if ( ! ok ) break; // Bad image resource. Throw instead? if ( nameLen > 0 ) rsrcPName.assign ( (char*)(ioBuf.ptr), paddedLen ); // ! Include the length byte and pad. ioBuf.ptr += paddedLen; // Move to the data length. XMP_Uns32 dataLen = GetUns32BE(ioBuf.ptr); XMP_Uns32 dataTotal = ((dataLen + 1) & 0xFFFFFFFEUL); // Round up to an even total. ioBuf.ptr += 4; // Advance to the resource data. XMP_Int64 thisDataPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data); XMP_Int64 nextRsrcPos = thisDataPos + dataTotal; if ( type != k8BIM ) { XMP_Uns32 fullRsrcLen = (XMP_Uns32) (nextRsrcPos - thisRsrcPos); this->otherRsrcs.push_back ( OtherRsrcInfo ( (XMP_Uns32)thisRsrcPos, fullRsrcLen ) ); MoveToOffset ( fileRef, nextRsrcPos, &ioBuf ); continue; } InternalRsrcMap::value_type mapValue ( id, InternalRsrcInfo ( id, dataLen, kIsFileBased ) ); InternalRsrcMap::iterator newRsrc = this->imgRsrcs.insert ( this->imgRsrcs.end(), mapValue ); InternalRsrcInfo* rsrcPtr = &newRsrc->second; rsrcPtr->origOffset = (XMP_Uns32)thisDataPos; if ( nameLen > 0 ) { rsrcPtr->rsrcName = (XMP_Uns8*) malloc ( paddedLen ); if ( rsrcPtr->rsrcName == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory ); memcpy ( (void*)rsrcPtr->rsrcName, rsrcPName.c_str(), paddedLen ); // AUDIT: Safe, allocated enough bytes above. } if ( ! IsMetadataImgRsrc ( id ) ) { MoveToOffset ( fileRef, nextRsrcPos, &ioBuf ); continue; } rsrcPtr->dataPtr = malloc ( dataLen ); // ! Allocate after the IsMetadataImgRsrc check. if ( rsrcPtr->dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory ); if ( dataTotal <= kIOBufferSize ) { // The image resource data fits within the I/O buffer. ok = CheckFileSpace ( fileRef, &ioBuf, dataTotal ); if ( ! ok ) break; // Bad image resource. Throw instead? memcpy ( (void*)rsrcPtr->dataPtr, ioBuf.ptr, dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above. ioBuf.ptr += dataTotal; // ! Add the rounded length. } else { // The image resource data is bigger than the I/O buffer. LFA_Seek ( fileRef, (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)), SEEK_SET ); LFA_Read ( fileRef, (void*)rsrcPtr->dataPtr, dataLen ); FillBuffer ( fileRef, nextRsrcPos, &ioBuf ); } } #if 0 { printf ( "\nPSIR_FileWriter::ParseFileResources, count = %d\n", this->imgRsrcs.size() ); InternalRsrcMap::iterator irPos = this->imgRsrcs.begin(); InternalRsrcMap::iterator irEnd = this->imgRsrcs.end(); for ( ; irPos != irEnd; ++irPos ) { InternalRsrcInfo& thisRsrc = irPos->second; printf ( " #%d, dataLen %d, origOffset %d (0x%X)%s\n", thisRsrc.id, thisRsrc.dataLen, thisRsrc.origOffset, thisRsrc.origOffset, (thisRsrc.changed ? ", changed" : "") ); } } #endif } // PSIR_FileWriter::ParseFileResources
int FileInfo::Def ( LFA_FileRef source, LFA_FileRef dest ) { int ret, flush; unsigned have; z_stream strm; unsigned char in[CHUNK]; unsigned char out[CHUNK]; // allocate deflate state strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; ret = deflateInit ( &strm, SWF_DEFAULT_COMPRESSION_LEVEL ); if ( ret != Z_OK ) return ret; // compress until end of file LFA_Seek ( source, SWF_COMPRESSION_BEGIN, SEEK_SET ); XMP_Uns64 outPos = SWF_COMPRESSION_BEGIN; try { do { strm.avail_in = LFA_Read ( source, in, CHUNK ); flush = ( (strm.avail_in < CHUNK) ? Z_FINISH : Z_NO_FLUSH ); strm.next_in = in; // run deflate() on input until output buffer not full, finish // compression if all of source has been read in do { strm.avail_out = CHUNK; strm.next_out = out; ret = deflate ( &strm, flush ); // no bad return value XMP_Assert ( ret != Z_STREAM_ERROR ); // state not clobbered have = CHUNK - strm.avail_out; LFA_Seek ( dest, outPos, SEEK_SET ); LFA_Write ( dest, out, have ); outPos += have; } while ( strm.avail_out == 0 ); XMP_Assert ( strm.avail_in == 0 ); // all input will be used // done when last data in file processed } while ( flush != Z_FINISH ); XMP_Assert ( ret == Z_STREAM_END ); // stream will be complete } catch ( ... ) { deflateEnd ( &strm ); return Z_ERRNO; } /* clean up and return */ deflateEnd ( &strm ); return Z_OK; } // FileInfo::Def
static bool ReadTag ( LFA_FileRef inFileRef, long * outTag, UInt32 * outLength, long * subtype, UInt64 & inOutPosition, UInt64 maxOffset ) { UInt32 realLength; long bytesRead; bytesRead = LFA_Read ( inFileRef, outTag, 4 ); if ( bytesRead != 4 ) return false; *outTag = GetUns32LE ( outTag ); bytesRead = LFA_Read ( inFileRef, outLength, 4 ); if ( bytesRead != 4 ) return false; *outLength = GetUns32LE ( outLength ); realLength = *outLength; realLength += (realLength & 1); // Round up to an even value. inOutPosition = GetFilePosition ( inFileRef ); // The file offset of the data portion. UInt64 maxLength = maxOffset - inOutPosition; if ( (inOutPosition > maxOffset) || ((UInt64)(*outLength) > maxLength) ) { bool ignoreLastPad = true; // Ignore cases where a final pad byte is missing. UInt64 fileLen = LFA_Measure ( inFileRef ); if ( inOutPosition > (maxOffset + 1) ) ignoreLastPad = false; if ( (UInt64)(*outLength) > (maxLength + 1) ) ignoreLastPad = false; if ( ! ignoreLastPad ) { // Workaround for bad files in the field that have a bad size in the outermost RIFF // chunk. Do a "runtime repair" of cases where the length is too long (beyond EOF). // This handles read-only usage, update usage is repaired (or not) in the handler. bool oversizeRIFF = (inOutPosition == 8) && // Is this the initial 'RIFF' chunk? (fileLen >= 8); // Is the file at least of the minimal size? if ( ! oversizeRIFF ) { XMP_Throw ( "RIFF tag exceeds maximum length", kXMPErr_BadValue ); } else { *outLength = (UInt32)(fileLen) - 8; realLength = *outLength; realLength += (realLength & 1); // Round up to an even value. } } } *subtype = 0; if ( (*outTag != FOURCC_LIST) && (*outTag != FOURCC_RIFF) ) { UInt64 tempPos = inOutPosition + realLength; if ( tempPos <= maxOffset ) { LFA_Seek ( inFileRef, tempPos, SEEK_SET ); } else if ( (tempPos == (maxOffset + 1)) && (maxOffset == (UInt64)LFA_Measure(inFileRef)) ) { LFA_Seek ( inFileRef, 0, SEEK_END ); // Hack to tolerate a missing final pad byte. } else { XMP_Throw ( "Bad RIFF offset", kXMPErr_BadValue ); } } else { bytesRead = LFA_Read ( inFileRef, subtype, 4 ); if ( bytesRead != 4 ) return false; *subtype = GetUns32LE ( subtype ); *outLength -= 4; realLength -= 4; // Special case: // Since the 'movi' chunk can contain billions of subchunks, skip over the 'movi' subchunk. // // The 'movi' subtype is added to the list as the TAG. // The subtype is returned empty so nobody will try to parse the subchunks. if ( *subtype == listtypeAVIMOVIE ) { inOutPosition = GetFilePosition ( inFileRef ); UInt64 tempPos = inOutPosition + realLength; if ( tempPos <= maxOffset ) { LFA_Seek ( inFileRef, tempPos, SEEK_SET ); } else if ( (tempPos == (maxOffset + 1)) && (maxOffset == (UInt64)LFA_Measure(inFileRef)) ) { LFA_Seek ( inFileRef, 0, SEEK_END ); // Hack to tolerate a missing final pad byte. } else { XMP_Throw ( "Bad RIFF offset", kXMPErr_BadValue ); } *outLength += 4; *outTag = *subtype; *subtype = 0; } inOutPosition = GetFilePosition ( inFileRef ); } return true; }
// TOTEST char LFA_GetChar( LFA_FileRef file ) { XMP_Uns8 c; LFA_Read( file, &c, 1, true); return c; }