1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 // Author: kenton@google.com (Kenton Varda) 9 // Based on original Protocol Buffers design by 10 // Sanjay Ghemawat, Jeff Dean, and others. 11 // 12 // This file contains common implementations of the interfaces defined in 13 // zero_copy_stream.h which are only included in the full (non-lite) 14 // protobuf library. These implementations include Unix file descriptors 15 // and C++ iostreams. See also: zero_copy_stream_impl_lite.h 16 17 #ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ 18 #define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ 19 20 #include <iosfwd> 21 #include <string> 22 23 #include "google/protobuf/stubs/common.h" 24 #include "google/protobuf/io/zero_copy_stream.h" 25 #include "google/protobuf/io/zero_copy_stream_impl_lite.h" 26 27 // Must be included last. 28 #include "google/protobuf/port_def.inc" 29 30 namespace google { 31 namespace protobuf { 32 namespace io { 33 34 // =================================================================== 35 36 // A ZeroCopyInputStream which reads from a file descriptor. 37 // 38 // FileInputStream is preferred over using an ifstream with IstreamInputStream. 39 // The latter will introduce an extra layer of buffering, harming performance. 40 // Also, it's conceivable that FileInputStream could someday be enhanced 41 // to use zero-copy file descriptors on OSs which support them. 42 class PROTOBUF_EXPORT FileInputStream final : public ZeroCopyInputStream { 43 public: 44 // Creates a stream that reads from the given Unix file descriptor. 45 // If a block_size is given, it specifies the number of bytes that 46 // should be read and returned with each call to Next(). Otherwise, 47 // a reasonable default is used. 48 explicit FileInputStream(int file_descriptor, int block_size = -1); 49 FileInputStream(const FileInputStream&) = delete; 50 FileInputStream& operator=(const FileInputStream&) = delete; 51 52 // Flushes any buffers and closes the underlying file. Returns false if 53 // an error occurs during the process; use GetErrno() to examine the error. 54 // Even if an error occurs, the file descriptor is closed when this returns. 55 bool Close(); 56 57 // By default, the file descriptor is not closed when the stream is 58 // destroyed. Call SetCloseOnDelete(true) to change that. WARNING: 59 // This leaves no way for the caller to detect if close() fails. If 60 // detecting close() errors is important to you, you should arrange 61 // to close the descriptor yourself. SetCloseOnDelete(bool value)62 void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); } 63 64 // If an I/O error has occurred on this file descriptor, this is the 65 // errno from that error. Otherwise, this is zero. Once an error 66 // occurs, the stream is broken and all subsequent operations will 67 // fail. GetErrno()68 int GetErrno() const { return copying_input_.GetErrno(); } 69 70 // implements ZeroCopyInputStream ---------------------------------- 71 bool Next(const void** data, int* size) override; 72 void BackUp(int count) override; 73 bool Skip(int count) override; 74 int64_t ByteCount() const override; 75 76 private: 77 class PROTOBUF_EXPORT CopyingFileInputStream final 78 : public CopyingInputStream { 79 public: 80 CopyingFileInputStream(int file_descriptor); 81 CopyingFileInputStream(const CopyingFileInputStream&) = delete; 82 CopyingFileInputStream& operator=(const CopyingFileInputStream&) = delete; 83 ~CopyingFileInputStream() override; 84 85 bool Close(); SetCloseOnDelete(bool value)86 void SetCloseOnDelete(bool value) { close_on_delete_ = value; } GetErrno()87 int GetErrno() const { return errno_; } 88 89 // implements CopyingInputStream --------------------------------- 90 int Read(void* buffer, int size) override; 91 int Skip(int count) override; 92 93 private: 94 // The file descriptor. 95 const int file_; 96 bool close_on_delete_; 97 bool is_closed_; 98 99 // The errno of the I/O error, if one has occurred. Otherwise, zero. 100 int errno_; 101 102 // Did we try to seek once and fail? If so, we assume this file descriptor 103 // doesn't support seeking and won't try again. 104 bool previous_seek_failed_; 105 }; 106 107 CopyingFileInputStream copying_input_; 108 CopyingInputStreamAdaptor impl_; 109 }; 110 111 // =================================================================== 112 113 // A ZeroCopyOutputStream which writes to a file descriptor. 114 // 115 // FileOutputStream is preferred over using an ofstream with 116 // OstreamOutputStream. The latter will introduce an extra layer of buffering, 117 // harming performance. Also, it's conceivable that FileOutputStream could 118 // someday be enhanced to use zero-copy file descriptors on OSs which 119 // support them. 120 class PROTOBUF_EXPORT FileOutputStream final 121 : public CopyingOutputStreamAdaptor { 122 public: 123 // Creates a stream that writes to the given Unix file descriptor. 124 // If a block_size is given, it specifies the size of the buffers 125 // that should be returned by Next(). Otherwise, a reasonable default 126 // is used. 127 explicit FileOutputStream(int file_descriptor, int block_size = -1); 128 FileOutputStream(const FileOutputStream&) = delete; 129 FileOutputStream& operator=(const FileOutputStream&) = delete; 130 131 ~FileOutputStream() override; 132 133 // Flushes any buffers and closes the underlying file. Returns false if 134 // an error occurs during the process; use GetErrno() to examine the error. 135 // Even if an error occurs, the file descriptor is closed when this returns. 136 bool Close(); 137 138 // By default, the file descriptor is not closed when the stream is 139 // destroyed. Call SetCloseOnDelete(true) to change that. WARNING: 140 // This leaves no way for the caller to detect if close() fails. If 141 // detecting close() errors is important to you, you should arrange 142 // to close the descriptor yourself. SetCloseOnDelete(bool value)143 void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); } 144 145 // If an I/O error has occurred on this file descriptor, this is the 146 // errno from that error. Otherwise, this is zero. Once an error 147 // occurs, the stream is broken and all subsequent operations will 148 // fail. GetErrno()149 int GetErrno() const { return copying_output_.GetErrno(); } 150 151 private: 152 class PROTOBUF_EXPORT CopyingFileOutputStream final 153 : public CopyingOutputStream { 154 public: 155 CopyingFileOutputStream(int file_descriptor); 156 CopyingFileOutputStream(const CopyingFileOutputStream&) = delete; 157 CopyingFileOutputStream& operator=(const CopyingFileOutputStream&) = delete; 158 ~CopyingFileOutputStream() override; 159 160 bool Close(); SetCloseOnDelete(bool value)161 void SetCloseOnDelete(bool value) { close_on_delete_ = value; } GetErrno()162 int GetErrno() const { return errno_; } 163 164 // implements CopyingOutputStream -------------------------------- 165 bool Write(const void* buffer, int size) override; 166 167 private: 168 // The file descriptor. 169 const int file_; 170 bool close_on_delete_; 171 bool is_closed_; 172 173 // The errno of the I/O error, if one has occurred. Otherwise, zero. 174 int errno_; 175 }; 176 177 CopyingFileOutputStream copying_output_; 178 }; 179 180 // =================================================================== 181 182 // A ZeroCopyInputStream which reads from a C++ istream. 183 // 184 // Note that for reading files (or anything represented by a file descriptor), 185 // FileInputStream is more efficient. 186 class PROTOBUF_EXPORT IstreamInputStream final : public ZeroCopyInputStream { 187 public: 188 // Creates a stream that reads from the given C++ istream. 189 // If a block_size is given, it specifies the number of bytes that 190 // should be read and returned with each call to Next(). Otherwise, 191 // a reasonable default is used. 192 explicit IstreamInputStream(std::istream* stream, int block_size = -1); 193 IstreamInputStream(const IstreamInputStream&) = delete; 194 IstreamInputStream& operator=(const IstreamInputStream&) = delete; 195 196 // implements ZeroCopyInputStream ---------------------------------- 197 bool Next(const void** data, int* size) override; 198 void BackUp(int count) override; 199 bool Skip(int count) override; 200 int64_t ByteCount() const override; 201 202 private: 203 class PROTOBUF_EXPORT CopyingIstreamInputStream final 204 : public CopyingInputStream { 205 public: 206 CopyingIstreamInputStream(std::istream* input); 207 CopyingIstreamInputStream(const CopyingIstreamInputStream&) = delete; 208 CopyingIstreamInputStream& operator=(const CopyingIstreamInputStream&) = 209 delete; 210 ~CopyingIstreamInputStream() override; 211 212 // implements CopyingInputStream --------------------------------- 213 int Read(void* buffer, int size) override; 214 // (We use the default implementation of Skip().) 215 216 private: 217 // The stream. 218 std::istream* input_; 219 }; 220 221 CopyingIstreamInputStream copying_input_; 222 CopyingInputStreamAdaptor impl_; 223 }; 224 225 // =================================================================== 226 227 // A ZeroCopyOutputStream which writes to a C++ ostream. 228 // 229 // Note that for writing files (or anything represented by a file descriptor), 230 // FileOutputStream is more efficient. 231 class PROTOBUF_EXPORT OstreamOutputStream final : public ZeroCopyOutputStream { 232 public: 233 // Creates a stream that writes to the given C++ ostream. 234 // If a block_size is given, it specifies the size of the buffers 235 // that should be returned by Next(). Otherwise, a reasonable default 236 // is used. 237 explicit OstreamOutputStream(std::ostream* stream, int block_size = -1); 238 OstreamOutputStream(const OstreamOutputStream&) = delete; 239 OstreamOutputStream& operator=(const OstreamOutputStream&) = delete; 240 ~OstreamOutputStream() override; 241 242 // implements ZeroCopyOutputStream --------------------------------- 243 bool Next(void** data, int* size) override; 244 void BackUp(int count) override; 245 int64_t ByteCount() const override; 246 247 private: 248 class PROTOBUF_EXPORT CopyingOstreamOutputStream final 249 : public CopyingOutputStream { 250 public: 251 CopyingOstreamOutputStream(std::ostream* output); 252 CopyingOstreamOutputStream(const CopyingOstreamOutputStream&) = delete; 253 CopyingOstreamOutputStream& operator=(const CopyingOstreamOutputStream&) = 254 delete; 255 ~CopyingOstreamOutputStream() override; 256 257 // implements CopyingOutputStream -------------------------------- 258 bool Write(const void* buffer, int size) override; 259 260 private: 261 // The stream. 262 std::ostream* output_; 263 }; 264 265 CopyingOstreamOutputStream copying_output_; 266 CopyingOutputStreamAdaptor impl_; 267 }; 268 269 // =================================================================== 270 271 // A ZeroCopyInputStream which reads from several other streams in sequence. 272 // ConcatenatingInputStream is unable to distinguish between end-of-stream 273 // and read errors in the underlying streams, so it assumes any errors mean 274 // end-of-stream. So, if the underlying streams fail for any other reason, 275 // ConcatenatingInputStream may do odd things. It is suggested that you do 276 // not use ConcatenatingInputStream on streams that might produce read errors 277 // other than end-of-stream. 278 class PROTOBUF_EXPORT ConcatenatingInputStream final 279 : public ZeroCopyInputStream { 280 public: 281 // All streams passed in as well as the array itself must remain valid 282 // until the ConcatenatingInputStream is destroyed. 283 ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count); 284 ConcatenatingInputStream(const ConcatenatingInputStream&) = delete; 285 ConcatenatingInputStream& operator=(const ConcatenatingInputStream&) = delete; 286 ~ConcatenatingInputStream() override = default; 287 288 // implements ZeroCopyInputStream ---------------------------------- 289 bool Next(const void** data, int* size) override; 290 void BackUp(int count) override; 291 bool Skip(int count) override; 292 int64_t ByteCount() const override; 293 294 295 private: 296 // As streams are retired, streams_ is incremented and count_ is 297 // decremented. 298 ZeroCopyInputStream* const* streams_; 299 int stream_count_; 300 int64_t bytes_retired_; // Bytes read from previous streams. 301 }; 302 303 // =================================================================== 304 305 } // namespace io 306 } // namespace protobuf 307 } // namespace google 308 309 #include "google/protobuf/port_undef.inc" 310 311 #endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ 312