diff --git a/src/common/GenericRecord.cpp b/src/common/GenericRecord.cpp index e898c9a..404644f 100644 --- a/src/common/GenericRecord.cpp +++ b/src/common/GenericRecord.cpp @@ -660,292 +660,3 @@ void Record::IsChanged(bool value) { SETBIT(CBash_Flags, _fIsChanged, value); } - -FNVRecord::FNVRecord(unsigned char *_recData): - Record(_recData), - formVersion(0) - { - memset(&versionControl2[0], 0x00, 2); - } - -FNVRecord::~FNVRecord() - { - // - } - -bool FNVRecord::Read() - { - if(IsLoaded() || IsChanged()) - return false; - uint32_t recSize = *(uint32_t*)&recData[-20]; - - //Check against the original record flags to see if it is compressed since the current flags may have changed - if ((*(uint32_t*)&recData[-16] & fIsCompressed) != 0) - { - unsigned char localBuffer[BUFFERSIZE]; - uint32_t expandedRecSize = *(uint32_t*)recData; - unsigned char *buffer = (expandedRecSize >= BUFFERSIZE) ? new unsigned char[expandedRecSize] : &localBuffer[0]; - uncompress(buffer, (uLongf*)&expandedRecSize, &recData[4], recSize - 4); - ParseRecord(buffer, buffer + expandedRecSize, true); - if(buffer != &localBuffer[0]) - delete [] buffer; - } - else - ParseRecord(recData, recData + recSize); - - IsLoaded(true); - return true; - } - -uint32_t FNVRecord::Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders) - { - uint32_t recSize = 0; - uint32_t recType = GetType(); - - collapser.Accept(formID); - - if(!IsChanged()) - { - if(bMastersChanged || flags != *(uint32_t*)&recData[-16]) - { - //if masters have changed, all formIDs have to be updated... - //or if the flags have changed internally (notably fIsDeleted or fIsCompressed, possibly others) - //so the record can't just be written as is. - if(Read()) - { - //if(expander.IsValid(data)) //optimization disabled for testing - // VisitFormIDs(expander); - //printer("Looking for correct expander\n"); - int32_t index = -1; - for(uint32_t x = 0; x < Expanders.size(); ++x) - if(IsValid(*Expanders[x])) - { - //if(index != -1) - // { - // printer("Multiple 'Correct' expanders found (%08X)! Using last one found (likely incorrect unless lucky)\n", formID); - // printer(" %i: %08X, %08X, %08X\n", index, Expanders[index]->FileStart, data, Expanders[index]->FileEnd); - // printer(" %i: %08X, %08X, %08X\n", x, Expanders[x]->FileStart, data, Expanders[x]->FileEnd); - // printer("Expanders:\n"); - // for(uint32_t z = 0; z < Expanders.size(); ++z) - // printer(" %i of %i: %08X, %08X\n", z, Expanders.size(), Expanders[z]->FileStart, Expanders[z]->FileEnd); - // } - index = x; - break; - } - if(index == -1) - { - printer("Unable to find the correct expander!\n"); - VisitFormIDs(expander); - } - else - VisitFormIDs(*Expanders[index]); - } - } - else - { - //if masters have not changed, the record can just be written from the read buffer - recSize = *(uint32_t*)&recData[-20]; - - writer.file_write(&recType, 4); - writer.file_write(&recSize, 4); - writer.file_write(&flags, 4); - writer.file_write(&formID, 4); - writer.file_write(&flagsUnk, 4); - writer.file_write(&formVersion, 2); - writer.file_write(&versionControl2[0], 2); - writer.file_write(recData, recSize); - Unload(); - return recSize + 24; - } - } - - VisitFormIDs(collapser); - - if(!IsDeleted()) - { - //IsCompressed(true); //Test code - WriteRecord(writer); - recSize = IsCompressed() ? writer.record_compress() : writer.record_size(); - writer.file_write(&recType, 4); - writer.file_write(&recSize, 4); - writer.file_write(&flags, 4); - writer.file_write(&formID, 4); - writer.file_write(&flagsUnk, 4); - writer.file_write(&formVersion, 2); - writer.file_write(&versionControl2[0], 2); - //if(IsCompressed()) - // { - // printer("Compressed: %08X\n", formID); - // } - writer.record_flush(); - } - else - { - writer.file_write(&recType, 4); - writer.file_write(&recSize, 4); - writer.file_write(&flags, 4); - writer.file_write(&formID, 4); - writer.file_write(&flagsUnk, 4); - writer.file_write(&formVersion, 2); - writer.file_write(&versionControl2[0], 2); - } - - expander.Accept(formID); - if(IsChanged()) - VisitFormIDs(expander); - else - Unload(); - return recSize + 24; - } - -TES5Record::TES5Record(unsigned char *_recData): - Record(_recData), - formVersion(0) - { - memset(&versionControl2[0], 0x00, 2); - } - -TES5Record::TES5Record(TES5Record *srcRecord) - { - if (srcRecord == NULL) - return; - - flags = srcRecord->flags; - formID = srcRecord->formID; - flagsUnk = srcRecord->flagsUnk; - formVersion = srcRecord->formVersion; - versionControl2[0] = srcRecord->versionControl2[0]; - versionControl2[1] = srcRecord->versionControl2[1]; - - recData = srcRecord->recData; - } - -TES5Record::~TES5Record() - { - // - } - -bool TES5Record::Read() - { - if(IsLoaded() || IsChanged()) - return false; - uint32_t recSize = *(uint32_t*)&recData[-20]; - - //Check against the original record flags to see if it is compressed since the current flags may have changed - if ((*(uint32_t*)&recData[-16] & fIsCompressed) != 0) - { - unsigned char localBuffer[BUFFERSIZE]; - uint32_t expandedRecSize = *(uint32_t*)recData; - unsigned char *buffer = (expandedRecSize >= BUFFERSIZE) ? new unsigned char[expandedRecSize] : &localBuffer[0]; - uncompress(buffer, (uLongf*)&expandedRecSize, &recData[4], recSize - 4); - ParseRecord(buffer, buffer + expandedRecSize, true); - if(buffer != &localBuffer[0]) - delete [] buffer; - } - else - ParseRecord(recData, recData + recSize); - - IsLoaded(true); - return true; - } - -uint32_t TES5Record::Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders) - { - uint32_t recSize = 0; - uint32_t recType = GetType(); - - collapser.Accept(formID); - - if(!IsChanged()) - { - if(bMastersChanged || flags != *(uint32_t*)&recData[-16]) - { - //if masters have changed, all formIDs have to be updated... - //or if the flags have changed internally (notably fIsDeleted or fIsCompressed, possibly others) - //so the record can't just be written as is. - if(Read()) - { - //if(expander.IsValid(data)) //optimization disabled for testing - // VisitFormIDs(expander); - //printer("Looking for correct expander\n"); - int32_t index = -1; - for(uint32_t x = 0; x < Expanders.size(); ++x) - if(IsValid(*Expanders[x])) - { - //if(index != -1) - // { - // printer("Multiple 'Correct' expanders found (%08X)! Using last one found (likely incorrect unless lucky)\n", formID); - // printer(" %i: %08X, %08X, %08X\n", index, Expanders[index]->FileStart, data, Expanders[index]->FileEnd); - // printer(" %i: %08X, %08X, %08X\n", x, Expanders[x]->FileStart, data, Expanders[x]->FileEnd); - // printer("Expanders:\n"); - // for(uint32_t z = 0; z < Expanders.size(); ++z) - // printer(" %i of %i: %08X, %08X\n", z, Expanders.size(), Expanders[z]->FileStart, Expanders[z]->FileEnd); - // } - index = x; - break; - } - if(index == -1) - { - printer("Unable to find the correct expander!\n"); - VisitFormIDs(expander); - } - else - VisitFormIDs(*Expanders[index]); - } - } - else - { - //if masters have not changed, the record can just be written from the read buffer - recSize = *(uint32_t*)&recData[-20]; - - writer.file_write(&recType, 4); - writer.file_write(&recSize, 4); - writer.file_write(&flags, 4); - writer.file_write(&formID, 4); - writer.file_write(&flagsUnk, 4); - writer.file_write(&formVersion, 2); - writer.file_write(&versionControl2[0], 2); - writer.file_write(recData, recSize); - Unload(); - return recSize + 24; - } - } - - VisitFormIDs(collapser); - - if(!IsDeleted()) - { - //IsCompressed(true); //Test code - WriteRecord(writer); - recSize = IsCompressed() ? writer.record_compress() : writer.record_size(); - writer.file_write(&recType, 4); - writer.file_write(&recSize, 4); - writer.file_write(&flags, 4); - writer.file_write(&formID, 4); - writer.file_write(&flagsUnk, 4); - writer.file_write(&formVersion, 2); - writer.file_write(&versionControl2[0], 2); - //if(IsCompressed()) - // { - // printer("Compressed: %08X\n", formID); - // } - writer.record_flush(); - } - else - { - writer.file_write(&recType, 4); - writer.file_write(&recSize, 4); - writer.file_write(&flags, 4); - writer.file_write(&formID, 4); - writer.file_write(&flagsUnk, 4); - writer.file_write(&formVersion, 2); - writer.file_write(&versionControl2[0], 2); - } - - expander.Accept(formID); - if(IsChanged()) - VisitFormIDs(expander); - else - Unload(); - return recSize + 24; - } \ No newline at end of file diff --git a/src/common/GenericRecord.h b/src/common/GenericRecord.h index a1ac093..6b50284 100644 --- a/src/common/GenericRecord.h +++ b/src/common/GenericRecord.h @@ -265,104 +265,3 @@ struct Record bool IsChanged(); void IsChanged(bool value); }; - -class FNVRecord : public Record - { - protected: - enum FNVHeaderFlags - { - fIsESM = 0x00000001, - fIsTaken = 0x00000002, //From OBSE, unconfirmed, requires fIsDeleted also be set - fUnknown1 = 0x00000004, - fUnknown2 = 0x00000008, - fUnknown3 = 0x00000010, - fIsDeleted = 0x00000020, - fIsBorderRegion = 0x00000040, //Has Tree LOD / Constant / Hidden From Local Map (FNV) - fIsTurnOffFire = 0x00000080, - fIsInaccessible = 0x00000100, // (FNV) - fIsCastsShadows = 0x00000200, //On Local Map / Motion Blur (FNV) - fIsQuestOrPersistent = 0x00000400, - fIsInitiallyDisabled = 0x00000800, - fIsIgnored = 0x00001000, - fIsNoVoiceFilter = 0x00002000, // (FNV) - fIsTemporary = 0x00004000, //From OBSE, unconfirmed - fIsVisibleWhenDistant = 0x00008000, - fIsRandomAnimStartOrHighPriorityLOD = 0x00010000, // (FNV) - fIsDangerousOrOffLimits = 0x00020000, // Radio Station (Talking Activator) (FNV) - fIsCompressed = 0x00040000, - fIsCantWait = 0x00080000, // Platform Specific Texture (FNV) - fUnknown4 = 0x00100000, - fUnknown5 = 0x00200000, - fUnknown6 = 0x00400000, - fUnknown7 = 0x00800000, - fUnknown8 = 0x01000000, - fIsObstacleOrNoAIAcquire = 0x02000000, // (FNV) - fIsNavMeshFilter = 0x04000000, // (FNV) - fIsNavMeshBoundBox = 0x08000000, // (FNV) - fIsNonPipboyOrAutoReflected = 0x10000000, // (FNV) - fIsChildUsableOrAutoRefracted = 0x20000000, // (FNV) - fIsNavMeshGround = 0x40000000, // (FNV) - fUnknown9 = 0x80000000 - }; - - public: - uint16_t formVersion; //FNV - uint8_t versionControl2[2]; //FNV - - FNVRecord(unsigned char *_recData=NULL); - virtual ~FNVRecord(); - - bool Read(); - uint32_t Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders); - }; - -class TES5Record : public Record - { - protected: - enum TES5HeaderFlags - { - fIsESM = 0x00000001, - fUnknown01 = 0x00000002, - fUnknown02 = 0x00000004, - fUnknown03 = 0x00000008, - fUnknown04 = 0x00000010, - fUnknown05 = 0x00000020, - fUnknown06 = 0x00000040, - fUnknown07 = 0x00000080, - fUnknown08 = 0x00000100, - fUnknown09 = 0x00000200, - fUnknown10 = 0x00000400, - fUnknown11 = 0x00000800, - fUnknown12 = 0x00001000, - fUnknown13 = 0x00002000, - fUnknown14 = 0x00004000, - fUnknown15 = 0x00008000, - fUnknown16 = 0x00010000, - fUnknown17 = 0x00020000, - fUnknown18 = 0x00040000, - fUnknown19 = 0x00080000, - fUnknown20 = 0x00100000, - fUnknown21 = 0x00200000, - fUnknown22 = 0x00400000, - fUnknown23 = 0x00800000, - fUnknown24 = 0x01000000, - fUnknown25 = 0x02000000, - fUnknown26 = 0x04000000, - fUnknown27 = 0x08000000, - fUnknown28 = 0x10000000, - fUnknown29 = 0x20000000, - fUnknown30 = 0x40000000, - fUnknown31 = 0x80000000 - }; - - public: - uint16_t formVersion; //TES5 - uint8_t versionControl2[2]; //TES5 - - TES5Record(unsigned char *_recData=NULL); - TES5Record(TES5Record *srcRecord); - virtual ~TES5Record(); - - bool Read(); - uint32_t Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders); - }; diff --git a/src/game/FalloutNewVegas/FNVRecord.cpp b/src/game/FalloutNewVegas/FNVRecord.cpp new file mode 100644 index 0000000..30ef27b --- /dev/null +++ b/src/game/FalloutNewVegas/FNVRecord.cpp @@ -0,0 +1,176 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is CBash code. +* +* The Initial Developer of the Original Code is +* Waruddar. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ + +#include "FNVRecord.h" +#include "FNVFile.h" +#include + +FNVRecord::FNVRecord(unsigned char *_recData): + Record(_recData), + formVersion(0) + { + memset(&versionControl2[0], 0x00, 2); + } + +FNVRecord::~FNVRecord() + { + // + } + +bool FNVRecord::Read() + { + if(IsLoaded() || IsChanged()) + return false; + uint32_t recSize = *(uint32_t*)&recData[-20]; + + //Check against the original record flags to see if it is compressed since the current flags may have changed + if ((*(uint32_t*)&recData[-16] & fIsCompressed) != 0) + { + unsigned char localBuffer[BUFFERSIZE]; + uint32_t expandedRecSize = *(uint32_t*)recData; + unsigned char *buffer = (expandedRecSize >= BUFFERSIZE) ? new unsigned char[expandedRecSize] : &localBuffer[0]; + uncompress(buffer, (uLongf*)&expandedRecSize, &recData[4], recSize - 4); + ParseRecord(buffer, buffer + expandedRecSize, true); + if(buffer != &localBuffer[0]) + delete [] buffer; + } + else + ParseRecord(recData, recData + recSize); + + IsLoaded(true); + return true; + } + +uint32_t FNVRecord::Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders) + { + uint32_t recSize = 0; + uint32_t recType = GetType(); + + collapser.Accept(formID); + + if(!IsChanged()) + { + if(bMastersChanged || flags != *(uint32_t*)&recData[-16]) + { + //if masters have changed, all formIDs have to be updated... + //or if the flags have changed internally (notably fIsDeleted or fIsCompressed, possibly others) + //so the record can't just be written as is. + if(Read()) + { + //if(expander.IsValid(data)) //optimization disabled for testing + // VisitFormIDs(expander); + //printer("Looking for correct expander\n"); + int32_t index = -1; + for(uint32_t x = 0; x < Expanders.size(); ++x) + if(IsValid(*Expanders[x])) + { + //if(index != -1) + // { + // printer("Multiple 'Correct' expanders found (%08X)! Using last one found (likely incorrect unless lucky)\n", formID); + // printer(" %i: %08X, %08X, %08X\n", index, Expanders[index]->FileStart, data, Expanders[index]->FileEnd); + // printer(" %i: %08X, %08X, %08X\n", x, Expanders[x]->FileStart, data, Expanders[x]->FileEnd); + // printer("Expanders:\n"); + // for(uint32_t z = 0; z < Expanders.size(); ++z) + // printer(" %i of %i: %08X, %08X\n", z, Expanders.size(), Expanders[z]->FileStart, Expanders[z]->FileEnd); + // } + index = x; + break; + } + if(index == -1) + { + printer("Unable to find the correct expander!\n"); + VisitFormIDs(expander); + } + else + VisitFormIDs(*Expanders[index]); + } + } + else + { + //if masters have not changed, the record can just be written from the read buffer + recSize = *(uint32_t*)&recData[-20]; + + writer.file_write(&recType, 4); + writer.file_write(&recSize, 4); + writer.file_write(&flags, 4); + writer.file_write(&formID, 4); + writer.file_write(&flagsUnk, 4); + writer.file_write(&formVersion, 2); + writer.file_write(&versionControl2[0], 2); + writer.file_write(recData, recSize); + Unload(); + return recSize + 24; + } + } + + VisitFormIDs(collapser); + + if(!IsDeleted()) + { + //IsCompressed(true); //Test code + WriteRecord(writer); + recSize = IsCompressed() ? writer.record_compress() : writer.record_size(); + writer.file_write(&recType, 4); + writer.file_write(&recSize, 4); + writer.file_write(&flags, 4); + writer.file_write(&formID, 4); + writer.file_write(&flagsUnk, 4); + writer.file_write(&formVersion, 2); + writer.file_write(&versionControl2[0], 2); + //if(IsCompressed()) + // { + // printer("Compressed: %08X\n", formID); + // } + writer.record_flush(); + } + else + { + writer.file_write(&recType, 4); + writer.file_write(&recSize, 4); + writer.file_write(&flags, 4); + writer.file_write(&formID, 4); + writer.file_write(&flagsUnk, 4); + writer.file_write(&formVersion, 2); + writer.file_write(&versionControl2[0], 2); + } + + expander.Accept(formID); + if(IsChanged()) + VisitFormIDs(expander); + else + Unload(); + return recSize + 24; + } diff --git a/src/game/FalloutNewVegas/FNVRecord.h b/src/game/FalloutNewVegas/FNVRecord.h new file mode 100644 index 0000000..ad5a9b2 --- /dev/null +++ b/src/game/FalloutNewVegas/FNVRecord.h @@ -0,0 +1,94 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is CBash code. +* +* The Initial Developer of the Original Code is +* Waruddar. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ + +#ifndef __CBASH_FNV_RECORD__ +#define __CBASH_FNV_RECORD__ + +#pragma once + +#include "common/GenericRecord.h" + +class FNVRecord : public Record + { + protected: + enum FNVHeaderFlags + { + fIsESM = 0x00000001, + fIsTaken = 0x00000002, //From OBSE, unconfirmed, requires fIsDeleted also be set + fUnknown1 = 0x00000004, + fUnknown2 = 0x00000008, + fUnknown3 = 0x00000010, + fIsDeleted = 0x00000020, + fIsBorderRegion = 0x00000040, //Has Tree LOD / Constant / Hidden From Local Map (FNV) + fIsTurnOffFire = 0x00000080, + fIsInaccessible = 0x00000100, // (FNV) + fIsCastsShadows = 0x00000200, //On Local Map / Motion Blur (FNV) + fIsQuestOrPersistent = 0x00000400, + fIsInitiallyDisabled = 0x00000800, + fIsIgnored = 0x00001000, + fIsNoVoiceFilter = 0x00002000, // (FNV) + fIsTemporary = 0x00004000, //From OBSE, unconfirmed + fIsVisibleWhenDistant = 0x00008000, + fIsRandomAnimStartOrHighPriorityLOD = 0x00010000, // (FNV) + fIsDangerousOrOffLimits = 0x00020000, // Radio Station (Talking Activator) (FNV) + fIsCompressed = 0x00040000, + fIsCantWait = 0x00080000, // Platform Specific Texture (FNV) + fUnknown4 = 0x00100000, + fUnknown5 = 0x00200000, + fUnknown6 = 0x00400000, + fUnknown7 = 0x00800000, + fUnknown8 = 0x01000000, + fIsObstacleOrNoAIAcquire = 0x02000000, // (FNV) + fIsNavMeshFilter = 0x04000000, // (FNV) + fIsNavMeshBoundBox = 0x08000000, // (FNV) + fIsNonPipboyOrAutoReflected = 0x10000000, // (FNV) + fIsChildUsableOrAutoRefracted = 0x20000000, // (FNV) + fIsNavMeshGround = 0x40000000, // (FNV) + fUnknown9 = 0x80000000 + }; + + public: + uint16_t formVersion; //FNV + uint8_t versionControl2[2]; //FNV + + FNVRecord(unsigned char *_recData=NULL); + virtual ~FNVRecord(); + + bool Read(); + uint32_t Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders); + }; + +#endif diff --git a/src/game/Skyrim/TES5Record.cpp b/src/game/Skyrim/TES5Record.cpp new file mode 100644 index 0000000..4c1d5ee --- /dev/null +++ b/src/game/Skyrim/TES5Record.cpp @@ -0,0 +1,196 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is CBash code. +* +* The Initial Developer of the Original Code is +* Waruddar. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ + +#include "TES5Record.h" +#include "TES5File.h" +#include + +TES5Record::TES5Record(unsigned char *_recData) : + Record(_recData), + formVersion(0) + { + memset(&versionControl2[0], 0x00, 2); + } + +TES5Record::TES5Record(TES5Record *srcRecord) + { + if (srcRecord == NULL) + return; + + flags = srcRecord->flags; + formID = srcRecord->formID; + flagsUnk = srcRecord->flagsUnk; + formVersion = srcRecord->formVersion; + versionControl2[0] = srcRecord->versionControl2[0]; + versionControl2[1] = srcRecord->versionControl2[1]; + + recData = srcRecord->recData; + } + +TES5Record::~TES5Record() + { + // + } + +TES5ModFile * TES5Record::GetParentMod() const + { + return dynamic_cast(this->Record::GetParentMod()); + } + +bool TES5Record::Read() + { + if (IsLoaded() || IsChanged()) + return false; + uint32_t recSize = *(uint32_t*)&recData[-20]; + + //Check against the original record flags to see if it is compressed since the current flags may have changed + if ((*(uint32_t*)&recData[-16] & fIsCompressed) != 0) + { + unsigned char localBuffer[BUFFERSIZE]; + uint32_t expandedRecSize = *(uint32_t*)recData; + unsigned char *buffer = (expandedRecSize >= BUFFERSIZE) ? new unsigned char[expandedRecSize] : &localBuffer[0]; + uncompress(buffer, (uLongf*)&expandedRecSize, &recData[4], recSize - 4); + ParseRecord(buffer, buffer + expandedRecSize, true); + if (buffer != &localBuffer[0]) + delete[] buffer; + } + else + ParseRecord(recData, recData + recSize); + + IsLoaded(true); + return true; + } + +uint32_t TES5Record::Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders) + { + uint32_t recSize = 0; + uint32_t recType = GetType(); + + collapser.Accept(formID); + + if (!IsChanged()) + { + if (bMastersChanged || flags != *(uint32_t*)&recData[-16]) + { + //if masters have changed, all formIDs have to be updated... + //or if the flags have changed internally (notably fIsDeleted or fIsCompressed, possibly others) + //so the record can't just be written as is. + if (Read()) + { + //if(expander.IsValid(data)) //optimization disabled for testing + // VisitFormIDs(expander); + //printer("Looking for correct expander\n"); + int32_t index = -1; + for (uint32_t x = 0; x < Expanders.size(); ++x) + if (IsValid(*Expanders[x])) + { + //if(index != -1) + // { + // printer("Multiple 'Correct' expanders found (%08X)! Using last one found (likely incorrect unless lucky)\n", formID); + // printer(" %i: %08X, %08X, %08X\n", index, Expanders[index]->FileStart, data, Expanders[index]->FileEnd); + // printer(" %i: %08X, %08X, %08X\n", x, Expanders[x]->FileStart, data, Expanders[x]->FileEnd); + // printer("Expanders:\n"); + // for(uint32_t z = 0; z < Expanders.size(); ++z) + // printer(" %i of %i: %08X, %08X\n", z, Expanders.size(), Expanders[z]->FileStart, Expanders[z]->FileEnd); + // } + index = x; + break; + } + if (index == -1) + { + printer("Unable to find the correct expander!\n"); + VisitFormIDs(expander); + } + else + VisitFormIDs(*Expanders[index]); + } + } + else + { + //if masters have not changed, the record can just be written from the read buffer + recSize = *(uint32_t*)&recData[-20]; + + writer.file_write(&recType, 4); + writer.file_write(&recSize, 4); + writer.file_write(&flags, 4); + writer.file_write(&formID, 4); + writer.file_write(&flagsUnk, 4); + writer.file_write(&formVersion, 2); + writer.file_write(&versionControl2[0], 2); + writer.file_write(recData, recSize); + Unload(); + return recSize + 24; + } + } + + VisitFormIDs(collapser); + + if (!IsDeleted()) + { + //IsCompressed(true); //Test code + WriteRecord(writer); + recSize = IsCompressed() ? writer.record_compress() : writer.record_size(); + writer.file_write(&recType, 4); + writer.file_write(&recSize, 4); + writer.file_write(&flags, 4); + writer.file_write(&formID, 4); + writer.file_write(&flagsUnk, 4); + writer.file_write(&formVersion, 2); + writer.file_write(&versionControl2[0], 2); + //if(IsCompressed()) + // { + // printer("Compressed: %08X\n", formID); + // } + writer.record_flush(); + } + else + { + writer.file_write(&recType, 4); + writer.file_write(&recSize, 4); + writer.file_write(&flags, 4); + writer.file_write(&formID, 4); + writer.file_write(&flagsUnk, 4); + writer.file_write(&formVersion, 2); + writer.file_write(&versionControl2[0], 2); + } + + expander.Accept(formID); + if (IsChanged()) + VisitFormIDs(expander); + else + Unload(); + return recSize + 24; + } \ No newline at end of file diff --git a/src/game/Skyrim/TES5Record.h b/src/game/Skyrim/TES5Record.h new file mode 100644 index 0000000..714b4a4 --- /dev/null +++ b/src/game/Skyrim/TES5Record.h @@ -0,0 +1,98 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is CBash code. +* +* The Initial Developer of the Original Code is +* Waruddar. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ + +#ifndef __CBASH_TES5_RECORD__ +#define __CBASH_TES5_RECORD__ + +#pragma once + +#include "common/GenericRecord.h" +#include "TES5ModFile.h" + +class TES5Record : public Record + { + protected: + enum TES5HeaderFlags + { + fIsESM = 0x00000001, + fUnknown01 = 0x00000002, + fUnknown02 = 0x00000004, + fUnknown03 = 0x00000008, + fUnknown04 = 0x00000010, + fUnknown05 = 0x00000020, + fUnknown06 = 0x00000040, + fUnknown07 = 0x00000080, + fUnknown08 = 0x00000100, + fUnknown09 = 0x00000200, + fUnknown10 = 0x00000400, + fUnknown11 = 0x00000800, + fUnknown12 = 0x00001000, + fUnknown13 = 0x00002000, + fUnknown14 = 0x00004000, + fUnknown15 = 0x00008000, + fUnknown16 = 0x00010000, + fUnknown17 = 0x00020000, + fUnknown18 = 0x00040000, + fUnknown19 = 0x00080000, + fUnknown20 = 0x00100000, + fUnknown21 = 0x00200000, + fUnknown22 = 0x00400000, + fUnknown23 = 0x00800000, + fUnknown24 = 0x01000000, + fUnknown25 = 0x02000000, + fUnknown26 = 0x04000000, + fUnknown27 = 0x08000000, + fUnknown28 = 0x10000000, + fUnknown29 = 0x20000000, + fUnknown30 = 0x40000000, + fUnknown31 = 0x80000000 + }; + + public: + uint16_t formVersion; //TES5 + uint8_t versionControl2[2]; //TES5 + + TES5Record(unsigned char *_recData = NULL); + TES5Record(TES5Record *srcRecord); + virtual ~TES5Record(); + + TES5ModFile * GetParentMod() const; + + bool Read(); + uint32_t Write(FileWriter &writer, const bool &bMastersChanged, FormIDResolver &expander, FormIDResolver &collapser, std::vector &Expanders); + }; + +#endif \ No newline at end of file