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