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