• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,
106                     uint64_t puff_size,
107                     std::shared_ptr<Buffer>* buffer);
108 
109   UniqueStreamPtr stream_;
110 
111   std::shared_ptr<Puffer> puffer_;
112   std::shared_ptr<Huffer> huffer_;
113 
114   // The size of the imaginary puff stream.
115   uint64_t puff_stream_size_;
116 
117   std::vector<BitExtent> deflates_;
118   // The current deflate is being processed.
119   std::vector<BitExtent>::iterator cur_deflate_;
120 
121   std::vector<ByteExtent> puffs_;
122   // The current puff is being processed.
123   std::vector<ByteExtent>::iterator cur_puff_;
124 
125   std::vector<uint64_t> upper_bounds_;
126 
127   // The current offset in the imaginary puff stream is |puff_pos_| +
128   // |skip_bytes_|
129   uint64_t puff_pos_;
130   uint64_t skip_bytes_;
131 
132   // The current bit offset in |stream_|.
133   uint64_t deflate_bit_pos_;
134 
135   // This value caches the first or last byte of a deflate stream. This is
136   // needed when two deflate stream end on the same byte (with greater than zero
137   // bit offset difference) or a deflate starts from middle of the byte. We need
138   // to cache the value in here before we have the rest of the puff buffer to
139   // make the deflate.
140   uint8_t last_byte_;
141 
142   // We have to figure out if we need to cache an extra puff byte for the last
143   // byte of the deflate. This is only needed if the last bit of the current
144   // deflate is not in the same byte as the first bit of the next deflate. The
145   // value is either 0 or 1. If 1.
146   size_t extra_byte_;
147 
148   // True if the stream is only for puffing. False if for huffing.
149   bool is_for_puff_;
150 
151   // True if the |Close()| is called.
152   bool closed_;
153 
154   std::unique_ptr<Buffer> deflate_buffer_;
155   std::shared_ptr<Buffer> puff_buffer_;
156 
157   // The list of puff buffer caches.
158   std::list<std::pair<int, std::shared_ptr<Buffer>>> caches_;
159   // The maximum memory (in bytes) kept for caching puff buffers by an object of
160   // this class.
161   size_t max_cache_size_;
162   // The current amount of memory (in bytes) used for caching puff buffers.
163   uint64_t cur_cache_size_;
164 
165   DISALLOW_COPY_AND_ASSIGN(PuffinStream);
166 };
167 
168 }  // namespace puffin
169 
170 #endif  // SRC_PUFFIN_STREAM_H_
171