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