// Program name: cfcreate.cpp // Programmed by: Anthony Barbachan // Programmed in: C++ (Turbo C++ 3.0 Compatable) // Purpose: Source file for a cabinet file object. // Version: 1.00 // Last modified on: 12/31/1998 // Changes: Created classes to be used to create cabinet files. // Version: 1.10 // Last modified on: 10/24/1999 // Changes: Changed cfc_folderinfo::open function to return an error value. #ifndef __CFCREATE_H__ #define __CFCREATE_H__ #include #include "cfheader.h" #include "object.hpp" #include "bstring.h" #include "queue.hpp" #include "cffile.h" #include "zlib.h" #ifdef unix #include #endif ////////////////////////////////////////////////////////////////////////////// class cfc_fileinfo : public ObjectBase { public: enum { ifoldCONTINUED_FROM_PREV = 0xFFFDU, ifoldCONTINUED_TO_NEXT = 0xFFFEU, ifoldCONTINUED_PREV_AND_NEXT = 0xFFFFU }; enum { A_RDONLY = 0x01, A_HIDDEN = 0x02, A_SYSTEM = 0x04, A_VOLUME = 0x08, // Gotten from Dr. Dobbs CABLIB A_DIRECTORY = 0x10, // Gotten from Dr. Dobbs CABLIB A_ARCHIVE = 0x20, A_EXECUTE = 0x40, A_NAME_IS_UTF = 0x80 }; struct Date { unsigned day: 5; unsigned month: 4; unsigned year: 7; }; struct Time { unsigned second: 5; unsigned minute: 6; unsigned hour: 5; }; struct file_fixed_header { dword size; // uncompressed size of this file in bytes dword folder_offset; // uncompressed offset of this file in the folder word folder; // index into the CFFOLDER area word date; // date stamp for this file word time; // time stamp for this file word attribs; // attribute flags for this file // char* name; // name of this file }; protected: dword size; // uncompressed size of this file in bytes dword folder_offset; // uncompressed offset of this file in the folder word folder; // index into the CFFOLDER area word date; // date stamp for this file word time; // time stamp for this file word attribs; // attribute flags for this file char* name; // name of this file private: void free_buffers() { if(name != NULL) delete[] name; } void clear_variables() { size = 0ul; folder_offset = 0ul; folder = 0u; date = 0u; time = 0u; attribs = 0u; name = NULL; } public: cfc_fileinfo() { clear_variables(); } virtual ~cfc_fileinfo() { free_buffers(); } void reset() { free_buffers(); clear_variables(); } dword get_size() { return size; } void set_size(dword newsize) { size = newsize; } dword get_folder_offset() { return folder_offset; } void set_folder_offset(dword offset) { folder_offset = offset; } word get_folder() { return folder; } void set_folder(word folderno) { folder = folderno; } word get_date() { return date; } void set_date(word newdate) { date = newdate; } word get_time() { return date; } void set_time(word newtime) { time = newtime; } word get_attribs() { return attribs; } void set_attribs(word newattribs) { attribs = newattribs; } const char* get_name() { return (const char *) name; } void set_name(const char* fname) { if(name != NULL) delete[] name; name = new char[strlen(fname) + 1u]; strcpy(name, fname); } // ((Year - 1980) << 9) + (Month << 5) + Day; unsigned Year() { return ((Date *) &date)->year + 1980; } unsigned Month() { return ((Date *) &date)->month; } unsigned Day() { return ((Date *) &date)->day; } void set_date(word m, word d, word y) { date = ((y - 1980) << 9) + (m << 5) + d; } // (Hour << 11) + (Minutes << 5) + (Seconds / 2) unsigned Hour() { return ((Time *) &time)->hour; } unsigned Minute() { return ((Time *) &time)->minute; } unsigned Second() { return ((Time *) &time)->second * 2; } void set_time(word h, word m, word s) { time = (h << 11) + (m << 5) + (s / 2); } int IsReadOnly() { return attribs & A_RDONLY; } int IsHidden() { return attribs & A_HIDDEN; } int IsSystem() { return attribs & A_SYSTEM; } int IsDirectory() { return attribs & A_DIRECTORY; } int IsVolume() { return attribs & A_VOLUME; } int IsArchive() { return attribs & A_ARCHIVE; } int MustExecute() { return attribs & A_EXECUTE; } int NameIsUtf() { return attribs & A_NAME_IS_UTF; } unsigned long entry_size() { return sizeof(struct file_fixed_header) + strlen(name) + 1u; } int write_entry(ostream& out); }; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Note: reserved area disabled for now class cfc_folderinfo : public ObjectBase { public: struct folder_fixed_header { dword offset; // offset of the first CFDATA block in this folder word nblocks; // number of CFDATA blocks in this folder word compression_type; // compression type indicator // byte* reserved_area; // (optional) per-folder reserved area }; enum { NO_COMPRESSION = 0, MSZIP_COMPRESSION = 1 }; typedef unsigned long CHECKSUM; protected: dword offset; // offset of the first CFDATA block in this folder word data_blocks; // number of CFDATA blocks in this folder word compression_type; // compression type indicator byte* reserved_area; // (optional) per-folder reserved area word folderno; // This folder's number QueueOf fileq; // Queue containing all added files ostream* tempfile; byte* unprocessed_data; // Unprocessed data from last add_file(...) operation word unprocessed_data_len; // Length of unprocessed data unsigned long nbytes; // Number of bytes currently in folder unsigned long processed_bytes; z_stream* compressor_data; private: void free_buffers() { if(reserved_area != NULL) delete[] reserved_area; if(unprocessed_data != NULL) delete[] unprocessed_data; if(compressor_data != NULL) { deflateEnd(compressor_data); delete compressor_data; } } void clear_variables() { offset = 0ul; data_blocks = 0u; compression_type = 0u; folderno = 0u; tempfile = NULL; // Note: Must never be freed within this class reserved_area = NULL; unprocessed_data = NULL; unprocessed_data_len = 0u; processed_bytes = 0ul; nbytes = 0ul; fileq.Flush(); compressor_data = NULL; } protected: int process_block(const byte* data, word datalen); int read_block(istream& in, byte* &buf, int& bytesread); int compress_block(byte* &dest, word &destlen, byte* src, word srclen); CHECKSUM CSUMCompute(byte* pb, unsigned cb, CHECKSUM seed); public: cfc_folderinfo() { clear_variables(); } virtual ~cfc_folderinfo() { free_buffers(); } void reset() { free_buffers(); clear_variables(); } int open(ostream& temp, dword soffset, word comptype, word fno) { return open(temp, soffset, comptype, fno, 0, 0); } int open(ostream& temp, dword soffset, word comptype, word fno, byte resrv_len, byte* resrv); int add_file(const char* fname); int freeze(void); void close(QueueOf &cabfileq, unsigned long& size, unsigned long& hsize); dword get_offset() { return offset; } word get_num_data_blocks() { return data_blocks; } word get_compression_type() { return compression_type; } word get_folderno() { return folderno; } unsigned long get_size() { return nbytes; } const byte* get_reserved_area() { return (const byte *) reserved_area; } unsigned long entry_size() { return sizeof(struct folder_fixed_header); } int write_entry(ostream& out, dword hsize); unsigned long get_processed_bytes() { return processed_bytes; } }; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// class cabinet_creator { public: struct cabinet_fixed_header { byte signature[4]; // cabinet file signature dword reserved1; // reserved dword size; // size of this cabinet file in bytes dword reserved2; // reserved dword files_offset; // offset of the first CFFILE entry dword reserved3; // reserved byte version_minor; // cabinet file format version, minor byte version_major; // cabinet file format version, major word nfolders; // number of CFFOLDER entries in this cabinet word nfiles; // number of CFFILE entries in this cabinet word flags; // cabinet file option indicators word id; // must be the same for all cabinets in a set word cabinetno; // number of this cabinet file in a set //word cbCFHeader; // (optional) size of per-cabinet reserved area //byte cbCFFolder; // (optional) size of per-folder reserved area //byte cbCFData; // (optional) size of per-datablock reserved area //byte* abReserve; // (optional) per-cabinet reserved area //byte* szCabinetPrev; // (optional) name of previous cabinet file //byte* szDiskPrev; // (optional) name of previous disk //byte* szCabinetNext; // (optional) name of next cabinet file //byte* szDiskNext; // (optional) name of next disk }; protected: fstream temp; b_string temp_file_name; QueueOf folderq; protected: void close_all_folders(QueueOf &fileq, unsigned long& nbytes, unsigned long& header_size); public: cabinet_creator() {} ~cabinet_creator() { } void reset() { folderq.Flush(); if(temp_file_name.Exists()) { temp.close(); unlink((const char *) temp_file_name); temp_file_name.clear(); } } int open(void); int new_folder(word comptype); int add_file(const char* fname); int close(const char* fname); int close(ostream& out); }; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// #endif