diff --git a/src/core/MemoryStream.cpp b/src/core/MemoryStream.cpp index 2e6d46f525..cf3855938b 100644 --- a/src/core/MemoryStream.cpp +++ b/src/core/MemoryStream.cpp @@ -69,7 +69,7 @@ MemoryStream::MemoryStream(const void * data, size_t dataSize) MemoryStream::~MemoryStream() { - if (MEMORY_ACCESS_OWNER) + if (_access & MEMORY_ACCESS_OWNER) { Memory::Free(_data); } diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index ed3e1073ca..92169a99f9 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -55,20 +55,37 @@ namespace ObjectFactory { size_t bufferSize = 0x600000; void * buffer = Memory::Allocate(bufferSize); - bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); - buffer = Memory::Reallocate(buffer, bufferSize); - auto ms = MemoryStream(buffer, bufferSize); - try + if (buffer == nullptr) { - result->ReadLegacy(&ms); - } - catch (Exception ex) - { - Console::Error::WriteFormat("Error reading object: '%s'", path); - Console::Error::WriteLine(); + log_error("Unable to allocate data buffer."); delete result; result = nullptr; } + else + { + try + { + bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); + if (bufferSize == SIZE_MAX) + { + throw IOException("Error decoding data."); + } + + buffer = Memory::Reallocate(buffer, bufferSize); + auto ms = MemoryStream(buffer, bufferSize); + result->ReadLegacy(&ms); + + Memory::Free(buffer); + } + catch (Exception ex) + { + Memory::Free(buffer); + Console::Error::WriteFormat("Error reading object: '%s'", path); + Console::Error::WriteLine(); + delete result; + result = nullptr; + } + } } } SDL_RWclose(file); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 16980ca014..cb6927efba 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -156,6 +156,8 @@ public: } } + // TODO append checksum match bytes + utf8 path[MAX_PATH]; GetPathForNewObject(path, sizeof(path), objectName); @@ -408,9 +410,29 @@ private: 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)); + uint8 objectType = entry->flags & 0x0F; + + // Encode data + sawyercoding_chunk_header chunkHeader; + chunkHeader.encoding = object_entry_group_encoding[objectType]; + chunkHeader.length = dataSize; + uint8 * encodedDataBuffer = Memory::Allocate(0x600000); + size_t encodedDataSize = sawyercoding_write_chunk_buffer(encodedDataBuffer, (uint8 *)data, chunkHeader); + + // Save to file + try + { + auto fs = FileStream(path, FILE_MODE_WRITE); + fs.Write(entry, sizeof(rct_object_entry)); + fs.Write(encodedDataBuffer, encodedDataSize); + + Memory::Free(encodedDataBuffer); + } + catch (Exception ex) + { + Memory::Free(encodedDataBuffer); + throw; + } } static void GetPathForNewObject(utf8 * buffer, size_t bufferSize, const char * name) @@ -618,28 +640,38 @@ extern "C" int object_load_packed(SDL_RWops * rw) { + IObjectRepository * objRepo = GetObjectRepository(); + rct_object_entry entry; SDL_RWread(rw, &entry, 16, 1); - uint8 * chunk = Memory::Allocate(0x600000); - if (chunk == nullptr) + // Check if we already have this object + if (objRepo->FindObject(&entry) != nullptr) { - log_error("Failed to allocate buffer for packed object."); - return 0; + sawyercoding_skip_chunk(rw); } - - uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); - chunk = Memory::Reallocate(chunk, chunkSize); - if (chunk == nullptr) + else { - log_error("Failed to reallocate buffer for packed object."); - return 0; + // Read object and save to new file + 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; + } + + objRepo->AddObject(&entry, chunk, chunkSize); + + Memory::Free(chunk); } - - IObjectRepository * objRepo = GetObjectRepository(); - objRepo->AddObject(&entry, chunk, chunkSize); - - Memory::Free(chunk); return 1; } } diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index d9622f4d8c..2e9dbebd05 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -96,6 +96,20 @@ bool sawyercoding_read_chunk_safe(SDL_RWops *rw, void *dst, size_t dstLength) } } +bool sawyercoding_skip_chunk(SDL_RWops *rw) +{ + // Read chunk header + sawyercoding_chunk_header chunkHeader; + if (SDL_RWread(rw, &chunkHeader, sizeof(sawyercoding_chunk_header), 1) != 1) { + log_error("Unable to read chunk header!"); + return false; + } + + // Skip chunk data + SDL_RWseek(rw, chunkHeader.length, RW_SEEK_CUR); + return true; +} + /** * * rct2: 0x0067685F @@ -157,6 +171,10 @@ size_t sawyercoding_read_chunk_with_size(SDL_RWops* rw, uint8 *buffer, const siz } uint8* src_buffer = malloc(chunkHeader.length); + if (src_buffer == NULL) { + log_error("Unable to read chunk data!"); + return -1; + } // Read chunk data if (SDL_RWread(rw, src_buffer, chunkHeader.length, 1) != 1) { diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index 5160c125ce..d7bd3d07b2 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -50,6 +50,7 @@ enum { int sawyercoding_validate_checksum(SDL_RWops* rw); uint32 sawyercoding_calculate_checksum(const uint8* buffer, size_t length); bool sawyercoding_read_chunk_safe(SDL_RWops *rw, void *dst, size_t dstLength); +bool sawyercoding_skip_chunk(SDL_RWops *rw); size_t sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer); size_t sawyercoding_read_chunk_with_size(SDL_RWops* rw, uint8 *buffer, const size_t buffer_size); size_t sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader);