transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / radiant / file.cpp
1 /*\r
2 Copyright (c) 2001, Loki software, inc.\r
3 All rights reserved.\r
4 \r
5 Redistribution and use in source and binary forms, with or without modification, \r
6 are permitted provided that the following conditions are met:\r
7 \r
8 Redistributions of source code must retain the above copyright notice, this list \r
9 of conditions and the following disclaimer.\r
10 \r
11 Redistributions in binary form must reproduce the above copyright notice, this\r
12 list of conditions and the following disclaimer in the documentation and/or\r
13 other materials provided with the distribution.\r
14 \r
15 Neither the name of Loki software nor the names of its contributors may be used \r
16 to endorse or promote products derived from this software without specific prior \r
17 written permission. \r
18 \r
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' \r
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \r
22 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY \r
23 DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES \r
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; \r
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON \r
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS \r
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \r
29 */\r
30 \r
31 //\r
32 // File class, can be a memory file or a regular disk file.\r
33 // Originally from LeoCAD, used with permission from the author. :)\r
34 //\r
35 // Leonardo Zide (leo@lokigames.com)\r
36 //\r
37 \r
38 #include "stdafx.h"\r
39 \r
40 #include <stdio.h>\r
41 #include <memory.h>\r
42 #include <stdlib.h>\r
43 #include <string.h>\r
44 \r
45 \r
46 IDataStream::IDataStream()\r
47 { }\r
48   \r
49 IDataStream::~IDataStream()\r
50 { }\r
51 \r
52 /////////////////////////////////////////////////////////////////////////////\r
53 // File construction/destruction\r
54 \r
55 MemStream::MemStream()\r
56 {\r
57   m_nGrowBytes = 1024;\r
58   m_nPosition = 0;\r
59   m_nBufferSize = 0;\r
60   m_nFileSize = 0;\r
61   m_pBuffer = NULL;\r
62   m_bAutoDelete = true;\r
63 }\r
64 \r
65 MemStream::MemStream(unsigned long nLen)\r
66 {\r
67   m_nGrowBytes = 1024;\r
68   m_nPosition = 0;\r
69   m_nBufferSize = 0;\r
70   m_nFileSize = 0;\r
71   m_pBuffer = NULL;\r
72   m_bAutoDelete = true;\r
73 \r
74   GrowFile (nLen);\r
75 }\r
76 \r
77 FileStream::FileStream()\r
78 {\r
79   m_hFile = NULL;\r
80   m_bCloseOnDelete = false;\r
81 }\r
82 \r
83 MemStream::~MemStream()\r
84 {\r
85   if (m_pBuffer)\r
86     Close();\r
87 \r
88   m_nGrowBytes = 0;\r
89   m_nPosition = 0;\r
90   m_nBufferSize = 0;\r
91   m_nFileSize = 0;\r
92 }\r
93 \r
94 FileStream::~FileStream()\r
95 {\r
96   if (m_hFile != NULL && m_bCloseOnDelete)\r
97     Close();\r
98 }\r
99 \r
100 /////////////////////////////////////////////////////////////////////////////\r
101 // File operations\r
102 \r
103 char* MemStream::ReadString(char* pBuf, unsigned long nMax)\r
104 {\r
105   int nRead = 0;\r
106   unsigned char ch;\r
107 \r
108   if (nMax <= 0)\r
109     return NULL;\r
110   if (m_nPosition >= m_nFileSize)\r
111     return NULL;\r
112 \r
113   while ((--nMax))\r
114   {\r
115     if (m_nPosition == m_nFileSize)\r
116       break;\r
117 \r
118     ch = m_pBuffer[m_nPosition];\r
119     m_nPosition++;\r
120     pBuf[nRead++] = ch;\r
121 \r
122     if (ch == '\n')\r
123       break;\r
124   }\r
125 \r
126   pBuf[nRead] = '\0';\r
127   return pBuf;\r
128 }\r
129 \r
130 char* FileStream::ReadString(char* pBuf, unsigned long nMax)\r
131 {\r
132   return fgets(pBuf, nMax, m_hFile);\r
133 }\r
134 \r
135 unsigned long MemStream::Read(void* pBuf, unsigned long nCount)\r
136 {\r
137   if (nCount == 0)\r
138     return 0;\r
139 \r
140   if (m_nPosition > m_nFileSize)\r
141     return 0;\r
142 \r
143   unsigned long nRead;\r
144   if (m_nPosition + nCount > m_nFileSize)\r
145     nRead = (unsigned long)(m_nFileSize - m_nPosition);\r
146   else\r
147     nRead = nCount;\r
148 \r
149   memcpy((unsigned char*)pBuf, (unsigned char*)m_pBuffer + m_nPosition, nRead);\r
150   m_nPosition += nRead;\r
151 \r
152   return nRead;\r
153 }\r
154 \r
155 unsigned long FileStream::Read(void* pBuf, unsigned long nCount)\r
156 {\r
157   return fread(pBuf, 1, nCount, m_hFile);\r
158 }\r
159 \r
160 int MemStream::GetChar()\r
161 {\r
162   if (m_nPosition > m_nFileSize)\r
163     return 0;\r
164 \r
165   unsigned char* ret = (unsigned char*)m_pBuffer + m_nPosition;\r
166   m_nPosition++;\r
167 \r
168   return *ret;\r
169 }\r
170 \r
171 int FileStream::GetChar()\r
172 {\r
173   return fgetc(m_hFile);\r
174 }\r
175 \r
176 unsigned long MemStream::Write(const void* pBuf, unsigned long nCount)\r
177 {\r
178   if (nCount == 0)\r
179     return 0;\r
180 \r
181   if (m_nPosition + nCount > m_nBufferSize)\r
182     GrowFile(m_nPosition + nCount);\r
183 \r
184   memcpy((unsigned char*)m_pBuffer + m_nPosition, (unsigned char*)pBuf, nCount);\r
185 \r
186   m_nPosition += nCount;\r
187 \r
188   if (m_nPosition > m_nFileSize)\r
189     m_nFileSize = m_nPosition;\r
190 \r
191   return nCount;\r
192 }\r
193 \r
194 unsigned long FileStream::Write(const void* pBuf, unsigned long nCount)\r
195 {\r
196   return fwrite(pBuf, 1, nCount, m_hFile);\r
197 }\r
198 \r
199 int MemStream::PutChar(int c)\r
200 {\r
201   if (m_nPosition + 1 > m_nBufferSize)\r
202     GrowFile(m_nPosition + 1);\r
203 \r
204   unsigned char* bt = (unsigned char*)m_pBuffer + m_nPosition;\r
205   *bt = c;\r
206 \r
207   m_nPosition++;\r
208 \r
209   if (m_nPosition > m_nFileSize)\r
210     m_nFileSize = m_nPosition;\r
211 \r
212   return 1;\r
213 }\r
214 \r
215 /*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */\r
216 void FileStream::printf(const char* s, ...)\r
217 {\r
218   va_list args;\r
219 \r
220   va_start (args, s);\r
221   vfprintf(m_hFile, s, args);\r
222   va_end (args);\r
223 }\r
224 \r
225 /*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */\r
226 void MemStream::printf(const char* s, ...)\r
227 {\r
228   va_list args;\r
229 \r
230   char buffer[4096];\r
231   va_start (args, s);\r
232   vsprintf(buffer, s, args);\r
233   va_end (args);\r
234   Write(buffer, strlen(buffer));\r
235 }\r
236 \r
237 int FileStream::PutChar(int c)\r
238 {\r
239   return fputc(c, m_hFile);\r
240 }\r
241 \r
242 bool FileStream::Open(const char *filename, const char *mode)\r
243 {\r
244   m_hFile = fopen(filename, mode);\r
245   m_bCloseOnDelete = true;\r
246 \r
247   return (m_hFile != NULL);\r
248 }\r
249 \r
250 void MemStream::Close()\r
251 {\r
252   m_nGrowBytes = 0;\r
253   m_nPosition = 0;\r
254   m_nBufferSize = 0;\r
255   m_nFileSize = 0;\r
256   if (m_pBuffer && m_bAutoDelete)\r
257     free(m_pBuffer);\r
258   m_pBuffer = NULL;\r
259 }\r
260 \r
261 void FileStream::Close()\r
262 {\r
263   if (m_hFile != NULL)\r
264     fclose(m_hFile);\r
265 \r
266   m_hFile = NULL;\r
267   m_bCloseOnDelete = false;\r
268 }\r
269 \r
270 unsigned long MemStream::Seek(long lOff, int nFrom)\r
271 {\r
272   unsigned long lNewPos = m_nPosition;\r
273 \r
274   if (nFrom == SEEK_SET)\r
275     lNewPos = lOff;\r
276   else if (nFrom == SEEK_CUR)\r
277     lNewPos += lOff;\r
278   else if (nFrom == SEEK_END)\r
279     lNewPos = m_nFileSize + lOff;\r
280   else\r
281     return (unsigned long)-1;\r
282 \r
283   m_nPosition = lNewPos;\r
284 \r
285   return m_nPosition;\r
286 }\r
287 \r
288 unsigned long FileStream::Seek(long lOff, int nFrom)\r
289 {\r
290   fseek (m_hFile, lOff, nFrom);\r
291 \r
292   return ftell(m_hFile);\r
293 }\r
294 \r
295 unsigned long MemStream::GetPosition() const\r
296 {\r
297     return m_nPosition;\r
298 }\r
299 \r
300 unsigned long FileStream::GetPosition() const\r
301 {\r
302   return ftell(m_hFile);\r
303 }\r
304 \r
305 void MemStream::GrowFile(unsigned long nNewLen)\r
306 {\r
307   if (nNewLen > m_nBufferSize)\r
308   {\r
309     // grow the buffer\r
310     unsigned long nNewBufferSize = m_nBufferSize;\r
311 \r
312     // determine new buffer size\r
313     while (nNewBufferSize < nNewLen)\r
314       nNewBufferSize += m_nGrowBytes;\r
315 \r
316     // allocate new buffer\r
317     unsigned char* lpNew;\r
318     if (m_pBuffer == NULL)\r
319       lpNew = static_cast<unsigned char*>(malloc(nNewBufferSize));\r
320     else\r
321       lpNew = static_cast<unsigned char*>(realloc(m_pBuffer, nNewBufferSize));\r
322 \r
323     m_pBuffer = lpNew;\r
324     m_nBufferSize = nNewBufferSize;\r
325   }\r
326 }\r
327 \r
328 void MemStream::Flush()\r
329 {\r
330   // Nothing to be done\r
331 }\r
332 \r
333 void FileStream::Flush()\r
334 {\r
335   if (m_hFile == NULL)\r
336     return;\r
337 \r
338   fflush(m_hFile);\r
339 }\r
340 \r
341 void MemStream::Abort()\r
342 {\r
343   Close();\r
344 }\r
345 \r
346 void FileStream::Abort()\r
347 {\r
348   if (m_hFile != NULL)\r
349   {\r
350     // close but ignore errors\r
351     if (m_bCloseOnDelete)\r
352       fclose(m_hFile);\r
353     m_hFile = NULL;\r
354     m_bCloseOnDelete = false;\r
355   }\r
356 }\r
357 \r
358 void MemStream::SetLength(unsigned long nNewLen)\r
359 {\r
360   if (nNewLen > m_nBufferSize)\r
361     GrowFile(nNewLen);\r
362 \r
363   if (nNewLen < m_nPosition)\r
364     m_nPosition = nNewLen;\r
365 \r
366   m_nFileSize = nNewLen;\r
367 }\r
368 \r
369 void FileStream::SetLength(unsigned long nNewLen)\r
370 {\r
371   fseek(m_hFile, nNewLen, SEEK_SET);\r
372 }\r
373 \r
374 unsigned long MemStream::GetLength() const\r
375 {\r
376   return m_nFileSize;\r
377 }\r
378 \r
379 unsigned long FileStream::GetLength() const\r
380 {\r
381   unsigned long nLen, nCur;\r
382 \r
383   // Seek is a non const operation\r
384   nCur = ftell(m_hFile);\r
385   fseek(m_hFile, 0, SEEK_END);\r
386   nLen = ftell(m_hFile);\r
387   fseek(m_hFile, nCur, SEEK_SET);\r
388 \r
389   return nLen;\r
390 }\r