7 Copyright (C) 2009, Net Direct Inc. (http://www.netdirect.ca/)
8 Copyright (C) 2008-2009, Nicolas VIVIEN
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
24 #include "cod-internal.h"
28 #include <sys/types.h>
43 size_t SeekNextCod(std::istream
&input
)
45 char local_file_sig
[] = PKZIP_LOCAL_FILE_SIG
;
46 char directory_sig
[] = PKZIP_DIRECTORY_SIG
;
50 // finished reading stream containing single cod file
56 if( input
.read(signature
, sizeof(signature
)).eof() ) {
57 throw Error("SeekNextCod: EOF while reading file signature");
60 if( memcmp(signature
, local_file_sig
, sizeof(signature
)) == 0 ) {
61 pkzip_local_header_t header
;
63 if( input
.read((char *)&header
, sizeof(pkzip_local_header_t
)).eof() ) {
64 throw Error("SeekNextCod: EOF while reading PKZIP header");
67 // skip cod file name and extra field, we don't need them
68 size_t skip_len
= header
.file_name_length
+ header
.extra_field_length
;
69 if( input
.ignore(skip_len
).eof() ) {
70 throw Error("SeekNextCod: EOF while skipping unused fields");
73 return btohl(header
.compressed_size
);
75 else if( memcmp(signature
, directory_sig
, sizeof(signature
)) == 0 ) {
76 // done reading when central directory is reached
80 // find and return size of cod file
81 if( input
.seekg(0, ios::end
).fail() ) {
82 throw Error("SeekNextCod: seek to end failed");
85 uint32_t size
= input
.tellg();
87 if( input
.seekg(0, ios::beg
).fail() ) {
88 throw Error("SeekNextCod: seek to start failed");
96 CodFileBuilder::CodFileBuilder(const std::string
&module_name
, size_t module_count
)
97 : m_module_name(module_name
)
98 , m_module_count(module_count
)
103 CodFileBuilder::~CodFileBuilder()
107 void CodFileBuilder::WriteNextHeader(std::ostream
&output
, const uint8_t* module_buffer
, uint32_t module_size
)
109 // ignored for single module .cod files (simple .cod file)
110 if( m_module_count
== 1 ) {
114 // 32bit CRC of module in file header and directory entry
115 // using zero for CRC will result in warnings when inflating .cod file
119 crc
= crc32(0, NULL
, module_size
);
120 crc
= crc32(crc
, module_buffer
, module_size
);
123 // .cod file name for siblings have hyphenated index number, name-1.cod
124 std::ostringstream
file_name(m_module_name
, ios::app
);
125 if( m_current_module
== 0 )
128 file_name
<< "-" << m_current_module
<< ".cod";
130 // current stream pointer is relative offset to start of file entry
131 uint32_t entry_offset
= output
.tellp();
133 // structures for the local file entry and central directory entry
134 pkzip_local_header_t header
;
135 pkzip_directory_t entry
;
137 // zero both structs, most fields are zero
138 memset(&header
, 0, sizeof(pkzip_local_header_t
));
139 memset(&entry
, 0, sizeof(pkzip_directory_t
));
141 char header_sig
[] = PKZIP_LOCAL_FILE_SIG
;
142 output
.write(header_sig
, sizeof(header_sig
));
144 // version is always 0x00A0 = 'Windows NTFS'
145 header
.version_needed
= htobs(10);
147 // time and date fields seem to randomly have invalid or fixed values
148 // just leave them as zero
149 //header.last_mod_time
150 //header.last_mod_date
152 header
.crc_32
= htobl(crc
);
153 header
.compressed_size
= htobl(module_size
);
154 header
.uncompressed_size
= htobl(module_size
);
155 header
.file_name_length
= htobs(file_name
.str().length());
157 // the very first cod sibling to be written has an extra field
158 // length equal to 4, with all zeros in the field itself
159 // all subsequent siblings have a zero length extra field
160 //header.extra_field_length = htobs(4);
162 output
.write((char *)&header
, sizeof(pkzip_local_header_t
));
163 output
<< file_name
.str();
165 char footer_sig
[] = PKZIP_DIRECTORY_SIG
;
167 // version is always 0x00A0 = 'Windows NTFS'
168 entry
.version_madeby
= htobs(10);
169 entry
.version_needed
= htobs(10);
171 entry
.crc_32
= htobl(crc
);
172 entry
.compressed_size
= htobl(module_size
);
173 entry
.uncompressed_size
= htobl(module_size
);
174 entry
.file_name_length
= htobs(file_name
.str().length());
175 entry
.relative_offset
= htobl(entry_offset
);
177 m_directory
.write(footer_sig
, sizeof(footer_sig
));
178 m_directory
.write((char*)&entry
, sizeof(pkzip_directory_t
));
179 m_directory
<< file_name
.str();
184 void CodFileBuilder::WriteFooter(std::ostream
&output
)
186 // ignored for single module .cod files (simple .cod file)
187 if( m_module_count
== 1 ) {
191 char sig
[] = PKZIP_END_DIRECTORY_SIG
;
193 pkzip_end_directory_t end
;
194 memset(&end
, 0, sizeof(pkzip_end_directory_t
));
196 end
.this_disk_entry_count
= htobs(m_current_module
);
197 end
.total_entry_count
= htobs(m_current_module
);
198 end
.directory_length
= htobl(m_directory
.str().length());
200 // current stream pointer is relative offset to start of directory
201 end
.directory_offset
= output
.tellp();
203 output
.write(m_directory
.str().c_str(), m_directory
.str().length());
204 output
.write(sig
, sizeof(sig
));
205 output
.write((char *)&end
, sizeof(pkzip_end_directory_t
));