OpenMW
components/esm/esmreader.hpp
Go to the documentation of this file.
00001 #ifndef OPENMW_ESM_READER_H
00002 #define OPENMW_ESM_READER_H
00003 
00004 #include <libs/platform/stdint.h>
00005 #include <libs/platform/string.h>
00006 #include <cassert>
00007 #include <vector>
00008 #include <sstream>
00009 
00010 #include <OgreDataStream.h>
00011 
00012 #include <components/misc/stringops.hpp>
00013 
00014 #include <components/to_utf8/to_utf8.hpp>
00015 
00016 #include "esmcommon.hpp"
00017 #include "loadtes3.hpp"
00018 
00019 namespace ESM {
00020 
00021 class ESMReader
00022 {
00023 public:
00024 
00025   ESMReader();
00026 
00027   /*************************************************************************
00028    *
00029    *  Information retrieval
00030    *
00031    *************************************************************************/
00032 
00033   int getVer() const { return mHeader.mData.version; }
00034   float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; }
00035   const std::string getAuthor() const { return mHeader.mData.author.toString(); }
00036   const std::string getDesc() const { return mHeader.mData.desc.toString(); }
00037   const std::vector<Header::MasterData> &getGameFiles() const { return mHeader.mMaster; }
00038   int getFormat() const;
00039   const NAME &retSubName() const { return mCtx.subName; }
00040   uint32_t getSubSize() const { return mCtx.leftSub; }
00041 
00042   /*************************************************************************
00043    *
00044    *  Opening and closing
00045    *
00046    *************************************************************************/
00047 
00051   ESM_Context getContext();
00052 
00054   void restoreContext(const ESM_Context &rc);
00055 
00059   void close();
00060 
00063   void openRaw(Ogre::DataStreamPtr _esm, const std::string &name);
00064 
00067   void open(Ogre::DataStreamPtr _esm, const std::string &name);
00068 
00069   void open(const std::string &file);
00070 
00071   void openRaw(const std::string &file);
00072 
00074   size_t getFileSize() { return mEsm->size(); }
00076   size_t getFileOffset() { return mEsm->tell(); }
00077 
00078   // This is a quick hack for multiple esm/esp files. Each plugin introduces its own
00079   //  terrain palette, but ESMReader does not pass a reference to the correct plugin
00080   //  to the individual load() methods. This hack allows to pass this reference
00081   //  indirectly to the load() method.
00082   int mIdx;
00083   void setIndex(const int index) {mIdx = index; mCtx.index = index;}
00084   const int getIndex() {return mIdx;}
00085 
00086   void setGlobalReaderList(std::vector<ESMReader> *list) {mGlobalReaderList = list;}
00087   std::vector<ESMReader> *getGlobalReaderList() {return mGlobalReaderList;}
00088 
00089   /*************************************************************************
00090    *
00091    *  Medium-level reading shortcuts
00092    *
00093    *************************************************************************/
00094 
00095   // Read data of a given type, stored in a subrecord of a given name
00096   template <typename X>
00097   void getHNT(X &x, const char* name)
00098   {
00099     getSubNameIs(name);
00100     getHT(x);
00101   }
00102 
00103   // Optional version of getHNT
00104   template <typename X>
00105   void getHNOT(X &x, const char* name)
00106   {
00107       if(isNextSub(name))
00108           getHT(x);
00109   }
00110 
00111   // Version with extra size checking, to make sure the compiler
00112   // doesn't mess up our struct padding.
00113   template <typename X>
00114   void getHNT(X &x, const char* name, int size)
00115   {
00116       assert(sizeof(X) == size);
00117       getSubNameIs(name);
00118       getHT(x);
00119   }
00120 
00121   template <typename X>
00122   void getHNOT(X &x, const char* name, int size)
00123   {
00124       assert(sizeof(X) == size);
00125       if(isNextSub(name))
00126           getHT(x);
00127   }
00128 
00129   int64_t getHNLong(const char *name);
00130 
00131   // Get data of a given type/size, including subrecord header
00132   template <typename X>
00133   void getHT(X &x)
00134   {
00135       getSubHeader();
00136       if (mCtx.leftSub != sizeof(X))
00137           fail("getHT(): subrecord size mismatch");
00138       getT(x);
00139   }
00140 
00141   // Version with extra size checking, to make sure the compiler
00142   // doesn't mess up our struct padding.
00143   template <typename X>
00144   void getHT(X &x, int size)
00145   {
00146       assert(sizeof(X) == size);
00147       getHT(x);
00148   }
00149 
00150   // Read a string by the given name if it is the next record.
00151   std::string getHNOString(const char* name);
00152 
00153   // Read a string with the given sub-record name
00154   std::string getHNString(const char* name);
00155 
00156   // Read a string, including the sub-record header (but not the name)
00157   std::string getHString();
00158 
00159   // Read the given number of bytes from a subrecord
00160   void getHExact(void*p, int size);
00161 
00162   // Read the given number of bytes from a named subrecord
00163   void getHNExact(void*p, int size, const char* name);
00164 
00165   /*************************************************************************
00166    *
00167    *  Low level sub-record methods
00168    *
00169    *************************************************************************/
00170 
00171   // Get the next subrecord name and check if it matches the parameter
00172   void getSubNameIs(const char* name);
00173 
00179   bool isNextSub(const char* name);
00180 
00181   // Read subrecord name. This gets called a LOT, so I've optimized it
00182   // slightly.
00183   void getSubName();
00184 
00185   // This is specially optimized for LoadINFO.
00186   bool isEmptyOrGetName();
00187 
00188   // Skip current sub record, including header (but not including
00189   // name.)
00190   void skipHSub();
00191 
00192   // Skip sub record and check its size
00193   void skipHSubSize(int size);
00194 
00195   /* Sub-record header. This updates leftRec beyond the current
00196      sub-record as well. leftSub contains size of current sub-record.
00197   */
00198   void getSubHeader();
00199 
00202   void getSubHeaderIs(int size);
00203 
00204   /*************************************************************************
00205    *
00206    *  Low level record methods
00207    *
00208    *************************************************************************/
00209 
00210   // Get the next record name
00211   NAME getRecName();
00212 
00213   // Skip the rest of this record. Assumes the name and header have
00214   // already been read
00215   void skipRecord();
00216 
00217   // Skip an entire record, including the header (but not the name)
00218   void skipHRecord();
00219 
00220   /* Read record header. This updatesleftFile BEYOND the data that
00221      follows the header, ie beyond the entire record. You should use
00222      leftRec to orient yourself inside the record itself.
00223   */
00224   void getRecHeader() { getRecHeader(mRecordFlags); }
00225   void getRecHeader(uint32_t &flags);
00226 
00227   bool hasMoreRecs() const { return mCtx.leftFile > 0; }
00228   bool hasMoreSubs() const { return mCtx.leftRec > 0; }
00229 
00230 
00231   /*************************************************************************
00232    *
00233    *  Lowest level data reading and misc methods
00234    *
00235    *************************************************************************/
00236 
00237   template <typename X>
00238   void getT(X &x) { getExact(&x, sizeof(X)); }
00239 
00240   void getExact(void*x, int size);
00241   void getName(NAME &name) { getT(name); }
00242   void getUint(uint32_t &u) { getT(u); }
00243 
00244   // Read the next 'size' bytes and return them as a string. Converts
00245   // them from native encoding to UTF8 in the process.
00246   std::string getString(int size);
00247 
00248   void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); }
00249   uint64_t getOffset() { return mEsm->tell(); }
00250 
00252   void fail(const std::string &msg);
00253 
00255   void setEncoder(ToUTF8::Utf8Encoder* encoder);
00256 
00258   unsigned int getRecordFlags() { return mRecordFlags; }
00259 
00260 private:
00261   Ogre::DataStreamPtr mEsm;
00262 
00263   ESM_Context mCtx;
00264 
00265   unsigned int mRecordFlags;
00266 
00267   // Special file signifier (see SpecialFile enum above)
00268 
00269   // Buffer for ESM strings
00270   std::vector<char> mBuffer;
00271 
00272   Header mHeader;
00273 
00274   std::vector<ESMReader> *mGlobalReaderList;
00275   ToUTF8::Utf8Encoder* mEncoder;
00276 };
00277 }
00278 #endif