diff --git a/src/object.c b/src/object.c index ae0978962c..0f0c4def05 100644 --- a/src/object.c +++ b/src/object.c @@ -132,7 +132,7 @@ int write_object_file(SDL_RWops *rw, rct_object_entry* entry) * * rct2: 0x006AA2B7 */ -int object_load_packed(SDL_RWops* rw) +int object_load_packed_old(SDL_RWops* rw) { object_unload_all(); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index a6f1c7ae9c..16980ca014 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -33,10 +33,12 @@ extern "C" { + #include "../config.h" #include "../localisation/localisation.h" #include "../object.h" #include "../platform/platform.h" #include "../scenario.h" + #include "../util/sawyercoding.h" } constexpr uint16 OBJECT_REPOSITORY_VERSION = 6; @@ -139,6 +141,36 @@ public: return object; } + void AddObject(const rct_object_entry * objectEntry, const void * data, size_t dataSize) override + { + char objectName[9] = { 0 }; + Memory::Copy(objectName, objectEntry->name, 8); + + int realChecksum = object_calculate_checksum(objectEntry, (const uint8 *)data, (int)dataSize); + if (realChecksum != objectEntry->checksum) + { + log_error("Checksum mismatch from packed object: %.8s", objectName); + if (!gConfigGeneral.allow_loading_with_incorrect_checksum) + { + return; + } + } + + utf8 path[MAX_PATH]; + GetPathForNewObject(path, sizeof(path), objectName); + + Console::WriteLine("Adding object: [%s]", objectName); + try + { + SaveObject(path, objectEntry, data, dataSize); + ScanObject(path); + } + catch (Exception ex) + { + Console::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path); + } + } + private: void ClearItems() { @@ -374,6 +406,50 @@ private: item->ThemeObjects = nullptr; } + static void SaveObject(const utf8 * path, const rct_object_entry * entry, const void * data, size_t dataSize) + { + // TODO + // auto fs = FileStream(path, FILE_MODE_WRITE); + // fs.Write(entry, sizeof(entry)); + } + + static void GetPathForNewObject(utf8 * buffer, size_t bufferSize, const char * name) + { + char normalisedName[9] = { 0 }; + for (int i = 0; i < 8; i++) + { + if (name[i] != ' ') + { + normalisedName[i] = toupper(name[i]); + } + else + { + normalisedName[i] = '\0'; + } + } + + substitute_path(buffer, gRCT2AddressObjectDataPath, normalisedName); + char * lastCh = buffer + strlen(buffer); + strcat(buffer, ".DAT"); + + for (; platform_file_exists(buffer);) + { + for (char * ch = lastCh - 1; ; ch--) + { + if (*ch == '\\') + { + substitute_path(buffer, gRCT2AddressObjectDataPath, "00000000.DAT"); + break; + } + if (*ch < '0') *ch = '0'; + else if (*ch == '9') *ch = 'A'; + else if (*ch == 'Z') *ch = '0'; + else (*ch)++; + if (*ch != '0') break; + } + } + } + static void GetRepositoryPath(utf8 * buffer, size_t bufferSize) { platform_get_user_directory(buffer, nullptr); @@ -539,4 +615,31 @@ extern "C" } } } + + int object_load_packed(SDL_RWops * rw) + { + rct_object_entry entry; + SDL_RWread(rw, &entry, 16, 1); + + uint8 * chunk = Memory::Allocate(0x600000); + if (chunk == nullptr) + { + log_error("Failed to allocate buffer for packed object."); + return 0; + } + + uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); + chunk = Memory::Reallocate(chunk, chunkSize); + if (chunk == nullptr) + { + log_error("Failed to reallocate buffer for packed object."); + return 0; + } + + IObjectRepository * objRepo = GetObjectRepository(); + objRepo->AddObject(&entry, chunk, chunkSize); + + Memory::Free(chunk); + return 1; + } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 93b10525a6..2d766fff21 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -55,6 +55,9 @@ interface IObjectRepository virtual const ObjectRepositoryItem * FindObject(const utf8 * name) abstract; virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract; virtual Object * LoadObject(const rct_object_entry * objectEntry) abstract; + virtual void AddObject(const rct_object_entry * objectEntry, + const void * data, + size_t dataSize) abstract; }; IObjectRepository * GetObjectRepository();