]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/stream/filestream.h
transformpath: do not segfault if environment variable is missing
[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         switch ( direction )
33         {
34         case SeekableStream::cur:
35                 return SEEK_CUR;
36         case SeekableStream::end:
37                 return SEEK_END;
38         default:
39                 break;
40         }
41         return SEEK_SET;
42 }
43 }
44
45
46 /// \brief A wrapper around a file input stream opened for reading in binary mode. Similar to std::ifstream.
47 ///
48 /// - Maintains a valid file handle associated with a name passed to the constructor.
49 /// - Implements SeekableInputStream.
50 class FileInputStream : public SeekableInputStream
51 {
52 std::FILE* m_file;
53 public:
54 FileInputStream( const char* name ){
55         m_file = name[0] == '\0' ? 0 : fopen( name, "rb" );
56 }
57 ~FileInputStream(){
58         if ( !failed() ) {
59                 fclose( m_file );
60         }
61 }
62
63 bool failed() const {
64         return m_file == 0;
65 }
66
67 size_type read( byte_type* buffer, size_type length ){
68         return fread( buffer, 1, length, m_file );
69 }
70
71 size_type seek( size_type position ){
72         return fseek( m_file, static_cast<long>( position ), SEEK_SET );
73 }
74 size_type seek( offset_type offset, seekdir direction ){
75         return fseek( m_file, offset, FileStreamDetail::whence_for_seekdir( direction ) );
76 }
77 size_type tell() const {
78         return ftell( m_file );
79 }
80
81 std::FILE* file(){
82         return m_file;
83 }
84 };
85
86 /// \brief A wrapper around a FileInputStream limiting access.
87 ///
88 /// - Maintains an input stream.
89 /// - Provides input starting at an offset in the file for a limited range.
90 class SubFileInputStream : public InputStream
91 {
92 FileInputStream& m_istream;
93 size_type m_remaining;
94 public:
95 typedef FileInputStream::position_type position_type;
96
97 SubFileInputStream( FileInputStream& istream, position_type offset, size_type size )
98         : m_istream( istream ), m_remaining( size ){
99         m_istream.seek( offset );
100 }
101
102 size_type read( byte_type* buffer, size_type length ){
103         size_type result = m_istream.read( buffer, std::min( length, m_remaining ) );
104         m_remaining -= result;
105         return result;
106 }
107 };
108
109
110 /// \brief A wrapper around a stdc file stream opened for writing in binary mode. Similar to std::ofstream..
111 ///
112 /// - Maintains a valid file handle associated with a name passed to the constructor.
113 /// - Implements SeekableInputStream.
114 class FileOutputStream : public SeekableOutputStream
115 {
116 std::FILE* m_file;
117 public:
118 FileOutputStream( const char* name ){
119         m_file = name[0] == '\0' ? 0 : fopen( name, "wb" );
120 }
121 ~FileOutputStream(){
122         if ( !failed() ) {
123                 fclose( m_file );
124         }
125 }
126
127 bool failed() const {
128         return m_file == 0;
129 }
130
131 size_type write( const byte_type* buffer, size_type length ){
132         return fwrite( buffer, 1, length, m_file );
133 }
134
135 size_type seek( size_type position ){
136         return fseek( m_file, static_cast<long>( position ), SEEK_SET );
137 }
138 size_type seek( offset_type offset, seekdir direction ){
139         return fseek( m_file, offset, FileStreamDetail::whence_for_seekdir( direction ) );
140 }
141 size_type tell() const {
142         return ftell( m_file );
143 }
144 };
145
146 inline bool file_copy( const char* source, const char* target ){
147         const std::size_t buffer_size = 1024;
148         unsigned char buffer[buffer_size];
149
150         FileInputStream sourceFile( source );
151         if ( sourceFile.failed() ) {
152                 return false;
153         }
154         FileOutputStream targetFile( target );
155         if ( targetFile.failed() ) {
156                 return false;
157         }
158
159         for (;; )
160         {
161                 std::size_t size = sourceFile.read( buffer, buffer_size );
162                 if ( size == 0 ) {
163                         break;
164                 }
165                 if ( targetFile.write( buffer, size ) != size ) {
166                         return false;
167                 }
168         }
169         return true;
170 }
171
172
173 #endif