content.h pt1
[voxelands-alt.git] / src / file.c
blob726b596c1a44db01e0c4e4c32752552918ea5ce8
1 /************************************************************************
2 * file.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "file.h"
21 #include "path.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <stdarg.h>
29 #define FILE_BUFF_STEP 1024
31 static int file_extend(file_t *file, int min)
33 return 0;
36 /* load a file into memory */
37 file_t *file_load(char* type, char *name)
39 file_t *ft;
40 FILE *f;
41 char* fn;
42 char* path;
44 if (type) {
45 fn = name;
46 path = path_get(type,name,1,NULL,0);
47 }else{
48 path = name;
49 fn = strrchr(name,'/');
50 if (!fn)
51 return NULL;
52 fn++;
55 f = fopen(path, "rb");
56 if (!f) {
57 free(path);
58 return NULL;
61 ft = malloc(sizeof(file_t));
62 if (!ft) {
63 free(path);
64 fclose(f);
65 return NULL;
68 ft->pos = 0;
69 ft->modified = 0;
71 fseek(f, 0, SEEK_END);
72 ft->len = ftell(f);
73 fseek(f, 0, SEEK_SET);
75 ft->size = ft->len+1;
77 ft->data = malloc(ft->size);
78 if (!ft->data) {
79 free(path);
80 fclose(f);
81 free(ft);
82 return NULL;
85 if (ft->len != fread(ft->data, 1, ft->len, f)) {
86 free(path);
87 fclose(f);
88 free(ft->data);
89 free(ft);
90 return NULL;
93 /* this lets us do string operations on text files */
94 ft->data[ft->len] = 0;
96 fclose(f);
98 ft->name = strdup(fn);
99 ft->path = path;
101 return ft;
104 /* load a file into memory */
105 file_t *file_create(char* type, char *name)
107 file_t *ft;
108 char* fn;
109 char* path;
111 if (name) {
112 if (type) {
113 fn = name;
114 path = path_get(type,name,0,NULL,0);
115 }else{
116 path = strdup(name);
117 fn = strrchr(name,'/');
118 if (!fn)
119 return NULL;
120 fn++;
122 }else{
123 fn = NULL;
124 path = NULL;
127 ft = malloc(sizeof(file_t));
128 if (!ft) {
129 free(path);
130 return NULL;
133 ft->pos = 0;
134 ft->len = 0;
135 ft->size = 0;
136 ft->modified = 0;
138 ft->data = NULL;
140 if (fn)
141 ft->name = strdup(fn);
142 ft->path = path;
144 return ft;
147 /* free a loaded file */
148 void file_free(file_t *file)
150 if (!file)
151 return;
153 if (file->data)
154 free(file->data);
156 if (file->name)
157 free(file->name);
159 free(file);
162 /* flush file data to disk */
163 void file_flush(file_t *file)
165 FILE *f;
166 if (!file || !file->modified || !file->path)
167 return;
169 if (!path_exists(file->path)) {
170 if (!path_create(NULL,file->path))
171 return;
174 f = fopen(file->path, "wb");
175 if (!f)
176 return;
178 if (file->len) {
179 if (fwrite(file->data,1,file->len,f) != file->len) {
180 fclose(f);
181 return;
185 fclose(f);
186 file->modified = 0;
189 /* find the next occurance of value from offset in file, return it's position
190 * relative to offset */
191 int file_find(file_t *file, int offset, unsigned char value)
193 int r;
194 if (!file)
195 return -1;
197 for (r=offset; r<file->len; r++) {
198 if (file->data[r] == value)
199 return (r-offset);
201 return -1;
204 /* find the next occurance of value from offset in file, return it's position
205 * relative to offset */
206 int file_strfind(file_t *file, int offset, char* value)
208 int r;
209 char* v;
210 if (!file || file->len <= offset)
211 return -1;
213 v = strstr((char*)(file->data+offset),value);
214 if (!v)
215 return -1;
217 r = (v-(char*)file->data);
218 if (r < 0)
219 return -1;
221 return (r-offset);
224 /* read from a file buffer to dst */
225 int file_read(file_t *file, void* dst, int size)
227 int len;
228 if (!file || !file->len)
229 return -1;
231 len = file->len - file->pos;
232 if (size < len) {
233 len = size;
236 if (len > 0) {
237 memcpy(dst, file->data+file->pos, len);
238 file->pos += len;
241 return len;
244 /* read a line from a file buffer to dst */
245 int file_readline(file_t *file, char* dst, int size)
247 int len;
248 char* b;
249 char* e;
250 if (!file || !file->len)
251 return -1;
253 b = (char*)(file->data+file->pos);
255 e = strchr(b,'\n');
256 if (e) {
257 len = (e-b);
258 file->pos += len+1;
259 }else{
260 len = strlen(b);
261 file->pos += len;
264 if (len >= size)
265 len = size-1;
267 memcpy(dst, b, len);
268 dst[len] = 0;
270 if (file->pos > file->len)
271 file->pos = file->len;
273 return len;
276 /* read integer from a file buffer */
277 int file_read_int(file_t *file)
279 int32_t r;
280 file_read(file,&r,4);
281 return r;
284 /* read short integer from a file buffer */
285 int16_t file_read_short(file_t *file)
287 int16_t r;
288 file_read(file,&r,2);
289 return r;
292 /* read char from a file buffer */
293 char file_read_char(file_t *file)
295 char r;
296 file_read(file,&r,1);
297 return r;
300 /* read unsigned integer from a file buffer */
301 uint32_t file_read_uint(file_t *file)
303 uint32_t r;
304 file_read(file,&r,4);
305 return r;
308 /* read float from a file buffer */
309 float file_read_float(file_t *file)
311 float r;
312 file_read(file,&r,4);
313 return r;
316 /* seek to a position in a file buffer */
317 int file_seek(file_t *file, int offset, int origin)
319 if (!file)
320 return -1;
322 switch (origin) {
323 case SEEK_SET:
324 if (file->len < offset)
325 offset = file->len;
327 file->pos = offset;
328 break;
329 case SEEK_CUR:
330 offset += file->pos;
331 if (file->len < offset)
332 offset = file->len;
334 file->pos = offset;
335 break;
336 case SEEK_END:
337 file->pos = file->len;
338 break;
339 default:;
342 if (file->pos < 0)
343 file->pos = 0;
345 return 0;
348 /* get the position in a file buffer */
349 int file_tell(file_t *file)
351 if (!file)
352 return -1;
354 return file->pos;
357 /* get the pointer to the current file position */
358 void *file_get(file_t *file)
360 return file->data+file->pos;
363 /* write data to a file buffer */
364 int file_write(file_t *file, void *buff, int size)
366 if (!file || !buff || size)
367 return -1;
369 if (file->size <= (file->pos+size)) {
370 if (file_extend(file,file->pos+size+1) < 0)
371 return 0;
374 if (!memcpy(file->data+file->pos,buff,size)) {
375 file->data[file->pos] = 0;
376 return 0;
379 file->pos += size;
380 file->data[file->pos] = 0;
382 return size;
385 /* write a formatted string to a file buffer (printf style) */
386 int file_writef(file_t *file, char* fmt, ...)
388 va_list ap;
389 int l;
390 int s;
391 if (!file)
392 return -1;
394 if (!file->size || !file->data) {
395 if (file_extend(file,FILE_BUFF_STEP) < 0)
396 return 0;
399 /* basically "keep trying till it all fits" */
400 while (1) {
401 va_start(ap, fmt);
402 s = (file->size-1)-file->pos;
403 l = vsnprintf((char*)(file->data+file->pos), s, fmt, ap);
404 va_end(ap);
405 if (l < s)
406 break;
407 if (file_extend(file,s+FILE_BUFF_STEP) < 0) {
408 if (file->data)
409 file->data[file->pos] = 0;
410 return 0;
414 file->pos += l;
415 file->data[file->pos] = 0;
417 return 0;