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