1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 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 "src/pdf/SkJpegInfo.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#ifndef SK_CODEC_DECODES_JPEG 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_cinamespace { 15cb93a386Sopenharmony_ciclass JpegSegment { 16cb93a386Sopenharmony_cipublic: 17cb93a386Sopenharmony_ci JpegSegment(const void* data, size_t size) 18cb93a386Sopenharmony_ci : fData(static_cast<const char*>(data)) 19cb93a386Sopenharmony_ci , fSize(size) 20cb93a386Sopenharmony_ci , fOffset(0) 21cb93a386Sopenharmony_ci , fLength(0) {} 22cb93a386Sopenharmony_ci bool read() { 23cb93a386Sopenharmony_ci if (!this->readBigendianUint16(&fMarker)) { 24cb93a386Sopenharmony_ci return false; 25cb93a386Sopenharmony_ci } 26cb93a386Sopenharmony_ci if (JpegSegment::StandAloneMarker(fMarker)) { 27cb93a386Sopenharmony_ci fLength = 0; 28cb93a386Sopenharmony_ci fBuffer = nullptr; 29cb93a386Sopenharmony_ci return true; 30cb93a386Sopenharmony_ci } 31cb93a386Sopenharmony_ci if (!this->readBigendianUint16(&fLength) || fLength < 2) { 32cb93a386Sopenharmony_ci return false; 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci fLength -= 2; // Length includes itself for some reason. 35cb93a386Sopenharmony_ci if (fOffset + fLength > fSize) { 36cb93a386Sopenharmony_ci return false; // Segment too long. 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci fBuffer = &fData[fOffset]; 39cb93a386Sopenharmony_ci fOffset += fLength; 40cb93a386Sopenharmony_ci return true; 41cb93a386Sopenharmony_ci } 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci bool isSOF() { 44cb93a386Sopenharmony_ci return (fMarker & 0xFFF0) == 0xFFC0 && fMarker != 0xFFC4 && 45cb93a386Sopenharmony_ci fMarker != 0xFFC8 && fMarker != 0xFFCC; 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci uint16_t marker() { return fMarker; } 48cb93a386Sopenharmony_ci uint16_t length() { return fLength; } 49cb93a386Sopenharmony_ci const char* data() { return fBuffer; } 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci static uint16_t GetBigendianUint16(const char* ptr) { 52cb93a386Sopenharmony_ci // "the most significant byte shall come first" 53cb93a386Sopenharmony_ci return (static_cast<uint8_t>(ptr[0]) << 8) | 54cb93a386Sopenharmony_ci static_cast<uint8_t>(ptr[1]); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ciprivate: 58cb93a386Sopenharmony_ci const char* const fData; 59cb93a386Sopenharmony_ci const size_t fSize; 60cb93a386Sopenharmony_ci size_t fOffset; 61cb93a386Sopenharmony_ci const char* fBuffer; 62cb93a386Sopenharmony_ci uint16_t fMarker; 63cb93a386Sopenharmony_ci uint16_t fLength; 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci bool readBigendianUint16(uint16_t* value) { 66cb93a386Sopenharmony_ci if (fOffset + 2 > fSize) { 67cb93a386Sopenharmony_ci return false; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci *value = JpegSegment::GetBigendianUint16(&fData[fOffset]); 70cb93a386Sopenharmony_ci fOffset += 2; 71cb93a386Sopenharmony_ci return true; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci static bool StandAloneMarker(uint16_t marker) { 74cb93a386Sopenharmony_ci // RST[m] markers or SOI, EOI, TEM 75cb93a386Sopenharmony_ci return (marker & 0xFFF8) == 0xFFD0 || marker == 0xFFD8 || 76cb93a386Sopenharmony_ci marker == 0xFFD9 || marker == 0xFF01; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci}; 79cb93a386Sopenharmony_ci} // namespace 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_cibool SkGetJpegInfo(const void* data, size_t len, 82cb93a386Sopenharmony_ci SkISize* size, 83cb93a386Sopenharmony_ci SkEncodedInfo::Color* colorType, 84cb93a386Sopenharmony_ci SkEncodedOrigin* orientation) { 85cb93a386Sopenharmony_ci static const uint16_t kSOI = 0xFFD8; 86cb93a386Sopenharmony_ci static const uint16_t kAPP0 = 0xFFE0; 87cb93a386Sopenharmony_ci JpegSegment segment(data, len); 88cb93a386Sopenharmony_ci if (!segment.read() || segment.marker() != kSOI) { 89cb93a386Sopenharmony_ci return false; // not a JPEG 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci if (!segment.read() || segment.marker() != kAPP0) { 92cb93a386Sopenharmony_ci return false; // not an APP0 segment 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci static const char kJfif[] = {'J', 'F', 'I', 'F', '\0'}; 95cb93a386Sopenharmony_ci SkASSERT(segment.data()); 96cb93a386Sopenharmony_ci if (SkToSizeT(segment.length()) < sizeof(kJfif) || 97cb93a386Sopenharmony_ci 0 != memcmp(segment.data(), kJfif, sizeof(kJfif))) { 98cb93a386Sopenharmony_ci return false; // Not JFIF JPEG 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci do { 101cb93a386Sopenharmony_ci if (!segment.read()) { 102cb93a386Sopenharmony_ci return false; // malformed JPEG 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci } while (!segment.isSOF()); 105cb93a386Sopenharmony_ci if (segment.length() < 6) { 106cb93a386Sopenharmony_ci return false; // SOF segment is short 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci if (8 != segment.data()[0]) { 109cb93a386Sopenharmony_ci return false; // Only support 8-bit precision 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci int numberOfComponents = segment.data()[5]; 112cb93a386Sopenharmony_ci if (numberOfComponents != 1 && numberOfComponents != 3) { 113cb93a386Sopenharmony_ci return false; // Invalid JFIF 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci if (size) { 116cb93a386Sopenharmony_ci *size = {JpegSegment::GetBigendianUint16(&segment.data()[3]), 117cb93a386Sopenharmony_ci JpegSegment::GetBigendianUint16(&segment.data()[1])}; 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci if (colorType) { 120cb93a386Sopenharmony_ci *colorType = numberOfComponents == 3 ? SkEncodedInfo::kYUV_Color 121cb93a386Sopenharmony_ci : SkEncodedInfo::kGray_Color; 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci if (orientation) { 124cb93a386Sopenharmony_ci *orientation = kTopLeft_SkEncodedOrigin; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci return true; 127cb93a386Sopenharmony_ci} 128cb93a386Sopenharmony_ci#endif // SK_CODEC_DECODES_JPEG 129