1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (archive_file.h).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #ifndef LIBRETRO_SDK_ARCHIVE_FILE_H__
24 #define LIBRETRO_SDK_ARCHIVE_FILE_H__
25 
26 #include <stdint.h>
27 #include <stddef.h>
28 #include <boolean.h>
29 
30 #ifdef _WIN32
31 #include <direct.h>
32 #else
33 #include <unistd.h>
34 #endif
35 
36 #include <retro_miscellaneous.h>
37 
38 #include <retro_common_api.h>
39 
40 #if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
41 #include "../../../config.h" /* for HAVE_MMAP */
42 #endif
43 
44 RETRO_BEGIN_DECLS
45 
46 enum file_archive_transfer_type
47 {
48    ARCHIVE_TRANSFER_NONE = 0,
49    ARCHIVE_TRANSFER_INIT,
50    ARCHIVE_TRANSFER_ITERATE,
51    ARCHIVE_TRANSFER_DEINIT,
52    ARCHIVE_TRANSFER_DEINIT_ERROR
53 };
54 
55 typedef struct file_archive_handle
56 {
57    uint8_t  *data;
58    uint32_t real_checksum;
59 } file_archive_file_handle_t;
60 
61 typedef struct file_archive_transfer
62 {
63    int64_t archive_size;
64    void *context;
65    struct RFILE *archive_file;
66    const struct file_archive_file_backend *backend;
67 #ifdef HAVE_MMAP
68    uint8_t *archive_mmap_data;
69    int archive_mmap_fd;
70 #endif
71    unsigned step_total;
72    unsigned step_current;
73    enum file_archive_transfer_type type;
74 } file_archive_transfer_t;
75 
76 typedef struct
77 {
78    file_archive_transfer_t archive;             /* int64_t alignment */
79    char *source_file;
80    char *subdir;
81    char *target_dir;
82    char *target_file;
83    char *valid_ext;
84    char *callback_error;
85    struct archive_extract_userdata *userdata;
86 } decompress_state_t;
87 
88 struct archive_extract_userdata
89 {
90    /* These are set or read by the archive processing */
91    char *first_extracted_file_path;
92    const char *extraction_directory;
93    struct string_list *ext;
94    struct string_list *list;
95    file_archive_transfer_t *transfer;
96    /* Not used by the processing, free to use outside or in iterate callback */
97    decompress_state_t *dec;
98    void* cb_data;
99    size_t archive_path_size;
100    uint32_t crc;
101    char archive_path[PATH_MAX_LENGTH];
102    char current_file_path[PATH_MAX_LENGTH];
103    bool found_file;
104    bool list_only;
105 };
106 
107 /* Returns true when parsing should continue. False to stop. */
108 typedef int (*file_archive_file_cb)(const char *name, const char *valid_exts,
109       const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
110       uint32_t crc32, struct archive_extract_userdata *userdata);
111 
112 struct file_archive_file_backend
113 {
114    int (*archive_parse_file_init)(
115       file_archive_transfer_t *state,
116       const char *file);
117    int (*archive_parse_file_iterate_step)(
118       void *context,
119       const char *valid_exts,
120       struct archive_extract_userdata *userdata,
121       file_archive_file_cb file_cb);
122    void (*archive_parse_file_free)(
123       void *context);
124 
125    bool     (*stream_decompress_data_to_file_init)(
126       void *context, file_archive_file_handle_t *handle,
127       const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size);
128    int      (*stream_decompress_data_to_file_iterate)(
129       void *context,
130       file_archive_file_handle_t *handle);
131 
132    uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t);
133    int64_t (*compressed_file_read)(const char *path, const char *needle, void **buf,
134          const char *optional_outfile);
135    const char *ident;
136 };
137 
138 int file_archive_parse_file_iterate(
139       file_archive_transfer_t *state,
140       bool *returnerr,
141       const char *file,
142       const char *valid_exts,
143       file_archive_file_cb file_cb,
144       struct archive_extract_userdata *userdata);
145 
146 void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state);
147 
148 int file_archive_parse_file_progress(file_archive_transfer_t *state);
149 
150 /**
151  * file_archive_extract_file:
152  * @archive_path                    : filename path to ZIP archive.
153  * @archive_path_size               : size of ZIP archive.
154  * @valid_exts                  : valid extensions for a file.
155  * @extraction_directory        : the directory to extract the temporary
156  *                                file to.
157  *
158  * Extract file from archive. If no file inside the archive is
159  * specified, the first file found will be used.
160  *
161  * Returns : true (1) on success, otherwise false (0).
162  **/
163 bool file_archive_extract_file(char *archive_path, size_t archive_path_size,
164       const char *valid_exts, const char *extraction_dir,
165       char *out_path, size_t len);
166 
167 /* Warning: 'list' must zero initialised before
168  * calling this function, otherwise memory leaks/
169  * undefined behaviour will occur */
170 bool file_archive_get_file_list_noalloc(struct string_list *list,
171       const char *path,
172       const char *valid_exts);
173 
174 /**
175  * file_archive_get_file_list:
176  * @path                        : filename path of archive
177  * @valid_exts                  : Valid extensions of archive to be parsed.
178  *                                If NULL, allow all.
179  *
180  * Returns: string listing of files from archive on success, otherwise NULL.
181  **/
182 struct string_list* file_archive_get_file_list(const char *path, const char *valid_exts);
183 
184 bool file_archive_perform_mode(const char *name, const char *valid_exts,
185       const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
186       uint32_t crc32, struct archive_extract_userdata *userdata);
187 
188 int file_archive_compressed_read(
189       const char* path, void **buf,
190       const char* optional_filename, int64_t *length);
191 
192 const struct file_archive_file_backend* file_archive_get_zlib_file_backend(void);
193 const struct file_archive_file_backend* file_archive_get_7z_file_backend(void);
194 
195 const struct file_archive_file_backend* file_archive_get_file_backend(const char *path);
196 
197 /**
198  * file_archive_get_file_crc32:
199  * @path                         : filename path of archive
200  *
201  * Returns: CRC32 of the specified file in the archive, otherwise 0.
202  * If no path within the archive is specified, the first
203  * file found inside is used.
204  **/
205 uint32_t file_archive_get_file_crc32(const char *path);
206 
207 extern const struct file_archive_file_backend zlib_backend;
208 extern const struct file_archive_file_backend sevenzip_backend;
209 
210 RETRO_END_DECLS
211 
212 #endif
213