diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common.hh | 34 | ||||
| -rw-r--r-- | src/script.cc | 149 | ||||
| -rw-r--r-- | src/script.hh | 31 | ||||
| -rw-r--r-- | src/util.cc | 136 |
4 files changed, 348 insertions, 2 deletions
diff --git a/src/common.hh b/src/common.hh index b057465..204cf2a 100644 --- a/src/common.hh +++ b/src/common.hh @@ -137,6 +137,38 @@ void SetPrintFunction(TPrintFunction *Function); void error(char *Text, ...) ATTR_PRINTF(1, 2); void print(int Level, char *Text, ...) ATTR_PRINTF(1, 2); -// +struct TReadStream { + // VIRTUAL FUNCTIONS + // ========================================================================= + virtual bool readFlag(void); // VTABLE[0] + virtual uint8 readByte(void) = 0; // VTABLE[1] + virtual uint16 readWord(void); // VTABLE[2] + virtual uint32 readQuad(void); // VTABLE[3] + virtual void readString(char *Buffer, int MaxLength); // VTABLE[4] + virtual void readBytes(uint8 *Buffer, int Count); // VTABLE[5] + virtual bool eof(void) = 0; // VTABLE[6] + virtual void skip(int Count) = 0; // VTABLE[7] +}; + +struct TReadBuffer: TReadStream { + // REGULAR FUNCTIONS + // ========================================================================= + TReadBuffer(uint8 *Data, int Size); + + // VIRTUAL FUNCTIONS + // ========================================================================= + uint8 readByte(void) override; + uint16 readWord(void) override; + uint32 readQuad(void) override; + void readBytes(uint8 *Buffer, int Count) override; + bool eof(void) override; + void skip(int Count) override; + + // DATA + // ========================================================================= + uint8 *Data; + int Size; + int Position; +}; #endif //TIBIA_COMMON_HH_ diff --git a/src/script.cc b/src/script.cc index 5c8c7d7..9db02f7 100644 --- a/src/script.cc +++ b/src/script.cc @@ -7,6 +7,8 @@ // which then becomes ambiguous whether you should free it or not. Used in: // - TReadScriptFile::error // - TWriteScriptFile::error +// - TReadBinaryFile::open +// - TReadBinaryFile::error static char ErrorString[100]; // Helper Functions @@ -113,7 +115,7 @@ static char *findLast(char *s, char c){ return Last; } -// TWriteScriptFile +// TReadScriptFile //============================================================================== TReadScriptFile::TReadScriptFile(void){ this->RecursionDepth = -1; @@ -788,3 +790,148 @@ void TWriteScriptFile::writeBytesequence(uint8 *Sequence, int Length){ this->writeText(s); } } + +// TReadBinaryFile REGULAR FUNCTIONS +//============================================================================== +TReadBinaryFile::TReadBinaryFile(void){ + this->File = NULL; +} + +void TReadBinaryFile::open(char *FileName){ + if(this->File != NULL){ + this->error("File still open"); + } + + this->File = fopen(FileName, "rb"); + if(this->File == NULL){ + snprintf(ErrorString, sizeof(ErrorString), + "Cannot open file %s", FileName); + throw ErrorString; + } + + strcpy(this->Filename, FileName); + this->FileSize = -1; +} + +int TReadBinaryFile::close(void){ + // TODO(fusion): Check if file is NULL? + if(fclose(this->File) != 0){ + int ErrCode = errno; + ::error("TReadBinaryFile::close: Fehler beim Schließen der Datei.\n"); + ::error("# Datei: %s, Fehlercode: %d (%s)\n", + this->Filename, ErrCode, strerror(ErrCode)); + } + this->File = NULL; +} + +void TReadBinaryFile::error(char *Text){ + if(this->File != NULL){ + if(fclose(this->File) != 0){ + ::error("TReadBinaryFile::error: Fehler %d beim Schließen der Datei.\n", errno); + } + this->File = NULL; + } + + snprintf(ErrorString, sizeof(ErrorString), + "error in binary-file \"%s\": %s.", + this->Filename, Text); + + throw ErrorString; +} + +int TReadBinaryFile::getPosition(void){ + // TODO(fusion): Check if file is NULL? + return (int)ftell(this->File); +} + +int TReadBinaryFile::getSize(void){ + // TODO(fusion): Check if file is NULL? + int Size = this->FileSize; + if(Size == -1){ + long Position = ftell(this->File); + fseek(this->File, 0, SEEK_END); + Size = (int)ftell(this->File); + fseek(this->File, Position, SEEK_SET); + this->FileSize = Size; + } + return Size; +} + +void TReadBinaryFile::seek(int Offset){ + if(this->File == NULL){ + this->error("File not open for seek"); + } + + if(Offset < 0){ + this->error("Negative offset for seek"); + } + + fseek(this->File, (long)Offset, 0); +} + +// TReadBinaryFile VIRTUAL FUNCTIONS +//============================================================================== +TReadBinaryFile::~TReadBinaryFile(void){ + if(this->File != NULL){ + ::error("TReadBinaryFile::~TReadBinaryFile: Datei %s ist noch offen.\n", this->Filename); + if(fclose(this->File) != 0){ + ::error("TReadBinaryFile::~TReadBinaryFile: Fehler %d beim Schließen der Datei.\n", errno); + } + } +} + +uint8 TReadBinaryFile::readByte(void){ + uint8 Byte; + int Result = (int)fread(&Byte, 1, 1, this->File); + if(Result != 1){ + int ErrCode = errno; + int Position = this->getPosition(); + ::error("TReadBinaryFile::readByte: Fehler beim Lesen eines Bytes\n"); + ::error("# Datei: %s, Position: %d, Rückgabewert: %d, Fehlercode: %d (%s)\n", + this->Filename, Position, Result, ErrCode, strerror(ErrCode)); + + // NOTE(fusion): Close file and make a backup, possibly for further inspection. + if(fclose(this->File) != 0){ + ::error("TReadBinaryFile::readByte: Fehler %d beim Schließen der Datei.\n", errno); + } + SaveFile(this->Filename); + + this->error("Error while reading byte"); + } + return Byte; +} + +void TReadBinaryFile::readBytes(uint8 *Buffer, int Count){ + int Result = (int)fread(Buffer, 1, Count, this->File); + if(Result != Count){ + int ErrCode = errno; + int Position = this->getPosition(); + ::error("TReadBinaryFile::readBytes: Fehler beim Lesen von %d Bytes\n", Count); + ::error("# Datei: %s, Position %d, Rückgabewert: %d, Fehlercode: %d (%s)\n", + this->Filename, Position, Result, ErrCode, strerror(ErrCode)); + + // NOTE(fusion): Close file and make a backup, possibly for further inspection. + if(fclose(this->File) != 0){ + ::error("TReadBinaryFile::readBytes: Fehler %d beim Schließen der Datei.\n", errno); + } + SaveFile(this->Filename); + + this->error("Error while reading bytes"); + } +} + +bool TReadBinaryFile::eof(TReadBinaryFile *this){ + if(this->File == NULL){ + this->error("File not open for eof check"); + } + + return this->getSize() <= this->getPosition(); +} + +void TReadBinaryFile::skip(int Count){ + if(this->File == NULL){ + this->error("File not open for skip"); + } + + this->seek(this->getPosition() + Count); +} diff --git a/src/script.hh b/src/script.hh index 0a83196..42ddd2e 100644 --- a/src/script.hh +++ b/src/script.hh @@ -101,4 +101,35 @@ struct TWriteScriptFile { int Line; }; +struct TReadBinaryFile: TReadStream { + // REGULAR FUNCTIONS + // ========================================================================= + TReadBinaryFile(void); + void open(char *FileName); + int close(void); + void error(char *Text); + int getPosition(void); + int getSize(void); + void seek(int Offset); + + // VIRTUAL FUNCTIONS + // ========================================================================= + // TODO(fusion): `TReadStream` itself doesn't have a destructor on its VTABLE + // which makes me think there is something else going on here or the compiler + // optimized it away because it was never used but it seems problematic. + virtual ~TReadBinaryFile(void) override; // VTABLE[8] + // Duplicate destructor that also calls operator delete. // VTABLE[9] + + uint8 readByte(void) override; + void readBytes(uint8 *Buffer, int Count) override; + bool eof(TReadBinaryFile *this) override; + void skip(int Count) override; + + // DATA + // ========================================================================= + FILE *File; + char Filename[4096]; + int FileSize; +}; + #endif //TIBIA_SCRIPT_HH_ diff --git a/src/util.cc b/src/util.cc index 74c1bf5..5cdd933 100644 --- a/src/util.cc +++ b/src/util.cc @@ -40,3 +40,139 @@ void print(int Level, char *Text, ...){ printf("%s", s); } } + +// TReadStream +// ============================================================================= +bool TReadStream::readFlag(void){ + return this->readByte() != 0; +} + +uint16 TReadStream::readWord(void){ + // NOTE(fusion): Data is encoded in little endian. + uint8 Byte0 = this->readByte(); + uint8 Byte1 = this->readByte(); + return ((uint16)Byte1 << 8) | (uint16)Byte0; +} + +uint32 TReadStream::readQuad(void){ + // NOTE(fusion): Data is encoded in little endian. + uint8 Byte0 = this->readByte(); + uint8 Byte1 = this->readByte(); + uint8 Byte2 = this->readByte(); + uint8 Byte3 = this->readByte(); + return ((uint32)Byte3 << 24) | ((uint32)Byte2 << 16) + | ((uint32)Byte1 << 8) | (uint32)Byte0; +} + +void TReadStream::readString(char *Buffer, int MaxLength){ + if(Buffer == NULL || MaxLength == 0){ + error("TReadStream::readString: Übergebener Puffer existiert nicht.\n"); + throw "internal error"; + } + + int Length = (int)this->readWord(); + if(Length == 0xFFFF){ + Length = (int)this->readQuad(); + } + + if(Length > 0){ + if(MaxLength < 0 || MaxLength > Length){ + this->readBytes(Buffer, Length); + Buffer[Length] = 0; + }else{ + this->readBytes(Buffer, MaxLength - 1); + this->skip(Length - MaxLength + 1); + Buffer[MaxLength - 1] = 0; + } + }else{ + Buffer[0] = 0; + } +} + +void TReadStream::readBytes(uint8 *Buffer, int Count){ + if(Buffer == NULL){ + error("TReadStream::readBytes: Übergebener Puffer existiert nicht.\n"); + throw "internal error"; + } + + for(int i = 0; i < Count; i += 1){ + Buffer[i] = this->readByte(); + } +} + +// TReadBuffer +// ============================================================================= +TReadBuffer::TReadBuffer(uint8 *Data, int Size){ + if(Data == NULL){ + error("TReadBuffer::TReadBuffer: data ist NULL.\n"); + Size = 0; + }else if(Size < 0){ + error("TReadBuffer::TReadBuffer: Ungültige Datengröße %d.\n", Size); + Size = 0; + } + + this->Data = Data; + this->Size = Size; + this->Position = 0; +} + +uint8 TReadBuffer::readByte(void){ + if((this->Size - this->Position) < 1){ + throw "buffer empty"; + } + + uint8 Byte = this->Data[this->Position]; + this->Position += 1; + return Byte; +} + +uint16 TReadBuffer::readWord(void){ + if((this->Size - this->Position) < 2){ + throw "buffer empty"; + } + + uint8 Byte0 = this->Data[this->Position]; + uint8 Byte1 = this->Data[this->Position + 1]; + this->Position += 2; + return ((uint16)Byte1 << 8) | (uint16)Byte0; +} + +uint32 TReadBuffer::readQuad(void){ + if((this->Size - this->Position) < 4){ + throw "buffer empty"; + } + + uint8 Byte0 = this->Data[this->Position]; + uint8 Byte1 = this->Data[this->Position + 1]; + uint8 Byte2 = this->Data[this->Position + 2]; + uint8 Byte3 = this->Data[this->Position + 3]; + this->Position += 4; + return ((uint32)Byte3 << 24) | ((uint32)Byte2 << 16) + | ((uint32)Byte1 << 8) | (uint32)Byte0; +} + +void TReadBuffer::readBytes(uint8 *Buffer, int Count){ + if(Buffer == NULL || Count <= 0){ + error("TReadBuffer::readBytes: Übergebener Puffer existiert nicht.\n"); + throw "buffer not existing"; + } + + if((this->Size - this->Position) < Count){ + throw "buffer empty"; + } + + memcpy(Buffer, &this->Data[this->Position], Count); + this->Position += Count; +} + +bool TReadBuffer::eof(void){ + return this->Size <= this->Position; +} + +void TReadBuffer::skip(int Count){ + if((this->Size - this->Position) < Count){ + throw "buffer empty"; + } + + this->Position += Count; +} |
