// Program name: cfreader.cpp // Programmed by: Anthony Barbachan // Programmed in: C++ (Turbo C++ 3.0 Compatable) // Purpose: Source file for the CabinetFile object. (reads, extracts from cabs) // Version: 1.00 // Last modified on: 12/12/1998 // Version: 2.00 // Last modification date: 10/18/1999 // Changes: Replaced code with new classes' code. #ifndef __CFREADER_CPP__ #define __CFREADER_CPP__ #ifndef unix #include #include #include #else #include "dos_comp.h" #endif #include #include #include #include #include "darray.h" #include "cffile.h" #include "cftypes.h" #include "cffdrmgr.h" #include "cffolder.h" #include "cfheader.h" #include "cfreader.h" using std::ios; ////////////////////////////////////////**************************************** int cabinet_reader::open(const char* fname) { int err = OK; word pos = 0u; //close(); // Close if open cabfile.open(fname, ios::in | ios::binary); // Open filestream if(!cabfile) { return UNABLE_TO_OPEN; } // Check for open error if((err = cabinet_header::read(cabfile)) != OK) { return err; }// Read head folder_array.add_objects(get_nfolders()); // Allocate folder entries for(pos = 0u; pos < get_nfolders(); pos++) // Read folder entries { if((err = folder_array[pos].read(cabfile, *this)) != OK){return err;} } file_array.add_objects(get_nfiles()); // Allocate file entries for(pos = 0u; pos < get_nfiles(); pos++) // Read file entries { if((err = file_array[pos].read(cabfile)) != OK) { return err; } } return OK; // Singal OK status to caller } ////////////////////////////////////////**************************************** void cabinet_reader::close() { cabfile.close(); file_array.reset(); folder_array.reset(); cabinet_header::clear(); } ////////////////////////////////////////**************************************** // This function extracts a file from the cabinet. // Returns FILE_NOT_FOUND on error, the file number if successful. long cabinet_reader::find_file(const char* fname) { for(size_t pos = 0u; pos < nfiles; pos++) { if(stricmp(file_array[pos].get_name(), fname) == 0) return pos; } return FILE_NOT_FOUND; } ////////////////////////////////////////**************************************** // This function extracts a file from the cabinet int cabinet_reader::extract(cabinet_file_header& file) { ofstream out; int err = OK; char* dir = NULL; char* filename = NULL; char originalpath[MAXPATH]; splitpath(file.get_name(), dir, filename); if(filename == NULL) { if(dir != NULL) delete[] dir; return NO_FILENAME; } if(getcwd(originalpath, MAXPATH) != originalpath) { if(dir != NULL) delete[] dir; delete[] filename; return GETCWD_FAILURE; } if((err = createpath(dir)) != OK) { if(dir != NULL) delete[] dir; delete[] filename; if(chdir(originalpath) == -1) { //return CHDIR_FAILURE; } return err; } out.open(filename, ios::out | ios::binary | ios::trunc); if(!out) { if(dir != NULL) delete[] dir; delete[] filename; if(chdir(originalpath) == -1) { //return CHDIR_FAILURE; } return UNABLE_TO_OPEN; } if((err = folder_array[file.get_folder()].extract_data(out, cabfile, file.get_offset(), file.get_size(), *this)) != OK) { if(dir != NULL) delete[] dir; delete[] filename; if(chdir(originalpath) == -1) ;//return CHDIR_FAILURE; return err; } out.flush(); #ifndef unix if((err = setdosfiletime(out.rdbuf()->fd(), file)) != OK) { if(dir != NULL) delete[] dir; delete[] filename; if(chdir(originalpath) == -1) ;//return CHDIR_FAILURE; return err; } #endif out.close(); if(dir != NULL) delete[] dir; if((err = restoreattributes(filename, file)) != OK) { delete[] filename; if(chdir(originalpath) == -1) ;//return CHDIR_FAILURE; return err; } delete[] filename; if(chdir(originalpath) == -1) { return CHDIR_FAILURE; } return OK; } ////////////////////////////////////////**************************************** // This function extracts a file from the cabinet int cabinet_reader::extract(const char* fname) { long find_status = find_file(fname); if((int) find_status < 0) return (int) find_status; cabinet_file_header& file = file_array[(word) find_status]; return extract(file); } ////////////////////////////////////////**************************************** // This function splits path into a directory path and a filename // The directory part is returned in dir and the filename is returned via file // Either dir or file may return as NULL // Whichever aren't NULL must be deleted to release the memory in use by them. void cabinet_reader::splitpath(const char* path, char* &dir, char* &file) { size_t temp = 0u; const char* pos = NULL; if((path == NULL) || (*path == '\0')) // If fname is NULL or is empty { dir = NULL; file = NULL; return; } if((pos = strrchr(path, pathseparator)) == NULL) // If no path { dir = NULL; file = new char[strlen(path) + 1u]; strcpy(file, path); return; } pos++; // Point pos to begining of filename temp = (size_t) (pos - path); dir = new char[temp + 1u]; // Assemble directory part strncpy(dir, path, temp); dir[temp] = '\0'; if((temp = strlen(pos)) == 0u) // If no filename { file = NULL; return; } file = new char[temp + 1u]; // Assemble filename strcpy(file, pos); } ////////////////////////////////////////**************************************** // Returns 0 if successful, -1 if failure int cabinet_reader::createpath(const char* path) { char* end = NULL; const char* ptr = NULL; const char* temp = NULL; const char* lastpos = NULL; const char rootdir[2] = { pathseparator, '\0' }; if(path == NULL) { return OK; } // Assume nothing to do if((temp = strdup(path)) == NULL) // duplicate path { return OUT_OF_MEMORY; } lastpos = temp + strlen(temp); // Find last string position ptr = temp; // Preset ptr to start of temp if(*ptr == pathseparator) // Detect absolute path { if(chdir(rootdir) == -1) { free((void *) temp); return CHDIR_FAILURE; } ptr++; } while(ptr != lastpos) // Loop until end of string { if(*ptr == pathseparator) { ptr++; } else { if((end = (char *) strchr(ptr, pathseparator)) != NULL) { *end = '\0'; } if(access(ptr, 0) == -1) { switch(errno) { case ENOENT: if(mkdir(ptr) == -1) { free((void *) temp); // Free allocated memory return MKDIR_FAILURE; } break; case EACCES: free((void *) temp); // Free allocated memory return ACCESS_DENIED; default: free((void *) temp); // Free allocated memory return UNKNOWN_ERROR; } } if(chdir(ptr) == -1) { free((void *) temp); return CHDIR_FAILURE; } ptr = (end != NULL) ? end + 1u : lastpos; } } free((void *) temp); // Free allocated memory return OK; } ////////////////////////////////////////**************************************** #ifndef unix int cabinet_reader::setdosfiletime(int handle, cabinet_file_header& fileinfo) { struct ftime timeinfo; timeinfo.ft_tsec = fileinfo.second(); timeinfo.ft_min = fileinfo.minute(); timeinfo.ft_hour = fileinfo.hour(); timeinfo.ft_day = fileinfo.day(); timeinfo.ft_month = fileinfo.month(); timeinfo.ft_year = fileinfo.year() - 1980; if(setftime(handle, &timeinfo) == -1) { return SETTIME_FAILURE; } return OK; } #endif ////////////////////////////////////////**************************************** #ifdef unix inline #endif int cabinet_reader::restoreattributes(const char* fname, cabinet_file_header& fileinfo) { #ifndef unix unsigned temp = 0u; if(fileinfo.is_readonly()) { temp |= _A_RDONLY; } if(fileinfo.is_hidden()) { temp |= _A_HIDDEN; } if(fileinfo.is_system()) { temp |= _A_SYSTEM; } if(fileinfo.is_archive()) { temp |= _A_ARCH; } if(_dos_setfileattr(fname, temp) != 0) { return SETATTRIB_FAILURE; } #endif return OK; } ////////////////////////////////////////**************************************** #endif