ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ExtractZIP.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 // Reference:
11 // https://github.com/madler/zlib/blob/master/contrib/minizip/miniunz.c
12 
13 #include <FileSystem.h>
14 #include <Logging.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <unzip.h>
18 
19 #include <iostream>
20 #include <string>
21 
22 #ifdef __APPLE__
23 // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no
24 // need for specific 64 bit functions
25 #define FOPEN_FUNC(filename, mode) fopen(filename, mode)
26 #else
27 #define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
28 #endif
29 
30 // If required in future, the `WRITEBUFFERSIZE` size can be increased to 16384.
31 #define WRITEBUFFERSIZE (8192)
32 
33 namespace cloudViewer {
34 namespace utility {
35 
37  const std::string &extract_dir,
38  const std::string &password) {
39  char filename_inzip[256];
40  char *filename_withoutpath;
41  char *p;
42  int err = UNZ_OK;
43  FILE *fout = nullptr;
44  void *buf;
45  uInt size_buf;
46 
47  unz_file_info64 file_info;
48  err = unzGetCurrentFileInfo64(uf, &file_info, filename_inzip,
49  sizeof(filename_inzip), nullptr, 0, nullptr,
50  0);
51 
52  if (err != UNZ_OK) {
53  utility::LogWarning("Error {} with zipfile in unzGetCurrentFileInfo.",
54  err);
55  return err;
56  }
57 
58  size_buf = WRITEBUFFERSIZE;
59  buf = (void *)malloc(size_buf);
60  if (buf == nullptr) {
61  utility::LogWarning("Error allocating memory.");
62  return UNZ_INTERNALERROR;
63  }
64 
65  // If zip entry is a directory then create it on disk.
66  p = filename_withoutpath = filename_inzip;
67  while ((*p) != '\0') {
68  if (((*p) == '/') || ((*p) == '\\')) {
69  filename_withoutpath = p + 1;
70  }
71  p++;
72  }
73 
74  if ((*filename_withoutpath) == '\0') {
75  const std::string dir_path = extract_dir + "/" + filename_inzip;
76  utility::LogDebug("Creating directory: {}", dir_path);
78  } else {
79  const char *write_filename;
80  write_filename = filename_inzip;
81 
82  if (password.empty()) {
83  err = unzOpenCurrentFilePassword(uf, nullptr);
84  } else {
85  err = unzOpenCurrentFilePassword(uf, password.c_str());
86  }
87 
88  if (err != UNZ_OK) {
90  "Extraction failed in unzOpenCurrentFilePassword with "
91  "error code: {}.",
92  err);
93  return err;
94  }
95 
96  if (err == UNZ_OK) {
97  std::string file_path = extract_dir + "/" +
98  static_cast<std::string>(write_filename);
99  fout = FOPEN_FUNC(file_path.c_str(), "wb");
100 
101  // Some zipfile don't contain directory alone before file.
102  if ((fout == nullptr) &&
103  filename_withoutpath == (char *)filename_inzip) {
105 
106  fout = FOPEN_FUNC(file_path.c_str(), "wb");
107  }
108 
109  if (fout == nullptr) {
110  utility::LogWarning("Extraction failed. Error opening {}",
111  file_path);
112  return UNZ_ERRNO;
113  }
114  }
115 
116  if (fout != nullptr) {
117  do {
118  err = unzReadCurrentFile(uf, buf, size_buf);
119  if (err < 0) {
121  "Extraction failed in unzReadCurrentFile with "
122  "error code: {}.",
123  err);
124  break;
125  }
126  if (err > 0)
127  if (fwrite(buf, err, 1, fout) != 1) {
129  "Extraction failed. Error in writing extracted "
130  "file.");
131  err = UNZ_ERRNO;
132  break;
133  }
134  } while (err > 0);
135 
136  if (fout) {
137  fclose(fout);
138  }
139  }
140 
141  if (err == UNZ_OK) {
142  err = unzCloseCurrentFile(uf);
143  if (err != UNZ_OK) {
145  "Extraction failed in unzCloseCurrentFile with error "
146  "code: {}.",
147  err);
148  }
149  } else {
151  }
152  }
153 
154  free(buf);
155  return err;
156 }
157 
158 void ExtractFromZIP(const std::string &file_path,
159  const std::string &extract_dir) {
160  unzFile uf = nullptr;
161  if (!file_path.empty()) {
162  uf = unzOpen64(file_path.c_str());
163  }
164  if (uf == nullptr) {
165  utility::LogError("Failed to open file {}.", file_path);
166  }
167 
169  int err = unzGetGlobalInfo64(uf, &gi);
170  if (err != UNZ_OK) {
171  // Close file, before throwing exception.
172  unzClose(uf);
174  "Extraction failed in unzGetGlobalInfo with error code: {}.",
175  err);
176  }
177 
178  // ExtractFromZIP supports password. Can be exposed if required in future.
179  const std::string password = "";
180 
181  for (uLong i = 0; i < gi.number_entry; ++i) {
182  err = ExtractCurrentFile(uf, extract_dir, password);
183  if (err != UNZ_OK) {
184  // Close file, before throwing exception.
185  unzClose(uf);
187  "Extraction failed in ExtractCurrentFile with error code: "
188  "{}.",
189  err);
190  }
191 
192  if ((i + 1) < gi.number_entry) {
193  err = unzGoToNextFile(uf);
194  if (err != UNZ_OK) {
195  // Close file, before throwing exception.
196  unzClose(uf);
198  "Extraction failed in ExtractCurrentFile with error "
199  "code: {}.",
200  err);
201  }
202  }
203  }
204 
205  // Extracted Successfully. Close File.
206  unzClose(uf);
207 }
208 
209 } // namespace utility
210 } // namespace cloudViewer
#define FOPEN_FUNC(filename, mode)
Definition: ExtractZIP.cpp:27
#define WRITEBUFFERSIZE
Definition: ExtractZIP.cpp:31
#define LogWarning(...)
Definition: Logging.h:72
#define LogError(...)
Definition: Logging.h:60
#define LogDebug(...)
Definition: Logging.h:90
bool MakeDirectoryHierarchy(const std::string &directory)
Definition: FileSystem.cpp:499
void ExtractFromZIP(const std::string &file_path, const std::string &extract_dir)
Function to extract files compressed in .zip format.
Definition: ExtractZIP.cpp:158
static int ExtractCurrentFile(unzFile uf, const std::string &extract_dir, const std::string &password)
Definition: ExtractZIP.cpp:36
Generic file read and write utility for python interface.
ZPOS64_T number_entry
Definition: unzip.h:108
int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password)
Definition: unzip.c:1654
int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)
Definition: unzip.c:1134
int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len)
Definition: unzip.c:1692
int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info)
Definition: unzip.c:838
unzFile ZEXPORT unzOpen64(voidpf file)
Definition: unzip.c:805
int ZEXPORT unzCloseCurrentFile(unzFile file)
Definition: unzip.c:2004
int ZEXPORT unzGoToNextFile(unzFile file)
Definition: unzip.c:1209
int ZEXPORT unzClose(unzFile file)
Definition: unzip.c:815
#define UNZ_INTERNALERROR
Definition: unzip.h:89
#define UNZ_ERRNO
Definition: unzip.h:85
voidp unzFile
Definition: unzip.h:80
#define UNZ_OK
Definition: unzip.h:83