1 /*
2 * This software is licensed under the terms of the MIT License.
3 * See COPYING for further information.
4 * ---
5 * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6 * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7 */
8
9 #include "taisei.h"
10
11 #include "rwops_autobuf.h"
12 #include "rwops_segment.h"
13
14 #define BUFFER(rw) ((Buffer*)((rw)->hidden.unknown.data1))
15
16 typedef struct Buffer {
17 SDL_RWops *memrw;
18 void *data;
19 void **ptr;
20 size_t size;
21 } Buffer;
22
auto_realloc(Buffer * b,size_t newsize)23 static void auto_realloc(Buffer *b, size_t newsize) {
24 size_t pos = SDL_RWtell(b->memrw);
25 SDL_RWclose(b->memrw);
26
27 b->size = newsize;
28 b->data = realloc(b->data, b->size);
29 b->memrw = SDL_RWFromMem(b->data, b->size);
30
31 if(b->ptr) {
32 *b->ptr = b->data;
33 }
34
35 if(pos > 0) {
36 SDL_RWseek(b->memrw, pos, RW_SEEK_SET);
37 }
38 }
39
auto_close(SDL_RWops * rw)40 static int auto_close(SDL_RWops *rw) {
41 if(rw) {
42 Buffer *b = BUFFER(rw);
43 SDL_RWclose(b->memrw);
44 free(b->data);
45 free(b);
46 SDL_FreeRW(rw);
47 }
48
49 return 0;
50 }
51
auto_seek(SDL_RWops * rw,int64_t offset,int whence)52 static int64_t auto_seek(SDL_RWops *rw, int64_t offset, int whence) {
53 return SDL_RWseek(BUFFER(rw)->memrw, offset, whence);
54 }
55
auto_size(SDL_RWops * rw)56 static int64_t auto_size(SDL_RWops *rw) {
57 // return SDL_RWsize(BUFFER(rw)->memrw);
58 return BUFFER(rw)->size;
59 }
60
auto_read(SDL_RWops * rw,void * ptr,size_t size,size_t maxnum)61 static size_t auto_read(SDL_RWops *rw, void *ptr, size_t size, size_t maxnum) {
62 return SDL_RWread(BUFFER(rw)->memrw, ptr, size, maxnum);
63 }
64
auto_write(SDL_RWops * rw,const void * ptr,size_t size,size_t maxnum)65 static size_t auto_write(SDL_RWops *rw, const void *ptr, size_t size, size_t maxnum) {
66 Buffer *b = BUFFER(rw);
67 size_t newsize = b->size;
68
69 while(size * maxnum > newsize - SDL_RWtell(rw)) {
70 newsize *= 2;
71 }
72
73 if(newsize > b->size) {
74 auto_realloc(b, newsize);
75 }
76
77 return SDL_RWwrite(BUFFER(rw)->memrw, ptr, size, maxnum);
78 }
79
SDL_RWAutoBuffer(void ** ptr,size_t initsize)80 SDL_RWops* SDL_RWAutoBuffer(void **ptr, size_t initsize) {
81 SDL_RWops *rw = SDL_AllocRW();
82
83 if(!rw) {
84 return NULL;
85 }
86
87 rw->type = SDL_RWOPS_UNKNOWN;
88 rw->seek = auto_seek;
89 rw->size = auto_size;
90 rw->read = auto_read;
91 rw->write = auto_write;
92 rw->close = auto_close;
93
94 Buffer *b = calloc(1, sizeof(Buffer));
95
96 b->size = initsize;
97 b->data = malloc(b->size);
98 b->ptr = ptr;
99 b->memrw = SDL_RWFromMem(b->data, b->size);
100
101 if(ptr) {
102 *ptr = b->data;
103 }
104
105 rw->hidden.unknown.data1 = b;
106
107 return rw;
108 }
109
SDL_RWCopyToBuffer(SDL_RWops * src)110 SDL_RWops* SDL_RWCopyToBuffer(SDL_RWops *src) {
111 uint8_t buf[4096] = {0};
112 ssize_t len;
113 SDL_RWops *abufrw = SDL_RWAutoBuffer(NULL, 4096);
114
115 while((len = SDL_RWread(src, buf, 1, sizeof(buf))) > 0) {
116 SDL_RWwrite(abufrw, buf, 1, len);
117 }
118
119 size_t datasize = SDL_RWtell(abufrw);
120 SDL_RWseek(abufrw, 0, RW_SEEK_SET);
121 abufrw = SDL_RWWrapSegment(abufrw, 0, datasize, true);
122
123 return abufrw;
124 }
125