Exemple #1
0
  bool InitName(const UString &name, bool newStyle)
  {
    _first = true;
    _newStyle = newStyle;
    int dotPos = name.ReverseFind('.');
    UString basePart = name;
    if (dotPos >= 0)
    {
      UString ext = name.Mid(dotPos + 1);
      if (ext.CompareNoCase(L"rar") == 0)
      {
        _afterPart = name.Mid(dotPos);
        basePart = name.Left(dotPos);
      }
      else if (ext.CompareNoCase(L"exe") == 0)
      {
        _afterPart = L".rar";
        basePart = name.Left(dotPos);
      }
      else if (!_newStyle)
      {
        if (ext.CompareNoCase(L"000") == 0 ||
            ext.CompareNoCase(L"001") == 0 ||
            ext.CompareNoCase(L"r00") == 0 ||
            ext.CompareNoCase(L"r01") == 0)
        {
          _afterPart.Empty();
          _first = false;
          _changedPart = ext;
          _unchangedPart = name.Left(dotPos + 1);
          return true;
        }
      }
    }

    if (!_newStyle)
    {
      _afterPart.Empty();
      _unchangedPart = basePart + UString(L".");
      _changedPart = L"r00";
      return true;
    }

    int numLetters = 1;
    if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0")
    {
      while (numLetters < basePart.Length())
      {
        if (basePart[basePart.Length() - numLetters - 1] != '0')
          break;
        numLetters++;
      }
    }
    else
      return false;
    _unchangedPart = basePart.Left(basePart.Length() - numLetters);
    _changedPart = basePart.Right(numLetters);
    return true;
  }
Exemple #2
0
int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
{
  if (lpData == NULL)
    return 0;
  CPanel *panel = (CPanel*)lpData;
  
  switch(panel->_sortID)
  {
    // if (panel->_sortIndex == 0)
    case kpidName:
    {
      const UString name1 = panel->GetItemName((int)lParam1);
      const UString name2 = panel->GetItemName((int)lParam2);
      int res = name1.CompareNoCase(name2);
      /*
      if (res != 0 || !panel->_flatMode)
        return res;
      const UString prefix1 = panel->GetItemPrefix(lParam1);
      const UString prefix2 = panel->GetItemPrefix(lParam2);
      return res = prefix1.CompareNoCase(prefix2);
      */
      return res;
    }
    case kpidNoProperty:
    {
      return MyCompare(lParam1, lParam2);
    }
    case kpidExtension:
    {
      const UString ext1 = GetExtension(panel->GetItemName((int)lParam1));
      const UString ext2 = GetExtension(panel->GetItemName((int)lParam2));
      return ext1.CompareNoCase(ext2);
    }
  }
  /*
  if (panel->_sortIndex == 1)
    return MyCompare(file1.Size, file2.Size);
  return ::CompareFileTime(&file1.MTime, &file2.MTime);
  */

  // PROPID propID = panel->_properties[panel->_sortIndex].ID;
  PROPID propID = panel->_sortID;

  NCOM::CPropVariant propVariant1, propVariant2;
  // Name must be first property
  panel->_folder->GetProperty((UINT32)lParam1, propID, &propVariant1);
  panel->_folder->GetProperty((UINT32)lParam2, propID, &propVariant2);
  if (propVariant1.vt != propVariant2.vt)
    return 0; // It means some BUG
  if (propVariant1.vt == VT_BSTR)
  {
    return _wcsicmp(propVariant1.bstrVal, propVariant2.bstrVal);
  }
  return propVariant1.Compare(propVariant2);
  // return 0;
}
bool StringToBool(const UString &s, bool &res)
{
  if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0 || s.Compare(L"+") == 0)
  {
    res = true;
    return true;
  }
  if (s.CompareNoCase(L"OFF") == 0 || s.Compare(L"-") == 0)
  {
    res = false;
    return true;
  }
  return false;
}
bool FindMethod(
  #ifdef EXTERNAL_CODECS
  ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
  #endif
  const UString &name,
  CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)
{
  UInt32 i;
  for (i = 0; i < g_NumCodecs; i++)
  {
    const CCodecInfo &codec = *g_Codecs[i];
    if (name.CompareNoCase(codec.Name) == 0)
    {
      methodId = codec.Id;
      numInStreams = codec.NumInStreams;
      numOutStreams = 1;
      return true;
    }
  }
  #ifdef EXTERNAL_CODECS
  if (externalCodecs)
    for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
    {
      const CCodecInfoEx &codec = (*externalCodecs)[i];
      if (codec.Name.CompareNoCase(name) == 0)
      {
        methodId = codec.Id;
        numInStreams = codec.NumInStreams;
        numOutStreams = codec.NumOutStreams;
        return true;
      }
    }
  #endif
  return false;
}
Exemple #5
0
static UString GetIconPath(const UString &filePath,
    const CLSID &clsID, const UString &extension, Int32 &iconIndex)
{
  CPluginLibrary library;
  CMyComPtr<IFolderManager> folderManager;
  CMyComPtr<IFolderFolder> folder;
  if (filePath.IsEmpty())
    folderManager = new CArchiveFolderManager;
  else if (library.LoadAndCreateManager(filePath, clsID, &folderManager) != S_OK)
    return UString();
  CMyComBSTR extBSTR;
  if (folderManager->GetExtensions(&extBSTR) != S_OK)
    return UString();
  const UString ext2 = (const wchar_t *)extBSTR;
  UStringVector exts;
  SplitString(ext2, exts);
  for (int i = 0; i < exts.Size(); i++)
  {
    const UString &plugExt = exts[i];
    if (extension.CompareNoCase((const wchar_t *)plugExt) == 0)
    {
      CMyComBSTR iconPathTemp;
      if (folderManager->GetIconPath(plugExt, &iconPathTemp, &iconIndex) != S_OK)
        break;
      if (iconPathTemp != 0)
        return (const wchar_t *)iconPathTemp;
    }
  }
  return UString();
}
Exemple #6
0
static bool IsExeExt(const UString &ext)
{
  for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++)
    if (ext.CompareNoCase(g_ExeExts[i]) == 0)
      return true;
  return false;
}
Exemple #7
0
void AddUniqueString(UStringVector &list, const UString &s)
{
  for (int i = 0; i < list.Size(); i++)
    if (s.CompareNoCase(list[i]) == 0)
      return;
  list.Add(s);
}
Exemple #8
0
int COpenCallbackImp::FindName(const UString &name)
{
  for (int i = 0; i < FileNames.Size(); i++)
    if (name.CompareNoCase(FileNames[i]) == 0)
      return i;
  return -1;
}
int CArchiveFolderManager::FindFormat(const UString &type)
{
  for (int i = 0; i < _codecs->Formats.Size(); i++)
    if (type.CompareNoCase(_codecs->Formats[i].Name) == 0)
      return i;
  return -1;
}
static inline int MyFileNameCompare(const UString &s1, const UString &s2)
{
  return 
  #ifdef _WIN32
  s1.CompareNoCase(s2);
  #else
  s1.Compare(s2);
  #endif
}
Exemple #11
0
int CCodecLib::FindIconIndex(const UString &ext) const
{
  for (int i = 0; i < IconPairs.Size(); i++)
  {
	const CIconPair &pair = IconPairs[i];
	if (ext.CompareNoCase(pair.Ext) == 0)
	  return pair.IconIndex;
  }
  return -1;
}
Exemple #12
0
HRESULT MyMoveFolder(
    const UString &srcPath,
    const UString &destPathSpec,
    IFolderOperationsExtractCallback *callback,
    UInt64 &completedSize)
{
  UString destPath = destPathSpec;
  int len = srcPath.Length();
  if (destPath.Length() >= len && srcPath.CompareNoCase(destPath.Left(len)) == 0)
  {
    if (destPath.Length() == len || destPath[len] == WCHAR_PATH_SEPARATOR)
    {
      UString message = UString(L"can not move folder \'") +
          destPath + UString(L"\' onto itself");
      RINOK(callback->ShowMessage(message));
      return E_ABORT;
    }
  }

  if (MyMoveFile(srcPath, destPath, callback, completedSize))
    return S_OK;

  if (!NDirectory::CreateComplexDirectory(destPath))
  {
    UString message = UString(L"can not create folder ") +  destPath;
    RINOK(callback->ShowMessage(message));
    return E_ABORT;
  }
  {
    CEnumeratorW enumerator(CombinePath(srcPath, L"*"));
    CFileInfoEx fi;
    while (enumerator.Next(fi))
    {
      const UString srcPath2 = CombinePath(srcPath, fi.Name);
      const UString destPath2 = CombinePath(destPath, fi.Name);
      if (fi.IsDir())
      {
        RINOK(MyMoveFolder(srcPath2, destPath2, callback, completedSize));
      }
      else
      {
        RINOK(MyMoveFile(srcPath2, fi, destPath2, callback, completedSize));
      }
    }
  }
  if (!NDirectory::MyRemoveDirectory(srcPath))
  {
    UString message = UString(L"can not remove folder") + srcPath;
    RINOK(callback->ShowMessage(message));
    return E_ABORT;
  }
  return S_OK;
}
static UString GetSubFolderNameForExtract(const UString &archiveName)
{
  int dotPos = archiveName.ReverseFind(L'.');
  if (dotPos < 0)
    return archiveName + UString(L"~");
  const UString ext = archiveName.Mid(dotPos + 1);
  UString res = archiveName.Left(dotPos);
  res.TrimRight();
  dotPos = res.ReverseFind(L'.');
  if (dotPos > 0)
  {
    const UString ext2 = res.Mid(dotPos + 1);
    if (ext.CompareNoCase(L"rar") == 0 &&
        (ext2.CompareNoCase(L"part001") == 0 ||
         ext2.CompareNoCase(L"part01") == 0 ||
         ext2.CompareNoCase(L"part1") == 0) ||
        IsItArcExt(ext2) && ext.CompareNoCase(L"001") == 0)
      res = res.Left(dotPos);
    res.TrimRight();
  }
  return GetCorrectFullFsPath(res);
}
Exemple #14
0
bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
{
  iconIndex = -1;
  for (int i = 0; i < IconPairs.Size(); i++)
  {
    const CIconPair &pair = IconPairs[i];
    if (ext.CompareNoCase(pair.Ext) == 0)
    {
      iconIndex = pair.IconIndex;
      return true;
    }
  }
  return false;
}
Exemple #15
0
HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const
{ 
  for (int i = 0; i < Codecs.Size(); i++)
  {
	const CDllCodecInfo &codec = Codecs[i];
	if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned)
	  continue;
	const CCodecLib &lib = Libs[codec.LibIndex];
	UString res;
	NWindows::NCOM::CPropVariant prop;
	RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop));
	if (prop.vt == VT_BSTR)
	  res = prop.bstrVal;
	else if (prop.vt != VT_EMPTY)
	  continue;
	if (name.CompareNoCase(res) == 0)
	  return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder);
  }
  return CLASS_E_CLASSNOTAVAILABLE;
}
Exemple #16
0
int CProxyFolder::FindDirSubItemIndex(const UString &name, int &insertPos) const
{
  int left = 0, right = Folders.Size();
  for (;;)
  {
    if (left == right)
    {
      insertPos = left;
      return -1;
    }
    int mid = (left + right) / 2;
    int compare = name.CompareNoCase(Folders[mid].Name);
    if (compare == 0)
      return mid;
    if (compare < 0)
      right = mid;
    else
      left = mid + 1;
  }
}
Exemple #17
0
int CCodecs::FindFormatForArchiveName(const UString &archivePath) const
{
  int slashPos1 = archivePath.ReverseFind(L'\\');
  int slashPos2 = archivePath.ReverseFind(L'.');
  int dotPos = archivePath.ReverseFind(L'.');
  if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2)
	return -1;
  UString ext = archivePath.Mid(dotPos + 1);
  for (int i = 0; i < Formats.Size(); i++)
  {
	const CArcInfoEx &arc = Formats[i];
	if (!arc.UpdateEnabled)
	  continue;
	// if (arc.FindExtension(ext) >= 0)
	UString mainExt = arc.GetMainExt();
	if (!mainExt.IsEmpty() && ext.CompareNoCase(mainExt) == 0)
	  return i;
  }
  return -1;
}
Exemple #18
0
static HRESULT MyCopyFile(
    const UString &srcPath,
    const CFileInfoW &srcFileInfo,
    const UString &destPathSpec,
    IFolderOperationsExtractCallback *callback,
    UInt64 &completedSize)
{
  UString destPath = destPathSpec;
  if (destPath.CompareNoCase(srcPath) == 0)
  {
    UString message = UString(L"can not move file \'") + destPath + UString(L"\' onto itself");
    RINOK(callback->ShowMessage(message));
    return E_ABORT;
  }

  Int32 writeAskResult;
  CMyComBSTR destPathResult;
  RINOK(callback->AskWrite(
      srcPath,
      BoolToInt(false),
      &srcFileInfo.MTime, &srcFileInfo.Size,
      destPath,
      &destPathResult,
      &writeAskResult));
  if (IntToBool(writeAskResult))
  {
    UString destPathNew = UString(destPathResult);
    RINOK(callback->SetCurrentFilePath(srcPath));
    if (!MyCopyFile(srcPath, destPathNew, callback, completedSize))
    {
      UString message = NError::MyFormatMessageW(GetLastError()) +
        UString(L" \'") +
        UString(destPathNew) +
        UString(L"\'");
      RINOK(callback->ShowMessage(message));
      return E_ABORT;
    }
  }
  completedSize += srcFileInfo.Size;
  return callback->SetCompleted(&completedSize);
}
Exemple #19
0
HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
{
  UString name = nameSpec;
  name.MakeUpper();
  if (name.IsEmpty())
    return E_INVALIDARG;
  
  if (name[0] == L'S')
  {
    name.Delete(0);
    if (name.IsEmpty())
      return SetSolidFromPROPVARIANT(value);
    if (value.vt != VT_EMPTY)
      return E_INVALIDARG;
    return SetSolidFromString(name);
  }
  
  UInt32 number;
  int index = ParseStringToUInt32(name, number);
  UString realName = name.Mid(index);
  if (index == 0)
  {
    if (name.CompareNoCase(L"RSFX") == 0) return PROPVARIANT_to_bool(value, _removeSfxBlock);
    if (name.CompareNoCase(L"HC") == 0) return PROPVARIANT_to_bool(value, _compressHeaders);
    if (name.CompareNoCase(L"HCF") == 0)
    {
      bool compressHeadersFull = true;
      RINOK(PROPVARIANT_to_bool(value, compressHeadersFull));
      return compressHeadersFull ? S_OK: E_INVALIDARG;
    }
    if (name.CompareNoCase(L"HE") == 0)
    {
      RINOK(PROPVARIANT_to_bool(value, _encryptHeaders));
      _encryptHeadersSpecified = true;
      return S_OK;
    }
    if (name.CompareNoCase(L"TC") == 0) return PROPVARIANT_to_bool(value, WriteCTime);
    if (name.CompareNoCase(L"TA") == 0) return PROPVARIANT_to_bool(value, WriteATime);
    if (name.CompareNoCase(L"TM") == 0) return PROPVARIANT_to_bool(value, WriteMTime);
    if (name.CompareNoCase(L"V") == 0) return PROPVARIANT_to_bool(value, _volumeMode);
  }
  return CMultiMethodProps::SetProperty(name, value);
}
Exemple #20
0
static bool CheckShellExtensionInfo2(const CSysString &extension, UString &iconPath, int &iconIndex)
{
  iconIndex = -1;
  iconPath.Empty();
  NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
  CKey extKey;
  if (extKey.Open(HKEY_CLASSES_ROOT, GetExtensionKeyName(extension), KEY_READ) != ERROR_SUCCESS)
    return false;
  CSysString programNameValue;
  if (extKey.QueryValue(NULL, programNameValue) != ERROR_SUCCESS)
    return false;
  CSysString extProgramKeyName = GetExtProgramKeyName(extension);
  UString programNameValueU = GetUnicodeString(programNameValue);
  if (programNameValueU.CompareNoCase(GetUnicodeString(extProgramKeyName)) != 0)
    return false;
  CKey iconKey;
  if (extKey.Open(HKEY_CLASSES_ROOT, extProgramKeyName + CSysString(TEXT(CHAR_PATH_SEPARATOR)) + kDefaultIconKeyName, KEY_READ) != ERROR_SUCCESS)
    return false;
  UString value;
  if (extKey.QueryValue(NULL, value) == ERROR_SUCCESS)
  {
    int pos = value.ReverseFind(L',');
    iconPath = value;
    if (pos >= 0)
    {
      const wchar_t *end;
      UInt64 index = ConvertStringToUInt64((const wchar_t *)value + pos + 1, &end);
      if (*end == 0)
      {
        iconIndex = (int)index;
        iconPath = value.Left(pos);
      }
    }
  }
  return true;
}
Exemple #21
0
Fichier : Main.cpp Projet : bks/qz7
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */,int /* nCmdShow */)
{
  g_hInstance = (HINSTANCE)hInstance;
  #ifndef _UNICODE
  g_IsNT = IsItWindowsNT();
  #endif
  InitCommonControls();

  UString archiveName, switches;
  #ifdef _SHELL_EXECUTE
  UString executeFile, executeParameters;
  #endif
  NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);

  UString fullPath;
  NDLL::MyGetModuleFileName(g_hInstance, fullPath);

  switches.Trim();
  bool assumeYes = false;
  if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0)
  {
    assumeYes = true;
    switches = switches.Mid(2);
    switches.Trim();
  }

  AString config;
  if (!ReadDataString(fullPath, kStartID, kEndID, config))
  {
    if (!assumeYes)
      ShowErrorMessage(L"Can't load config info");
    return 1;
  }

  UString dirPrefix = L"." WSTRING_PATH_SEPARATOR;
  UString appLaunched;
  bool showProgress = true;
  if (!config.IsEmpty())
  {
    CObjectVector<CTextConfigPair> pairs;
    if (!GetTextConfig(config, pairs))
    {
      if (!assumeYes)
        ShowErrorMessage(L"Config failed");
      return 1;
    }
    UString friendlyName = GetTextConfigValue(pairs, L"Title");
    UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt");
    UString progress = GetTextConfigValue(pairs, L"Progress");
    if (progress.CompareNoCase(L"no") == 0)
      showProgress = false;
    int index = FindTextConfigItem(pairs, L"Directory");
    if (index >= 0)
      dirPrefix = pairs[index].String;
    if (!installPrompt.IsEmpty() && !assumeYes)
    {
      if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |
          MB_ICONQUESTION) != IDYES)
        return 0;
    }
    appLaunched = GetTextConfigValue(pairs, L"RunProgram");
    
    #ifdef _SHELL_EXECUTE
    executeFile = GetTextConfigValue(pairs, L"ExecuteFile");
    executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches;
    #endif
  }

  NFile::NDirectory::CTempDirectory tempDir;
  if (!tempDir.Create(kTempDirPrefix))
  {
    if (!assumeYes)
      ShowErrorMessage(L"Can not create temp folder archive");
    return 1;
  }

  CCodecs *codecs = new CCodecs;
  CMyComPtr<IUnknown> compressCodecsInfo = codecs;
  HRESULT result = codecs->Load();
  if (result != S_OK)
  {
    ShowErrorMessage(L"Can not load codecs");
    return 1;
  }

  UString tempDirPath = GetUnicodeString(tempDir.GetPath());
  {
    bool isCorrupt = false;
    UString errorMessage;
    HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
      isCorrupt, errorMessage);
    
    if (result != S_OK)
    {
      if (!assumeYes)
      {
        if (result == S_FALSE || isCorrupt)
        {
          errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE);
          result = E_FAIL;
        }
        if (result != E_ABORT && !errorMessage.IsEmpty())
          ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
      }
      return 1;
    }
  }

  CCurrentDirRestorer currentDirRestorer;

  if (!SetCurrentDirectory(tempDir.GetPath()))
    return 1;
  
  HANDLE hProcess = 0;
#ifdef _SHELL_EXECUTE
  if (!executeFile.IsEmpty())
  {
    CSysString filePath = GetSystemString(executeFile);
    SHELLEXECUTEINFO execInfo;
    execInfo.cbSize = sizeof(execInfo);
    execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
    execInfo.hwnd = NULL;
    execInfo.lpVerb = NULL;
    execInfo.lpFile = filePath;

    if (!switches.IsEmpty())
      executeParameters += switches;

    CSysString parametersSys = GetSystemString(executeParameters);
    if (parametersSys.IsEmpty())
      execInfo.lpParameters = NULL;
    else
      execInfo.lpParameters = parametersSys;

    execInfo.lpDirectory = NULL;
    execInfo.nShow = SW_SHOWNORMAL;
    execInfo.hProcess = 0;
    /* BOOL success = */ ::ShellExecuteEx(&execInfo);
    UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
    if(result <= 32)
    {
      if (!assumeYes)
        ShowErrorMessage(L"Can not open file");
      return 1;
    }
    hProcess = execInfo.hProcess;
  }
  else
#endif
  {
    if (appLaunched.IsEmpty())
    {
      appLaunched = L"setup.exe";
      if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched)))
      {
        if (!assumeYes)
          ShowErrorMessage(L"Can not find setup.exe");
        return 1;
      }
    }
    
    {
      UString s2 = tempDirPath;
      NFile::NName::NormalizeDirPathPrefix(s2);
      appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, s2);
    }
    
    appLaunched.Replace(L"%%T", tempDirPath);

    if (!switches.IsEmpty())
    {
      appLaunched += L' ';
      appLaunched += switches;
    }
    STARTUPINFO startupInfo;
    startupInfo.cb = sizeof(startupInfo);
    startupInfo.lpReserved = 0;
    startupInfo.lpDesktop = 0;
    startupInfo.lpTitle = 0;
    startupInfo.dwFlags = 0;
    startupInfo.cbReserved2 = 0;
    startupInfo.lpReserved2 = 0;
    
    PROCESS_INFORMATION processInformation;
    
    CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched);
    
    BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,
      NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
      &startupInfo, &processInformation);
    if (createResult == 0)
    {
      if (!assumeYes)
        ShowLastErrorMessage();
      return 1;
    }
    ::CloseHandle(processInformation.hThread);
    hProcess = processInformation.hProcess;
  }
  if (hProcess != 0)
  {
    WaitForSingleObject(hProcess, INFINITE);
    ::CloseHandle(hProcess);
  }
  return 0;
}
Exemple #22
0
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
{
  #ifndef _7ZIP_ST
  const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
  _numThreads = numProcessors;
  #endif
  InitMethodProperties();
  for (int i = 0; i < numProperties; i++)
  {
    UString name = UString(names[i]);
    name.MakeUpper();
    if (name.IsEmpty())
      return E_INVALIDARG;

    const PROPVARIANT &prop = values[i];

    if (name[0] == L'X')
    {
      UInt32 level = 9;
      RINOK(ParsePropValue(name.Mid(1), prop, level));
      m_Level = level;
      continue;
    }
    else if (name == L"M")
    {
      if (prop.vt == VT_BSTR)
      {
        UString m = prop.bstrVal;
        m.MakeUpper();
        if (m == L"COPY") m_MainMethod = NFileHeader::NCompressionMethod::kStored;
        else if (m == L"DEFLATE") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated;
        else if (m == L"DEFLATE64") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated64;
        else if (m == L"BZIP2") m_MainMethod = NFileHeader::NCompressionMethod::kBZip2;
        else if (m == L"LZMA") m_MainMethod = NFileHeader::NCompressionMethod::kLZMA;
        else if (m == L"PPMD") m_MainMethod = NFileHeader::NCompressionMethod::kPPMd;
        else return E_INVALIDARG;
      }
      else if (prop.vt == VT_UI4)
      {
        switch(prop.ulVal)
        {
          case NFileHeader::NCompressionMethod::kStored:
          case NFileHeader::NCompressionMethod::kDeflated:
          case NFileHeader::NCompressionMethod::kDeflated64:
          case NFileHeader::NCompressionMethod::kBZip2:
          case NFileHeader::NCompressionMethod::kLZMA:
            m_MainMethod = (Byte)prop.ulVal;
            break;
          default:
            return E_INVALIDARG;
        }
      }
      else
        return E_INVALIDARG;
    }
    else if (name.Left(2) == L"EM")
    {
      if (prop.vt == VT_BSTR)
      {
        UString valueString = prop.bstrVal;
        valueString.MakeUpper();
        if (valueString.Left(3) == L"AES")
        {
          valueString = valueString.Mid(3);
          if (valueString == L"128")
            m_AesKeyMode = 1;
          else if (valueString == L"192")
            m_AesKeyMode = 2;
          else if (valueString == L"256" || valueString.IsEmpty())
            m_AesKeyMode = 3;
          else
            return E_INVALIDARG;
          m_IsAesMode = true;
          m_ForceAesMode = true;
        }
        else if (valueString == L"ZIPCRYPTO")
        {
          m_IsAesMode = false;
          m_ForceAesMode = true;
        }
        else
          return E_INVALIDARG;
      }
      else
        return E_INVALIDARG;
    }
    else if (name[0] == L'D')
    {
      UInt32 dicSize = kBZip2DicSizeX5;
      RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
      m_DicSize = dicSize;
    }
    else if (name.Left(3) == L"MEM")
    {
      UInt32 memSize = 1 << 24;
      RINOK(ParsePropDictionaryValue(name.Mid(3), prop, memSize));
      m_MemSize = memSize;
    }
    else if (name[0] == L'O')
    {
      UInt32 order = 8;
      RINOK(ParsePropValue(name.Mid(1), prop, order));
      m_Order = order;
    }
    else if (name.Left(4) == L"PASS")
    {
      UInt32 num = kDeflateNumPassesX9;
      RINOK(ParsePropValue(name.Mid(4), prop, num));
      m_NumPasses = num;
    }
    else if (name.Left(2) == L"FB")
    {
      UInt32 num = kDeflateNumFastBytesX9;
      RINOK(ParsePropValue(name.Mid(2), prop, num));
      m_NumFastBytes = num;
    }
    else if (name.Left(2) == L"MC")
    {
      UInt32 num = 0xFFFFFFFF;
      RINOK(ParsePropValue(name.Mid(2), prop, num));
      m_NumMatchFinderCycles = num;
      m_NumMatchFinderCyclesDefined = true;
    }
    else if (name.Left(2) == L"MT")
    {
      #ifndef _7ZIP_ST
      RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
      #endif
    }
    else if (name.Left(1) == L"A")
    {
      UInt32 num = kLzAlgoX5;
      RINOK(ParsePropValue(name.Mid(1), prop, num));
      m_Algo = num;
    }
    else if (name.CompareNoCase(L"TC") == 0)
    {
      RINOK(SetBoolProperty(m_WriteNtfsTimeExtra, prop));
    }
    else if (name.CompareNoCase(L"CL") == 0)
    {
      RINOK(SetBoolProperty(m_ForceLocal, prop));
      if (m_ForceLocal)
        m_ForceUtf8 = false;
    }
    else if (name.CompareNoCase(L"CU") == 0)
    {
      RINOK(SetBoolProperty(m_ForceUtf8, prop));
      if (m_ForceUtf8)
        m_ForceLocal = false;
    }
    else
      return E_INVALIDARG;
  }
  return S_OK;
}
Exemple #23
0
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
  UInt64 endPos = 0;
  {
    RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
    RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
  }
  
  _phySizeDefined = true;
  for (;;)
  {
    CItemEx item;
    bool filled;
    RINOK(ReadItem2(stream, filled, item));
    if (!filled)
      break;
    _items.Add(item);
    
    RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize));
    if (_phySize > endPos)
    {
      _errorMessage = kUnexpectedEnd;
      break;
    }
    /*
    if (_phySize == endPos)
    {
      _errorMessage = "There are no trailing zero-filled records";
      break;
    }
    */
    if (callback != NULL)
    {
      if (_items.Size() == 1)
      {
        RINOK(callback->SetTotal(NULL, &endPos));
      }
      if (_items.Size() % 100 == 0)
      {
        UInt64 numFiles = _items.Size();
        RINOK(callback->SetCompleted(&numFiles, &_phySize));
      }
    }
  }

  if (_items.Size() == 0)
  {
    CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
    if (!callback)
      return S_FALSE;
    callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
    if (!openVolumeCallback)
      return S_FALSE;
    NCOM::CPropVariant prop;
    if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK)
      return S_FALSE;
    if (prop.vt != VT_BSTR)
      return S_FALSE;
    UString baseName = prop.bstrVal;
    baseName = baseName.Right(4);
    if (baseName.CompareNoCase(L".tar") != 0)
      return S_FALSE;
  }
  return S_OK;
}
Exemple #24
0
HRESULT DecompressArchives(
    CCodecs *codecs, const CIntVector &formatIndices,
    UStringVector &archivePaths, UStringVector &archivePathsFull,
    const NWildcard::CCensorNode &wildcardCensor,
    const CExtractOptions &optionsSpec,
    IOpenCallbackUI *openCallback,
    IExtractCallbackUI *extractCallback,
    UString &errorMessage,
    CDecompressStat &stat)
{
  stat.Clear();
  CExtractOptions options = optionsSpec;
  int i;
  UInt64 totalPackSize = 0;
  CRecordVector<UInt64> archiveSizes;
  for (i = 0; i < archivePaths.Size(); i++)
  {
    const UString &archivePath = archivePaths[i];
    NFile::NFind::CFileInfoW fi;
    if (!NFile::NFind::FindFile(archivePath, fi))
      throw "there is no such archive";
    if (fi.IsDir())
      throw "can't decompress folder";
    archiveSizes.Add(fi.Size);
    totalPackSize += fi.Size;
  }
  CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
  CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
  bool multi = (archivePaths.Size() > 1);
  extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
  if (multi)
  {
    RINOK(extractCallback->SetTotal(totalPackSize));
  }
  for (i = 0; i < archivePaths.Size(); i++)
  {
    const UString &archivePath = archivePaths[i];
    NFile::NFind::CFileInfoW fi;
    if (!NFile::NFind::FindFile(archivePath, fi))
      throw "there is no such archive";

    if (fi.IsDir())
      throw "there is no such archive";

    options.ArchiveFileInfo = fi;

    #ifndef _NO_CRYPTO
    openCallback->Open_ClearPasswordWasAskedFlag();
    #endif

    RINOK(extractCallback->BeforeOpen(archivePath));
    CArchiveLink archiveLink;

    CIntVector formatIndices2 = formatIndices;
    #ifndef _SFX
    if (formatIndices.IsEmpty())
    {
      int pos = archivePath.ReverseFind(L'.');
      if (pos >= 0)
      {
        UString s = archivePath.Mid(pos + 1);
        int index = codecs->FindFormatForExtension(s);
        if (index >= 0 && s == L"001")
        {
          s = archivePath.Left(pos);
          pos = s.ReverseFind(L'.');
          if (pos >= 0)
          {
            int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1));
            if (index2 >= 0 && s.CompareNoCase(L"rar") != 0)
            {
              formatIndices2.Add(index2);
              formatIndices2.Add(index);
            }
          }
        }
      }
    }
    #endif
    HRESULT result = MyOpenArchive(codecs, formatIndices2, archivePath, archiveLink, openCallback);
    if (result == E_ABORT)
      return result;

    bool crypted = false;
    #ifndef _NO_CRYPTO
    crypted = openCallback->Open_WasPasswordAsked();
    #endif

    RINOK(extractCallback->OpenResult(archivePath, result, crypted));
    if (result != S_OK)
      continue;

    for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
    {
      int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
      if (index >= 0 && index > i)
      {
        archivePaths.Delete(index);
        archivePathsFull.Delete(index);
        totalPackSize -= archiveSizes[index];
        archiveSizes.Delete(index);
      }
    }
    if (archiveLink.VolumePaths.Size() != 0)
    {
      totalPackSize += archiveLink.VolumesSize;
      RINOK(extractCallback->SetTotal(totalPackSize));
    }

    #ifndef _NO_CRYPTO
    UString password;
    RINOK(openCallback->Open_GetPasswordIfAny(password));
    if (!password.IsEmpty())
    {
      RINOK(extractCallback->SetPassword(password));
    }
    #endif

    options.DefaultItemName = archiveLink.GetDefaultItemName();
    RINOK(DecompressArchive(
        archiveLink.GetArchive(),
        fi.Size + archiveLink.VolumesSize,
        wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage));
    extractCallbackSpec->LocalProgressSpec->InSize += fi.Size +
        archiveLink.VolumesSize;
    extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
    if (!errorMessage.IsEmpty())
      return E_FAIL;
  }
  stat.NumFolders = extractCallbackSpec->NumFolders;
  stat.NumFiles = extractCallbackSpec->NumFiles;
  stat.UnpackSize = extractCallbackSpec->UnpackSize;
  stat.NumArchives = archivePaths.Size();
  stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
  return S_OK;
}
Exemple #25
0
HRESULT CAgent::RenameItem(
    const wchar_t *newArchiveName,
    const UInt32 *indices, UInt32 numItems,
    const wchar_t *newItemName,
    IFolderArchiveUpdateCallback *updateCallback100)
{
  if (!CanUpdate())
    return E_NOTIMPL;
  if (numItems != 1)
    return E_INVALIDARG;
  CUpdateCallbackAgent updateCallbackAgent;
  updateCallbackAgent.SetCallback(updateCallback100);
  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
  
  CUIntVector realIndices;
  _agentFolder->GetRealIndices(indices, numItems, realIndices);

  UString fullPrefix = _agentFolder->GetFullPathPrefixPlusPrefix(indices[0]);
  UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]);
  UString newItemPath = fullPrefix + newItemName;

  CRecordVector<CUpdatePair2> updatePairs;
  UStringVector newNames;

  int curIndex = 0;
  UInt32 numItemsInArchive;
  RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
  for (UInt32 i = 0; i < numItemsInArchive; i++)
  {
    if (curIndex < realIndices.Size())
      if (realIndices[curIndex] == i)
      {
        CUpdatePair2 up2;
        up2.NewData = false;
        up2.NewProps = true;
        RINOK(IsArchiveItemAnti(GetArchive(), i, up2.IsAnti));
        up2.ArcIndex = i;

        UString oldFullPath;
        RINOK(GetArchiveItemPath(GetArchive(), i, DefaultName, oldFullPath));

        if (oldItemPath.CompareNoCase(oldFullPath.Left(oldItemPath.Length())) != 0)
          return E_INVALIDARG;

        up2.NewNameIndex = newNames.Add(newItemPath + oldFullPath.Mid(oldItemPath.Length()));
        updatePairs.Add(up2);
        curIndex++;
        continue;
      }
    CUpdatePair2 up2;
    up2.NewData = up2.NewProps = false;
    up2.IsAnti = false;
    up2.ArcIndex = i;
    updatePairs.Add(up2);
  }
  updateCallbackSpec->Callback = &updateCallbackAgent;
  updateCallbackSpec->UpdatePairs = &updatePairs;
  updateCallbackSpec->NewNames = &newNames;
  updateCallbackSpec->Archive = GetArchive();
  return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback);
}
Exemple #26
0
int APIENTRY WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  LPSTR lpCmdLine,
  int nCmdShow)
{
  // Disable current directory from being in the search path.
  // This call does not help with implicitly loaded DLLs.
  if (!RemoveCurrentDirFromSearchPath()) {
    WCHAR minOSTitle[512] = { '\0' };
    WCHAR minOSText[512] = { '\0' };
    LoadStringW(NULL, IDS_MIN_OS_TITLE, minOSTitle,
                sizeof(minOSTitle) / sizeof(minOSTitle[0]));
    LoadStringW(NULL, IDS_MIN_OS_TEXT, minOSText,
                sizeof(minOSText) / sizeof(minOSText[0]));
    MessageBoxW(NULL, minOSText, minOSTitle, MB_OK | MB_ICONERROR);
    return 1;
  }

  g_hInstance = (HINSTANCE)hInstance;
  #ifndef _UNICODE
  g_IsNT = IsItWindowsNT();
  #endif
  InitCommonControls();

  UString archiveName, switches;
  #ifdef _SHELL_EXECUTE
  UString executeFile, executeParameters;
  #endif
  NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);

  UString fullPath;
  NDLL::MyGetModuleFileName(g_hInstance, fullPath);

  switches.Trim();
  bool assumeYes = false;
  if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0)
  {
    assumeYes = true;
    switches = switches.Mid(2);
    switches.Trim();
  }

  /* BEGIN Mozilla customizations */
  bool showProgress = true;
  if (switches.Left(3).CompareNoCase(UString(L"-ms")) == 0 ||
	  switches.Left(4).CompareNoCase(UString(L"/INI")) == 0 ||
	  switches.Left(2).CompareNoCase(UString(L"/S")) == 0)
    showProgress = false;
  /* END Mozilla customizations */

  AString config;
  if (!ReadDataString(fullPath, kStartID, kEndID, config))
  {
    if (!assumeYes)
      MyMessageBox(L"Can't load config info");
    return 1;
  }

  UString dirPrefix = L".\\";
  UString appLaunched;
  if (!config.IsEmpty())
  {
    CObjectVector<CTextConfigPair> pairs;
    if (!GetTextConfig(config, pairs))
    {
      if (!assumeYes)
        MyMessageBox(L"Config failed");
      return 1;
    }
    UString friendlyName = GetTextConfigValue(pairs, L"Title");
    UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt");
    UString progress = GetTextConfigValue(pairs, L"Progress");
    if (progress.CompareNoCase(L"no") == 0)
      showProgress = false;
    int index = FindTextConfigItem(pairs, L"Directory");
    if (index >= 0)
      dirPrefix = pairs[index].String;
    if (!installPrompt.IsEmpty() && !assumeYes)
    {
      if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO | 
          MB_ICONQUESTION) != IDYES)
        return 0;
    }
    appLaunched = GetTextConfigValue(pairs, L"RunProgram");
    
    #ifdef _SHELL_EXECUTE
    executeFile = GetTextConfigValue(pairs, L"ExecuteFile");
    executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches;
    #endif
  }

  NFile::NDirectory::CTempDirectory tempDir;
  if (!tempDir.Create(kTempDirPrefix))
  {
    if (!assumeYes)
      MyMessageBox(L"Can not create temp folder archive");
    return 1;
  }

  COpenCallbackGUI openCallback;

  UString tempDirPath = GetUnicodeString(tempDir.GetPath());
  bool isCorrupt = false;
  UString errorMessage;
  HRESULT result = ExtractArchive(fullPath, tempDirPath, &openCallback, showProgress, 
      isCorrupt, errorMessage);

  if (result != S_OK)
  {
    if (!assumeYes)
    {
      if (result == S_FALSE || isCorrupt)
      {
        errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE);
        result = E_FAIL;
      }
      if (result != E_ABORT && !errorMessage.IsEmpty())
        ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
    }
    return 1;
  }

  CCurrentDirRestorer currentDirRestorer;

  if (!SetCurrentDirectory(tempDir.GetPath()))
    return 1;
  
  HANDLE hProcess = 0;
#ifdef _SHELL_EXECUTE
  if (!executeFile.IsEmpty())
  {
    CSysString filePath = GetSystemString(executeFile);
    SHELLEXECUTEINFO execInfo;
    execInfo.cbSize = sizeof(execInfo);
    execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
    execInfo.hwnd = NULL;
    execInfo.lpVerb = NULL;
    execInfo.lpFile = filePath;

    if (!switches.IsEmpty())
      executeParameters += switches;

    CSysString parametersSys = GetSystemString(executeParameters);
    if (parametersSys.IsEmpty())
      execInfo.lpParameters = NULL;
    else
      execInfo.lpParameters = parametersSys;

    execInfo.lpDirectory = NULL;
    execInfo.nShow = SW_SHOWNORMAL;
    execInfo.hProcess = 0;
    bool success = BOOLToBool(::ShellExecuteEx(&execInfo));
    result = (UINT32)execInfo.hInstApp;
    if(result <= 32)
    {
      if (!assumeYes)
        MyMessageBox(L"Can not open file");
      return 1;
    }
    hProcess = execInfo.hProcess;
  }
  else
#endif
  {
    if (appLaunched.IsEmpty())
    {
      appLaunched = L"setup.exe";
      if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched)))
      {
        if (!assumeYes)
          MyMessageBox(L"Can not find setup.exe");
        return 1;
      }
    }
    
    {
      UString s2 = tempDirPath;
      NFile::NName::NormalizeDirPathPrefix(s2);
      appLaunched.Replace(L"%%T\\", s2);
    }
    
    appLaunched.Replace(L"%%T", tempDirPath);

    if (!switches.IsEmpty())
    {
      appLaunched += L' ';
      appLaunched += switches;
    }
    STARTUPINFO startupInfo;
    startupInfo.cb = sizeof(startupInfo);
    startupInfo.lpReserved = 0;
    startupInfo.lpDesktop = 0;
    startupInfo.lpTitle = 0;
    startupInfo.dwFlags = 0;
    startupInfo.cbReserved2 = 0;
    startupInfo.lpReserved2 = 0;
    
    PROCESS_INFORMATION processInformation;
    
    CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched);
    
    BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys, 
      NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */, 
      &startupInfo, &processInformation);
    if (createResult == 0)
    {
      if (!assumeYes)
        ShowLastErrorMessage();
      return 1;
    }
    ::CloseHandle(processInformation.hThread);
    hProcess = processInformation.hProcess;
  }
  if (hProcess != 0)
  {
    WaitForSingleObject(hProcess, INFINITE);
    ::CloseHandle(hProcess);
  }
  return 0;
}
// if string contains switch then function updates switch structures
// out: (string is a switch)
bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms)
{
  int len = s.Length();
  if (len == 0) 
    return false;
  int pos = 0;
  if (!IsItSwitchChar(s[pos]))
    return false;
  while(pos < len)
  {
    if (IsItSwitchChar(s[pos]))
      pos++;
    const int kNoLen = -1;
    int matchedSwitchIndex = 0; // GCC Warning
    int maxLen = kNoLen;
    for(int switchIndex = 0; switchIndex < _numSwitches; switchIndex++)
    {
      int switchLen = MyStringLen(switchForms[switchIndex].IDString);
      if (switchLen <= maxLen || pos + switchLen > len) 
        continue;

      UString temp = s + pos;
      temp = temp.Left(switchLen);
      if(temp.CompareNoCase(switchForms[switchIndex].IDString) == 0)
      // if(_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0)
      {
        matchedSwitchIndex = switchIndex;
        maxLen = switchLen;
      }
    }
    if (maxLen == kNoLen)
      throw "maxLen == kNoLen";
    CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex];
    const CSwitchForm &switchForm = switchForms[matchedSwitchIndex];
    if ((!switchForm.Multi) && matchedSwitch.ThereIs)
      throw "switch must be single";
    matchedSwitch.ThereIs = true;
    pos += maxLen;
    int tailSize = len - pos;
    NSwitchType::EEnum type = switchForm.Type;
    switch(type)
    {
      case NSwitchType::kPostMinus:
        {
          if (tailSize == 0)
            matchedSwitch.WithMinus = false;
          else
          {
            matchedSwitch.WithMinus = (s[pos] == kSwitchMinus);
            if (matchedSwitch.WithMinus)
              pos++;
          }
          break;
        }
      case NSwitchType::kPostChar:
        {
          if (tailSize < switchForm.MinLen)
            throw "switch is not full";
          UString set = switchForm.PostCharSet;
          const int kEmptyCharValue = -1;
          if (tailSize == 0)
            matchedSwitch.PostCharIndex = kEmptyCharValue;
          else
          {
            int index = set.Find(s[pos]);
            if (index < 0)
              matchedSwitch.PostCharIndex =  kEmptyCharValue;
            else
            {
              matchedSwitch.PostCharIndex = index;
              pos++;
            }
          }
          break;
        }
      case NSwitchType::kLimitedPostString: 
      case NSwitchType::kUnLimitedPostString: 
        {
          int minLen = switchForm.MinLen;
          if (tailSize < minLen)
            throw "switch is not full";
          if (type == NSwitchType::kUnLimitedPostString)
          {
            matchedSwitch.PostStrings.Add(s.Mid(pos));
            return true;
          }
          int maxLen = switchForm.MaxLen;
          UString stringSwitch = s.Mid(pos, minLen);
          pos += minLen;
          for(int i = minLen; i < maxLen && pos < len; i++, pos++)
          {
            wchar_t c = s[pos];
            if (IsItSwitchChar(c))
              break;
            stringSwitch += c;
          }
          matchedSwitch.PostStrings.Add(stringSwitch);
          break;
        }
      case NSwitchType::kSimple:
          break;
    }
  }
  return true;
}
int main2(int n, const char *args[])
{
  fprintf(stderr, "\nLZMA 4.27 Copyright (c) 1999-2005 Igor Pavlov  2005-08-07\n");

  if (n == 1)
  {
    PrintHelp();
    return 0;
  }

  if (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4)
  {
    fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
    return 1;
  }   

  UStringVector commandStrings;
  WriteArgumentsToStringList(n, args, commandStrings);
  CParser parser(kNumSwitches);
  try
  {
    parser.ParseStrings(kSwitchForms, commandStrings);
  }
  catch(...) 
  {
    IncorrectCommand();
  }

  if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
  {
    PrintHelp();
    return 0;
  }
  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;

  int paramIndex = 0;
  if (paramIndex >= nonSwitchStrings.Size())
    IncorrectCommand();
  const UString &command = nonSwitchStrings[paramIndex++]; 

  bool dictionaryIsDefined = false;
  UInt32 dictionary = 1 << 21;
  if(parser[NKey::kDictionary].ThereIs)
  {
    UInt32 dicLog;
    if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
      IncorrectCommand();
    dictionary = 1 << dicLog;
    dictionaryIsDefined = true;
  }
  UString mf = L"BT4";
  if (parser[NKey::kMatchFinder].ThereIs)
    mf = parser[NKey::kMatchFinder].PostStrings[0];

  if (command.CompareNoCase(L"b") == 0)
  {
    const UInt32 kNumDefaultItereations = 10;
    UInt32 numIterations = kNumDefaultItereations;
    {
      if (paramIndex < nonSwitchStrings.Size())
        if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
          numIterations = kNumDefaultItereations;
    }
    return LzmaBenchmark(stderr, numIterations, dictionary, 
        mf.CompareNoCase(L"BT4") == 0);
  }

  bool encodeMode = false;
  if (command.CompareNoCase(L"e") == 0)
    encodeMode = true;
  else if (command.CompareNoCase(L"d") == 0)
    encodeMode = false;
  else
    IncorrectCommand();

  bool stdInMode = parser[NKey::kStdIn].ThereIs;
  bool stdOutMode = parser[NKey::kStdOut].ThereIs;

  CMyComPtr<ISequentialInStream> inStream;
  CInFileStream *inStreamSpec = 0;
  if (stdInMode)
  {
    inStream = new CStdInFileStream;
    MY_SET_BINARY_MODE(stdin);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &inputName = nonSwitchStrings[paramIndex++]; 
    inStreamSpec = new CInFileStream;
    inStream = inStreamSpec;
    if (!inStreamSpec->Open(GetSystemString(inputName)))
    {
      fprintf(stderr, "\nError: can not open input file %s\n", 
          (const char *)GetOemString(inputName));
      return 1;
    }
  }

  CMyComPtr<ISequentialOutStream> outStream;
  if (stdOutMode)
  {
    outStream = new CStdOutFileStream;
    MY_SET_BINARY_MODE(stdout);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &outputName = nonSwitchStrings[paramIndex++]; 
    COutFileStream *outStreamSpec = new COutFileStream;
    outStream = outStreamSpec;
    if (!outStreamSpec->Create(GetSystemString(outputName), true))
    {
      fprintf(stderr, "\nError: can not open output file %s\n", 
        (const char *)GetOemString(outputName));
      return 1;
    }
  }

  if (parser[NKey::kFilter86].ThereIs)
  {
    // -f86 switch is for x86 filtered mode: BCJ + LZMA.
    if (parser[NKey::kEOS].ThereIs || stdInMode)
      throw "Can not use stdin in this mode";
    UInt64 fileSize;
    inStreamSpec->File.GetLength(fileSize);
    if (fileSize > 0xF0000000)
      throw "File is too big";
    UInt32 inSize = (UInt32)fileSize;
    Byte *inBuffer = 0;
    if (inSize != 0)
    {
      inBuffer = (Byte *)MyAlloc((size_t)inSize); 
      if (inBuffer == 0)
        throw kCantAllocate;
    }
    
    UInt32 processedSize;
    if (inStream->Read(inBuffer, (UInt32)inSize, &processedSize) != S_OK)
      throw "Can not read";
    if ((UInt32)inSize != processedSize)
      throw "Read size error";

    Byte *outBuffer = 0;
    size_t outSizeProcessed;
    if (encodeMode)
    {
      // we allocate 105% of original size for output buffer
      size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
      if (outSize != 0)
      {
        outBuffer = (Byte *)MyAlloc((size_t)outSize); 
        if (outBuffer == 0)
          throw kCantAllocate;
      }
      if (!dictionaryIsDefined)
        dictionary = 1 << 23;
      int res = LzmaRamEncode(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, 
          dictionary, SZ_FILTER_AUTO);
      if (res != 0)
      {
        fprintf(stderr, "\nEncoder error = %d\n", (int)res);
        return 1;
      }
    }
    else
    {
      size_t outSize;
      if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
        throw "data error";
      if (outSize != 0)
      {
        outBuffer = (Byte *)MyAlloc(outSize); 
        if (outBuffer == 0)
          throw kCantAllocate;
      }
      int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
      if (res != 0)
        throw "LzmaDecoder error";
    }
    if (outStream->Write(outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
      throw "Can not write";
    MyFree(outBuffer);
    MyFree(inBuffer);
    return 0;
  }


  UInt64 fileSize;
  if (encodeMode)
  {
    NCompress::NLZMA::CEncoder *encoderSpec = 
      new NCompress::NLZMA::CEncoder;
    CMyComPtr<ICompressCoder> encoder = encoderSpec;

    if (!dictionaryIsDefined)
      dictionary = 1 << 23;

    UInt32 posStateBits = 2;
    UInt32 litContextBits = 3; // for normal files
    // UInt32 litContextBits = 0; // for 32-bit data
    UInt32 litPosBits = 0;
    // UInt32 litPosBits = 2; // for 32-bit data
    UInt32 algorithm = 2;
    UInt32 numFastBytes = 128;

    bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
 
    if(parser[NKey::kMode].ThereIs)
      if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
        IncorrectCommand();

    if(parser[NKey::kFastBytes].ThereIs)
      if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
        IncorrectCommand();
    if(parser[NKey::kLitContext].ThereIs)
      if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
        IncorrectCommand();
    if(parser[NKey::kLitPos].ThereIs)
      if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
        IncorrectCommand();
    if(parser[NKey::kPosBits].ThereIs)
      if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
        IncorrectCommand();

    PROPID propIDs[] = 
    {
      NCoderPropID::kDictionarySize,
      NCoderPropID::kPosStateBits,
      NCoderPropID::kLitContextBits,
      NCoderPropID::kLitPosBits,
      NCoderPropID::kAlgorithm,
      NCoderPropID::kNumFastBytes,
      NCoderPropID::kMatchFinder,
      NCoderPropID::kEndMarker
    };
    const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
    /*
    NWindows::NCOM::CPropVariant properties[kNumProps];
    properties[0] = UInt32(dictionary);
    properties[1] = UInt32(posStateBits);
    properties[2] = UInt32(litContextBits);
   
    properties[3] = UInt32(litPosBits);
    properties[4] = UInt32(algorithm);
    properties[5] = UInt32(numFastBytes);
    properties[6] = mf;
    properties[7] = eos;
    */
    PROPVARIANT properties[kNumProps];
    for (int p = 0; p < 6; p++)
      properties[p].vt = VT_UI4;
    properties[0].ulVal = UInt32(dictionary);
    properties[1].ulVal = UInt32(posStateBits);
    properties[2].ulVal = UInt32(litContextBits);
    properties[3].ulVal = UInt32(litPosBits);
    properties[4].ulVal = UInt32(algorithm);
    properties[5].ulVal = UInt32(numFastBytes);
    
    properties[6].vt = VT_BSTR;
    properties[6].bstrVal = (BSTR)(const wchar_t *)mf;

    properties[7].vt = VT_BOOL;
    properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;

    if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
      IncorrectCommand();
    encoderSpec->WriteCoderProperties(outStream);

    if (eos || stdInMode)
      fileSize = (UInt64)(Int64)-1;
    else
      inStreamSpec->File.GetLength(fileSize);

    for (int i = 0; i < 8; i++)
    {
      Byte b = Byte(fileSize >> (8 * i));
      if (outStream->Write(&b, sizeof(b), 0) != S_OK)
      {
        fprintf(stderr, "Write error");
        return 1;
      }
    }
    HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
    if (result == E_OUTOFMEMORY)
    {
      fprintf(stderr, "\nError: Can not allocate memory\n");
      return 1;
    }   
    else if (result != S_OK)
    {
      fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
      return 1;
    }   
  }
  else
  {
Exemple #29
0
HRESULT CArc::OpenStream(
    CCodecs *codecs,
    int formatIndex,
    IInStream *stream,
    ISequentialInStream *seqStream,
    IArchiveOpenCallback *callback)
{
  Archive.Release();
  ErrorMessage.Empty();
  const UString fileName = ExtractFileNameFromPath(Path);
  UString extension;
  {
    int dotPos = fileName.ReverseFind(L'.');
    if (dotPos >= 0)
      extension = fileName.Mid(dotPos + 1);
  }
  CIntVector orderIndices;
  if (formatIndex >= 0)
    orderIndices.Add(formatIndex);
  else
  {

  int i;
  int numFinded = 0;
  for (i = 0; i < codecs->Formats.Size(); i++)
    if (codecs->Formats[i].FindExtension(extension) >= 0)
      orderIndices.Insert(numFinded++, i);
    else
      orderIndices.Add(i);
  
  if (!stream)
  {
    if (numFinded != 1)
      return E_NOTIMPL;
    orderIndices.DeleteFrom(1);
  }

  #ifndef _SFX
  if (orderIndices.Size() >= 2 && (numFinded == 0 || extension.CompareNoCase(L"exe") == 0))
  {
    CIntVector orderIndices2;
    CByteBuffer byteBuffer;
    const size_t kBufferSize = (1 << 21);
    byteBuffer.SetCapacity(kBufferSize);
    RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
    size_t processedSize = kBufferSize;
    RINOK(ReadStream(stream, byteBuffer, &processedSize));
    if (processedSize == 0)
      return S_FALSE;

    const Byte *buf = byteBuffer;
    CByteBuffer hashBuffer;
    const UInt32 kNumVals = 1 << (kNumHashBytes * 8);
    hashBuffer.SetCapacity(kNumVals);
    Byte *hash = hashBuffer;
    memset(hash, 0xFF, kNumVals);
    Byte prevs[256];
    if (orderIndices.Size() >= 256)
      return S_FALSE;
    int i;
    for (i = 0; i < orderIndices.Size(); i++)
    {
      const CArcInfoEx &ai = codecs->Formats[orderIndices[i]];
      const CByteBuffer &sig = ai.StartSignature;
      if (sig.GetCapacity() < kNumHashBytes)
        continue;
      UInt32 v = HASH_VAL(sig, 0);
      prevs[i] = hash[v];
      hash[v] = (Byte)i;
    }

    processedSize -= (kNumHashBytes - 1);
    for (UInt32 pos = 0; pos < processedSize; pos++)
    {
      for (; pos < processedSize && hash[HASH_VAL(buf, pos)] == 0xFF; pos++);
      if (pos == processedSize)
        break;
      UInt32 v = HASH_VAL(buf, pos);
      Byte *ptr = &hash[v];
      int i = *ptr;
      do
      {
        int index = orderIndices[i];
        const CArcInfoEx &ai = codecs->Formats[index];
        const CByteBuffer &sig = ai.StartSignature;
        if (sig.GetCapacity() != 0 && pos + sig.GetCapacity() <= processedSize + (kNumHashBytes - 1) &&
            TestSignature(buf + pos, sig, sig.GetCapacity()))
        {
          orderIndices2.Add(index);
          orderIndices[i] = 0xFF;
          *ptr = prevs[i];
        }
        else
          ptr = &prevs[i];
        i = *ptr;
      }
      while (i != 0xFF);
    }
    
    for (i = 0; i < orderIndices.Size(); i++)
    {
      int val = orderIndices[i];
      if (val != 0xFF)
        orderIndices2.Add(val);
    }
    orderIndices = orderIndices2;
  }
  else if (extension == L"000" || extension == L"001")
  {
    CByteBuffer byteBuffer;
    const size_t kBufferSize = (1 << 10);
    byteBuffer.SetCapacity(kBufferSize);
    Byte *buffer = byteBuffer;
    RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
    size_t processedSize = kBufferSize;
    RINOK(ReadStream(stream, buffer, &processedSize));
    if (processedSize >= 16)
    {
      Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
      if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] & 1) != 0)
      {
        for (int i = 0; i < orderIndices.Size(); i++)
        {
          int index = orderIndices[i];
          const CArcInfoEx &ai = codecs->Formats[index];
          if (ai.Name.CompareNoCase(L"rar") != 0)
            continue;
          orderIndices.Delete(i--);
          orderIndices.Insert(0, index);
          break;
        }
      }
    }
  }
  if (orderIndices.Size() >= 2)
  {
    int isoIndex = codecs->FindFormatForArchiveType(L"iso");
    int udfIndex = codecs->FindFormatForArchiveType(L"udf");
    int iIso = -1;
    int iUdf = -1;
    for (int i = 0; i < orderIndices.Size(); i++)
    {
      if (orderIndices[i] == isoIndex) iIso = i;
      if (orderIndices[i] == udfIndex) iUdf = i;
    }
    if (iUdf > iIso && iIso >= 0)
    {
      orderIndices[iUdf] = isoIndex;
      orderIndices[iIso] = udfIndex;
    }
  }

  #endif
  }

  for (int i = 0; i < orderIndices.Size(); i++)
  {
    if (stream)
    {
      RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
    }
    CMyComPtr<IInArchive> archive;

    FormatIndex = orderIndices[i];
    RINOK(codecs->CreateInArchive(FormatIndex, archive));
    if (!archive)
      continue;

    #ifdef EXTERNAL_CODECS
    {
      CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
      archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
      if (setCompressCodecsInfo)
      {
        RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
      }
    }
    #endif

    // OutputDebugStringW(codecs->Formats[FormatIndex].Name);

    HRESULT result;
    if (stream)
      result = archive->Open(stream, &kMaxCheckStartPosition, callback);
    else
    {
      CMyComPtr<IArchiveOpenSeq> openSeq;
      archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq);
      if (!openSeq)
        return E_NOTIMPL;
      result = openSeq->OpenSeq(seqStream);
    }

    if (result == S_FALSE)
      continue;
    RINOK(result);

    {
      NCOM::CPropVariant prop;
      archive->GetArchiveProperty(kpidError, &prop);
      if (prop.vt != VT_EMPTY)
        ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error";
    }
    
    Archive = archive;
    const CArcInfoEx &format = codecs->Formats[FormatIndex];
    if (format.Exts.Size() == 0)
      DefaultName = GetDefaultName2(fileName, L"", L"");
    else
    {
      int subExtIndex = format.FindExtension(extension);
      if (subExtIndex < 0)
        subExtIndex = 0;
      const CArcExtInfo &extInfo = format.Exts[subExtIndex];
      DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt);
    }
    return S_OK;
  }
  return S_FALSE;
}
static HRESULT Update2(
    DECL_EXTERNAL_CODECS_LOC_VARS
    IInStream *inStream,
    const CArchiveDatabaseEx *database,
    const CObjectVector<CUpdateItem> &updateItems,
    ISequentialOutStream *seqOutStream,
    IArchiveUpdateCallback *updateCallback,
    const CUpdateOptions &options)
{
  UInt64 numSolidFiles = options.NumSolidFiles;
  if (numSolidFiles == 0)
    numSolidFiles = 1;
  /*
  CMyComPtr<IOutStream> outStream;
  RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
  if (!outStream)
    return E_NOTIMPL;
  */

  UInt64 startBlockSize = database != 0 ? database->ArchiveInfo.StartPosition: 0;
  if (startBlockSize > 0 && !options.RemoveSfxBlock)
  {
    RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
  }

  CRecordVector<int> fileIndexToUpdateIndexMap;
  if (database != 0)
  {
    fileIndexToUpdateIndexMap.Reserve(database->Files.Size());
    for (int i = 0; i < database->Files.Size(); i++)
      fileIndexToUpdateIndexMap.Add(-1);
  }
  int i;
  for(i = 0; i < updateItems.Size(); i++)
  {
    int index = updateItems[i].IndexInArchive;
    if (index != -1)
      fileIndexToUpdateIndexMap[index] = i;
  }

  CRecordVector<int> folderRefs;
  if (database != 0)
  {
    for(i = 0; i < database->Folders.Size(); i++)
    {
      CNum indexInFolder = 0;
      CNum numCopyItems = 0;
      CNum numUnPackStreams = database->NumUnPackStreamsVector[i];
      for (CNum fileIndex = database->FolderStartFileIndex[i];
      indexInFolder < numUnPackStreams; fileIndex++)
      {
        if (database->Files[fileIndex].HasStream)
        {
          indexInFolder++;
          int updateIndex = fileIndexToUpdateIndexMap[fileIndex];
          if (updateIndex >= 0)
            if (!updateItems[updateIndex].NewData)
              numCopyItems++;
        }
      }
      if (numCopyItems != numUnPackStreams && numCopyItems != 0)
        return E_NOTIMPL; // It needs repacking !!!
      if (numCopyItems > 0)
        folderRefs.Add(i);
    }
    folderRefs.Sort(CompareFolderRefs, (void *)database);
  }

  CArchiveDatabase newDatabase;

  ////////////////////////////

  COutArchive archive;
  RINOK(archive.Create(seqOutStream, false));
  RINOK(archive.SkeepPrefixArchiveHeader());
  UInt64 complexity = 0;
  for(i = 0; i < folderRefs.Size(); i++)
    complexity += database->GetFolderFullPackSize(folderRefs[i]);
  UInt64 inSizeForReduce = 0;
  for(i = 0; i < updateItems.Size(); i++)
  {
    const CUpdateItem &updateItem = updateItems[i];
    if (updateItem.NewData)
    {
      complexity += updateItem.Size;
      if (numSolidFiles == 1)
      {
        if (updateItem.Size > inSizeForReduce)
          inSizeForReduce = updateItem.Size;
      }
      else
        inSizeForReduce += updateItem.Size;
    }
  }
  RINOK(updateCallback->SetTotal(complexity));
  complexity = 0;
  RINOK(updateCallback->SetCompleted(&complexity));


  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(updateCallback, true);

  /////////////////////////////////////////
  // Write Copy Items

  for(i = 0; i < folderRefs.Size(); i++)
  {
    int folderIndex = folderRefs[i];
    
    lps->ProgressOffset = complexity;
    UInt64 packSize = database->GetFolderFullPackSize(folderIndex);
    RINOK(WriteRange(inStream, archive.SeqStream,
        database->GetFolderStreamPos(folderIndex, 0), packSize, progress));
    complexity += packSize;
    
    const CFolder &folder = database->Folders[folderIndex];
    CNum startIndex = database->FolderStartPackStreamIndex[folderIndex];
    for (int j = 0; j < folder.PackStreams.Size(); j++)
    {
      newDatabase.PackSizes.Add(database->PackSizes[startIndex + j]);
      // newDatabase.PackCRCsDefined.Add(database.PackCRCsDefined[startIndex + j]);
      // newDatabase.PackCRCs.Add(database.PackCRCs[startIndex + j]);
    }
    newDatabase.Folders.Add(folder);

    CNum numUnPackStreams = database->NumUnPackStreamsVector[folderIndex];
    newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);

    CNum indexInFolder = 0;
    for (CNum fi = database->FolderStartFileIndex[folderIndex];
        indexInFolder < numUnPackStreams; fi++)
    {
      CFileItem file = database->Files[fi];
      if (file.HasStream)
      {
        indexInFolder++;
        int updateIndex = fileIndexToUpdateIndexMap[fi];
        if (updateIndex >= 0)
        {
          const CUpdateItem &updateItem = updateItems[updateIndex];
          if (updateItem.NewProperties)
          {
            CFileItem file2;
            FromUpdateItemToFileItem(updateItem, file2);
            file2.UnPackSize = file.UnPackSize;
            file2.FileCRC = file.FileCRC;
            file2.IsFileCRCDefined = file.IsFileCRCDefined;
            file2.HasStream = file.HasStream;
            file = file2;
          }
        }
        newDatabase.Files.Add(file);
      }
    }
  }

  /////////////////////////////////////////
  // Compress New Files

  CObjectVector<CSolidGroup> groups;
  SplitFilesToGroups(*options.Method, options.UseFilters, options.MaxFilter, 
      updateItems, groups);

  const UInt32 kMinReduceSize = (1 << 16);
  if (inSizeForReduce < kMinReduceSize)
    inSizeForReduce = kMinReduceSize;

  for (int groupIndex = 0; groupIndex < groups.Size(); groupIndex++)
  {
    const CSolidGroup &group = groups[groupIndex];
    int numFiles = group.Indices.Size();
    if (numFiles == 0)
      continue;
    CRecordVector<CRefItem> refItems;
    refItems.Reserve(numFiles);
    bool sortByType = (numSolidFiles > 1);
    for (i = 0; i < numFiles; i++)
      refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType));
    refItems.Sort(CompareUpdateItems, (void *)&sortByType);
    
    CRecordVector<UInt32> indices;
    indices.Reserve(numFiles);

    for (i = 0; i < numFiles; i++)
    {
      UInt32 index = refItems[i].Index;
      indices.Add(index);
      /*
      const CUpdateItem &updateItem = updateItems[index];
      CFileItem file;
      if (updateItem.NewProperties)
        FromUpdateItemToFileItem(updateItem, file);
      else
        file = database.Files[updateItem.IndexInArchive];
      if (file.IsAnti || file.IsDirectory)
        return E_FAIL;
      newDatabase.Files.Add(file);
      */
    }
    
    CEncoder encoder(group.Method);

    for (i = 0; i < numFiles;)
    {
      UInt64 totalSize = 0;
      int numSubFiles;
      UString prevExtension;
      for (numSubFiles = 0; i + numSubFiles < numFiles && 
          numSubFiles < numSolidFiles; numSubFiles++)
      {
        const CUpdateItem &updateItem = updateItems[indices[i + numSubFiles]];
        totalSize += updateItem.Size;
        if (totalSize > options.NumSolidBytes)
          break;
        if (options.SolidExtension)
        {
          UString ext = updateItem.GetExtension();
          if (numSubFiles == 0)
            prevExtension = ext;
          else
            if (ext.CompareNoCase(prevExtension) != 0)
              break;
        }
      }
      if (numSubFiles < 1)
        numSubFiles = 1;

      CFolderInStream *inStreamSpec = new CFolderInStream;
      CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
      inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
      
      CFolder folderItem;

      int startPackIndex = newDatabase.PackSizes.Size();
      RINOK(encoder.Encode(
          EXTERNAL_CODECS_LOC_VARS
          solidInStream, NULL, &inSizeForReduce, folderItem, 
          archive.SeqStream, newDatabase.PackSizes, progress));

      for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
        lps->OutSize += newDatabase.PackSizes[startPackIndex];

      lps->InSize += folderItem.GetUnPackSize();
      // for()
      // newDatabase.PackCRCsDefined.Add(false);
      // newDatabase.PackCRCs.Add(0);
      
      newDatabase.Folders.Add(folderItem);
      
      CNum numUnPackStreams = 0;
      for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
      {
        const CUpdateItem &updateItem = updateItems[indices[i + subIndex]];
        CFileItem file;
        if (updateItem.NewProperties)
          FromUpdateItemToFileItem(updateItem, file);
        else
          file = database->Files[updateItem.IndexInArchive];
        if (file.IsAnti || file.IsDirectory)
          return E_FAIL;
        
        /*
        CFileItem &file = newDatabase.Files[
              startFileIndexInDatabase + i + subIndex];
        */
        if (!inStreamSpec->Processed[subIndex])
        {
          continue;
          // file.Name += L".locked";
        }

        file.FileCRC = inStreamSpec->CRCs[subIndex];
        file.UnPackSize = inStreamSpec->Sizes[subIndex];
        if (file.UnPackSize != 0)
        {
          file.IsFileCRCDefined = true;
          file.HasStream = true;
          numUnPackStreams++;
        }
        else
        {
          file.IsFileCRCDefined = false;
          file.HasStream = false;
        }
        newDatabase.Files.Add(file);
      }
      // numUnPackStreams = 0 is very bad case for locked files
      // v3.13 doesn't understand it.
      newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
      i += numSubFiles;
    }
  }

  {
    /////////////////////////////////////////
    // Write Empty Files & Folders
    
    CRecordVector<int> emptyRefs;
    for(i = 0; i < updateItems.Size(); i++)
    {
      const CUpdateItem &updateItem = updateItems[i];
      if (updateItem.NewData)
      {
        if (updateItem.HasStream())
          continue;
      }
      else
        if (updateItem.IndexInArchive != -1)
          if (database->Files[updateItem.IndexInArchive].HasStream)
            continue;
      emptyRefs.Add(i);
    }
    emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
    for(i = 0; i < emptyRefs.Size(); i++)
    {
      const CUpdateItem &updateItem = updateItems[emptyRefs[i]];
      CFileItem file;
      if (updateItem.NewProperties)
        FromUpdateItemToFileItem(updateItem, file);
      else
        file = database->Files[updateItem.IndexInArchive];
      newDatabase.Files.Add(file);
    }
  }
    
  /*
  if (newDatabase.Files.Size() != updateItems.Size())
    return E_FAIL;
  */

  return archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS
      newDatabase, options.HeaderMethod, options.HeaderOptions);
}