CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/Alignment/Geners/src/BinaryArchiveBase.cc

Go to the documentation of this file.
00001 #include <cerrno>
00002 #include <cctype>
00003 #include <cstdlib>
00004 #include <cstring>
00005 #include <climits>
00006 #include <cassert>
00007 
00008 #include "Alignment/Geners/interface/BinaryArchiveBase.hh"
00009 #include "Alignment/Geners/interface/CatalogIO.hh"
00010 #include "Alignment/Geners/interface/binaryIO.hh"
00011 
00012 #ifdef GENERS_BINARY_ARCHIVE_FORMAT_ID
00013 #undef GENERS_BINARY_ARCHIVE_FORMAT_ID
00014 #endif
00015 #define GENERS_BINARY_ARCHIVE_FORMAT_ID (0x1f2e3d4c)
00016 
00017 static bool parse_unsigned(std::ostringstream& err,
00018                            const char *c, unsigned *result)
00019 {
00020     char *endptr;
00021     errno = 0;
00022     const unsigned long value = strtoul(c, &endptr, 0);
00023     if (errno || *endptr != '\0')
00024     {
00025         err << "expected an unsigned integer, got \"" << c << '"';
00026         if (errno) err << ", " << strerror(errno);
00027         return false;
00028     }
00029     if (value > UINT_MAX)
00030     {
00031         err << "unsigned value \"" << c << "\" is out of range";
00032         return false;
00033     }
00034     *result = value;
00035     return true;
00036 }
00037 
00038 static bool parse_int(std::ostringstream& err,
00039                       const char *c, int *result)
00040 {
00041     char *endptr;
00042     errno = 0;
00043     const long value = strtol(c, &endptr, 0);
00044     if (errno || *endptr != '\0')
00045     {
00046         err << "expected an integer, got \"" << c << '"';
00047         if (errno) err << ", " << strerror(errno);
00048         return false;
00049     }
00050     if (value < INT_MIN || value > INT_MAX)
00051     {
00052         err << "integer value \"" << c << "\" is out of range";
00053         return false;
00054     }
00055     *result = value;
00056     return true;
00057 }
00058 
00059 namespace gs {
00060     BinaryArchiveBase::BinaryArchiveBase(const char* name, const char* mode)
00061         : AbsArchive(name),
00062           mode_(parseMode(mode)),
00063           errorStream_(0),
00064           cStream_(0),
00065           catalog_(0),
00066           storedEntryId_(0),
00067           storedLocationId_(0),
00068           catalogIsSet_(false),
00069           addCatalogToData_(false)
00070     {
00071         CStringStream::CompressionMode m = CStringStream::NOT_COMPRESSED;
00072         int compressionLevel = -1;
00073         unsigned minSizeToCompress = 1024U;
00074         unsigned bufSize = 1048576U; // 1024*1024
00075 
00076         std::ostringstream err;
00077         modeIsValid_ = parseArchiveOptions(err, mode, &m, &compressionLevel,
00078                                            &minSizeToCompress, &bufSize,
00079                                            &addCatalogToData_);
00080         if (modeIsValid_)
00081             cStream_ = new CStringStream(m, compressionLevel,
00082                                          minSizeToCompress, bufSize);
00083         else
00084         {
00085             errorStream() << "In BinaryArchiveBase constructor: "
00086                           << "invalid archive opening mode \"" << mode << '"';
00087             const std::string& errInfo = err.str();
00088             if (!errInfo.empty())
00089                 errorStream() << ": " << errInfo;
00090         }
00091     }
00092 
00093 
00094     void BinaryArchiveBase::releaseClassIds()
00095     {
00096         delete storedEntryId_; storedEntryId_ = 0;
00097         delete storedLocationId_; storedLocationId_ = 0;
00098     }
00099 
00100 
00101     BinaryArchiveBase::~BinaryArchiveBase()
00102     {
00103         releaseClassIds();
00104         delete errorStream_;
00105         delete catalog_;
00106         delete cStream_;
00107     }
00108 
00109 
00110     void BinaryArchiveBase::writeHeader(std::ostream& os)
00111     {
00112         const unsigned format = GENERS_BINARY_ARCHIVE_FORMAT_ID;
00113         write_pod(os, format);
00114 
00115         // Write some other info
00116         const unsigned multiplex = addCatalogToData_ ? 1 : 0;
00117         const unsigned sizeoflong = sizeof(long);
00118         const unsigned infoword = (sizeoflong << 1) | multiplex;
00119         write_pod(os, infoword);
00120 
00121         if (multiplex)
00122         {
00123             // Write class ids for CatalogEntry and ItemLocation
00124             releaseClassIds();
00125             storedEntryId_ = new ClassId(ClassId::makeId<CatalogEntry>());
00126             storedEntryId_->write(os);
00127             storedLocationId_ = new ClassId(ClassId::makeId<ItemLocation>());
00128             storedLocationId_->write(os);
00129         }
00130     }
00131 
00132 
00133     bool BinaryArchiveBase::readHeader(std::istream& is)
00134     {
00135         const unsigned expectedFormat = GENERS_BINARY_ARCHIVE_FORMAT_ID;
00136         is.seekg(0, std::ios_base::beg);
00137         unsigned format = 0;
00138         read_pod(is, &format);
00139         if (format != expectedFormat)
00140             return false;
00141 
00142         unsigned infoword = 0xffffffff;
00143         read_pod(is, &infoword);
00144         const unsigned multiplex = infoword & 0x1U;
00145         const unsigned sizeoflong = infoword >> 1;
00146 
00147         // The following check will make sure that we are not reading
00148         // an archive created on a 32-bit machine with a 64-bit system
00149         // (and otherwise)
00150         if (sizeoflong != sizeof(long))
00151             return false;
00152 
00153         addCatalogToData_ = multiplex;
00154         if (addCatalogToData_)
00155         {
00156             releaseClassIds();
00157             storedEntryId_ = new ClassId(is, 1);
00158             storedLocationId_ = new ClassId(is, 1);
00159 
00160             // Can't open this archive for update if the above class ids
00161             // are obsolete -- otherwise we will loose the capability to
00162             // restore the catalog
00163             if (mode_ & std::ios_base::out)
00164             {
00165                 const ClassId& entryId = ClassId::makeId<CatalogEntry>();
00166                 const ClassId& locId = ClassId::makeId<ItemLocation>();
00167                 if (entryId != *storedEntryId_ || locId != *storedLocationId_)
00168                     throw IOInvalidData(
00169                         "In gs::BinaryArchiveBase::readHeader: this "
00170                         "archive can no longer be open for update as it was "
00171                         "created using an older version of I/O software");
00172             }
00173         }
00174         return !is.fail();
00175     }
00176 
00177 
00178     void BinaryArchiveBase::openDataFile(std::fstream& stream,
00179                                          const char* filename)
00180     {
00181         assert(filename);
00182         if (stream.is_open())
00183             stream.close();
00184         stream.clear();
00185         stream.open(filename, mode_);
00186         if (!stream.is_open())
00187             throw IOOpeningFailure("gs::BinaryArchiveBase::openDataFile",
00188                                    filename);
00189 
00190         // Do we need to write the header out or to read it in?
00191         bool writeHead = false;
00192         if (mode_ & std::ios_base::out)
00193         {
00194             if (mode_ & std::ios_base::trunc)
00195                 writeHead = true;
00196             else if (isEmptyFile(stream))
00197                 writeHead = true;
00198         }
00199 
00200         if (writeHead)
00201         {
00202             writeHeader(stream);
00203             if (stream.fail())
00204             {
00205                 stream.close();
00206                 std::string e = "In gs::BinaryArchiveBase::openDataFile: "
00207                     "failed to write archive header to file \"";
00208                 e += filename;
00209                 e += "\"";
00210                 throw IOWriteFailure(e);
00211             }
00212         }
00213         else
00214         {
00215             if (!readHeader(stream))
00216             {
00217                 const bool failed = stream.fail();
00218                 stream.close();                
00219                 std::string e = "In gs::BinaryArchiveBase::openDataFile: ";
00220                 if (failed)
00221                 {
00222                     e += "could not read archive header from file \"";
00223                     e += filename;
00224                     e += "\"";
00225                     throw IOReadFailure(e);
00226                 }
00227                 else
00228                 {
00229                     e += "no valid archive header in file \"";
00230                     e += filename;
00231                     e += "\"";
00232                     throw IOInvalidData(e);
00233                 }
00234             }
00235         }
00236     }
00237 
00238 
00239     void BinaryArchiveBase::setCatalog(AbsCatalog* c)
00240     {
00241         if (c)
00242         {
00243             assert(!catalogIsSet_);
00244             catalogIsSet_ = true;
00245         }
00246         delete catalog_;
00247         catalog_ = c;
00248     }
00249 
00250 
00251     void BinaryArchiveBase::itemSearch(
00252         const SearchSpecifier& namePattern,
00253         const SearchSpecifier& categoryPattern,
00254         std::vector<unsigned long long>* idsFound) const
00255     {
00256         if (catalog_)
00257             catalog_->search(namePattern, categoryPattern, idsFound);
00258         else
00259         {
00260             assert(idsFound);
00261             idsFound->clear();
00262         }
00263     }
00264 
00265 
00266     bool BinaryArchiveBase::parseArchiveOptions(
00267         std::ostringstream& err,
00268         const char* modeIn, CStringStream::CompressionMode* m,
00269         int* compressionLevel, unsigned* minSizeToCompress,
00270         unsigned* bufSize, bool* multiplexCatalog)
00271     {
00272         if (!modeIn)
00273             return true;
00274         std::string cmode(modeIn ? modeIn : "");
00275         if (cmode.empty())
00276             return true;
00277         char* mode = const_cast<char*>(cmode.c_str());
00278 
00279         unsigned cnt = 0;
00280         for (char* opt = strtok(mode, ":"); opt; opt = strtok(0, ":"), ++cnt)
00281         {
00282             // Skip the first word -- this is the file opening mode
00283             if (!cnt)
00284                 continue;
00285             char* eq = strchr(opt, '=');
00286             if (eq)
00287             {
00288                 // Get rid of spaces around option name
00289                 char* optname = opt;
00290                 while (isspace(*optname) && optname < eq)
00291                     ++optname;
00292                 if (optname == eq)
00293                 {
00294                     err << "invalid binary archive option \"\"";
00295                     return false;
00296                 }
00297                 char* optend = eq - 1;
00298                 while (isspace(*optend))
00299                     --optend;
00300                 ++optend;
00301                 *optend = '\0';
00302 
00303                 // Get rid of spaces around option value
00304                 char* optval = eq + 1;
00305                 while (*optval && isspace(*optval))
00306                     ++optval;
00307                 if (!*optval)
00308                 {
00309                     err << "invalid binary archive option value \"\"";
00310                     return false;
00311                 }
00312                 char* valend = opt + strlen(opt) - 1;
00313                 while (isspace(*valend))
00314                     --valend;
00315                 ++valend;
00316                 *valend = '\0';
00317                 if (strlen(optval) == 0)
00318                 {
00319                     err << "invalid binary archive option value \"\"";
00320                     return false;
00321                 }
00322 
00323                 // Go over possible options
00324                 if (!strcasecmp(optname, "z"))
00325                 {
00326                     // Compression type
00327                     if (!CStringStream::getCompressionModeByName(optval, m))
00328                     {
00329                         err << "invalid compression type \"" << optval << '"';
00330                         return false;
00331                     }
00332                 }
00333                 else if (!strcasecmp(optname, "cl"))
00334                 {
00335                     // Compression level
00336                     if (!parse_int(err, optval, compressionLevel))
00337                         return false;
00338                     if (*compressionLevel < -1 || *compressionLevel > 9)
00339                     {
00340                         err << "compression level is out of range";
00341                         return false;
00342                     }
00343                 }
00344                 else if (!strcasecmp(optname, "cb"))
00345                 {
00346                     // Compression buffer size
00347                     if (!parse_unsigned(err, optval, bufSize))
00348                         return false;
00349                 }
00350                 else if (!strcasecmp(optname, "cm"))
00351                 {
00352                     // Compression minimum size
00353                     if (!parse_unsigned(err, optval, minSizeToCompress))
00354                         return false;
00355                 }
00356                 else if (!strcasecmp(optname, "cat"))
00357                 {
00358                     // Internal or external catalog
00359                     if (optval[0] == 'i' || optval[0] == 'I')
00360                         *multiplexCatalog = true;
00361                     else if (optval[0] == 's' || optval[0] == 'S')
00362                         *multiplexCatalog = false;
00363                     else
00364                     {
00365                         err << "invalid catalog mode \"" << optval << '"';
00366                         return false;
00367                     }
00368                 }
00369                 else
00370                 {
00371                     // Unknown option
00372                     err << "unrecognized binary archive option \""
00373                         << optname << '"';
00374                     return false;
00375                 }
00376             }
00377             else
00378             {
00379                 err << "invalid binary archive option \"" << opt << '"';
00380                 return false;
00381             }
00382         }
00383         return true;
00384     }
00385 
00386 
00387     std::ios_base::openmode BinaryArchiveBase::parseMode(const char* mode)
00388     {
00389         std::ios_base::openmode m = std::ios_base::binary;
00390         if (mode)
00391         {
00392             const unsigned len = strlen(mode);
00393             for (unsigned i=0; i<len; ++i)
00394             {
00395                 // Note that all characters other than 'r', 'w',
00396                 // 'a', and '+' are basically ignored inside this cycle
00397                 if (mode[i] == 'r')
00398                     m |= std::ios_base::in;
00399                 else if (mode[i] == 'w')
00400                     m |= (std::ios_base::out | std::ios_base::trunc);
00401                 else if (mode[i] == 'a')
00402                     m |= (std::ios_base::out | std::ios_base::app);
00403                 else if (mode[i] == '+')
00404                     m |= (std::ios_base::in | std::ios_base::out);
00405                 else if (mode[i] == ':')
00406                     break;
00407             }
00408         }
00409 
00410         // Make sure that we are at least reading
00411         if (!(m & (std::ios_base::in | std::ios_base::out)))
00412             m |= std::ios_base::in;
00413         return m;
00414     }
00415 
00416 
00417     void BinaryArchiveBase::search(AbsReference& reference)
00418     {
00419         if (catalog_)
00420         {
00421             std::vector<unsigned long long> idlist;
00422             catalog_->search(reference.namePattern(),
00423                              reference.categoryPattern(),
00424                              &idlist);
00425             const unsigned long nfound = idlist.size();
00426             for (unsigned long i=0; i<nfound; ++i)
00427             {
00428                 CPP11_shared_ptr<const CatalogEntry> pentry = 
00429                     catalog_->retrieveEntry(idlist[i]);
00430                 if (reference.isIOCompatible(*pentry))
00431                     addItemToReference(reference, idlist[i]);
00432             }
00433         }
00434     }
00435 
00436 
00437     bool BinaryArchiveBase::isEmptyFile(std::fstream& s)
00438     {
00439         s.seekg(0, std::ios_base::end);
00440         return s.tellg() == std::streampos(0);
00441     }
00442 
00443 
00444     std::istream& BinaryArchiveBase::inputStream(const unsigned long long id)
00445     {
00446         unsigned long long length = 0;
00447         unsigned compressionCode = 0;
00448         std::istream& is = plainInputStream(id, &compressionCode, &length);
00449         if (cStream_->compressionMode() == CStringStream::NOT_COMPRESSED)
00450             return is;
00451         else
00452         {
00453             cStream_->readCompressed(is, compressionCode, length);
00454             return *cStream_;
00455         }
00456     }
00457 
00458 
00459     std::ostream& BinaryArchiveBase::outputStream()
00460     {
00461         return plainOutputStream();
00462     }
00463 
00464 
00465     std::ostream& BinaryArchiveBase::compressedStream(std::ostream& os)
00466     {
00467         if (cStream_->compressionMode() == CStringStream::NOT_COMPRESSED)
00468             return os;
00469         else
00470         {
00471             cStream_->reset();
00472             cStream_->setSink(os);
00473             return *cStream_;
00474         }
00475     }
00476 
00477 
00478     unsigned BinaryArchiveBase::flushCompressedRecord(std::ostream&)
00479     {
00480         CStringStream::CompressionMode m = cStream_->compressionMode();
00481         if (m != CStringStream::NOT_COMPRESSED)
00482         {
00483             cStream_->flush();
00484             m = cStream_->writeCompressed();
00485         }
00486         return static_cast<unsigned>(m);
00487     }
00488 }