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/codec/SkJpegUtility.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci/*
13cb93a386Sopenharmony_ci * Call longjmp to continue execution on an error
14cb93a386Sopenharmony_ci */
15cb93a386Sopenharmony_civoid skjpeg_err_exit(j_common_ptr dinfo) {
16cb93a386Sopenharmony_ci    // Simply return to Skia client code
17cb93a386Sopenharmony_ci    // JpegDecoderMgr will take care of freeing memory
18cb93a386Sopenharmony_ci    skjpeg_error_mgr* error = (skjpeg_error_mgr*) dinfo->err;
19cb93a386Sopenharmony_ci    (*error->output_message) (dinfo);
20cb93a386Sopenharmony_ci    if (error->fJmpBufStack.empty()) {
21cb93a386Sopenharmony_ci        SK_ABORT("JPEG error with no jmp_buf set.");
22cb93a386Sopenharmony_ci    }
23cb93a386Sopenharmony_ci#if defined(_JBLEN) && (defined(_JMP_BUF_DEFINED) || defined(_JBTYPE))
24cb93a386Sopenharmony_ci    longjmp((_JBTYPE*)*error->fJmpBufStack.back(), 1);
25cb93a386Sopenharmony_ci#else
26cb93a386Sopenharmony_ci    longjmp(*error->fJmpBufStack.back(), 1);
27cb93a386Sopenharmony_ci#endif
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci// Functions for buffered sources //
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci/*
33cb93a386Sopenharmony_ci * Initialize the buffered source manager
34cb93a386Sopenharmony_ci */
35cb93a386Sopenharmony_cistatic void sk_init_buffered_source(j_decompress_ptr dinfo) {
36cb93a386Sopenharmony_ci    skjpeg_source_mgr* src = (skjpeg_source_mgr*) dinfo->src;
37cb93a386Sopenharmony_ci    src->next_input_byte = (const JOCTET*) src->fBuffer;
38cb93a386Sopenharmony_ci    src->bytes_in_buffer = 0;
39cb93a386Sopenharmony_ci}
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci/*
42cb93a386Sopenharmony_ci * Fill the input buffer from the stream
43cb93a386Sopenharmony_ci */
44cb93a386Sopenharmony_cistatic boolean sk_fill_buffered_input_buffer(j_decompress_ptr dinfo) {
45cb93a386Sopenharmony_ci    skjpeg_source_mgr* src = (skjpeg_source_mgr*) dinfo->src;
46cb93a386Sopenharmony_ci    size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize);
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci    // libjpeg is still happy with a less than full read, as long as the result is non-zero
49cb93a386Sopenharmony_ci    if (bytes == 0) {
50cb93a386Sopenharmony_ci        // Let libjpeg know that the buffer needs to be refilled
51cb93a386Sopenharmony_ci        src->next_input_byte = nullptr;
52cb93a386Sopenharmony_ci        src->bytes_in_buffer = 0;
53cb93a386Sopenharmony_ci        return false;
54cb93a386Sopenharmony_ci    }
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    src->next_input_byte = (const JOCTET*) src->fBuffer;
57cb93a386Sopenharmony_ci    src->bytes_in_buffer = bytes;
58cb93a386Sopenharmony_ci    return true;
59cb93a386Sopenharmony_ci}
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci/*
62cb93a386Sopenharmony_ci * Skip a certain number of bytes in the stream
63cb93a386Sopenharmony_ci */
64cb93a386Sopenharmony_cistatic void sk_skip_buffered_input_data(j_decompress_ptr dinfo, long numBytes) {
65cb93a386Sopenharmony_ci    skjpeg_source_mgr* src = (skjpeg_source_mgr*) dinfo->src;
66cb93a386Sopenharmony_ci    size_t bytes = (size_t) numBytes;
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    if (bytes > src->bytes_in_buffer) {
69cb93a386Sopenharmony_ci        size_t bytesToSkip = bytes - src->bytes_in_buffer;
70cb93a386Sopenharmony_ci        if (bytesToSkip != src->fStream->skip(bytesToSkip)) {
71cb93a386Sopenharmony_ci            SkCodecPrintf("Failure to skip.\n");
72cb93a386Sopenharmony_ci            dinfo->err->error_exit((j_common_ptr) dinfo);
73cb93a386Sopenharmony_ci            return;
74cb93a386Sopenharmony_ci        }
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci        src->next_input_byte = (const JOCTET*) src->fBuffer;
77cb93a386Sopenharmony_ci        src->bytes_in_buffer = 0;
78cb93a386Sopenharmony_ci    } else {
79cb93a386Sopenharmony_ci        src->next_input_byte += numBytes;
80cb93a386Sopenharmony_ci        src->bytes_in_buffer -= numBytes;
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci}
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci/*
85cb93a386Sopenharmony_ci * We do not need to do anything to terminate our stream
86cb93a386Sopenharmony_ci */
87cb93a386Sopenharmony_cistatic void sk_term_source(j_decompress_ptr dinfo)
88cb93a386Sopenharmony_ci{
89cb93a386Sopenharmony_ci    // The current implementation of SkJpegCodec does not call
90cb93a386Sopenharmony_ci    // jpeg_finish_decompress(), so this function is never called.
91cb93a386Sopenharmony_ci    // If we want to modify this function to do something, we also
92cb93a386Sopenharmony_ci    // need to modify SkJpegCodec to call jpeg_finish_decompress().
93cb93a386Sopenharmony_ci}
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci// Functions for memory backed sources //
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci/*
98cb93a386Sopenharmony_ci * Initialize the mem backed source manager
99cb93a386Sopenharmony_ci */
100cb93a386Sopenharmony_cistatic void sk_init_mem_source(j_decompress_ptr dinfo) {
101cb93a386Sopenharmony_ci    /* no work necessary here, all things are done in constructor */
102cb93a386Sopenharmony_ci}
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_cistatic void sk_skip_mem_input_data (j_decompress_ptr cinfo, long num_bytes) {
105cb93a386Sopenharmony_ci    jpeg_source_mgr* src = cinfo->src;
106cb93a386Sopenharmony_ci    size_t bytes = static_cast<size_t>(num_bytes);
107cb93a386Sopenharmony_ci    if(bytes > src->bytes_in_buffer) {
108cb93a386Sopenharmony_ci        src->next_input_byte = nullptr;
109cb93a386Sopenharmony_ci        src->bytes_in_buffer = 0;
110cb93a386Sopenharmony_ci    } else {
111cb93a386Sopenharmony_ci        src->next_input_byte += bytes;
112cb93a386Sopenharmony_ci        src->bytes_in_buffer -= bytes;
113cb93a386Sopenharmony_ci    }
114cb93a386Sopenharmony_ci}
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_cistatic boolean sk_fill_mem_input_buffer (j_decompress_ptr cinfo) {
117cb93a386Sopenharmony_ci    /* The whole JPEG data is expected to reside in the supplied memory,
118cb93a386Sopenharmony_ci     * buffer, so any request for more data beyond the given buffer size
119cb93a386Sopenharmony_ci     * is treated as an error.
120cb93a386Sopenharmony_ci     */
121cb93a386Sopenharmony_ci    return false;
122cb93a386Sopenharmony_ci}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci/*
125cb93a386Sopenharmony_ci * Constructor for the source manager that we provide to libjpeg
126cb93a386Sopenharmony_ci * We provide skia implementations of all of the stream processing functions required by libjpeg
127cb93a386Sopenharmony_ci */
128cb93a386Sopenharmony_ciskjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream)
129cb93a386Sopenharmony_ci    : fStream(stream)
130cb93a386Sopenharmony_ci{
131cb93a386Sopenharmony_ci    if (stream->hasLength() && stream->getMemoryBase()) {
132cb93a386Sopenharmony_ci        init_source = sk_init_mem_source;
133cb93a386Sopenharmony_ci        fill_input_buffer = sk_fill_mem_input_buffer;
134cb93a386Sopenharmony_ci        skip_input_data = sk_skip_mem_input_data;
135cb93a386Sopenharmony_ci        resync_to_restart = jpeg_resync_to_restart;
136cb93a386Sopenharmony_ci        term_source = sk_term_source;
137cb93a386Sopenharmony_ci        bytes_in_buffer = static_cast<size_t>(stream->getLength());
138cb93a386Sopenharmony_ci        next_input_byte = static_cast<const JOCTET*>(stream->getMemoryBase());
139cb93a386Sopenharmony_ci    } else {
140cb93a386Sopenharmony_ci        init_source = sk_init_buffered_source;
141cb93a386Sopenharmony_ci        fill_input_buffer = sk_fill_buffered_input_buffer;
142cb93a386Sopenharmony_ci        skip_input_data = sk_skip_buffered_input_data;
143cb93a386Sopenharmony_ci        resync_to_restart = jpeg_resync_to_restart;
144cb93a386Sopenharmony_ci        term_source = sk_term_source;
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci}
147