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