File indexing completed on 2024-04-06 11:56:20
0001 #include <cassert>
0002 #include <sstream>
0003
0004 #include "Alignment/Geners/interface/AbsArchive.hh"
0005 #include "Alignment/Geners/interface/IOException.hh"
0006
0007 #define GS_STREAM_COPY_BUFFER_SIZE 65536
0008
0009 static void archive_stream_copy(std::istream &in, std::size_t count, std::ostream &out) {
0010 if (count) {
0011 const std::size_t bufsize = GS_STREAM_COPY_BUFFER_SIZE;
0012 char buffer[bufsize];
0013
0014 bool in_fail = in.fail();
0015 bool out_fail = out.fail();
0016 while (count > bufsize && !in_fail && !out_fail) {
0017 in.read(buffer, bufsize);
0018 in_fail = in.fail();
0019 if (!in_fail) {
0020 out.write(buffer, bufsize);
0021 out_fail = out.fail();
0022 }
0023 count -= bufsize;
0024 }
0025 if (!in_fail && !out_fail) {
0026 in.read(buffer, count);
0027 if (!in.fail())
0028 out.write(buffer, count);
0029 }
0030 }
0031 }
0032
0033 namespace {
0034 class NotWritableRecord : public gs::AbsRecord {
0035 public:
0036 inline NotWritableRecord(const gs::ClassId &classId, const char *ioPrototype, const char *name, const char *category)
0037 : gs::AbsRecord(classId, ioPrototype, name, category) {}
0038
0039 NotWritableRecord() = delete;
0040
0041 private:
0042 inline bool writeData(std::ostream &) const override { return false; }
0043 };
0044 }
0045
0046 namespace gs {
0047 AbsArchive::AbsArchive(const char *name) : name_(name ? name : ""), lastItemId_(0), lastItemLength_(0) {}
0048
0049 void AbsArchive::addItemToReference(AbsReference &r, const unsigned long long id) const { r.addItemId(id); }
0050
0051 unsigned long long AbsArchive::copyItem(const unsigned long long id,
0052 AbsArchive *destination,
0053 const char *newName,
0054 const char *newCategory) {
0055 if (!isReadable())
0056 throw gs::IOInvalidArgument(
0057 "In gs::AbsArchive::copyItem: "
0058 "origin archive is not readable");
0059 assert(destination);
0060 if (this == destination)
0061 throw gs::IOInvalidArgument(
0062 "In gs::AbsArchive::copyItem: "
0063 "origin and destination archives are the same");
0064 AbsArchive &ar(*destination);
0065 if (!ar.isWritable())
0066 throw gs::IOInvalidArgument(
0067 "In gs::AbsArchive::copyItem: "
0068 "destination archive is not writable");
0069 std::shared_ptr<const CatalogEntry> entry(catalogEntry(id));
0070 if (!entry)
0071 throw gs::IOInvalidArgument(
0072 "In gs::AbsArchive::copyItem: no item "
0073 "in the archive with the given id");
0074
0075
0076 long long sz = 0;
0077 std::istream &is = inputStream(id, &sz);
0078
0079
0080
0081 std::ostream &os = ar.outputStream();
0082 std::streampos base = os.tellp();
0083 std::ostream &compressed = ar.compressedStream(os);
0084
0085
0086 unsigned long long len;
0087 if (sz >= 0)
0088 len = sz;
0089 else
0090 len = entry->itemLength();
0091 archive_stream_copy(is, len, compressed);
0092 if (is.fail())
0093 throw IOReadFailure(
0094 "In gs::AbsArchive::copyItem: "
0095 "input stream failure");
0096 if (compressed.fail())
0097 throw IOWriteFailure(
0098 "In gs::AbsArchive::copyItem: "
0099 "output stream failure");
0100 const unsigned compressCode = ar.flushCompressedRecord(compressed);
0101 if (os.fail())
0102 throw IOWriteFailure(
0103 "In gs::AbsArchive::copyItem: "
0104 "failed to transfer compressed data");
0105
0106
0107 std::streamoff off = os.tellp() - base;
0108 const long long delta = off;
0109 assert(delta >= 0LL);
0110
0111
0112 const char *name = newName;
0113 if (!name)
0114 name = entry->name().c_str();
0115 const char *category = newCategory;
0116 if (!category)
0117 category = entry->category().c_str();
0118 NotWritableRecord record(entry->type(), entry->ioPrototype().c_str(), name, category);
0119
0120
0121 const unsigned long long id2 = ar.addToCatalog(record, compressCode, delta);
0122 if (id == 0ULL)
0123 throw IOWriteFailure(
0124 "In gs::AbsArchive::copyItem: "
0125 "failed to add catalog entry");
0126 ar.lastItemId_ = id2;
0127 ar.lastItemLength_ = delta;
0128 return id2;
0129 }
0130 }
0131
0132 static std::string local_error_message(gs::AbsArchive &ar, const gs::AbsRecord &record, const char *failedAction) {
0133 std::ostringstream err;
0134 err << "In operator<<(gs::AbsArchive& ar, const gs::AbsRecord& record): "
0135 << "failed to " << failedAction << " to the archive \"" << ar.name() << "\" for item with type \""
0136 << record.type().name() << "\", name \"" << record.name() << "\", and category \"" << record.category() << '"';
0137 return err.str();
0138 }
0139
0140 gs::AbsArchive &operator<<(gs::AbsArchive &ar, const gs::AbsRecord &record) {
0141
0142 if (record.id())
0143 throw gs::IOInvalidArgument(
0144 "In operator<<(gs::AbsArchive& ar, const gs::AbsRecord& record): "
0145 "records can not be reused");
0146
0147
0148
0149
0150
0151
0152 std::ostream &os = ar.outputStream();
0153 std::streampos base = os.tellp();
0154 std::ostream &compressed = ar.compressedStream(os);
0155
0156
0157 if (!record.writeData(compressed))
0158 throw gs::IOWriteFailure(local_error_message(ar, record, "write data"));
0159
0160 const unsigned compressCode = ar.flushCompressedRecord(compressed);
0161 if (os.fail())
0162 throw gs::IOWriteFailure(local_error_message(ar, record, "transfer compressed data"));
0163
0164
0165 std::streamoff off = os.tellp() - base;
0166 const long long delta = off;
0167 assert(delta >= 0LL);
0168
0169
0170 const unsigned long long id = ar.addToCatalog(record, compressCode, delta);
0171 if (id == 0ULL)
0172 throw gs::IOWriteFailure(local_error_message(ar, record, "add catalog entry"));
0173
0174
0175 record.itemId_ = id;
0176 record.itemLength_ = delta;
0177
0178
0179 ar.lastItemId_ = id;
0180 ar.lastItemLength_ = delta;
0181
0182 return ar;
0183 }