File indexing completed on 2025-02-21 09:30:07
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 #pragma once
0046 #ifndef AI_BLOBIOSYSTEM_H_INCLUDED
0047 #define AI_BLOBIOSYSTEM_H_INCLUDED
0048
0049 #ifdef __GNUC__
0050 #pragma GCC system_header
0051 #endif
0052
0053 #include <assimp/cexport.h>
0054 #include <assimp/DefaultLogger.hpp>
0055 #include <assimp/IOStream.hpp>
0056 #include <assimp/IOSystem.hpp>
0057 #include <cstdint>
0058 #include <set>
0059 #include <vector>
0060
0061 namespace Assimp {
0062 class BlobIOSystem;
0063
0064
0065
0066
0067 class BlobIOStream : public IOStream {
0068 public:
0069
0070
0071
0072
0073 BlobIOStream(BlobIOSystem *creator, const std::string &file, size_t initial = 4096) :
0074 buffer(),
0075 cur_size(),
0076 file_size(),
0077 cursor(),
0078 initial(initial),
0079 file(file),
0080 creator(creator) {
0081
0082 }
0083
0084
0085 ~BlobIOStream() override;
0086
0087 public:
0088
0089 aiExportDataBlob *GetBlob() {
0090 aiExportDataBlob *blob = new aiExportDataBlob();
0091 blob->size = file_size;
0092 blob->data = buffer;
0093
0094 buffer = nullptr;
0095
0096 return blob;
0097 }
0098
0099
0100 size_t Read(void *, size_t, size_t) override {
0101 return 0;
0102 }
0103
0104
0105 size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override {
0106 pSize *= pCount;
0107 if (cursor + pSize > cur_size) {
0108 Grow(cursor + pSize);
0109 }
0110
0111 memcpy(buffer + cursor, pvBuffer, pSize);
0112 cursor += pSize;
0113
0114 file_size = std::max(file_size, cursor);
0115 return pCount;
0116 }
0117
0118
0119 aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override {
0120 switch (pOrigin) {
0121 case aiOrigin_CUR:
0122 cursor += pOffset;
0123 break;
0124
0125 case aiOrigin_END:
0126 cursor = file_size - pOffset;
0127 break;
0128
0129 case aiOrigin_SET:
0130 cursor = pOffset;
0131 break;
0132
0133 default:
0134 return AI_FAILURE;
0135 }
0136
0137 if (cursor > file_size) {
0138 Grow(cursor);
0139 }
0140
0141 file_size = std::max(cursor, file_size);
0142
0143 return AI_SUCCESS;
0144 }
0145
0146
0147 size_t Tell() const override {
0148 return cursor;
0149 }
0150
0151
0152 size_t FileSize() const override {
0153 return file_size;
0154 }
0155
0156
0157 void Flush() override {
0158
0159 }
0160
0161 private:
0162
0163 void Grow(size_t need = 0) {
0164
0165
0166
0167
0168
0169
0170 size_t new_size = std::max(initial, std::max(need, cur_size + (cur_size >> 1)));
0171
0172 const uint8_t *const old = buffer;
0173 buffer = new uint8_t[new_size];
0174
0175 if (old) {
0176 memcpy(buffer, old, cur_size);
0177 delete[] old;
0178 }
0179
0180 cur_size = new_size;
0181 }
0182
0183 private:
0184 uint8_t *buffer;
0185 size_t cur_size, file_size, cursor, initial;
0186
0187 const std::string file;
0188 BlobIOSystem *const creator;
0189 };
0190
0191 #define AI_BLOBIO_MAGIC "$blobfile"
0192
0193
0194
0195
0196 class BlobIOSystem : public IOSystem {
0197
0198 friend class BlobIOStream;
0199 typedef std::pair<std::string, aiExportDataBlob *> BlobEntry;
0200
0201
0202 public:
0203
0204 BlobIOSystem() :
0205 baseName{AI_BLOBIO_MAGIC} {
0206 }
0207
0208
0209
0210 BlobIOSystem(const std::string &baseName) :
0211 baseName(baseName) {
0212
0213 }
0214
0215 ~BlobIOSystem() override {
0216 for (BlobEntry &blobby : blobs) {
0217 delete blobby.second;
0218 }
0219 }
0220
0221 public:
0222
0223 const char *GetMagicFileName() const {
0224 return baseName.c_str();
0225 }
0226
0227
0228 aiExportDataBlob *GetBlobChain() {
0229 const auto magicName = std::string(this->GetMagicFileName());
0230 const bool hasBaseName = baseName != AI_BLOBIO_MAGIC;
0231
0232
0233 aiExportDataBlob *master = nullptr, *cur;
0234
0235 for (const BlobEntry &blobby : blobs) {
0236 if (blobby.first == magicName) {
0237 master = blobby.second;
0238 master->name.Set(hasBaseName ? blobby.first : "");
0239 break;
0240 }
0241 }
0242
0243 if (!master) {
0244 ASSIMP_LOG_ERROR("BlobIOSystem: no data written or master file was not closed properly.");
0245 return nullptr;
0246 }
0247
0248 cur = master;
0249
0250 for (const BlobEntry &blobby : blobs) {
0251 if (blobby.second == master) {
0252 continue;
0253 }
0254
0255 cur->next = blobby.second;
0256 cur = cur->next;
0257
0258 if (hasBaseName) {
0259 cur->name.Set(blobby.first);
0260 } else {
0261
0262 const std::string::size_type s = blobby.first.find_first_of('.');
0263 cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s + 1));
0264 }
0265 }
0266
0267
0268 blobs.clear();
0269 return master;
0270 }
0271
0272 public:
0273
0274 bool Exists(const char *pFile) const override {
0275 return created.find(std::string(pFile)) != created.end();
0276 }
0277
0278
0279 char getOsSeparator() const override {
0280 return '/';
0281 }
0282
0283
0284 IOStream *Open(const char *pFile, const char *pMode) override {
0285 if (pMode[0] != 'w') {
0286 return nullptr;
0287 }
0288
0289 created.insert(std::string(pFile));
0290 return new BlobIOStream(this, std::string(pFile));
0291 }
0292
0293
0294 void Close(IOStream *pFile) override {
0295 delete pFile;
0296 }
0297
0298 private:
0299
0300 void OnDestruct(const std::string &filename, BlobIOStream *child) {
0301
0302
0303
0304 blobs.emplace_back(filename, child->GetBlob());
0305 }
0306
0307 private:
0308 std::string baseName;
0309 std::set<std::string> created;
0310 std::vector<BlobEntry> blobs;
0311 };
0312
0313
0314 BlobIOStream::~BlobIOStream() {
0315 if (nullptr != creator) {
0316 creator->OnDestruct(file, this);
0317 }
0318 delete[] buffer;
0319 }
0320
0321 }
0322
0323 #endif