pkzip.h

Go to the documentation of this file.
00001 /*
00002  Copyright (C) 2001-2006, William Joseph.
00003  All Rights Reserved.
00004 
00005  This file is part of GtkRadiant.
00006 
00007  GtkRadiant is free software; you can redistribute it and/or modify
00008  it under the terms of the GNU General Public License as published by
00009  the Free Software Foundation; either version 2 of the License, or
00010  (at your option) any later version.
00011 
00012  GtkRadiant is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU General Public License for more details.
00016 
00017  You should have received a copy of the GNU General Public License
00018  along with GtkRadiant; if not, write to the Free Software
00019  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00021 
00022 #if !defined(INCLUDED_PKZIP_H)
00023 #define INCLUDED_PKZIP_H
00024 
00025 #include "bytestreamutils.h"
00026 #include "idatastream.h"
00027 #include <algorithm>
00028 
00029 class zip_magic
00030 {
00031     public:
00032         bool operator== (const zip_magic& other) const
00033         {
00034             return m_value[0] == other.m_value[0] && m_value[1] == other.m_value[1] && m_value[2] == other.m_value[2]
00035                     && m_value[3] == other.m_value[3];
00036         }
00037         bool operator!= (const zip_magic& other) const
00038         {
00039             return !(*this == other);
00040         }
00041         char m_value[4];
00042 };
00043 
00044 inline void istream_read_zip_magic (InputStream& istream, zip_magic& magic)
00045 {
00046     istream.read(reinterpret_cast<InputStream::byte_type*> (magic.m_value), 4);
00047 }
00048 
00049 struct zip_version
00050 {
00051         char version;
00052         char ostype;
00053 };
00054 
00055 inline void istream_read_zip_version (InputStream& istream, zip_version& version)
00056 {
00057     version.version = istream_read_byte(istream);
00058     version.ostype = istream_read_byte(istream);
00059 }
00060 
00061 struct zip_dostime
00062 {
00063         unsigned short time;
00064         unsigned short date;
00065 };
00066 
00067 inline void istream_read_zip_dostime (InputStream& istream, zip_dostime& dostime)
00068 {
00069     dostime.time = istream_read_int16_le(istream);
00070     dostime.date = istream_read_int16_le(istream);
00071 }
00072 
00073 const zip_magic zip_file_header_magic = { { 'P', 'K', 0x03, 0x04 } };
00074 
00075 /* A. Local file header */
00076 struct zip_file_header
00077 {
00078         zip_magic z_magic; /* local file header signature (0x04034b50) */
00079         zip_version z_extract; /* version needed to extract */
00080         unsigned short z_flags; /* general purpose bit flag */
00081         unsigned short z_compr; /* compression method */
00082         zip_dostime z_dostime; /* last mod file time (dos format) */
00083         unsigned int z_crc32; /* crc-32 */
00084         unsigned int z_csize; /* compressed size */
00085         unsigned int z_usize; /* uncompressed size */
00086         unsigned short z_namlen; /* filename length (null if stdin) */
00087         unsigned short z_extras; /* extra field length */
00088         /* followed by filename (of variable size) */
00089         /* followed by extra field (of variable size) */
00090 };
00091 
00092 inline void istream_read_zip_file_header (SeekableInputStream& istream, zip_file_header& file_header)
00093 {
00094     istream_read_zip_magic(istream, file_header.z_magic);
00095     istream_read_zip_version(istream, file_header.z_extract);
00096     file_header.z_flags = istream_read_uint16_le(istream);
00097     file_header.z_compr = istream_read_uint16_le(istream);
00098     istream_read_zip_dostime(istream, file_header.z_dostime);
00099     file_header.z_crc32 = istream_read_uint32_le(istream);
00100     file_header.z_csize = istream_read_uint32_le(istream);
00101     file_header.z_usize = istream_read_uint32_le(istream);
00102     file_header.z_namlen = istream_read_uint16_le(istream);
00103     file_header.z_extras = istream_read_uint16_le(istream);
00104     istream.seek(file_header.z_namlen + file_header.z_extras, SeekableInputStream::cur);
00105 }
00106 ;
00107 
00108 /* B. data descriptor
00109  * the data descriptor exists only if bit 3 of z_flags is set. It is byte aligned
00110  * and immediately follows the last byte of compressed data. It is only used if
00111  * the output media of the compressor was not seekable, eg. standard output.
00112  */
00113 const zip_magic zip_file_trailer_magic = { { 'P', 'K', 0x07, 0x08 } };
00114 
00115 struct zip_file_trailer
00116 {
00117         zip_magic z_magic;
00118         unsigned int z_crc32; /* crc-32 */
00119         unsigned int z_csize; /* compressed size */
00120         unsigned int z_usize; /* uncompressed size */
00121 };
00122 
00123 inline void istream_read_zip_file_trailer (InputStream& istream, zip_file_trailer& file_trailer)
00124 {
00125     istream_read_zip_magic(istream, file_trailer.z_magic);
00126     file_trailer.z_crc32 = istream_read_uint32_le(istream);
00127     file_trailer.z_csize = istream_read_uint32_le(istream);
00128     file_trailer.z_usize = istream_read_uint32_le(istream);
00129 }
00130 ;
00131 
00132 /* C. central directory structure:
00133  [file header] . . . end of central dir record
00134  */
00135 
00136 /* directory file header
00137  * - a single entry including filename, extras and comment may not exceed 64k.
00138  */
00139 
00140 const zip_magic zip_root_dirent_magic = { { 'P', 'K', 0x01, 0x02 } };
00141 
00142 struct zip_root_dirent
00143 {
00144         zip_magic z_magic;
00145         zip_version z_encoder; /* version made by */
00146         zip_version z_extract; /* version need to extract */
00147         unsigned short z_flags; /* general purpose bit flag */
00148         unsigned short z_compr; /* compression method */
00149         zip_dostime z_dostime; /* last mod file time&date (dos format) */
00150         unsigned int z_crc32; /* crc-32 */
00151         unsigned int z_csize; /* compressed size */
00152         unsigned int z_usize; /* uncompressed size */
00153         unsigned short z_namlen; /* filename length (null if stdin) */
00154         unsigned short z_extras; /* extra field length */
00155         unsigned short z_comment; /* file comment length */
00156         unsigned short z_diskstart; /* disk number of start (if spanning zip over multiple disks) */
00157         unsigned short z_filetype; /* internal file attributes, bit0 = ascii */
00158         unsigned int z_filemode; /* extrnal file attributes, eg. msdos attrib byte */
00159         unsigned int z_off; /* relative offset of local file header, seekval if singledisk */
00160         /* followed by filename (of variable size) */
00161         /* followed by extra field (of variable size) */
00162         /* followed by file comment (of variable size) */
00163 };
00164 
00165 inline void istream_read_zip_root_dirent (SeekableInputStream& istream, zip_root_dirent& root_dirent)
00166 {
00167     istream_read_zip_magic(istream, root_dirent.z_magic);
00168     istream_read_zip_version(istream, root_dirent.z_encoder);
00169     istream_read_zip_version(istream, root_dirent.z_extract);
00170     root_dirent.z_flags = istream_read_uint16_le(istream);
00171     root_dirent.z_compr = istream_read_uint16_le(istream);
00172     istream_read_zip_dostime(istream, root_dirent.z_dostime);
00173     root_dirent.z_crc32 = istream_read_uint32_le(istream);
00174     root_dirent.z_csize = istream_read_uint32_le(istream);
00175     root_dirent.z_usize = istream_read_uint32_le(istream);
00176     root_dirent.z_namlen = istream_read_uint16_le(istream);
00177     root_dirent.z_extras = istream_read_uint16_le(istream);
00178     root_dirent.z_comment = istream_read_uint16_le(istream);
00179     root_dirent.z_diskstart = istream_read_uint16_le(istream);
00180     root_dirent.z_filetype = istream_read_uint16_le(istream);
00181     root_dirent.z_filemode = istream_read_uint32_le(istream);
00182     root_dirent.z_off = istream_read_uint32_le(istream);
00183     istream.seek(root_dirent.z_namlen + root_dirent.z_extras + root_dirent.z_comment, SeekableInputStream::cur);
00184 }
00185 
00186 /* end of central dir record */
00187 const zip_magic zip_disk_trailer_magic = { { 'P', 'K', 0x05, 0x06 } };
00188 const unsigned int disk_trailer_length = 22;
00189 struct zip_disk_trailer
00190 {
00191         zip_magic z_magic;
00192         unsigned short z_disk; /* number of this disk */
00193         unsigned short z_finaldisk; /* number of the disk with the start of the central dir */
00194         unsigned short z_entries; /* total number of entries in the central dir on this disk */
00195         unsigned short z_finalentries; /* total number of entries in the central dir */
00196         unsigned int z_rootsize; /* size of the central directory */
00197         unsigned int z_rootseek; /* offset of start of central directory with respect to *
00198          * the starting disk number */
00199         unsigned short z_comment; /* zipfile comment length */
00200         /* followed by zipfile comment (of variable size) */
00201 };
00202 
00203 inline void istream_read_zip_disk_trailer (SeekableInputStream& istream, zip_disk_trailer& disk_trailer)
00204 {
00205     istream_read_zip_magic(istream, disk_trailer.z_magic);
00206     disk_trailer.z_disk = istream_read_uint16_le(istream);
00207     disk_trailer.z_finaldisk = istream_read_uint16_le(istream);
00208     disk_trailer.z_entries = istream_read_uint16_le(istream);
00209     disk_trailer.z_finalentries = istream_read_uint16_le(istream);
00210     disk_trailer.z_rootsize = istream_read_uint32_le(istream);
00211     disk_trailer.z_rootseek = istream_read_uint32_le(istream);
00212     disk_trailer.z_comment = istream_read_uint16_le(istream);
00213     istream.seek(disk_trailer.z_comment, SeekableInputStream::cur);
00214 }
00215 
00216 inline SeekableStream::position_type pkzip_find_disk_trailer (SeekableInputStream& istream)
00217 {
00218     istream.seek(0, SeekableInputStream::end);
00219     SeekableStream::position_type start_position = istream.tell();
00220     if (start_position < disk_trailer_length)
00221         return 0;
00222     start_position -= disk_trailer_length;
00223 
00224     zip_magic magic;
00225     istream.seek(start_position);
00226     istream_read_zip_magic(istream, magic);
00227 
00228     if (magic == zip_disk_trailer_magic)
00229         return start_position;
00230     else {
00231         const SeekableStream::position_type max_comment = 0x10000;
00232         const SeekableStream::position_type bufshift = 6;
00233         const SeekableStream::position_type bufsize = max_comment >> bufshift;
00234         unsigned char buffer[bufsize];
00235 
00236         SeekableStream::position_type search_end = (max_comment < start_position) ? start_position - max_comment : 0;
00237         SeekableStream::position_type position = start_position;
00238         while (position != search_end) {
00239             StreamBase::size_type to_read = std::min(bufsize, position - search_end);
00240             position -= to_read;
00241 
00242             istream.seek(position);
00243             StreamBase::size_type size = istream.read(buffer, to_read);
00244 
00245             unsigned char* p = buffer + size;
00246             while (p != buffer) {
00247                 --p;
00248                 magic.m_value[3] = magic.m_value[2];
00249                 magic.m_value[2] = magic.m_value[1];
00250                 magic.m_value[1] = magic.m_value[0];
00251                 magic.m_value[0] = *p;
00252                 if (magic == zip_disk_trailer_magic) {
00253                     return position + (p - buffer);
00254                 }
00255             }
00256         }
00257         return 0;
00258     }
00259 }
00260 
00261 #endif

Generated by  doxygen 1.6.2