Home | History | Annotate | Download | only in io
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // Author: kenton (at) google.com (Kenton Varda)
     32 //  Based on original Protocol Buffers design by
     33 //  Sanjay Ghemawat, Jeff Dean, and others.
     34 //
     35 // This file contains common implementations of the interfaces defined in
     36 // zero_copy_stream.h which are only included in the full (non-lite)
     37 // protobuf library.  These implementations include Unix file descriptors
     38 // and C++ iostreams.  See also:  zero_copy_stream_impl_lite.h
     39 
     40 #ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
     41 #define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
     42 
     43 #include <string>
     44 #include <iosfwd>
     45 #include <google/protobuf/io/zero_copy_stream.h>
     46 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
     47 #include <google/protobuf/stubs/common.h>
     48 
     49 
     50 namespace google {
     51 namespace protobuf {
     52 namespace io {
     53 
     54 
     55 // ===================================================================
     56 
     57 // A ZeroCopyInputStream which reads from a file descriptor.
     58 //
     59 // FileInputStream is preferred over using an ifstream with IstreamInputStream.
     60 // The latter will introduce an extra layer of buffering, harming performance.
     61 // Also, it's conceivable that FileInputStream could someday be enhanced
     62 // to use zero-copy file descriptors on OSs which support them.
     63 class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
     64  public:
     65   // Creates a stream that reads from the given Unix file descriptor.
     66   // If a block_size is given, it specifies the number of bytes that
     67   // should be read and returned with each call to Next().  Otherwise,
     68   // a reasonable default is used.
     69   explicit FileInputStream(int file_descriptor, int block_size = -1);
     70   ~FileInputStream();
     71 
     72   // Flushes any buffers and closes the underlying file.  Returns false if
     73   // an error occurs during the process; use GetErrno() to examine the error.
     74   // Even if an error occurs, the file descriptor is closed when this returns.
     75   bool Close();
     76 
     77   // By default, the file descriptor is not closed when the stream is
     78   // destroyed.  Call SetCloseOnDelete(true) to change that.  WARNING:
     79   // This leaves no way for the caller to detect if close() fails.  If
     80   // detecting close() errors is important to you, you should arrange
     81   // to close the descriptor yourself.
     82   void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); }
     83 
     84   // If an I/O error has occurred on this file descriptor, this is the
     85   // errno from that error.  Otherwise, this is zero.  Once an error
     86   // occurs, the stream is broken and all subsequent operations will
     87   // fail.
     88   int GetErrno() { return copying_input_.GetErrno(); }
     89 
     90   // implements ZeroCopyInputStream ----------------------------------
     91   bool Next(const void** data, int* size);
     92   void BackUp(int count);
     93   bool Skip(int count);
     94   int64 ByteCount() const;
     95 
     96  private:
     97   class LIBPROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream {
     98    public:
     99     CopyingFileInputStream(int file_descriptor);
    100     ~CopyingFileInputStream();
    101 
    102     bool Close();
    103     void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
    104     int GetErrno() { return errno_; }
    105 
    106     // implements CopyingInputStream ---------------------------------
    107     int Read(void* buffer, int size);
    108     int Skip(int count);
    109 
    110    private:
    111     // The file descriptor.
    112     const int file_;
    113     bool close_on_delete_;
    114     bool is_closed_;
    115 
    116     // The errno of the I/O error, if one has occurred.  Otherwise, zero.
    117     int errno_;
    118 
    119     // Did we try to seek once and fail?  If so, we assume this file descriptor
    120     // doesn't support seeking and won't try again.
    121     bool previous_seek_failed_;
    122 
    123     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileInputStream);
    124   };
    125 
    126   CopyingFileInputStream copying_input_;
    127   CopyingInputStreamAdaptor impl_;
    128 
    129   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileInputStream);
    130 };
    131 
    132 // ===================================================================
    133 
    134 // A ZeroCopyOutputStream which writes to a file descriptor.
    135 //
    136 // FileOutputStream is preferred over using an ofstream with
    137 // OstreamOutputStream.  The latter will introduce an extra layer of buffering,
    138 // harming performance.  Also, it's conceivable that FileOutputStream could
    139 // someday be enhanced to use zero-copy file descriptors on OSs which
    140 // support them.
    141 class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
    142  public:
    143   // Creates a stream that writes to the given Unix file descriptor.
    144   // If a block_size is given, it specifies the size of the buffers
    145   // that should be returned by Next().  Otherwise, a reasonable default
    146   // is used.
    147   explicit FileOutputStream(int file_descriptor, int block_size = -1);
    148   ~FileOutputStream();
    149 
    150   // Flushes any buffers and closes the underlying file.  Returns false if
    151   // an error occurs during the process; use GetErrno() to examine the error.
    152   // Even if an error occurs, the file descriptor is closed when this returns.
    153   bool Close();
    154 
    155   // Flushes FileOutputStream's buffers but does not close the
    156   // underlying file. No special measures are taken to ensure that
    157   // underlying operating system file object is synchronized to disk.
    158   bool Flush();
    159 
    160   // By default, the file descriptor is not closed when the stream is
    161   // destroyed.  Call SetCloseOnDelete(true) to change that.  WARNING:
    162   // This leaves no way for the caller to detect if close() fails.  If
    163   // detecting close() errors is important to you, you should arrange
    164   // to close the descriptor yourself.
    165   void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); }
    166 
    167   // If an I/O error has occurred on this file descriptor, this is the
    168   // errno from that error.  Otherwise, this is zero.  Once an error
    169   // occurs, the stream is broken and all subsequent operations will
    170   // fail.
    171   int GetErrno() { return copying_output_.GetErrno(); }
    172 
    173   // implements ZeroCopyOutputStream ---------------------------------
    174   bool Next(void** data, int* size);
    175   void BackUp(int count);
    176   int64 ByteCount() const;
    177 
    178  private:
    179   class LIBPROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
    180    public:
    181     CopyingFileOutputStream(int file_descriptor);
    182     ~CopyingFileOutputStream();
    183 
    184     bool Close();
    185     void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
    186     int GetErrno() { return errno_; }
    187 
    188     // implements CopyingOutputStream --------------------------------
    189     bool Write(const void* buffer, int size);
    190 
    191    private:
    192     // The file descriptor.
    193     const int file_;
    194     bool close_on_delete_;
    195     bool is_closed_;
    196 
    197     // The errno of the I/O error, if one has occurred.  Otherwise, zero.
    198     int errno_;
    199 
    200     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileOutputStream);
    201   };
    202 
    203   CopyingFileOutputStream copying_output_;
    204   CopyingOutputStreamAdaptor impl_;
    205 
    206   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream);
    207 };
    208 
    209 // ===================================================================
    210 
    211 // A ZeroCopyInputStream which reads from a C++ istream.
    212 //
    213 // Note that for reading files (or anything represented by a file descriptor),
    214 // FileInputStream is more efficient.
    215 class LIBPROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
    216  public:
    217   // Creates a stream that reads from the given C++ istream.
    218   // If a block_size is given, it specifies the number of bytes that
    219   // should be read and returned with each call to Next().  Otherwise,
    220   // a reasonable default is used.
    221   explicit IstreamInputStream(istream* stream, int block_size = -1);
    222   ~IstreamInputStream();
    223 
    224   // implements ZeroCopyInputStream ----------------------------------
    225   bool Next(const void** data, int* size);
    226   void BackUp(int count);
    227   bool Skip(int count);
    228   int64 ByteCount() const;
    229 
    230  private:
    231   class LIBPROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream {
    232    public:
    233     CopyingIstreamInputStream(istream* input);
    234     ~CopyingIstreamInputStream();
    235 
    236     // implements CopyingInputStream ---------------------------------
    237     int Read(void* buffer, int size);
    238     // (We use the default implementation of Skip().)
    239 
    240    private:
    241     // The stream.
    242     istream* input_;
    243 
    244     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingIstreamInputStream);
    245   };
    246 
    247   CopyingIstreamInputStream copying_input_;
    248   CopyingInputStreamAdaptor impl_;
    249 
    250   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(IstreamInputStream);
    251 };
    252 
    253 // ===================================================================
    254 
    255 // A ZeroCopyOutputStream which writes to a C++ ostream.
    256 //
    257 // Note that for writing files (or anything represented by a file descriptor),
    258 // FileOutputStream is more efficient.
    259 class LIBPROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream {
    260  public:
    261   // Creates a stream that writes to the given C++ ostream.
    262   // If a block_size is given, it specifies the size of the buffers
    263   // that should be returned by Next().  Otherwise, a reasonable default
    264   // is used.
    265   explicit OstreamOutputStream(ostream* stream, int block_size = -1);
    266   ~OstreamOutputStream();
    267 
    268   // implements ZeroCopyOutputStream ---------------------------------
    269   bool Next(void** data, int* size);
    270   void BackUp(int count);
    271   int64 ByteCount() const;
    272 
    273  private:
    274   class LIBPROTOBUF_EXPORT CopyingOstreamOutputStream : public CopyingOutputStream {
    275    public:
    276     CopyingOstreamOutputStream(ostream* output);
    277     ~CopyingOstreamOutputStream();
    278 
    279     // implements CopyingOutputStream --------------------------------
    280     bool Write(const void* buffer, int size);
    281 
    282    private:
    283     // The stream.
    284     ostream* output_;
    285 
    286     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOstreamOutputStream);
    287   };
    288 
    289   CopyingOstreamOutputStream copying_output_;
    290   CopyingOutputStreamAdaptor impl_;
    291 
    292   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OstreamOutputStream);
    293 };
    294 
    295 // ===================================================================
    296 
    297 // A ZeroCopyInputStream which reads from several other streams in sequence.
    298 // ConcatenatingInputStream is unable to distinguish between end-of-stream
    299 // and read errors in the underlying streams, so it assumes any errors mean
    300 // end-of-stream.  So, if the underlying streams fail for any other reason,
    301 // ConcatenatingInputStream may do odd things.  It is suggested that you do
    302 // not use ConcatenatingInputStream on streams that might produce read errors
    303 // other than end-of-stream.
    304 class LIBPROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream {
    305  public:
    306   // All streams passed in as well as the array itself must remain valid
    307   // until the ConcatenatingInputStream is destroyed.
    308   ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count);
    309   ~ConcatenatingInputStream();
    310 
    311   // implements ZeroCopyInputStream ----------------------------------
    312   bool Next(const void** data, int* size);
    313   void BackUp(int count);
    314   bool Skip(int count);
    315   int64 ByteCount() const;
    316 
    317 
    318  private:
    319   // As streams are retired, streams_ is incremented and count_ is
    320   // decremented.
    321   ZeroCopyInputStream* const* streams_;
    322   int stream_count_;
    323   int64 bytes_retired_;  // Bytes read from previous streams.
    324 
    325   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
    326 };
    327 
    328 // ===================================================================
    329 
    330 // A ZeroCopyInputStream which wraps some other stream and limits it to
    331 // a particular byte count.
    332 class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
    333  public:
    334   LimitingInputStream(ZeroCopyInputStream* input, int64 limit);
    335   ~LimitingInputStream();
    336 
    337   // implements ZeroCopyInputStream ----------------------------------
    338   bool Next(const void** data, int* size);
    339   void BackUp(int count);
    340   bool Skip(int count);
    341   int64 ByteCount() const;
    342 
    343 
    344  private:
    345   ZeroCopyInputStream* input_;
    346   int64 limit_;  // Decreases as we go, becomes negative if we overshoot.
    347 
    348   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
    349 };
    350 
    351 // ===================================================================
    352 
    353 }  // namespace io
    354 }  // namespace protobuf
    355 
    356 }  // namespace google
    357 #endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
    358