FIFE  be64c707dea6b3250bd4355bf5c825d25920087d
dat2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2019 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // 3rd party library includes
25 
26 // FIFE includes
27 // These includes are split up in two parts, separated by one empty line
28 // First block: files included from the FIFE root src directory
29 // Second block: files included from the same folder
30 #include "vfs/raw/rawdata.h"
31 #include "util/base/exception.h"
32 #include "util/log/logger.h"
33 
34 #include "dat2.h"
35 
36 namespace FIFE {
40  static Logger _log(LM_FO_LOADERS);
41 
42  DAT2::DAT2(VFS* vfs, const std::string& file)
43  : VFSSource(vfs), m_datpath(file), m_data(vfs->open(file)), m_filelist() {
44 
45  FL_LOG(_log, LMsg("MFFalloutDAT2")
46  << "loading: " << file
47  << " filesize: " << m_data->getDataLength());
48 
49  m_data->setIndex(m_data->getDataLength() - 8);
50  uint32_t fileListLength = m_data->read32Little();
51  uint32_t archiveSize = m_data->read32Little();
52 
53  FL_LOG(_log, LMsg("MFFalloutDAT2")
54  << "FileListLength: " << fileListLength
55  << " ArchiveSize: " << archiveSize);
56 
57  if (archiveSize != m_data->getDataLength())
58  throw InvalidFormat("size mismatch");
59 
60  m_data->setIndex( archiveSize - fileListLength - 8);
61  m_filecount = m_data->read32Little();
62  m_currentIndex = m_data->getCurrentIndex();
63 
64  FL_LOG(_log, LMsg("MFFalloutDAT2 FileCount: ") << m_filecount);
65 
66  // Do not read the complete file list at startup.
67  // Instead read a chunk each frame.
69  m_timer.setCallback(std::bind( &DAT2::readFileEntry, this) );
70  m_timer.start();
71  }
72 
73  void DAT2::readFileEntry() const {
74  assert( m_filecount != 0);
75 
76  // Load more items per call,
77  // otherwise it takes _ages_ until everything is in.
78  uint32_t load_per_cycle = 50;
79  if( load_per_cycle > m_filecount )
80  load_per_cycle = m_filecount;
81  m_filecount -= load_per_cycle;
82 
83  // Save the old index in an exception save way.
84  IndexSaver isaver(m_data.get());
85 
86  // Move index to file list and read the entries.
87  m_data->setIndex(m_currentIndex);
89  while( load_per_cycle-- ) {
90  uint32_t namelen = m_data->read32Little();
91  info.name = fixPath(m_data->readString(namelen));
92 
93  info.type = m_data->read8();
94  info.unpackedLength = m_data->read32Little();
95  info.packedLength = m_data->read32Little();
96  info.offset = m_data->read32Little();
97 
98  m_filelist.insert(std::make_pair(info.name, info));
99  }
100  m_currentIndex = m_data->getCurrentIndex();
101 
102  // Finally log on completion and stop the timer.
103  if( m_filecount == 0 ) {
104  FL_LOG(_log, LMsg("MFFalloutDAT2, All file entries in '") << m_datpath << "' loaded.");
105  m_timer.stop();
106  }
107  }
108 
109  RawData* DAT2::open(const std::string& file) const {
110  const RawDataDAT2::s_info& info = getInfo(file);
111  return new RawData(new RawDataDAT2(getVFS(), m_datpath, info));
112  }
113 
114  bool DAT2::fileExists(const std::string& name) const {
115  return findFileEntry(name) != m_filelist.end();
116  }
117 
118  const RawDataDAT2::s_info& DAT2::getInfo(const std::string& name) const {
119  type_filelist::const_iterator i = findFileEntry(name);
120  if (i == m_filelist.end()) {
121  throw NotFound(name);
122  }
123  return i->second;
124  }
125 
126  DAT2::type_filelist::const_iterator DAT2::findFileEntry(const std::string& path) const {
127 
128  // Either the normalization is bogus, or we have to do
129  // it here, too. Otherwise we can't load the files returned
130  // by listFiles.
131 
132  std::string name = path;
133 
134  // Normalize the path
135  if (name.find("./") == 0) {
136  name.erase(0, 2);
137  }
138 
139  type_filelist::const_iterator i = m_filelist.find(name);
140 
141  // We might have another chance to find the file
142  // if the number of file entries not zero.
143  if ( m_filecount && i == m_filelist.end()) {
144  FL_LOG(_log, LMsg("MFFalloutDAT2")
145  << "Missing '" << name
146  << "' in partially(" << m_filecount <<") loaded "<< m_datpath);
147  while( m_filecount && i == m_filelist.end()) {
148  readFileEntry();
149  i = m_filelist.find(name);
150  }
151  }
152  return i;
153  }
154 
155 
156  std::set<std::string> DAT2::listFiles(const std::string& pathstr) const {
157  return list(pathstr, false);
158  }
159 
160  std::set<std::string> DAT2::listDirectories(const std::string& pathstr) const {
161  return list(pathstr, true);
162  }
163 
164  std::set<std::string> DAT2::list(const std::string& pathstr, bool dirs) const {
165  std::set<std::string> list;
166  std::string path = pathstr;
167 
168  // Force loading the complete file entries
169  // This is a costly operation... right after startup.
170  // Later this should do nothing.
171  while( m_filecount ) {
172  readFileEntry();
173  }
174 
175  // Normalize the path
176  if (path.find("./") == 0) {
177  path.erase(0, 2);
178  }
179 
180  size_t lastIndex = path.size();
181  if (lastIndex != 0 && path[lastIndex-1] != '/') {
182  path += '/';
183  }
184 
185  type_filelist::const_iterator end = m_filelist.end();
186  for (type_filelist::const_iterator i = m_filelist.begin(); i != end; ++i) {
187  const std::string& file = i->first;
188  if (file.find(path) == 0) {
189  std::string cleanedfile = file.substr(path.size(), file.size()); // strip the pathstr
190  bool isdir = cleanedfile.find('/') != std::string::npos; // if we still have a / it's a subdir
191 
192  if (isdir) {
193  cleanedfile = cleanedfile.substr(0, cleanedfile.find('/'));
194  if (cleanedfile.find('/') != cleanedfile.rfind('/')) {
195  // check if this is a direct subdir
196  continue;
197  }
198  }
199 
200  if (isdir == dirs) {
201  list.insert(cleanedfile);
202  }
203  }
204  }
205 
206  return list;
207  }
208 } // FIFE
uint32_t m_filecount
number of file entries to read
Definition: dat2.h:88
std::set< std::string > listFiles(const std::string &pathstr) const
list all files in a directory of this source
Definition: dat2.cpp:156
The needed information for the extraction.
Definition: rawdatadat2.h:51
Timer m_timer
lazy loading timer
Definition: dat2.h:92
Helper class to create log strings out from separate parts Usage: LMsg("some text") << variable << "...
Definition: logger.h:82
const RawDataDAT2::s_info & getInfo(const std::string &name) const
Get Information needed to unpack and extract data.
Definition: dat2.cpp:118
VFSSource abstract baseclass.
Definition: vfssource.h:46
static Logger _log(LM_AUDIO)
void readFileEntry() const
read a bunch of file entries
Definition: dat2.cpp:73
void setInterval(int32_t msec)
Set the interval in milliseconds.
Definition: timer.cpp:60
std::set< std::string > listDirectories(const std::string &pathstr) const
list all directories in a directory of this source
Definition: dat2.cpp:160
void start()
Start the timer.
Definition: timer.cpp:45
std::set< std::string > list(const std::string &pathstr, bool dirs) const
Definition: dat2.cpp:164
VFS * getVFS() const
get the VFS this source is associated with.
Definition: vfssource.h:60
type_filelist::const_iterator findFileEntry(const std::string &name) const
find a file entry
Definition: dat2.cpp:126
A subclass of RawDataMemSource, that fills itself with a FALLOUT1 .DAT file entry.
Definition: rawdatadat2.h:46
bool fileExists(const std::string &name) const
check if the given file exists
Definition: dat2.cpp:114
RawData * open(const std::string &file) const
open a file inside this source
Definition: dat2.cpp:109
std::unique_ptr< RawData > m_data
Definition: dat2.h:83
uint32_t m_currentIndex
current index in file
Definition: dat2.h:90
#define FL_LOG(logger, msg)
Definition: logger.h:71
void stop()
Stop the timer.
Definition: timer.cpp:53
the main VFS (virtual file system) class
Definition: vfs.h:58
unsigned int uint32_t
Definition: core.h:40
std::string fixPath(std::string path) const
Definition: vfssource.cpp:45
DAT2(VFS *vfs, const std::string &path)
Constructor Create a VFSSource for a Fallout2 DAT file.
Definition: dat2.cpp:42
void setCallback(const type_callback &callback)
Set the callback that will be called.
Definition: timer.cpp:64
type_filelist m_filelist
Definition: dat2.h:85
std::string m_datpath
Definition: dat2.h:82
Used to access diffrent kinds of data.
Definition: rawdata.h:48