A game engine for top-down 2D RPG games.
rpg
game-engine
raylib
c99
1#include <keraforge.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <errno.h>
6#include <lzma.h>
7
8
9int kf_exists(char *filename)
10{
11 FILE *fp = fopen(filename, "r");
12 bool opened = fp != NULL;
13 if (opened)
14 fclose(fp);
15 return opened;
16}
17
18u8 *kf_readbin(char *filename, size_t *plen)
19{
20 FILE *fp = fopen(filename, "rb");
21 if (!fp)
22 return NULL;
23
24 *plen = 0;
25 fseek(fp, 0, SEEK_END);
26 *plen = ftell(fp);
27 fseek(fp, 0, SEEK_SET);
28 if (*plen == 0)
29 {
30 fclose(fp);
31 return NULL;
32 }
33
34 u8 *data = malloc(*plen);
35 (void)fread(data, 1, *plen, fp);
36 fclose(fp);
37
38 return data;
39}
40
41int kf_writebin(char *filename, u8 *data, size_t len)
42{
43 FILE *fp = fopen(filename, "wb");
44 if (!fp)
45 return 0;
46
47 size_t n = fwrite(data, 1, len, fp);
48 fclose(fp);
49
50 if (n != len)
51 return 0;
52
53 return 1;
54}
55
56static
57int _kf_compress(lzma_stream *s, FILE *ifp, FILE *ofp)
58{
59 lzma_action a = LZMA_RUN;
60 u8 inbuf[BUFSIZ], outbuf[BUFSIZ];
61
62 s->next_in = NULL;
63 s->avail_in = 0;
64 s->next_out = outbuf;
65 s->avail_out = sizeof(outbuf);
66
67 for (;;)
68 {
69 if (s->avail_in == 0 && !feof(ifp))
70 {
71 s->next_in = inbuf;
72 s->avail_in = fread(inbuf, 1, sizeof(inbuf), ifp);
73
74 if (ferror(ifp))
75 {
76 KF_THROW("read error: %s", strerror(errno));
77 return 0; /* unreachable */
78 }
79
80 if (feof(ifp))
81 a = LZMA_FINISH;
82 }
83
84 lzma_ret r = lzma_code(s, a);
85
86 if (s->avail_out == 0 || r == LZMA_STREAM_END)
87 {
88 size_t nwrote = sizeof(outbuf) - s->avail_out;
89
90 if (fwrite(outbuf, 1, nwrote, ofp) != nwrote)
91 {
92 KF_THROW("write error: %s", strerror(errno));
93 return 0; /* unreachable */
94 }
95
96 s->next_out = outbuf;
97 s->avail_out = sizeof(outbuf);
98 }
99
100 if (r != LZMA_OK)
101 {
102 if (r == LZMA_STREAM_END)
103 return 1;
104
105 KF_THROW("lzma compression error: code=%d", r);
106 return 0; /* unreachable */
107 }
108 }
109
110 KF_UNREACHABLE("broke out of for(;;) loop");
111 return 0; /* unreachable */
112}
113
114int kf_compress(char *infile, char *outfile)
115{
116 FILE *ifp = fopen(infile, "r");
117 if (!ifp)
118 {
119 KF_THROW("failed to open input file: %s", infile);
120 return 0; /* unreachable */
121 }
122 FILE *ofp = fopen(outfile, "w");
123 if (!ofp)
124 {
125 fclose(ifp);
126 KF_THROW("failed to open output file: %s", outfile);
127 return 0; /* unreachable */
128 }
129
130 lzma_stream s = LZMA_STREAM_INIT;
131 lzma_ret r = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
132 if (r != LZMA_OK)
133 {
134 KF_THROW("failed to initialize lzma encoder: code=%d\n", r);
135 return 0; /* unreachable */
136 }
137
138 int res = _kf_compress(&s, ifp, ofp);
139
140 lzma_end(&s);
141 fclose(ifp);
142 fclose(ofp);
143
144 return res;
145}
146
147int kf_decompress(char *infile, char *outfile)
148{
149 FILE *ifp = fopen(infile, "r");
150 if (!ifp)
151 {
152 KF_THROW("failed to open input file: %s", infile);
153 return 0; /* unreachable */
154 }
155 FILE *ofp = fopen(outfile, "w");
156 if (!ofp)
157 {
158 fclose(ifp);
159 KF_THROW("failed to open output file: %s", outfile);
160 return 0; /* unreachable */
161 }
162
163 lzma_stream s = LZMA_STREAM_INIT;
164 lzma_ret r = lzma_stream_decoder(&s, UINT64_MAX, LZMA_CONCATENATED);
165 if (r != LZMA_OK)
166 {
167 KF_THROW("failed to initialize lzma decoder: code=%d\n", r);
168 return 0; /* unreachable */
169 }
170
171 int res = _kf_compress(&s, ifp, ofp);
172
173 lzma_end(&s);
174 fclose(ifp);
175 fclose(ofp);
176
177 return res;
178}