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