Merge commit '48410b113dd2036e69dbf723a39ec9af02fc9b12'
[xonotic/netradiant.git] / libs / stream / filestream.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant 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 GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #if !defined(INCLUDED_STREAM_FILESTREAM_H)
23 #define INCLUDED_STREAM_FILESTREAM_H
24
25 #include "idatastream.h"
26 #include <algorithm>
27 #include <cstdio>
28
29 namespace FileStreamDetail
30 {
31   inline int whence_for_seekdir(SeekableStream::seekdir direction)
32   {
33     switch(direction)
34     {
35     case SeekableStream::cur:
36       return SEEK_CUR;
37     case SeekableStream::end:
38       return SEEK_END;
39     default:
40       break;
41     }
42     return SEEK_SET;
43   }
44 }
45
46
47 /// \brief A wrapper around a file input stream opened for reading in binary mode. Similar to std::ifstream.
48 ///
49 /// - Maintains a valid file handle associated with a name passed to the constructor.
50 /// - Implements SeekableInputStream.
51 class FileInputStream : public SeekableInputStream
52 {
53   std::FILE* m_file;
54 public:
55   FileInputStream(const char* name)
56   {
57     m_file = name[0] == '\0' ? 0 : fopen(name, "rb");
58   }
59   ~FileInputStream()
60   {
61     if(!failed())
62       fclose(m_file);
63   }
64
65   bool failed() const
66   {
67     return m_file == 0;
68   }
69
70   size_type read(byte_type* buffer, size_type length)
71   {
72     return fread(buffer, 1, length, m_file);
73   }
74
75   size_type seek(size_type position)
76   {
77     return fseek(m_file, static_cast<long>(position), SEEK_SET);
78   }
79   size_type seek(offset_type offset, seekdir direction)
80   {
81     return fseek(m_file, offset, FileStreamDetail::whence_for_seekdir(direction));
82   }
83   size_type tell() const
84   {
85     return ftell(m_file);
86   }
87
88   std::FILE* file()
89   {
90     return m_file;
91   }
92 };
93
94 /// \brief A wrapper around a FileInputStream limiting access.
95 ///
96 /// - Maintains an input stream.
97 /// - Provides input starting at an offset in the file for a limited range.
98 class SubFileInputStream : public InputStream
99 {
100   FileInputStream& m_istream;
101   size_type m_remaining;
102 public:
103   typedef FileInputStream::position_type position_type;
104
105   SubFileInputStream(FileInputStream& istream, position_type offset, size_type size)
106     : m_istream(istream), m_remaining(size)
107   {
108     m_istream.seek(offset);
109   }
110
111         size_type read(byte_type* buffer, size_type length)
112   {
113     size_type result = m_istream.read(buffer, std::min(length, m_remaining));
114     m_remaining -= result;
115     return result;
116   }
117 };
118
119
120 /// \brief A wrapper around a stdc file stream opened for writing in binary mode. Similar to std::ofstream..
121 ///
122 /// - Maintains a valid file handle associated with a name passed to the constructor.
123 /// - Implements SeekableInputStream.
124 class FileOutputStream : public SeekableOutputStream
125 {
126   std::FILE* m_file;
127 public:
128   FileOutputStream(const char* name)
129   {
130     m_file = name[0] == '\0' ? 0 : fopen(name, "wb");
131   }
132   ~FileOutputStream()
133   {
134     if(!failed())
135       fclose(m_file);
136   }
137
138   bool failed() const
139   {
140     return m_file == 0;
141   }
142
143   size_type write(const byte_type* buffer, size_type length)
144   {
145     return fwrite(buffer, 1, length, m_file);
146   }
147
148   size_type seek(size_type position)
149   {
150     return fseek(m_file, static_cast<long>(position), SEEK_SET);
151   }
152   size_type seek(offset_type offset, seekdir direction)
153   {
154     return fseek(m_file, offset, FileStreamDetail::whence_for_seekdir(direction));
155   }
156   size_type tell() const
157   {
158     return ftell(m_file);
159   }
160 };
161
162 inline bool file_copy(const char* source, const char* target)
163 {
164   const std::size_t buffer_size = 1024;
165   unsigned char buffer[buffer_size];
166
167   FileInputStream sourceFile(source);
168   if(sourceFile.failed())
169   {
170     return false;
171   }
172   FileOutputStream targetFile(target);
173   if(targetFile.failed())
174   {
175     return false;
176   }
177
178   for(;;)
179   {
180     std::size_t size = sourceFile.read(buffer, buffer_size);
181     if(size == 0)
182     {
183       break;
184     }
185     if(targetFile.write(buffer, size) != size)
186     {
187       return false;
188     }
189   }
190   return true;
191 }
192
193
194 #endif