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