# cod.cc

Go to the documentation of this file.

    00001 ///
    00002 /// \file       cod.cc
    00003 ///             COD file API
    00004 ///
    00005
    00006 /*
    00007     Copyright (C) 2009-2011, Net Direct Inc. (http://www.netdirect.ca/)
    00008     Copyright (C) 2008-2009, Nicolas VIVIEN
    00009     Copyright (C) 2009, Josh Kropf
    00010
    00011     This program is free software; you can redistribute it and/or modify
    00012     it under the terms of the GNU General Public License as published by
    00013     the Free Software Foundation; either version 2 of the License, or
    00014     (at your option) any later version.
    00015
    00016     This program is distributed in the hope that it will be useful,
    00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00019
    00020     See the GNU General Public License in the COPYING file at the
    00021     root directory of this project for more details.
    00022 */
    00023
    00024 #include "cod.h"
    00025 #include "cod-internal.h"
    00026 #include "error.h"
    00027 #include "endian.h"
    00028 #include <config.h>
    00029 #include <sys/types.h>
    00030 #include <sys/stat.h>
    00031 #include <unistd.h>
    00032 #include <string>
    00033 #include <string.h>
    00034
    00035 #ifdef HAVE_ZLIB
    00036  #include <zlib.h>
    00037 #endif
    00038
    00039 using namespace std;
    00040
    00041 namespace Barry {
    00042
    00043
    00044 size_t SeekNextCod(std::istream &input)
    00045 {
    00046         unsigned char codtype_simple[] = CODFILE_TYPE_SIMPLE;
    00047         char codtype_pkzip[] = CODFILE_TYPE_PKZIP;
    00048         char local_file_sig[] = PKZIP_LOCAL_FILE_SIG;
    00049         char directory_sig[] = PKZIP_DIRECTORY_SIG;
    00050
    00051         char signature[4];
    00052
    00053         // finished reading stream containing single cod file
    00054         input.peek();
    00055         if( input.eof() ) {
    00056                 return 0;
    00057         }
    00058
    00059         if( input.read(signature, sizeof(signature)).eof() ) {
    00060                 throw Error("SeekNextCod: EOF while reading file signature");
    00061         }
    00062
    00063         if( memcmp(signature, codtype_pkzip, sizeof(codtype_pkzip)) == 0 ) {
    00064
    00065                 if( memcmp(signature, local_file_sig, sizeof(signature)) == 0 ) {
    00066                         pkzip_local_header_t header;
    00067
    00068                         if( input.read((char *)&header, sizeof(pkzip_local_header_t)).eof() ) {
    00069                                 throw Error("SeekNextCod: EOF while reading PKZIP header");
    00070                         }
    00071
    00072                         // skip cod file name and extra field, we don't need them
    00073                         size_t skip_len = header.file_name_length + header.extra_field_length;
    00074                         if( input.ignore(skip_len).eof() ) {
    00075                                 throw Error("SeekNextCod: EOF while skipping unused fields");
    00076                         }
    00077
    00078                         return btohl(header.compressed_size);
    00079                 }
    00080                 else if( memcmp(signature, directory_sig, sizeof(signature)) == 0 ) {
    00081                         // done reading when central directory is reached
    00082                         return 0;
    00083                 }
    00084         }
    00085         else if( memcmp(signature, codtype_simple, sizeof(codtype_simple)) == 0 ) {
    00086                 // find and return size of cod file
    00087                 if( input.seekg(0, ios::end).fail() ) {
    00088                         throw Error("SeekNextCod: seek to end failed");
    00089                 }
    00090
    00091                 uint32_t size = input.tellg();
    00092
    00093                 if( input.seekg(0, ios::beg).fail() ) {
    00094                         throw Error("SeekNextCod: seek to start failed");
    00095                 }
    00096
    00097                 return size;
    00098         }
    00099         else {
    00100                 throw Error("SeekNextCod: unknown COD file signature");
    00101         }
    00102
    00103         return 0;
    00104 }
    00105
    00106
    00107 CodFileBuilder::CodFileBuilder(const std::string &module_name, size_t module_count)
    00108         : m_module_name(module_name)
    00109         , m_module_count(module_count)
    00110         , m_current_module(0)
    00111 {
    00112 }
    00113
    00114 CodFileBuilder::~CodFileBuilder()
    00115 {
    00116 }
    00117
    00118 void CodFileBuilder::WriteNextHeader(std::ostream &output, const uint8_t* module_buffer, uint32_t module_size)
    00119 {
    00120         // ignored for single module .cod files (simple .cod file)
    00121         if( m_module_count == 1 ) {
    00122                 return;
    00123         }
    00124
    00125         // 32bit CRC of module in file header and directory entry
    00126         // using zero for CRC will result in warnings when inflating .cod file
    00127         uint32_t crc = 0;
    00128
    00129 #ifdef HAVE_ZLIB
    00130         crc = crc32(0, NULL, module_size);
    00131         crc = crc32(crc, module_buffer, module_size);
    00132 #endif
    00133
    00134         // .cod file name for siblings have hyphenated index number, name-1.cod
    00135         std::ostringstream file_name(m_module_name, ios::app);
    00136         if( m_current_module == 0 )
    00137                 file_name << ".cod";
    00138         else
    00139                 file_name << "-" << m_current_module << ".cod";
    00140
    00141         // current stream pointer is relative offset to start of file entry
    00142         uint32_t entry_offset = output.tellp();
    00143
    00144         // structures for the local file entry and central directory entry
    00145         pkzip_local_header_t header;
    00146         pkzip_directory_t entry;
    00147
    00148         // zero both structs, most fields are zero
    00149         memset(&header, 0, sizeof(pkzip_local_header_t));
    00150         memset(&entry, 0, sizeof(pkzip_directory_t));
    00151
    00152         char header_sig[] = PKZIP_LOCAL_FILE_SIG;
    00153         output.write(header_sig, sizeof(header_sig));
    00154
    00155         // version is always 0x00A0 = 'Windows NTFS'
    00156         header.version_needed = htobs(10);
    00157
    00158         // time and date fields seem to randomly have invalid or fixed values
    00159         // just leave them as zero
    00160         //header.last_mod_time
    00161         //header.last_mod_date
    00162
    00163         header.crc_32 = htobl(crc);
    00164         header.compressed_size = htobl(module_size);
    00165         header.uncompressed_size = htobl(module_size);
    00166         header.file_name_length = htobs(file_name.str().length());
    00167
    00168         // the very first cod sibling to be written has an extra field
    00169         // length equal to 4, with all zeros in the field itself
    00170         // all subsequent siblings have a zero length extra field
    00171         //header.extra_field_length = htobs(4);
    00172
    00173         output.write((char *)&header, sizeof(pkzip_local_header_t));
    00174         output << file_name.str();
    00175
    00176         char footer_sig[] = PKZIP_DIRECTORY_SIG;
    00177
    00178         // version is always 0x00A0 = 'Windows NTFS'
    00179         entry.version_madeby = htobs(10);
    00180         entry.version_needed = htobs(10);
    00181
    00182         entry.crc_32 = htobl(crc);
    00183         entry.compressed_size = htobl(module_size);
    00184         entry.uncompressed_size = htobl(module_size);
    00185         entry.file_name_length = htobs(file_name.str().length());
    00186         entry.relative_offset = htobl(entry_offset);
    00187
    00188         m_directory.write(footer_sig, sizeof(footer_sig));
    00189         m_directory.write((char*)&entry, sizeof(pkzip_directory_t));
    00190         m_directory << file_name.str();
    00191
    00192         m_current_module ++;
    00193 }
    00194
    00195 void CodFileBuilder::WriteFooter(std::ostream &output)
    00196 {
    00197         // ignored for single module .cod files (simple .cod file)
    00198         if( m_module_count == 1 ) {
    00199                 return;
    00200         }
    00201
    00202         pkzip_end_directory_t end;
    00203         memset(&end, 0, sizeof(pkzip_end_directory_t));
    00204
    00205         end.this_disk_entry_count = htobs(m_current_module);
    00206         end.total_entry_count = htobs(m_current_module);
    00207         end.directory_length = htobl(m_directory.str().length());
    00208
    00209         // current stream pointer is relative offset to start of directory
    00210         end.directory_offset = output.tellp();
    00211
    00212         char sig[] = PKZIP_END_DIRECTORY_SIG;
    00213
    00214         output.write(m_directory.str().data(), m_directory.str().length());
    00215         output.write(sig, sizeof(sig));
    00216         output.write((char *)&end, sizeof(pkzip_end_directory_t));
    00217 }
    00218
    00219
    00220 } // namespace Barry
    00221