Explorar el Código

Changed SubDirectory class members to smart-pointers and optimised initialisation

Ivan Arkhipov hace 6 años
padre
commit
092b506dcc
Se han modificado 2 ficheros con 79 adiciones y 66 borrados
  1. 25 11
      include/SubDirectory.h
  2. 54 55
      src/SubDirectory.cpp

+ 25 - 11
include/SubDirectory.h

@@ -7,6 +7,7 @@
 
 #include <vector>
 #include <map>
+#include <queue>
 #include <unordered_map>
 #include <unordered_set>
 #include "Subfile.h"
@@ -18,33 +19,46 @@ namespace LOTRO_DAT
 {
     enum FILE_TYPE : int;
     class DatFile;
-    class DatException;
     class BinaryData;
     class Subfile;
 
     class SubDirectory
     {
     public:
-        SubDirectory();
-        SubDirectory(long long offset, DatFile *dat, long long max_subdirs = 63);
+        struct SubDirectoryOffsetComp {
+            bool operator() (const SubDirectory* f, const SubDirectory *s){
+                if (!f || !s)
+                    return false;
+                return f->offset_ < s->offset_;
+            }
+        };
+        SubDirectory() = delete;
+        explicit SubDirectory(const SubDirectory& other) = delete;
+        SubDirectory& operator =(const SubDirectory &other) = delete;
+
+        SubDirectory(long long offset, DatFile &dat, long long max_subdirs = 63);
         ~SubDirectory();
-        void MakeDictionary(std::map<long long, Subfile*> &dict);
+        void MakeDictionary(std::map<long long, std::shared_ptr<Subfile>> &dict);
 
-        static std::set<long long> visited_subdirectories_;
-    private:
         bool MakeSubDirectories();
-
         bool MakeSubFiles();
-        Subfile* MakeSubfile(long long dictionary_offset, long long unknown1, long long file_id, long long file_offset,
+
+        static std::unordered_set<long long> visited_subdirectories_;
+        static std::unordered_set<long long> visited_subfiles_;
+        static std::set<std::shared_ptr<SubDirectory>, SubDirectoryOffsetComp> subdir_init_queue_;
+        static std::set<std::shared_ptr<SubDirectory>, SubDirectoryOffsetComp> subfile_init_queue_;
+
+    private:
+        std::shared_ptr<Subfile> MakeSubfile(long long dictionary_offset, long long unknown1, long long file_id, long long file_offset,
                              long long file_size, long long timestamp, long long version, long long block_size, long long unknown2);
 
         FILE_TYPE GetSubfileType(long long file_id, long long file_offset) const;
-        DatFile *dat_;
+        DatFile &dat_;
         long long offset_;
         long long max_subdirs_;
-        std::vector<SubDirectory *> subdirs_;
 
-        std::vector<Subfile *> subfiles_;
+        std::vector<std::shared_ptr<SubDirectory>> subdirs_;
+        std::vector<std::shared_ptr<Subfile>> subfiles_;
     };
 }
 };

+ 54 - 55
src/SubDirectory.cpp

@@ -17,40 +17,26 @@
 #include "Subfiles/UnknownSubfile.h"
 
 namespace LOTRO_DAT {
-    std::set<long long> SubDirectory::visited_subdirectories_ = std::set<long long>();
+    std::unordered_set<long long> SubDirectory::visited_subdirectories_ = std::unordered_set<long long>();
+    std::unordered_set<long long> SubDirectory::visited_subfiles_ = std::unordered_set<long long>();
+    std::set<std::shared_ptr<SubDirectory>, SubDirectory::SubDirectoryOffsetComp> SubDirectory::subdir_init_queue_
+           = std::set<std::shared_ptr<SubDirectory>, SubDirectory::SubDirectoryOffsetComp>();
+    std::set<std::shared_ptr<SubDirectory>, SubDirectory::SubDirectoryOffsetComp> SubDirectory::subfile_init_queue_
+            = std::set<std::shared_ptr<SubDirectory>, SubDirectory::SubDirectoryOffsetComp>();
 
-    SubDirectory::SubDirectory() {
-        offset_ = 0;
-    }
 
     SubDirectory::~SubDirectory() {
         subfiles_.clear();
         subdirs_.clear();
     }
 
-    SubDirectory::SubDirectory(long long offset, DatFile *dat, long long max_subdirs) :
+    SubDirectory::SubDirectory(long long offset, DatFile &dat, long long max_subdirs) :
             dat_(dat), offset_(offset), max_subdirs_(max_subdirs) {
-        LOG(DEBUG) << "Initialising " << offset_ << " SubDirectory";
-        LOG(DEBUG) << "Processing SubDirectories";
-
-        if (!MakeSubDirectories()) {
-            subfiles_.clear();
-            subdirs_.clear();
-            return;
-        }
-
-        LOG(DEBUG) << "Processing SubFiles";
-        if (!MakeSubFiles()) {
-            subfiles_.clear();
-            subdirs_.clear();
-            return;
-        }
-        LOG(DEBUG) << "SubDirectory " << offset_ << " initialized successfully";
     }
 
     bool SubDirectory::MakeSubDirectories() {
         BinaryData data(1024);
-        dat_->ReadData(data, 63 * 8, offset_);
+        dat_.ReadData(data, 63 * 8, offset_);
 
         if (data.Empty()) {
             LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
@@ -74,18 +60,20 @@ namespace LOTRO_DAT {
 
             SubDirectory *subdir = new SubDirectory(data.ToNumber<4>(i + 4), dat_);
 
-            if (subdir->subfiles_.empty() && subdir->subdirs_.empty()) {
-                LOG(WARNING) << "Sub-subdirectory is empty or made empty... Dictionary offset = " << offset_ + i << "; Passing others";
-                break;
-            } else
+            //if (subdir->subfiles_.empty() && subdir->subdirs_.empty()) {
+            //    LOG(WARNING) << "Sub-subdirectory is empty or made empty... Dictionary offset = " << offset_ + i << "; Passing others";
+            //    break;
+            //} else {
                 subdirs_.push_back(subdir);
+                subdir_init_queue_.insert(subdir);
+            //}
         }
         return true;
     }
 
     bool SubDirectory::MakeSubFiles() {
         BinaryData data = BinaryData(4);
-        dat_->ReadData(data, 4, offset_ + 63 * 8);
+        dat_.ReadData(data, 4, offset_ + 63 * 8);
 
         if (data.Empty()) {
             LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
@@ -98,9 +86,12 @@ namespace LOTRO_DAT {
             return false;
         }
 
+        subfiles_.resize(unsigned(subfiles_number), nullptr);
+        BinaryData headers(32 * unsigned(subfiles_number));
+        dat_.ReadData(headers, 32 * subfiles_number, offset_ + 63 * 8 + 4);
+
         for (int i = 0; i < subfiles_number; i++) {
-            BinaryData header(32);
-            dat_->ReadData(header, 32, offset_ + 63 * 8 + 4 + 32 * i);
+            BinaryData header = headers.CutData(32 * i, 32 * (i + 1));
 
             if (header.Empty()) {
                 LOG(ERROR) << "(READ ERROR) Incorrect directory (unable to read subfile data) at offset " << offset_;
@@ -110,7 +101,12 @@ namespace LOTRO_DAT {
             if (header.ToNumber<4>(20) == 0 || header.ToNumber<4>(28) != 0)
                 continue;
 
-            Subfile *subfile = MakeSubfile(
+            if (visited_subfiles_.count(header.ToNumber<4>(4))) {
+                LOG(ERROR) << "Found duplicate file with id " << header.ToNumber<4>(4);
+                break;
+            }
+
+            subfiles_[i] = MakeSubfile(
                     offset_ + 63 * 8 + 4 + 32 * i,
                     header.ToNumber<4>(0), // unknown1
                     header.ToNumber<4>(4), // file_id
@@ -122,32 +118,35 @@ namespace LOTRO_DAT {
                     header.ToNumber<4>(28) // unknown2 - must be zero??
             );
 
-//            if (dat_->CorrectSubfile(subfile)) {
-                subfiles_.emplace_back(subfile);
-//            } else {
-//                LOG(WARNING) << "Incorrect Subfile in directory at offset " << offset_ + 63 * 8 + 4 + 32 * i << " (id = " << subfile->file_id() << ");";
-//                break;
-//            }
+            if (dat_.CorrectSubfile(subfiles_[i])) {
+                visited_subfiles_.insert(subfiles_[i]->file_id());
+            } else {
+                LOG(WARNING) << "Incorrect Subfile in directory at offset " << offset_ + 63 * 8 + 4 + 32 * i << " (id = " << subfiles_[i]->file_id() << ");";
+                delete subfiles_[i];
+                subfiles_[i] = nullptr;
+                break;
+            }
         }
         return true;
     }
 
-    void SubDirectory::MakeDictionary(std::map<long long, Subfile *> &dict) {
-        for (Subfile *i : subfiles_) {
-            if (dict.count(i->file_id() != 0)) {
-                LOG(WARNING) << "Found multiple instances of file " << i->file_id() << " at dictionary offset "
-                             << i->dictionary_offset() << ". Base offset = " << dict[i->file_id()]->dictionary_offset();
-                if (!dat_->CorrectSubfile(i) || dat_->CorrectSubfile(dict[i->file_id_]))
+    void SubDirectory::MakeDictionary(std::map<long long, std::shared_ptr<Subfile> > &dict) {
+        for (const std::shared_ptr<Subfile> &file: subfiles_) {
+            if (dict.count(file->file_id() != 0)) {
+                LOG(WARNING) << "Found multiple instances of file " << file->file_id() << " at dictionary offset "
+                             << file->dictionary_offset() << ". Base offset = " << dict[file->file_id()]->dictionary_offset();
+                if (!dat_.CorrectSubfile(file) || dat_.CorrectSubfile(dict[file->file_id_]))
                     continue;
             }
-            dict[i->file_id()] = i;
+            dict[file->file_id()] = file;
         }
 
-        for (SubDirectory *i : subdirs_)
-            i->MakeDictionary(dict);
+        for (const auto &dir : subdirs_) {
+            dir->MakeDictionary(dict);
+        }
     }
 
-    Subfile *SubDirectory::MakeSubfile(long long dictionary_offset, long long unknown1, long long file_id,
+    std::shared_ptr<Subfile> SubDirectory::MakeSubfile(long long dictionary_offset, long long unknown1, long long file_id,
                                        long long file_offset, long long file_size, long long timestamp,
                                        long long version, long long block_size, long long unknown2) {
 
@@ -155,22 +154,22 @@ namespace LOTRO_DAT {
 
         switch (type) {
             case TEXT:
-                return dynamic_cast<Subfile *>(new TextSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+                return std::dynamic_pointer_cast<Subfile>(std::make_shared<TextSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
             case JPG:
-                return dynamic_cast<Subfile *>(new JpgSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+                return std::dynamic_pointer_cast<Subfile>(std::make_shared<JpgSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
             case DDS:
-                return dynamic_cast<Subfile *>(new DdsSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+                return std::dynamic_pointer_cast<Subfile>(std::make_shared<DdsSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
             case WAV:
-                return dynamic_cast<Subfile *>(new WavSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+                return std::dynamic_pointer_cast<Subfile>(std::make_shared<WavSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
             case OGG:
-                return dynamic_cast<Subfile *>(new OggSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+                return std::dynamic_pointer_cast<Subfile>(std::make_shared<OggSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
             case FONT:
-                return dynamic_cast<Subfile *>(new FontSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+                return std::dynamic_pointer_cast<Subfile>(std::make_shared<FontSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
             case UNKNOWN:
-                return dynamic_cast<Subfile *>(new UnknownSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+                return std::dynamic_pointer_cast<Subfile>(std::make_shared<UnknownSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
         }
         LOG(ERROR) << "Incorrect file type..";
-        return dynamic_cast<Subfile *>(new UnknownSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
+        return std::dynamic_pointer_cast<Subfile>(std::make_shared<UnknownSubfile>(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
     }
 
     FILE_TYPE SubDirectory::GetSubfileType(long long file_id, long long file_offset) const {
@@ -183,7 +182,7 @@ namespace LOTRO_DAT {
             return FONT;
 
         BinaryData header(64);
-        dat_->ReadData(header, 64, (unsigned) file_offset + 8);
+        dat_.ReadData(header, 64, (unsigned) file_offset + 8);
 
         if (header.Empty()) {
             LOG(ERROR) << "Unable to read file header. file_id = " << file_id << ", offset = " << offset_;