bool PackageFile::Open(const String& fileName, unsigned startOffset) { #ifdef ANDROID if (URHO3D_IS_ASSET(fileName)) { URHO3D_LOGERROR("Package files within the apk are not supported on Android"); return false; } #endif SharedPtr<File> file(new File(context_, fileName)); if (!file->IsOpen()) return false; // Check ID, then read the directory file->Seek(startOffset); String id = file->ReadFileID(); if (id != "UPAK" && id != "ULZ4") { // If start offset has not been explicitly specified, also try to read package size from the end of file // to know how much we must rewind to find the package start if (!startOffset) { unsigned fileSize = file->GetSize(); file->Seek((unsigned)(fileSize - sizeof(unsigned))); unsigned newStartOffset = fileSize - file->ReadUInt(); if (newStartOffset < fileSize) { startOffset = newStartOffset; file->Seek(startOffset); id = file->ReadFileID(); } } if (id != "UPAK" && id != "ULZ4") { URHO3D_LOGERROR(fileName + " is not a valid package file"); return false; } } fileName_ = fileName; nameHash_ = fileName_; totalSize_ = file->GetSize(); compressed_ = id == "ULZ4"; unsigned numFiles = file->ReadUInt(); checksum_ = file->ReadUInt(); for (unsigned i = 0; i < numFiles; ++i) { String entryName = file->ReadString(); PackageEntry newEntry; newEntry.offset_ = file->ReadUInt() + startOffset; newEntry.size_ = file->ReadUInt(); newEntry.checksum_ = file->ReadUInt(); if (!compressed_ && newEntry.offset_ + newEntry.size_ > totalSize_) { URHO3D_LOGERROR("File entry " + entryName + " outside package file"); return false; } else entries_[entryName] = newEntry; } return true; }
bool File::OpenInternal(const String& fileName, FileMode mode, bool fromPackage) { Close(); compressed_ = false; readSyncNeeded_ = false; writeSyncNeeded_ = false; FileSystem* fileSystem = GetSubsystem<FileSystem>(); if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName))) { URHO3D_LOGERRORF("Access denied to %s", fileName.CString()); return false; } if (fileName.Empty()) { URHO3D_LOGERROR("Could not open file with empty name"); return false; } #ifdef __ANDROID__ if (URHO3D_IS_ASSET(fileName)) { if (mode != FILE_READ) { URHO3D_LOGERROR("Only read mode is supported for Android asset files"); return false; } assetHandle_ = SDL_RWFromFile(URHO3D_ASSET(fileName), "rb"); if (!assetHandle_) { URHO3D_LOGERRORF("Could not open Android asset file %s", fileName.CString()); return false; } else { fileName_ = fileName; mode_ = mode; position_ = 0; if (!fromPackage) { size_ = SDL_RWsize(assetHandle_); offset_ = 0; } checksum_ = 0; return true; } } #endif #ifdef _WIN32 handle_ = _wfopen(GetWideNativePath(fileName).CString(), openMode[mode]); #else handle_ = fopen(GetNativePath(fileName).CString(), openMode[mode]); #endif // If file did not exist in readwrite mode, retry with write-update mode if (mode == FILE_READWRITE && !handle_) { #ifdef _WIN32 handle_ = _wfopen(GetWideNativePath(fileName).CString(), openMode[mode + 1]); #else handle_ = fopen(GetNativePath(fileName).CString(), openMode[mode + 1]); #endif } if (!handle_) { URHO3D_LOGERRORF("Could not open file %s", fileName.CString()); return false; } if (!fromPackage) { fseek((FILE*)handle_, 0, SEEK_END); long size = ftell((FILE*)handle_); fseek((FILE*)handle_, 0, SEEK_SET); if (size > M_MAX_UNSIGNED) { URHO3D_LOGERRORF("Could not open file %s which is larger than 4GB", fileName.CString()); Close(); size_ = 0; return false; } size_ = (unsigned)size; offset_ = 0; } fileName_ = fileName; mode_ = mode; position_ = 0; checksum_ = 0; return true; }