CachedFileStream::CachedFileStream(const char* stream, bool autoFree) { ExtractFileFromPath( filename, stream ); PathJoin( originalfile, core->CachePath, filename, NULL ); str = _fopen( originalfile, "rb" ); if (str == NULL) { // File was not found in cache if (core->GameOnCD) { _FILE* src = _fopen( stream, "rb" ); #ifdef _DEBUG core->CachedFileStreamPtrCount++; #endif _FILE* dest = _fopen( originalfile, "wb" ); #ifdef _DEBUG core->CachedFileStreamPtrCount++; #endif void* buff = malloc( 1024 * 1000 ); do { size_t len = _fread( buff, 1, 1024 * 1000, src ); size_t c = _fwrite( buff, 1, len, dest ); if (c != len) { printf("CachedFileStream failed to write to cached file '%s' (from '%s')\n", originalfile, stream); abort(); } } while (!_feof( src )); free( buff ); _fclose( src ); #ifdef _DEBUG core->CachedFileStreamPtrCount--; #endif _fclose( dest ); #ifdef _DEBUG core->CachedFileStreamPtrCount--; #endif } else { // Don't cache files already on hdd strncpy(originalfile, stream, _MAX_PATH); } str = _fopen( originalfile, "rb" ); } #ifdef _DEBUG core->CachedFileStreamPtrCount++; #endif startpos = 0; _fseek( str, 0, SEEK_END ); size = _ftell( str ); _fseek( str, 0, SEEK_SET ); Pos = 0; this->autoFree = autoFree; }
/*! \param Option */ xbShort xbDbf::GetDbtHeader( xbShort Option ) { char *p; xbShort i; char MemoBlock[24]; /* Option = 0 --> read only first four bytes 1 --> read the entire thing */ if( !mfp ) return XB_NOT_OPEN; if( _fseek( mfp, 0, SEEK_SET )) return XB_SEEK_ERROR; if(( fread( MemoBlock, 24, 1, mfp )) != 1 ) return XB_READ_ERROR; p = MemoBlock; MemoHeader.NextBlock = xbase->GetLong( p ); if(IsType3Dbt() || Option == 0) return XB_NO_ERROR; /* version IV stuff follows */ p+=8; for( i = 0; i < 8; i++, p++ ) MemoHeader.FileName[i] = *p; MemoHeader.Version = *p; p+=4; MemoHeader.BlockSize = xbase->GetShort( p ); return XB_NO_ERROR; }
// Calculate number of additional pages required to be allocated on heap by bootloader. Result CalcRequiredAllocSizeFor3DSX(Handle file, u32* numOut) { _fseek(file, 0x0, SEEK_SET); _3DSX_Header hdr; if (_fread(&hdr, sizeof(hdr), file) != 0) return -1; if (hdr.magic != _3DSX_MAGIC) return -2; _3DSX_LoadInfo d; d.segSizes[0] = (hdr.codeSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[0] >= hdr.codeSegSize); // int overflow d.segSizes[1] = (hdr.rodataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[1] >= hdr.rodataSegSize); // int overflow d.segSizes[2] = (hdr.dataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[2] >= hdr.dataSegSize); // int overflow // Calculate # of pages required. u32 pagesRequired = d.segSizes[0]/0x1000 + d.segSizes[1]/0x1000 + d.segSizes[2]/0x1000; // XXX: int overflow if(pagesRequired > CN_TOTAL3DSXPAGES) *numOut = pagesRequired - CN_TOTAL3DSXPAGES + 1; else *numOut = 0; //svc_closeHandle(file); return 0; }
xbShort xbDbf::ReadMemoBlock( xbLong BlockNo, xbShort Option ) { size_t ReadSize; CurMemoBlockNo = -1; if( BlockNo < 1L ) return XB_INVALID_BLOCK_NO; if( _fseek( mfp,((xbOffT)BlockNo*MemoHeader.BlockSize), SEEK_SET )) return XB_SEEK_ERROR; if( Option == 0 || Option == 1 ) ReadSize = MemoHeader.BlockSize; else ReadSize = 8L; if(fread( mbb, ReadSize, 1, mfp ) != 1 ) return XB_READ_ERROR; if( Option == 0 || Option == 4){ // 1st block of a set of valid data blocks mfield1 = xbase->GetShort( (char *) mbb ); MStartPos = xbase->GetShort( (char *) mbb+2 ); MFieldLen = xbase->GetLong ( (char *) mbb+4 ); } else if( Option == 2 ){ // 1st block of a set of free blocks NextFreeBlock = xbase->GetLong( (char *) mbb ); FreeBlockCnt = xbase->GetLong( (char *) mbb+4 ); } if( Option == 0 || Option == 1 ) CurMemoBlockNo = BlockNo; return XB_NO_ERROR; }
CachedFileStream::CachedFileStream(CachedFileStream* cfs, int startpos, int size, bool autoFree) { this->size = size; this->startpos = startpos; this->autoFree = autoFree; char cpath[_MAX_PATH]; PathJoin( cpath, core->CachePath, cfs->filename, NULL ); str = _fopen( cpath, "rb" ); if (str == NULL) { str = _fopen( cfs->originalfile, "rb" ); if (str == NULL) { printf( "Can't open stream (maybe leaking?)\n" ); return; } strncpy( originalfile, cfs->originalfile, sizeof(originalfile) ); strncpy( filename, cfs->filename, sizeof(filename) ); } else { strncpy( originalfile, cpath, sizeof(originalfile) ); strncpy( filename, cfs->filename, sizeof(filename) ); } #ifdef _DEBUG core->CachedFileStreamPtrCount++; #endif _fseek( str, startpos, SEEK_SET ); Pos = 0; }
/* A portable fseek() function return 0 on success, non-zero on failure (with errno set) */ int my_fseek (FILE *fp, my_off_t offset, int whence) { #if defined (HAVE_FSEEKO) && SIZEOF_OFF_T >= 8 return fseeko(fp, offset, whence); #elif defined (HAVE_FSEEK64) return fseek64(fp, offset, whence); #elif defined (__BEOS__) return _fseek(fp, offset, whence); #elif SIZEOF_FPOS_T >= 8 /* lacking a 64-bit capable fseek(), use a 64-bit capable fsetpos() and fgetpos() to implement fseek()*/ fpos_t pos; switch (whence) { case SEEK_END: #ifdef MS_WINDOWS fflush (fp); if (_lseeki64 (fileno(fp), 0, 2) == -1) return -1; #else if (fseek (fp, 0, SEEK_END) != 0) return -1; #endif /* fall through */ case SEEK_CUR: if (fgetpos (fp, &pos) != 0) return -1; offset += pos; break; /* case SEEK_SET: break; */ } return fsetpos(fp, &offset); #else #error "Large file support, but no way to fseek." #endif }
/*! */ xbShort xbDbf::OpenMemoFile() { if (Version == (char)0xf5 || Version == (char)0x30) return OpenFPTFile(); xbShort len, rc; xbOffT Size, NewSize, l; MemofileName = GetFileName(); len = GetFileName().len() - 1; if( MemofileName[len] == 'F' ) MemofileName.putAt(len, 'T'); else if( MemofileName[len] == 'f' ) MemofileName.putAt(len, 't'); else return XB_INVALID_NAME; if(( mfp = fopen( MemofileName, "r+b" )) == NULL ){ // // Try to open read only if can't open read/write // if(( mfp = fopen( MemofileName, "rb" )) == NULL ) return XB_OPEN_ERROR; } #ifdef XB_LOCKING_ON setbuf( mfp, NULL ); #endif if(( rc = GetDbtHeader(1)) != 0 ){ fclose( mfp ); return rc; } len = GetMemoBlockSize(); if( len == 0 || ((len % 512) != 0 )){ fclose( mfp ); return XB_INVALID_BLOCK_SIZE; } /* logic to verify file size is a multiple of block size */ if(( rc = _fseek( mfp, 0, SEEK_END )) != 0 ){ fclose( mfp ); return XB_SEEK_ERROR; } /* if the file is not a multiple of block size, fix it, append nulls */ Size = _ftell( mfp ); if(( Size % MemoHeader.BlockSize ) != 0 ){ NewSize = ( Size / MemoHeader.BlockSize + 1) * MemoHeader.BlockSize; for( l = Size; l < NewSize; l++ ) fputc( 0x00, mfp ); } if(( mbb = (void *) malloc(len)) == NULL ){ fclose( mfp ); return XB_NO_MEMORY; } return XB_NO_ERROR; }
/*! */ xbShort xbDbf::UpdateHeadNextNode() const { char buf[4]; memset( buf, 0x00, 4 ); xbase->PutLong( buf, MemoHeader.NextBlock ); if(( _fseek( mfp, 0, SEEK_SET )) != 0 ) return XB_SEEK_ERROR; if(( fwrite( &buf, 4, 1, mfp )) != 1 ) return XB_WRITE_ERROR; return XB_NO_ERROR; }
/*! \param FieldNo */ xbLong xbDbf::GetFPTFieldLen( xbShort FieldNo ) { xbLong BlockNo; if(( BlockNo = GetLongField(FieldNo)) == 0L ) return 0L; // Seek to start_of_block + 4 if(_fseek(mfp, ((xbOffT)BlockNo * MemoHeader.BlockSize + 4), SEEK_SET) != 0) return XB_SEEK_ERROR; char h[4]; if((fread(h, 4, 1, mfp)) != 1) return XB_READ_ERROR; return xbase->GetHBFULong(h); }
int CachedFileStream::Seek(int newpos, int type) { switch (type) { case GEM_CURRENT_POS: _fseek( str, newpos, SEEK_CUR ); Pos += newpos; break; case GEM_STREAM_START: _fseek( str, startpos + newpos, SEEK_SET ); Pos = newpos; break; default: return GEM_ERROR; } //we went past the buffer if (Pos>size) { printf("[Streams]: Invalid seek position: %ld (limit: %ld)\n",Pos, size); return GEM_ERROR; } return GEM_OK; }
int fseek ( FILE * stream, long int offset, int origin ) { //printf("INTERCEPTED fseek\n"); clock_t start = clock(); int ret = _fseek(stream,offset,origin); clock_t end = clock(); double called_time = (double)(start-program_start)/(double)(CLOCKS_PER_SEC); double exec_time = (double)(end-start)/(double)(CLOCKS_PER_SEC); fprintf(logFile,"%lf %lf fseek %p %ld %d = %d\n",called_time,exec_time,stream,offset,origin,ret); return ret; }
/*! \param BlockNo \param Option */ xbShort xbDbf::WriteMemoBlock( xbLong BlockNo, xbShort Option ) { /* Option = 0 - 1st Block of a set of valid data blocks, set buckets */ /* Option = 1 - subsequant block of data in a multi block set or db III */ /* Option = 2 - 1st block of a set offree blocks, set buckets */ xbLong WriteSize; if( BlockNo < 1L ) return XB_INVALID_BLOCK_NO; CurMemoBlockNo = -1; if( Option == 0 ){ xbase->PutShort( (char *) mbb, mfield1 ); xbase->PutShort( (char *) mbb+2, MStartPos ); xbase->PutLong ( (char *) mbb+4, MFieldLen ); WriteSize = MemoHeader.BlockSize; } else if( Option == 2 ){ xbase->PutLong((char *) mbb, NextFreeBlock ); xbase->PutLong((char *) mbb+4, FreeBlockCnt ); WriteSize = 8L; } else WriteSize = MemoHeader.BlockSize; if( _fseek( mfp,((xbOffT)BlockNo*MemoHeader.BlockSize), SEEK_SET )) return XB_SEEK_ERROR; if(( fwrite( mbb, WriteSize, 1, mfp )) != 1 ) return XB_WRITE_ERROR; if( Option == 0 || Option == 1 ) CurMemoBlockNo = BlockNo; return XB_NO_ERROR; }
/*! */ xbLong xbDbf::CalcLastDataBlock() { if( _fseek( mfp, 0, SEEK_END ) != 0 ) return XB_SEEK_ERROR; return ( _ftell( mfp ) / MemoHeader.BlockSize ); }
/*! \param FieldNo \param len \param Buf \param LockOpt */ xbShort xbDbf::GetFPTField(xbShort FieldNo, xbLong len, char * Buf, xbShort LockOpt) { if (FieldNo < 0 || FieldNo > (NoOfFields - 1)) return XB_INVALID_FIELDNO; if (GetFieldType(FieldNo) != 'M') return XB_NOT_MEMO_FIELD; #ifdef XB_LOCKING_ON // if( LockOpt != -1 ) // if( LockMemoFile( XB_LOCK ) != XB_NO_ERROR ) // return XB_LOCK_FAILED; #endif xbLong BlockNo; char buf[18]; if( Version == (char)0x30 ) { memset( buf, 0x00, 18 ) ; GetField( FieldNo, buf ); BlockNo = xbase->GetLong((char*) buf); } else { BlockNo = GetLongField(FieldNo); } if ( BlockNo == 0L ) return 0L; // Seek to start_of_block + 4 // FIXME LOCK #ifdef XB_LOCKING_ON // try { #endif if (_fseek(mfp, ((xbOffT)BlockNo * MemoHeader.BlockSize + 4), SEEK_SET) != 0) return XB_SEEK_ERROR; char h[4]; if ((fread(h, 4, 1, mfp)) != 1) return XB_READ_ERROR; xbULong fLen = xbase->GetHBFULong(h); xbULong l = (fLen < (xbULong)len) ? fLen : len; if ((fread(Buf, l, 1, mfp)) != 1) return XB_READ_ERROR; Buf[l]=0; #ifdef XB_LOCKING_ON // } // catch (...) { // if (LockOpt != -1) // LockMemoFile( XB_UNLOCK ); // throw; // } #endif #ifdef XB_LOCKING_ON // if (LockOpt != -1) // LockMemoFile( XB_UNLOCK ); #endif return XB_NO_ERROR; }
int Load3DSX(Handle file, Handle process, void* baseAddr, u32 heapAddr) { // Extra heap must be deallocated before loading a new 3DSX. if(hasExtraHeap) return -5; u32 i, j, k, m; u32 endAddr = 0x00100000+CN_NEWTOTALPAGES*0x1000; SEC_ASSERT(baseAddr >= (void*)0x00100000); SEC_ASSERT((((u32) baseAddr) & 0xFFF) == 0); // page alignment _fseek(file, 0x0, SEEK_SET); _3DSX_Header hdr; if (_fread(&hdr, sizeof(hdr), file) != 0) return -1; if (hdr.magic != _3DSX_MAGIC) return -2; _3DSX_LoadInfo d; d.segSizes[0] = (hdr.codeSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[0] >= hdr.codeSegSize); // int overflow d.segSizes[1] = (hdr.rodataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[1] >= hdr.rodataSegSize); // int overflow d.segSizes[2] = (hdr.dataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[2] >= hdr.dataSegSize); // int overflow // Map extra heap. u32 pagesRequired = d.segSizes[0]/0x1000 + d.segSizes[1]/0x1000 + d.segSizes[2]/0x1000; // XXX: int overflow u32 extendedPagesSize = 0; if(pagesRequired > CN_TOTAL3DSXPAGES) { if(svc_unmapProcessMemory(process, 0x00100000, 0x02000000))return -12; u32 extendedPages = pagesRequired - CN_TOTAL3DSXPAGES + 1; u32 i; for(i=0; i<extendedPages; i++) { if(svc_controlProcessMemory(process, endAddr+i*0x1000, heapAddr+i*0x1000, 0x1000, MEMOP_MAP, 0x7)) return -4; } if(svc_controlProcessMemory(process, heapAddr, 0, extendedPages*0x1000, MEMOP_PROTECT, 0x1)) return -5; processHandle = process; hasExtraHeap = 1; extraHeapAddr = heapAddr; extraHeapPages = extendedPages; extendedPagesSize = extraHeapPages*0x1000; endAddr += extendedPagesSize; if(svc_mapProcessMemory(process, 0x00100000, 0x02000000))return -13; } u32 offsets[2] = { d.segSizes[0], d.segSizes[0] + d.segSizes[1] }; d.segPtrs[0] = baseAddr; d.segPtrs[1] = (char*)d.segPtrs[0] + d.segSizes[0]; SEC_ASSERT((u32)d.segPtrs[1] >= d.segSizes[0]); // int overflow d.segPtrs[2] = (char*)d.segPtrs[1] + d.segSizes[1]; SEC_ASSERT((u32)d.segPtrs[2] >= d.segSizes[1]); // int overflow SEC_ASSERT((u32)d.segPtrs[2] < endAddr); // within user memory // Skip header for future compatibility. _fseek(file, hdr.headerSize, SEEK_SET); // Read the relocation headers SEC_ASSERT(hdr.dataSegSize >= hdr.bssSize); // int underflow u32* relocs = (u32*)((char*)d.segPtrs[2] + hdr.dataSegSize - hdr.bssSize); SEC_ASSERT((u32)relocs >= (u32)d.segPtrs[2]); // int overflow SEC_ASSERT((u32)relocs < endAddr); // within user memory u32 nRelocTables = hdr.relocHdrSize/4; u32 relocsEnd = (u32)(relocs + 3*nRelocTables); SEC_ASSERT((u32)relocsEnd >= (u32)relocs); // int overflow SEC_ASSERT((u32)relocsEnd < endAddr); // within user memory // XXX: Ensure enough RW pages exist at baseAddr to hold a memory block of length "totalSize". // This also checks whether the memory region overflows into IPC data or loader data. for (i = 0; i < 3; i ++) if (_fread(&relocs[i*nRelocTables], nRelocTables*4, file) != 0) return -3; // Read the segments if (_fread(d.segPtrs[0], hdr.codeSegSize, file) != 0) return -4; if (_fread(d.segPtrs[1], hdr.rodataSegSize, file) != 0) return -5; if (_fread(d.segPtrs[2], hdr.dataSegSize - hdr.bssSize, file) != 0) return -6; // Relocate the segments for (i = 0; i < 3; i ++) { for (j = 0; j < nRelocTables; j ++) { u32 nRelocs = relocs[i*nRelocTables+j]; if (j >= 2) { // We are not using this table - ignore it _fseek(file, nRelocs*sizeof(_3DSX_Reloc), SEEK_CUR); continue; } static _3DSX_Reloc relocTbl[RELOCBUFSIZE]; u32* pos = (u32*)d.segPtrs[i]; u32* endPos = pos + (d.segSizes[i]/4); SEC_ASSERT(((u32) endPos) < endAddr); // within user memory while (nRelocs) { u32 toDo = nRelocs > RELOCBUFSIZE ? RELOCBUFSIZE : nRelocs; nRelocs -= toDo; if (_fread(relocTbl, toDo*sizeof(_3DSX_Reloc), file) != 0) return -7; for (k = 0; k < toDo && pos < endPos; k ++) { pos += relocTbl[k].skip; u32 num_patches = relocTbl[k].patch; for (m = 0; m < num_patches && pos < endPos; m ++) { void* addr = TranslateAddr(*pos, &d, offsets); SEC_ASSERT(((u32) pos) < endAddr); // within user memory switch (j) { case 0: *pos = (u32)addr; break; case 1: *pos = (int)addr - (int)pos; break; } pos++; } } } } } // Detect and fill _prm structure u32* prmStruct = (u32*)baseAddr + 1; if(prmStruct[0]==0x6D72705F) { // Write service handle table pointer // the actual structure has to be filled out by cn_bootloader prmStruct[1] = (u32)__service_ptr; // XXX: other fields that need filling: // prmStruct[2] <-- __apt_appid (default: 0x300) // prmStruct[3] <-- __heap_size (default: 24*1024*1024) // prmStruct[4] <-- __gsp_heap_size (default: 32*1024*1024) // prmStruct[5] <-- __system_arglist (default: NULL) prmStruct[2] = 0x300; prmStruct[3] = 29*1024*1024 - extendedPagesSize; prmStruct[4] = 32*1024*1024; prmStruct[5] = CN_ARGCV_LOC; prmStruct[6] = RUNFLAG_APTWORKAROUND; //__system_runflags // XXX: Notes on __system_arglist: // Contains a pointer to a u32 specifying the number of arguments immediately followed // by the NULL-terminated argument strings themselves (no pointers). The first argument // should always be the path to the file we are booting. Example: // \x02\x00\x00\x00sd:/dir/file.3dsx\x00Argument1\x00 // Above corresponds to { "sd:/dir/file.3dsx", "Argument1" }. } // Protect memory at d.segPtrs[0] as CODE (r-x) -- npages = d.segSizes[0] / 0x1000 for(i=0;i<d.segSizes[0]>>12;i++)svc_controlProcessMemory(process, (u32)d.segPtrs[0]+i*0x1000, 0x0, 0x00001000, MEMOP_PROTECT, 0x5); // Protect memory at d.segPtrs[1] as RODATA (r--) -- npages = d.segSizes[1] / 0x1000 for(i=0;i<d.segSizes[1]>>12;i++)svc_controlProcessMemory(process, (u32)d.segPtrs[1]+i*0x1000, 0x0, 0x00001000, MEMOP_PROTECT, 0x1); // Protect memory at d.segPtrs[2] as DATA (rw-) -- npages = d.segSizes[2] / 0x1000 for(i=0;i<d.segSizes[2]>>12;i++)svc_controlProcessMemory(process, (u32)d.segPtrs[2]+i*0x1000, 0x0, 0x00001000, MEMOP_PROTECT, 0x3); //svc_closeHandle(process); TODO //svc_closeHandle(file); return 0; // Success. }
/*! */ xbShort xbDbf::CreateMemoFile( void ) { xbShort len,i; char *sp; char buf[4]; len = GetMemoBlockSize(); if( len == 0 || len % 512 != 0 ) return XB_INVALID_BLOCK_SIZE; if(( sp = (char*)strrchr(GetFileName(), PATH_SEPARATOR)) != NULL ) sp++; else sp = MemoHeader.FileName; memset( MemoHeader.FileName, 0x00, 8 ); for( i = 0; i < 8 && *sp != '.'; i++ ) MemoHeader.FileName[i] = *sp++; MemofileName = GetFileName(); len = GetFileName().len() - 1; if( MemofileName[len] == 'F' ) MemofileName.putAt(len, 'T'); else if( MemofileName[len] == 'f' ) MemofileName.putAt(len, 't'); else return XB_INVALID_NAME; /* Initialize the variables */ MemoHeader.NextBlock = 1L; if(( mfp = fopen( MemofileName, "w+b" )) == NULL ) return XB_OPEN_ERROR; #ifdef XB_LOCKING_ON setbuf( mfp, NULL ); #endif if(( _fseek( mfp, 0, SEEK_SET )) != 0 ){ fclose( mfp ); return XB_SEEK_ERROR; } memset( buf, 0x00, 4 ); xbase->PutLong( buf, MemoHeader.NextBlock ); if(( fwrite( &buf, 4, 1, mfp )) != 1 ){ fclose( mfp ); return XB_WRITE_ERROR; } if( IsType3Dbt() ){ /* dBASE III+ */ for( i = 0; i < 12; i++ ) fputc( 0x00, mfp ); fputc( 0x03, mfp ); for( i = 0; i < 495; i++ ) fputc( 0x00, mfp ); } else { for( i = 0; i < 4; i++ ) fputc( 0x00, mfp ); fwrite( &MemoHeader.FileName, 8, 1, mfp ); for( i = 0; i < 4; i++ ) fputc( 0x00, mfp ); memset( buf, 0x00, 2 ); xbase->PutShort( buf, MemoHeader.BlockSize ); if(( fwrite( &buf, 2, 1, mfp )) != 1 ){ fclose( mfp ); return XB_WRITE_ERROR; } for( i = 22; i < MemoHeader.BlockSize; i++ ) fputc( 0x00, mfp ); } if(( mbb = (void *) malloc( MemoHeader.BlockSize )) == NULL ){ fclose( mfp ); return XB_NO_MEMORY; } return XB_NO_ERROR; }
static INT PAL_RNGReadFrame( LPBYTE lpBuffer, UINT uiBufferSize, UINT uiRngNum, UINT uiFrameNum, FILE *fpRngMKF ) /*++ Purpose: Read a frame from a RNG animation. Parameters: [OUT] lpBuffer - pointer to the destination buffer. [IN] uiBufferSize - size of the destination buffer. [IN] uiRngNum - the number of the RNG animation in the MKF archive. [IN] uiFrameNum - frame number in the RNG animation. [IN] fpRngMKF - pointer to the fopen'ed MKF file. Return value: Integer value which indicates the size of the chunk. -1 if there are error in parameters. -2 if buffer size is not enough. --*/ { UINT uiOffset = 0; UINT uiSubOffset = 0; UINT uiNextOffset = 0; UINT uiChunkCount = 0; INT iChunkLen = 0; if (lpBuffer == NULL || fpRngMKF == NULL || uiBufferSize == 0) { return -1; } // // Get the total number of chunks. // uiChunkCount = PAL_MKFGetChunkCount(fpRngMKF); if (uiRngNum >= uiChunkCount) { return -1; } // // Get the offset of the chunk. // _fseek(fpRngMKF, 4 * uiRngNum, SEEK_SET); _fread(&uiOffset, sizeof(UINT), 1, fpRngMKF); _fread(&uiNextOffset, sizeof(UINT), 1, fpRngMKF); uiOffset = SWAP32(uiOffset); uiNextOffset = SWAP32(uiNextOffset); // // Get the length of the chunk. // iChunkLen = uiNextOffset - uiOffset; if (iChunkLen != 0) { _fseek(fpRngMKF, uiOffset, SEEK_SET); } else { return -1; } // // Get the number of sub chunks. // _fread(&uiChunkCount, sizeof(UINT), 1, fpRngMKF); uiChunkCount = (SWAP32(uiChunkCount) - 4) / 4; if (uiFrameNum >= uiChunkCount) { return -1; } // // Get the offset of the sub chunk. // _fseek(fpRngMKF, uiOffset + 4 * uiFrameNum, SEEK_SET); _fread(&uiSubOffset, sizeof(UINT), 1, fpRngMKF); _fread(&uiNextOffset, sizeof(UINT), 1, fpRngMKF); uiSubOffset = SWAP32(uiSubOffset); uiNextOffset = SWAP32(uiNextOffset); // // Get the length of the sub chunk. // iChunkLen = uiNextOffset - uiSubOffset; if ((UINT)iChunkLen > uiBufferSize) { return -2; } if (iChunkLen != 0) { _fseek(fpRngMKF, uiOffset + uiSubOffset, SEEK_SET); _fread(lpBuffer, iChunkLen, 1, fpRngMKF); } else { return -1; } return iChunkLen; }