Home | History | Annotate | Download | only in src
      1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef SRC_PUFFIN_STREAM_H_
      6 #define SRC_PUFFIN_STREAM_H_
      7 
      8 #include <list>
      9 #include <memory>
     10 #include <string>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "puffin/src/include/puffin/common.h"
     15 #include "puffin/src/include/puffin/huffer.h"
     16 #include "puffin/src/include/puffin/puffer.h"
     17 #include "puffin/src/include/puffin/stream.h"
     18 
     19 namespace puffin {
     20 
     21 // A class for puffing a deflate stream and huffing into a deflate stream. The
     22 // puff stream is "imaginary", which means it doesn't really exists; It is build
     23 // and used on demand. This class uses a given deflate stream, and puffs the
     24 // deflate buffers in the stream as needed or vice versa.  An object of this
     25 // class can be used for reading and writing puff data but should not be used
     26 // for both reading and writing using the same instance. In theory we can
     27 // separate this class into two classes, namely |PuffStream| and |HuffStream|,
     28 // but they are sharing a lot of codes which might be inconvenient and
     29 // unnecessary to do so. In this implementation, there is no protection against
     30 // reading and writing at the same time.
     31 class PuffinStream : public StreamInterface {
     32  public:
     33   ~PuffinStream() override = default;
     34 
     35   // Creates a |PuffinStream| for reading puff buffers from a deflate stream.
     36   // |stream|    IN  The deflate stream.
     37   // |puffer|    IN  The |Puffer| used for puffing the stream.
     38   // |puff_size| IN  The size of the puff stream (assuming |stream| has been
     39   //                 completely puffed.
     40   // |deflates|  IN  The location of deflates in |stream|.
     41   // |puffs|     IN  The location of puffs into the final puff stream.
     42   // |max_cache_size| IN  The amount of memory to use for caching puff buffers.
     43   //                      If the mount is smaller than the maximum puff buffer
     44   //                      size in |puffs|, then its value will be set to zero
     45   //                      and no puff will be cached.
     46   static UniqueStreamPtr CreateForPuff(UniqueStreamPtr stream,
     47                                        std::shared_ptr<Puffer> puffer,
     48                                        uint64_t puff_size,
     49                                        const std::vector<BitExtent>& deflates,
     50                                        const std::vector<ByteExtent>& puffs,
     51                                        size_t max_cache_size = 0);
     52 
     53   // Creates a |PuffinStream| for writing puff buffers into a deflate stream.
     54   // |stream|    IN  The deflate stream.
     55   // |huffer|    IN  The |Huffer| used for huffing into the |stream|.
     56   // |puff_size| IN  The size of the puff stream (assuming |stream| has been
     57   //                 completely puffed.
     58   // |deflates|  IN  The location of deflates in |stream|.
     59   // |puffs|     IN  The location of puffs into the input puff stream.
     60   static UniqueStreamPtr CreateForHuff(UniqueStreamPtr stream,
     61                                        std::shared_ptr<Huffer> huffer,
     62                                        uint64_t puff_size,
     63                                        const std::vector<BitExtent>& deflates,
     64                                        const std::vector<ByteExtent>& puffs);
     65 
     66   bool GetSize(uint64_t* size) const override;
     67 
     68   // Returns the current offset in the imaginary puff stream.
     69   bool GetOffset(uint64_t* offset) const override;
     70 
     71   // Sets the current offset in the imaginary puff stream.
     72   bool Seek(uint64_t offset) override;
     73 
     74   // Reads from the deflate stream |stream_| and writes the puff stream into
     75   // |buffer|.
     76   bool Read(void* buffer, size_t length) override;
     77 
     78   // Reads the puff stream from |buffer|, huffs it and writes it into the
     79   // deflate stream |stream_|. The current assumption for write is that data is
     80   // wrote from beginning to end with no retraction or random change of offset.
     81   // This function, writes non-puff data directly to |stream_| and caches the
     82   // puff data into |puff_buffer_|. When |puff_buffer_| is full, it huffs it
     83   // into |deflate_buffer_| and writes it to |stream_|.
     84   bool Write(const void* buffer, size_t length) override;
     85 
     86   bool Close() override;
     87 
     88  protected:
     89   // The non-public internal Ctor.
     90   PuffinStream(UniqueStreamPtr stream,
     91                std::shared_ptr<Puffer> puffer,
     92                std::shared_ptr<Huffer> huffer,
     93                uint64_t puff_size,
     94                const std::vector<BitExtent>& deflates,
     95                const std::vector<ByteExtent>& puffs,
     96                size_t max_cache_size);
     97 
     98  private:
     99   // See |extra_byte_|.
    100   bool SetExtraByte();
    101 
    102   // Returns the cache for the |puff_id|th puff. If it does not find it, either
    103   // returns the least accessed cached (if cache is full) or creates a new empty
    104   // buffer. It returns false if it cannot find the |puff_id|th puff cache.
    105   bool GetPuffCache(int puff_id, uint64_t puff_size, SharedBufferPtr* buffer);
    106 
    107   UniqueStreamPtr stream_;
    108 
    109   std::shared_ptr<Puffer> puffer_;
    110   std::shared_ptr<Huffer> huffer_;
    111 
    112   // The size of the imaginary puff stream.
    113   uint64_t puff_stream_size_;
    114 
    115   std::vector<BitExtent> deflates_;
    116   // The current deflate is being processed.
    117   std::vector<BitExtent>::iterator cur_deflate_;
    118 
    119   std::vector<ByteExtent> puffs_;
    120   // The current puff is being processed.
    121   std::vector<ByteExtent>::iterator cur_puff_;
    122 
    123   std::vector<uint64_t> upper_bounds_;
    124 
    125   // The current offset in the imaginary puff stream is |puff_pos_| +
    126   // |skip_bytes_|
    127   uint64_t puff_pos_;
    128   uint64_t skip_bytes_;
    129 
    130   // The current bit offset in |stream_|.
    131   uint64_t deflate_bit_pos_;
    132 
    133   // This value caches the first or last byte of a deflate stream. This is
    134   // needed when two deflate stream end on the same byte (with greater than zero
    135   // bit offset difference) or a deflate starts from middle of the byte. We need
    136   // to cache the value in here before we have the rest of the puff buffer to
    137   // make the deflate.
    138   uint8_t last_byte_;
    139 
    140   // We have to figure out if we need to cache an extra puff byte for the last
    141   // byte of the deflate. This is only needed if the last bit of the current
    142   // deflate is not in the same byte as the first bit of the next deflate. The
    143   // value is either 0 or 1. If 1.
    144   size_t extra_byte_;
    145 
    146   // True if the stream is only for puffing. False if for huffing.
    147   bool is_for_puff_;
    148 
    149   // True if the |Close()| is called.
    150   bool closed_;
    151 
    152   UniqueBufferPtr deflate_buffer_;
    153   SharedBufferPtr puff_buffer_;
    154 
    155   // The list of puff buffer caches.
    156   std::list<std::pair<int, SharedBufferPtr>> caches_;
    157   // The maximum memory (in bytes) kept for caching puff buffers by an object of
    158   // this class.
    159   size_t max_cache_size_;
    160   // The current amount of memory (in bytes) used for caching puff buffers.
    161   uint64_t cur_cache_size_;
    162 
    163   DISALLOW_COPY_AND_ASSIGN(PuffinStream);
    164 };
    165 
    166 }  // namespace puffin
    167 
    168 #endif  // SRC_PUFFIN_STREAM_H_
    169