annotate libmlk-core/core/zfile.c @ 303:48a09c9d3d00

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