1 /*
2 * Copyright 2023 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 "src/codec/SkJpegSourceMgr.h"
9
10 #include "include/core/SkData.h"
11 #include "include/core/SkRefCnt.h"
12 #include "include/core/SkStream.h"
13 #include "include/core/SkTypes.h"
14 #include "src/codec/SkCodecPriv.h"
15
16 #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
17 #include "src/codec/SkJpegConstants.h"
18 #include "src/codec/SkJpegSegmentScan.h"
19 #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
20
21 ////////////////////////////////////////////////////////////////////////////////////////////////////
22 // SkStream helpers.
23
24 /*
25 * Class that will will rewind an SkStream, and then restore it to its original position when it
26 * goes out of scope. If the SkStream is not seekable, then the stream will not be altered at all,
27 * and will return false from canRestore.
28 */
29
30 class ScopedSkStreamRestorer {
31 public:
ScopedSkStreamRestorer(SkStream * stream)32 ScopedSkStreamRestorer(SkStream* stream) : fStream(stream), fPosition(stream->getPosition()) {
33 if (!fStream->rewind()) {
34 SkCodecPrintf("Failed to rewind decoder stream.\n");
35 }
36 }
~ScopedSkStreamRestorer()37 ~ScopedSkStreamRestorer() {
38 if (!fStream->seek(fPosition)) {
39 SkCodecPrintf("Failed to restore decoder stream.\n");
40 }
41 }
42
43 private:
44 SkStream* const fStream;
45 const size_t fPosition;
46 };
47
48 ////////////////////////////////////////////////////////////////////////////////////////////////////
49 // SkJpegMemorySourceMgr
50
51 class SkJpegMemorySourceMgr : public SkJpegSourceMgr {
52 public:
SkJpegMemorySourceMgr(SkStream * stream)53 SkJpegMemorySourceMgr(SkStream* stream) : SkJpegSourceMgr(stream) {}
~SkJpegMemorySourceMgr()54 ~SkJpegMemorySourceMgr() override {}
55
initSource(const uint8_t * & nextInputByte,size_t & bytesInBuffer)56 void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
57 nextInputByte = reinterpret_cast<const uint8_t*>(fStream->getMemoryBase());
58 bytesInBuffer = static_cast<size_t>(fStream->getLength());
59 }
fillInputBuffer(const uint8_t * & nextInputByte,size_t & bytesInBuffer)60 bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
61 // The whole JPEG data is expected to reside in the supplied memory buffer, so any request
62 // for more data beyond the given buffer size is treated as an error.
63 SkCodecPrintf("Asked to re-fill a memory-mapped stream.\n");
64 return false;
65 }
skipInputBytes(size_t bytesToSkip,const uint8_t * & nextInputByte,size_t & bytesInBuffer)66 bool skipInputBytes(size_t bytesToSkip,
67 const uint8_t*& nextInputByte,
68 size_t& bytesInBuffer) override {
69 if (bytesToSkip > bytesInBuffer) {
70 SkCodecPrintf("Asked to read past end of a memory-mapped stream.\n");
71 return false;
72 }
73 nextInputByte += bytesToSkip;
74 bytesInBuffer -= bytesToSkip;
75 return true;
76 }
77 #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
getAllSegments()78 const std::vector<SkJpegSegment>& getAllSegments() override {
79 if (fScanner) {
80 return fScanner->getSegments();
81 }
82 fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage);
83 fScanner->onBytes(fStream->getMemoryBase(), fStream->getLength());
84 return fScanner->getSegments();
85 }
getSubsetData(size_t offset,size_t size,bool * wasCopied)86 sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override {
87 if (offset > fStream->getLength() || size > fStream->getLength() - offset) {
88 return nullptr;
89 }
90 if (wasCopied) {
91 *wasCopied = false;
92 }
93 return SkData::MakeWithoutCopy(
94 reinterpret_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, size);
95 }
getSegmentParameters(const SkJpegSegment & segment)96 sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override {
97 const uint8_t* base =
98 reinterpret_cast<const uint8_t*>(fStream->getMemoryBase()) + segment.offset;
99 SkASSERT(segment.offset < fStream->getLength());
100 SkASSERT(kJpegMarkerCodeSize + segment.parameterLength <=
101 fStream->getLength() - segment.offset);
102
103 // Read the marker and verify it matches `segment`.
104 SkASSERT(base[0] == 0xFF);
105 SkASSERT(base[1] == segment.marker);
106
107 // Read the parameter length and verify it matches `segment`.
108 SkASSERT(256 * base[2] + base[3] == segment.parameterLength);
109 if (segment.parameterLength <= kJpegSegmentParameterLengthSize) {
110 return nullptr;
111 }
112
113 // Read the remainder of the segment.
114 return SkData::MakeWithoutCopy(base + kJpegMarkerCodeSize + kJpegSegmentParameterLengthSize,
115 segment.parameterLength - kJpegSegmentParameterLengthSize);
116 }
117 #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
118 };
119
120 ////////////////////////////////////////////////////////////////////////////////////////////////////
121 // SkJpegBufferedSourceMgr
122
123 class SkJpegBufferedSourceMgr : public SkJpegSourceMgr {
124 public:
SkJpegBufferedSourceMgr(SkStream * stream,size_t bufferSize)125 SkJpegBufferedSourceMgr(SkStream* stream, size_t bufferSize) : SkJpegSourceMgr(stream) {
126 fBuffer = SkData::MakeUninitialized(bufferSize);
127 }
~SkJpegBufferedSourceMgr()128 ~SkJpegBufferedSourceMgr() override {}
129
initSource(const uint8_t * & nextInputByte,size_t & bytesInBuffer)130 void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
131 nextInputByte = fBuffer->bytes();
132 bytesInBuffer = 0;
133 }
fillInputBuffer(const uint8_t * & nextInputByte,size_t & bytesInBuffer)134 bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
135 size_t bytesRead = fStream->read(fBuffer->writable_data(), fBuffer->size());
136 if (bytesRead == 0) {
137 // Fail if we read zero bytes (libjpeg will accept any non-zero number of bytes).
138 SkCodecPrintf("Hit end of file reading a buffered stream.\n");
139 return false;
140 }
141 nextInputByte = fBuffer->bytes();
142 bytesInBuffer = bytesRead;
143 return true;
144 }
skipInputBytes(size_t bytesToSkip,const uint8_t * & nextInputByte,size_t & bytesInBuffer)145 bool skipInputBytes(size_t bytesToSkip,
146 const uint8_t*& nextInputByte,
147 size_t& bytesInBuffer) override {
148 // Skip through the already-read (or already in memory) buffer.
149 if (bytesToSkip <= bytesInBuffer) {
150 nextInputByte += bytesToSkip;
151 bytesInBuffer -= bytesToSkip;
152 return true;
153 }
154 bytesToSkip -= bytesInBuffer;
155
156 // Fail if we skip past the end of the stream.
157 if (fStream->skip(bytesToSkip) != bytesToSkip) {
158 SkCodecPrintf("Failed to skip through buffered stream.\n");
159 return false;
160 }
161
162 bytesInBuffer = 0;
163 nextInputByte = fBuffer->bytes();
164 return true;
165 }
166 #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
getAllSegments()167 const std::vector<SkJpegSegment>& getAllSegments() override {
168 if (fScanner) {
169 return fScanner->getSegments();
170 }
171 ScopedSkStreamRestorer streamRestorer(fStream);
172 fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage);
173 while (!fScanner->isDone() && !fScanner->hadError()) {
174 constexpr size_t kBufferSize = 1024;
175 uint8_t buffer[kBufferSize];
176 size_t bytesRead = fStream->read(buffer, kBufferSize);
177 if (bytesRead == 0) {
178 SkCodecPrintf("Unexpected EOF.\n");
179 break;
180 }
181 fScanner->onBytes(buffer, bytesRead);
182 }
183 return fScanner->getSegments();
184 }
getSubsetData(size_t offset,size_t size,bool * wasCopied)185 sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override {
186 ScopedSkStreamRestorer streamRestorer(fStream);
187 if (!fStream->seek(offset)) {
188 SkCodecPrintf("Failed to seek to subset stream position.\n");
189 return nullptr;
190 }
191 sk_sp<SkData> data = SkData::MakeUninitialized(size);
192 if (fStream->read(data->writable_data(), size) != size) {
193 SkCodecPrintf("Failed to read subset stream data.\n");
194 return nullptr;
195 }
196 if (wasCopied) {
197 *wasCopied = true;
198 }
199 return data;
200 }
getSegmentParameters(const SkJpegSegment & segment)201 sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override {
202 // If the segment's parameter length isn't longer than the two bytes for the length,
203 // early-out early-out.
204 if (segment.parameterLength <= kJpegSegmentParameterLengthSize) {
205 return nullptr;
206 }
207
208 // Seek to the start of the segment.
209 ScopedSkStreamRestorer streamRestorer(fStream);
210 if (!fStream->seek(segment.offset)) {
211 SkCodecPrintf("Failed to seek to segment\n");
212 return nullptr;
213 }
214
215 // Read the marker and verify it matches `segment`.
216 uint8_t markerCode[kJpegMarkerCodeSize] = {0};
217 if (fStream->read(markerCode, kJpegMarkerCodeSize) != kJpegMarkerCodeSize) {
218 SkCodecPrintf("Failed to read segment marker code\n");
219 return nullptr;
220 }
221 SkASSERT(markerCode[0] == 0xFF);
222 SkASSERT(markerCode[1] == segment.marker);
223
224 // Read the parameter length and verify it matches `segment`.
225 uint8_t parameterLength[kJpegSegmentParameterLengthSize] = {0};
226 if (fStream->read(parameterLength, kJpegSegmentParameterLengthSize) !=
227 kJpegSegmentParameterLengthSize) {
228 SkCodecPrintf("Failed to read parameter length\n");
229 return nullptr;
230 }
231 SkASSERT(256 * parameterLength[0] + parameterLength[1] == segment.parameterLength);
232
233 // Read the remainder of the segment.
234 size_t sizeToRead = segment.parameterLength - kJpegSegmentParameterLengthSize;
235 auto result = SkData::MakeUninitialized(sizeToRead);
236 if (fStream->read(result->writable_data(), sizeToRead) != sizeToRead) {
237 return nullptr;
238 }
239
240 return result;
241 }
242 #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
243
244 private:
245 sk_sp<SkData> fBuffer;
246 };
247
248 ////////////////////////////////////////////////////////////////////////////////////////////////////
249 // SkJpegUnseekableSourceMgr
250
251 #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
252 /*
253 * This class implements SkJpegSourceMgr for a stream that cannot seek or rewind. It scans the data
254 * as it is presented to the decoder. This allows it to track the position of segments, so that it
255 * can extract subsets at a specific offset (e.g, relative to the EndOfImage segment for JpegR or
256 * relative to an MPF segment for MPF).
257 */
258 class SkJpegUnseekableSourceMgr : public SkJpegSourceMgr {
259 public:
SkJpegUnseekableSourceMgr(SkStream * stream,size_t bufferSize)260 SkJpegUnseekableSourceMgr(SkStream* stream, size_t bufferSize) : SkJpegSourceMgr(stream) {
261 fBuffer = SkData::MakeUninitialized(bufferSize);
262 fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage);
263 }
~SkJpegUnseekableSourceMgr()264 ~SkJpegUnseekableSourceMgr() override {}
265
initSource(const uint8_t * & nextInputByte,size_t & bytesInBuffer)266 void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
267 nextInputByte = fBuffer->bytes();
268 bytesInBuffer = 0;
269 }
fillInputBuffer(const uint8_t * & nextInputByte,size_t & bytesInBuffer)270 bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
271 if (!readToBufferAndScan(fBuffer->size())) {
272 SkCodecPrintf("Failure filling unseekable input buffer.\n");
273 return false;
274 }
275 nextInputByte = fBuffer->bytes();
276 bytesInBuffer = fLastReadSize;
277 return true;
278 }
skipInputBytes(size_t bytesToSkip,const uint8_t * & nextInputByte,size_t & bytesInBuffer)279 bool skipInputBytes(size_t bytesToSkip,
280 const uint8_t*& nextInputByte,
281 size_t& bytesInBuffer) override {
282 // Skip through the already-read (or already in memory) buffer.
283 if (bytesToSkip <= bytesInBuffer) {
284 nextInputByte += bytesToSkip;
285 bytesInBuffer -= bytesToSkip;
286 return true;
287 }
288 bytesToSkip -= bytesInBuffer;
289
290 // Read the remaining bytes to skip into fBuffer and feed them into fScanner.
291 while (bytesToSkip > 0) {
292 if (!readToBufferAndScan(std::min(bytesToSkip, fBuffer->size()))) {
293 SkCodecPrintf("Failure filling unseekable input buffer.\n");
294 return false;
295 }
296 bytesToSkip -= fLastReadSize;
297 }
298
299 // Indicate to libjpeg that it it needs to call fillInputBuffer.
300 bytesInBuffer = 0;
301 nextInputByte = fBuffer->bytes();
302 return true;
303 }
getAllSegments()304 const std::vector<SkJpegSegment>& getAllSegments() override {
305 while (!fScanner->isDone() && !fScanner->hadError()) {
306 if (!readToBufferAndScan(fBuffer->size())) {
307 SkCodecPrintf("Failure finishing unseekable input buffer.\n");
308 break;
309 }
310 }
311 return fScanner->getSegments();
312 }
getSubsetData(size_t offset,size_t size,bool * wasCopied)313 sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override {
314 // If we haven't reached the EndOfImage, then we are throwing away the base image before
315 // decoding it. This is only reasonable for tests.
316 if (!fScanner->isDone()) {
317 SkCodecPrintf("getSubsetData is prematurely terminating scan.\n");
318 }
319
320 // If we have read past offset, we can never get that data back again.
321 if (offset < fLastReadOffset) {
322 SkCodecPrintf("Requested that is gone.\n");
323 return nullptr;
324 }
325
326 // Allocate the memory to return, and indicate that the result is a copy.
327 sk_sp<SkData> subsetData = SkData::MakeUninitialized(size);
328 uint8_t* subsetDataCurrent = reinterpret_cast<uint8_t*>(subsetData->writable_data());
329
330 // Determine the relationship between the offset we're reading from and |fBuffer|.
331 size_t offsetIntoBuffer = offset - fLastReadOffset;
332 if (offsetIntoBuffer >= fLastReadSize) {
333 // We have to skip past |fBuffer| to get to |offset|.
334 fLastReadOffset += fLastReadSize;
335 fLastReadSize = 0;
336
337 // Skip any additional bytes needed to get to |offset|.
338 size_t bytesToSkip = offset - fLastReadOffset;
339 while (bytesToSkip > 0) {
340 size_t bytesSkipped = fStream->skip(bytesToSkip);
341 if (bytesSkipped == 0) {
342 SkCodecPrintf("Failed to skip bytes before subset.\n");
343 return nullptr;
344 }
345 bytesToSkip -= bytesSkipped;
346 fLastReadOffset += bytesSkipped;
347 }
348 } else {
349 // This assert is to emphatically document the side of the branch we're on.
350 SkASSERT(offsetIntoBuffer < fLastReadSize);
351
352 // Some of the data we want to copy has already been read into |fBuffer|. Copy that data
353 // to |subsetData|
354 size_t bytesToReadFromBuffer = std::min(fLastReadSize - offsetIntoBuffer, size);
355 memcpy(subsetDataCurrent, fBuffer->bytes() + offsetIntoBuffer, bytesToReadFromBuffer);
356 size -= bytesToReadFromBuffer;
357 subsetDataCurrent += bytesToReadFromBuffer;
358
359 // If all of the data that we needed was in |fBuffer|, then return early.
360 if (size == 0) {
361 if (wasCopied) {
362 *wasCopied = true;
363 }
364 return subsetData;
365 }
366 // We will now have to read beyond |fBuffer|, so reset it.
367 fLastReadOffset += fLastReadSize;
368 fLastReadSize = 0;
369 }
370
371 // Read the remaining data from |fStream|.
372 while (size > 0) {
373 size_t bytesRead = fStream->read(subsetDataCurrent, size);
374 if (bytesRead == 0) {
375 SkCodecPrintf("Failed to read subset stream data.\n");
376 return nullptr;
377 }
378 size -= bytesRead;
379 subsetDataCurrent += bytesRead;
380 fLastReadOffset += bytesRead;
381 }
382
383 if (wasCopied) {
384 *wasCopied = true;
385 }
386 return subsetData;
387 }
getSegmentParameters(const SkJpegSegment & segment)388 sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override {
389 // The only way to implement this for an unseekable stream is to record the parameters as
390 // they are scanned.
391 return nullptr;
392 }
393
394 private:
395 // Read the specified number of bytes into fBuffer and feed them to fScanner. The number of
396 // bytes must not be larger than fBuffer's size.
readToBufferAndScan(size_t bytesToRead)397 bool readToBufferAndScan(size_t bytesToRead) {
398 SkASSERT(bytesToRead <= fBuffer->size());
399 fLastReadOffset += fLastReadSize;
400 fLastReadSize = fStream->read(fBuffer->writable_data(), bytesToRead);
401 if (fLastReadSize == 0) {
402 SkCodecPrintf("Hit end of file reading an unseekable stream.\n");
403 return false;
404 }
405 fScanner->onBytes(fBuffer->bytes(), fLastReadSize);
406 return true;
407 }
408
409 sk_sp<SkData> fBuffer;
410
411 // The number of bytes that were most recently read into fBuffer (this can be less than the size
412 // of fBuffer).
413 size_t fLastReadSize = 0;
414
415 // The offset into the stream (total number of bytes read) at the time of our most recent read
416 // into fBuffer.
417 size_t fLastReadOffset = 0;
418 };
419 #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
420
421 ////////////////////////////////////////////////////////////////////////////////////////////////////
422 // SkJpegSourceMgr
423
424 // static
Make(SkStream * stream,size_t bufferSize)425 std::unique_ptr<SkJpegSourceMgr> SkJpegSourceMgr::Make(SkStream* stream, size_t bufferSize) {
426 #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
427 if (!stream->hasPosition()) {
428 return std::make_unique<SkJpegUnseekableSourceMgr>(stream, bufferSize);
429 }
430 #endif
431 if (stream->hasLength() && stream->getMemoryBase()) {
432 return std::make_unique<SkJpegMemorySourceMgr>(stream);
433 }
434 return std::make_unique<SkJpegBufferedSourceMgr>(stream, bufferSize);
435 }
436
SkJpegSourceMgr(SkStream * stream)437 SkJpegSourceMgr::SkJpegSourceMgr(SkStream* stream) : fStream(stream) {}
438
439 SkJpegSourceMgr::~SkJpegSourceMgr() = default;
440