Comments (3)
Hello PMime,
First of all, sorry for the late reply!
originally I wanted to use your library in our software. But my company insisted that I should take the 7zip SDK.
Thank you in any case for having considered bit7z!
Because I assume that you are experienced in the SDK, I address to you.
We have the following issue: We like to integrate the functionality of the 7zip SDK to add files to an archive. Files that are already in the archive should remain.
The SDK offers a nice C++ example: \CPP\7zip\UI\Client7z. It contains all things we aim for.
But there is an important problem. If the archive already exists and has some files in it, they disappear and only the new files are compressed in the archive.
I already have exchanged outFileStreamSpec->Create(archiveName, true) with outFileStreamSpec->Open(archiveName, OPEN_ALWAYS) in the Client7z example.
It would be nice, if you could explain how to solve this problem, best with code snippets.
Sure, I'll try my best to explain how to implement the updating of archives.
Unfortunately, the documentation of 7-zip is really scarce and incomplete in this sense.
I managed to implement it in bit7z only after digging up many small pieces of information through the internet.
And now, the internal code of bit7z has some abstraction levels that make it slightly tricky to understand how it works.
Essentially, the procedure of updating an archive consists of:
- Creating a "temporary" archive on which to copy the compressed data from the old one;
- Adding (compressing) the new files to this temporary archive;
- Deleting the original archive and renaming the new one with its name.
Unfortunately, I don't know of a way to do this without using a temporary file.
As far as I know, this is the same way implemented in the 7-zip File Manager.
Anyway, a "bit" of code that I hope it can help you:
/* Relevant changes to include in your UpdateCallback */
class UpdateCallback : protected CMyUnknownImp, public IArchiveUpdateCallback {
public:
UpdateCallback(const vector<FSItem>& new_items)
: mOldArc{ nullptr }, mOldItemsCount{ 0 } /* other members */ {}
virtual ~UpdateCallback() {
Finalize();
}
MY_UNKNOWN_IMP1( IArchiveUpdateCallback )
void setOldArc(IInArchive* old_arc) {
if ( old_arc ) {
mOldArc = old_arc;
//Note: GetNumberOfItems may fail, here I omitted the check of its HRESULT return value!
mOldArc->GetNumberOfItems(&mOldItemsCount);
}
}
uint32_t itemsCount() {
/* Total number of items is equal to the number of items in the old archive
plus the new items to be added */
return mOldItemsCount + mNewItems.size();
}
COM_DECLSPEC_NOTHROW STDMETHODIMP GetProperty(UInt32 index, PROPID propID, PROPVARIANT* value) {
PROPVARIANT prop = {};
if (propID == kpidIsAnti) {
prop.vt = VT_BOOL;
prop.boolVal = VARIANT_FALSE;
} else if (index < mOldItemsCount) { //Index refers to an item in the old archive
// Getting the property from the old archive reader
mOldArc->GetProperty(index, propID, &prop);
} else {
// Here you should put the code for getting the properties of the new item, as usual
}
*value = prop;
return S_OK;
}
COM_DECLSPEC_NOTHROW STDMETHODIMP GetStream(UInt32 index, ISequentialInStream** inStream) {
RINOK(Finalize());
if (index < mOldItemsCount) { // Old item in the archive, no need to create a stream
return S_OK;
}
// Here you should put the code for creating a stream for the new file
return S_OK;
}
COM_DECLSPEC_NOTHROW STDMETHODIMP GetUpdateItemInfo(UInt32 index,
Int32* newData,
Int32* newProperties,
UInt32* indexInArchive) {
bool is_old_item = index < mOldItemsCount;
//Note: 0=false, i.e. no new data (old item). 1=true, i.e. new data (new item);
if (newData != nullptr) {
*newData = is_old_item ? 0 : 1;
}
if (newProperties != nullptr) {
*newProperties = is_old_item ? 0 : 1;
}
if (indexInArchive != nullptr) {
*indexInArchive = is_old_item ? index : static_cast<uint32_t>(-1);
}
return S_OK;
}
// Other methods from IArchiveUpdateCallback
private:
IInArchive* mOldArc;
uint32_t mOldItemsCount;
// Other private members of your update callback class
};
int main() {
std::cout << "Loading 7-zip DLL..." << std::endl;
auto library = LoadLibrary("./7z.dll");
if (library == nullptr) {
std::cerr << "Could not load 7z.dll" << std::endl;
return -1;
}
std::cout << "Getting CreateObject function..." << std::endl;
auto create_object = reinterpret_cast<CreateObjectFunc>(GetProcAddress(library, "CreateObject"));
if (create_object == nullptr) {
std::cerr << "Could not get CreateObject function" << std::endl;
return -1;
}
std::cout << "Initializing old archive reader..." << std::endl;
CMyComPtr<IInArchive> old_arc;
HRESULT res = create_object(&format_GUID, &::IID_IInArchive, reinterpret_cast<void**>(&old_arc));
if ( res != S_OK ) {
std::cerr << "Could not get class object for old_arc (error " << res << ")" << std::endl;
return -1;
}
std::cout << "Creating old archive input stream..." << std::endl;
CMyComPtr<CInFileStream> in_file_stream = new CInFileStream;
if ( !in_file_stream->Open( L"archive.7z" ) ) {
std::cerr << "Could not open input archive file stream" << std::endl;
return -1;
}
std::cout << "Initializing OpenCallback for the old archive..." << std::endl;
CMyComPtr<IArchiveOpenCallback> open_callback = new OpenCallback();
res = old_arc->Open( in_file_stream, nullptr, open_callback );
if ( res != S_OK ) {
std::cerr << "Could not open archive file" << std::endl;
return -1;
}
std::cout << "Initializing the new output archive from the input old one..." << std::endl;
CMyComPtr<IOutArchive> new_arc;
res = old_arc->QueryInterface(::IID_IOutArchive, reinterpret_cast<void**>(&new_arc));
if ( res != S_OK ) {
std::cerr << "Could not initialize new archive (error " << res << ")" << std::endl;
return -1;
}
std::cout << "Creating output file stream..." << std::endl;
CMyComPtr<COutFileStream> out_file_stream = new COutFileStream();
if (!out_file_stream->Create(L"archive.7z.tmp", true)) {
std::cerr << "Could not create temp file" << std::endl;
return -1;
}
std::cout << "Initializing UpdateCallback..." << std::endl;
/* New item that you want to add.
Note: FSItem is a class that I use in bit7z, it's similar to the CDirItem in Client7z.cpp */
FSItem item{L"7z.dll"};
vector<FSItem> new_items = {item}; //new items vector
CMyComPtr<UpdateCallback> update_callback = new UpdateCallback{new_items};
/* This is the most important part: your update callback must have access
to the old archive reader so that it can:
- distinguish between requests concerning old and new data;
- have access to the properties of the old items.
*/
update_callback->setOldArc(old_arc);
std::cout << "Compressing new files..." << std::endl;
res = new_arc->UpdateItems(out_file_stream, update_callback->itemsCount(), update_callback);
if (res == E_NOTIMPL) {
std::cerr << "Unsupported operation" << std::endl;
return -1;
}
if (res != S_OK) {
std::cerr << "Error while compressing" << std::endl;
return -1;
}
// Releasing the streams so that we can rename the temporary archive back to the original file name
in_file_stream.Release();
out_file_stream.Release();
// Closing the old archive so that we can delete it
old_arc->Close();
// Renaming the temporary archive back to the original file name
std::error_code ec;
std::filesystem::rename("archive.7z.tmp", "archive.7z", ec);
if (ec) {
std::cerr << "Could not restore the old archive file name (" << ec.message() << ")" << std::endl;
return -1;
}
std::cout << "Operation completed!" << std::endl;
}
from bit7z.
Thank you Riccardo! Especially the code is very helpful
from bit7z.
Glad that I could be of assistance!
from bit7z.
Related Issues (20)
- [Bug]: Incorrect display and decompression of compressed file name HOT 4
- [Feature Request]: RenameOutput HOT 2
- [Feature Request]: custom suffix format HOT 1
- [Bug]: Issues regarding the Fat32 and Exfat file systems HOT 8
- [Bug]: Errors related to file compression HOT 4
- [Feature Request]: Can you provide a method for setting the file time HOT 1
- [build-error]: Failed to open the archive file: No such process HOT 2
- [Bug]: UpdateMode::Update not working as expected, throwing exception HOT 3
- [Feature Request]: Creation or extraction archive file in one line HOT 1
- [Feature Request]: Support for compressed packages in four formats: ace, img, uue, and war HOT 2
- [Feature Request]: Extracting files whose names contain forbidden characters HOT 1
- Do I need to build 7zip myself? HOT 6
- [Bug]:
- [Bug]: Multiple Definition Linker Error for IID_IUnknown HOT 10
- [Bug]: BIT7Z_DISABLE_USE_STD_FILESYSTEM not working HOT 4
- [Bug]: Compile error when bit7z.lib is introduced into the project. HOT 11
- [Feature Request]: Is "tstring_to_path" forgotten here? HOT 1
- [Bug]: HOT 3
- [Feature Request]: Compresses files open for writing by another applications HOT 1
- [Bug]: CreateObject 函数调用异常
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bit7z.