1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 30 #if OGRE_NO_ZIP_ARCHIVE == 0 31 // workaround for Wundef in zzip/conf.h 32 #ifndef __GNUC_MINOR_ 33 #define __GNUC_MINOR_ 0 34 #endif 35 36 #include <zzip/zzip.h> 37 #include <zzip/plugin.h> 38 39 namespace Ogre { 40 namespace { 41 class ZipArchive : public Archive 42 { 43 protected: 44 /// Handle to root zip file 45 ZZIP_DIR* mZzipDir; 46 /// File list (since zziplib seems to only allow scanning of dir tree once) 47 FileInfoList mFileList; 48 /// A pointer to file io alternative implementation 49 zzip_plugin_io_handlers* mPluginIo; 50 51 OGRE_AUTO_MUTEX; 52 public: 53 ZipArchive(const String& name, const String& archType, zzip_plugin_io_handlers* pluginIo = NULL); 54 ~ZipArchive(); 55 /// @copydoc Archive::isCaseSensitive isCaseSensitive(void) const56 bool isCaseSensitive(void) const { return OGRE_RESOURCEMANAGER_STRICT != 0; } 57 58 /// @copydoc Archive::load 59 void load(); 60 /// @copydoc Archive::unload 61 void unload(); 62 63 /// @copydoc Archive::open 64 DataStreamPtr open(const String& filename, bool readOnly = true) const; 65 66 /// @copydoc Archive::create 67 DataStreamPtr create(const String& filename); 68 69 /// @copydoc Archive::remove 70 void remove(const String& filename); 71 72 /// @copydoc Archive::list 73 StringVectorPtr list(bool recursive = true, bool dirs = false) const; 74 75 /// @copydoc Archive::listFileInfo 76 FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) const; 77 78 /// @copydoc Archive::find 79 StringVectorPtr find(const String& pattern, bool recursive = true, 80 bool dirs = false) const; 81 82 /// @copydoc Archive::findFileInfo 83 FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, 84 bool dirs = false) const; 85 86 /// @copydoc Archive::exists 87 bool exists(const String& filename) const; 88 89 /// @copydoc Archive::getModifiedTime 90 time_t getModifiedTime(const String& filename) const; 91 }; 92 93 /** Specialisation of DataStream to handle streaming data from zip archives. */ 94 class ZipDataStream : public DataStream 95 { 96 protected: 97 ZZIP_FILE* mZzipFile; 98 /// We need caching because sometimes serializers step back in data stream and zziplib behaves slow 99 StaticCache<2 * OGRE_STREAM_TEMP_SIZE> mCache; 100 public: 101 /// Constructor for creating named streams 102 ZipDataStream(const String& name, ZZIP_FILE* zzipFile, size_t uncompressedSize); 103 ~ZipDataStream(); 104 /// @copydoc DataStream::read 105 size_t read(void* buf, size_t count); 106 /// @copydoc DataStream::write 107 size_t write(const void* buf, size_t count); 108 /// @copydoc DataStream::skip 109 void skip(long count); 110 /// @copydoc DataStream::seek 111 void seek( size_t pos ); 112 /// @copydoc DataStream::seek 113 size_t tell(void) const; 114 /// @copydoc DataStream::eof 115 bool eof(void) const; 116 /// @copydoc DataStream::close 117 void close(void); 118 }; 119 120 /// Utility method to format out zzip errors getErrorDescription(zzip_error_t zzipError,const String & file)121 static String getErrorDescription(zzip_error_t zzipError, const String& file) 122 { 123 const char* errorMsg = ""; 124 switch (zzipError) 125 { 126 case ZZIP_NO_ERROR: 127 break; 128 case ZZIP_OUTOFMEM: 129 errorMsg = "Out of memory"; 130 break; 131 case ZZIP_DIR_OPEN: 132 errorMsg = "Unable to open zip file"; 133 break; 134 case ZZIP_DIR_STAT: 135 case ZZIP_DIR_SEEK: 136 case ZZIP_DIR_READ: 137 errorMsg = "Unable to read zip file"; 138 break; 139 case ZZIP_UNSUPP_COMPR: 140 errorMsg = "Unsupported compression format"; 141 break; 142 case ZZIP_CORRUPTED: 143 errorMsg = "Corrupted archive"; 144 break; 145 case ZZIP_DIR_TOO_SHORT: 146 errorMsg = "Zip file is too short"; 147 break; 148 case ZZIP_DIR_EDH_MISSING: 149 errorMsg = "Zip-file's central directory record missing. Is this a 7z file"; 150 break; 151 case ZZIP_ENOENT: 152 errorMsg = "File not in archive"; 153 break; 154 default: 155 errorMsg = "Unknown error"; 156 break; 157 }; 158 159 return StringUtil::format("%s '%s'", errorMsg, file.c_str()); 160 } 161 162 /// A static pointer to file io alternative implementation for the embedded files 163 zzip_plugin_io_handlers* gPluginIo = NULL; 164 } 165 //----------------------------------------------------------------------- ZipArchive(const String & name,const String & archType,zzip_plugin_io_handlers * pluginIo)166 ZipArchive::ZipArchive(const String& name, const String& archType, zzip_plugin_io_handlers* pluginIo) 167 : Archive(name, archType), mZzipDir(0), mPluginIo(pluginIo) 168 { 169 } 170 //----------------------------------------------------------------------- ~ZipArchive()171 ZipArchive::~ZipArchive() 172 { 173 unload(); 174 } 175 //----------------------------------------------------------------------- load()176 void ZipArchive::load() 177 { 178 OGRE_LOCK_AUTO_MUTEX; 179 if (!mZzipDir) 180 { 181 zzip_error_t zzipError; 182 mZzipDir = zzip_dir_open_ext_io(mName.c_str(), &zzipError, 0, mPluginIo); 183 if (zzipError) 184 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, getErrorDescription(zzipError, mName)); 185 186 // Cache names 187 ZZIP_DIRENT zzipEntry; 188 while (zzip_dir_read(mZzipDir, &zzipEntry)) 189 { 190 FileInfo info; 191 info.archive = this; 192 // Get basename / path 193 StringUtil::splitFilename(zzipEntry.d_name, info.basename, info.path); 194 info.filename = zzipEntry.d_name; 195 // Get sizes 196 info.compressedSize = static_cast<size_t>(zzipEntry.d_csize); 197 info.uncompressedSize = static_cast<size_t>(zzipEntry.st_size); 198 // folder entries 199 if (info.basename.empty()) 200 { 201 info.filename = info.filename.substr (0, info.filename.length () - 1); 202 StringUtil::splitFilename(info.filename, info.basename, info.path); 203 // Set compressed size to -1 for folders; anyway nobody will check 204 // the compressed size of a folder, and if he does, its useless anyway 205 info.compressedSize = size_t (-1); 206 } 207 #if !OGRE_RESOURCEMANAGER_STRICT 208 else 209 { 210 info.filename = info.basename; 211 } 212 #endif 213 mFileList.push_back(info); 214 215 } 216 217 } 218 } 219 //----------------------------------------------------------------------- unload()220 void ZipArchive::unload() 221 { 222 OGRE_LOCK_AUTO_MUTEX; 223 if (mZzipDir) 224 { 225 zzip_dir_close(mZzipDir); 226 mZzipDir = 0; 227 mFileList.clear(); 228 } 229 230 } 231 //----------------------------------------------------------------------- open(const String & filename,bool readOnly) const232 DataStreamPtr ZipArchive::open(const String& filename, bool readOnly) const 233 { 234 // zziplib is not threadsafe 235 OGRE_LOCK_AUTO_MUTEX; 236 String lookUpFileName = filename; 237 238 #if OGRE_RESOURCEMANAGER_STRICT 239 const int flags = 0; 240 #else 241 const int flags = ZZIP_CASELESS; 242 #endif 243 244 // Format not used here (always binary) 245 ZZIP_FILE* zzipFile = 246 zzip_file_open(mZzipDir, lookUpFileName.c_str(), ZZIP_ONLYZIP | flags); 247 248 #if !OGRE_RESOURCEMANAGER_STRICT 249 if (!zzipFile) // Try if we find the file 250 { 251 String basename, path; 252 StringUtil::splitFilename(lookUpFileName, basename, path); 253 const FileInfoListPtr fileNfo = findFileInfo(basename, true); 254 if (fileNfo->size() == 1) // If there are more files with the same do not open anyone 255 { 256 Ogre::FileInfo info = fileNfo->at(0); 257 lookUpFileName = info.path + info.basename; 258 zzipFile = zzip_file_open(mZzipDir, lookUpFileName.c_str(), ZZIP_ONLYZIP | flags); // When an error happens here we will catch it below 259 } 260 } 261 #endif 262 263 if (!zzipFile) 264 { 265 OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND, getErrorDescription((zzip_error_t)zzip_error(mZzipDir), mName)); 266 } 267 268 // Get uncompressed size too 269 ZZIP_STAT zstat; 270 zzip_dir_stat(mZzipDir, lookUpFileName.c_str(), &zstat, flags); 271 272 // Construct & return stream 273 return DataStreamPtr(OGRE_NEW ZipDataStream(lookUpFileName, zzipFile, static_cast<size_t>(zstat.st_size))); 274 275 } 276 //--------------------------------------------------------------------- create(const String & filename)277 DataStreamPtr ZipArchive::create(const String& filename) 278 { 279 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, 280 "Modification of zipped archives is not supported", 281 "ZipArchive::create"); 282 283 } 284 //--------------------------------------------------------------------- remove(const String & filename)285 void ZipArchive::remove(const String& filename) 286 { 287 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, 288 "Modification of zipped archives is not supported", 289 "ZipArchive::remove"); 290 } 291 //----------------------------------------------------------------------- list(bool recursive,bool dirs) const292 StringVectorPtr ZipArchive::list(bool recursive, bool dirs) const 293 { 294 OGRE_LOCK_AUTO_MUTEX; 295 StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T); 296 297 FileInfoList::const_iterator i, iend; 298 iend = mFileList.end(); 299 for (i = mFileList.begin(); i != iend; ++i) 300 if ((dirs == (i->compressedSize == size_t (-1))) && 301 (recursive || i->path.empty())) 302 ret->push_back(i->filename); 303 304 return ret; 305 } 306 //----------------------------------------------------------------------- listFileInfo(bool recursive,bool dirs) const307 FileInfoListPtr ZipArchive::listFileInfo(bool recursive, bool dirs) const 308 { 309 OGRE_LOCK_AUTO_MUTEX; 310 FileInfoList* fil = OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)(); 311 FileInfoList::const_iterator i, iend; 312 iend = mFileList.end(); 313 for (i = mFileList.begin(); i != iend; ++i) 314 if ((dirs == (i->compressedSize == size_t (-1))) && 315 (recursive || i->path.empty())) 316 fil->push_back(*i); 317 318 return FileInfoListPtr(fil, SPFM_DELETE_T); 319 } 320 //----------------------------------------------------------------------- find(const String & pattern,bool recursive,bool dirs) const321 StringVectorPtr ZipArchive::find(const String& pattern, bool recursive, bool dirs) const 322 { 323 OGRE_LOCK_AUTO_MUTEX; 324 StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T); 325 // If pattern contains a directory name, do a full match 326 bool full_match = (pattern.find ('/') != String::npos) || 327 (pattern.find ('\\') != String::npos); 328 bool wildCard = pattern.find('*') != String::npos; 329 330 FileInfoList::const_iterator i, iend; 331 iend = mFileList.end(); 332 for (i = mFileList.begin(); i != iend; ++i) 333 if ((dirs == (i->compressedSize == size_t (-1))) && 334 (recursive || full_match || wildCard)) 335 // Check basename matches pattern (zip is case insensitive) 336 if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false)) 337 ret->push_back(i->filename); 338 339 return ret; 340 } 341 //----------------------------------------------------------------------- findFileInfo(const String & pattern,bool recursive,bool dirs) const342 FileInfoListPtr ZipArchive::findFileInfo(const String& pattern, 343 bool recursive, bool dirs) const 344 { 345 OGRE_LOCK_AUTO_MUTEX; 346 FileInfoListPtr ret = FileInfoListPtr(OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T); 347 // If pattern contains a directory name, do a full match 348 bool full_match = (pattern.find ('/') != String::npos) || 349 (pattern.find ('\\') != String::npos); 350 bool wildCard = pattern.find('*') != String::npos; 351 352 FileInfoList::const_iterator i, iend; 353 iend = mFileList.end(); 354 for (i = mFileList.begin(); i != iend; ++i) 355 if ((dirs == (i->compressedSize == size_t (-1))) && 356 (recursive || full_match || wildCard)) 357 // Check name matches pattern (zip is case insensitive) 358 if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false)) 359 ret->push_back(*i); 360 361 return ret; 362 } 363 //----------------------------------------------------------------------- 364 struct FileNameCompare : public std::binary_function<FileInfo, String, bool> 365 { operator ()Ogre::FileNameCompare366 bool operator()(const Ogre::FileInfo& lhs, const String& filename) const 367 { 368 return lhs.filename == filename; 369 } 370 }; 371 //----------------------------------------------------------------------- exists(const String & filename) const372 bool ZipArchive::exists(const String& filename) const 373 { 374 OGRE_LOCK_AUTO_MUTEX; 375 String cleanName = filename; 376 #if !OGRE_RESOURCEMANAGER_STRICT 377 if(filename.rfind('/') != String::npos) 378 { 379 StringVector tokens = StringUtil::split(filename, "/"); 380 cleanName = tokens[tokens.size() - 1]; 381 } 382 #endif 383 384 return std::find_if (mFileList.begin(), mFileList.end(), std::bind2nd<FileNameCompare>(FileNameCompare(), cleanName)) != mFileList.end(); 385 } 386 //--------------------------------------------------------------------- getModifiedTime(const String & filename) const387 time_t ZipArchive::getModifiedTime(const String& filename) const 388 { 389 // Zziplib doesn't yet support getting the modification time of individual files 390 // so just check the mod time of the zip itself 391 struct stat tagStat; 392 bool ret = (stat(mName.c_str(), &tagStat) == 0); 393 394 if (ret) 395 { 396 return tagStat.st_mtime; 397 } 398 else 399 { 400 return 0; 401 } 402 403 } 404 //----------------------------------------------------------------------- ZipDataStream(const String & name,ZZIP_FILE * zzipFile,size_t uncompressedSize)405 ZipDataStream::ZipDataStream(const String& name, ZZIP_FILE* zzipFile, size_t uncompressedSize) 406 :DataStream(name), mZzipFile(zzipFile) 407 { 408 mSize = uncompressedSize; 409 } 410 //----------------------------------------------------------------------- ~ZipDataStream()411 ZipDataStream::~ZipDataStream() 412 { 413 close(); 414 } 415 //----------------------------------------------------------------------- read(void * buf,size_t count)416 size_t ZipDataStream::read(void* buf, size_t count) 417 { 418 size_t was_avail = mCache.read(buf, count); 419 zzip_ssize_t r = 0; 420 if (was_avail < count) 421 { 422 r = zzip_file_read(mZzipFile, (char*)buf + was_avail, count - was_avail); 423 if (r<0) { 424 ZZIP_DIR *dir = zzip_dirhandle(mZzipFile); 425 String msg = zzip_strerror_of(dir); 426 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 427 mName+" - error from zziplib: "+msg, 428 "ZipDataStream::read"); 429 } 430 mCache.cacheData((char*)buf + was_avail, (size_t)r); 431 } 432 return was_avail + (size_t)r; 433 } 434 //--------------------------------------------------------------------- write(const void * buf,size_t count)435 size_t ZipDataStream::write(const void* buf, size_t count) 436 { 437 // not supported 438 return 0; 439 } 440 //----------------------------------------------------------------------- skip(long count)441 void ZipDataStream::skip(long count) 442 { 443 long was_avail = static_cast<long>(mCache.avail()); 444 if (count > 0) 445 { 446 if (!mCache.ff(count)) 447 zzip_seek(mZzipFile, static_cast<zzip_off_t>(count - was_avail), SEEK_CUR); 448 } 449 else if (count < 0) 450 { 451 if (!mCache.rewind((size_t)(-count))) 452 zzip_seek(mZzipFile, static_cast<zzip_off_t>(count + was_avail), SEEK_CUR); 453 } 454 } 455 //----------------------------------------------------------------------- seek(size_t pos)456 void ZipDataStream::seek( size_t pos ) 457 { 458 zzip_off_t newPos = static_cast<zzip_off_t>(pos); 459 zzip_off_t prevPos = static_cast<zzip_off_t>(tell()); 460 if (prevPos < 0) 461 { 462 // seek set after invalid pos 463 mCache.clear(); 464 zzip_seek(mZzipFile, newPos, SEEK_SET); 465 } 466 else 467 { 468 // everything is going all right, relative seek 469 skip((long)(newPos - prevPos)); 470 } 471 } 472 //----------------------------------------------------------------------- tell(void) const473 size_t ZipDataStream::tell(void) const 474 { 475 zzip_off_t pos = zzip_tell(mZzipFile); 476 if (pos<0) 477 return (size_t)(-1); 478 return static_cast<size_t>(pos) - mCache.avail(); 479 } 480 //----------------------------------------------------------------------- eof(void) const481 bool ZipDataStream::eof(void) const 482 { 483 return (tell() >= mSize); 484 } 485 //----------------------------------------------------------------------- close(void)486 void ZipDataStream::close(void) 487 { 488 mAccess = 0; 489 if (mZzipFile != 0) 490 { 491 zzip_file_close(mZzipFile); 492 mZzipFile = 0; 493 } 494 mCache.clear(); 495 } 496 //----------------------------------------------------------------------- 497 //----------------------------------------------------------------------- 498 // ZipArchiveFactory 499 //----------------------------------------------------------------------- createInstance(const String & name,bool readOnly)500 Archive *ZipArchiveFactory::createInstance( const String& name, bool readOnly ) 501 { 502 if(!readOnly) 503 return NULL; 504 505 return OGRE_NEW ZipArchive(name, getType()); 506 } 507 //----------------------------------------------------------------------- getType(void) const508 const String& ZipArchiveFactory::getType(void) const 509 { 510 static String name = "Zip"; 511 return name; 512 } 513 //----------------------------------------------------------------------- 514 //----------------------------------------------------------------------- 515 // EmbeddedZipArchiveFactory 516 //----------------------------------------------------------------------- 517 //----------------------------------------------------------------------- 518 /// a struct to hold embedded file data 519 struct EmbeddedFileData 520 { 521 const uint8 * fileData; 522 zzip_size_t fileSize; 523 zzip_size_t curPos; 524 bool isFileOpened; 525 EmbeddedZipArchiveFactory::DecryptEmbeddedZipFileFunc decryptFunc; 526 }; 527 //----------------------------------------------------------------------- 528 /// A type for a map between the file names to file index 529 typedef std::map<String, int> FileNameToIndexMap; 530 typedef FileNameToIndexMap::iterator FileNameToIndexMapIter; 531 /// A type to store the embedded files data 532 typedef std::vector<EmbeddedFileData> EmbbedFileDataList; 533 534 namespace { 535 /// A static map between the file names to file index 536 FileNameToIndexMap * EmbeddedZipArchiveFactory_mFileNameToIndexMap; 537 /// A static list to store the embedded files data 538 EmbbedFileDataList * EmbeddedZipArchiveFactory_mEmbbedFileDataList; 539 _zzip_plugin_io sEmbeddedZipArchiveFactory_PluginIo; 540 #define EMBED_IO_BAD_FILE_HANDLE (-1) 541 #define EMBED_IO_SUCCESS (0) 542 //----------------------------------------------------------------------- 543 /// functions for embedded zzip_plugin_io_handlers implementation 544 /// The functions are here and not as static members because they 545 /// use types that I don't want to define in the header like zzip_char_t, 546 // zzip_ssize_t and such. 547 //----------------------------------------------------------------------- 548 // get file date by index getEmbeddedFileDataByIndex(int fd)549 EmbeddedFileData & getEmbeddedFileDataByIndex(int fd) 550 { 551 return (*EmbeddedZipArchiveFactory_mEmbbedFileDataList)[fd-1]; 552 } 553 //----------------------------------------------------------------------- 554 // opens the file EmbeddedZipArchiveFactory_open(zzip_char_t * name,int flags,...)555 int EmbeddedZipArchiveFactory_open(zzip_char_t* name, int flags, ...) 556 { 557 String nameAsString = name; 558 FileNameToIndexMapIter foundIter = EmbeddedZipArchiveFactory_mFileNameToIndexMap->find(nameAsString); 559 if (foundIter != EmbeddedZipArchiveFactory_mFileNameToIndexMap->end()) 560 { 561 int fd = foundIter->second; 562 EmbeddedFileData & curEmbeddedFileData = getEmbeddedFileDataByIndex(fd); 563 if(curEmbeddedFileData.isFileOpened) 564 { 565 // file is opened - return an error handle 566 return EMBED_IO_BAD_FILE_HANDLE; 567 } 568 569 curEmbeddedFileData.isFileOpened = true; 570 return fd; 571 } 572 else 573 { 574 // not found - return an error handle 575 return EMBED_IO_BAD_FILE_HANDLE; 576 } 577 } 578 //----------------------------------------------------------------------- 579 // Closes a file. 580 // Return Value - On success, close returns 0. EmbeddedZipArchiveFactory_close(int fd)581 int EmbeddedZipArchiveFactory_close(int fd) 582 { 583 if (fd == EMBED_IO_BAD_FILE_HANDLE) 584 { 585 // bad index - return an error 586 return -1; 587 } 588 589 EmbeddedFileData & curEmbeddedFileData = getEmbeddedFileDataByIndex(fd); 590 591 if(curEmbeddedFileData.isFileOpened == false) 592 { 593 // file is opened - return an error handle 594 return -1; 595 } 596 else 597 { 598 // success 599 curEmbeddedFileData.isFileOpened = false; 600 curEmbeddedFileData.curPos = 0; 601 return 0; 602 } 603 604 } 605 606 //----------------------------------------------------------------------- 607 // reads data from the file EmbeddedZipArchiveFactory_read(int fd,void * buf,zzip_size_t len)608 zzip_ssize_t EmbeddedZipArchiveFactory_read(int fd, void* buf, zzip_size_t len) 609 { 610 if (fd == EMBED_IO_BAD_FILE_HANDLE) 611 { 612 // bad index - return an error size - negative 613 return -1; 614 } 615 // get the current buffer in file; 616 EmbeddedFileData & curEmbeddedFileData = getEmbeddedFileDataByIndex(fd); 617 const uint8 * curFileData = curEmbeddedFileData.fileData; 618 if (len + curEmbeddedFileData.curPos > curEmbeddedFileData.fileSize) 619 { 620 len = curEmbeddedFileData.fileSize - curEmbeddedFileData.curPos; 621 } 622 curFileData += curEmbeddedFileData.curPos; 623 624 // copy to out buffer 625 memcpy(buf, curFileData, len); 626 627 if( curEmbeddedFileData.decryptFunc != NULL ) 628 { 629 if (!curEmbeddedFileData.decryptFunc(curEmbeddedFileData.curPos, buf, len)) 630 { 631 // decrypt failed - return an error size - negative 632 return -1; 633 } 634 } 635 636 // move the cursor to the new pos 637 curEmbeddedFileData.curPos += len; 638 639 return len; 640 } 641 //----------------------------------------------------------------------- 642 // Moves file pointer. EmbeddedZipArchiveFactory_seeks(int fd,zzip_off_t offset,int whence)643 zzip_off_t EmbeddedZipArchiveFactory_seeks(int fd, zzip_off_t offset, int whence) 644 { 645 if (fd == EMBED_IO_BAD_FILE_HANDLE) 646 { 647 // bad index - return an error - nonzero value. 648 return -1; 649 } 650 651 zzip_size_t newPos = -1; 652 // get the current buffer in file; 653 EmbeddedFileData & curEmbeddedFileData = getEmbeddedFileDataByIndex(fd); 654 switch(whence) 655 { 656 case SEEK_CUR: 657 newPos = (zzip_size_t)(curEmbeddedFileData.curPos + offset); 658 break; 659 case SEEK_END: 660 newPos = (zzip_size_t)(curEmbeddedFileData.fileSize - offset); 661 break; 662 case SEEK_SET: 663 newPos = (zzip_size_t)offset; 664 break; 665 default: 666 // bad whence - return an error - nonzero value. 667 return -1; 668 break; 669 }; 670 if (newPos >= curEmbeddedFileData.fileSize) 671 { 672 // bad whence - return an error - nonzero value. 673 return -1; 674 } 675 676 curEmbeddedFileData.curPos = newPos; 677 return newPos; 678 } 679 //----------------------------------------------------------------------- 680 // returns the file size EmbeddedZipArchiveFactory_filesize(int fd)681 zzip_off_t EmbeddedZipArchiveFactory_filesize(int fd) 682 { 683 if (fd == EMBED_IO_BAD_FILE_HANDLE) 684 { 685 // bad index - return an error - nonzero value. 686 return -1; 687 } 688 // get the current buffer in file; 689 EmbeddedFileData & curEmbeddedFileData = getEmbeddedFileDataByIndex(fd); 690 return curEmbeddedFileData.fileSize; 691 } 692 //----------------------------------------------------------------------- 693 // writes data to the file EmbeddedZipArchiveFactory_write(int fd,_zzip_const void * buf,zzip_size_t len)694 zzip_ssize_t EmbeddedZipArchiveFactory_write(int fd, _zzip_const void* buf, zzip_size_t len) 695 { 696 // the files in this case are read only - return an error - nonzero value. 697 return -1; 698 } 699 } // namespace { 700 //----------------------------------------------------------------------- EmbeddedZipArchiveFactory()701 EmbeddedZipArchiveFactory::EmbeddedZipArchiveFactory() 702 { 703 // init static member 704 if (gPluginIo == NULL) 705 { 706 gPluginIo = &sEmbeddedZipArchiveFactory_PluginIo; 707 gPluginIo->fd.open = EmbeddedZipArchiveFactory_open; 708 gPluginIo->fd.close = EmbeddedZipArchiveFactory_close; 709 gPluginIo->fd.read = EmbeddedZipArchiveFactory_read; 710 gPluginIo->fd.seeks = EmbeddedZipArchiveFactory_seeks; 711 gPluginIo->fd.filesize = EmbeddedZipArchiveFactory_filesize; 712 gPluginIo->fd.write = EmbeddedZipArchiveFactory_write; 713 gPluginIo->fd.sys = 1; 714 gPluginIo->fd.type = 1; 715 } 716 } 717 //----------------------------------------------------------------------- ~EmbeddedZipArchiveFactory()718 EmbeddedZipArchiveFactory::~EmbeddedZipArchiveFactory() 719 { 720 } 721 //----------------------------------------------------------------------- createInstance(const String & name,bool readOnly)722 Archive *EmbeddedZipArchiveFactory::createInstance( const String& name, bool readOnly ) 723 { 724 ZipArchive * resZipArchive = OGRE_NEW ZipArchive(name, getType(), gPluginIo); 725 return resZipArchive; 726 } 727 //----------------------------------------------------------------------- getType(void) const728 const String& EmbeddedZipArchiveFactory::getType(void) const 729 { 730 static String name = "EmbeddedZip"; 731 return name; 732 } 733 //----------------------------------------------------------------------- addEmbbeddedFile(const String & name,const uint8 * fileData,size_t fileSize,DecryptEmbeddedZipFileFunc decryptFunc)734 void EmbeddedZipArchiveFactory::addEmbbeddedFile(const String& name, const uint8 * fileData, 735 size_t fileSize, DecryptEmbeddedZipFileFunc decryptFunc) 736 { 737 static bool needToInit = true; 738 if(needToInit) 739 { 740 needToInit = false; 741 742 // we can't be sure when global variables get initialized 743 // meaning it is possible our list has not been init when this 744 // function is being called. The solution is to use local 745 // static members in this function an init the pointers for the 746 // global here. We know for use that the local static variables 747 // are create in this stage. 748 static FileNameToIndexMap sFileNameToIndexMap; 749 static EmbbedFileDataList sEmbbedFileDataList; 750 EmbeddedZipArchiveFactory_mFileNameToIndexMap = &sFileNameToIndexMap; 751 EmbeddedZipArchiveFactory_mEmbbedFileDataList = &sEmbbedFileDataList; 752 } 753 754 EmbeddedFileData newEmbeddedFileData; 755 newEmbeddedFileData.curPos = 0; 756 newEmbeddedFileData.isFileOpened = false; 757 newEmbeddedFileData.fileData = fileData; 758 newEmbeddedFileData.fileSize = fileSize; 759 newEmbeddedFileData.decryptFunc = decryptFunc; 760 EmbeddedZipArchiveFactory_mEmbbedFileDataList->push_back(newEmbeddedFileData); 761 (*EmbeddedZipArchiveFactory_mFileNameToIndexMap)[name] = static_cast<int>(EmbeddedZipArchiveFactory_mEmbbedFileDataList->size()); 762 } 763 //----------------------------------------------------------------------- removeEmbbeddedFile(const String & name)764 void EmbeddedZipArchiveFactory::removeEmbbeddedFile( const String& name ) 765 { 766 EmbeddedZipArchiveFactory_mFileNameToIndexMap->erase(name); 767 } 768 } 769 770 #endif 771