1//
2// ZipManipulator.cpp
3//
4// Library: Zip
5// Package: Manipulation
6// Module: ZipManipulator
7//
8// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Zip/ZipManipulator.h"
16#include "Poco/Zip/ZipException.h"
17#include "Poco/Zip/ZipUtil.h"
18#include "Poco/Zip/Add.h"
19#include "Poco/Zip/Delete.h"
20#include "Poco/Zip/Keep.h"
21#include "Poco/Zip/Rename.h"
22#include "Poco/Zip/Replace.h"
23#include "Poco/Zip/Compress.h"
24#include "Poco/Delegate.h"
25#include "Poco/File.h"
26#include "Poco/FileStream.h"
27
28
29namespace Poco {
30namespace Zip {
31
32
33ZipManipulator::ZipManipulator(const std::string& zipFile, bool backupOriginalFile):
34 _zipFile(zipFile),
35 _backupOriginalFile(backupOriginalFile),
36 _changes(),
37 _in(0)
38{
39 Poco::FileInputStream in(zipFile);
40 _in = new ZipArchive(in);
41}
42
43
44ZipManipulator::~ZipManipulator()
45{
46}
47
48
49void ZipManipulator::deleteFile(const std::string& zipPath)
50{
51 const ZipLocalFileHeader& entry = getForChange(zipPath);
52 addOperation(zipPath, new Delete(entry));
53}
54
55
56void ZipManipulator::replaceFile(const std::string& zipPath, const std::string& localPath)
57{
58 const ZipLocalFileHeader& entry = getForChange(zipPath);
59 addOperation(zipPath, new Replace(entry, localPath));
60}
61
62
63void ZipManipulator::renameFile(const std::string& zipPath, const std::string& newZipPath)
64{
65 const ZipLocalFileHeader& entry = getForChange(zipPath);
66 // checked later in Compress too but the earlier one gets the error the better
67 std::string fn = ZipUtil::validZipEntryFileName(newZipPath);
68 addOperation(zipPath, new Rename(entry, fn));
69}
70
71
72void ZipManipulator::addFile(const std::string& zipPath, const std::string& localPath, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
73{
74 addOperation(zipPath, new Add(zipPath, localPath, cm, cl));
75}
76
77
78ZipArchive ZipManipulator::commit()
79{
80 // write to a tmp file
81 std::string outFile(_zipFile + ".tmp");
82 ZipArchive retVal(compress(outFile));
83 //renaming
84 {
85 Poco::File aFile(_zipFile);
86 if (_backupOriginalFile)
87 {
88 Poco::File tmp(_zipFile+".bak");
89 if (tmp.exists())
90 tmp.remove();
91 aFile.renameTo(_zipFile+".bak");
92 }
93 else
94 aFile.remove();
95 }
96
97 {
98 Poco::File resFile(outFile);
99 Poco::File zipFile(_zipFile);
100 if (zipFile.exists())
101 zipFile.remove();
102 resFile.renameTo(_zipFile);
103 }
104 return retVal;
105}
106
107
108const ZipLocalFileHeader& ZipManipulator::getForChange(const std::string& zipPath) const
109{
110 ZipArchive::FileHeaders::const_iterator it = _in->findHeader(zipPath);
111 if (it == _in->headerEnd())
112 throw ZipManipulationException("Entry not found: " + zipPath);
113
114 if (_changes.find(zipPath) != _changes.end())
115 throw ZipManipulationException("A change request exists already for entry " + zipPath);
116
117 return it->second;
118}
119
120
121void ZipManipulator::addOperation(const std::string& zipPath, ZipOperation::Ptr ptrOp)
122{
123 std::pair<Changes::iterator, bool> result = _changes.insert(std::make_pair(zipPath, ptrOp));
124 if (!result.second)
125 throw ZipManipulationException("A change request exists already for entry " + zipPath);
126}
127
128
129void ZipManipulator::onEDone(const void*, const ZipLocalFileHeader& hdr)
130{
131 EDone(this, hdr);
132}
133
134
135ZipArchive ZipManipulator::compress(const std::string& outFile)
136{
137 // write to a tmp file
138 Poco::FileInputStream in(_zipFile);
139 Poco::FileOutputStream out(outFile);
140 Compress c(out, true);
141 c.EDone += Poco::Delegate<ZipManipulator, const ZipLocalFileHeader>(this, &ZipManipulator::onEDone);
142
143 ZipArchive::FileHeaders::const_iterator it = _in->headerBegin();
144 for (; it != _in->headerEnd(); ++it)
145 {
146 Changes::iterator itC = _changes.find(it->first);
147 if (itC != _changes.end())
148 {
149 itC->second->execute(c, in);
150 _changes.erase(itC);
151 }
152 else
153 {
154 Keep k(it->second);
155 k.execute(c, in);
156 }
157 }
158 //Remaining files are add operations!
159 Changes::iterator itC = _changes.begin();
160 for (; itC != _changes.end(); ++itC)
161 {
162 itC->second->execute(c, in);
163 }
164 _changes.clear();
165 c.EDone -= Poco::Delegate<ZipManipulator, const ZipLocalFileHeader>(this, &ZipManipulator::onEDone);
166 in.close();
167 return c.close();
168}
169
170
171} } // namespace Poco::Zip
172