1 // Program name: cfcreate.cpp
2 // Programmed by: Anthony Barbachan
3 // Programmed in: C++ (Turbo C++ 3.0 Compatable)
4 // Purpose: Source file for a cabinet file object.
5 // Version: 1.00
6 // Last modified on: 12/31/1998
7 // Changes: Created classes to be used to create cabinet files.
8 // Version: 1.10
9 // Last modified on: 10/24/1999
10 // Changes: Changed cfc_folderinfo::open function to return an error value.
11 
12 #ifndef __CFCREATE_H__
13 #define __CFCREATE_H__
14 
15 #include <string.h>
16 #include "cfheader.h"
17 #include "object.hpp"
18 #include "bstring.h"
19 #include "queue.hpp"
20 #include "cffile.h"
21 #include "zlib.h"
22 
23 using std::fstream;
24 
25 #ifdef unix
26 #include <unistd.h>
27 #endif
28 
29 //////////////////////////////////////////////////////////////////////////////
30 
31 class cfc_fileinfo : public ObjectBase
32 {
33 	public:
34 		enum
35 		{
36 			ifoldCONTINUED_FROM_PREV = 0xFFFDU,
37 			ifoldCONTINUED_TO_NEXT = 0xFFFEU,
38 			ifoldCONTINUED_PREV_AND_NEXT = 0xFFFFU
39 		};
40 		enum
41 		{
42 			A_RDONLY = 0x01,
43 			A_HIDDEN = 0x02,
44 			A_SYSTEM = 0x04,
45 			A_VOLUME = 0x08,			// Gotten from Dr. Dobbs CABLIB
46 			A_DIRECTORY = 0x10,			// Gotten from Dr. Dobbs CABLIB
47 			A_ARCHIVE = 0x20,
48 			A_EXECUTE = 0x40,
49 			A_NAME_IS_UTF = 0x80
50 		};
51 		struct Date
52 		{
53 			unsigned day: 5;
54 			unsigned month: 4;
55 			unsigned year: 7;
56 		};
57 		struct Time
58 		{
59 			unsigned second: 5;
60 			unsigned minute: 6;
61 			unsigned hour: 5;
62 		};
63 		struct file_fixed_header
64 		{
65 			dword size;			// uncompressed size of this file in bytes
66 			dword folder_offset;	// uncompressed offset of this file in the folder
67 			word folder;			// index into the CFFOLDER area
68 			word date;			// date stamp for this file
69 			word time;			// time stamp for this file
70 			word attribs;			// attribute flags for this file
71 			// char* name;			// name of this file
72 		};
73 	protected:
74 		dword size;			// uncompressed size of this file in bytes
75 		dword folder_offset;	// uncompressed offset of this file in the folder
76 		word folder;			// index into the CFFOLDER area
77 		word date;			// date stamp for this file
78 		word time;			// time stamp for this file
79 		word attribs;			// attribute flags for this file
80 		char* name;			// name of this file
81 	private:
free_buffers()82 		void free_buffers()
83 		{
84 			if(name != NULL) delete[] name;
85 		}
clear_variables()86 		void clear_variables()
87 		{
88 			size = 0ul;
89 			folder_offset = 0ul;
90 			folder = 0u;
91 			date = 0u;
92 			time = 0u;
93 			attribs = 0u;
94 			name = NULL;
95 		}
96 	public:
cfc_fileinfo()97 		cfc_fileinfo() { clear_variables(); }
~cfc_fileinfo()98 		virtual ~cfc_fileinfo() { free_buffers(); }
reset()99 		void reset() { free_buffers(); clear_variables(); }
get_size()100 		dword get_size() { return size; }
set_size(dword newsize)101 		void set_size(dword newsize) { size = newsize; }
get_folder_offset()102 		dword get_folder_offset() { return folder_offset; }
set_folder_offset(dword offset)103 		void set_folder_offset(dword offset) { folder_offset = offset; }
get_folder()104 		word get_folder() { return folder; }
set_folder(word folderno)105 		void set_folder(word folderno) { folder = folderno; }
get_date()106 		word get_date() { return date; }
set_date(word newdate)107 		void set_date(word newdate) { date = newdate; }
get_time()108 		word get_time() { return date; }
set_time(word newtime)109 		void set_time(word newtime) { time = newtime; }
get_attribs()110 		word get_attribs() { return attribs; }
set_attribs(word newattribs)111 		void set_attribs(word newattribs) { attribs = newattribs; }
get_name()112 		const char* get_name() { return (const char *) name; }
set_name(const char * fname)113 		void set_name(const char* fname)
114 		{
115 			if(name != NULL) delete[] name;
116 			name = new char[strlen(fname) + 1u];
117 			strcpy(name, fname);
118 		}
119 		// ((Year - 1980) << 9) + (Month << 5) + Day;
Year()120 		unsigned Year() { return ((Date *) &date)->year + 1980; }
Month()121 		unsigned Month() { return ((Date *) &date)->month; }
Day()122 		unsigned Day() { return ((Date *) &date)->day; }
set_date(word m,word d,word y)123 		void set_date(word m, word d, word y)
124 		{
125 			date = ((y - 1980) << 9) + (m << 5) + d;
126 		}
127 		// (Hour << 11) + (Minutes << 5) + (Seconds / 2)
Hour()128 		unsigned Hour() { return ((Time *) &time)->hour; }
Minute()129 		unsigned Minute() { return ((Time *) &time)->minute; }
Second()130 		unsigned Second() { return ((Time *) &time)->second * 2; }
set_time(word h,word m,word s)131 		void set_time(word h, word m, word s)
132 		{
133 			time = (h << 11) + (m << 5) + (s / 2);
134 		}
IsReadOnly()135 		int IsReadOnly() { return attribs & A_RDONLY; }
IsHidden()136 		int IsHidden() { return attribs & A_HIDDEN; }
IsSystem()137 		int IsSystem() { return attribs & A_SYSTEM; }
IsDirectory()138 		int IsDirectory() { return attribs & A_DIRECTORY; }
IsVolume()139 		int IsVolume() { return attribs & A_VOLUME; }
IsArchive()140 		int IsArchive() { return attribs & A_ARCHIVE; }
MustExecute()141 		int MustExecute() { return attribs & A_EXECUTE; }
NameIsUtf()142 		int NameIsUtf() { return attribs & A_NAME_IS_UTF; }
entry_size()143 		unsigned long entry_size()
144 		{
145 			return sizeof(struct file_fixed_header) + strlen(name) + 1u;
146 		}
147 		int write_entry(ostream& out);
148 };
149 
150 //////////////////////////////////////////////////////////////////////////////
151 //////////////////////////////////////////////////////////////////////////////
152 
153 // Note: reserved area disabled for now
154 
155 class cfc_folderinfo : public ObjectBase
156 {
157 	public:
158 		struct folder_fixed_header
159 		{
160 			dword offset;			// offset of the first CFDATA block in this folder
161 			word nblocks;			// number of CFDATA blocks in this folder
162 			word compression_type;	// compression type indicator
163 			// byte* reserved_area;	// (optional) per-folder reserved area
164 		};
165 		enum
166 		{
167 			NO_COMPRESSION = 0,
168 			MSZIP_COMPRESSION = 1
169 		};
170 		typedef unsigned long CHECKSUM;
171 	protected:
172 		dword offset;			// offset of the first CFDATA block in this folder
173 		word data_blocks;		// number of CFDATA blocks in this folder
174 		word compression_type;	// compression type indicator
175 		byte* reserved_area;	// (optional) per-folder reserved area
176 		word folderno;			// This folder's number
177 
178 		QueueOf<cfc_fileinfo> fileq;	// Queue containing all added files
179 		ostream* tempfile;
180 		byte* unprocessed_data;	// Unprocessed data from last add_file(...) operation
181 		word unprocessed_data_len;	// Length of unprocessed data
182 		unsigned long nbytes; 		// Number of bytes currently in folder
183 		unsigned long processed_bytes;
184 		z_stream* compressor_data;
185 	private:
free_buffers()186 		void free_buffers()
187 		{
188 			if(reserved_area != NULL) delete[] reserved_area;
189 			if(unprocessed_data != NULL) delete[] unprocessed_data;
190 
191 			if(compressor_data != NULL)
192 			{
193 				deflateEnd(compressor_data);
194 				delete compressor_data;
195 			}
196 		}
clear_variables()197 		void clear_variables()
198 		{
199 			offset = 0ul;
200 			data_blocks = 0u;
201 			compression_type = 0u;
202 			folderno = 0u;
203 			tempfile = NULL;	// Note: Must never be freed within this class
204 			reserved_area = NULL;
205 			unprocessed_data = NULL;
206 			unprocessed_data_len = 0u;
207 			processed_bytes = 0ul;
208 			nbytes = 0ul;
209 			fileq.Flush();
210 			compressor_data = NULL;
211 		}
212 	protected:
213 		int process_block(const byte* data, word datalen);
214 		int read_block(istream& in, byte* &buf, int& bytesread);
215 		int compress_block(byte* &dest, word &destlen, byte* src, word srclen);
216 		CHECKSUM CSUMCompute(byte* pb, unsigned cb, CHECKSUM seed);
217 	public:
cfc_folderinfo()218 		cfc_folderinfo() { clear_variables(); }
~cfc_folderinfo()219 		virtual ~cfc_folderinfo() { free_buffers(); }
reset()220 		void reset() { free_buffers(); clear_variables(); }
open(ostream & temp,dword soffset,word comptype,word fno)221 		int open(ostream& temp, dword soffset, word comptype, word fno)
222 		{
223 			return open(temp, soffset, comptype, fno, 0, 0);
224 		}
225 		int open(ostream& temp, dword soffset, word comptype, word fno, byte resrv_len, byte* resrv);
226 		int add_file(const char* fname);
227 		int freeze(void);
228 		void close(QueueOf<cfc_fileinfo> &cabfileq, unsigned long& size, unsigned long& hsize);
get_offset()229 		dword get_offset() { return offset; }
get_num_data_blocks()230 		word get_num_data_blocks() { return data_blocks; }
get_compression_type()231 		word get_compression_type() { return compression_type; }
get_folderno()232 		word get_folderno() { return folderno; }
get_size()233 		unsigned long get_size() { return nbytes; }
get_reserved_area()234 		const byte* get_reserved_area() { return (const byte *) reserved_area; }
entry_size()235 		unsigned long entry_size() { return sizeof(struct folder_fixed_header); }
236 		int write_entry(ostream& out, dword hsize);
get_processed_bytes()237 		unsigned long get_processed_bytes() { return processed_bytes; }
238 };
239 
240 //////////////////////////////////////////////////////////////////////////////
241 //////////////////////////////////////////////////////////////////////////////
242 
243 class cabinet_creator
244 {
245 	public:
246 		struct cabinet_fixed_header
247 		{
248 			byte signature[4];		// cabinet file signature
249 			dword reserved1;		// reserved
250 			dword size;			// size of this cabinet file in bytes
251 			dword reserved2;		// reserved
252 			dword files_offset;		// offset of the first CFFILE entry
253 			dword reserved3;		// reserved
254 			byte version_minor;		// cabinet file format version, minor
255 			byte version_major;		// cabinet file format version, major
256 			word nfolders;			// number of CFFOLDER entries in this cabinet
257 			word nfiles;			// number of CFFILE entries in this cabinet
258 			word flags;			// cabinet file option indicators
259 			word id;				// must be the same for all cabinets in a set
260 			word cabinetno;		// number of this cabinet file in a set
261 			//word cbCFHeader;		// (optional) size of per-cabinet reserved area
262 			//byte cbCFFolder;		// (optional) size of per-folder reserved area
263 			//byte cbCFData;			// (optional) size of per-datablock reserved area
264 			//byte* abReserve;		// (optional) per-cabinet reserved area
265 			//byte* szCabinetPrev;	// (optional) name of previous cabinet file
266 			//byte* szDiskPrev;		// (optional) name of previous disk
267 			//byte* szCabinetNext;	// (optional) name of next cabinet file
268 			//byte* szDiskNext;		// (optional) name of next disk
269 		};
270 	protected:
271 		fstream temp;
272 		b_string temp_file_name;
273 		QueueOf<cfc_folderinfo> folderq;
274 	protected:
275 		void close_all_folders(QueueOf<cfc_fileinfo> &fileq, unsigned long& nbytes, unsigned long& header_size);
276 	public:
cabinet_creator()277 		cabinet_creator() {}
~cabinet_creator()278 		~cabinet_creator()
279 		{
280 		}
reset()281 		void reset()
282 		{
283 			folderq.Flush();
284 
285 			if(temp_file_name.Exists())
286 			{
287 				temp.close();
288 				unlink((const char *) temp_file_name);
289 				temp_file_name.clear();
290 			}
291 		}
292 		int open(void);
293 		int new_folder(word comptype);
294 		int add_file(const char* fname);
295 		int close(const char* fname);
296 		int close(ostream& out);
297 };
298 
299 //////////////////////////////////////////////////////////////////////////////
300 //////////////////////////////////////////////////////////////////////////////
301 
302 #endif
303