1 /*
2 * archive_reader.cc
3 * Copyright (c) 2020 Ariadne Conill
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions, and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions, and the following disclaimer in the documentation
13 * provided with the distribution.
14 *
15 * This software is provided "as is" and without any warranty, express or
16 * implied. In no event shall the authors be liable for any damages arising from
17 * the use of this software.
18 */
19
20 #ifdef USE_LIBARCHIVE
21
22 #include "archive_reader.h"
23 #include "audstrings.h"
24 #include "runtime.h"
25
ArchiveReader(VFSFile && archive_file)26 EXPORT ArchiveReader::ArchiveReader(VFSFile && archive_file) :
27 m_archive_file (archive_file)
28 {
29 }
30
read_folder()31 EXPORT Index<String> ArchiveReader::read_folder()
32 {
33 Index<String> files;
34 archive * a = nullptr;
35 archive_entry * entry = nullptr;
36
37 // if fseek returns non-zero, bail
38 if (m_archive_file.fseek (0, VFS_SEEK_SET))
39 return files;
40
41 a = archive_read_new ();
42 archive_read_support_filter_all (a);
43 archive_read_support_format_all (a);
44
45 archive_read_open (a, this, nullptr, reader, nullptr);
46
47 while (archive_read_next_header (a, & entry) == ARCHIVE_OK)
48 {
49 files.append (String (archive_entry_pathname (entry)));
50 }
51
52 archive_read_free (a);
53
54 return files;
55 }
56
reader(archive * a,void * client_data,const void ** buff)57 ssize_t ArchiveReader::reader(archive * a, void * client_data, const void ** buff)
58 {
59 constexpr int pagesize = 4096;
60
61 ArchiveReader * ar = (ArchiveReader *) client_data;
62
63 ar->m_buf.clear ();
64 ar->m_buf.insert (0, pagesize);
65
66 auto size = ar->m_archive_file.fread (ar->m_buf.begin (), 1, pagesize);
67 ar->m_buf.remove (size, -1);
68
69 * buff = ar->m_buf.begin ();
70
71 return size;
72 }
73
open(const char * path)74 EXPORT VFSFile ArchiveReader::open(const char * path)
75 {
76 return VFSFile (path, read_file (path));
77 }
78
read_file(const char * path)79 EXPORT VFSArchiveReaderImpl * ArchiveReader::read_file(const char * path)
80 {
81 archive * a = nullptr;
82 archive_entry * entry = nullptr;
83
84 // if fseek returns non-zero, bail
85 if (m_archive_file.fseek (0, VFS_SEEK_SET))
86 return nullptr;
87
88 a = archive_read_new ();
89 archive_read_support_filter_all (a);
90 archive_read_support_format_all (a);
91
92 archive_read_open (a, this, nullptr, reader, nullptr);
93
94 while (archive_read_next_header (a, & entry) == ARCHIVE_OK)
95 {
96 if (! str_compare (archive_entry_pathname (entry), path))
97 return new VFSArchiveReaderImpl (a, entry);
98 }
99
100 // on error, cleanup and return nullptr
101 archive_read_free (a);
102 return nullptr;
103 }
104
VFSArchiveReaderImpl(archive * a,archive_entry * entry)105 VFSArchiveReaderImpl::VFSArchiveReaderImpl(archive * a, archive_entry * entry) :
106 m_archive (a),
107 m_archive_entry (entry),
108 m_pos (0),
109 m_eof (false)
110 {
111 m_size = archive_entry_size (m_archive_entry);
112 }
113
~VFSArchiveReaderImpl()114 VFSArchiveReaderImpl::~VFSArchiveReaderImpl()
115 {
116 if (m_archive)
117 archive_read_free (m_archive);
118
119 m_archive = nullptr;
120 }
121
fsize()122 int64_t VFSArchiveReaderImpl::fsize ()
123 {
124 return m_size;
125 }
126
ftell()127 int64_t VFSArchiveReaderImpl::ftell ()
128 {
129 return m_pos;
130 }
131
feof()132 bool VFSArchiveReaderImpl::feof ()
133 {
134 return m_eof;
135 }
136
ftruncate(int64_t)137 int VFSArchiveReaderImpl::ftruncate (int64_t)
138 {
139 return 0;
140 }
141
fflush()142 int VFSArchiveReaderImpl::fflush ()
143 {
144 return 0;
145 }
146
fwrite(const void * ptr,int64_t size,int64_t nmemb)147 int64_t VFSArchiveReaderImpl::fwrite (const void * ptr, int64_t size, int64_t nmemb)
148 {
149 return 0;
150 }
151
fseek(int64_t offset,VFSSeekType whence)152 int VFSArchiveReaderImpl::fseek (int64_t offset, VFSSeekType whence)
153 {
154 AUDERR("<%p> implement me!\n", this);
155 return -1;
156 }
157
fread(void * ptr,int64_t size,int64_t nmemb)158 int64_t VFSArchiveReaderImpl::fread (void * ptr, int64_t size, int64_t nmemb)
159 {
160 auto ret = archive_read_data (m_archive, ptr, (size * nmemb));
161 if (ret < ARCHIVE_OK)
162 return -1;
163
164 if (! ret)
165 m_eof = true;
166
167 m_pos += ret;
168
169 return ret;
170 }
171
172 #endif // USE_LIBARCHIVE
173