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; #ifndef ANDROID 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 #endif if(m_typeIndex < 0) { #ifndef ANDROID //I don't *think* we care about this // uncompressed if(!CopyFile(m_filename, outFilename, false)) #endif rv = 0; } else { IInArchive* object = NULL; HRESULT hr = E_FAIL; if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object))) { InFileStream* ifs = new InFileStream(m_filename); if(SUCCEEDED(object->Open(ifs,0,0))) { gameInfo.resize(rv); OutStream* os = new OutStream(index, outFilename); const UInt32 indices [1] = {index}; hr = object->Extract(indices, 1, 0, os); object->Close(); } object->Release(); } if(FAILED(hr)) rv = 0; } #ifndef ANDROID if(outAttributes & FILE_ATTRIBUTE_READONLY) SetFileAttributes(outFilename, outAttributes); // restore read-only attribute #endif 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 { IInArchive* object = NULL; HRESULT hr = E_FAIL; if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object))) { InFileStream* ifs = new InFileStream(m_filename); if(SUCCEEDED(object->Open(ifs,0,0))) { OutStream* os = new OutStream(index, outBuffer, item.size); const UInt32 indices [1] = {index}; hr = object->Extract(indices, 1, 0, os); object->Close(); } object->Release(); } if(FAILED(hr)) 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; m_filename = new char[strlen(filename)+1]; strcpy(m_filename, filename); // detect archive type using format signature in file for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++) { fseek(file, 0, SEEK_SET); std::string& formatSig = s_formatInfos[i].signature; 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].signature.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); } else { IInArchive* object = NULL; if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object))) { InFileStream* ifs = new InFileStream(filename); if(SUCCEEDED(object->Open(ifs,0,0))) { UInt32 numItems = 0; object->GetNumberOfItems(&numItems); m_numItems = numItems; m_items = new ArchiveItem[m_numItems]; for(int i = 0; i < m_numItems; i++) { PROPVARIANT var = {VT_EMPTY}; ArchiveItem& item = m_items[i]; object->GetProperty(i, kpidSize, &var); item.size = var.uhVal.LowPart; object->GetProperty(i, kpidPath, &var); std::string& path = wstrToStr(var.bstrVal); item.name = new char[path.size()+1]; strcpy(item.name, path.c_str()); //object->GetProperty(i, kpidMethod, &var); //std::string& method = wstrToStr(var.bstrVal); //item.method = new char[method.size()+1]; //strcpy(item.method, method.c_str()); object->GetProperty(i, kpidEncrypted, &var); #ifdef _NO_CRYPTO if(var.boolVal) item.size = 0; // don't support decompressing it, pretend size zero #else #error password support NYI... see client7z.cpp item.encrypted = !!var.boolVal; #endif VariantClear((VARIANTARG*)&var); } object->Close(); } object->Release(); } } fclose(file); }