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