1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12 */
13 
14 #include "ZipArchive.h"
15 
16 #include <osgDB/FileUtils>
17 #include <osgDB/FileNameUtils>
18 #include <osgDB/ReadFile>
19 #include <osgDB/Registry>
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 
24 #include <sstream>
25 #include <cstdio>
26 #include "unzip.h"
27 
28 #if !defined(S_ISDIR)
29 #  if defined( _S_IFDIR) && !defined( __S_IFDIR)
30 #    define __S_IFDIR _S_IFDIR
31 #  endif
32 #  define S_ISDIR(mode)    (mode&__S_IFDIR)
33 #endif
34 
35 #ifndef S_ISREG
36 #define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
37 #endif
38 
39 
ZipArchive()40 ZipArchive::ZipArchive()  :
41 _zipLoaded( false )
42 {
43 }
44 
~ZipArchive()45 ZipArchive::~ZipArchive()
46 {
47 }
48 
49 /** close the archive (on all threads) */
close()50 void ZipArchive::close()
51 {
52     if ( _zipLoaded )
53     {
54         OpenThreads::ScopedLock<OpenThreads::Mutex> exclusive(_zipMutex);
55         if ( _zipLoaded )
56         {
57             // close the file (on one thread since it's a shared file)
58             const PerThreadData& data = getDataNoLock();
59             CloseZip( data._zipHandle );
60 
61             // clear out the file handles
62             _perThreadData.clear();
63 
64             // clear out the index.
65             _zipIndex.clear();
66 
67             _zipLoaded = false;
68         }
69     }
70 }
71 
72 /** return true if file exists in archive.*/
fileExists(const std::string & filename) const73 bool ZipArchive::fileExists(const std::string& filename) const
74 {
75     return GetZipEntry(filename) != NULL;
76 }
77 
78 /** Get the file name which represents the master file recorded in the Archive.*/
getMasterFileName() const79 std::string ZipArchive::getMasterFileName() const
80 {
81     return std::string();
82 }
83 
getArchiveFileName() const84 std::string ZipArchive::getArchiveFileName() const
85 {
86     std::string result;
87     if( _zipLoaded )
88     {
89         result = _mainRecord.name;
90     }
91     return result;
92 }
93 
94 /** Get the full list of file names available in the archive.*/
getFileNames(osgDB::Archive::FileNameList & fileNameList) const95 bool ZipArchive::getFileNames(osgDB::Archive::FileNameList& fileNameList) const
96 {
97     if(_zipLoaded)
98     {
99         ZipEntryMap::const_iterator iter = _zipIndex.begin();
100 
101         for(;iter != _zipIndex.end(); ++iter)
102         {
103             fileNameList.push_back((*iter).first);
104         }
105 
106         return true;
107     }
108     else
109     {
110         return false;
111     }
112 }
113 
open(const std::string & file,ArchiveStatus,const osgDB::ReaderWriter::Options * options)114 bool ZipArchive::open(const std::string& file, ArchiveStatus /*status*/, const osgDB::ReaderWriter::Options* options)
115 {
116     if ( !_zipLoaded )
117     {
118         // exclusive lock when we open for the first time:
119         OpenThreads::ScopedLock<OpenThreads::Mutex> exclusiveLock( _zipMutex );
120 
121         if ( !_zipLoaded ) // double-check avoids race condition
122         {
123             std::string ext = osgDB::getLowerCaseFileExtension(file);
124             if (!acceptsExtension(ext)) return false;
125 
126             // save the filename + password so other threads can open the file
127             _filename = osgDB::findDataFile( file, options );
128             if (_filename.empty()) return false;
129 
130             _password = ReadPassword(options);
131 
132             // open the zip file in this thread:
133             const PerThreadData& data = getDataNoLock();
134 
135             // establish a shared (read-only) index:
136             if ( data._zipHandle != NULL )
137             {
138                 IndexZipFiles( data._zipHandle );
139                 _zipLoaded = true;
140             }
141         }
142     }
143 
144     return _zipLoaded;
145 }
146 
open(std::istream & fin,const osgDB::ReaderWriter::Options * options)147 bool ZipArchive::open(std::istream& fin, const osgDB::ReaderWriter::Options* options)
148 {
149     if ( !_zipLoaded )
150     {
151         // exclusive lock when we open for the first time:
152         OpenThreads::ScopedLock<OpenThreads::Mutex> exclusive(_zipMutex);
153 
154         if ( !_zipLoaded ) // double-check avoids race condition
155         {
156             osgDB::ReaderWriter::ReadResult result = osgDB::ReaderWriter::ReadResult(osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED);
157 
158             if (fin.fail()) return false;
159 
160             // read the stream into a memory buffer that we'll keep around for any other
161             // threads that want to open the file
162             std::stringstream buf;
163             buf << fin.rdbuf();
164             _membuffer = buf.str();
165 
166             _password = ReadPassword(options);
167 
168             // open on this thread:
169             const PerThreadData& data = getDataNoLock();
170 
171             if ( data._zipHandle != NULL )
172             {
173                 IndexZipFiles( data._zipHandle );
174                 _zipLoaded = true;
175             }
176         }
177     }
178 
179     return _zipLoaded;
180 }
181 
readObject(const std::string & file,const osgDB::ReaderWriter::Options * options) const182 osgDB::ReaderWriter::ReadResult ZipArchive::readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
183 {
184     osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
185 
186     std::string ext = osgDB::getLowerCaseFileExtension(file);
187     if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
188 
189     const ZIPENTRY* ze = GetZipEntry(file);
190     if(ze != NULL)
191     {
192         std::stringstream buffer;
193 
194         osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer);
195         if (rw != NULL)
196         {
197             // Setup appropriate options
198             osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ?
199             static_cast<osgDB::ReaderWriter::Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) :
200             new osgDB::ReaderWriter::Options;
201 
202             local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name));
203 
204             osgDB::ReaderWriter::ReadResult readResult = rw->readObject(buffer,local_opt.get());
205             if (readResult.success())
206             {
207                 return readResult;
208             }
209         }
210     }
211 
212     return rresult;
213 }
214 
readImage(const std::string & file,const osgDB::ReaderWriter::Options * options) const215 osgDB::ReaderWriter::ReadResult ZipArchive::readImage(const std::string& file,const osgDB::ReaderWriter::Options* options) const
216 {
217     osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
218 
219     std::string ext = osgDB::getLowerCaseFileExtension(file);
220     if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
221 
222     const ZIPENTRY* ze = GetZipEntry(file);
223     if(ze != NULL)
224     {
225         std::stringstream buffer;
226 
227         osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer);
228         if (rw != NULL)
229         {
230             // Setup appropriate options
231             osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ?
232             static_cast<osgDB::ReaderWriter::Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) :
233             new osgDB::ReaderWriter::Options;
234 
235             local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name));
236 
237             osgDB::ReaderWriter::ReadResult readResult = rw->readImage(buffer,local_opt.get());
238             if (readResult.success())
239             {
240                 return readResult;
241             }
242         }
243     }
244 
245    return rresult;
246 }
247 
readHeightField(const std::string & file,const osgDB::ReaderWriter::Options * options) const248 osgDB::ReaderWriter::ReadResult ZipArchive::readHeightField(const std::string& file,const osgDB::ReaderWriter::Options* options) const
249 {
250     osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
251 
252     std::string ext = osgDB::getLowerCaseFileExtension(file);
253     if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
254 
255     const ZIPENTRY* ze = GetZipEntry(file);
256     if(ze != NULL)
257     {
258         std::stringstream buffer;
259 
260         osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer);
261         if (rw != NULL)
262         {
263             // Setup appropriate options
264             osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ?
265             options->cloneOptions() :
266             new osgDB::ReaderWriter::Options;
267 
268             local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name));
269 
270             osgDB::ReaderWriter::ReadResult readResult = rw->readObject(buffer,local_opt.get());
271             if (readResult.success())
272             {
273                 return readResult;
274             }
275         }
276     }
277 
278     return rresult;
279 }
280 
readNode(const std::string & file,const osgDB::ReaderWriter::Options * options) const281 osgDB::ReaderWriter::ReadResult ZipArchive::readNode(const std::string& file,const osgDB::ReaderWriter::Options* options) const
282 {
283     osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
284 
285     std::string ext = osgDB::getLowerCaseFileExtension(file);
286     if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
287 
288     const ZIPENTRY* ze = GetZipEntry(file);
289     if(ze != NULL)
290     {
291         std::stringstream buffer;
292 
293         osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer);
294         if (rw != NULL)
295         {
296             // Setup appropriate options
297             osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ?
298                 options->cloneOptions() :
299                 new osgDB::ReaderWriter::Options;
300 
301             local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name));
302 
303             osgDB::ReaderWriter::ReadResult readResult = rw->readNode(buffer,local_opt.get());
304             if (readResult.success())
305             {
306                 return readResult;
307             }
308         }
309     }
310 
311     return rresult;
312 }
313 
readScript(const std::string & file,const osgDB::ReaderWriter::Options * options) const314 osgDB::ReaderWriter::ReadResult ZipArchive::readScript(const std::string& file,const osgDB::ReaderWriter::Options* options) const
315 {
316     osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
317 
318     std::string ext = osgDB::getLowerCaseFileExtension(file);
319     if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
320 
321     const ZIPENTRY* ze = GetZipEntry(file);
322     if (ze != NULL)
323     {
324         std::stringstream buffer;
325 
326         osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer);
327         if (rw != NULL)
328         {
329             // Setup appropriate options
330             osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ?
331                 options->cloneOptions() :
332                 new osgDB::ReaderWriter::Options;
333 
334             local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name));
335 
336             osgDB::ReaderWriter::ReadResult readResult = rw->readScript(buffer,local_opt.get());
337             if (readResult.success())
338             {
339                 return readResult;
340             }
341         }
342     }
343 
344     return rresult;
345 }
346 
readShader(const std::string & file,const osgDB::ReaderWriter::Options * options) const347 osgDB::ReaderWriter::ReadResult ZipArchive::readShader(const std::string& file,const osgDB::ReaderWriter::Options* options) const
348 {
349     osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
350 
351     std::string ext = osgDB::getLowerCaseFileExtension(file);
352     if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
353 
354     const ZIPENTRY* ze = GetZipEntry(file);
355     if(ze != NULL)
356     {
357         std::stringstream buffer;
358 
359         osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer);
360         if (rw != NULL)
361         {
362             // Setup appropriate options
363             osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ?
364                 options->cloneOptions() :
365                 new osgDB::ReaderWriter::Options;
366 
367             local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name));
368 
369             osgDB::ReaderWriter::ReadResult readResult = rw->readShader(buffer,local_opt.get());
370             if (readResult.success())
371             {
372                 return readResult;
373             }
374         }
375     }
376 
377     return rresult;
378 }
379 
writeObject(const osg::Object &,const std::string &,const osgDB::ReaderWriter::Options *) const380 osgDB::ReaderWriter::WriteResult ZipArchive::writeObject(const osg::Object& /*obj*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const
381 {
382     return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED);
383 }
384 
writeScript(const osg::Script &,const std::string &,const osgDB::ReaderWriter::Options *) const385 osgDB::ReaderWriter::WriteResult ZipArchive::writeScript(const osg::Script& /*obj*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const
386 {
387     return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED);
388 }
389 
writeImage(const osg::Image &,const std::string &,const osgDB::ReaderWriter::Options *) const390 osgDB::ReaderWriter::WriteResult ZipArchive::writeImage(const osg::Image& /*image*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const
391 {
392     return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED);
393 }
394 
writeHeightField(const osg::HeightField &,const std::string &,const osgDB::ReaderWriter::Options *) const395 osgDB::ReaderWriter::WriteResult ZipArchive::writeHeightField(const osg::HeightField& /*heightField*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const
396 {
397     return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED);
398 }
399 
writeNode(const osg::Node &,const std::string &,const osgDB::ReaderWriter::Options *) const400 osgDB::ReaderWriter::WriteResult ZipArchive::writeNode(const osg::Node& /*node*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const
401 {
402     return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED);
403 }
404 
writeShader(const osg::Shader &,const std::string &,const osgDB::ReaderWriter::Options *) const405 osgDB::ReaderWriter::WriteResult ZipArchive::writeShader(const osg::Shader& /*shader*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const
406 {
407     return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED);
408 }
409 
410 
ReadFromZipEntry(const ZIPENTRY * ze,const osgDB::ReaderWriter::Options *,std::stringstream & buffer) const411 osgDB::ReaderWriter* ZipArchive::ReadFromZipEntry(const ZIPENTRY* ze, const osgDB::ReaderWriter::Options* /*options*/, std::stringstream& buffer) const
412 {
413     if (ze != 0)
414     {
415         char* ibuf = new (std::nothrow) char[ze->unc_size];
416         if (ibuf)
417         {
418             // fetch the handle for the current thread:
419             const PerThreadData& data = getData();
420             if ( data._zipHandle != NULL )
421             {
422                 ZRESULT result = UnzipItem(data._zipHandle, ze->index, ibuf, ze->unc_size);
423                 bool unzipSuccesful = CheckZipErrorCode(result);
424                 if(unzipSuccesful)
425                 {
426                     buffer.write(ibuf,ze->unc_size);
427                 }
428 
429                 delete[] ibuf;
430 
431                 std::string file_ext = osgDB::getFileExtension(ze->name);
432 
433                 osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(file_ext);
434                 if (rw != NULL)
435                 {
436                     return rw;
437                 }
438             }
439             else
440             {
441                 delete[] ibuf;
442             }
443         }
444         else
445         {
446             //std::cout << "Error- failed to allocate enough memory to unzip file '" << ze->name << ", with size '" << ze->unc_size << std::endl;
447         }
448     }
449 
450     return NULL;
451 }
452 
CleanupFileString(std::string & strFileOrDir)453 void CleanupFileString(std::string& strFileOrDir)
454 {
455     if (strFileOrDir.empty())
456     {
457         return;
458     }
459 
460     // convert all separators to unix-style for conformity
461     for (unsigned int i = 0; i < strFileOrDir.length(); ++i)
462     {
463         if (strFileOrDir[i] == '\\')
464         {
465             strFileOrDir[i] = '/';
466         }
467     }
468 
469     // get rid of trailing separators
470     if (strFileOrDir[strFileOrDir.length()-1] == '/')
471     {
472         strFileOrDir = strFileOrDir.substr(0, strFileOrDir.length()-1);
473     }
474 
475     //add a beginning separator
476     if(strFileOrDir[0] != '/')
477     {
478         strFileOrDir.insert(0, "/");
479     }
480 }
481 
IndexZipFiles(HZIP hz)482 void ZipArchive::IndexZipFiles(HZIP hz)
483 {
484     if(hz != NULL && !_zipLoaded)
485     {
486         //mZipRecord = hz;
487 
488         GetZipItem(hz, -1, &_mainRecord);
489         int numitems = _mainRecord.index;
490 
491         // Now loop through each file in zip
492         for (int i = 0; i < numitems; i++)
493         {
494             ZIPENTRY* ze = new ZIPENTRY();
495 
496             GetZipItem(hz, i, ze);
497             std::string name = ze->name;
498 
499             CleanupFileString(name);
500 
501             if(!name.empty())
502             {
503                 _zipIndex.insert(ZipEntryMapping(name, ze));
504             }
505             else
506             {
507                 // ze isn't being used to delete it
508                 delete ze;
509             }
510         }
511     }
512 }
513 
GetZipEntry(const std::string & filename)514 ZIPENTRY* ZipArchive::GetZipEntry(const std::string& filename)
515 {
516     ZIPENTRY* ze = NULL;
517     std::string fileToLoad = filename;
518     CleanupFileString(fileToLoad);
519 
520     ZipEntryMap::iterator iter = _zipIndex.find(fileToLoad);
521     if(iter != _zipIndex.end())
522     {
523         ze = (*iter).second;
524     }
525 
526     return ze;
527 }
528 
GetZipEntry(const std::string & filename) const529 const ZIPENTRY* ZipArchive::GetZipEntry(const std::string& filename) const
530 {
531     ZIPENTRY* ze = NULL;
532     std::string fileToLoad = filename;
533     CleanupFileString(fileToLoad);
534 
535     ZipEntryMap::const_iterator iter = _zipIndex.find(fileToLoad);
536     if(iter != _zipIndex.end())
537     {
538         ze = (*iter).second;
539     }
540 
541     return ze;
542 }
543 
getFileType(const std::string & filename) const544 osgDB::FileType ZipArchive::getFileType(const std::string& filename) const
545 {
546     const ZIPENTRY* ze = GetZipEntry(filename);
547     if(ze != NULL)
548     {
549     #ifdef ZIP_STD
550         if (ze->attr & S_IFDIR)
551     #else
552         if (ze->attr & FILE_ATTRIBUTE_DIRECTORY)
553     #endif
554         {
555             return osgDB::DIRECTORY;
556         }
557         else
558         {
559             return osgDB::REGULAR_FILE;
560         }
561     }
562 
563     return osgDB::FILE_NOT_FOUND;
564 }
565 
getDirectoryContents(const std::string & dirName) const566 osgDB::DirectoryContents ZipArchive::getDirectoryContents(const std::string& dirName) const
567 {
568     osgDB::DirectoryContents dirContents;
569 
570     ZipEntryMap::const_iterator iter = _zipIndex.begin();
571     ZipEntryMap::const_iterator iterEnd = _zipIndex.end();
572 
573     for(; iter != iterEnd; ++iter)
574     {
575         std::string searchPath = dirName;
576         CleanupFileString(searchPath);
577 
578         if(iter->first.size() > searchPath.size())
579         {
580             size_t endSubElement = iter->first.find(searchPath);
581 
582             //we match the whole string in the beginning of the path
583             if(endSubElement == 0)
584             {
585                 std::string remainingFile = iter->first.substr(searchPath.size() + 1, std::string::npos);
586                 size_t endFileToken = remainingFile.find_first_of('/');
587 
588                 if(endFileToken == std::string::npos)
589                 {
590                     dirContents.push_back(remainingFile);
591                 }
592             }
593         }
594     }
595 
596     return dirContents;
597 }
598 
ReadPassword(const osgDB::ReaderWriter::Options * options) const599 std::string ZipArchive::ReadPassword(const osgDB::ReaderWriter::Options* options) const
600 {
601     //try pulling it off the options first
602     std::string password = "";
603     if(options != NULL)
604     {
605         const osgDB::AuthenticationMap* credentials = options->getAuthenticationMap();
606         if(credentials != NULL)
607         {
608             const osgDB::AuthenticationDetails* details = credentials->getAuthenticationDetails("ZipPlugin");
609             if(details != NULL)
610             {
611                 password = details->password;
612             }
613         }
614     }
615 
616     //if no password, try the registry
617     if(password.empty())
618     {
619         osgDB::Registry* reg = osgDB::Registry::instance();
620         if(reg != NULL)
621         {
622             const osgDB::AuthenticationMap* credentials = reg->getAuthenticationMap();
623             if(credentials != NULL)
624             {
625                 const osgDB::AuthenticationDetails* details = credentials->getAuthenticationDetails("ZipPlugin");
626                 if(details != NULL)
627                 {
628                     password = details->password;
629                 }
630             }
631         }
632     }
633 
634     return password;
635 }
636 
CheckZipErrorCode(ZRESULT result) const637 bool ZipArchive::CheckZipErrorCode(ZRESULT result) const
638 {
639     if(result == ZR_OK)
640     {
641         return true;
642     }
643     else
644     {
645         unsigned buf_size  = 1025;
646         char* buf = new (std::nothrow) char[buf_size];
647         if (buf)
648         {
649             buf[buf_size - 1] = 0;
650 
651             FormatZipMessage(result, buf, buf_size - 1);
652 
653             //print error message
654             //sprintf(buf, "%s");
655             OSG_WARN << "Error loading zip file: " << getArchiveFileName() << ", Zip loader returned error: " << buf << "\n";
656             delete [] buf;
657         }
658 
659         return false;
660     }
661 }
662 
663 const ZipArchive::PerThreadData&
getData() const664 ZipArchive::getData() const
665 {
666     OpenThreads::ScopedLock<OpenThreads::Mutex> exclusive( const_cast<ZipArchive*>(this)->_zipMutex );
667     return getDataNoLock();
668 }
669 
670 
671 const ZipArchive::PerThreadData&
getDataNoLock() const672 ZipArchive::getDataNoLock() const
673 {
674     // get/create data for the currently running thread:
675     size_t current = OpenThreads::Thread::CurrentThreadId();
676 
677     PerThreadDataMap::const_iterator i = _perThreadData.find( current );
678 
679     if ( i == _perThreadData.end() || i->second._zipHandle == NULL )
680     {
681         // cache pattern: cast to const for caching purposes
682         ZipArchive* ncThis = const_cast<ZipArchive*>(this);
683 
684         // data does not already exist, so open the ZIP with a handle exclusively for this thread:
685         PerThreadData& data = ncThis->_perThreadData[current];
686         if ( !_filename.empty() )
687         {
688             data._zipHandle = OpenZip( _filename.c_str(), _password.c_str() );
689         }
690         else if ( !_membuffer.empty() )
691         {
692             data._zipHandle = OpenZip( (void*)_membuffer.c_str(), _membuffer.length(), _password.c_str() );
693         }
694         else
695         {
696             data._zipHandle = NULL;
697         }
698         return data;
699     }
700     else
701     {
702         return i->second;
703     }
704 }
705