1 /*
2  * Copyright 2010 The Android Open Source Project
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 
9 #include "SkJpegUtility.h"
10 
11 /////////////////////////////////////////////////////////////////////
sk_init_source(j_decompress_ptr cinfo)12 static void sk_init_source(j_decompress_ptr cinfo) {
13     skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
14     src->next_input_byte = (const JOCTET*)src->fBuffer;
15     src->bytes_in_buffer = 0;
16 #ifdef SK_BUILD_FOR_ANDROID
17     src->current_offset = 0;
18 #endif
19     if (!src->fStream->rewind()) {
20         SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
21         cinfo->err->error_exit((j_common_ptr)cinfo);
22     }
23 }
24 
25 #ifdef SK_BUILD_FOR_ANDROID
sk_seek_input_data(j_decompress_ptr cinfo,long byte_offset)26 static boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) {
27     skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
28     size_t bo = (size_t) byte_offset;
29 
30     if (bo > src->current_offset) {
31         (void)src->fStream->skip(bo - src->current_offset);
32     } else {
33         if (!src->fStream->rewind()) {
34             SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
35             cinfo->err->error_exit((j_common_ptr)cinfo);
36             return false;
37         }
38         (void)src->fStream->skip(bo);
39     }
40 
41     src->current_offset = bo;
42     src->next_input_byte = (const JOCTET*)src->fBuffer;
43     src->bytes_in_buffer = 0;
44     return true;
45 }
46 #endif
47 
sk_fill_input_buffer(j_decompress_ptr cinfo)48 static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
49     skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
50     if (src->fDecoder != NULL && src->fDecoder->shouldCancelDecode()) {
51         return FALSE;
52     }
53     size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize);
54     // note that JPEG is happy with less than the full read,
55     // as long as the result is non-zero
56     if (bytes == 0) {
57         return FALSE;
58     }
59 
60 #ifdef SK_BUILD_FOR_ANDROID
61     src->current_offset += bytes;
62 #endif
63     src->next_input_byte = (const JOCTET*)src->fBuffer;
64     src->bytes_in_buffer = bytes;
65     return TRUE;
66 }
67 
sk_skip_input_data(j_decompress_ptr cinfo,long num_bytes)68 static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
69     skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
70 
71     if (num_bytes > (long)src->bytes_in_buffer) {
72         size_t bytesToSkip = num_bytes - src->bytes_in_buffer;
73         while (bytesToSkip > 0) {
74             size_t bytes = src->fStream->skip(bytesToSkip);
75             if (bytes <= 0 || bytes > bytesToSkip) {
76 //              SkDebugf("xxxxxxxxxxxxxx failure to skip request %d returned %d\n", bytesToSkip, bytes);
77                 cinfo->err->error_exit((j_common_ptr)cinfo);
78                 return;
79             }
80 #ifdef SK_BUILD_FOR_ANDROID
81             src->current_offset += bytes;
82 #endif
83             bytesToSkip -= bytes;
84         }
85         src->next_input_byte = (const JOCTET*)src->fBuffer;
86         src->bytes_in_buffer = 0;
87     } else {
88         src->next_input_byte += num_bytes;
89         src->bytes_in_buffer -= num_bytes;
90     }
91 }
92 
sk_term_source(j_decompress_ptr)93 static void sk_term_source(j_decompress_ptr /*cinfo*/) {}
94 
95 
96 ///////////////////////////////////////////////////////////////////////////////
97 
skjpeg_source_mgr(SkStream * stream,SkImageDecoder * decoder)98 skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder)
99     : fStream(stream)
100     , fDecoder(decoder) {
101 
102     init_source = sk_init_source;
103     fill_input_buffer = sk_fill_input_buffer;
104     skip_input_data = sk_skip_input_data;
105     resync_to_restart = jpeg_resync_to_restart;
106     term_source = sk_term_source;
107 #ifdef SK_BUILD_FOR_ANDROID
108     seek_input_data = sk_seek_input_data;
109 #endif
110 //    SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
111 }
112 
113 ///////////////////////////////////////////////////////////////////////////////
114 
sk_init_destination(j_compress_ptr cinfo)115 static void sk_init_destination(j_compress_ptr cinfo) {
116     skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
117 
118     dest->next_output_byte = dest->fBuffer;
119     dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
120 }
121 
sk_empty_output_buffer(j_compress_ptr cinfo)122 static boolean sk_empty_output_buffer(j_compress_ptr cinfo) {
123     skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
124 
125 //  if (!dest->fStream->write(dest->fBuffer, skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer))
126     if (!dest->fStream->write(dest->fBuffer,
127             skjpeg_destination_mgr::kBufferSize)) {
128         ERREXIT(cinfo, JERR_FILE_WRITE);
129         return false;
130     }
131 
132     dest->next_output_byte = dest->fBuffer;
133     dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
134     return TRUE;
135 }
136 
sk_term_destination(j_compress_ptr cinfo)137 static void sk_term_destination (j_compress_ptr cinfo) {
138     skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
139 
140     size_t size = skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer;
141     if (size > 0) {
142         if (!dest->fStream->write(dest->fBuffer, size)) {
143             ERREXIT(cinfo, JERR_FILE_WRITE);
144             return;
145         }
146     }
147     dest->fStream->flush();
148 }
149 
skjpeg_destination_mgr(SkWStream * stream)150 skjpeg_destination_mgr::skjpeg_destination_mgr(SkWStream* stream)
151         : fStream(stream) {
152     this->init_destination = sk_init_destination;
153     this->empty_output_buffer = sk_empty_output_buffer;
154     this->term_destination = sk_term_destination;
155 }
156 
skjpeg_error_exit(j_common_ptr cinfo)157 void skjpeg_error_exit(j_common_ptr cinfo) {
158     skjpeg_error_mgr* error = (skjpeg_error_mgr*)cinfo->err;
159 
160     (*error->output_message) (cinfo);
161 
162     /* Let the memory manager delete any temp files before we die */
163     jpeg_destroy(cinfo);
164 
165     longjmp(error->fJmpBuf, -1);
166 }
167