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