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 "SkJpegUtility.h"
9 
10 #include "SkCodecPriv.h"
11 
12 /*
13  * Initialize the source manager
14  */
sk_init_source(j_decompress_ptr dinfo)15 static void sk_init_source(j_decompress_ptr dinfo) {
16     skjpeg_source_mgr* src = (skjpeg_source_mgr*) dinfo->src;
17     src->next_input_byte = (const JOCTET*) src->fBuffer;
18     src->bytes_in_buffer = 0;
19 }
20 
21 /*
22  * Fill the input buffer from the stream
23  */
sk_fill_input_buffer(j_decompress_ptr dinfo)24 static boolean sk_fill_input_buffer(j_decompress_ptr dinfo) {
25     skjpeg_source_mgr* src = (skjpeg_source_mgr*) dinfo->src;
26     size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize);
27 
28     // libjpeg is still happy with a less than full read, as long as the result is non-zero
29     if (bytes == 0) {
30         return false;
31     }
32 
33     src->next_input_byte = (const JOCTET*) src->fBuffer;
34     src->bytes_in_buffer = bytes;
35     return true;
36 }
37 
38 /*
39  * Skip a certain number of bytes in the stream
40  */
sk_skip_input_data(j_decompress_ptr dinfo,long numBytes)41 static void sk_skip_input_data(j_decompress_ptr dinfo, long numBytes) {
42     skjpeg_source_mgr* src = (skjpeg_source_mgr*) dinfo->src;
43     size_t bytes = (size_t) numBytes;
44 
45     if (bytes > src->bytes_in_buffer) {
46         size_t bytesToSkip = bytes - src->bytes_in_buffer;
47         if (bytesToSkip != src->fStream->skip(bytesToSkip)) {
48             SkCodecPrintf("Failure to skip.\n");
49             dinfo->err->error_exit((j_common_ptr) dinfo);
50             return;
51         }
52 
53         src->next_input_byte = (const JOCTET*) src->fBuffer;
54         src->bytes_in_buffer = 0;
55     } else {
56         src->next_input_byte += numBytes;
57         src->bytes_in_buffer -= numBytes;
58     }
59 }
60 
61 /*
62  * We do not need to do anything to terminate our stream
63  */
sk_term_source(j_decompress_ptr dinfo)64 static void sk_term_source(j_decompress_ptr dinfo)
65 {
66     // The current implementation of SkJpegCodec does not call
67     // jpeg_finish_decompress(), so this function is never called.
68     // If we want to modify this function to do something, we also
69     // need to modify SkJpegCodec to call jpeg_finish_decompress().
70 }
71 
72 /*
73  * Constructor for the source manager that we provide to libjpeg
74  * We provide skia implementations of all of the stream processing functions required by libjpeg
75  */
skjpeg_source_mgr(SkStream * stream)76 skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream)
77     : fStream(stream)
78 {
79     init_source = sk_init_source;
80     fill_input_buffer = sk_fill_input_buffer;
81     skip_input_data = sk_skip_input_data;
82     resync_to_restart = jpeg_resync_to_restart;
83     term_source = sk_term_source;
84 }
85 
86 /*
87  * Call longjmp to continue execution on an error
88  */
skjpeg_err_exit(j_common_ptr dinfo)89 void skjpeg_err_exit(j_common_ptr dinfo) {
90     // Simply return to Skia client code
91     // JpegDecoderMgr will take care of freeing memory
92     skjpeg_error_mgr* error = (skjpeg_error_mgr*) dinfo->err;
93     (*error->output_message) (dinfo);
94     longjmp(error->fJmpBuf, 1);
95 }
96