HRESULT CHandler::SetMainMethod( CCompressionMethodMode &methodMode #ifndef _7ZIP_ST , UInt32 numThreads #endif ) { methodMode.Bonds = _bonds; CObjectVector<COneMethodInfo> methods = _methods; { FOR_VECTOR (i, methods) { AString &methodName = methods[i].MethodName; if (methodName.IsEmpty()) methodName = kDefaultMethodName; } if (methods.IsEmpty()) { COneMethodInfo &m = methods.AddNew(); m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); methodMode.DefaultMethod_was_Inserted = true; } }
HRESULT CDirEnumerator::GetNextFile(NFind::CFileInfo &fileInfo, bool &filled, FString &resPath) { filled = false; for (;;) { if (Enumerators.IsEmpty()) { if (Index >= FileNames.Size()) return S_OK; const FString &path = FileNames[Index]; int pos = path.ReverseFind(FCHAR_PATH_SEPARATOR); resPath.Empty(); if (pos >= 0) resPath = path.Left(pos + 1); #ifdef _WIN32 // it's for "c:" paths/ if (BasePrefix.IsEmpty() && path.Length() == 2 && path[1] == ':') { fileInfo.Name = path; fileInfo.Attrib = FILE_ATTRIBUTE_DIRECTORY; fileInfo.Size = 0; } else #endif if (!fileInfo.Find(BasePrefix + path)) { WRes errorCode = GetNormalizedError(); resPath = path; return errorCode; } Index++; break; } bool found; if (!Enumerators.Back().Next(fileInfo, found)) { HRESULT errorCode = GetNormalizedError(); resPath = Prefixes.Back(); return errorCode; } if (found) { resPath = Prefixes.Back(); break; } Enumerators.DeleteBack(); Prefixes.DeleteBack(); } resPath += fileInfo.Name; if (!FlatMode && fileInfo.IsDir()) { FString prefix = resPath + FCHAR_PATH_SEPARATOR; Enumerators.Add(NFind::CEnumerator(BasePrefix + prefix + FCHAR_ANY_MASK)); Prefixes.Add(prefix); } filled = true; return S_OK; }
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties) { if (properties.IsEmpty()) return S_OK; CMyComPtr<ISetProperties> setProperties; unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties); if (!setProperties) return S_OK; UStringVector realNames; CPropVariant *values = new CPropVariant[properties.Size()]; try { int i; for(i = 0; i < properties.Size(); i++) { const CProperty &property = properties[i]; NCOM::CPropVariant propVariant; UString name = property.Name; if (property.Value.IsEmpty()) { if (!name.IsEmpty()) { wchar_t c = name.Back(); if (c == L'-') propVariant = false; else if (c == L'+') propVariant = true; if (propVariant.vt != VT_EMPTY) name.DeleteBack(); } } else ParseNumberString(property.Value, propVariant); realNames.Add(name); values[i] = propVariant; } CRecordVector<const wchar_t *> names; for(i = 0; i < realNames.Size(); i++) names.Add((const wchar_t *)realNames[i]); RINOK(setProperties->SetProperties(&names.Front(), values, names.Size())); } catch(...) { delete []values; throw; } delete []values; return S_OK; }
bool CDirEnumerator::GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &resPath, DWORD &errorCode) { filled = false; for (;;) { if (Enumerators.IsEmpty()) { if (Index >= FileNames.Size()) return true; const UString &path = FileNames[Index]; int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR); resPath.Empty(); if (pos >= 0) resPath = path.Left(pos + 1); if (!NFind::FindFile(BasePrefix + path, fileInfo)) { errorCode = ::GetLastError(); resPath = path; return false; } Index++; break; } bool found; if (!Enumerators.Back().Next(fileInfo, found)) { errorCode = ::GetLastError(); resPath = Prefixes.Back(); return false; } if (found) { resPath = Prefixes.Back(); break; } Enumerators.DeleteBack(); Prefixes.DeleteBack(); } resPath += fileInfo.Name; if (!FlatMode && fileInfo.IsDir()) { UString prefix = resPath + (UString)(wchar_t)kDirDelimiter; Enumerators.Add(NFind::CEnumeratorW(BasePrefix + prefix + (UString)(wchar_t)kAnyStringWildcard)); Prefixes.Add(prefix); } filled = true; return true; }
HRESULT CInArchive::ReadLocals( CObjectVector<CItemEx> &items, CProgressVirt *progress) { items.Clear(); while (m_Signature == NSignature::kLocalFileHeader) { CItemEx item; item.LocalHeaderPos = m_Position - 4 - ArcInfo.MarkerPos; // we write ralative LocalHeaderPos here. Later we can correct it to real Base. try { ReadLocalItem(item); item.FromLocal = true; if (item.HasDescriptor()) ReadLocalItemDescriptor(item); else { RINOK(IncreaseRealPosition(item.PackSize)); } items.Add(item); m_Signature = ReadUInt32(); } catch (CUnexpectEnd &) { if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0])) return S_FALSE; throw; } if (progress && items.Size() % 1 == 0) RINOK(progress->SetCompletedLocal(items.Size(), item.LocalHeaderPos)); } if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader) if (IsStrangeItem(items[0])) return S_FALSE; return S_OK; }
HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress) { HRESULT res; try { res = ReadHeaders2(items, progress); } catch (const CInBufferException &e) { res = e.ErrorCode; } catch (const CUnexpectEnd &) { if (items.IsEmpty()) return S_FALSE; UnexpectedEnd = true; res = S_OK; } catch (...) { _inBufMode = false; throw; } ArcInfo.FinishPos = m_Position; _inBufMode = false; return res; }
HRESULT CHandler::SetCompressionMethod( CCompressionMethodMode &methodMode, CObjectVector<COneMethodInfo> &methodsInfo #ifdef COMPRESS_MT , UInt32 numThreads #endif ) { UInt32 level = _level; if (methodsInfo.IsEmpty()) { COneMethodInfo oneMethodInfo; oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName); methodsInfo.Add(oneMethodInfo); } bool needSolid = false; for(int i = 0; i < methodsInfo.Size(); i++) { COneMethodInfo &oneMethodInfo = methodsInfo[i]; SetCompressionMethod2(oneMethodInfo #ifdef COMPRESS_MT , numThreads #endif ); if (!IsCopyMethod(oneMethodInfo.MethodName)) needSolid = true; CMethodFull methodFull; if (!FindMethod( EXTERNAL_CODECS_VARS oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams)) return E_INVALIDARG; methodFull.Props = oneMethodInfo.Props; methodMode.Methods.Add(methodFull); if (!_numSolidBytesDefined) { for (int j = 0; j < methodFull.Props.Size(); j++) { const CProp &prop = methodFull.Props[j]; if ((prop.Id == NCoderPropID::kDictionarySize || prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4) { _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7; const UInt64 kMinSize = (1 << 24); if (_numSolidBytes < kMinSize) _numSolidBytes = kMinSize; _numSolidBytesDefined = true; break; } } } } if (!needSolid && !_numSolidBytesDefined) { _numSolidBytesDefined = true; _numSolidBytes = 0; } return S_OK; }
HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress) { items.Clear(); // m_Signature must be kLocalFileHeader or kEcd // m_Position points to next byte after signature RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); if (!_inBuffer.Create(1 << 15)) return E_OUTOFMEMORY; _inBuffer.SetStream(Stream); bool needReadCd = true; bool localsWereRead = false; if (m_Signature == NSignature::kEcd) { // It must be empty archive or backware archive // we don't support backware archive still const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); CEcd ecd; ecd.Parse(buf); // if (ecd.cdSize != 0) // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ?? if (!ecd.IsEmptyArc()) return S_FALSE; ArcInfo.Base = ArcInfo.MarkerPos; needReadCd = false; IsArc = true; // check it: we need more tests? RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position)); } UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0; HRESULT res = S_OK; if (needReadCd) { CItemEx firstItem; // try { try { if (!ReadLocalItem(firstItem)) return S_FALSE; } catch(CUnexpectEnd &) { return S_FALSE; } IsArc = true; res = ReadCd(items, cdRelatOffset, cdSize, progress); if (res == S_OK) m_Signature = ReadUInt32(); } // catch() { res = S_FALSE; } if (res != S_FALSE && res != S_OK) return res; if (res == S_OK && items.Size() == 0) res = S_FALSE; if (res == S_OK) { // we can't read local items here to keep _inBufMode state firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base; int index = FindItem(items, firstItem.LocalHeaderPos); if (index == -1) res = S_FALSE; else if (!AreItemsEqual(firstItem, items[index])) res = S_FALSE; ArcInfo.CdWasRead = true; ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; } } CObjectVector<CItemEx> cdItems; bool needSetBase = false; unsigned numCdItems = items.Size(); if (res == S_FALSE) { // CD doesn't match firstItem so we clear items and read Locals. items.Clear(); localsWereRead = true; _inBufMode = false; ArcInfo.Base = ArcInfo.MarkerPos; RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position)); m_Signature = ReadUInt32(); RINOK(ReadLocals(items, progress)); if (m_Signature != NSignature::kCentralFileHeader) { m_Position -= 4; NoCentralDir = true; HeadersError = true; return S_OK; } _inBufMode = true; _inBuffer.Init(); cdAbsOffset = m_Position - 4; for (;;) { CItemEx cdItem; RINOK(ReadCdItem(cdItem)); cdItems.Add(cdItem); if (progress && cdItems.Size() % 1 == 0) RINOK(progress->SetCompletedCD(items.Size())); m_Signature = ReadUInt32(); if (m_Signature != NSignature::kCentralFileHeader) break; } cdSize = (m_Position - 4) - cdAbsOffset; needSetBase = true; numCdItems = cdItems.Size(); if (!cdItems.IsEmpty()) { ArcInfo.CdWasRead = true; ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos; } } CEcd64 ecd64; bool isZip64 = false; UInt64 ecd64AbsOffset = m_Position - 4; if (m_Signature == NSignature::kEcd64) { IsZip64 = isZip64 = true; UInt64 recordSize = ReadUInt64(); const unsigned kBufSize = kEcd64_MainSize; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); ecd64.Parse(buf); Skip64(recordSize - kEcd64_MainSize); m_Signature = ReadUInt32(); if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) return E_NOTIMPL; if (needSetBase) { ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; cdRelatOffset = ecd64.cdStartOffset; needSetBase = false; } if (ecd64.numEntriesInCDOnThisDisk != numCdItems || ecd64.numEntriesInCD != numCdItems || ecd64.cdSize != cdSize || (ecd64.cdStartOffset != cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; } if (m_Signature == NSignature::kEcd64Locator) { if (!isZip64) return S_FALSE; /* UInt32 startEndCDDiskNumber = */ ReadUInt32(); UInt64 ecd64RelatOffset = ReadUInt64(); /* UInt32 numberOfDisks = */ ReadUInt32(); if (ecd64AbsOffset != ArcInfo.Base + ecd64RelatOffset) return S_FALSE; m_Signature = ReadUInt32(); } if (m_Signature != NSignature::kEcd) return S_FALSE; const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); CEcd ecd; ecd.Parse(buf); COPY_ECD_ITEM_16(thisDiskNumber); COPY_ECD_ITEM_16(startCDDiskNumber); COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk); COPY_ECD_ITEM_16(numEntriesInCD); COPY_ECD_ITEM_32(cdSize); COPY_ECD_ITEM_32(cdStartOffset); if (needSetBase) { ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; cdRelatOffset = ecd64.cdStartOffset; needSetBase = false; } if (localsWereRead && (UInt64)ArcInfo.Base != ArcInfo.MarkerPos) { UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base; for (unsigned i = 0; i < items.Size(); i++) items[i].LocalHeaderPos += delta; } // ---------- merge Central Directory Items ---------- if (!cdItems.IsEmpty()) { for (unsigned i = 0; i < cdItems.Size(); i++) { const CItemEx &cdItem = cdItems[i]; int index = FindItem(items, cdItem.LocalHeaderPos); if (index == -1) { items.Add(cdItem); continue; } CItemEx &item = items[index]; if (item.Name != cdItem.Name // || item.Name.Len() != cdItem.Name.Len() || item.PackSize != cdItem.PackSize || item.Size != cdItem.Size // item.ExtractVersion != cdItem.ExtractVersion || !FlagsAreSame(item, cdItem) || item.Crc != cdItem.Crc) continue; // item.LocalHeaderPos = cdItem.LocalHeaderPos; // item.Name = cdItem.Name; item.MadeByVersion = cdItem.MadeByVersion; item.CentralExtra = cdItem.CentralExtra; item.InternalAttrib = cdItem.InternalAttrib; item.ExternalAttrib = cdItem.ExternalAttrib; item.Comment = cdItem.Comment; item.FromCentral = cdItem.FromCentral; } } if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) return E_NOTIMPL; if (isZip64) { if (ecd64.numEntriesInCDOnThisDisk != items.Size()) HeadersError = true; } else { // old 7-zip could store 32-bit number of CD items to 16-bit field. if ((UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)numCdItems || (UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)items.Size()) HeadersError = true; } ReadBuffer(ArcInfo.Comment, ecd.commentSize); _inBufMode = false; _inBuffer.Free(); if ( (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) || (UInt32)ecd64.cdSize != (UInt32)cdSize || ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; // printf("\nOpen OK"); return S_OK; }
DWORD CDirEnumerator::GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath) { filled = false; resPath.Empty(); for (;;) { #if defined(_WIN32) && !defined(UNDER_CE) bool isRootPrefix = (BasePrefix.IsEmpty() || (NName::IsSuperPath(BasePrefix) && BasePrefix[NName::kSuperPathPrefixSize] == 0)); #endif if (Enumerators.IsEmpty()) { if (Index >= FilePaths.Size()) return S_OK; const FString &path = FilePaths[Index++]; int pos = path.ReverseFind_PathSepar(); if (pos >= 0) resPath.SetFrom(path, pos + 1); #if defined(_WIN32) && !defined(UNDER_CE) if (isRootPrefix && path.Len() == 2 && NName::IsDrivePath2(path)) { // we use "c:" item as directory item fi.ClearBase(); fi.Name = path; fi.SetAsDir(); fi.Size = 0; } else #endif if (!fi.Find(BasePrefix + path)) { DWORD error = GetNormalizedError(); resPath = path; return error; } break; } bool found; if (Enumerators.Back().Next(fi, found)) { if (found) { resPath = Prefixes.Back(); break; } } else { DWORD error = GetNormalizedError(); resPath = Prefixes.Back(); Enumerators.DeleteBack(); Prefixes.DeleteBack(); return error; } Enumerators.DeleteBack(); Prefixes.DeleteBack(); } resPath += fi.Name; if (EnterToDirs && fi.IsDir()) { FString s = resPath; s.Add_PathSepar(); Prefixes.Add(s); s += FCHAR_ANY_MASK; Enumerators.Add(NFind::CEnumerator(BasePrefix + s)); } filled = true; return S_OK; }
DWORD CDirEnumerator::GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath) { filled = false; resPath.Empty(); for (;;) { if (Enumerators.IsEmpty()) { if (Index >= FilePaths.Size()) return S_OK; const FString &path = FilePaths[Index++]; int pos = path.ReverseFind(FCHAR_PATH_SEPARATOR); if (pos >= 0) resPath.SetFrom(path, pos + 1); #ifdef _WIN32 if (BasePrefix.IsEmpty() && path.Len() == 2 && path[1] == ':') { // we use "c:" item as directory item fi.Clear(); fi.Name = path; fi.SetAsDir(); fi.Size = 0; } else #endif if (!fi.Find(BasePrefix + path)) { DWORD error = GetNormalizedError(); resPath = path; return error; } break; } bool found; if (Enumerators.Back().Next(fi, found)) { if (found) { resPath = Prefixes.Back(); break; } } else { DWORD error = GetNormalizedError(); resPath = Prefixes.Back(); Enumerators.DeleteBack(); Prefixes.DeleteBack(); return error; } Enumerators.DeleteBack(); Prefixes.DeleteBack(); } resPath += fi.Name; if (EnterToDirs && fi.IsDir()) { FString s = resPath; s += FCHAR_PATH_SEPARATOR; Prefixes.Add(s); s += FCHAR_ANY_MASK; Enumerators.Add(NFind::CEnumerator(BasePrefix + s)); } filled = true; return S_OK; }