CMS 3D CMS Logo

BinaryArchiveBase.cc
Go to the documentation of this file.
1 #include <cerrno>
2 #include <cctype>
3 #include <cstdlib>
4 #include <cstring>
5 #include <climits>
6 #include <cassert>
7 
8 #include "Alignment/Geners/interface/BinaryArchiveBase.hh"
9 #include "Alignment/Geners/interface/CatalogIO.hh"
10 #include "Alignment/Geners/interface/binaryIO.hh"
11 
12 #ifdef GENERS_BINARY_ARCHIVE_FORMAT_ID
13 #undef GENERS_BINARY_ARCHIVE_FORMAT_ID
14 #endif
15 #define GENERS_BINARY_ARCHIVE_FORMAT_ID (0x1f2e3d4c)
16 
17 static bool parse_unsigned(std::ostringstream& err,
18  const char *c, unsigned *result)
19 {
20  char *endptr;
21  errno = 0;
22  const unsigned long value = strtoul(c, &endptr, 0);
23  if (errno || *endptr != '\0')
24  {
25  err << "expected an unsigned integer, got \"" << c << '"';
26  if (errno) err << ", " << strerror(errno);
27  return false;
28  }
29  if (value > UINT_MAX)
30  {
31  err << "unsigned value \"" << c << "\" is out of range";
32  return false;
33  }
34  *result = value;
35  return true;
36 }
37 
38 static bool parse_int(std::ostringstream& err,
39  const char *c, int *result)
40 {
41  char *endptr;
42  errno = 0;
43  const long value = strtol(c, &endptr, 0);
44  if (errno || *endptr != '\0')
45  {
46  err << "expected an integer, got \"" << c << '"';
47  if (errno) err << ", " << strerror(errno);
48  return false;
49  }
50  if (value < INT_MIN || value > INT_MAX)
51  {
52  err << "integer value \"" << c << "\" is out of range";
53  return false;
54  }
55  *result = value;
56  return true;
57 }
58 
59 namespace gs {
60  BinaryArchiveBase::BinaryArchiveBase(const char* name, const char* mode)
61  : AbsArchive(name),
62  mode_(parseMode(mode)),
63  errorStream_(nullptr),
64  cStream_(nullptr),
65  catalog_(nullptr),
66  storedEntryId_(nullptr),
67  storedLocationId_(nullptr),
68  catalogIsSet_(false),
69  addCatalogToData_(false)
70  {
71  CStringStream::CompressionMode m = CStringStream::NOT_COMPRESSED;
72  int compressionLevel = -1;
73  unsigned minSizeToCompress = 1024U;
74  unsigned bufSize = 1048576U; // 1024*1024
75 
76  std::ostringstream err;
77  modeIsValid_ = parseArchiveOptions(err, mode, &m, &compressionLevel,
78  &minSizeToCompress, &bufSize,
79  &addCatalogToData_);
80  if (modeIsValid_)
81  cStream_ = new CStringStream(m, compressionLevel,
82  minSizeToCompress, bufSize);
83  else
84  {
85  errorStream() << "In BinaryArchiveBase constructor: "
86  << "invalid archive opening mode \"" << mode << '"';
87  const std::string& errInfo = err.str();
88  if (!errInfo.empty())
89  errorStream() << ": " << errInfo;
90  }
91  }
92 
93 
94  void BinaryArchiveBase::releaseClassIds()
95  {
96  delete storedEntryId_; storedEntryId_ = nullptr;
97  delete storedLocationId_; storedLocationId_ = nullptr;
98  }
99 
100 
101  BinaryArchiveBase::~BinaryArchiveBase()
102  {
103  releaseClassIds();
104  delete errorStream_;
105  delete catalog_;
106  delete cStream_;
107  }
108 
109 
110  void BinaryArchiveBase::writeHeader(std::ostream& os)
111  {
112  const unsigned format = GENERS_BINARY_ARCHIVE_FORMAT_ID;
113  write_pod(os, format);
114 
115  // Write some other info
116  const unsigned multiplex = addCatalogToData_ ? 1 : 0;
117  const unsigned sizeoflong = sizeof(long);
118  const unsigned infoword = (sizeoflong << 1) | multiplex;
119  write_pod(os, infoword);
120 
121  if (multiplex)
122  {
123  // Write class ids for CatalogEntry and ItemLocation
124  releaseClassIds();
125  storedEntryId_ = new ClassId(ClassId::makeId<CatalogEntry>());
126  storedEntryId_->write(os);
127  storedLocationId_ = new ClassId(ClassId::makeId<ItemLocation>());
128  storedLocationId_->write(os);
129  }
130  }
131 
132 
133  bool BinaryArchiveBase::readHeader(std::istream& is)
134  {
135  const unsigned expectedFormat = GENERS_BINARY_ARCHIVE_FORMAT_ID;
136  is.seekg(0, std::ios_base::beg);
137  unsigned format = 0;
138  read_pod(is, &format);
139  if (format != expectedFormat)
140  return false;
141 
142  unsigned infoword = 0xffffffff;
143  read_pod(is, &infoword);
144  const unsigned multiplex = infoword & 0x1U;
145  const unsigned sizeoflong = infoword >> 1;
146 
147  // The following check will make sure that we are not reading
148  // an archive created on a 32-bit machine with a 64-bit system
149  // (and otherwise)
150  if (sizeoflong != sizeof(long))
151  return false;
152 
153  addCatalogToData_ = multiplex;
154  if (addCatalogToData_)
155  {
156  releaseClassIds();
157  storedEntryId_ = new ClassId(is, 1);
158  storedLocationId_ = new ClassId(is, 1);
159 
160  // Can't open this archive for update if the above class ids
161  // are obsolete -- otherwise we will loose the capability to
162  // restore the catalog
163  if (mode_ & std::ios_base::out)
164  {
165  const ClassId& entryId = ClassId::makeId<CatalogEntry>();
166  const ClassId& locId = ClassId::makeId<ItemLocation>();
167  if (entryId != *storedEntryId_ || locId != *storedLocationId_)
168  throw IOInvalidData(
169  "In gs::BinaryArchiveBase::readHeader: this "
170  "archive can no longer be open for update as it was "
171  "created using an older version of I/O software");
172  }
173  }
174  return !is.fail();
175  }
176 
177 
178  void BinaryArchiveBase::openDataFile(std::fstream& stream,
179  const char* filename)
180  {
181  assert(filename);
182  if (stream.is_open())
183  stream.close();
184  stream.clear();
185  stream.open(filename, mode_);
186  if (!stream.is_open())
187  throw IOOpeningFailure("gs::BinaryArchiveBase::openDataFile",
188  filename);
189 
190  // Do we need to write the header out or to read it in?
191  bool writeHead = false;
192  if (mode_ & std::ios_base::out)
193  {
194  if (mode_ & std::ios_base::trunc)
195  writeHead = true;
196  else if (isEmptyFile(stream))
197  writeHead = true;
198  }
199 
200  if (writeHead)
201  {
202  writeHeader(stream);
203  if (stream.fail())
204  {
205  stream.close();
206  std::string e = "In gs::BinaryArchiveBase::openDataFile: "
207  "failed to write archive header to file \"";
208  e += filename;
209  e += "\"";
210  throw IOWriteFailure(e);
211  }
212  }
213  else
214  {
215  if (!readHeader(stream))
216  {
217  const bool failed = stream.fail();
218  stream.close();
219  std::string e = "In gs::BinaryArchiveBase::openDataFile: ";
220  if (failed)
221  {
222  e += "could not read archive header from file \"";
223  e += filename;
224  e += "\"";
225  throw IOReadFailure(e);
226  }
227  else
228  {
229  e += "no valid archive header in file \"";
230  e += filename;
231  e += "\"";
232  throw IOInvalidData(e);
233  }
234  }
235  }
236  }
237 
238 
239  void BinaryArchiveBase::setCatalog(AbsCatalog* c)
240  {
241  if (c)
242  {
243  assert(!catalogIsSet_);
244  catalogIsSet_ = true;
245  }
246  delete catalog_;
247  catalog_ = c;
248  }
249 
250 
251  void BinaryArchiveBase::itemSearch(
252  const SearchSpecifier& namePattern,
253  const SearchSpecifier& categoryPattern,
254  std::vector<unsigned long long>* idsFound) const
255  {
256  if (catalog_)
257  catalog_->search(namePattern, categoryPattern, idsFound);
258  else
259  {
260  assert(idsFound);
261  idsFound->clear();
262  }
263  }
264 
265 
266  bool BinaryArchiveBase::parseArchiveOptions(
267  std::ostringstream& err,
268  const char* modeIn, CStringStream::CompressionMode* m,
269  int* compressionLevel, unsigned* minSizeToCompress,
270  unsigned* bufSize, bool* multiplexCatalog)
271  {
272  if (!modeIn)
273  return true;
274  std::string cmode(modeIn ? modeIn : "");
275  if (cmode.empty())
276  return true;
277  char* mode = const_cast<char*>(cmode.c_str());
278 
279  unsigned cnt = 0;
280  for (char* opt = strtok(mode, ":"); opt; opt = strtok(nullptr, ":"), ++cnt)
281  {
282  // Skip the first word -- this is the file opening mode
283  if (!cnt)
284  continue;
285  char* eq = strchr(opt, '=');
286  if (eq)
287  {
288  // Get rid of spaces around option name
289  char* optname = opt;
290  while (isspace(*optname) && optname < eq)
291  ++optname;
292  if (optname == eq)
293  {
294  err << "invalid binary archive option \"\"";
295  return false;
296  }
297  char* optend = eq - 1;
298  while (isspace(*optend))
299  --optend;
300  ++optend;
301  *optend = '\0';
302 
303  // Get rid of spaces around option value
304  char* optval = eq + 1;
305  while (*optval && isspace(*optval))
306  ++optval;
307  if (!*optval)
308  {
309  err << "invalid binary archive option value \"\"";
310  return false;
311  }
312  char* valend = opt + strlen(opt) - 1;
313  while (isspace(*valend))
314  --valend;
315  ++valend;
316  *valend = '\0';
317  if (strlen(optval) == 0)
318  {
319  err << "invalid binary archive option value \"\"";
320  return false;
321  }
322 
323  // Go over possible options
324  if (!strcasecmp(optname, "z"))
325  {
326  // Compression type
327  if (!CStringStream::getCompressionModeByName(optval, m))
328  {
329  err << "invalid compression type \"" << optval << '"';
330  return false;
331  }
332  }
333  else if (!strcasecmp(optname, "cl"))
334  {
335  // Compression level
336  if (!parse_int(err, optval, compressionLevel))
337  return false;
338  if (*compressionLevel < -1 || *compressionLevel > 9)
339  {
340  err << "compression level is out of range";
341  return false;
342  }
343  }
344  else if (!strcasecmp(optname, "cb"))
345  {
346  // Compression buffer size
347  if (!parse_unsigned(err, optval, bufSize))
348  return false;
349  }
350  else if (!strcasecmp(optname, "cm"))
351  {
352  // Compression minimum size
353  if (!parse_unsigned(err, optval, minSizeToCompress))
354  return false;
355  }
356  else if (!strcasecmp(optname, "cat"))
357  {
358  // Internal or external catalog
359  if (optval[0] == 'i' || optval[0] == 'I')
360  *multiplexCatalog = true;
361  else if (optval[0] == 's' || optval[0] == 'S')
362  *multiplexCatalog = false;
363  else
364  {
365  err << "invalid catalog mode \"" << optval << '"';
366  return false;
367  }
368  }
369  else
370  {
371  // Unknown option
372  err << "unrecognized binary archive option \""
373  << optname << '"';
374  return false;
375  }
376  }
377  else
378  {
379  err << "invalid binary archive option \"" << opt << '"';
380  return false;
381  }
382  }
383  return true;
384  }
385 
386 
387  std::ios_base::openmode BinaryArchiveBase::parseMode(const char* mode)
388  {
389  std::ios_base::openmode m = std::ios_base::binary;
390  if (mode)
391  {
392  const unsigned len = strlen(mode);
393  for (unsigned i=0; i<len; ++i)
394  {
395  // Note that all characters other than 'r', 'w',
396  // 'a', and '+' are basically ignored inside this cycle
397  if (mode[i] == 'r')
398  m |= std::ios_base::in;
399  else if (mode[i] == 'w')
401  else if (mode[i] == 'a')
402  m |= (std::ios_base::out | std::ios_base::app);
403  else if (mode[i] == '+')
405  else if (mode[i] == ':')
406  break;
407  }
408  }
409 
410  // Make sure that we are at least reading
411  if (!(m & (std::ios_base::in | std::ios_base::out)))
412  m |= std::ios_base::in;
413  return m;
414  }
415 
416 
417  void BinaryArchiveBase::search(AbsReference& reference)
418  {
419  if (catalog_)
420  {
421  std::vector<unsigned long long> idlist;
422  catalog_->search(reference.namePattern(),
423  reference.categoryPattern(),
424  &idlist);
425  const unsigned long nfound = idlist.size();
426  for (unsigned long i=0; i<nfound; ++i)
427  {
428  CPP11_shared_ptr<const CatalogEntry> pentry =
429  catalog_->retrieveEntry(idlist[i]);
430  if (reference.isIOCompatible(*pentry))
431  addItemToReference(reference, idlist[i]);
432  }
433  }
434  }
435 
436 
437  bool BinaryArchiveBase::isEmptyFile(std::fstream& s)
438  {
439  s.seekg(0, std::ios_base::end);
440  return s.tellg() == std::streampos(0);
441  }
442 
443 
444  std::istream& BinaryArchiveBase::inputStream(const unsigned long long id,
445  long long *sz)
446  {
447  unsigned long long length = 0;
448  unsigned compressionCode = 0;
449  std::istream& is = plainInputStream(id, &compressionCode, &length);
450  if (cStream_->compressionMode() == CStringStream::NOT_COMPRESSED)
451  {
452  if (sz)
453  *sz = -1LL;
454  return is;
455  }
456  else
457  {
458  cStream_->readCompressed(is, compressionCode, length);
459  if (sz)
460  {
461  std::streamoff off = cStream_->tellp();
462  *sz = off;
463  }
464  return *cStream_;
465  }
466  }
467 
468 
469  std::ostream& BinaryArchiveBase::outputStream()
470  {
471  return plainOutputStream();
472  }
473 
474 
475  std::ostream& BinaryArchiveBase::compressedStream(std::ostream& os)
476  {
477  if (cStream_->compressionMode() == CStringStream::NOT_COMPRESSED)
478  return os;
479  else
480  {
481  cStream_->reset();
482  cStream_->setSink(os);
483  return *cStream_;
484  }
485  }
486 
487 
488  unsigned BinaryArchiveBase::flushCompressedRecord(std::ostream&)
489  {
490  CStringStream::CompressionMode m = cStream_->compressionMode();
491  if (m != CStringStream::NOT_COMPRESSED)
492  {
493  cStream_->flush();
494  m = cStream_->writeCompressed();
495  }
496  return static_cast<unsigned>(m);
497  }
498 }
std::vector< T >::const_iterator search(const cond::Time_t &val, const std::vector< T > &container)
Definition: IOVProxy.cc:314
static bool parse_unsigned(std::ostringstream &err, const char *c, unsigned *result)
static int const bufSize
Definition: Guid.cc:24
void readHeader(xercesc::DOMNode *parentNode, EcalCondHeader &header)
read header from
void writeHeader(xercesc::DOMNode *parentNode, const EcalCondHeader &header)
write
#define end
Definition: vmac.h:39
Definition: value.py:1
static bool parse_int(std::ostringstream &err, const char *c, int *result)
#define GENERS_BINARY_ARCHIVE_FORMAT_ID
Definition: AbsArchive.cc:53