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