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