Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
memoryzipstream.cc
Go to the documentation of this file.
1 
19 
20 #include <cstring>
21 
22 #include "ion/base/logging.h"
24 #include "third_party/unzip/unzip.h"
25 #include "third_party/zlib/src/contrib/minizip/zip.h"
26 
27 namespace ion {
28 namespace base {
29 
32 struct MemoryZipStream::ZipStreamInfo : public Allocatable {
33  ZipStreamInfo() : position(0U), buffer(GetAllocator()) {}
34  zlib_filefunc_def def;
35  size_t position;
37 };
38 
39 namespace {
40 
42 typedef long ZipLong; // NOLINT
43 
46 static voidpf ZCALLBACK
47  OpenZipStream(voidpf opaque, const char* filename, int mode) {
48  if (MemoryZipStream::ZipStreamInfo* info =
49  reinterpret_cast<MemoryZipStream::ZipStreamInfo*>(opaque))
50  info->position = 0U;
51  return opaque;
52 }
53 
55 static uLong ZCALLBACK
56 ReadFromZipStream(voidpf opaque, voidpf stream, void* buf, uLong size) {
57  uLong bytes_read = 0;
58  if (MemoryZipStream::ZipStreamInfo* info =
59  reinterpret_cast<MemoryZipStream::ZipStreamInfo*>(opaque)) {
60  if (info->position + size > info->buffer.size()) {
61  const int64 available = info->buffer.size() - info->position;
62  size = available < 0 ? 0 : static_cast<uLong>(available);
63  }
64  if (size) {
65  memcpy(buf, &info->buffer[info->position], size);
66  info->position += size;
67  bytes_read = size;
68  }
69  }
70  return bytes_read;
71 }
72 
75 static uLong ZCALLBACK WriteToZipStream(
76  voidpf opaque, voidpf stream, const void* buf, uLong size) {
77  uLong bytes_written = 0;
78  if (MemoryZipStream::ZipStreamInfo* info =
79  reinterpret_cast<MemoryZipStream::ZipStreamInfo*>(opaque)) {
80  if (info->position + size > info->buffer.size())
81  info->buffer.resize(info->position + size);
82 
83  memcpy(&info->buffer[info->position], buf, size);
84  info->position += size;
85 
86  bytes_written = size;
87  }
88  return bytes_written;
89 }
90 
92 static ZipLong ZCALLBACK TellZipStream(voidpf opaque, voidpf stream) {
93  ZipLong position = 0;
94  if (MemoryZipStream::ZipStreamInfo* info =
95  reinterpret_cast<MemoryZipStream::ZipStreamInfo*>(opaque))
96  position = static_cast<ZipLong>(info->position);
97  return position;
98 }
99 
101 static ZipLong ZCALLBACK
102 SeekZipStream(voidpf opaque, voidpf stream, uLong offset, int origin) {
103  bool ok = true;
104  if (MemoryZipStream::ZipStreamInfo* info =
105  reinterpret_cast<MemoryZipStream::ZipStreamInfo*>(opaque)) {
106  ok = false;
107  const int64 size = info->buffer.size();
108  if (origin == SEEK_SET) {
109  ok = true;
110  info->position = offset;
111  } else if (origin == SEEK_CUR) {
112  ok = (static_cast<size_t>(offset) + info->position) <=
113  static_cast<size_t>(size);
114  if (ok)
115  info->position += offset;
116  } else if (origin == SEEK_END) {
117  const int64 new_pos = size - static_cast<int64>(offset);
118  ok = new_pos >= 0 && new_pos <= size;
119  if (ok)
120  info->position = offset + static_cast<size_t>(size);
121  }
122  }
123  return ok ? 0 : -1;
124 }
125 
127 static int ZCALLBACK CloseZipStream(voidpf opaque, voidpf stream) {
128  return 0;
129 }
130 
132 static int ZCALLBACK ErrorZipStream(voidpf opaque, voidpf stream) {
134  LOG(ERROR) << "An error occurred in a MemoryZipStream";
135  return -1;
136 }
137 
138 struct ScopedUnzip {
139  explicit ScopedUnzip(MemoryZipStream::ZipStreamInfo* info)
140  : handle(info->buffer.size() ? unzAttach(&info->def, &info->def) : NULL) {
141  }
142  ~ScopedUnzip() {
143  if (handle)
144  unzDetach(&handle);
145  }
146  operator bool() { return handle != NULL; }
147 
148  unzFile handle;
149 };
150 
151 struct ScopedZip {
152  explicit ScopedZip(MemoryZipStream::ZipStreamInfo* info)
153  : handle(info->buffer.size()
154  ? zipOpen2("", APPEND_STATUS_ADDINZIP, NULL, &info->def)
155  : zipOpen2("", APPEND_STATUS_CREATE, NULL, &info->def)) {}
156  ~ScopedZip() {
157  if (handle)
158  zipClose(handle, "");
159  }
160  operator bool() { return handle != NULL; }
161 
162  zipFile handle;
163 };
164 
165 } // anonymous namespace
166 
168  : info_(new(GetAllocator()) ZipStreamInfo()) {
169  InitCallbacks();
170 }
171 
173  : info_(new(GetAllocator()) ZipStreamInfo()) {
174  info_->buffer = data;
175  InitCallbacks();
176 }
177 
179  : info_(new(GetAllocator()) ZipStreamInfo()) {
180  info_->buffer.swap(*data);
181  InitCallbacks();
182 }
183 
185 
186 void MemoryZipStream::AddFile(const std::string& filename,
187  const DataVector& data) {
188  if (ScopedZip zip = ScopedZip(info_.get())) {
189  zipOpenNewFileInZip(
190  zip.handle, filename.c_str(), NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
191  Z_BEST_COMPRESSION);
192  zipWriteInFileInZip(zip.handle, data.data(),
193  static_cast<unsigned int>(data.size()));
194  zipCloseFileInZip(zip.handle);
195  }
196 }
197 
198 void MemoryZipStream::AddFile(const std::string& filename,
199  const std::string& data) {
200  DataVector vec(*this, data.begin(), data.end());
201  AddFile(filename, vec);
202 }
203 
204 bool MemoryZipStream::ContainsFile(const std::string& filename) {
205  bool contains = false;
206  if (ScopedUnzip unz = ScopedUnzip(info_.get()))
207  contains = unzLocateFile(unz.handle, filename.c_str(), 0) == UNZ_OK;
208  return contains;
209 }
210 
212  const std::string& filename) {
213  DataVector data(*this);
214  if (ScopedUnzip unz = ScopedUnzip(info_.get())) {
216  unz_file_info info;
218  static const int kStringLength = 256;
219  char extra_field[kStringLength + 1];
220  char comment[kStringLength + 1];
221  if (unzLocateFile(unz.handle, filename.c_str(), 0) == UNZ_OK &&
222  unzOpenCurrentFile(unz.handle) == UNZ_OK &&
223  unzGetCurrentFileInfo(unz.handle, &info, NULL, 0, extra_field,
224  kStringLength, comment, kStringLength) ==
225  UNZ_OK) {
227  data.resize(info.uncompressed_size);
229  unzReadCurrentFile(unz.handle, &data[0],
230  static_cast<unsigned int>(info.uncompressed_size));
231  }
232  }
233  return data;
234 }
235 
237  return info_->buffer;
238 }
239 
240 void MemoryZipStream::InitCallbacks() {
242  info_->def.zopen_file = OpenZipStream;
243  info_->def.zread_file = ReadFromZipStream;
244  info_->def.zwrite_file = WriteToZipStream;
245  info_->def.ztell_file = TellZipStream;
246  info_->def.zseek_file = SeekZipStream;
247  info_->def.zclose_file = CloseZipStream;
248  info_->def.zerror_file = ErrorZipStream;
249  info_->def.opaque = info_.get();
250 }
251 
252 } // namespace base
253 } // namespace ion
std::string buffer
unzFile handle
void AddFile(const std::string &filename, const DataVector &data)
Compresses and adds a vector of data to this, associating it with the passed filename.
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
uint32 offset
const DataVector GetFileData(const std::string &filename)
Returns the file data for filename.
Point3f position
Definition: shapeutils.cc:67
MemoryZipStream()
Constructs an empty MemoryZipStream.
AllocVector< uint8 > DataVector
bool ContainsFile(const std::string &filename)
Returns whether this contains filename.
Copyright 2016 Google Inc.
const DataVector & GetData() const
Gets the memory buffer backing this.
const AllocatorPtr & GetAllocator() const
Returns the Allocator that was used for the instance.
Definition: allocatable.h:68