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 #include "puffin/src/include/puffin/puffer.h" 6 7 #include <algorithm> 8 #include <memory> 9 #include <string> 10 #include <utility> 11 #include <vector> 12 13 #include "puffin/src/bit_reader.h" 14 #include "puffin/src/huffman_table.h" 15 #include "puffin/src/include/puffin/common.h" 16 #include "puffin/src/include/puffin/stream.h" 17 #include "puffin/src/puff_data.h" 18 #include "puffin/src/puff_writer.h" 19 #include "puffin/src/set_errors.h" 20 21 namespace puffin { 22 23 using std::vector; 24 using std::string; 25 26 Puffer::Puffer() : dyn_ht_(new HuffmanTable()), fix_ht_(new HuffmanTable()) {} 27 28 Puffer::~Puffer() {} 29 30 bool Puffer::PuffDeflate(BitReaderInterface* br, 31 PuffWriterInterface* pw, 32 vector<BitExtent>* deflates, 33 Error* error) const { 34 *error = Error::kSuccess; 35 PuffData pd; 36 HuffmanTable* cur_ht; 37 // No bits left to read, return. We try to cache at least eight bits because 38 // the minimum length of a deflate bit stream is 8: (fixed huffman table) 3 39 // bits header + 5 bits just one len/dist symbol. 40 while (br->CacheBits(8)) { 41 auto start_bit_offset = br->OffsetInBits(); 42 43 TEST_AND_RETURN_FALSE_SET_ERROR(br->CacheBits(3), 44 Error::kInsufficientInput); 45 uint8_t final_bit = br->ReadBits(1); // BFINAL 46 br->DropBits(1); 47 uint8_t type = br->ReadBits(2); // BTYPE 48 br->DropBits(2); 49 DVLOG(2) << "Read block type: " 50 << BlockTypeToString(static_cast<BlockType>(type)); 51 52 // Header structure 53 // +-+-+-+-+-+-+-+-+ 54 // |F| TP| SKIP | 55 // +-+-+-+-+-+-+-+-+ 56 // F -> final_bit 57 // TP -> type 58 // SKIP -> skipped_bits (only in kUncompressed type) 59 auto block_header = (final_bit << 7) | (type << 5); 60 switch (static_cast<BlockType>(type)) { 61 case BlockType::kUncompressed: { 62 auto skipped_bits = br->ReadBoundaryBits(); 63 br->SkipBoundaryBits(); 64 TEST_AND_RETURN_FALSE_SET_ERROR(br->CacheBits(32), 65 Error::kInsufficientInput); 66 auto len = br->ReadBits(16); // LEN 67 br->DropBits(16); 68 auto nlen = br->ReadBits(16); // NLEN 69 br->DropBits(16); 70 71 if ((len ^ nlen) != 0xFFFF) { 72 LOG(ERROR) << "Length of uncompressed data is invalid;" 73 << " LEN(" << len << ") NLEN(" << nlen << ")"; 74 *error = Error::kInvalidInput; 75 return false; 76 } 77 78 // Put skipped bits into header. 79 block_header |= skipped_bits; 80 81 // Insert block header. 82 pd.type = PuffData::Type::kBlockMetadata; 83 pd.block_metadata[0] = block_header; 84 pd.length = 1; 85 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 86 87 // Insert all the raw literals. 88 pd.type = PuffData::Type::kLiterals; 89 pd.length = len; 90 TEST_AND_RETURN_FALSE_SET_ERROR( 91 br->GetByteReaderFn(pd.length, &pd.read_fn), 92 Error::kInsufficientInput); 93 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 94 95 pd.type = PuffData::Type::kEndOfBlock; 96 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 97 98 if (deflates != nullptr) { 99 deflates->emplace_back(start_bit_offset, 100 br->OffsetInBits() - start_bit_offset); 101 } 102 103 // continue the loop. Do not read any literal/length/distance. 104 continue; 105 } 106 107 case BlockType::kFixed: 108 fix_ht_->BuildFixedHuffmanTable(); 109 cur_ht = fix_ht_.get(); 110 pd.type = PuffData::Type::kBlockMetadata; 111 pd.block_metadata[0] = block_header; 112 pd.length = 1; 113 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 114 break; 115 116 case BlockType::kDynamic: 117 pd.type = PuffData::Type::kBlockMetadata; 118 pd.block_metadata[0] = block_header; 119 pd.length = sizeof(pd.block_metadata) - 1; 120 TEST_AND_RETURN_FALSE(dyn_ht_->BuildDynamicHuffmanTable( 121 br, &pd.block_metadata[1], &pd.length, error)); 122 pd.length += 1; // For the header. 123 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 124 cur_ht = dyn_ht_.get(); 125 break; 126 127 default: 128 LOG(ERROR) << "Invalid block compression type: " 129 << static_cast<int>(type); 130 *error = Error::kInvalidInput; 131 return false; 132 } 133 134 while (true) { // Breaks when the end of block is reached. 135 auto max_bits = cur_ht->LitLenMaxBits(); 136 if (!br->CacheBits(max_bits)) { 137 // It could be the end of buffer and the bit length of the end_of_block 138 // symbol has less than maximum bit length of current Huffman table. So 139 // only asking for the size of end of block symbol (256). 140 TEST_AND_RETURN_FALSE_SET_ERROR(cur_ht->EndOfBlockBitLength(&max_bits), 141 Error::kInvalidInput); 142 } 143 TEST_AND_RETURN_FALSE_SET_ERROR(br->CacheBits(max_bits), 144 Error::kInsufficientInput); 145 auto bits = br->ReadBits(max_bits); 146 uint16_t lit_len_alphabet; 147 size_t nbits; 148 TEST_AND_RETURN_FALSE_SET_ERROR( 149 cur_ht->LitLenAlphabet(bits, &lit_len_alphabet, &nbits), 150 Error::kInvalidInput); 151 br->DropBits(nbits); 152 if (lit_len_alphabet < 256) { 153 pd.type = PuffData::Type::kLiteral; 154 pd.byte = lit_len_alphabet; 155 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 156 157 } else if (256 == lit_len_alphabet) { 158 pd.type = PuffData::Type::kEndOfBlock; 159 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 160 if (deflates != nullptr) { 161 deflates->emplace_back(start_bit_offset, 162 br->OffsetInBits() - start_bit_offset); 163 } 164 break; // Breaks the loop. 165 } else { 166 TEST_AND_RETURN_FALSE_SET_ERROR(lit_len_alphabet <= 285, 167 Error::kInvalidInput); 168 // Reading length. 169 auto len_code_start = lit_len_alphabet - 257; 170 auto extra_bits_len = kLengthExtraBits[len_code_start]; 171 uint16_t extra_bits_value = 0; 172 if (extra_bits_len) { 173 TEST_AND_RETURN_FALSE_SET_ERROR(br->CacheBits(extra_bits_len), 174 Error::kInsufficientInput); 175 extra_bits_value = br->ReadBits(extra_bits_len); 176 br->DropBits(extra_bits_len); 177 } 178 auto length = kLengthBases[len_code_start] + extra_bits_value; 179 180 TEST_AND_RETURN_FALSE_SET_ERROR( 181 br->CacheBits(cur_ht->DistanceMaxBits()), 182 Error::kInsufficientInput); 183 auto bits = br->ReadBits(cur_ht->DistanceMaxBits()); 184 uint16_t distance_alphabet; 185 size_t nbits; 186 TEST_AND_RETURN_FALSE_SET_ERROR( 187 cur_ht->DistanceAlphabet(bits, &distance_alphabet, &nbits), 188 Error::kInvalidInput); 189 br->DropBits(nbits); 190 191 // Reading distance. 192 extra_bits_len = kDistanceExtraBits[distance_alphabet]; 193 extra_bits_value = 0; 194 if (extra_bits_len) { 195 TEST_AND_RETURN_FALSE_SET_ERROR(br->CacheBits(extra_bits_len), 196 Error::kInsufficientInput); 197 extra_bits_value = br->ReadBits(extra_bits_len); 198 br->DropBits(extra_bits_len); 199 } 200 201 pd.type = PuffData::Type::kLenDist; 202 pd.length = length; 203 pd.distance = kDistanceBases[distance_alphabet] + extra_bits_value; 204 TEST_AND_RETURN_FALSE(pw->Insert(pd, error)); 205 } 206 } 207 } 208 TEST_AND_RETURN_FALSE(pw->Flush(error)); 209 return true; 210 } 211 212 } // namespace puffin 213