BLARGG_EXPORT fex_err_t fex_open( fex_t** fe_out, const char path [] ) { *fe_out = NULL; fex_type_t type; RETURN_ERR( fex_identify_file( &type, path ) ); return fex_open_type( fe_out, path, type ); }
int ArchiveFile::ExtractItem(int index, const char* outFilename) const { assert(!s_formatInfos.empty()); //assert(index >= 0 && index < m_numItems); if(!(index >= 0 && index < m_numItems)) return 0; ArchiveItem& item = m_items[index]; int rv = item.size; DWORD outAttributes = GetFileAttributes(outFilename); if(outAttributes & FILE_ATTRIBUTE_READONLY) SetFileAttributes(outFilename, outAttributes & ~FILE_ATTRIBUTE_READONLY); // temporarily remove read-only attribute so we can decompress to there if(m_typeIndex < 0) { // uncompressed if(!CopyFile(m_filename, outFilename, false)) rv = 0; } else { fex_t * object; fex_err_t err = fex_open_type( &object, m_filename, s_formatInfos[m_typeIndex].type ); if ( !err ) { if ( index != 0 ) err = fex_seek_arc( object, item.offset ); if ( !err ) { unsigned char * buffer = new unsigned char[item.size]; err = fex_read( object, buffer, item.size ); if ( !err ) { FILE * f = fopen(outFilename, "wb"); if (f) { fwrite( buffer, 1, item.size, f ); fclose( f ); } else rv = 0; } else rv = 0; } else rv = 0; fex_close( object ); } else rv = 0; } if(outAttributes & FILE_ATTRIBUTE_READONLY) SetFileAttributes(outFilename, outAttributes); // restore read-only attribute return rv; }
int ArchiveFile::ExtractItem(int index, unsigned char* outBuffer, int bufSize) const { assert(!s_formatInfos.empty()); //assert(index >= 0 && index < m_numItems); if(!(index >= 0 && index < m_numItems)) return 0; ArchiveItem& item = m_items[index]; if(bufSize < item.size) return 0; if(m_typeIndex < 0) { // uncompressed FILE* file = fopen(m_filename, "rb"); fread(outBuffer, 1, item.size, file); fclose(file); } else { fex_t * object; fex_err_t err = fex_open_type( &object, m_filename, s_formatInfos[m_typeIndex].type ); if ( !err ) { if ( index != 0 ) err = fex_seek_arc( object, item.offset ); if ( !err ) { err = fex_read( object, outBuffer, item.size ); if ( !err ) { fex_close( object ); return item.size; } } fex_close( object ); } return 0; } return item.size; }
ArchiveFile::ArchiveFile(const char* filename) { assert(!s_formatInfos.empty()); m_typeIndex = -1; m_numItems = 0; m_items = NULL; m_filename = NULL; FILE* file = fopen(filename, "rb"); if(!file) return; //TODO - maybe windows only check here if we ever drop fex into portable code. unfortunately this is probably too unwieldy to ever happen //convert the filename to unicode wchar_t temp_wchar[MAX_PATH*2]; char filename_utf8[MAX_PATH*4]; MultiByteToWideChar(CP_THREAD_ACP,0,filename,-1,temp_wchar,ARRAY_SIZE(temp_wchar)); //now convert it back to utf-8. is there a way to do this in one step? WideCharToMultiByte(CP_UTF8,0,temp_wchar,-1,filename_utf8,ARRAY_SIZE(filename_utf8), NULL, NULL); m_filename = new char[strlen(filename_utf8)+1]; strcpy(m_filename, filename_utf8); // detect archive type using format signature in file for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++) { for (size_t j = 0; j < s_formatInfos[i].signatures.size(); j++) { fseek(file, 0, SEEK_SET); std::string& formatSig = s_formatInfos[i].signatures[j]; int len = formatSig.size(); if(len == 0) continue; // because some formats have no signature char* fileSig = (char*)_alloca(len); fread(fileSig, 1, len, file); if(!memcmp(formatSig.c_str(), fileSig, len)) m_typeIndex = i; } } // if no signature match has been found, detect archive type using filename. // this is only for signature-less formats const char* fileExt = strrchr(filename, '.'); if(fileExt++) { for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++) { if(s_formatInfos[i].signatures.empty()) { std::vector<std::string>& formatExts = s_formatInfos[i].extensions; for(size_t j = 0; j < formatExts.size(); j++) { if(!_stricmp(formatExts[j].c_str(), fileExt)) { m_typeIndex = i; break; } } } } } if(m_typeIndex < 0) { // uncompressed m_numItems = 1; m_items = new ArchiveItem[m_numItems]; fseek(file, 0, SEEK_END); m_items[0].size = ftell(file); m_items[0].name = new char[strlen(filename)+1]; strcpy(m_items[0].name, filename); m_items[0].wname = _wcsdup(temp_wchar); } else { fex_t * object; fex_err_t err = fex_open_type( &object, m_filename, s_formatInfos[m_typeIndex].type ); if ( !err ) { int numItems = 0; while ( !fex_done(object) ) { numItems++; err = fex_next(object); if ( err ) break; } err = fex_rewind(object); if ( err ) { fex_close(object); return; } m_numItems = numItems; m_items = new ArchiveItem[m_numItems]; for (int i = 0; i < m_numItems; i++) { ArchiveItem& item = m_items[i]; const char * name = fex_name(object); item.name = new char[strlen(name)+1]; strcpy(item.name, name); const wchar_t* wname = fex_wname(object); if(wname) { item.wname = _wcsdup(fex_wname(object)); } else { const char* name = fex_name(object); wchar_t temp_wchar[MAX_PATH]; //what code page to use??? who knows. MultiByteToWideChar(CP_ACP,0,name,-1,temp_wchar,ARRAY_SIZE(temp_wchar)); item.wname = _wcsdup(temp_wchar); } err = fex_stat(object); if (err) break; item.size = fex_size(object); item.offset = fex_tell_arc(object); fex_next(object); } fex_close(object); } } fclose(file); }