// This internal function copies each file into a temporary zip that matches file specification, then does this for each subdirectory if requested void ZipFile::UpdateFilesInZip(ZipFile* TempZipFile, String* FileSpec, String* CurrDirectory, int RootPathLength, UpdateOption UpdateWhen, Boolean AddNewFiles, Boolean RecurseSubdirectories, PathInclusion AddPathMethod, char* Password) { IEnumerator* filesEnum = Directory::GetFiles(CurrDirectory, FileSpec)->GetEnumerator(); String* fullFileName; String* adjustedFileName; CompressedFile* file; DateTime lastUpdate; bool updateFile; while (filesEnum->MoveNext()) { fullFileName = filesEnum->Current->ToString(); adjustedFileName = GetAdjustedFileName(fullFileName, RootPathLength, AddPathMethod); if (file = files->get_Item(adjustedFileName)) { lastUpdate = File::GetLastWriteTime(fullFileName); switch (UpdateWhen) { case UpdateOption::Never: updateFile = false; break; case UpdateOption::Always: updateFile = true; break; case UpdateOption::ZipFileIsNewer: updateFile = (DateTime::Compare(file->get_FileDateTime(), lastUpdate) > 0); break; case UpdateOption::DiskFileIsNewer: updateFile = (DateTime::Compare(file->get_FileDateTime(), lastUpdate) < 0); break; default: updateFile = false; break; } if (updateFile) { // Need to update compressed file from disk, so we add the it the new temporary archive AddFileToZip(TempZipFile, this, fullFileName, adjustedFileName, Password, S"Update Zip File"); } else { // Otherwise we just copy the compressed file from the original archive CopyFileInZip(file, this, TempZipFile, S"Update Zip File"); } } else if (AddNewFiles) { // This was a new file so we just add it the new zip, if requested... AddFileToZip(TempZipFile, this, fullFileName, adjustedFileName, Password, S"Update Zip File"); } } if (RecurseSubdirectories) { IEnumerator* dirsEnum = Directory::GetDirectories(CurrDirectory, "*")->GetEnumerator(); while (dirsEnum->MoveNext()) UpdateFilesInZip(TempZipFile, FileSpec, dirsEnum->Current->ToString(), RootPathLength, UpdateWhen, AddNewFiles, RecurseSubdirectories, AddPathMethod, Password); } }
// Extracts specified files from zip void ZipFile::Extract(String* FileSpec, String* DestPath, UpdateOption OverwriteWhen, Boolean RecurseSubdirectories, PathInclusion CreatePathMethod) { // Any file spec in destination path will be ignored DestPath = JustPath(DestPath); char* pszPassword = NULL; char* pszFileName = NULL; OpenFileForUnzip(); // Just wrapping in a try/catch/finally to make sure unmanaged code allocations always get released try { Regex* filePattern = GetFilePatternRegularExpression(FileSpec, caseSensitive); IEnumerator* filesEnum = files->GetEnumerator(); CompressedFile* file; String* sourceFileName; String* destFileName; bool writeFile; int err; // Get ANSI password, if one was provided if (password) if (password->get_Length()) pszPassword = StringToCharBuffer(password); // Loop through compressed file collection while (filesEnum->MoveNext()) { file = static_cast<CompressedFile*>(filesEnum->Current); sourceFileName = file->get_FileName(); if (filePattern->IsMatch(GetSearchFileName(FileSpec, sourceFileName, RecurseSubdirectories))) { pszFileName = StringToCharBuffer(sourceFileName); err = unzLocateFile(hUnzipFile, pszFileName, (caseSensitive ? 1 : 2)); free(pszFileName); pszFileName = NULL; // We should find file in zip file if it was in our compressed file collection if (err != Z_OK) throw new CompressionException(String::Concat(S"Extract Zip File Error: Compressed file \"", sourceFileName, "\" cannot be found in zip file!")); // Open compressed file for unzipping if (pszPassword) err = unzOpenCurrentFilePassword(hUnzipFile, pszPassword); else err = unzOpenCurrentFile(hUnzipFile); if (err != Z_OK) throw new CompressionException(S"Extract Zip File", err); // Get full destination file name switch (CreatePathMethod) { case PathInclusion::FullPath: destFileName = sourceFileName; break; case PathInclusion::NoPath: destFileName = String::Concat(DestPath, Path::GetFileName(sourceFileName)); break; case PathInclusion::RelativePath: destFileName = String::Concat(DestPath, sourceFileName); break; } // Make sure destination directory exists Directory::CreateDirectory(JustPath(destFileName)); // See if destination file already exists if (File::Exists(destFileName)) { DateTime lastUpdate = File::GetLastWriteTime(destFileName); switch (OverwriteWhen) { case UpdateOption::Never: writeFile = false; break; case UpdateOption::Always: writeFile = true; break; case UpdateOption::ZipFileIsNewer: writeFile = (DateTime::Compare(file->get_FileDateTime(), lastUpdate) > 0); break; case UpdateOption::DiskFileIsNewer: writeFile = (DateTime::Compare(file->get_FileDateTime(), lastUpdate) < 0); break; default: writeFile = false; break; } } else writeFile = true; if (writeFile) { System::Byte buffer[] = new System::Byte[BufferSize]; System::Byte __pin * destBuff = &buffer[0]; // pin buffer so it can be safely passed into unmanaged code... FileStream* fileStream = File::Create(destFileName); int read; __int64 total = 0, len = -1; // Send initial progress event len = file->get_UncompressedSize(); CurrentFile(destFileName, sourceFileName); FileProgress(0, len); // Read initial buffer read = unzReadCurrentFile(hUnzipFile, destBuff, buffer->get_Length()); if (read < 0) throw new CompressionException(S"Extract Zip File", read); while (read) { // Write data to file stream, fileStream->Write(buffer, 0, read); // Raise progress event total += read; FileProgress(total, len); // Read next buffer from source file stream read = unzReadCurrentFile(hUnzipFile, destBuff, buffer->get_Length()); if (read < 0) throw new CompressionException(S"Extract Zip File", read); } fileStream->Close(); } // Close compressed file unzCloseCurrentFile(hUnzipFile); } } } catch (CompressionException* ex) { // We just rethrow any errors back to user throw ex; } catch (Exception* ex) { throw ex; } __finally { if (pszPassword) free(pszPassword); if (pszFileName) free(pszFileName); } }