const Archive::FileHandle Archive_FAT::insert(const FileHandle& idBeforeThis, const std::string& strFilename, stream::len storedSize, std::string type, File::Attribute attr) { // TESTED BY: fmt_grp_duke3d_insert2 // TESTED BY: fmt_grp_duke3d_remove_insert // TESTED BY: fmt_grp_duke3d_insert_remove // Make sure filename is within the allowed limit if ( (this->lenMaxFilename > 0) && (strFilename.length() > this->lenMaxFilename) ) { throw stream::error(createString("maximum filename length is " << this->lenMaxFilename << " chars")); } std::shared_ptr<FATEntry> pNewFile = this->createNewFATEntry(); pNewFile->strName = strFilename; pNewFile->storedSize = storedSize; pNewFile->realSize = storedSize; // default to no filter pNewFile->type = type; pNewFile->fAttr = attr; pNewFile->lenHeader = 0; pNewFile->bValid = false; // not yet valid // Figure out where the new file is going to go const FATEntry *pFATBeforeThis = NULL; if (this->isValid(idBeforeThis)) { // Insert at idBeforeThis // TESTED BY: fmt_grp_duke3d_insert_mid pFATBeforeThis = dynamic_cast<const FATEntry *>(idBeforeThis.get()); assert(pFATBeforeThis); pNewFile->iOffset = pFATBeforeThis->iOffset; pNewFile->iIndex = pFATBeforeThis->iIndex; } else { // Append to end of archive // TESTED BY: fmt_grp_duke3d_insert_end if (this->vcFAT.size()) { auto pFATAfterThis = dynamic_cast<const FATEntry *>(this->vcFAT.back().get()); assert(pFATAfterThis); pNewFile->iOffset = pFATAfterThis->iOffset + pFATAfterThis->lenHeader + pFATAfterThis->storedSize; pNewFile->iIndex = pFATAfterThis->iIndex + 1; } else { // There are no files in the archive pNewFile->iOffset = this->offFirstFile; pNewFile->iIndex = 0; } } // Add the file's entry from the FAT. May throw (e.g. filename too long), // archive should be left untouched in this case. this->preInsertFile(pFATBeforeThis, &*pNewFile); // Now it's mostly valid. Really this is here so that it's invalid during // preInsertFile(), so any calls in there to shiftFiles() will ignore the // new file. But we're about to call shiftFiles() now, and we need the file // to be marked valid otherwise it won't be skipped/ignored. pNewFile->bValid = true; if (this->isValid(idBeforeThis)) { // Update the offsets of any files located after this one (since they will // all have been shifted forward to make room for the insert.) this->shiftFiles( &*pNewFile, pNewFile->iOffset + pNewFile->lenHeader, pNewFile->storedSize, 1 ); // Add the new file to the vector now all the existing offsets have been // updated. // TESTED BY: fmt_grp_duke3d_insert_mid auto itBeforeThis = std::find(this->vcFAT.begin(), this->vcFAT.end(), idBeforeThis); assert(itBeforeThis != this->vcFAT.end()); this->vcFAT.insert(itBeforeThis, pNewFile); } else { // TESTED BY: fmt_grp_duke3d_insert_end this->vcFAT.push_back(pNewFile); } // Insert space for the file's data into the archive. If there is a header // (e.g. embedded FAT) then preInsertFile() will have inserted space for // this and written the data, so our insert should start just after the // header. this->content->seekp(pNewFile->iOffset + pNewFile->lenHeader, stream::start); this->content->insert(pNewFile->storedSize); this->postInsertFile(&*pNewFile); return pNewFile; }
bool CASC::ReadFile(FileHandle const& file, void* buffer, DWORD bytes, PDWORD bytesRead) { return ::CascReadFile(file.get(), buffer, bytes, bytesRead); }
DWORD CASC::GetFilePointer(FileHandle const& file) { return ::CascSetFilePointer(file.get(), 0, nullptr, FILE_CURRENT); }
bool CASC::SetFilePointer(FileHandle const& file, LONGLONG position) { LONG parts[2]; memcpy(parts, &position, sizeof(parts)); return ::CascSetFilePointer(file.get(), parts[0], &parts[1], FILE_BEGIN) != CASC_INVALID_POS; }
DWORD CASC::GetFileSize(FileHandle const& file, PDWORD fileSizeHigh) { return ::CascGetFileSize(file.get(), fileSizeHigh); }