blob: 6718978b451001444b8eedbc79baffa72a368a4c [file] [log] [blame]
/*
* Copyright 2023 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/codec/SkJpegSourceMgr.h"
#include "include/core/SkData.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkStream.h"
#include "src/codec/SkCodecPriv.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// SkJpegMemorySourceMgr
class SkJpegMemorySourceMgr : public SkJpegSourceMgr {
public:
SkJpegMemorySourceMgr(SkStream* stream) : fStream(stream) {}
~SkJpegMemorySourceMgr() override {}
void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
nextInputByte = reinterpret_cast<const uint8_t*>(fStream->getMemoryBase());
bytesInBuffer = static_cast<size_t>(fStream->getLength());
}
bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
// The whole JPEG data is expected to reside in the supplied memory buffer, so any request
// for more data beyond the given buffer size is treated as an error.
SkCodecPrintf("Asked to re-fill a memory-mapped stream.\n");
return false;
}
bool skipInputBytes(size_t bytesToSkip,
const uint8_t*& nextInputByte,
size_t& bytesInBuffer) override {
if (bytesToSkip > bytesInBuffer) {
SkCodecPrintf("Asked to read past end of a memory-mapped stream.\n");
return false;
}
nextInputByte += bytesToSkip;
bytesInBuffer -= bytesToSkip;
return true;
}
private:
SkStream* const fStream; // unowned.
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// SkJpegBufferedSourceMgr
class SkJpegBufferedSourceMgr : public SkJpegSourceMgr {
public:
SkJpegBufferedSourceMgr(SkStream* stream) : fStream(stream) {}
~SkJpegBufferedSourceMgr() override {}
void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
constexpr size_t kBufferSize = 1024;
fBuffer = SkData::MakeUninitialized(kBufferSize);
nextInputByte = fBuffer->bytes();
bytesInBuffer = 0;
}
bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
size_t bytesRead = fStream->read(fBuffer->writable_data(), fBuffer->size());
if (bytesRead == 0) {
// Fail if we read zero bytes (libjpeg will accept any non-zero number of bytes).
SkCodecPrintf("Hit end of file reading a buffered stream.\n");
return false;
}
nextInputByte = fBuffer->bytes();
bytesInBuffer = bytesRead;
return true;
}
bool skipInputBytes(size_t bytesToSkip,
const uint8_t*& nextInputByte,
size_t& bytesInBuffer) override {
// Skip through the already-read (or already in memory) buffer.
if (bytesToSkip <= bytesInBuffer) {
nextInputByte += bytesToSkip;
bytesInBuffer -= bytesToSkip;
return true;
}
bytesToSkip -= bytesInBuffer;
// Fail if we skip past the end of the stream.
if (fStream->skip(bytesToSkip) != bytesToSkip) {
SkCodecPrintf("Failed to skip through buffered stream.\n");
return false;
}
bytesInBuffer = 0;
nextInputByte = fBuffer->bytes();
return true;
}
private:
SkStream* const fStream; // unowned.
sk_sp<SkData> fBuffer;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// SkJpegSourceMgr
// static
std::unique_ptr<SkJpegSourceMgr> SkJpegSourceMgr::Make(SkStream* stream) {
if (stream->hasLength() && stream->getMemoryBase()) {
return std::make_unique<SkJpegMemorySourceMgr>(stream);
}
return std::make_unique<SkJpegBufferedSourceMgr>(stream);
}