]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - plugins/archivezip/archive.cpp
Merge remote-tracking branch 'illwieckz/exportents'
[xonotic/netradiant.git] / plugins / archivezip / archive.cpp
index 1a171972c0f95163dea8e0151809c23301654b56..a8616e626daafdb51a6e76c932f5a90d4ffc9bdc 100644 (file)
@@ -1,23 +1,23 @@
 /*
-Copyright (C) 2001-2006, William Joseph.
-All Rights Reserved.
+   Copyright (C) 2001-2006, William Joseph.
+   All Rights Reserved.
 
-This file is part of GtkRadiant.
+   This file is part of GtkRadiant.
 
-GtkRadiant is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   GtkRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-GtkRadiant is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GtkRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GtkRadiant; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+   You should have received a copy of the GNU General Public License
+   along with GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 #include "idatastream.h"
 #include "cmdlib.h"
@@ -34,62 +34,54 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 class DeflatedArchiveFile : public ArchiveFile
 {
-  CopiedString m_name;
-  FileInputStream m_istream;
-  SubFileInputStream m_substream;
-  DeflatedInputStream m_zipstream;
-  FileInputStream::size_type m_size;
+CopiedString m_name;
+FileInputStream m_istream;
+SubFileInputStream m_substream;
+DeflatedInputStream m_zipstream;
+FileInputStream::size_type m_size;
 public:
-  typedef FileInputStream::size_type size_type;
-  typedef FileInputStream::position_type position_type;
-
-  DeflatedArchiveFile(const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size)
-    : m_name(name), m_istream(archiveName), m_substream(m_istream, position, stream_size), m_zipstream(m_substream), m_size(file_size)
-  {
-  }
-
-  void release()
-  {
-    delete this;
-  }
-  size_type size() const
-  {
-    return m_size;
-  }
-  const char* getName() const
-  {
-    return m_name.c_str();
-  }
-  InputStream& getInputStream()
-  {
-    return m_zipstream;
-  }
+typedef FileInputStream::size_type size_type;
+typedef FileInputStream::position_type position_type;
+
+DeflatedArchiveFile( const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size )
+       : m_name( name ), m_istream( archiveName ), m_substream( m_istream, position, stream_size ), m_zipstream( m_substream ), m_size( file_size ){
+}
+
+void release(){
+       delete this;
+}
+size_type size() const {
+       return m_size;
+}
+const char* getName() const {
+       return m_name.c_str();
+}
+InputStream& getInputStream(){
+       return m_zipstream;
+}
 };
 
 class DeflatedArchiveTextFile : public ArchiveTextFile
 {
-  CopiedString m_name;
-  FileInputStream m_istream;
-  SubFileInputStream m_substream;
-  DeflatedInputStream m_zipstream;
-  BinaryToTextInputStream<DeflatedInputStream> m_textStream;
+CopiedString m_name;
+FileInputStream m_istream;
+SubFileInputStream m_substream;
+DeflatedInputStream m_zipstream;
+BinaryToTextInputStream<DeflatedInputStream> m_textStream;
 public:
-  typedef FileInputStream::size_type size_type;
-  typedef FileInputStream::position_type position_type;
-
-  DeflatedArchiveTextFile(const char* name, const char* archiveName, position_type position, size_type stream_size)
-    : m_name(name), m_istream(archiveName), m_substream(m_istream, position, stream_size), m_zipstream(m_substream), m_textStream(m_zipstream)
-  {
-  }
-
-  void release()
-  {
-    delete this;
-  }
-  TextInputStream& getInputStream()
-  {
-    return m_textStream;
-  }
+typedef FileInputStream::size_type size_type;
+typedef FileInputStream::position_type position_type;
+
+DeflatedArchiveTextFile( const char* name, const char* archiveName, position_type position, size_type stream_size )
+       : m_name( name ), m_istream( archiveName ), m_substream( m_istream, position, stream_size ), m_zipstream( m_substream ), m_textStream( m_zipstream ){
+}
+
+void release(){
+       delete this;
+}
+TextInputStream& getInputStream(){
+       return m_textStream;
+}
 };
 
 #include "pkzip.h"
@@ -101,251 +93,222 @@ public:
 
 class ZipArchive : public Archive
 {
-  class ZipRecord
-  {
-  public:
-    enum ECompressionMode
-    {
-      eStored,
-      eDeflated,
-    };
-    ZipRecord(unsigned int position, unsigned int compressed_size, unsigned int uncompressed_size, ECompressionMode mode)
-      : m_position(position), m_stream_size(compressed_size), m_file_size(uncompressed_size), m_mode(mode)
-    {
-    }
-    unsigned int m_position;
-    unsigned int m_stream_size;
-    unsigned int m_file_size;
-    ECompressionMode m_mode;
-  };
-
-  typedef GenericFileSystem<ZipRecord> ZipFileSystem;
-  ZipFileSystem m_filesystem;
-  CopiedString m_name;
-  FileInputStream m_istream;
-
-  bool read_record()
-  {
-    zip_magic magic;
-    istream_read_zip_magic(m_istream, magic);
-    if(!(magic == zip_root_dirent_magic))
-    {
-      return false;
-    }
-    zip_version version_encoder;
-    istream_read_zip_version(m_istream, version_encoder);
-    zip_version version_extract;
-    istream_read_zip_version(m_istream, version_extract);
-    //unsigned short flags = 
-    istream_read_int16_le(m_istream);
-    unsigned short compression_mode = istream_read_int16_le(m_istream);
-    if(compression_mode != Z_DEFLATED && compression_mode != 0)
-    {
-      return false;
-    }
-    zip_dostime dostime;
-    istream_read_zip_dostime(m_istream, dostime);
-    //unsigned int crc32 = 
-    istream_read_int32_le(m_istream);
-    unsigned int compressed_size = istream_read_uint32_le(m_istream);
-    unsigned int uncompressed_size = istream_read_uint32_le(m_istream);
-    unsigned int namelength = istream_read_uint16_le(m_istream);
-    unsigned short extras = istream_read_uint16_le(m_istream);
-    unsigned short comment = istream_read_uint16_le(m_istream);
-    //unsigned short diskstart =
-    istream_read_int16_le(m_istream);
-    //unsigned short filetype = 
-    istream_read_int16_le(m_istream);
-    //unsigned int filemode =
-    istream_read_int32_le(m_istream);
-    unsigned int position = istream_read_int32_le(m_istream);
-
-    Array<char> filename(namelength+1);
-    m_istream.read(reinterpret_cast<FileInputStream::byte_type*>(filename.data()), namelength);
-    filename[namelength] = '\0';
-
-    m_istream.seek(extras + comment, FileInputStream::cur);
-
-    if(path_is_directory(filename.data()))
-    {
-      m_filesystem[filename.data()] = 0;
-    }
-    else
-    {
-      ZipFileSystem::entry_type& file = m_filesystem[filename.data()];
-      if(!file.is_directory())
-      {
-        globalOutputStream() << "Warning: zip archive " << makeQuoted(m_name.c_str()) << " contains duplicated file: " << makeQuoted(filename.data()) << "\n";
-      }
-      else
-      {
-        file = new ZipRecord(position, compressed_size, uncompressed_size, (compression_mode == Z_DEFLATED) ? ZipRecord::eDeflated : ZipRecord::eStored);
-      }
-    }
-    
-    return true;
-  }
-
-  bool read_pkzip()
-  {
-    SeekableStream::position_type pos = pkzip_find_disk_trailer(m_istream);
-    if(pos != 0)
-    {
-      zip_disk_trailer disk_trailer;
-      m_istream.seek(pos);
-      istream_read_zip_disk_trailer(m_istream, disk_trailer);
-      if(!(disk_trailer.z_magic == zip_disk_trailer_magic))
-      {
-        return false;
-      }
-
-      m_istream.seek(disk_trailer.z_rootseek);
-      for(unsigned int i = 0; i < disk_trailer.z_entries; ++i)
-      {
-        if(!read_record())
-        {
-          return false;
-        }
-      }
-      return true;
-    }
-    return false;
-  }
+class ZipRecord
+{
 public:
-  ZipArchive(const char* name)
-    : m_name(name), m_istream(name)
-  {
-    if(!m_istream.failed())
-    {
-      if(!read_pkzip())
-      {
-        globalErrorStream() << "ERROR: invalid zip-file " << makeQuoted(name) << '\n';
-      }        
-    }
-  }
-  ~ZipArchive()
-  {
-    for(ZipFileSystem::iterator i = m_filesystem.begin(); i != m_filesystem.end(); ++i)
-    {
-      delete i->second.file();
-    }
-  }
-
-  bool failed()
-  {
-    return m_istream.failed();
-  }
-
-  void release()
-  {
-    delete this;
-  }
-  ArchiveFile* openFile(const char* name)
-  {
-    ZipFileSystem::iterator i = m_filesystem.find(name);
-    if(i != m_filesystem.end() && !i->second.is_directory())
-    {
-      ZipRecord* file = i->second.file();
-
-      m_istream.seek(file->m_position);
-      zip_file_header file_header;
-      istream_read_zip_file_header(m_istream, file_header);
-      if(file_header.z_magic != zip_file_header_magic)
-      {
-        globalErrorStream() << "error reading zip file " << makeQuoted(m_name.c_str());
-        return 0;
-      }
-
-      switch(file->m_mode)
-      {
-      case ZipRecord::eStored:
-        return StoredArchiveFile::create(name, m_name.c_str(), m_istream.tell(), file->m_stream_size, file->m_file_size);
-      case ZipRecord::eDeflated:
-        return new DeflatedArchiveFile(name, m_name.c_str(), m_istream.tell(), file->m_stream_size, file->m_file_size);
-      }
-    }
-    return 0;
-  }
-  ArchiveTextFile* openTextFile(const char* name)
-  {
-    ZipFileSystem::iterator i = m_filesystem.find(name);
-    if(i != m_filesystem.end() && !i->second.is_directory())
-    {
-      ZipRecord* file = i->second.file();
-
-      m_istream.seek(file->m_position);
-      zip_file_header file_header;
-      istream_read_zip_file_header(m_istream, file_header);
-      if(file_header.z_magic != zip_file_header_magic)
-      {
-        globalErrorStream() << "error reading zip file " << makeQuoted(m_name.c_str());
-        return 0;
-      }
-
-      switch(file->m_mode)
-      {
-      case ZipRecord::eStored:
-        return StoredArchiveTextFile::create(name, m_name.c_str(), m_istream.tell(), file->m_stream_size);
-      case ZipRecord::eDeflated:
-        return new DeflatedArchiveTextFile(name, m_name.c_str(), m_istream.tell(), file->m_stream_size);
-      }
-    }
-    return 0;
-  }
-  bool containsFile(const char* name)
-  {
-    ZipFileSystem::iterator i = m_filesystem.find(name);
-    return i != m_filesystem.end() && !i->second.is_directory();
-  }
-  void forEachFile(VisitorFunc visitor, const char* root)
-  {
-    m_filesystem.traverse(visitor, root);
-  }
+enum ECompressionMode
+{
+       eStored,
+       eDeflated,
+};
+ZipRecord( unsigned int position, unsigned int compressed_size, unsigned int uncompressed_size, ECompressionMode mode )
+       : m_position( position ), m_stream_size( compressed_size ), m_file_size( uncompressed_size ), m_mode( mode ){
+}
+unsigned int m_position;
+unsigned int m_stream_size;
+unsigned int m_file_size;
+ECompressionMode m_mode;
 };
 
-Archive* OpenArchive(const char* name)
-{
-  return new ZipArchive(name);
+typedef GenericFileSystem<ZipRecord> ZipFileSystem;
+ZipFileSystem m_filesystem;
+CopiedString m_name;
+FileInputStream m_istream;
+
+bool read_record(){
+       zip_magic magic;
+       istream_read_zip_magic( m_istream, magic );
+       if ( !( magic == zip_root_dirent_magic ) ) {
+               return false;
+       }
+       zip_version version_encoder;
+       istream_read_zip_version( m_istream, version_encoder );
+       zip_version version_extract;
+       istream_read_zip_version( m_istream, version_extract );
+       //unsigned short flags =
+       istream_read_int16_le( m_istream );
+       unsigned short compression_mode = istream_read_int16_le( m_istream );
+       if ( compression_mode != Z_DEFLATED && compression_mode != 0 ) {
+               return false;
+       }
+       zip_dostime dostime;
+       istream_read_zip_dostime( m_istream, dostime );
+       //unsigned int crc32 =
+       istream_read_int32_le( m_istream );
+       unsigned int compressed_size = istream_read_uint32_le( m_istream );
+       unsigned int uncompressed_size = istream_read_uint32_le( m_istream );
+       unsigned int namelength = istream_read_uint16_le( m_istream );
+       unsigned short extras = istream_read_uint16_le( m_istream );
+       unsigned short comment = istream_read_uint16_le( m_istream );
+       //unsigned short diskstart =
+       istream_read_int16_le( m_istream );
+       //unsigned short filetype =
+       istream_read_int16_le( m_istream );
+       //unsigned int filemode =
+       istream_read_int32_le( m_istream );
+       unsigned int position = istream_read_int32_le( m_istream );
+
+       Array<char> filename( namelength + 1 );
+       m_istream.read( reinterpret_cast<FileInputStream::byte_type*>( filename.data() ), namelength );
+       filename[namelength] = '\0';
+
+       m_istream.seek( extras + comment, FileInputStream::cur );
+
+       if ( path_is_directory( filename.data() ) ) {
+               m_filesystem[filename.data()] = 0;
+       }
+       else
+       {
+               ZipFileSystem::entry_type& file = m_filesystem[filename.data()];
+               if ( !file.is_directory() ) {
+                       globalOutputStream() << "Warning: zip archive " << makeQuoted( m_name.c_str() ) << " contains duplicated file: " << makeQuoted( filename.data() ) << "\n";
+               }
+               else
+               {
+                       file = new ZipRecord( position, compressed_size, uncompressed_size, ( compression_mode == Z_DEFLATED ) ? ZipRecord::eDeflated : ZipRecord::eStored );
+               }
+       }
+
+       return true;
+}
+
+bool read_pkzip(){
+       SeekableStream::position_type pos = pkzip_find_disk_trailer( m_istream );
+       if ( pos != 0 ) {
+               zip_disk_trailer disk_trailer;
+               m_istream.seek( pos );
+               istream_read_zip_disk_trailer( m_istream, disk_trailer );
+               if ( !( disk_trailer.z_magic == zip_disk_trailer_magic ) ) {
+                       return false;
+               }
+
+               m_istream.seek( disk_trailer.z_rootseek );
+               for ( unsigned int i = 0; i < disk_trailer.z_entries; ++i )
+               {
+                       if ( !read_record() ) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+       return false;
+}
+public:
+ZipArchive( const char* name )
+       : m_name( name ), m_istream( name ){
+       if ( !m_istream.failed() ) {
+               if ( !read_pkzip() ) {
+                       globalErrorStream() << "ERROR: invalid zip-file " << makeQuoted( name ) << '\n';
+               }
+       }
+}
+~ZipArchive(){
+       for ( ZipFileSystem::iterator i = m_filesystem.begin(); i != m_filesystem.end(); ++i )
+       {
+               delete i->second.file();
+       }
+}
+
+bool failed(){
+       return m_istream.failed();
+}
+
+void release(){
+       delete this;
+}
+ArchiveFile* openFile( const char* name ){
+       ZipFileSystem::iterator i = m_filesystem.find( name );
+       if ( i != m_filesystem.end() && !i->second.is_directory() ) {
+               ZipRecord* file = i->second.file();
+
+               m_istream.seek( file->m_position );
+               zip_file_header file_header;
+               istream_read_zip_file_header( m_istream, file_header );
+               if ( file_header.z_magic != zip_file_header_magic ) {
+                       globalErrorStream() << "error reading zip file " << makeQuoted( m_name.c_str() );
+                       return 0;
+               }
+
+               switch ( file->m_mode )
+               {
+               case ZipRecord::eStored:
+                       return StoredArchiveFile::create( name, m_name.c_str(), m_istream.tell(), file->m_stream_size, file->m_file_size );
+               case ZipRecord::eDeflated:
+                       return new DeflatedArchiveFile( name, m_name.c_str(), m_istream.tell(), file->m_stream_size, file->m_file_size );
+               }
+       }
+       return 0;
+}
+ArchiveTextFile* openTextFile( const char* name ){
+       ZipFileSystem::iterator i = m_filesystem.find( name );
+       if ( i != m_filesystem.end() && !i->second.is_directory() ) {
+               ZipRecord* file = i->second.file();
+
+               m_istream.seek( file->m_position );
+               zip_file_header file_header;
+               istream_read_zip_file_header( m_istream, file_header );
+               if ( file_header.z_magic != zip_file_header_magic ) {
+                       globalErrorStream() << "error reading zip file " << makeQuoted( m_name.c_str() );
+                       return 0;
+               }
+
+               switch ( file->m_mode )
+               {
+               case ZipRecord::eStored:
+                       return StoredArchiveTextFile::create( name, m_name.c_str(), m_istream.tell(), file->m_stream_size );
+               case ZipRecord::eDeflated:
+                       return new DeflatedArchiveTextFile( name, m_name.c_str(), m_istream.tell(), file->m_stream_size );
+               }
+       }
+       return 0;
+}
+bool containsFile( const char* name ){
+       ZipFileSystem::iterator i = m_filesystem.find( name );
+       return i != m_filesystem.end() && !i->second.is_directory();
+}
+void forEachFile( VisitorFunc visitor, const char* root ){
+       m_filesystem.traverse( visitor, root );
+}
+};
+
+Archive* OpenArchive( const char* name ){
+       return new ZipArchive( name );
 }
 
 #if 0
 
 class TestZip
 {
-  class TestVisitor : public Archive::IVisitor
-  {
-  public:
-    void visit(const char* name)
-    {
-      int bleh = 0;
-    }
-  };
+class TestVisitor : public Archive::IVisitor
+{
+public:
+void visit( const char* name ){
+       int bleh = 0;
+}
+};
 public:
-  TestZip()
-  {
-    testzip("c:/quake3/baseq3/mapmedia.pk3", "textures/radiant/notex.tga");
-  }
-
-  void testzip(const char* name, const char* filename)
-  {
-    Archive* archive = OpenArchive(name);
-    ArchiveFile* file = archive->openFile(filename);
-    if(file != 0)
-    {
-      unsigned char buffer[4096];
-      std::size_t count = file->getInputStream().read((InputStream::byte_type*)buffer, 4096);
-      file->release();
-    }
-    TestVisitor visitor;
-    archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 0), "");
-    archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "");
-    archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFiles, 1), "");
-    archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eDirectories, 1), "");
-    archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "textures");
-    archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "textures/");
-    archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 2), "");
-    archive->release();
-  }
+TestZip(){
+       testzip( "c:/quake3/baseq3/mapmedia.pk3", "textures/radiant/notex.tga" );
+}
+
+void testzip( const char* name, const char* filename ){
+       Archive* archive = OpenArchive( name );
+       ArchiveFile* file = archive->openFile( filename );
+       if ( file != 0 ) {
+               unsigned char buffer[4096];
+               std::size_t count = file->getInputStream().read( (InputStream::byte_type*)buffer, 4096 );
+               file->release();
+       }
+       TestVisitor visitor;
+       archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "" );
+       archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "" );
+       archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFiles, 1 ), "" );
+       archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eDirectories, 1 ), "" );
+       archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "textures" );
+       archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "textures/" );
+       archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 2 ), "" );
+       archive->release();
+}
 };
 
 TestZip g_TestZip;