Panda3D
bamCacheRecord.cxx
1 // Filename: bamCacheRecord.cxx
2 // Created by: drose (09Jun06)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "bamCacheRecord.h"
16 #include "bamReader.h"
17 #include "bamWriter.h"
18 #include "virtualFileSystem.h"
19 #include "virtualFile.h"
20 #include "indent.h"
21 #include "config_util.h" // util_cat
22 
23 TypeHandle BamCacheRecord::_type_handle;
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: BamCacheRecord::Default Constructor
27 // Access: Private
28 // Description: Used when reading from a bam file.
29 ////////////////////////////////////////////////////////////////////
30 BamCacheRecord::
31 BamCacheRecord() :
32  _recorded_time(0),
33  _record_size(0),
34  _source_timestamp(0),
35  _ptr(NULL),
36  _ref_ptr(NULL),
37  _record_access_time(0)
38 {
39 }
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: BamCacheRecord::Constructor
43 // Access: Private
44 // Description: Use BamCache::lookup() to create one of these.
45 ////////////////////////////////////////////////////////////////////
46 BamCacheRecord::
47 BamCacheRecord(const Filename &source_pathname,
48  const Filename &cache_filename) :
49  _source_pathname(source_pathname),
50  _cache_filename(cache_filename),
51  _recorded_time(0),
52  _record_size(0),
53  _source_timestamp(0),
54  _ptr(NULL),
55  _ref_ptr(NULL),
56  _record_access_time(0)
57 {
58 }
59 
60 ////////////////////////////////////////////////////////////////////
61 // Function: BamCacheRecord::Copy Constructor
62 // Access: Private
63 // Description: Use make_copy() to make a copy. The copy does not
64 // share the data pointer.
65 ////////////////////////////////////////////////////////////////////
66 BamCacheRecord::
67 BamCacheRecord(const BamCacheRecord &copy) :
68  _source_pathname(copy._source_pathname),
69  _cache_filename(copy._cache_filename),
70  _recorded_time(copy._recorded_time),
71  _record_size(copy._record_size),
72  _source_timestamp(copy._source_timestamp),
73  _ptr(NULL),
74  _ref_ptr(NULL),
75  _record_access_time(copy._record_access_time)
76 {
77 }
78 
79 ////////////////////////////////////////////////////////////////////
80 // Function: BamCacheRecord::Destructor
81 // Access: Published, Virtual
82 // Description:
83 ////////////////////////////////////////////////////////////////////
84 BamCacheRecord::
85 ~BamCacheRecord() {
86  clear_data();
87 }
88 
89 ////////////////////////////////////////////////////////////////////
90 // Function: BamCacheRecord::dependents_unchanged
91 // Access: Published
92 // Description: Returns true if all of the dependent files are still
93 // the same as when the cache was recorded, false
94 // otherwise.
95 ////////////////////////////////////////////////////////////////////
99 
100  if (util_cat.is_debug()) {
101  util_cat.debug()
102  << "Validating dependents for " << get_source_pathname() << "\n";
103  }
104 
105  DependentFiles::const_iterator fi;
106  for (fi = _files.begin(); fi != _files.end(); ++fi) {
107  const DependentFile &dfile = (*fi);
108  PT(VirtualFile) file = vfs->get_file(dfile._pathname);
109  if (file == (VirtualFile *)NULL) {
110  // No such file.
111  if (dfile._timestamp != 0) {
112  if (util_cat.is_debug()) {
113  util_cat.debug()
114  << dfile._pathname << " does not exist.\n";
115  }
116  return false;
117  }
118  } else {
119  if (file->get_timestamp() != dfile._timestamp ||
120  file->get_file_size() != dfile._size) {
121  // File has changed timestamp or size.
122  if (util_cat.is_debug()) {
123  util_cat.debug()
124  << dfile._pathname << " has changed timestamp or size.\n";
125  }
126  return false;
127  }
128  }
129 
130  // Presumably, the file is unchanged.
131  if (util_cat.is_debug()) {
132  util_cat.debug()
133  << dfile._pathname << " is unchanged.\n";
134  }
135  }
136 
137  if (util_cat.is_debug()) {
138  util_cat.debug()
139  << "Dependents valid.\n";
140  }
141 
142  return true;
143 }
144 
145 
146 ////////////////////////////////////////////////////////////////////
147 // Function: BamCacheRecord::clear_dependent_files
148 // Access: Published
149 // Description: Empties the list of files that contribute to the data
150 // in this record.
151 ////////////////////////////////////////////////////////////////////
152 void BamCacheRecord::
154  _files.clear();
155 }
156 
157 ////////////////////////////////////////////////////////////////////
158 // Function: BamCacheRecord::add_dependent_file
159 // Access: Published
160 // Description: Adds the indicated file to the list of files that
161 // will be loaded to generate the data in this record.
162 // This should be called once for the primary source
163 // file, and again for each secondary source file, if
164 // any.
165 ////////////////////////////////////////////////////////////////////
166 void BamCacheRecord::
167 add_dependent_file(const Filename &pathname) {
169 
170  _files.push_back(DependentFile());
171  DependentFile &dfile = _files.back();
172  dfile._pathname = pathname;
173  dfile._pathname.make_absolute();
174 
175  PT(VirtualFile) file = vfs->get_file(dfile._pathname);
176  if (file == (VirtualFile *)NULL) {
177  // No such file.
178  dfile._timestamp = 0;
179  dfile._size = 0;
180 
181  } else {
182  dfile._timestamp = file->get_timestamp();
183  dfile._size = file->get_file_size();
184 
185  if (dfile._pathname == _source_pathname) {
186  _source_timestamp = dfile._timestamp;
187  }
188  }
189 }
190 
191 ////////////////////////////////////////////////////////////////////
192 // Function: BamCacheRecord::output
193 // Access: Published
194 // Description:
195 ////////////////////////////////////////////////////////////////////
196 void BamCacheRecord::
197 output(ostream &out) const {
198  out << "BamCacheRecord " << get_source_pathname();
199 }
200 
201 ////////////////////////////////////////////////////////////////////
202 // Function: BamCacheRecord::write
203 // Access: Published
204 // Description:
205 ////////////////////////////////////////////////////////////////////
206 void BamCacheRecord::
207 write(ostream &out, int indent_level) const {
208  indent(out, indent_level)
209  << "BamCacheRecord " << get_source_pathname() << "\n";
210  indent(out, indent_level)
211  << "source " << format_timestamp(_source_timestamp) << "\n";
212  indent(out, indent_level)
213  << "recorded " << format_timestamp(_recorded_time) << "\n";
214 
215  indent(out, indent_level)
216  << _files.size() << " dependent files.\n";
217  DependentFiles::const_iterator fi;
218  for (fi = _files.begin(); fi != _files.end(); ++fi) {
219  const DependentFile &dfile = (*fi);
220  indent(out, indent_level + 2)
221  << setw(10) << dfile._size << " "
222  << format_timestamp(dfile._timestamp) << " "
223  << dfile._pathname << "\n";
224  }
225 }
226 
227 ////////////////////////////////////////////////////////////////////
228 // Function: BamCacheRecord::format_timestamp
229 // Access: Private, Static
230 // Description: Returns a timestamp value formatted nicely for
231 // output.
232 ////////////////////////////////////////////////////////////////////
233 string BamCacheRecord::
234 format_timestamp(time_t timestamp) {
235  static const size_t buffer_size = 512;
236  char buffer[buffer_size];
237 
238  if (timestamp == 0) {
239  // A zero timestamp is a special case.
240  return " (no date) ";
241  }
242 
243  time_t now = time(NULL);
244  struct tm *tm_p = localtime(&timestamp);
245 
246  if (timestamp > now || (now - timestamp > 86400 * 365)) {
247  // A timestamp in the future, or more than a year in the past,
248  // gets a year appended.
249  strftime(buffer, buffer_size, "%b %d %Y", tm_p);
250  } else {
251  // Otherwise, within the past year, show the date and time.
252  strftime(buffer, buffer_size, "%b %d %H:%M", tm_p);
253  }
254 
255  return buffer;
256 }
257 
258 ////////////////////////////////////////////////////////////////////
259 // Function: BamCacheRecord::register_with_read_factory
260 // Access: Published, Static
261 // Description: Tells the BamReader how to create objects of type
262 // BamCacheRecord.
263 ////////////////////////////////////////////////////////////////////
264 void BamCacheRecord::
266  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
267 }
268 
269 ////////////////////////////////////////////////////////////////////
270 // Function: BamCacheRecord::write_datagram
271 // Access: Published, Virtual
272 // Description: Writes the contents of this object to the datagram
273 // for shipping out to a Bam file.
274 ////////////////////////////////////////////////////////////////////
275 void BamCacheRecord::
278  dg.add_string(_source_pathname);
279  dg.add_string(_cache_filename);
280  dg.add_uint32(_recorded_time);
281  dg.add_uint64(_record_size);
282 
283  dg.add_uint16(_files.size());
284  DependentFiles::const_iterator fi;
285  for (fi = _files.begin(); fi != _files.end(); ++fi) {
286  const DependentFile &file = (*fi);
287  dg.add_string(file._pathname);
288  dg.add_uint32(file._timestamp);
289  dg.add_uint64(file._size);
290  }
291 }
292 
293 ////////////////////////////////////////////////////////////////////
294 // Function: BamCacheRecord::make_from_bam
295 // Access: Protected, Static
296 // Description: This function is called by the BamReader's factory
297 // when a new object of type BamCacheRecord is encountered
298 // in the Bam file. It should create the BamCacheRecord
299 // and extract its information from the file.
300 ////////////////////////////////////////////////////////////////////
301 TypedWritable *BamCacheRecord::
302 make_from_bam(const FactoryParams &params) {
303  BamCacheRecord *object = new BamCacheRecord;
304  DatagramIterator scan;
305  BamReader *manager;
306 
307  parse_params(params, scan, manager);
308  object->fillin(scan, manager);
309 
310  return object;
311 }
312 
313 ////////////////////////////////////////////////////////////////////
314 // Function: BamCacheRecord::fillin
315 // Access: Protected
316 // Description: This internal function is called by make_from_bam to
317 // read in all of the relevant data from the BamFile for
318 // the new BamCacheRecord.
319 ////////////////////////////////////////////////////////////////////
320 void BamCacheRecord::
321 fillin(DatagramIterator &scan, BamReader *manager) {
323 
324  _source_pathname = scan.get_string();
325  _cache_filename = scan.get_string();
326  _recorded_time = scan.get_uint32();
327  _record_size = scan.get_uint64();
328 
329  unsigned int num_files = scan.get_uint16();
330  _files.reserve(num_files);
331  for (unsigned int i = 0; i < num_files; ++i) {
332  _files.push_back(DependentFile());
333  DependentFile &file = _files.back();
334  file._pathname = scan.get_string();
335  file._timestamp = scan.get_uint32();
336  file._size = scan.get_uint64();
337 
338  // If we come across the original source file (we normally expect
339  // to), record that as its timestamp.
340  if (file._pathname == _source_pathname) {
341  _source_timestamp = file._timestamp;
342  }
343  }
344 }
void add_string(const string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:351
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
PN_uint32 get_uint32()
Extracts an unsigned 32-bit integer.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:37
string get_string()
Extracts a variable-length string.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class&#39;s make_from_bam() method to read in all...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
void add_uint64(PN_uint64 value)
Adds an unsigned 64-bit integer to the datagram.
Definition: datagram.I:203
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static void register_with_read_factory()
Tells the BamReader how to create objects of type BamCacheRecord.
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname)...
Definition: filename.cxx:1019
void clear_dependent_files()
Empties the list of files that contribute to the data in this record.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:192
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record...
A class to retrieve the individual data elements previously stored in a Datagram. ...
bool dependents_unchanged() const
Returns true if all of the dependent files are still the same as when the cache was recorded...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
PN_uint64 get_uint64()
Extracts an unsigned 64-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43