This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_rwops.c
660 lines (560 loc) · 17.3 KB
1
/*
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Simple DirectMedia Layer
Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
20
*/
21
#include "SDL_config.h"
22
23
24
25
26
/* This file provides a general interface for SDL to read and write
data sources. It can easily be extended to files, memory, etc.
*/
27
#include "SDL_endian.h"
28
#include "SDL_rwops.h"
29
30
#ifdef __APPLE__
31
#include "cocoa/SDL_rwopsbundlesupport.h"
32
33
#endif /* __APPLE__ */
34
35
36
37
#ifdef __NDS__
/* include libfat headers for fatInitDefault(). */
#include <fat.h>
#endif /* __NDS__ */
38
39
#ifdef __WIN32__
40
41
/* Functions to read/write Win32 API file pointers */
42
43
44
/* Will not use it on WinCE because stdio is buffered, it means
faster, and all stdio functions anyway are embedded in coredll.dll -
the main wince dll*/
45
46
#include "../core/windows/SDL_windows.h"
47
48
49
50
51
#ifndef INVALID_SET_FILE_POINTER
#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
#endif
52
53
#define READAHEAD_BUFFER_SIZE 1024
54
static int SDLCALL
55
windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
56
57
{
#ifndef _WIN32_WCE
58
UINT old_error_mode;
59
#endif
60
61
62
63
64
65
HANDLE h;
DWORD r_right, w_right;
DWORD must_exist, truncate;
int a_mode;
if (!context)
66
return -1; /* failed (invalid call) */
67
68
69
70
71
context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */
context->hidden.windowsio.buffer.data = NULL;
context->hidden.windowsio.buffer.size = 0;
context->hidden.windowsio.buffer.left = 0;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* "r" = reading, file must exist */
/* "w" = writing, truncate existing, file may not exist */
/* "r+"= reading or writing, file must exist */
/* "a" = writing, append file may not exist */
/* "a+"= append + read, file may not exist */
/* "w+" = read, write, truncate. file may not exist */
must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
r_right = (SDL_strchr(mode, '+') != NULL
|| must_exist) ? GENERIC_READ : 0;
a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
w_right = (a_mode || SDL_strchr(mode, '+')
|| truncate) ? GENERIC_WRITE : 0;
if (!r_right && !w_right) /* inconsistent mode */
return -1; /* failed (invalid call) */
90
91
context->hidden.windowsio.buffer.data =
92
(char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
93
if (!context->hidden.windowsio.buffer.data) {
94
95
96
SDL_OutOfMemory();
return -1;
}
97
#ifdef _WIN32_WCE
98
{
99
100
LPTSTR tstr = WIN_UTF8ToString(filename);
h = CreateFile(tstr, (w_right | r_right),
101
102
103
(w_right) ? 0 : FILE_SHARE_READ, NULL,
(must_exist | truncate | a_mode),
FILE_ATTRIBUTE_NORMAL, NULL);
104
SDL_free(tstr);
105
}
106
#else
107
108
109
/* Do not open a dialog box if failure */
old_error_mode =
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
110
111
112
113
114
115
116
117
118
{
LPTSTR tstr = WIN_UTF8ToString(filename);
h = CreateFile(tstr, (w_right | r_right),
(w_right) ? 0 : FILE_SHARE_READ, NULL,
(must_exist | truncate | a_mode),
FILE_ATTRIBUTE_NORMAL, NULL);
SDL_free(tstr);
}
119
120
/* restore old behavior */
121
SetErrorMode(old_error_mode);
122
#endif /* _WIN32_WCE */
123
124
if (h == INVALID_HANDLE_VALUE) {
125
126
SDL_free(context->hidden.windowsio.buffer.data);
context->hidden.windowsio.buffer.data = NULL;
127
128
129
SDL_SetError("Couldn't open %s", filename);
return -2; /* failed (CreateFile) */
}
130
131
context->hidden.windowsio.h = h;
context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
132
133
return 0; /* ok */
134
}
135
136
static long SDLCALL
137
windows_file_seek(SDL_RWops * context, long offset, int whence)
138
{
139
DWORD windowswhence;
140
long file_pos;
141
142
143
if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
SDL_SetError("windows_file_seek: invalid context/file not opened");
144
145
return -1;
}
146
147
/* FIXME: We may be able to satisfy the seek within buffered data */
148
149
if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
offset -= (long)context->hidden.windowsio.buffer.left;
150
}
151
context->hidden.windowsio.buffer.left = 0;
152
153
154
switch (whence) {
case RW_SEEK_SET:
155
windowswhence = FILE_BEGIN;
156
157
break;
case RW_SEEK_CUR:
158
windowswhence = FILE_CURRENT;
159
160
break;
case RW_SEEK_END:
161
windowswhence = FILE_END;
162
163
break;
default:
164
SDL_SetError("windows_file_seek: Unknown value for 'whence'");
165
166
return -1;
}
167
168
file_pos =
169
SetFilePointer(context->hidden.windowsio.h, offset, NULL, windowswhence);
170
171
172
if (file_pos != INVALID_SET_FILE_POINTER)
return file_pos; /* success */
173
174
175
SDL_Error(SDL_EFSEEK);
return -1; /* error */
176
}
177
178
static size_t SDLCALL
179
windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
180
{
181
182
183
size_t total_need;
size_t total_read = 0;
size_t read_ahead;
184
DWORD byte_read;
185
186
total_need = size * maxnum;
187
188
if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
189
|| !total_need)
190
191
return 0;
192
193
194
195
if (context->hidden.windowsio.buffer.left > 0) {
void *data = (char *) context->hidden.windowsio.buffer.data +
context->hidden.windowsio.buffer.size -
context->hidden.windowsio.buffer.left;
196
read_ahead =
197
SDL_min(total_need, context->hidden.windowsio.buffer.left);
198
SDL_memcpy(ptr, data, read_ahead);
199
context->hidden.windowsio.buffer.left -= read_ahead;
200
201
202
203
204
205
206
if (read_ahead == total_need) {
return maxnum;
}
ptr = (char *) ptr + read_ahead;
total_need -= read_ahead;
total_read += read_ahead;
207
}
208
209
210
if (total_need < READAHEAD_BUFFER_SIZE) {
if (!ReadFile
211
(context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
212
213
214
215
216
READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
SDL_Error(SDL_EFREAD);
return 0;
}
read_ahead = SDL_min(total_need, (int) byte_read);
217
218
219
SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
context->hidden.windowsio.buffer.size = byte_read;
context->hidden.windowsio.buffer.left = byte_read - read_ahead;
220
221
222
total_read += read_ahead;
} else {
if (!ReadFile
223
(context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
224
225
226
227
228
229
SDL_Error(SDL_EFREAD);
return 0;
}
total_read += byte_read;
}
return (total_read / size);
230
}
231
232
static size_t SDLCALL
233
windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
234
size_t num)
235
{
236
237
size_t total_bytes;
238
239
DWORD byte_written;
size_t nwritten;
240
241
242
total_bytes = size * num;
243
if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
244
245
246
|| total_bytes <= 0 || !size)
return 0;
247
248
249
if (context->hidden.windowsio.buffer.left) {
SetFilePointer(context->hidden.windowsio.h,
-(LONG)context->hidden.windowsio.buffer.left, NULL,
250
FILE_CURRENT);
251
context->hidden.windowsio.buffer.left = 0;
252
253
}
254
/* if in append mode, we must go to the EOF before write */
255
256
if (context->hidden.windowsio.append) {
if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
257
INVALID_SET_FILE_POINTER) {
258
259
260
261
SDL_Error(SDL_EFWRITE);
return 0;
}
}
262
263
if (!WriteFile
264
(context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
265
266
267
268
269
270
SDL_Error(SDL_EFWRITE);
return 0;
}
nwritten = byte_written / size;
return nwritten;
271
}
272
273
static int SDLCALL
274
windows_file_close(SDL_RWops * context)
275
276
{
277
if (context) {
278
279
280
if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
CloseHandle(context->hidden.windowsio.h);
context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */
281
}
282
283
284
if (context->hidden.windowsio.buffer.data) {
SDL_free(context->hidden.windowsio.buffer.data);
context->hidden.windowsio.buffer.data = NULL;
285
}
286
287
288
289
SDL_FreeRW(context);
}
return (0);
}
290
#endif /* __WIN32__ */
291
292
#ifdef HAVE_STDIO_H
293
294
/* Functions to read/write stdio file pointers */
295
296
297
static long SDLCALL
stdio_seek(SDL_RWops * context, long offset, int whence)
298
299
300
301
302
303
304
{
if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
return (ftell(context->hidden.stdio.fp));
} else {
SDL_Error(SDL_EFSEEK);
return (-1);
}
305
}
306
307
308
static size_t SDLCALL
stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
309
{
310
311
312
313
314
315
316
size_t nread;
nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
if (nread == 0 && ferror(context->hidden.stdio.fp)) {
SDL_Error(SDL_EFREAD);
}
return (nread);
317
}
318
319
320
static size_t SDLCALL
stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
321
{
322
323
324
325
326
327
328
size_t nwrote;
nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
SDL_Error(SDL_EFWRITE);
}
return (nwrote);
329
}
330
331
332
static int SDLCALL
stdio_close(SDL_RWops * context)
333
{
334
int status = 0;
335
336
337
if (context) {
if (context->hidden.stdio.autoclose) {
/* WARNING: Check the return value here! */
338
339
340
341
if (fclose(context->hidden.stdio.fp) != 0) {
SDL_Error(SDL_EFWRITE);
status = -1;
}
342
343
344
}
SDL_FreeRW(context);
}
345
return status;
346
347
348
349
350
}
#endif /* !HAVE_STDIO_H */
/* Functions to read/write memory pointers */
351
352
static long SDLCALL
mem_seek(SDL_RWops * context, long offset, int whence)
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
{
Uint8 *newpos;
switch (whence) {
case RW_SEEK_SET:
newpos = context->hidden.mem.base + offset;
break;
case RW_SEEK_CUR:
newpos = context->hidden.mem.here + offset;
break;
case RW_SEEK_END:
newpos = context->hidden.mem.stop + offset;
break;
default:
SDL_SetError("Unknown value for 'whence'");
return (-1);
}
if (newpos < context->hidden.mem.base) {
newpos = context->hidden.mem.base;
}
if (newpos > context->hidden.mem.stop) {
newpos = context->hidden.mem.stop;
}
context->hidden.mem.here = newpos;
377
return (long)(context->hidden.mem.here - context->hidden.mem.base);
378
}
379
380
381
static size_t SDLCALL
mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
{
size_t total_bytes;
size_t mem_available;
total_bytes = (maxnum * size);
if ((maxnum <= 0) || (size <= 0)
|| ((total_bytes / maxnum) != (size_t) size)) {
return 0;
}
mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
if (total_bytes > mem_available) {
total_bytes = mem_available;
}
SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
context->hidden.mem.here += total_bytes;
return (total_bytes / size);
}
402
403
404
static size_t SDLCALL
mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
405
406
407
408
409
410
411
412
{
if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
}
SDL_memcpy(context->hidden.mem.here, ptr, num * size);
context->hidden.mem.here += num * size;
return (num);
}
413
414
415
static size_t SDLCALL
mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
416
417
418
419
{
SDL_SetError("Can't write to read-only memory");
return (-1);
}
420
421
422
423
424
425
426
427
static int SDLCALL
mem_close(SDL_RWops * context)
{
if (context) {
SDL_FreeRW(context);
}
return (0);
428
429
}
430
431
432
/* Functions to create SDL_RWops structures from various data sources */
433
434
SDL_RWops *
SDL_RWFromFile(const char *file, const char *mode)
435
{
436
SDL_RWops *rwops = NULL;
437
#ifdef HAVE_STDIO_H
438
FILE *fp = NULL;
439
#endif
440
441
442
443
if (!file || !*file || !mode || !*mode) {
SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
return NULL;
}
444
#if defined(__WIN32__)
445
446
447
rwops = SDL_AllocRW();
if (!rwops)
return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
448
if (windows_file_open(rwops, file, mode) < 0) {
449
450
451
SDL_FreeRW(rwops);
return NULL;
}
452
453
454
455
rwops->seek = windows_file_seek;
rwops->read = windows_file_read;
rwops->write = windows_file_write;
rwops->close = windows_file_close;
456
457
#elif HAVE_STDIO_H
458
459
460
461
462
463
#ifdef __APPLE__
fp = SDL_OpenFPFromBundleOrFallback(file, mode);
#else
fp = fopen(file, mode);
#endif
if (fp == NULL) {
464
465
466
467
SDL_SetError("Couldn't open %s", file);
} else {
rwops = SDL_RWFromFP(fp, 1);
}
468
#else
469
SDL_SetError("SDL not compiled with stdio support");
470
#endif /* !HAVE_STDIO_H */
471
472
return (rwops);
473
474
}
475
#ifdef HAVE_STDIO_H
476
SDL_RWops *
477
SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
478
479
480
{
SDL_RWops *rwops = NULL;
481
482
483
484
485
486
487
#if 0
/*#ifdef __NDS__*/
/* set it up so we can use stdio file function */
fatInitDefault();
printf("called fatInitDefault()");
#endif /* __NDS__ */
488
489
490
491
492
493
494
495
496
497
rwops = SDL_AllocRW();
if (rwops != NULL) {
rwops->seek = stdio_seek;
rwops->read = stdio_read;
rwops->write = stdio_write;
rwops->close = stdio_close;
rwops->hidden.stdio.fp = fp;
rwops->hidden.stdio.autoclose = autoclose;
}
return (rwops);
498
}
499
500
501
502
503
504
505
#else
SDL_RWops *
SDL_RWFromFP(void * fp, SDL_bool autoclose)
{
SDL_SetError("SDL not compiled with stdio support");
return NULL;
}
506
#endif /* HAVE_STDIO_H */
507
508
509
SDL_RWops *
SDL_RWFromMem(void *mem, int size)
510
{
511
SDL_RWops *rwops;
512
513
514
515
516
517
518
519
520
521
522
523
rwops = SDL_AllocRW();
if (rwops != NULL) {
rwops->seek = mem_seek;
rwops->read = mem_read;
rwops->write = mem_write;
rwops->close = mem_close;
rwops->hidden.mem.base = (Uint8 *) mem;
rwops->hidden.mem.here = rwops->hidden.mem.base;
rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
}
return (rwops);
524
525
}
526
527
SDL_RWops *
SDL_RWFromConstMem(const void *mem, int size)
528
{
529
SDL_RWops *rwops;
530
531
532
533
534
535
536
537
538
539
540
541
rwops = SDL_AllocRW();
if (rwops != NULL) {
rwops->seek = mem_seek;
rwops->read = mem_read;
rwops->write = mem_writeconst;
rwops->close = mem_close;
rwops->hidden.mem.base = (Uint8 *) mem;
rwops->hidden.mem.here = rwops->hidden.mem.base;
rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
}
return (rwops);
542
543
}
544
545
SDL_RWops *
SDL_AllocRW(void)
546
{
547
SDL_RWops *area;
548
549
550
551
552
553
area = (SDL_RWops *) SDL_malloc(sizeof *area);
if (area == NULL) {
SDL_OutOfMemory();
}
return (area);
554
555
}
556
557
void
SDL_FreeRW(SDL_RWops * area)
558
{
559
SDL_free(area);
560
}
561
562
563
/* Functions for dynamically reading and writing endian-specific values */
564
565
Uint16
SDL_ReadLE16(SDL_RWops * src)
566
{
567
Uint16 value;
568
569
570
SDL_RWread(src, &value, (sizeof value), 1);
return (SDL_SwapLE16(value));
571
}
572
573
574
Uint16
SDL_ReadBE16(SDL_RWops * src)
575
{
576
Uint16 value;
577
578
579
SDL_RWread(src, &value, (sizeof value), 1);
return (SDL_SwapBE16(value));
580
}
581
582
583
Uint32
SDL_ReadLE32(SDL_RWops * src)
584
{
585
Uint32 value;
586
587
588
SDL_RWread(src, &value, (sizeof value), 1);
return (SDL_SwapLE32(value));
589
}
590
591
592
Uint32
SDL_ReadBE32(SDL_RWops * src)
593
{
594
Uint32 value;
595
596
597
SDL_RWread(src, &value, (sizeof value), 1);
return (SDL_SwapBE32(value));
598
}
599
600
601
Uint64
SDL_ReadLE64(SDL_RWops * src)
602
{
603
Uint64 value;
604
605
606
SDL_RWread(src, &value, (sizeof value), 1);
return (SDL_SwapLE64(value));
607
}
608
609
610
Uint64
SDL_ReadBE64(SDL_RWops * src)
611
{
612
Uint64 value;
613
614
615
SDL_RWread(src, &value, (sizeof value), 1);
return (SDL_SwapBE64(value));
616
617
}
618
size_t
619
SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
620
{
621
622
value = SDL_SwapLE16(value);
return (SDL_RWwrite(dst, &value, (sizeof value), 1));
623
}
624
625
size_t
626
SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
627
{
628
629
value = SDL_SwapBE16(value);
return (SDL_RWwrite(dst, &value, (sizeof value), 1));
630
}
631
632
size_t
633
SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
634
{
635
636
value = SDL_SwapLE32(value);
return (SDL_RWwrite(dst, &value, (sizeof value), 1));
637
}
638
639
size_t
640
SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
641
{
642
643
value = SDL_SwapBE32(value);
return (SDL_RWwrite(dst, &value, (sizeof value), 1));
644
}
645
646
size_t
647
SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
648
{
649
650
value = SDL_SwapLE64(value);
return (SDL_RWwrite(dst, &value, (sizeof value), 1));
651
}
652
653
size_t
654
SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
655
{
656
657
value = SDL_SwapBE64(value);
return (SDL_RWwrite(dst, &value, (sizeof value), 1));
658
}
659
660
/* vi: set ts=4 sw=4 expandtab: */