Home | History | Annotate | Download | only in codec
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkStreamBuffer_DEFINED
      9 #define SkStreamBuffer_DEFINED
     10 
     11 #include "SkData.h"
     12 #include "SkStream.h"
     13 #include "SkTypes.h"
     14 #include "../private/SkTHash.h"
     15 
     16 /**
     17  *  Helper class for reading from a stream that may not have all its data
     18  *  available yet.
     19  *
     20  *  Used by GIFImageReader, and currently set up for that use case.
     21  *
     22  *  Buffers up to 256 * 3 bytes (256 colors, with 3 bytes each) to support GIF.
     23  *  FIXME (scroggo): Make this more general purpose?
     24  */
     25 class SkStreamBuffer : SkNoncopyable {
     26 public:
     27     // Takes ownership of the SkStream.
     28     SkStreamBuffer(SkStream*);
     29 
     30     ~SkStreamBuffer();
     31 
     32     /**
     33      *  Return a pointer the buffered data.
     34      *
     35      *  The number of bytes buffered is the number passed to buffer()
     36      *  after the last call to flush().
     37      */
     38     const char* get() const;
     39 
     40     /**
     41      *  Buffer from the stream into our buffer.
     42      *
     43      *  If this call returns true, get() can be used to access |bytes| bytes
     44      *  from the stream. In addition, markPosition() can be called to mark this
     45      *  position and enable calling getAtPosition() later to retrieve |bytes|
     46      *  bytes.
     47      *
     48      *  @param bytes Total number of bytes desired.
     49      *
     50      *  @return Whether all bytes were successfully buffered.
     51      */
     52     bool buffer(size_t bytes);
     53 
     54     /**
     55      *  Flush the buffer.
     56      *
     57      *  After this call, no bytes are buffered.
     58      */
     59     void flush() {
     60         if (fHasLengthAndPosition) {
     61             if (fTrulyBuffered < fBytesBuffered) {
     62                 fStream->move(fBytesBuffered - fTrulyBuffered);
     63             }
     64             fTrulyBuffered = 0;
     65         }
     66         fPosition += fBytesBuffered;
     67         fBytesBuffered = 0;
     68     }
     69 
     70     /**
     71      *  Mark the current position in the stream to return to it later.
     72      *
     73      *  This is the position of the start of the buffer. After this call, a
     74      *  a client can call getDataAtPosition to retrieve all the bytes currently
     75      *  buffered.
     76      *
     77      *  @return size_t Position which can be passed to getDataAtPosition later
     78      *      to retrieve the data currently buffered.
     79      */
     80     size_t markPosition();
     81 
     82     /**
     83      *  Retrieve data at position, as previously marked by markPosition().
     84      *
     85      *  @param position Position to retrieve data, as marked by markPosition().
     86      *  @param length   Amount of data required at position.
     87      *  @return SkData The data at position.
     88      */
     89     sk_sp<SkData> getDataAtPosition(size_t position, size_t length);
     90 
     91 private:
     92     static constexpr size_t kMaxSize = 256 * 3;
     93 
     94     std::unique_ptr<SkStream>   fStream;
     95     size_t                      fPosition;
     96     char                        fBuffer[kMaxSize];
     97     size_t                      fBytesBuffered;
     98     // If the stream has a length and position, we can make two optimizations:
     99     // - We can skip buffering
    100     // - During parsing, we can store the position and size of data that is
    101     //   needed later during decoding.
    102     const bool                  fHasLengthAndPosition;
    103     // When fHasLengthAndPosition is true, we do not need to actually buffer
    104     // inside buffer(). We'll buffer inside get(). This keeps track of how many
    105     // bytes we've buffered inside get(), for the (non-existent) case of:
    106     //  buffer(n)
    107     //  get()
    108     //  buffer(n + u)
    109     //  get()
    110     // The second call to get() needs to only truly buffer the part that was
    111     // not already buffered.
    112     mutable size_t              fTrulyBuffered;
    113     // Only used if !fHasLengthAndPosition. In that case, markPosition will
    114     // copy into an SkData, stored here.
    115     SkTHashMap<size_t, SkData*> fMarkedData;
    116 };
    117 #endif // SkStreamBuffer_DEFINED
    118 
    119