1
2/*
3 * Copyright 2010 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkJpegUtility.h"
11
12/////////////////////////////////////////////////////////////////////
13static void sk_init_source(j_decompress_ptr cinfo) {
14    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
15    src->next_input_byte = (const JOCTET*)src->fBuffer;
16    src->bytes_in_buffer = 0;
17    src->current_offset = 0;
18    src->fStream->rewind();
19}
20
21static boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) {
22    skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
23
24    if (byte_offset > src->current_offset) {
25        (void)src->fStream->skip(byte_offset - src->current_offset);
26    } else {
27        src->fStream->rewind();
28        (void)src->fStream->skip(byte_offset);
29    }
30
31    src->current_offset = byte_offset;
32    src->next_input_byte = (const JOCTET*)src->fBuffer;
33    src->bytes_in_buffer = 0;
34    return TRUE;
35}
36
37static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
38    skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
39    if (src->fDecoder != NULL && src->fDecoder->shouldCancelDecode()) {
40        return FALSE;
41    }
42    size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize);
43    // note that JPEG is happy with less than the full read,
44    // as long as the result is non-zero
45    if (bytes == 0) {
46        return FALSE;
47    }
48
49    src->current_offset += bytes;
50    src->next_input_byte = (const JOCTET*)src->fBuffer;
51    src->bytes_in_buffer = bytes;
52    return TRUE;
53}
54
55static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
56    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
57
58    if (num_bytes > (long)src->bytes_in_buffer) {
59        long bytesToSkip = num_bytes - src->bytes_in_buffer;
60        while (bytesToSkip > 0) {
61            long bytes = (long)src->fStream->skip(bytesToSkip);
62            if (bytes <= 0 || bytes > bytesToSkip) {
63//              SkDebugf("xxxxxxxxxxxxxx failure to skip request %d returned %d\n", bytesToSkip, bytes);
64                cinfo->err->error_exit((j_common_ptr)cinfo);
65                return;
66            }
67            src->current_offset += bytes;
68            bytesToSkip -= bytes;
69        }
70        src->next_input_byte = (const JOCTET*)src->fBuffer;
71        src->bytes_in_buffer = 0;
72    } else {
73        src->next_input_byte += num_bytes;
74        src->bytes_in_buffer -= num_bytes;
75    }
76}
77
78static boolean sk_resync_to_restart(j_decompress_ptr cinfo, int desired) {
79    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
80
81    // what is the desired param for???
82
83    if (!src->fStream->rewind()) {
84        SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
85        cinfo->err->error_exit((j_common_ptr)cinfo);
86        return FALSE;
87    }
88    src->next_input_byte = (const JOCTET*)src->fBuffer;
89    src->bytes_in_buffer = 0;
90    return TRUE;
91}
92
93static void sk_term_source(j_decompress_ptr /*cinfo*/) {}
94
95
96static void skmem_init_source(j_decompress_ptr cinfo) {
97    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
98    src->next_input_byte = (const JOCTET*)src->fMemoryBase;
99    src->start_input_byte = (const JOCTET*)src->fMemoryBase;
100    src->bytes_in_buffer = src->fMemoryBaseSize;
101    src->current_offset = src->fMemoryBaseSize;
102}
103
104static boolean skmem_fill_input_buffer(j_decompress_ptr cinfo) {
105    SkDebugf("xxxxxxxxxxxxxx skmem_fill_input_buffer called\n");
106    return FALSE;
107}
108
109static void skmem_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
110    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
111//    SkDebugf("xxxxxxxxxxxxxx skmem_skip_input_data called %d\n", num_bytes);
112    src->next_input_byte = (const JOCTET*)((const char*)src->next_input_byte + num_bytes);
113    src->bytes_in_buffer -= num_bytes;
114}
115
116static boolean skmem_resync_to_restart(j_decompress_ptr cinfo, int desired) {
117    SkDebugf("xxxxxxxxxxxxxx skmem_resync_to_restart called\n");
118    return TRUE;
119}
120
121static void skmem_term_source(j_decompress_ptr /*cinfo*/) {}
122
123
124///////////////////////////////////////////////////////////////////////////////
125
126skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder,
127                                     bool ownStream) : fStream(stream) {
128    fDecoder = decoder;
129    const void* baseAddr = stream->getMemoryBase();
130    size_t bufferSize = 4096;
131    size_t len;
132    fMemoryBase = NULL;
133    fUnrefStream = ownStream;
134    fMemoryBaseSize = 0;
135
136    init_source = sk_init_source;
137    fill_input_buffer = sk_fill_input_buffer;
138    skip_input_data = sk_skip_input_data;
139    resync_to_restart = sk_resync_to_restart;
140    term_source = sk_term_source;
141    seek_input_data = sk_seek_input_data;
142//    SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
143}
144
145skjpeg_source_mgr::~skjpeg_source_mgr() {
146    if (fMemoryBase) {
147        sk_free(fMemoryBase);
148    }
149    if (fUnrefStream) {
150        fStream->unref();
151    }
152}
153
154///////////////////////////////////////////////////////////////////////////////
155
156static void sk_init_destination(j_compress_ptr cinfo) {
157    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
158
159    dest->next_output_byte = dest->fBuffer;
160    dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
161}
162
163static boolean sk_empty_output_buffer(j_compress_ptr cinfo) {
164    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
165
166//  if (!dest->fStream->write(dest->fBuffer, skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer))
167    if (!dest->fStream->write(dest->fBuffer,
168            skjpeg_destination_mgr::kBufferSize)) {
169        ERREXIT(cinfo, JERR_FILE_WRITE);
170        return false;
171    }
172
173    dest->next_output_byte = dest->fBuffer;
174    dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
175    return TRUE;
176}
177
178static void sk_term_destination (j_compress_ptr cinfo) {
179    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
180
181    size_t size = skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer;
182    if (size > 0) {
183        if (!dest->fStream->write(dest->fBuffer, size)) {
184            ERREXIT(cinfo, JERR_FILE_WRITE);
185            return;
186        }
187    }
188    dest->fStream->flush();
189}
190
191skjpeg_destination_mgr::skjpeg_destination_mgr(SkWStream* stream)
192        : fStream(stream) {
193    this->init_destination = sk_init_destination;
194    this->empty_output_buffer = sk_empty_output_buffer;
195    this->term_destination = sk_term_destination;
196}
197
198void skjpeg_error_exit(j_common_ptr cinfo) {
199    skjpeg_error_mgr* error = (skjpeg_error_mgr*)cinfo->err;
200
201    (*error->output_message) (cinfo);
202
203    /* Let the memory manager delete any temp files before we die */
204    jpeg_destroy(cinfo);
205
206    longjmp(error->fJmpBuf, -1);
207}
208