1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * File I/O routines.
12 *
13 * See LICENSE.txt for copyright information.
14 */
15
16
17 #include "allegro5/allegro.h"
18 #include "allegro5/internal/aintern.h"
19 #include "allegro5/internal/aintern_file.h"
20
21
22 /* Function: al_fopen
23 */
al_fopen(const char * path,const char * mode)24 ALLEGRO_FILE *al_fopen(const char *path, const char *mode)
25 {
26 return al_fopen_interface(al_get_new_file_interface(), path, mode);
27 }
28
29
30 /* Function: al_fopen_interface
31 */
al_fopen_interface(const ALLEGRO_FILE_INTERFACE * drv,const char * path,const char * mode)32 ALLEGRO_FILE *al_fopen_interface(const ALLEGRO_FILE_INTERFACE *drv,
33 const char *path, const char *mode)
34 {
35 ALLEGRO_FILE *f = NULL;
36
37 ASSERT(drv);
38 ASSERT(path);
39 ASSERT(mode);
40
41 if (drv->fi_fopen) {
42 f = al_malloc(sizeof(*f));
43 if (!f) {
44 al_set_errno(ENOMEM);
45 }
46 else {
47 f->vtable = drv;
48 f->userdata = drv->fi_fopen(path, mode);
49 f->ungetc_len = 0;
50 if (!f->userdata) {
51 al_free(f);
52 f = NULL;
53 }
54 }
55 }
56
57 return f;
58 }
59
60
61 /* Function: al_create_file_handle
62 */
al_create_file_handle(const ALLEGRO_FILE_INTERFACE * drv,void * userdata)63 ALLEGRO_FILE *al_create_file_handle(const ALLEGRO_FILE_INTERFACE *drv,
64 void *userdata)
65 {
66 ALLEGRO_FILE *f;
67
68 ASSERT(drv);
69
70 f = al_malloc(sizeof(*f));
71 if (!f) {
72 al_set_errno(ENOMEM);
73 }
74 else {
75 f->vtable = drv;
76 f->userdata = userdata;
77 f->ungetc_len = 0;
78 }
79
80 return f;
81 }
82
83
84 /* Function: al_fclose
85 */
al_fclose(ALLEGRO_FILE * f)86 bool al_fclose(ALLEGRO_FILE *f)
87 {
88 if (f) {
89 bool ret = f->vtable->fi_fclose(f);
90 al_free(f);
91 return ret;
92 }
93
94 al_set_errno(EINVAL);
95 return false;
96 }
97
98
99 /* Function: al_fread
100 */
al_fread(ALLEGRO_FILE * f,void * ptr,size_t size)101 size_t al_fread(ALLEGRO_FILE *f, void *ptr, size_t size)
102 {
103 ASSERT(f);
104 ASSERT(ptr || size == 0);
105
106 if (f->ungetc_len) {
107 int bytes_ungetc = 0;
108 unsigned char *cptr = ptr;
109
110 while (f->ungetc_len > 0 && size > 0) {
111 *cptr++ = f->ungetc[--f->ungetc_len];
112 ++bytes_ungetc;
113 --size;
114 }
115
116 return bytes_ungetc + f->vtable->fi_fread(f, cptr, size);
117 }
118 else {
119 return f->vtable->fi_fread(f, ptr, size);
120 }
121 }
122
123
124 /* Function: al_fwrite
125 */
al_fwrite(ALLEGRO_FILE * f,const void * ptr,size_t size)126 size_t al_fwrite(ALLEGRO_FILE *f, const void *ptr, size_t size)
127 {
128 ASSERT(f);
129 ASSERT(ptr || size == 0);
130
131 f->ungetc_len = 0;
132 return f->vtable->fi_fwrite(f, ptr, size);
133 }
134
135
136 /* Function: al_fflush
137 */
al_fflush(ALLEGRO_FILE * f)138 bool al_fflush(ALLEGRO_FILE *f)
139 {
140 ASSERT(f);
141
142 return f->vtable->fi_fflush(f);
143 }
144
145
146 /* Function: al_ftell
147 */
al_ftell(ALLEGRO_FILE * f)148 int64_t al_ftell(ALLEGRO_FILE *f)
149 {
150 ASSERT(f);
151
152 return f->vtable->fi_ftell(f) - f->ungetc_len;
153 }
154
155
156 /* Function: al_fseek
157 */
al_fseek(ALLEGRO_FILE * f,int64_t offset,int whence)158 bool al_fseek(ALLEGRO_FILE *f, int64_t offset, int whence)
159 {
160 ASSERT(f);
161 /* offset can be negative */
162 ASSERT(
163 whence == ALLEGRO_SEEK_SET ||
164 whence == ALLEGRO_SEEK_CUR ||
165 whence == ALLEGRO_SEEK_END
166 );
167
168 if (f->ungetc_len) {
169 if (whence == ALLEGRO_SEEK_CUR) {
170 offset -= f->ungetc_len;
171 }
172 f->ungetc_len = 0;
173 }
174
175 return f->vtable->fi_fseek(f, offset, whence);
176 }
177
178
179 /* Function: al_feof
180 */
al_feof(ALLEGRO_FILE * f)181 bool al_feof(ALLEGRO_FILE *f)
182 {
183 ASSERT(f);
184
185 return f->ungetc_len == 0 && f->vtable->fi_feof(f);
186 }
187
188
189 /* Function: al_ferror
190 */
al_ferror(ALLEGRO_FILE * f)191 int al_ferror(ALLEGRO_FILE *f)
192 {
193 ASSERT(f);
194
195 return f->vtable->fi_ferror(f);
196 }
197
198
199 /* Function: al_ferrmsg
200 */
al_ferrmsg(ALLEGRO_FILE * f)201 const char *al_ferrmsg(ALLEGRO_FILE *f)
202 {
203 const char *msg;
204
205 ASSERT(f);
206 msg = f->vtable->fi_ferrmsg(f);
207 ASSERT(msg);
208 return msg;
209 }
210
211
212 /* Function: al_fclearerr
213 */
al_fclearerr(ALLEGRO_FILE * f)214 void al_fclearerr(ALLEGRO_FILE *f)
215 {
216 ASSERT(f);
217
218 f->vtable->fi_fclearerr(f);
219 }
220
221
222 /* Function: al_fgetc
223 */
al_fgetc(ALLEGRO_FILE * f)224 int al_fgetc(ALLEGRO_FILE *f)
225 {
226 uint8_t c;
227 ASSERT(f);
228
229 if (al_fread(f, &c, 1) != 1) {
230 return EOF;
231 }
232
233 return c;
234 }
235
236
237 /* Function: al_fputc
238 */
al_fputc(ALLEGRO_FILE * f,int c)239 int al_fputc(ALLEGRO_FILE *f, int c)
240 {
241 uint8_t b = (c & 0xff);
242 ASSERT(f);
243
244 if (al_fwrite(f, &b, 1) != 1) {
245 return EOF;
246 }
247
248 return b;
249 }
250
251
252 /* Function: al_fread16le
253 */
al_fread16le(ALLEGRO_FILE * f)254 int16_t al_fread16le(ALLEGRO_FILE *f)
255 {
256 unsigned char b[2];
257 ASSERT(f);
258
259 if (al_fread(f, b, 2) == 2) {
260 return (((int16_t)b[1] << 8) | (int16_t)b[0]);
261 }
262
263 return EOF;
264 }
265
266
267 /* Function: al_fread32le
268 */
al_fread32le(ALLEGRO_FILE * f)269 int32_t al_fread32le(ALLEGRO_FILE *f)
270 {
271 unsigned char b[4];
272 ASSERT(f);
273
274 if (al_fread(f, b, 4) == 4) {
275 return (((int32_t)b[3] << 24) | ((int32_t)b[2] << 16) |
276 ((int32_t)b[1] << 8) | (int32_t)b[0]);
277 }
278
279 return EOF;
280 }
281
282
283 /* Function: al_fwrite16le
284 */
al_fwrite16le(ALLEGRO_FILE * f,int16_t w)285 size_t al_fwrite16le(ALLEGRO_FILE *f, int16_t w)
286 {
287 uint8_t b1, b2;
288 ASSERT(f);
289
290 b1 = (w & 0xFF00) >> 8;
291 b2 = w & 0x00FF;
292
293 if (al_fputc(f, b2) == b2) {
294 if (al_fputc(f, b1) == b1) {
295 return 2;
296 }
297 return 1;
298 }
299 return 0;
300 }
301
302
303 /* Function: al_fwrite32le
304 */
al_fwrite32le(ALLEGRO_FILE * f,int32_t l)305 size_t al_fwrite32le(ALLEGRO_FILE *f, int32_t l)
306 {
307 uint8_t b1, b2, b3, b4;
308 ASSERT(f);
309
310 b1 = ((l & 0xFF000000L) >> 24);
311 b2 = ((l & 0x00FF0000L) >> 16);
312 b3 = ((l & 0x0000FF00L) >> 8);
313 b4 = l & 0x00FF;
314
315 if (al_fputc(f, b4) == b4) {
316 if (al_fputc(f, b3) == b3) {
317 if (al_fputc(f, b2) == b2) {
318 if (al_fputc(f, b1) == b1) {
319 return 4;
320 }
321 return 3;
322 }
323 return 2;
324 }
325 return 1;
326 }
327 return 0;
328 }
329
330
331 /* Function: al_fread16be
332 */
al_fread16be(ALLEGRO_FILE * f)333 int16_t al_fread16be(ALLEGRO_FILE *f)
334 {
335 unsigned char b[2];
336 ASSERT(f);
337
338 if (al_fread(f, b, 2) == 2) {
339 return (((int16_t)b[0] << 8) | (int16_t)b[1]);
340 }
341
342 return EOF;
343 }
344
345
346 /* Function: al_fread32be
347 */
al_fread32be(ALLEGRO_FILE * f)348 int32_t al_fread32be(ALLEGRO_FILE *f)
349 {
350 unsigned char b[4];
351 ASSERT(f);
352
353 if (al_fread(f, b, 4) == 4) {
354 return (((int32_t)b[0] << 24) | ((int32_t)b[1] << 16) |
355 ((int32_t)b[2] << 8) | (int32_t)b[3]);
356 }
357
358 return EOF;
359 }
360
361
362 /* Function: al_fwrite16be
363 */
al_fwrite16be(ALLEGRO_FILE * f,int16_t w)364 size_t al_fwrite16be(ALLEGRO_FILE *f, int16_t w)
365 {
366 uint8_t b1, b2;
367 ASSERT(f);
368
369 b1 = (w & 0xFF00) >> 8;
370 b2 = w & 0x00FF;
371
372 if (al_fputc(f, b1) == b1) {
373 if (al_fputc(f, b2) == b2) {
374 return 2;
375 }
376 return 1;
377 }
378 return 0;
379 }
380
381
382 /* Function: al_fwrite32be
383 */
al_fwrite32be(ALLEGRO_FILE * f,int32_t l)384 size_t al_fwrite32be(ALLEGRO_FILE *f, int32_t l)
385 {
386 uint8_t b1, b2, b3, b4;
387 ASSERT(f);
388
389 b1 = ((l & 0xFF000000L) >> 24);
390 b2 = ((l & 0x00FF0000L) >> 16);
391 b3 = ((l & 0x0000FF00L) >> 8);
392 b4 = l & 0x00FF;
393
394 if (al_fputc(f, b1) == b1) {
395 if (al_fputc(f, b2) == b2) {
396 if (al_fputc(f, b3) == b3) {
397 if (al_fputc(f, b4) == b4) {
398 return 4;
399 }
400 return 3;
401 }
402 return 2;
403 }
404 return 1;
405 }
406 return 0;
407 }
408
409
410 /* Function: al_fgets
411 */
al_fgets(ALLEGRO_FILE * f,char * const buf,size_t max)412 char *al_fgets(ALLEGRO_FILE *f, char * const buf, size_t max)
413 {
414 char *p = buf;
415 int c;
416 ASSERT(f);
417 ASSERT(buf);
418
419 /* Handle silly cases. */
420 if (max == 0) {
421 return NULL;
422 }
423 if (max == 1) {
424 *buf = '\0';
425 return buf;
426 }
427
428 /* Return NULL if already at end of file. */
429 if ((c = al_fgetc(f)) == EOF) {
430 return NULL;
431 }
432
433 /* Fill buffer until empty, or we reach a newline or EOF or error. */
434 do {
435 *p++ = c;
436 max--;
437 if (max == 1 || c == '\n')
438 break;
439 c = al_fgetc(f);
440 } while (c != EOF);
441
442 /* Return NULL on error. */
443 if (c == EOF && al_ferror(f)) {
444 return NULL;
445 }
446
447 /* Add null terminator. */
448 ASSERT(max >= 1);
449 *p = '\0';
450
451 return buf;
452 }
453
454
455 /* Function: al_fget_ustr
456 */
al_fget_ustr(ALLEGRO_FILE * f)457 ALLEGRO_USTR *al_fget_ustr(ALLEGRO_FILE *f)
458 {
459 ALLEGRO_USTR *us;
460 char buf[128];
461
462 if (!al_fgets(f, buf, sizeof(buf))) {
463 return NULL;
464 }
465
466 us = al_ustr_new("");
467
468 do {
469 al_ustr_append_cstr(us, buf);
470 if (al_ustr_has_suffix_cstr(us, "\n"))
471 break;
472 } while (al_fgets(f, buf, sizeof(buf)));
473
474 return us;
475 }
476
477
478 /* Function: al_fputs
479 */
al_fputs(ALLEGRO_FILE * f,char const * p)480 int al_fputs(ALLEGRO_FILE *f, char const *p)
481 {
482 size_t n;
483 ASSERT(f);
484 ASSERT(p);
485
486 n = strlen(p);
487 if (al_fwrite(f, p, n) != n) {
488 return EOF;
489 }
490
491 return n;
492 }
493
494
495 /* Function: al_fungetc
496 */
al_fungetc(ALLEGRO_FILE * f,int c)497 int al_fungetc(ALLEGRO_FILE *f, int c)
498 {
499 ASSERT(f != NULL);
500
501 if (f->vtable->fi_fungetc) {
502 return f->vtable->fi_fungetc(f, c);
503 }
504 else {
505 /* If the interface does not provide an implementation for ungetc,
506 * then a default one will be used. (Note that if the interface does
507 * implement it, then this ungetc buffer will never be filled, and all
508 * other references to it within this file will always be ignored.)
509 */
510 if (f->ungetc_len == ALLEGRO_UNGETC_SIZE) {
511 return EOF;
512 }
513
514 f->ungetc[f->ungetc_len++] = (unsigned char) c;
515
516 return c;
517 }
518 }
519
520
521 /* Function: al_fsize
522 */
al_fsize(ALLEGRO_FILE * f)523 int64_t al_fsize(ALLEGRO_FILE *f)
524 {
525 ASSERT(f != NULL);
526
527 return f->vtable->fi_fsize(f);
528 }
529
530
531 /* Function: al_get_file_userdata
532 */
al_get_file_userdata(ALLEGRO_FILE * f)533 void *al_get_file_userdata(ALLEGRO_FILE *f)
534 {
535 ASSERT(f != NULL);
536
537 return f->userdata;
538 }
539
540
541 /* Function: al_vfprintf
542 */
al_vfprintf(ALLEGRO_FILE * pfile,const char * format,va_list args)543 int al_vfprintf(ALLEGRO_FILE *pfile, const char *format, va_list args)
544 {
545 int rv = -1;
546 ALLEGRO_USTR *ustr = 0;
547 size_t size = 0;
548 bool success;
549
550 if (pfile != 0 && format != 0)
551 {
552 ustr = al_ustr_new("");
553 if (ustr)
554 {
555 success = al_ustr_vappendf(ustr, format, args);
556 if (success)
557 {
558 size = al_ustr_size(ustr);
559 if (size > 0)
560 {
561 rv = al_fwrite(pfile, (const void*)(al_cstr(ustr)), size);
562 if (rv != (int)size) {
563 rv = -1;
564 }
565 }
566 }
567 al_ustr_free(ustr);
568 }
569 }
570 return rv;
571 }
572
573
574 /* Function: al_fprintf
575 */
al_fprintf(ALLEGRO_FILE * pfile,const char * format,...)576 int al_fprintf(ALLEGRO_FILE *pfile, const char *format, ...)
577 {
578 int rv = -1;
579 va_list args;
580
581 if (pfile != 0 && format != 0)
582 {
583 va_start(args, format);
584 rv = al_vfprintf(pfile, format, args);
585 va_end(args);
586 }
587 return rv;
588 }
589
590
591 /* vim: set sts=3 sw=3 et: */
592