1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-18 18:40:06 +00:00

Merge branch 'next' of git://github.com/zinnschlag/openmw into next

This commit is contained in:
scrawl 2013-03-13 19:46:05 +01:00
commit e4717d7c92
21 changed files with 402 additions and 203 deletions

View File

@ -23,8 +23,7 @@ struct ESMData
std::string author; std::string author;
std::string description; std::string description;
int version; int version;
int type; std::vector<ESM::Header::MasterData> masters;
ESM::ESMReader::MasterList masters;
std::deque<EsmTool::RecordBase *> mRecords; std::deque<EsmTool::RecordBase *> mRecords;
std::map<ESM::Cell *, std::deque<ESM::CellRef> > mCellRefs; std::map<ESM::Cell *, std::deque<ESM::CellRef> > mCellRefs;
@ -284,16 +283,13 @@ int load(Arguments& info)
info.data.author = esm.getAuthor(); info.data.author = esm.getAuthor();
info.data.description = esm.getDesc(); info.data.description = esm.getDesc();
info.data.masters = esm.getMasters(); info.data.masters = esm.getMasters();
info.data.version = esm.getVer();
info.data.type = esm.getType();
if (!quiet) if (!quiet)
{ {
std::cout << "Author: " << esm.getAuthor() << std::endl std::cout << "Author: " << esm.getAuthor() << std::endl
<< "Description: " << esm.getDesc() << std::endl << "Description: " << esm.getDesc() << std::endl
<< "File format version: " << esm.getFVer() << std::endl << "File format version: " << esm.getFVer() << std::endl;
<< "Special flag: " << esm.getSpecial() << std::endl; std::vector<ESM::Header::MasterData> m = esm.getMasters();
ESM::ESMReader::MasterList m = esm.getMasters();
if (!m.empty()) if (!m.empty())
{ {
std::cout << "Masters:" << std::endl; std::cout << "Masters:" << std::endl;
@ -430,9 +426,9 @@ int clone(Arguments& info)
esm.setAuthor(info.data.author); esm.setAuthor(info.data.author);
esm.setDescription(info.data.description); esm.setDescription(info.data.description);
esm.setVersion(info.data.version); esm.setVersion(info.data.version);
esm.setType(info.data.type); esm.setRecordCount (recordCount);
for (ESM::ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) for (std::vector<ESM::Header::MasterData>::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it)
esm.addMaster(it->name, it->size); esm.addMaster(it->name, it->size);
std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary);

View File

@ -1,4 +1,3 @@
set (OPENCS_SRC main.cpp) set (OPENCS_SRC main.cpp)
opencs_units (. editor) opencs_units (. editor)

View File

@ -113,5 +113,7 @@ int CS::Editor::run()
{ {
mStartup.show(); mStartup.show();
QApplication::setQuitOnLastWindowClosed (true);
return QApplication::exec(); return QApplication::exec();
} }

View File

@ -2,7 +2,7 @@
#include "document.hpp" #include "document.hpp"
#include <cassert> #include <cassert>
#include <QDebug>
void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin, void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified) const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
{ {
@ -237,6 +237,9 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, b
connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving()));
} }
CSMDoc::Document::~Document()
{}
QUndoStack& CSMDoc::Document::getUndoStack() QUndoStack& CSMDoc::Document::getUndoStack()
{ {
return mUndoStack; return mUndoStack;
@ -290,11 +293,13 @@ void CSMDoc::Document::abortOperation (int type)
} }
} }
void CSMDoc::Document::modificationStateChanged (bool clean) void CSMDoc::Document::modificationStateChanged (bool clean)
{ {
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
void CSMDoc::Document::operationDone (int type) void CSMDoc::Document::operationDone (int type)
{ {
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
@ -308,9 +313,12 @@ void CSMDoc::Document::saving()
if (mSaveCount>15) if (mSaveCount>15)
{ {
//clear the stack before resetting the save state
//to avoid emitting incorrect states
mUndoStack.setClean();
mSaveCount = 0; mSaveCount = 0;
mSaveTimer.stop(); mSaveTimer.stop();
mUndoStack.setClean();
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
} }

View File

@ -63,6 +63,7 @@ namespace CSMDoc
public: public:
Document (const std::vector<boost::filesystem::path>& files, bool new_); Document (const std::vector<boost::filesystem::path>& files, bool new_);
~Document();
QUndoStack& getUndoStack(); QUndoStack& getUndoStack();
@ -105,4 +106,4 @@ namespace CSMDoc
}; };
} }
#endif #endif

View File

@ -56,7 +56,7 @@ void CSVDoc::Operations::quitOperation (int type)
mLayout->removeItem ((*iter)->getLayout()); mLayout->removeItem ((*iter)->getLayout());
delete *iter; (*iter)->deleteLater();
mOperations.erase (iter); mOperations.erase (iter);
if (oldCount > 1) if (oldCount > 1)

View File

@ -7,6 +7,7 @@
#include <QMenuBar> #include <QMenuBar>
#include <QMdiArea> #include <QMdiArea>
#include <QDockWidget> #include <QDockWidget>
#include <QtGui/QApplication>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
@ -39,6 +40,16 @@ void CSVDoc::View::setupFileMenu()
mSave = new QAction (tr ("&Save"), this); mSave = new QAction (tr ("&Save"), this);
connect (mSave, SIGNAL (triggered()), this, SLOT (save())); connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
file->addAction (mSave); file->addAction (mSave);
QAction *close = new QAction (tr ("&Close"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close);
QAction *exit = new QAction (tr ("&Exit"), this);
connect (exit, SIGNAL (triggered()), this, SLOT (exit()));
connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *)));
file->addAction(exit);
} }
void CSVDoc::View::setupEditMenu() void CSVDoc::View::setupEditMenu()
@ -117,15 +128,15 @@ void CSVDoc::View::updateActions()
mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying));
} }
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent) CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), QMainWindow (viewParent) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
mViewTotal (totalViews)
{ {
setDockOptions (QMainWindow::AllowNestedDocks);
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
mSubViewWindow = new QMainWindow(); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
setCentralWidget (mSubViewWindow);
setCentralWidget (&mSubViewWindow);
mOperations = new Operations; mOperations = new Operations;
addDockWidget (Qt::BottomDockWidgetArea, mOperations); addDockWidget (Qt::BottomDockWidgetArea, mOperations);
@ -200,7 +211,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
/// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis)
SubView *view = mSubViewFactory.makeSubView (id, *mDocument); SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
mSubViewWindow->addDockWidget (Qt::TopDockWidgetArea, view); mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&))); SLOT (addSubView (const CSMWorld::UniversalId&)));
@ -239,7 +250,12 @@ void CSVDoc::View::abortOperation (int type)
updateActions(); updateActions();
} }
QDockWidget *CSVDoc::View::getOperations() const CSVDoc::Operations *CSVDoc::View::getOperations() const
{ {
return mOperations; return mOperations;
} }
void CSVDoc::View::exit()
{
emit exitApplicationRequest (this);
}

View File

@ -41,7 +41,8 @@ namespace CSVDoc
std::vector<QAction *> mEditingActions; std::vector<QAction *> mEditingActions;
Operations *mOperations; Operations *mOperations;
SubViewFactoryManager mSubViewFactory; SubViewFactoryManager mSubViewFactory;
QMainWindow* mSubViewWindow; QMainWindow mSubViewWindow;
// not implemented // not implemented
View (const View&); View (const View&);
@ -65,9 +66,12 @@ namespace CSVDoc
void updateActions(); void updateActions();
void exitApplication();
public: public:
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent); View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews);
///< The ownership of \a document is not transferred to *this. ///< The ownership of \a document is not transferred to *this.
virtual ~View(); virtual ~View();
@ -82,7 +86,7 @@ namespace CSVDoc
void updateProgress (int current, int max, int type, int threads); void updateProgress (int current, int max, int type, int threads);
QDockWidget *getOperations() const; Operations *getOperations() const;
signals: signals:
@ -90,23 +94,28 @@ namespace CSVDoc
void loadDocumentRequest(); void loadDocumentRequest();
void exitApplicationRequest (CSVDoc::View *view);
public slots: public slots:
void addSubView (const CSMWorld::UniversalId& id); void addSubView (const CSMWorld::UniversalId& id);
void abortOperation (int type);
private slots: private slots:
void newView(); void newView();
void save(); void save();
void exit();
void verify(); void verify();
void addGlobalsSubView(); void addGlobalsSubView();
void addGmstsSubView(); void addGmstsSubView();
void abortOperation (int type);
}; };
} }

View File

@ -12,6 +12,11 @@
#include "view.hpp" #include "view.hpp"
#include <QMessageBox>
#include <QPushButton>
#include <QtGui/QApplication>
#include <QDebug>
void CSVDoc::ViewManager::updateIndices() void CSVDoc::ViewManager::updateIndices()
{ {
std::map<CSMDoc::Document *, std::pair<int, int> > documents; std::map<CSMDoc::Document *, std::pair<int, int> > documents;
@ -31,7 +36,7 @@ void CSVDoc::ViewManager::updateIndices()
} }
CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
: mDocumentManager (documentManager) : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false)
{ {
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
@ -40,7 +45,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType,
new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float));
} }
CSVDoc::ViewManager::~ViewManager() CSVDoc::ViewManager::~ViewManager()
@ -63,9 +67,8 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); this, SLOT (progress (int, int, int, int, CSMDoc::Document *)));
} }
QMainWindow *mainWindow = new QMainWindow; View *view = new View (*this, document, countViews (document)+1);
View *view = new View (*this, document, countViews (document)+1, mainWindow);
mViews.push_back (view); mViews.push_back (view);
@ -94,23 +97,143 @@ bool CSVDoc::ViewManager::closeRequest (View *view)
{ {
std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view); std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view);
bool continueWithClose = true;
if (iter!=mViews.end()) if (iter!=mViews.end())
{ {
bool last = countViews (view->getDocument())<=1; bool last = countViews (view->getDocument())<=1;
/// \todo check if save is in progress -> warn user about possible data loss
/// \todo check if document has not been saved -> return false and start close dialogue
mViews.erase (iter);
view->deleteLater();
if (last) if (last)
mDocumentManager.removeDocument (view->getDocument()); continueWithClose = notifySaveOnClose (view);
else else
{
(*iter)->deleteLater();
mViews.erase (iter);
updateIndices(); updateIndices();
}
} }
return true; return continueWithClose;
}
bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view)
{
bool result = true;
CSMDoc::Document *document = view->getDocument();
//notify user of saving in progress
if ( (document->getState() & CSMDoc::State_Saving) )
result = showSaveInProgressMessageBox (view);
//notify user of unsaved changes and process response
else if ( document->getState() & CSMDoc::State_Modified)
result = showModifiedDocumentMessageBox (view);
return result;
}
bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view)
{
QMessageBox messageBox;
CSMDoc::Document *document = view->getDocument();
messageBox.setText ("The document has been modified.");
messageBox.setInformativeText ("Do you want to save your changes?");
messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
messageBox.setDefaultButton (QMessageBox::Save);
bool retVal = true;
connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close()));
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
mUserWarned = true;
int response = messageBox.exec();
mUserWarned = false;
switch (response)
{
case QMessageBox::Save:
document->save();
mExitOnSaveStateChange = true;
retVal = false;
break;
case QMessageBox::Discard:
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
break;
case QMessageBox::Cancel:
//disconnect to prevent unintended view closures
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
retVal = false;
break;
default:
break;
}
return retVal;
}
bool CSVDoc::ViewManager::showSaveInProgressMessageBox (CSVDoc::View *view)
{
QMessageBox messageBox;
CSMDoc::Document *document = view->getDocument();
messageBox.setText ("The document is currently being saved.");
messageBox.setInformativeText("Do you want to close now and abort saving, or wait until saving has completed?");
QPushButton* waitButton = messageBox.addButton (tr("Wait"), QMessageBox::YesRole);
QPushButton* closeButton = messageBox.addButton (tr("Close Now"), QMessageBox::RejectRole);
QPushButton* cancelButton = messageBox.addButton (tr("Cancel"), QMessageBox::NoRole);
messageBox.setDefaultButton (waitButton);
bool retVal = true;
//Connections shut down message box if operation ends before user makes a decision.
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close()));
//set / clear the user warned flag to indicate whether or not the message box is currently active.
mUserWarned = true;
messageBox.exec();
mUserWarned = false;
//if closed by the warning handler, defaults to the RejectRole button (closeButton)
if (messageBox.clickedButton() == waitButton)
{
//save the View iterator for shutdown after the save operation ends
mExitOnSaveStateChange = true;
retVal = false;
}
else if (messageBox.clickedButton() == closeButton)
{
//disconnect to avoid segmentation fault
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
view->abortOperation(CSMDoc::State_Saving);
mExitOnSaveStateChange = true;
}
else if (messageBox.clickedButton() == cancelButton)
{
//abort shutdown, allow save to complete
//disconnection to prevent unintended view closures
mExitOnSaveStateChange = false;
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
retVal = false;
}
return retVal;
} }
void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document) void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document)
@ -126,3 +249,25 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads,
if ((*iter)->getDocument()==document) if ((*iter)->getDocument()==document)
(*iter)->updateProgress (current, max, type, threads); (*iter)->updateProgress (current, max, type, threads);
} }
void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *document)
{
if ( !(state & CSMDoc::State_Saving) )
{
//if the user is being warned (message box is active), shut down the message box,
//as there is no save operation currently running
if ( mUserWarned )
emit closeMessageBox();
//otherwise, the user has closed the message box before the save operation ended.
//exit the application
else if (mExitOnSaveStateChange)
QApplication::instance()->exit();
}
}
void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
{
if (notifySaveOnClose (view))
QApplication::instance()->exit();
}

View File

@ -27,12 +27,17 @@ namespace CSVDoc
CSMDoc::DocumentManager& mDocumentManager; CSMDoc::DocumentManager& mDocumentManager;
std::vector<View *> mViews; std::vector<View *> mViews;
CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories;
bool mExitOnSaveStateChange;
bool mUserWarned;
// not implemented // not implemented
ViewManager (const ViewManager&); ViewManager (const ViewManager&);
ViewManager& operator= (const ViewManager&); ViewManager& operator= (const ViewManager&);
void updateIndices(); void updateIndices();
bool notifySaveOnClose (View *view = 0);
bool showModifiedDocumentMessageBox (View *view);
bool showSaveInProgressMessageBox (View *view);
public: public:
@ -54,13 +59,21 @@ namespace CSVDoc
void loadDocumentRequest(); void loadDocumentRequest();
void closeMessageBox();
public slots:
void exitApplication (CSVDoc::View *view);
private slots: private slots:
void documentStateChanged (int state, CSMDoc::Document *document); void documentStateChanged (int state, CSMDoc::Document *document);
void progress (int current, int max, int type, int threads, CSMDoc::Document *document); void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
void onExitWarningHandler(int state, CSMDoc::Document* document);
}; };
} }
#endif #endif

View File

@ -27,14 +27,15 @@ void ESMStore::load(ESM::ESMReader &esm)
ESM::Dialogue *dialogue = 0; ESM::Dialogue *dialogue = 0;
/// \todo Move this to somewhere else. ESMReader?
// Cache parent esX files by tracking their indices in the global list of // Cache parent esX files by tracking their indices in the global list of
// all files/readers used by the engine. This will greaty accelerate // all files/readers used by the engine. This will greaty accelerate
// refnumber mangling, as required for handling moved references. // refnumber mangling, as required for handling moved references.
int index = ~0; int index = ~0;
const ESM::ESMReader::MasterList &masters = esm.getMasters(); const std::vector<ESM::Header::MasterData> &masters = esm.getMasters();
std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList(); std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList();
for (size_t j = 0; j < masters.size(); j++) { for (size_t j = 0; j < masters.size(); j++) {
ESM::MasterData &mast = const_cast<ESM::MasterData&>(masters[j]); ESM::Header::MasterData &mast = const_cast<ESM::Header::MasterData&>(masters[j]);
std::string fname = mast.name; std::string fname = mast.name;
for (int i = 0; i < esm.getIndex(); i++) { for (int i = 0; i < esm.getIndex(); i++) {
const std::string &candidate = allPlugins->at(i).getContext().filename; const std::string &candidate = allPlugins->at(i).getContext().filename;

View File

@ -39,7 +39,7 @@ add_component_dir (esm
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
loadweap records aipackage effectlist spelllist variant variantimp loadweap records aipackage effectlist spelllist variant variantimp loadtes3
) )
add_component_dir (misc add_component_dir (misc

View File

@ -2,6 +2,7 @@
#define OPENMW_ESM_COMMON_H #define OPENMW_ESM_COMMON_H
#include <string> #include <string>
#include <cstring>
#include <libs/platform/stdint.h> #include <libs/platform/stdint.h>
#include <libs/platform/string.h> #include <libs/platform/string.h>
@ -14,24 +15,6 @@ enum Version
VER_13 = 0x3fa66666 VER_13 = 0x3fa66666
}; };
enum FileType
{
FT_ESP = 0, // Plugin
FT_ESM = 1, // Master
FT_ESS = 32 // Savegame
};
// Used to mark special files. The original ESM files are given
// special treatment in a few places, most noticably in loading and
// filtering out "dirtly" GMST entries correctly.
enum SpecialFile
{
SF_Other,
SF_Morrowind,
SF_Tribunal,
SF_Bloodmoon
};
/* A structure used for holding fixed-length strings. In the case of /* A structure used for holding fixed-length strings. In the case of
LEN=4, it can be more efficient to match the string as a 32 bit LEN=4, it can be more efficient to match the string as a 32 bit
number, therefore the struct is implemented as a union with an int. number, therefore the struct is implemented as a union with an int.
@ -41,7 +24,7 @@ union NAME_T
{ {
char name[LEN]; char name[LEN];
int32_t val; int32_t val;
bool operator==(const char *str) const bool operator==(const char *str) const
{ {
for(int i=0; i<LEN; i++) for(int i=0; i<LEN; i++)
@ -61,6 +44,8 @@ union NAME_T
bool operator!=(int v) const { return v != val; } bool operator!=(int v) const { return v != val; }
std::string toString() const { return std::string(name, strnlen(name, LEN)); } std::string toString() const { return std::string(name, strnlen(name, LEN)); }
void assign (const std::string& value) { std::strncpy (name, value.c_str(), LEN); }
}; };
typedef NAME_T<4> NAME; typedef NAME_T<4> NAME;
@ -70,28 +55,6 @@ typedef NAME_T<256> NAME256;
#pragma pack(push) #pragma pack(push)
#pragma pack(1) #pragma pack(1)
/// File header data for all ES files
struct HEDRstruct
{
/* File format version. This is actually a float, the supported
versions are 1.2 and 1.3. These correspond to:
1.2 = 0x3f99999a and 1.3 = 0x3fa66666
*/
int version;
int type; // 0=esp, 1=esm, 32=ess
NAME32 author; // Author's name
NAME256 desc; // File description
int records; // Number of records? Not used.
};
// Defines another files (esm or esp) that this file depends upon.
struct MasterData
{
std::string name;
uint64_t size;
int index; // Position of the parent file in the global list of loaded files
};
// Data that is only present in save game files // Data that is only present in save game files
struct SaveData struct SaveData
{ {
@ -113,7 +76,6 @@ struct ESM_Context
uint32_t leftRec, leftSub; uint32_t leftRec, leftSub;
size_t leftFile; size_t leftFile;
NAME recName, subName; NAME recName, subName;
HEDRstruct header;
// When working with multiple esX files, we will generate lists of all files that // When working with multiple esX files, we will generate lists of all files that
// actually contribute to a specific cell. Therefore, we need to store the index // actually contribute to a specific cell. Therefore, we need to store the index
// of the file belonging to this contest. See CellStore::(list/load)refs for details. // of the file belonging to this contest. See CellStore::(list/load)refs for details.

View File

@ -15,11 +15,16 @@ ESM_Context ESMReader::getContext()
return mCtx; return mCtx;
} }
ESMReader::ESMReader(void): ESMReader::ESMReader():
mBuffer(50*1024) mBuffer(50*1024)
{ {
} }
int ESMReader::getFormat() const
{
return mHeader.mFormat;
}
void ESMReader::restoreContext(const ESM_Context &rc) void ESMReader::restoreContext(const ESM_Context &rc)
{ {
// Reopen the file if necessary // Reopen the file if necessary
@ -51,18 +56,6 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name)
mEsm = _esm; mEsm = _esm;
mCtx.filename = name; mCtx.filename = name;
mCtx.leftFile = mEsm->size(); mCtx.leftFile = mEsm->size();
// Flag certain files for special treatment, based on the file
// name.
const char *cstr = mCtx.filename.c_str();
if (iends(cstr, "Morrowind.esm"))
mSpf = SF_Morrowind;
else if (iends(cstr, "Tribunal.esm"))
mSpf = SF_Tribunal;
else if (iends(cstr, "Bloodmoon.esm"))
mSpf = SF_Bloodmoon;
else
mSpf = SF_Other;
} }
void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name)
@ -74,42 +67,7 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name)
getRecHeader(); getRecHeader();
// Get the header mHeader.load (*this);
getHNT(mCtx.header, "HEDR", 300);
// Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it.
while (isNextSub("MAST"))
{
MasterData m;
m.name = getHString();
m.size = getHNLong("DATA");
mMasters.push_back(m);
}
if (mCtx.header.type == FT_ESS)
{
// Savegame-related data
// Player position etc
getHNT(mSaveData, "GMDT", 124);
/* Image properties, five ints. Is always:
Red-mask: 0xff0000
Blue-mask: 0x00ff00
Green-mask: 0x0000ff
Alpha-mask: 0x000000
Bpp: 32
*/
getSubNameIs("SCRD");
skipHSubSize(20);
/* Savegame screenshot:
128x128 pixels * 4 bytes per pixel
*/
getSubNameIs("SCRS");
skipHSubSize(65536);
}
} }
void ESMReader::open(const std::string &file) void ESMReader::open(const std::string &file)

View File

@ -12,7 +12,9 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
#include "esmcommon.hpp" #include "esmcommon.hpp"
#include "loadtes3.hpp"
namespace ESM { namespace ESM {
@ -20,15 +22,7 @@ class ESMReader
{ {
public: public:
ESMReader(void); ESMReader();
/*************************************************************************
*
* Public type definitions
*
*************************************************************************/
typedef std::vector<MasterData> MasterList;
/************************************************************************* /*************************************************************************
* *
@ -36,14 +30,12 @@ public:
* *
*************************************************************************/ *************************************************************************/
int getVer() const { return mCtx.header.version; } int getVer() const { return mHeader.mData.version; }
float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; }
int getSpecial() const { return mSpf; } const std::string getAuthor() const { return mHeader.mData.author.toString(); }
int getType() const { return mCtx.header.type; } const std::string getDesc() const { return mHeader.mData.desc.toString(); }
const std::string getAuthor() const { return mCtx.header.author.toString(); } const std::vector<Header::MasterData> &getMasters() const { return mHeader.mMaster; }
const std::string getDesc() const { return mCtx.header.desc.toString(); } int getFormat() const;
const SaveData &getSaveData() const { return mSaveData; }
const MasterList &getMasters() const { return mMasters; }
const NAME &retSubName() const { return mCtx.subName; } const NAME &retSubName() const { return mCtx.subName; }
uint32_t getSubSize() const { return mCtx.leftSub; } uint32_t getSubSize() const { return mCtx.leftSub; }
@ -263,13 +255,12 @@ private:
ESM_Context mCtx; ESM_Context mCtx;
// Special file signifier (see SpecialFile enum above) // Special file signifier (see SpecialFile enum above)
int mSpf;
// Buffer for ESM strings // Buffer for ESM strings
std::vector<char> mBuffer; std::vector<char> mBuffer;
SaveData mSaveData; Header mHeader;
MasterList mMasters;
std::vector<ESMReader> *mGlobalReaderList; std::vector<ESMReader> *mGlobalReaderList;
ToUTF8::Utf8Encoder* mEncoder; ToUTF8::Utf8Encoder* mEncoder;
}; };

View File

@ -1,6 +1,8 @@
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include <cassert>
#include <fstream> #include <fstream>
#include <cstring> #include <iostream>
bool count = true; bool count = true;
@ -9,40 +11,40 @@ namespace ESM
int ESMWriter::getVersion() int ESMWriter::getVersion()
{ {
return m_header.version; return mHeader.mData.version;
} }
void ESMWriter::setVersion(int ver) void ESMWriter::setVersion(int ver)
{ {
m_header.version = ver; mHeader.mData.version = ver;
}
int ESMWriter::getType()
{
return m_header.type;
}
void ESMWriter::setType(int type)
{
m_header.type = type;
} }
void ESMWriter::setAuthor(const std::string& auth) void ESMWriter::setAuthor(const std::string& auth)
{ {
strncpy((char*)&m_header.author, auth.c_str(), 32); mHeader.mData.author.assign (auth);
} }
void ESMWriter::setDescription(const std::string& desc) void ESMWriter::setDescription(const std::string& desc)
{ {
strncpy((char*)&m_header.desc, desc.c_str(), 256); mHeader.mData.desc.assign (desc);
}
void ESMWriter::setRecordCount (int count)
{
mHeader.mData.records = count;
}
void ESMWriter::setFormat (int format)
{
mHeader.mFormat = format;
} }
void ESMWriter::addMaster(const std::string& name, uint64_t size) void ESMWriter::addMaster(const std::string& name, uint64_t size)
{ {
MasterData d; Header::MasterData d;
d.name = name; d.name = name;
d.size = size; d.size = size;
m_masters.push_back(d); mHeader.mMaster.push_back(d);
} }
void ESMWriter::save(const std::string& file) void ESMWriter::save(const std::string& file)
@ -58,25 +60,13 @@ void ESMWriter::save(std::ostream& file)
startRecord("TES3", 0); startRecord("TES3", 0);
m_header.records = 0; mHeader.save (*this);
writeHNT("HEDR", m_header, 300);
m_headerPos = m_stream->tellp() - (std::streampos)4;
for (std::list<MasterData>::iterator it = m_masters.begin(); it != m_masters.end(); ++it)
{
writeHNCString("MAST", it->name);
writeHNT("DATA", it->size);
}
endRecord("TES3"); endRecord("TES3");
} }
void ESMWriter::close() void ESMWriter::close()
{ {
std::cout << "Writing amount of saved records (" << m_recordCount - 1 << ")" << std::endl;
m_stream->seekp(m_headerPos);
writeT<int>(m_recordCount-1);
m_stream->seekp(0, std::ios::end);
m_stream->flush(); m_stream->flush();
if (!m_records.empty()) if (!m_records.empty())
@ -86,7 +76,7 @@ void ESMWriter::close()
void ESMWriter::startRecord(const std::string& name, uint32_t flags) void ESMWriter::startRecord(const std::string& name, uint32_t flags)
{ {
m_recordCount++; m_recordCount++;
writeName(name); writeName(name);
RecordData rec; RecordData rec;
rec.name = name; rec.name = name;
@ -109,7 +99,7 @@ void ESMWriter::startSubRecord(const std::string& name)
rec.size = 0; rec.size = 0;
writeT<int>(0); // Size goes here writeT<int>(0); // Size goes here
m_records.push_back(rec); m_records.push_back(rec);
assert(m_records.back().size == 0); assert(m_records.back().size == 0);
} }
@ -118,7 +108,7 @@ void ESMWriter::endRecord(const std::string& name)
RecordData rec = m_records.back(); RecordData rec = m_records.back();
assert(rec.name == name); assert(rec.name == name);
m_records.pop_back(); m_records.pop_back();
m_stream->seekp(rec.position); m_stream->seekp(rec.position);
count = false; count = false;

View File

@ -1,12 +1,13 @@
#ifndef OPENMW_ESM_WRITER_H #ifndef OPENMW_ESM_WRITER_H
#define OPENMW_ESM_WRITER_H #define OPENMW_ESM_WRITER_H
#include <iostream> #include <iosfwd>
#include <list> #include <list>
#include <assert.h>
#include <components/to_utf8/to_utf8.hpp>
#include "esmcommon.hpp" #include "esmcommon.hpp"
#include <components/to_utf8/to_utf8.hpp> #include "loadtes3.hpp"
namespace ESM { namespace ESM {
@ -22,11 +23,11 @@ class ESMWriter
public: public:
int getVersion(); int getVersion();
void setVersion(int ver); void setVersion(int ver);
int getType();
void setType(int type);
void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8? void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8?
void setAuthor(const std::string& author); void setAuthor(const std::string& author);
void setDescription(const std::string& desc); void setDescription(const std::string& desc);
void setRecordCount (int count);
void setFormat (int format);
void addMaster(const std::string& name, uint64_t size); void addMaster(const std::string& name, uint64_t size);
@ -80,7 +81,7 @@ public:
{ {
write((char*)&data, size); write((char*)&data, size);
} }
void startRecord(const std::string& name, uint32_t flags); void startRecord(const std::string& name, uint32_t flags);
void startSubRecord(const std::string& name); void startSubRecord(const std::string& name);
void endRecord(const std::string& name); void endRecord(const std::string& name);
@ -90,14 +91,13 @@ public:
void write(const char* data, size_t size); void write(const char* data, size_t size);
private: private:
std::list<MasterData> m_masters;
std::list<RecordData> m_records; std::list<RecordData> m_records;
std::ostream* m_stream; std::ostream* m_stream;
std::streampos m_headerPos; std::streampos m_headerPos;
ToUTF8::Utf8Encoder* m_encoder; ToUTF8::Utf8Encoder* m_encoder;
int m_recordCount; int m_recordCount;
HEDRstruct m_header; Header mHeader;
}; };
} }

View File

@ -245,7 +245,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
// If the most significant 8 bits are used, then this reference already exists. // If the most significant 8 bits are used, then this reference already exists.
// In this case, do not spawn a new reference, but overwrite the old one. // In this case, do not spawn a new reference, but overwrite the old one.
ref.mRefnum &= 0x00ffffff; // delete old plugin ID ref.mRefnum &= 0x00ffffff; // delete old plugin ID
const ESM::ESMReader::MasterList &masters = esm.getMasters(); const std::vector<Header::MasterData> &masters = esm.getMasters();
global = masters[local-1].index + 1; global = masters[local-1].index + 1;
ref.mRefnum |= global << 24; // insert global plugin ID ref.mRefnum |= global << 24; // insert global plugin ID
} }
@ -348,7 +348,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
int local = (mref.mRefnum & 0xff000000) >> 24; int local = (mref.mRefnum & 0xff000000) >> 24;
size_t global = esm.getIndex() + 1; size_t global = esm.getIndex() + 1;
mref.mRefnum &= 0x00ffffff; // delete old plugin ID mref.mRefnum &= 0x00ffffff; // delete old plugin ID
const ESM::ESMReader::MasterList &masters = esm.getMasters(); const std::vector<Header::MasterData> &masters = esm.getMasters();
global = masters[local-1].index + 1; global = masters[local-1].index + 1;
mref.mRefnum |= global << 24; // insert global plugin ID mref.mRefnum |= global << 24; // insert global plugin ID

View File

@ -0,0 +1,53 @@
#include "loadtes3.hpp"
#include "esmcommon.hpp"
#include "esmreader.hpp"
#include "esmwriter.hpp"
void ESM::Header::blank()
{
mData.version = ESM::VER_13;
mData.type = 0;
mData.author.assign ("");
mData.desc.assign ("");
mData.records = 0;
mFormat = CurrentFormat;
}
void ESM::Header::load (ESMReader &esm)
{
esm.getHNT (mData, "HEDR", 300);
if (esm.isNextSub ("FORM"))
{
esm.getHT (mFormat);
if (mFormat<0)
esm.fail ("invalid format code");
}
else
mFormat = 0;
while (esm.isNextSub ("MAST"))
{
MasterData m;
m.name = esm.getHString();
m.size = esm.getHNLong ("DATA");
mMaster.push_back (m);
}
}
void ESM::Header::save (ESMWriter &esm)
{
esm.writeHNT ("HEDR", mData, 300);
if (mFormat>0)
esm.writeHNT ("FORM", mFormat);
for (std::vector<Header::MasterData>::iterator iter = mMaster.begin();
iter != mMaster.end(); ++iter)
{
esm.writeHNCString ("MAST", iter->name);
esm.writeHNT ("DATA", iter->size);
}
}

View File

@ -0,0 +1,55 @@
#ifndef COMPONENT_ESM_TES3_H
#define COMPONENT_ESM_TES3_H
#include <vector>
#include "esmcommon.hpp"
namespace ESM
{
class ESMReader;
class ESMWriter;
#pragma pack(push)
#pragma pack(1)
/// \brief File header record
struct Header
{
static const int CurrentFormat = 0; // most recent known format
struct Data
{
/* File format version. This is actually a float, the supported
versions are 1.2 and 1.3. These correspond to:
1.2 = 0x3f99999a and 1.3 = 0x3fa66666
*/
int version;
int type; // 0=esp, 1=esm, 32=ess (unused)
NAME32 author; // Author's name
NAME256 desc; // File description
int records; // Number of records? Not used.
};
// Defines another files (esm or esp) that this file depends upon.
struct MasterData
{
std::string name;
uint64_t size;
int index; // Position of the parent file in the global list of loaded files
};
Data mData;
int mFormat;
std::vector<MasterData> mMaster;
void blank();
void load (ESMReader &esm);
void save (ESMWriter &esm);
};
#pragma pack(pop)
}
#endif

View File

@ -1,6 +1,6 @@
#include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QDir> #include <QDir>
#include <QDebug>
#include <stdexcept> #include <stdexcept>
@ -157,7 +157,7 @@ Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const
if (!file) if (!file)
return Qt::NoItemFlags; return Qt::NoItemFlags;
if (canBeChecked(file)) { if (canBeChecked(file)) {
if (index.column() == 0) { if (index.column() == 0) {
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
} else { } else {
@ -226,7 +226,7 @@ bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2)
return true; return true;
if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm"))
return false; return false;
return e1->fileName().toLower() < e2->fileName().toLower(); return e1->fileName().toLower() < e2->fileName().toLower();
} }
@ -281,7 +281,7 @@ void DataFilesModel::addFiles(const QString &path)
fileReader.setEncoder(&encoder); fileReader.setEncoder(&encoder);
fileReader.open(dir.absoluteFilePath(path).toStdString()); fileReader.open(dir.absoluteFilePath(path).toStdString());
ESM::ESMReader::MasterList mlist = fileReader.getMasters(); std::vector<ESM::Header::MasterData> mlist = fileReader.getMasters();
QStringList masters; QStringList masters;
for (unsigned int i = 0; i < mlist.size(); ++i) { for (unsigned int i = 0; i < mlist.size(); ++i) {
@ -369,10 +369,10 @@ QStringList DataFilesModel::checkedItems()
QStringList DataFilesModel::checkedItemsPaths() QStringList DataFilesModel::checkedItemsPaths()
{ {
QStringList list; QStringList list;
QList<EsmFile *>::ConstIterator it; QList<EsmFile *>::ConstIterator it;
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd(); QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
int i = 0; int i = 0;
for (it = mFiles.constBegin(); it != itEnd; ++it) { for (it = mFiles.constBegin(); it != itEnd; ++it) {
EsmFile *file = item(i); EsmFile *file = item(i);
@ -381,7 +381,7 @@ QStringList DataFilesModel::checkedItemsPaths()
if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file)) if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file))
list << file->path(); list << file->path();
} }
return list; return list;
} }