forked from blastrock/pkgj
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextractzip.cpp
More file actions
87 lines (76 loc) · 2.68 KB
/
Copy pathextractzip.cpp
File metadata and controls
87 lines (76 loc) · 2.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "extractzip.hpp"
#include "file.hpp"
#include "pkgi.hpp"
#include <zip.h>
#include <boost/scope_exit.hpp>
#if __arm__
extern const char _ctype_[];
// For some reason bzip2 needs this, and it isn't defined by the toolchain
const char* __ctype_ptr__ = _ctype_;
#endif
void pkgi_extract_zip(const std::string& zip_file, const std::string& dest)
{
int err;
const auto zip_fd = zip_open(zip_file.c_str(), ZIP_RDONLY, &err);
if (!zip_fd)
throw formatEx<std::runtime_error>(
"failed to open zip {}:\n{}", zip_file, err);
BOOST_SCOPE_EXIT_ALL(&)
{
zip_close(zip_fd);
};
const auto num_entries = zip_get_num_entries(zip_fd, 0);
for (auto i = 0; i < num_entries; ++i)
{
struct zip_stat stat;
if (zip_stat_index(zip_fd, i, 0, &stat) != 0)
throw formatEx<std::runtime_error>(
"can't zip_stat index {} of {}:\n{}",
i,
zip_file,
zip_strerror(zip_fd));
if (!(stat.valid & ZIP_STAT_NAME))
throw std::runtime_error("unsupported zip: no file name");
if (!(stat.valid & ZIP_STAT_SIZE))
throw std::runtime_error("unsupported zip: no file size");
std::string path = stat.name;
if (path[path.size() - 1] == '/')
{
LOGF("creating directory {}", path);
pkgi_mkdirs((dest + '/' + path).c_str());
}
else
{
LOGF("uncompressing file {}", path);
const auto comp_fd = zip_fopen_index(zip_fd, i, 0);
if (!comp_fd)
throw formatEx<std::runtime_error>(
"can't zip_fopen index {} of {}:\n{}",
i,
zip_file,
zip_strerror(zip_fd));
BOOST_SCOPE_EXIT_ALL(&)
{
zip_fclose(comp_fd);
};
const auto out_fd = pkgi_create((dest + '/' + path).c_str());
if (!out_fd)
throw formatEx<std::runtime_error>("can't open file {}", path);
BOOST_SCOPE_EXIT_ALL(&)
{
pkgi_close(out_fd);
};
static constexpr auto READ_SIZE = 1 * 1024 * 1024;
std::vector<uint8_t> buffer(READ_SIZE);
uint64_t pos = 0;
while (pos < stat.size)
{
const auto to_read =
std::min<uint64_t>(buffer.size(), stat.size - pos);
const auto readed = zip_fread(comp_fd, buffer.data(), to_read);
pkgi_write(out_fd, buffer.data(), readed);
pos += readed;
}
}
}
}