From 1b4079536d15df78c592e0a491104fa0e7ed17b5 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 28 Jun 2016 21:16:09 +0100 Subject: [PATCH] try to read objects with bad image tables --- src/core/FileStream.hpp | 19 ++++++++++++++++--- src/core/IStream.hpp | 2 ++ src/core/MemoryStream.cpp | 8 ++++++++ src/core/MemoryStream.h | 2 ++ src/object/ImageTable.cpp | 14 +++++++++++++- 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/core/FileStream.hpp b/src/core/FileStream.hpp index 9a0bca777d..4716222a79 100644 --- a/src/core/FileStream.hpp +++ b/src/core/FileStream.hpp @@ -37,6 +37,7 @@ private: bool _canRead; bool _canWrite; bool _disposed; + uint64 _fileSize; public: FileStream(const utf8 * path, int fileMode) @@ -64,6 +65,7 @@ public: } _disposed = false; + _fileSize = SDL_RWsize(_file); } ~FileStream() @@ -78,7 +80,7 @@ public: bool CanRead() const override { return _canRead; } bool CanWrite() const override { return _canWrite; } - uint64 GetLength() const override { return SDL_RWsize(_file); } + uint64 GetLength() const override { return _fileSize; } uint64 GetPosition() const override { return SDL_RWtell(_file); } void SetPosition(uint64 position) override @@ -103,10 +105,15 @@ public: void Read(void * buffer, uint64 length) override { - if (SDL_RWread(_file, buffer, (size_t)length, 1) != 1) + uint64 remainingBytes = GetLength() - GetPosition(); + if (length <= remainingBytes) { - throw IOException("Attempted to read past end of file."); + if (SDL_RWread(_file, buffer, (size_t)length, 1) == 1) + { + return; + } } + throw IOException("Attempted to read past end of file."); } void Write(const void * buffer, uint64 length) override @@ -116,4 +123,10 @@ public: throw IOException("Unable to write to file."); } } + + uint64 TryRead(void * buffer, uint64 length) override + { + size_t readBytes = SDL_RWread(_file, buffer, 1, (size_t)length); + return readBytes; + } }; diff --git a/src/core/IStream.hpp b/src/core/IStream.hpp index 697cadfe75..4bf2e3e878 100644 --- a/src/core/IStream.hpp +++ b/src/core/IStream.hpp @@ -47,6 +47,8 @@ interface IStream virtual void Read(void * buffer, uint64 length) abstract; virtual void Write(const void * buffer, uint64 length) abstract; + virtual uint64 TryRead(void * buffer, uint64 length) abstract; + /////////////////////////////////////////////////////////////////////////// // Helper methods /////////////////////////////////////////////////////////////////////////// diff --git a/src/core/MemoryStream.cpp b/src/core/MemoryStream.cpp index cf3855938b..35364fab0f 100644 --- a/src/core/MemoryStream.cpp +++ b/src/core/MemoryStream.cpp @@ -149,6 +149,14 @@ void MemoryStream::Read(void * buffer, uint64 length) _position = (void*)((uintptr_t)_position + length); } +uint64 MemoryStream::TryRead(void * buffer, uint64 length) +{ + uint64 remainingBytes = GetLength() - GetPosition(); + uint64 bytesToRead = Math::Min(length, remainingBytes); + Read(buffer, bytesToRead); + return bytesToRead; +} + void MemoryStream::Write(const void * buffer, uint64 length) { uint64 position = GetPosition(); diff --git a/src/core/MemoryStream.h b/src/core/MemoryStream.h index c7a2a0763b..82a2fcfe5e 100644 --- a/src/core/MemoryStream.h +++ b/src/core/MemoryStream.h @@ -63,6 +63,8 @@ public: void Read(void * buffer, uint64 length) override; void Write(const void * buffer, uint64 length) override; + uint64 TryRead(void * buffer, uint64 length) override; + private: void EnsureCapacity(size_t capacity); }; diff --git a/src/object/ImageTable.cpp b/src/object/ImageTable.cpp index ebd877dbd7..1b4ec16fa8 100644 --- a/src/object/ImageTable.cpp +++ b/src/object/ImageTable.cpp @@ -14,6 +14,7 @@ *****************************************************************************/ #pragma endregion +#include "../core/Console.hpp" #include "../core/IStream.hpp" #include "../core/Memory.hpp" #include "ImageTable.h" @@ -53,5 +54,16 @@ void ImageTable::Read(IStream * stream) } // Read g1 element data - stream->Read(_data, _dataSize); + size_t readBytes = (size_t)stream->TryRead(_data, _dataSize); + + // If data is shorter than expected (some custom objects are unfortunately like that) + size_t unreadBytes = _dataSize - readBytes; + if (unreadBytes > 0) + { + void * ptr = (void*)(((uintptr_t)_data) + readBytes); + Memory::Set(ptr, 0, unreadBytes); + + Console::Error::WriteFormat("Warning: Image table size shorter than expected."); + Console::Error::WriteLine(); + } }