7 Copyright (C) 2009-2013, 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.
26 #include "cod-internal.h"
30 #include <sys/types.h>
45 size_t SeekNextCod(std::istream
&input
)
47 unsigned char codtype_simple
[] = CODFILE_TYPE_SIMPLE
;
48 char codtype_pkzip
[] = CODFILE_TYPE_PKZIP
;
49 char local_file_sig
[] = PKZIP_LOCAL_FILE_SIG
;
50 char directory_sig
[] = PKZIP_DIRECTORY_SIG
;
54 // finished reading stream containing single cod file
60 if( input
.read(signature
, sizeof(signature
)).eof() ) {
61 throw Error(_("SeekNextCod: EOF while reading file signature"));
64 if( memcmp(signature
, codtype_pkzip
, sizeof(codtype_pkzip
)) == 0 ) {
66 if( memcmp(signature
, local_file_sig
, sizeof(signature
)) == 0 ) {
67 pkzip_local_header_t header
;
69 if( input
.read((char *)&header
, sizeof(pkzip_local_header_t
)).eof() ) {
70 throw Error(_("SeekNextCod: EOF while reading PKZIP header"));
73 // skip cod file name and extra field, we don't need them
74 size_t skip_len
= header
.file_name_length
+ header
.extra_field_length
;
75 if( input
.ignore(skip_len
).eof() ) {
76 throw Error(_("SeekNextCod: EOF while skipping unused fields"));
79 return btohl(header
.compressed_size
);
81 else if( memcmp(signature
, directory_sig
, sizeof(signature
)) == 0 ) {
82 // done reading when central directory is reached
86 else if( memcmp(signature
, codtype_simple
, sizeof(codtype_simple
)) == 0 ) {
87 // find and return size of cod file
88 if( input
.seekg(0, ios::end
).fail() ) {
89 throw Error(_("SeekNextCod: seek to end failed"));
92 uint32_t size
= input
.tellg();
94 if( input
.seekg(0, ios::beg
).fail() ) {
95 throw Error(_("SeekNextCod: seek to start failed"));
101 throw Error(_("SeekNextCod: unknown COD file signature"));
108 CodFileBuilder::CodFileBuilder(const std::string
&module_name
, size_t module_count
)
109 : m_module_name(module_name
)
110 , m_module_count(module_count
)
111 , m_current_module(0)
115 CodFileBuilder::~CodFileBuilder()
119 void CodFileBuilder::WriteNextHeader(std::ostream
&output
, const uint8_t* module_buffer
, uint32_t module_size
)
121 // ignored for single module .cod files (simple .cod file)
122 if( m_module_count
== 1 ) {
126 // 32bit CRC of module in file header and directory entry
127 // using zero for CRC will result in warnings when inflating .cod file
131 crc
= crc32(0, NULL
, module_size
);
132 crc
= crc32(crc
, module_buffer
, module_size
);
135 // .cod file name for siblings have hyphenated index number, name-1.cod
136 std::ostringstream
file_name(m_module_name
, ios::app
);
137 if( m_current_module
== 0 )
140 file_name
<< "-" << m_current_module
<< ".cod";
142 // current stream pointer is relative offset to start of file entry
143 uint32_t entry_offset
= output
.tellp();
145 // structures for the local file entry and central directory entry
146 pkzip_local_header_t header
;
147 pkzip_directory_t entry
;
149 // zero both structs, most fields are zero
150 memset(&header
, 0, sizeof(pkzip_local_header_t
));
151 memset(&entry
, 0, sizeof(pkzip_directory_t
));
153 char header_sig
[] = PKZIP_LOCAL_FILE_SIG
;
154 output
.write(header_sig
, sizeof(header_sig
));
156 // version is always 0x00A0 = 'Windows NTFS'
157 header
.version_needed
= htobs(10);
159 // time and date fields seem to randomly have invalid or fixed values
160 // just leave them as zero
161 //header.last_mod_time
162 //header.last_mod_date
164 header
.crc_32
= htobl(crc
);
165 header
.compressed_size
= htobl(module_size
);
166 header
.uncompressed_size
= htobl(module_size
);
167 header
.file_name_length
= htobs(file_name
.str().length());
169 // the very first cod sibling to be written has an extra field
170 // length equal to 4, with all zeros in the field itself
171 // all subsequent siblings have a zero length extra field
172 //header.extra_field_length = htobs(4);
174 output
.write((char *)&header
, sizeof(pkzip_local_header_t
));
175 output
<< file_name
.str();
177 char footer_sig
[] = PKZIP_DIRECTORY_SIG
;
179 // version is always 0x00A0 = 'Windows NTFS'
180 entry
.version_madeby
= htobs(10);
181 entry
.version_needed
= htobs(10);
183 entry
.crc_32
= htobl(crc
);
184 entry
.compressed_size
= htobl(module_size
);
185 entry
.uncompressed_size
= htobl(module_size
);
186 entry
.file_name_length
= htobs(file_name
.str().length());
187 entry
.relative_offset
= htobl(entry_offset
);
189 m_directory
.write(footer_sig
, sizeof(footer_sig
));
190 m_directory
.write((char*)&entry
, sizeof(pkzip_directory_t
));
191 m_directory
<< file_name
.str();
196 void CodFileBuilder::WriteFooter(std::ostream
&output
)
198 // ignored for single module .cod files (simple .cod file)
199 if( m_module_count
== 1 ) {
203 pkzip_end_directory_t end
;
204 memset(&end
, 0, sizeof(pkzip_end_directory_t
));
206 end
.this_disk_entry_count
= htobs(m_current_module
);
207 end
.total_entry_count
= htobs(m_current_module
);
208 end
.directory_length
= htobl(m_directory
.str().length());
210 // current stream pointer is relative offset to start of directory
211 end
.directory_offset
= output
.tellp();
213 char sig
[] = PKZIP_END_DIRECTORY_SIG
;
215 output
.write(m_directory
.str().data(), m_directory
.str().length());
216 output
.write(sig
, sizeof(sig
));
217 output
.write((char *)&end
, sizeof(pkzip_end_directory_t
));