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