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