7 Copyright (C) 2009, Net Direct Inc. (http://www.netdirect.ca/)
8 Copyright (C) 2008-2009, Nicolas VIVIEN
9 Copyright (C) 2009, Josh Kropf
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 See the GNU General Public License in the COPYING file at the
21 root directory of this project for more details.
25 #include "cod-internal.h"
29 #include <sys/types.h>
44 size_t SeekNextCod(std::istream
&input
)
46 unsigned char codtype_simple
[] = CODFILE_TYPE_SIMPLE
;
47 char codtype_pkzip
[] = CODFILE_TYPE_PKZIP
;
48 char local_file_sig
[] = PKZIP_LOCAL_FILE_SIG
;
49 char directory_sig
[] = PKZIP_DIRECTORY_SIG
;
53 // finished reading stream containing single cod file
59 if( input
.read(signature
, sizeof(signature
)).eof() ) {
60 throw Error("SeekNextCod: EOF while reading file signature");
63 if( memcmp(signature
, codtype_pkzip
, sizeof(codtype_pkzip
)) == 0 ) {
65 if( memcmp(signature
, local_file_sig
, sizeof(signature
)) == 0 ) {
66 pkzip_local_header_t header
;
68 if( input
.read((char *)&header
, sizeof(pkzip_local_header_t
)).eof() ) {
69 throw Error("SeekNextCod: EOF while reading PKZIP header");
72 // skip cod file name and extra field, we don't need them
73 size_t skip_len
= header
.file_name_length
+ header
.extra_field_length
;
74 if( input
.ignore(skip_len
).eof() ) {
75 throw Error("SeekNextCod: EOF while skipping unused fields");
78 return btohl(header
.compressed_size
);
80 else if( memcmp(signature
, directory_sig
, sizeof(signature
)) == 0 ) {
81 // done reading when central directory is reached
85 else if( memcmp(signature
, codtype_simple
, sizeof(codtype_simple
)) == 0 ) {
86 // find and return size of cod file
87 if( input
.seekg(0, ios::end
).fail() ) {
88 throw Error("SeekNextCod: seek to end failed");
91 uint32_t size
= input
.tellg();
93 if( input
.seekg(0, ios::beg
).fail() ) {
94 throw Error("SeekNextCod: seek to start failed");
100 throw Error("SeekNextCod: unknown COD file signature");
107 CodFileBuilder::CodFileBuilder(const std::string
&module_name
, size_t module_count
)
108 : m_module_name(module_name
)
109 , m_module_count(module_count
)
110 , m_current_module(0)
114 CodFileBuilder::~CodFileBuilder()
118 void CodFileBuilder::WriteNextHeader(std::ostream
&output
, const uint8_t* module_buffer
, uint32_t module_size
)
120 // ignored for single module .cod files (simple .cod file)
121 if( m_module_count
== 1 ) {
125 // 32bit CRC of module in file header and directory entry
126 // using zero for CRC will result in warnings when inflating .cod file
130 crc
= crc32(0, NULL
, module_size
);
131 crc
= crc32(crc
, module_buffer
, module_size
);
134 // .cod file name for siblings have hyphenated index number, name-1.cod
135 std::ostringstream
file_name(m_module_name
, ios::app
);
136 if( m_current_module
== 0 )
139 file_name
<< "-" << m_current_module
<< ".cod";
141 // current stream pointer is relative offset to start of file entry
142 uint32_t entry_offset
= output
.tellp();
144 // structures for the local file entry and central directory entry
145 pkzip_local_header_t header
;
146 pkzip_directory_t entry
;
148 // zero both structs, most fields are zero
149 memset(&header
, 0, sizeof(pkzip_local_header_t
));
150 memset(&entry
, 0, sizeof(pkzip_directory_t
));
152 char header_sig
[] = PKZIP_LOCAL_FILE_SIG
;
153 output
.write(header_sig
, sizeof(header_sig
));
155 // version is always 0x00A0 = 'Windows NTFS'
156 header
.version_needed
= htobs(10);
158 // time and date fields seem to randomly have invalid or fixed values
159 // just leave them as zero
160 //header.last_mod_time
161 //header.last_mod_date
163 header
.crc_32
= htobl(crc
);
164 header
.compressed_size
= htobl(module_size
);
165 header
.uncompressed_size
= htobl(module_size
);
166 header
.file_name_length
= htobs(file_name
.str().length());
168 // the very first cod sibling to be written has an extra field
169 // length equal to 4, with all zeros in the field itself
170 // all subsequent siblings have a zero length extra field
171 //header.extra_field_length = htobs(4);
173 output
.write((char *)&header
, sizeof(pkzip_local_header_t
));
174 output
<< file_name
.str();
176 char footer_sig
[] = PKZIP_DIRECTORY_SIG
;
178 // version is always 0x00A0 = 'Windows NTFS'
179 entry
.version_madeby
= htobs(10);
180 entry
.version_needed
= htobs(10);
182 entry
.crc_32
= htobl(crc
);
183 entry
.compressed_size
= htobl(module_size
);
184 entry
.uncompressed_size
= htobl(module_size
);
185 entry
.file_name_length
= htobs(file_name
.str().length());
186 entry
.relative_offset
= htobl(entry_offset
);
188 m_directory
.write(footer_sig
, sizeof(footer_sig
));
189 m_directory
.write((char*)&entry
, sizeof(pkzip_directory_t
));
190 m_directory
<< file_name
.str();
195 void CodFileBuilder::WriteFooter(std::ostream
&output
)
197 // ignored for single module .cod files (simple .cod file)
198 if( m_module_count
== 1 ) {
202 pkzip_end_directory_t end
;
203 memset(&end
, 0, sizeof(pkzip_end_directory_t
));
205 end
.this_disk_entry_count
= htobs(m_current_module
);
206 end
.total_entry_count
= htobs(m_current_module
);
207 end
.directory_length
= htobl(m_directory
.str().length());
209 // current stream pointer is relative offset to start of directory
210 end
.directory_offset
= output
.tellp();
212 char sig
[] = PKZIP_END_DIRECTORY_SIG
;
214 output
.write(m_directory
.str().data(), m_directory
.str().length());
215 output
.write(sig
, sizeof(sig
));
216 output
.write((char *)&end
, sizeof(pkzip_end_directory_t
));