comparison src/libmlk-core/core/zfile.c @ 320:8f9937403749

misc: improve loading of data
author David Demelier <markand@malikania.fr>
date Fri, 01 Oct 2021 20:30:00 +0200
parents libmlk-core/core/zfile.c@1a6125ffebff
children 7d7991f97acf
comparison
equal deleted inserted replaced
319:b843eef4cc35 320:8f9937403749
1 /*
2 * zfile.c -- load potentially ZSTD compressed file
3 *
4 * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "config.h"
20
21 #include <sys/stat.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 /*
31 * If not enabled, we still need to check if a file is in zstandard so we use
32 * the magic number defined in the zstd.h file or copy it if zstd is disabled.
33 */
34 #if defined(MLK_WITH_ZSTD)
35 # include <zstd.h>
36 #else
37 # define ZSTD_MAGICNUMBER 0xFD2FB528
38 #endif
39
40 /* Windows thing. */
41 #if !defined(O_BINARY)
42 # define O_BINARY 0
43 #endif
44
45 #include <port/port.h>
46
47 #include "zfile.h"
48
49 static int
50 is_zstd(int fd)
51 {
52 uint32_t magic = 0;
53
54 read(fd, &magic, sizeof (magic));
55 lseek(fd, 0, SEEK_SET);
56
57 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
58 magic = SDL_Swap32(magic);
59 #endif
60
61 return magic == ZSTD_MAGICNUMBER;
62 }
63
64 static int
65 decompress(int fd, struct zfile *zf)
66 {
67 #if defined(MLK_WITH_ZSTD)
68 char *in = NULL;
69 unsigned long long datasz;
70 struct stat st;
71 ssize_t nr;
72
73 /* Load uncompressed data. */
74 if (fstat(fd, &st) < 0)
75 goto fail;
76 if (!(in = calloc(1, st.st_size)) || (nr = read(fd, in, st.st_size)) != st.st_size)
77 goto fail;
78
79 switch ((datasz = ZSTD_getFrameContentSize(in, st.st_size))) {
80 case ZSTD_CONTENTSIZE_ERROR:
81 errno = EINVAL;
82 goto fail;
83 case ZSTD_CONTENTSIZE_UNKNOWN:
84 errno = ENOTSUP;
85 goto fail;
86 default:
87 break;
88 }
89
90 /* Finally decompress. */
91 if (!(zf->data = calloc(1, datasz + 1)))
92 goto fail;
93 if (ZSTD_isError(ZSTD_decompress(zf->data, datasz, in, st.st_size))) {
94 errno = EINVAL;
95 goto fail;
96 }
97 if (!(zf->fp = fmemopen(zf->data, datasz, "r")))
98 goto fail;
99
100 close(fd);
101 free(in);
102
103 return 0;
104
105 fail:
106 close(fd);
107 free(zf->data);
108 free(in);
109
110 return -1;
111 #else
112 (void)fd;
113 (void)zf;
114
115 errno = ENOTSUP;
116
117 return -1;
118 #endif
119 }
120
121 static int
122 reopen(int fd, struct zfile *zf)
123 {
124 if (!(zf->fp = fdopen(fd, "r")))
125 return close(fd), -1;
126
127 return 0;
128 }
129
130 int
131 zfile_open(struct zfile *zf, const char *path)
132 {
133 assert(zf);
134 assert(path);
135
136 int fd;
137
138 memset(zf, 0, sizeof (*zf));
139
140 if ((fd = open(path, O_RDONLY | O_BINARY)) < 0)
141 return -1;
142
143 return is_zstd(fd) ? decompress(fd, zf) : reopen(fd, zf);
144 }
145
146 void
147 zfile_close(struct zfile *zf)
148 {
149 assert(zf);
150
151 free(zf->data);
152
153 if (zf->fp)
154 fclose(zf->fp);
155
156 memset(zf, 0, sizeof (*zf));
157 }