aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common.hh34
-rw-r--r--src/script.cc149
-rw-r--r--src/script.hh31
-rw-r--r--src/util.cc136
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;
+}