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