1 /* Copyright (C) 2002 The gtkmm Development Team
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <glibmm/streamiochannel.h>
18 #include <glibmm/main.h> //For Source
19 #include <glib.h>
20 #include <fstream>
21 #include <iostream>
22
23 namespace Glib
24 {
25
26 #ifndef GLIBMM_DISABLE_DEPRECATED
27
28 // static
29 Glib::RefPtr<StreamIOChannel>
create(std::istream & stream)30 StreamIOChannel::create(std::istream& stream)
31 {
32 return Glib::RefPtr<StreamIOChannel>(new StreamIOChannel(&stream, nullptr));
33 }
34
35 // static
36 Glib::RefPtr<StreamIOChannel>
create(std::ostream & stream)37 StreamIOChannel::create(std::ostream& stream)
38 {
39 return Glib::RefPtr<StreamIOChannel>(new StreamIOChannel(nullptr, &stream));
40 }
41
42 // static
43 Glib::RefPtr<StreamIOChannel>
create(std::iostream & stream)44 StreamIOChannel::create(std::iostream& stream)
45 {
46 return Glib::RefPtr<StreamIOChannel>(new StreamIOChannel(&stream, &stream));
47 }
48
StreamIOChannel(std::istream * stream_in,std::ostream * stream_out)49 StreamIOChannel::StreamIOChannel(std::istream* stream_in, std::ostream* stream_out)
50 : stream_in_(stream_in), stream_out_(stream_out)
51 {
52 get_flags_vfunc(); // initialize GIOChannel flag bits
53 }
54
~StreamIOChannel()55 StreamIOChannel::~StreamIOChannel() noexcept
56 {
57 }
58
59 IOStatus
read_vfunc(char * buf,gsize count,gsize & bytes_read)60 StreamIOChannel::read_vfunc(char* buf, gsize count, gsize& bytes_read)
61 {
62 g_return_val_if_fail(stream_in_ != nullptr, IO_STATUS_ERROR);
63
64 stream_in_->clear();
65 stream_in_->read(buf, count);
66 bytes_read = stream_in_->gcount();
67
68 if (stream_in_->eof())
69 return IO_STATUS_EOF;
70
71 if (stream_in_->fail())
72 {
73 throw Glib::Error(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Reading from stream failed");
74 }
75
76 return IO_STATUS_NORMAL;
77 }
78
79 IOStatus
write_vfunc(const char * buf,gsize count,gsize & bytes_written)80 StreamIOChannel::write_vfunc(const char* buf, gsize count, gsize& bytes_written)
81 {
82 g_return_val_if_fail(stream_out_ != nullptr, IO_STATUS_ERROR);
83
84 bytes_written = 0;
85
86 stream_out_->clear();
87 stream_out_->write(buf, count);
88
89 if (stream_out_->fail())
90 {
91 throw Glib::Error(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Writing to stream failed");
92 }
93
94 bytes_written = count; // all or nothing ;)
95
96 return IO_STATUS_NORMAL;
97 }
98
99 IOStatus
seek_vfunc(gint64 offset,SeekType type)100 StreamIOChannel::seek_vfunc(gint64 offset, SeekType type)
101 {
102 std::ios::seekdir direction = std::ios::beg;
103
104 switch (type)
105 {
106 case SEEK_TYPE_SET:
107 direction = std::ios::beg;
108 break;
109 case SEEK_TYPE_CUR:
110 direction = std::ios::cur;
111 break;
112 case SEEK_TYPE_END:
113 direction = std::ios::end;
114 break;
115 }
116
117 bool failed = false;
118
119 if (stream_in_)
120 {
121 stream_in_->clear();
122 stream_in_->seekg(offset, direction);
123 failed = stream_in_->fail();
124 }
125 if (stream_out_)
126 {
127 stream_out_->clear();
128 stream_out_->seekp(offset, direction);
129 failed = (failed || stream_out_->fail());
130 }
131
132 if (failed)
133 {
134 throw Glib::Error(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Seeking into stream failed");
135 }
136
137 return Glib::IO_STATUS_NORMAL;
138 }
139
140 IOStatus
close_vfunc()141 StreamIOChannel::close_vfunc()
142 {
143 bool failed = false;
144
145 if (std::fstream* const fstream = dynamic_cast<std::fstream*>(stream_in_))
146 {
147 fstream->clear();
148 fstream->close();
149 failed = fstream->fail();
150 }
151 else if (std::ifstream* const ifstream = dynamic_cast<std::ifstream*>(stream_in_))
152 {
153 ifstream->clear();
154 ifstream->close();
155 failed = ifstream->fail();
156 }
157 else if (std::ofstream* const ofstream = dynamic_cast<std::ofstream*>(stream_out_))
158 {
159 ofstream->clear();
160 ofstream->close();
161 failed = ofstream->fail();
162 }
163 else
164 {
165 throw Glib::Error(
166 G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Attempt to close non-file stream");
167 }
168
169 if (failed)
170 {
171 throw Glib::Error(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Failed to close stream");
172 }
173
174 return IO_STATUS_NORMAL;
175 }
176
set_flags_vfunc(IOFlags)177 IOStatus StreamIOChannel::set_flags_vfunc(IOFlags)
178 {
179 return IO_STATUS_NORMAL;
180 }
181
182 IOFlags
get_flags_vfunc()183 StreamIOChannel::get_flags_vfunc()
184 {
185 gobj()->is_seekable = 1;
186 gobj()->is_readable = (stream_in_ != nullptr);
187 gobj()->is_writeable = (stream_out_ != nullptr);
188
189 IOFlags flags = IO_FLAG_IS_SEEKABLE;
190
191 if (stream_in_)
192 flags |= IO_FLAG_IS_READABLE;
193 if (stream_out_)
194 flags |= IO_FLAG_IS_WRITEABLE;
195
196 return flags;
197 }
198
create_watch_vfunc(IOCondition)199 Glib::RefPtr<Glib::Source> StreamIOChannel::create_watch_vfunc(IOCondition)
200 {
201 g_warning("Glib::StreamIOChannel::create_watch_vfunc() not implemented");
202 return Glib::RefPtr<Glib::Source>();
203 }
204
205 #endif // GLIBMM_DISABLE_DEPRECATED
206
207 } // namespace Glib
208