bool ZipArchive::copyFileToNewZip(CentralDir *cdir, Stream *newZipStream)
{
   // [tom, 1/24/2007] Using the stored compressor allows us to copy the raw
   // data regardless of compression method without having to re-compress it.
   Compressor *comp = Compressor::findCompressor(Stored);
   if(comp == NULL)
      return false;

   if(! mStream->setPosition(cdir->mLocalHeadOffset))
      return false;

   // Copy file header
   // FIXME [tom, 1/24/2007] This will currently not copy the extra fields
   FileHeader fh;
   if(! fh.read(mStream))
      return false;

   cdir->mLocalHeadOffset = newZipStream->getPosition();

   if(! fh.write(newZipStream))
      return false;

   // Copy file data
   Stream *readS = comp->createReadStream(cdir, mStream);
   if(readS == NULL)
      return false;

   bool ret = newZipStream->copyFrom(readS);

   // [tom, 1/24/2007] closeFile() just frees the relevant filters and
   // thus it is safe to call from here.
   closeFile(readS);

   return ret;
}
Stream *ZipArchive::openFileForRead(const CentralDir *fileCD)
{
   if(mMode != Read && mMode != ReadWrite)
      return NULL;

   if((fileCD->mInternalFlags & (CDFileDeleted | CDFileOpen)) != 0)
      return NULL;

   Stream *stream = mStream;

   if(fileCD->mInternalFlags & CDFileDirty)
   {
      // File is dirty, we need to read from the temporary file
      for(S32 i = 0;i < mTempFiles.size();++i)
      {
         if(mTempFiles[i]->getCentralDir() == fileCD)
         {
            // Found the temporary file
            if(! mTempFiles[i]->rewind())
            {
               if(isVerbose())
                  Con::errorf("ZipArchive::openFile - %s: %s is dirty, but could not rewind temporary file?", mFilename ? mFilename : "<no filename>", fileCD->mFilename.c_str());
               return NULL;
            }

            stream = mTempFiles[i];
            break;
         }
      }

      if(stream == mStream)
      {
         if(isVerbose())
            Con::errorf("ZipArchive::openFile - %s: %s is dirty, but no temporary file found?", mFilename ? mFilename : "<no filename>", fileCD->mFilename.c_str());
         return NULL;
      }
   }
   else
   {
      // Read from the zip file directly
      if(! mStream->setPosition(fileCD->mLocalHeadOffset))
      {
         if(isVerbose())
            Con::errorf("ZipArchive::openFile - %s: Could not locate local header for file %s", mFilename ? mFilename : "<no filename>", fileCD->mFilename.c_str());
         return NULL;
      }

      FileHeader fh;
      if(! fh.read(mStream))
      {
         if(isVerbose())
            Con::errorf("ZipArchive::openFile - %s: Could not read local header for file %s", mFilename ? mFilename : "<no filename>", fileCD->mFilename.c_str());
         return NULL;
      }
   }

   Stream *attachTo = stream;
   U16 compMethod = fileCD->mCompressMethod;

   if(fileCD->mFlags & Encrypted)
   {
      if(fileCD->mCompressMethod == AESEncrypted)
      {
         // [tom, 1/19/2007] Whilst AES support does exist, I'm not including it in TGB
         // to avoid having to deal with crypto export legal issues.
         Con::errorf("ZipArchive::openFile - %s: File %s is AES encrypted, but AES is not supported in this version.", mFilename ? mFilename : "<no filename>", fileCD->mFilename.c_str());
      }
      else
      {
         ZipCryptRStream *cryptStream = new ZipCryptRStream;
         cryptStream->setPassword(DEFAULT_ZIP_PASSWORD);
         cryptStream->setFileEndPos(stream->getPosition() + fileCD->mCompressedSize);
         if(! cryptStream->attachStream(stream))
         {
            delete cryptStream;
            return NULL;
         }

         attachTo = cryptStream;
      }
   }

   Compressor *comp = Compressor::findCompressor(compMethod);
   if(comp == NULL)
   {
      if(isVerbose())
         Con::errorf("ZipArchive::openFile - %s: Unsupported compression method (%d) for file %s", mFilename ? mFilename : "<no filename>", fileCD->mCompressMethod, fileCD->mFilename.c_str());
      return NULL;
   }

   return comp->createReadStream(fileCD, attachTo);
}