1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkJpegSegmentScan.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkCodecPriv.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkJpegConstants.h"
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
17*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
20*c8dee2aaSAndroid Build Coastguard Worker // SkJpegSegmentScanner
21*c8dee2aaSAndroid Build Coastguard Worker
SkJpegSegmentScanner(uint8_t stopMarker)22*c8dee2aaSAndroid Build Coastguard Worker SkJpegSegmentScanner::SkJpegSegmentScanner(uint8_t stopMarker) : fStopMarker(stopMarker) {}
23*c8dee2aaSAndroid Build Coastguard Worker
getSegments() const24*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkJpegSegment>& SkJpegSegmentScanner::getSegments() const { return fSegments; }
25*c8dee2aaSAndroid Build Coastguard Worker
GetParameters(const SkData * scannedData,const SkJpegSegment & segment)26*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> SkJpegSegmentScanner::GetParameters(const SkData* scannedData,
27*c8dee2aaSAndroid Build Coastguard Worker const SkJpegSegment& segment) {
28*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeSubset(
29*c8dee2aaSAndroid Build Coastguard Worker scannedData,
30*c8dee2aaSAndroid Build Coastguard Worker segment.offset + kJpegMarkerCodeSize + kJpegSegmentParameterLengthSize,
31*c8dee2aaSAndroid Build Coastguard Worker segment.parameterLength - kJpegSegmentParameterLengthSize);
32*c8dee2aaSAndroid Build Coastguard Worker }
33*c8dee2aaSAndroid Build Coastguard Worker
onBytes(const void * data,size_t size)34*c8dee2aaSAndroid Build Coastguard Worker void SkJpegSegmentScanner::onBytes(const void* data, size_t size) {
35*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
36*c8dee2aaSAndroid Build Coastguard Worker size_t bytesRemaining = size;
37*c8dee2aaSAndroid Build Coastguard Worker
38*c8dee2aaSAndroid Build Coastguard Worker while (bytesRemaining > 0) {
39*c8dee2aaSAndroid Build Coastguard Worker // Process the data byte-by-byte, unless we are in kSegmentParam or kEntropyCodedData, in
40*c8dee2aaSAndroid Build Coastguard Worker // which case, perform some optimizations to avoid examining every byte.
41*c8dee2aaSAndroid Build Coastguard Worker size_t bytesToMoveForward = 0;
42*c8dee2aaSAndroid Build Coastguard Worker switch (fState) {
43*c8dee2aaSAndroid Build Coastguard Worker case State::kSegmentParam: {
44*c8dee2aaSAndroid Build Coastguard Worker // Skip forward through payloads.
45*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fSegmentParamBytesRemaining > 0);
46*c8dee2aaSAndroid Build Coastguard Worker bytesToMoveForward = std::min(fSegmentParamBytesRemaining, bytesRemaining);
47*c8dee2aaSAndroid Build Coastguard Worker fSegmentParamBytesRemaining -= bytesToMoveForward;
48*c8dee2aaSAndroid Build Coastguard Worker if (fSegmentParamBytesRemaining == 0) {
49*c8dee2aaSAndroid Build Coastguard Worker fState = State::kEntropyCodedData;
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker break;
52*c8dee2aaSAndroid Build Coastguard Worker }
53*c8dee2aaSAndroid Build Coastguard Worker case State::kEntropyCodedData: {
54*c8dee2aaSAndroid Build Coastguard Worker // Skip through entropy-coded data, only looking at sentinel characters.
55*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* sentinel =
56*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(memchr(bytes, 0xFF, bytesRemaining));
57*c8dee2aaSAndroid Build Coastguard Worker if (sentinel) {
58*c8dee2aaSAndroid Build Coastguard Worker bytesToMoveForward = (sentinel - bytes) + 1;
59*c8dee2aaSAndroid Build Coastguard Worker fState = State::kEntropyCodedDataSentinel;
60*c8dee2aaSAndroid Build Coastguard Worker } else {
61*c8dee2aaSAndroid Build Coastguard Worker bytesToMoveForward = bytesRemaining;
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker break;
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker case State::kDone:
66*c8dee2aaSAndroid Build Coastguard Worker // Skip all data after we have hit our stop marker.
67*c8dee2aaSAndroid Build Coastguard Worker bytesToMoveForward = bytesRemaining;
68*c8dee2aaSAndroid Build Coastguard Worker break;
69*c8dee2aaSAndroid Build Coastguard Worker default: {
70*c8dee2aaSAndroid Build Coastguard Worker onByte(*bytes);
71*c8dee2aaSAndroid Build Coastguard Worker bytesToMoveForward = 1;
72*c8dee2aaSAndroid Build Coastguard Worker break;
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker }
75*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(bytesToMoveForward > 0);
76*c8dee2aaSAndroid Build Coastguard Worker fOffset += bytesToMoveForward;
77*c8dee2aaSAndroid Build Coastguard Worker bytes += bytesToMoveForward;
78*c8dee2aaSAndroid Build Coastguard Worker bytesRemaining -= bytesToMoveForward;
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker }
81*c8dee2aaSAndroid Build Coastguard Worker
saveCurrentSegment(uint16_t length)82*c8dee2aaSAndroid Build Coastguard Worker void SkJpegSegmentScanner::saveCurrentSegment(uint16_t length) {
83*c8dee2aaSAndroid Build Coastguard Worker SkJpegSegment s = {fCurrentSegmentOffset, fCurrentSegmentMarker, length};
84*c8dee2aaSAndroid Build Coastguard Worker fSegments.push_back(s);
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker fCurrentSegmentMarker = 0;
87*c8dee2aaSAndroid Build Coastguard Worker fCurrentSegmentOffset = 0;
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker
onMarkerSecondByte(uint8_t byte)90*c8dee2aaSAndroid Build Coastguard Worker void SkJpegSegmentScanner::onMarkerSecondByte(uint8_t byte) {
91*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fState == State::kStartOfImageByte1 || fState == State::kSecondMarkerByte1 ||
92*c8dee2aaSAndroid Build Coastguard Worker fState == State::kEntropyCodedDataSentinel ||
93*c8dee2aaSAndroid Build Coastguard Worker fState == State::kPostEntropyCodedDataFill);
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker fCurrentSegmentMarker = byte;
96*c8dee2aaSAndroid Build Coastguard Worker fCurrentSegmentOffset = fOffset - 1;
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker if (byte == fStopMarker) {
99*c8dee2aaSAndroid Build Coastguard Worker saveCurrentSegment(0);
100*c8dee2aaSAndroid Build Coastguard Worker fState = State::kDone;
101*c8dee2aaSAndroid Build Coastguard Worker } else if (byte == kJpegMarkerStartOfImage) {
102*c8dee2aaSAndroid Build Coastguard Worker saveCurrentSegment(0);
103*c8dee2aaSAndroid Build Coastguard Worker fState = State::kSecondMarkerByte0;
104*c8dee2aaSAndroid Build Coastguard Worker } else if (MarkerStandsAlone(byte)) {
105*c8dee2aaSAndroid Build Coastguard Worker saveCurrentSegment(0);
106*c8dee2aaSAndroid Build Coastguard Worker fState = State::kEntropyCodedData;
107*c8dee2aaSAndroid Build Coastguard Worker } else {
108*c8dee2aaSAndroid Build Coastguard Worker fCurrentSegmentMarker = byte;
109*c8dee2aaSAndroid Build Coastguard Worker fState = State::kSegmentParamLengthByte0;
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker
onByte(uint8_t byte)113*c8dee2aaSAndroid Build Coastguard Worker void SkJpegSegmentScanner::onByte(uint8_t byte) {
114*c8dee2aaSAndroid Build Coastguard Worker switch (fState) {
115*c8dee2aaSAndroid Build Coastguard Worker case State::kStartOfImageByte0:
116*c8dee2aaSAndroid Build Coastguard Worker if (byte != 0xFF) {
117*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("First byte was %02x, not 0xFF", byte);
118*c8dee2aaSAndroid Build Coastguard Worker fState = State::kError;
119*c8dee2aaSAndroid Build Coastguard Worker return;
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker fState = State::kStartOfImageByte1;
122*c8dee2aaSAndroid Build Coastguard Worker break;
123*c8dee2aaSAndroid Build Coastguard Worker case State::kStartOfImageByte1:
124*c8dee2aaSAndroid Build Coastguard Worker if (byte != kJpegMarkerStartOfImage) {
125*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Second byte was %02x, not %02x", byte, kJpegMarkerStartOfImage);
126*c8dee2aaSAndroid Build Coastguard Worker fState = State::kError;
127*c8dee2aaSAndroid Build Coastguard Worker return;
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker onMarkerSecondByte(byte);
130*c8dee2aaSAndroid Build Coastguard Worker break;
131*c8dee2aaSAndroid Build Coastguard Worker case State::kSecondMarkerByte0:
132*c8dee2aaSAndroid Build Coastguard Worker if (byte != 0xFF) {
133*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Third byte was %02x, not 0xFF", byte);
134*c8dee2aaSAndroid Build Coastguard Worker fState = State::kError;
135*c8dee2aaSAndroid Build Coastguard Worker return;
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker fState = State::kSecondMarkerByte1;
138*c8dee2aaSAndroid Build Coastguard Worker break;
139*c8dee2aaSAndroid Build Coastguard Worker case State::kSecondMarkerByte1:
140*c8dee2aaSAndroid Build Coastguard Worker // See section B.1.1.3: All markers are assigned two-byte codes: a 0xFF byte followed by
141*c8dee2aaSAndroid Build Coastguard Worker // a byte which is not equal to 0x00 or 0xFF.
142*c8dee2aaSAndroid Build Coastguard Worker if (byte == 0xFF || byte == 0x00) {
143*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("SkJpegSegment marker was 0xFF,0xFF or 0xFF,0x00");
144*c8dee2aaSAndroid Build Coastguard Worker fState = State::kError;
145*c8dee2aaSAndroid Build Coastguard Worker return;
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker onMarkerSecondByte(byte);
148*c8dee2aaSAndroid Build Coastguard Worker break;
149*c8dee2aaSAndroid Build Coastguard Worker case State::kSegmentParamLengthByte0:
150*c8dee2aaSAndroid Build Coastguard Worker fSegmentParamLengthByte0 = byte;
151*c8dee2aaSAndroid Build Coastguard Worker fState = State::kSegmentParamLengthByte1;
152*c8dee2aaSAndroid Build Coastguard Worker break;
153*c8dee2aaSAndroid Build Coastguard Worker case State::kSegmentParamLengthByte1: {
154*c8dee2aaSAndroid Build Coastguard Worker uint16_t paramLength = 256u * fSegmentParamLengthByte0 + byte;
155*c8dee2aaSAndroid Build Coastguard Worker fSegmentParamLengthByte0 = 0;
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker // See section B.1.1.4: A marker segment consists of a marker followed by a sequence
158*c8dee2aaSAndroid Build Coastguard Worker // of related parameters. The first parameter in a marker segment is the two-byte length
159*c8dee2aaSAndroid Build Coastguard Worker // parameter. This length parameter encodes the number of bytes in the marker segment,
160*c8dee2aaSAndroid Build Coastguard Worker // including the length parameter and excluding the two-byte marker.
161*c8dee2aaSAndroid Build Coastguard Worker if (paramLength < kJpegSegmentParameterLengthSize) {
162*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("SkJpegSegment payload length was %u < 2 bytes", paramLength);
163*c8dee2aaSAndroid Build Coastguard Worker fState = State::kError;
164*c8dee2aaSAndroid Build Coastguard Worker return;
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker saveCurrentSegment(paramLength);
167*c8dee2aaSAndroid Build Coastguard Worker fSegmentParamBytesRemaining = paramLength - kJpegSegmentParameterLengthSize;
168*c8dee2aaSAndroid Build Coastguard Worker if (fSegmentParamBytesRemaining > 0) {
169*c8dee2aaSAndroid Build Coastguard Worker fState = State::kSegmentParam;
170*c8dee2aaSAndroid Build Coastguard Worker } else {
171*c8dee2aaSAndroid Build Coastguard Worker fState = State::kEntropyCodedData;
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker break;
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker case State::kSegmentParam:
176*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fSegmentParamBytesRemaining > 0);
177*c8dee2aaSAndroid Build Coastguard Worker fSegmentParamBytesRemaining -= 1;
178*c8dee2aaSAndroid Build Coastguard Worker if (fSegmentParamBytesRemaining == 0) {
179*c8dee2aaSAndroid Build Coastguard Worker fState = State::kEntropyCodedData;
180*c8dee2aaSAndroid Build Coastguard Worker }
181*c8dee2aaSAndroid Build Coastguard Worker break;
182*c8dee2aaSAndroid Build Coastguard Worker case State::kEntropyCodedData:
183*c8dee2aaSAndroid Build Coastguard Worker if (byte == 0xFF) {
184*c8dee2aaSAndroid Build Coastguard Worker fState = State::kEntropyCodedDataSentinel;
185*c8dee2aaSAndroid Build Coastguard Worker }
186*c8dee2aaSAndroid Build Coastguard Worker break;
187*c8dee2aaSAndroid Build Coastguard Worker case State::kEntropyCodedDataSentinel:
188*c8dee2aaSAndroid Build Coastguard Worker if (byte == 0x00) {
189*c8dee2aaSAndroid Build Coastguard Worker fState = State::kEntropyCodedData;
190*c8dee2aaSAndroid Build Coastguard Worker } else if (byte == 0xFF) {
191*c8dee2aaSAndroid Build Coastguard Worker fState = State::kPostEntropyCodedDataFill;
192*c8dee2aaSAndroid Build Coastguard Worker } else {
193*c8dee2aaSAndroid Build Coastguard Worker onMarkerSecondByte(byte);
194*c8dee2aaSAndroid Build Coastguard Worker }
195*c8dee2aaSAndroid Build Coastguard Worker break;
196*c8dee2aaSAndroid Build Coastguard Worker case State::kPostEntropyCodedDataFill:
197*c8dee2aaSAndroid Build Coastguard Worker // See section B.1.1.3: Any marker may optionally be preceded by any number of fill
198*c8dee2aaSAndroid Build Coastguard Worker // bytes, which are bytes assigned code 0xFF. Skip past any 0xFF fill bytes that may be
199*c8dee2aaSAndroid Build Coastguard Worker // present at the end of the entropy-coded data.
200*c8dee2aaSAndroid Build Coastguard Worker if (byte == 0xFF) {
201*c8dee2aaSAndroid Build Coastguard Worker fState = State::kPostEntropyCodedDataFill;
202*c8dee2aaSAndroid Build Coastguard Worker } else if (byte == 0x00) {
203*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Post entropy coded data had 0xFF,0x00");
204*c8dee2aaSAndroid Build Coastguard Worker fState = State::kError;
205*c8dee2aaSAndroid Build Coastguard Worker return;
206*c8dee2aaSAndroid Build Coastguard Worker } else {
207*c8dee2aaSAndroid Build Coastguard Worker onMarkerSecondByte(byte);
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker break;
210*c8dee2aaSAndroid Build Coastguard Worker case State::kDone:
211*c8dee2aaSAndroid Build Coastguard Worker break;
212*c8dee2aaSAndroid Build Coastguard Worker case State::kError:
213*c8dee2aaSAndroid Build Coastguard Worker break;
214*c8dee2aaSAndroid Build Coastguard Worker }
215*c8dee2aaSAndroid Build Coastguard Worker }
216