1 | /* |
2 | * Copyright 2018 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 | #include "include/core/SkTypes.h" |
9 | #include "src/codec/SkCodecPriv.h" |
10 | |
11 | bool SkParseEncodedOrigin(const uint8_t* data, size_t data_length, SkEncodedOrigin* orientation) { |
12 | SkASSERT(orientation); |
13 | bool littleEndian; |
14 | // We need eight bytes to read the endian marker and the offset, below. |
15 | if (data_length < 8 || !is_valid_endian_marker(data, &littleEndian)) { |
16 | return false; |
17 | } |
18 | |
19 | auto getEndianInt = [](const uint8_t* data, bool littleEndian) -> uint32_t { |
20 | if (littleEndian) { |
21 | return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0]); |
22 | } |
23 | |
24 | return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]); |
25 | }; |
26 | |
27 | // Get the offset from the start of the marker. |
28 | // Though this only reads four bytes, use a larger int in case it overflows. |
29 | uint64_t offset = getEndianInt(data + 4, littleEndian); |
30 | |
31 | // Require that the marker is at least large enough to contain the number of entries. |
32 | if (data_length < offset + 2) { |
33 | return false; |
34 | } |
35 | uint32_t numEntries = get_endian_short(data + offset, littleEndian); |
36 | |
37 | // Tag (2 bytes), Datatype (2 bytes), Number of elements (4 bytes), Data (4 bytes) |
38 | const uint32_t kEntrySize = 12; |
39 | const auto max = SkTo<uint32_t>((data_length - offset - 2) / kEntrySize); |
40 | numEntries = std::min(numEntries, max); |
41 | |
42 | // Advance the data to the start of the entries. |
43 | data += offset + 2; |
44 | |
45 | const uint16_t kOriginTag = 0x112; |
46 | const uint16_t kOriginType = 3; |
47 | for (uint32_t i = 0; i < numEntries; i++, data += kEntrySize) { |
48 | uint16_t tag = get_endian_short(data, littleEndian); |
49 | uint16_t type = get_endian_short(data + 2, littleEndian); |
50 | uint32_t count = getEndianInt(data + 4, littleEndian); |
51 | if (kOriginTag == tag && kOriginType == type && 1 == count) { |
52 | uint16_t val = get_endian_short(data + 8, littleEndian); |
53 | if (0 < val && val <= kLast_SkEncodedOrigin) { |
54 | *orientation = (SkEncodedOrigin) val; |
55 | return true; |
56 | } |
57 | } |
58 | } |
59 | |
60 | return false; |
61 | } |
62 | |