comparison Resources/Orthanc/Core/Compression/ZipWriter.cpp @ 200:03afbee0cc7b

integration of Orthanc core into Stone
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 23 Mar 2018 11:04:03 +0100
parents
children
comparison
equal deleted inserted replaced
199:dabe9982fca3 200:03afbee0cc7b
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #include "../PrecompiledHeaders.h"
35
36 #ifndef NOMINMAX
37 #define NOMINMAX
38 #endif
39
40 #include "ZipWriter.h"
41
42 #include <limits>
43 #include <boost/filesystem.hpp>
44 #include <boost/date_time/posix_time/posix_time.hpp>
45
46 #include "../../Resources/ThirdParty/minizip/zip.h"
47 #include "../OrthancException.h"
48 #include "../Logging.h"
49
50
51 static void PrepareFileInfo(zip_fileinfo& zfi)
52 {
53 memset(&zfi, 0, sizeof(zfi));
54
55 using namespace boost::posix_time;
56 ptime now = second_clock::local_time();
57
58 boost::gregorian::date today = now.date();
59 ptime midnight(today);
60
61 time_duration sinceMidnight = now - midnight;
62 zfi.tmz_date.tm_sec = sinceMidnight.seconds(); // seconds after the minute - [0,59]
63 zfi.tmz_date.tm_min = sinceMidnight.minutes(); // minutes after the hour - [0,59]
64 zfi.tmz_date.tm_hour = sinceMidnight.hours(); // hours since midnight - [0,23]
65
66 // http://www.boost.org/doc/libs/1_35_0/doc/html/boost/gregorian/greg_day.html
67 zfi.tmz_date.tm_mday = today.day(); // day of the month - [1,31]
68
69 // http://www.boost.org/doc/libs/1_35_0/doc/html/boost/gregorian/greg_month.html
70 zfi.tmz_date.tm_mon = today.month() - 1; // months since January - [0,11]
71
72 // http://www.boost.org/doc/libs/1_35_0/doc/html/boost/gregorian/greg_year.html
73 zfi.tmz_date.tm_year = today.year(); // years - [1980..2044]
74 }
75
76
77
78 namespace Orthanc
79 {
80 struct ZipWriter::PImpl
81 {
82 zipFile file_;
83
84 PImpl() : file_(NULL)
85 {
86 }
87 };
88
89 ZipWriter::ZipWriter() :
90 pimpl_(new PImpl),
91 isZip64_(false),
92 hasFileInZip_(false),
93 append_(false),
94 compressionLevel_(6)
95 {
96 }
97
98 ZipWriter::~ZipWriter()
99 {
100 Close();
101 }
102
103 void ZipWriter::Close()
104 {
105 if (IsOpen())
106 {
107 zipClose(pimpl_->file_, "Created by Orthanc");
108 pimpl_->file_ = NULL;
109 hasFileInZip_ = false;
110 }
111 }
112
113 bool ZipWriter::IsOpen() const
114 {
115 return pimpl_->file_ != NULL;
116 }
117
118 void ZipWriter::Open()
119 {
120 if (IsOpen())
121 {
122 return;
123 }
124
125 if (path_.size() == 0)
126 {
127 LOG(ERROR) << "Please call SetOutputPath() before creating the file";
128 throw OrthancException(ErrorCode_BadSequenceOfCalls);
129 }
130
131 hasFileInZip_ = false;
132
133 int mode = APPEND_STATUS_CREATE;
134 if (append_ &&
135 boost::filesystem::exists(path_))
136 {
137 mode = APPEND_STATUS_ADDINZIP;
138 }
139
140 if (isZip64_)
141 {
142 pimpl_->file_ = zipOpen64(path_.c_str(), mode);
143 }
144 else
145 {
146 pimpl_->file_ = zipOpen(path_.c_str(), mode);
147 }
148
149 if (!pimpl_->file_)
150 {
151 throw OrthancException(ErrorCode_CannotWriteFile);
152 }
153 }
154
155 void ZipWriter::SetOutputPath(const char* path)
156 {
157 Close();
158 path_ = path;
159 }
160
161 void ZipWriter::SetZip64(bool isZip64)
162 {
163 Close();
164 isZip64_ = isZip64;
165 }
166
167 void ZipWriter::SetCompressionLevel(uint8_t level)
168 {
169 if (level >= 10)
170 {
171 LOG(ERROR) << "ZIP compression level must be between 0 (no compression) and 9 (highest compression)";
172 throw OrthancException(ErrorCode_ParameterOutOfRange);
173 }
174
175 Close();
176 compressionLevel_ = level;
177 }
178
179 void ZipWriter::OpenFile(const char* path)
180 {
181 Open();
182
183 zip_fileinfo zfi;
184 PrepareFileInfo(zfi);
185
186 int result;
187
188 if (isZip64_)
189 {
190 result = zipOpenNewFileInZip64(pimpl_->file_, path,
191 &zfi,
192 NULL, 0,
193 NULL, 0,
194 "", // Comment
195 Z_DEFLATED,
196 compressionLevel_, 1);
197 }
198 else
199 {
200 result = zipOpenNewFileInZip(pimpl_->file_, path,
201 &zfi,
202 NULL, 0,
203 NULL, 0,
204 "", // Comment
205 Z_DEFLATED,
206 compressionLevel_);
207 }
208
209 if (result != 0)
210 {
211 throw OrthancException(ErrorCode_CannotWriteFile);
212 }
213
214 hasFileInZip_ = true;
215 }
216
217
218 void ZipWriter::Write(const std::string& data)
219 {
220 if (data.size())
221 {
222 Write(&data[0], data.size());
223 }
224 }
225
226
227 void ZipWriter::Write(const char* data, size_t length)
228 {
229 if (!hasFileInZip_)
230 {
231 LOG(ERROR) << "Call first OpenFile()";
232 throw OrthancException(ErrorCode_BadSequenceOfCalls);
233 }
234
235 const size_t maxBytesInAStep = std::numeric_limits<int32_t>::max();
236
237 while (length > 0)
238 {
239 int bytes = static_cast<int32_t>(length <= maxBytesInAStep ? length : maxBytesInAStep);
240
241 if (zipWriteInFileInZip(pimpl_->file_, data, bytes))
242 {
243 throw OrthancException(ErrorCode_CannotWriteFile);
244 }
245
246 data += bytes;
247 length -= bytes;
248 }
249 }
250
251
252 void ZipWriter::SetAppendToExisting(bool append)
253 {
254 Close();
255 append_ = append;
256 }
257
258
259 }