1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // Emulates the IO functions in C stdio.h reading and writing to
16 // memory.
17 //
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "memio.h"
24 
25 #include "z_zone.h"
26 
27 typedef enum {
28 	MODE_READ,
29 	MODE_WRITE,
30 } memfile_mode_t;
31 
32 struct _MEMFILE {
33 	unsigned char *buf;
34 	size_t buflen;
35 	size_t alloced;
36 	unsigned int position;
37 	memfile_mode_t mode;
38 };
39 
40 // Open a memory area for reading
41 
mem_fopen_read(void * buf,size_t buflen)42 MEMFILE *mem_fopen_read(void *buf, size_t buflen)
43 {
44 	MEMFILE *file;
45 
46 	file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
47 
48 	file->buf = (unsigned char *) buf;
49 	file->buflen = buflen;
50 	file->position = 0;
51 	file->mode = MODE_READ;
52 
53 	return file;
54 }
55 
56 // Read bytes
57 
mem_fread(void * buf,size_t size,size_t nmemb,MEMFILE * stream)58 size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream)
59 {
60 	size_t items;
61 
62 	if (stream->mode != MODE_READ)
63 	{
64 		printf("not a read stream\n");
65 		return -1;
66 	}
67 
68 	// Trying to read more bytes than we have left?
69 
70 	items = nmemb;
71 
72 	if (items * size > stream->buflen - stream->position)
73 	{
74 		items = (stream->buflen - stream->position) / size;
75 	}
76 
77 	// Copy bytes to buffer
78 
79 	memcpy(buf, stream->buf + stream->position, items * size);
80 
81 	// Update position
82 
83 	stream->position += items * size;
84 
85 	return items;
86 }
87 
88 // Open a memory area for writing
89 
mem_fopen_write(void)90 MEMFILE *mem_fopen_write(void)
91 {
92 	MEMFILE *file;
93 
94 	file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
95 
96 	file->alloced = 1024;
97 	file->buf = Z_Malloc(file->alloced, PU_STATIC, 0);
98 	file->buflen = 0;
99 	file->position = 0;
100 	file->mode = MODE_WRITE;
101 
102 	return file;
103 }
104 
105 // Write bytes to stream
106 
mem_fwrite(const void * ptr,size_t size,size_t nmemb,MEMFILE * stream)107 size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream)
108 {
109 	size_t bytes;
110 
111 	if (stream->mode != MODE_WRITE)
112 	{
113 		return -1;
114 	}
115 
116 	// More bytes than can fit in the buffer?
117 	// If so, reallocate bigger.
118 
119 	bytes = size * nmemb;
120 
121 	while (bytes > stream->alloced - stream->position)
122 	{
123 		unsigned char *newbuf;
124 
125 		newbuf = Z_Malloc(stream->alloced * 2, PU_STATIC, 0);
126 		memcpy(newbuf, stream->buf, stream->alloced);
127 		Z_Free(stream->buf);
128 		stream->buf = newbuf;
129 		stream->alloced *= 2;
130 	}
131 
132 	// Copy into buffer
133 
134 	memcpy(stream->buf + stream->position, ptr, bytes);
135 	stream->position += bytes;
136 
137 	if (stream->position > stream->buflen)
138 		stream->buflen = stream->position;
139 
140 	return nmemb;
141 }
142 
mem_get_buf(MEMFILE * stream,void ** buf,size_t * buflen)143 void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen)
144 {
145 	*buf = stream->buf;
146 	*buflen = stream->buflen;
147 }
148 
mem_fclose(MEMFILE * stream)149 void mem_fclose(MEMFILE *stream)
150 {
151 	if (stream->mode == MODE_WRITE)
152 	{
153 		Z_Free(stream->buf);
154 	}
155 
156 	Z_Free(stream);
157 }
158 
mem_ftell(MEMFILE * stream)159 long mem_ftell(MEMFILE *stream)
160 {
161 	return stream->position;
162 }
163 
mem_fseek(MEMFILE * stream,signed long position,mem_rel_t whence)164 int mem_fseek(MEMFILE *stream, signed long position, mem_rel_t whence)
165 {
166 	unsigned int newpos;
167 
168 	switch (whence)
169 	{
170 		case MEM_SEEK_SET:
171 			newpos = (int) position;
172 			break;
173 
174 		case MEM_SEEK_CUR:
175 			newpos = (int) (stream->position + position);
176 			break;
177 
178 		case MEM_SEEK_END:
179 			newpos = (int) (stream->buflen + position);
180 			break;
181 		default:
182 			return -1;
183 	}
184 
185 	if (newpos < stream->buflen)
186 	{
187 		stream->position = newpos;
188 		return 0;
189 	}
190 	else
191 	{
192 		printf("Error seeking to %i\n", newpos);
193 		return -1;
194 	}
195 }
196 
197 
198