blob: 3ae470b9bdd4715c3942d0c9c3e1b310e4e2c64d [file] [log] [blame]
Amin Hassanic3e6b532017-03-07 17:47:25 -08001// 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/utils.h"
6
7#include <inttypes.h>
8
9#include <string>
10#include <vector>
11
12#include "puffin/src/bit_reader.h"
13#include "puffin/src/include/puffin/common.h"
14#include "puffin/src/include/puffin/stream.h"
15#include "puffin/src/set_errors.h"
16
17namespace puffin {
18
19using std::string;
20using std::vector;
21
22string ByteExtentsToString(const vector<ByteExtent>& extents) {
23 string str;
24 for (const auto& extent : extents)
25 str += std::to_string(extent.offset) + ":" + std::to_string(extent.length) +
26 ",";
27 return str;
28}
29
30size_t BytesInByteExtents(const vector<ByteExtent>& extents) {
31 size_t bytes = 0;
32 for (const auto& extent : extents) {
33 bytes += extent.length;
34 }
35 return bytes;
36}
37
38// This function uses RFC1950 (https://www.ietf.org/rfc/rfc1950.txt) for the
39// definition of a zlib stream.
40bool LocateDeflatesInZlibBlocks(const UniqueStreamPtr& src,
41 const vector<ByteExtent>& zlibs,
42 vector<ByteExtent>* deflates) {
43 for (auto& zlib : zlibs) {
44 TEST_AND_RETURN_FALSE(src->Seek(zlib.offset));
45 uint16_t zlib_header;
46 TEST_AND_RETURN_FALSE(src->Read(&zlib_header, 2));
47 BufferBitReader br(reinterpret_cast<uint8_t*>(&zlib_header), 2);
48
49 TEST_AND_RETURN_FALSE(br.CacheBits(8));
50 auto cmf = br.ReadBits(8);
51 auto cm = br.ReadBits(4);
52 if (cm != 8 && cm != 15) {
53 LOG(ERROR) << "Invalid compression method! cm: " << cm;
54 return false;
55 }
56 br.DropBits(4);
57 auto cinfo = br.ReadBits(4);
58 if (cinfo > 7) {
59 LOG(ERROR) << "cinfo greater than 7 is not allowed in deflate";
60 return false;
61 }
62 br.DropBits(4);
63
64 TEST_AND_RETURN_FALSE(br.CacheBits(8));
65 auto flg = br.ReadBits(8);
66 if (((cmf << 8) + flg) % 31) {
67 LOG(ERROR) << "Invalid zlib header on offset: " << zlib.offset;
68 return false;
69 }
70 br.ReadBits(5); // FCHECK
71 br.DropBits(5);
72
73 auto fdict = br.ReadBits(1);
74 br.DropBits(1);
75
76 br.ReadBits(2); // FLEVEL
77 br.DropBits(2);
78
79 auto header_len = 2;
80 if (fdict) {
81 TEST_AND_RETURN_FALSE(br.CacheBits(32));
82 br.DropBits(32);
83 header_len += 4;
84 }
85
86 ByteExtent deflate;
87 deflate.offset = zlib.offset + header_len;
88 deflate.length = zlib.length - header_len - 4;
89 deflates->push_back(deflate);
90 }
91 return true;
92}
93
94} // namespace puffin