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 "src/codec/SkJpegDecoderMgr.h"
9
10#include "src/codec/SkJpegUtility.h"
11
12#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
13    #include "include/android/SkAndroidFrameworkUtils.h"
14#endif
15
16/*
17 * Print information, warning, and error messages
18 */
19static void print_message(const j_common_ptr info, const char caller[]) {
20    char buffer[JMSG_LENGTH_MAX];
21    info->err->format_message(info, buffer);
22    SkCodecPrintf("libjpeg error %d <%s> from %s\n", info->err->msg_code, buffer, caller);
23}
24
25/*
26 * Reporting function for error and warning messages.
27 */
28static void output_message(j_common_ptr info) {
29    print_message(info, "output_message");
30}
31
32static void progress_monitor(j_common_ptr info) {
33  int scan = ((j_decompress_ptr)info)->input_scan_number;
34  // Progressive images with a very large number of scans can cause the
35  // decoder to hang.  Here we use the progress monitor to abort on
36  // a very large number of scans.  100 is arbitrary, but much larger
37  // than the number of scans we might expect in a normal image.
38  if (scan >= 100) {
39      skjpeg_err_exit(info);
40  }
41}
42
43bool JpegDecoderMgr::returnFalse(const char caller[]) {
44    print_message((j_common_ptr) &fDInfo, caller);
45    return false;
46}
47
48SkCodec::Result JpegDecoderMgr::returnFailure(const char caller[], SkCodec::Result result) {
49    print_message((j_common_ptr) &fDInfo, caller);
50    return result;
51}
52
53bool JpegDecoderMgr::getEncodedColor(SkEncodedInfo::Color* outColor) {
54    switch (fDInfo.jpeg_color_space) {
55        case JCS_GRAYSCALE:
56            *outColor = SkEncodedInfo::kGray_Color;
57            return true;
58        case JCS_YCbCr:
59            *outColor = SkEncodedInfo::kYUV_Color;
60            return true;
61        case JCS_RGB:
62#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
63            SkAndroidFrameworkUtils::SafetyNetLog("118372692");
64#endif
65            *outColor = SkEncodedInfo::kRGB_Color;
66            return true;
67        case JCS_YCCK:
68            *outColor = SkEncodedInfo::kYCCK_Color;
69            return true;
70        case JCS_CMYK:
71            *outColor = SkEncodedInfo::kInvertedCMYK_Color;
72            return true;
73        default:
74            return false;
75    }
76}
77
78JpegDecoderMgr::JpegDecoderMgr(SkStream* stream)
79    : fSrcMgr(stream)
80    , fInit(false)
81{
82    // Error manager must be set before any calls to libjeg in order to handle failures
83    fDInfo.err = jpeg_std_error(&fErrorMgr);
84    fErrorMgr.error_exit = skjpeg_err_exit;
85}
86
87void JpegDecoderMgr::init() {
88    jpeg_create_decompress(&fDInfo);
89    fInit = true;
90    fDInfo.src = &fSrcMgr;
91    fDInfo.err->output_message = &output_message;
92    fDInfo.progress = &fProgressMgr;
93    fProgressMgr.progress_monitor = &progress_monitor;
94}
95
96JpegDecoderMgr::~JpegDecoderMgr() {
97    if (fInit) {
98        jpeg_destroy_decompress(&fDInfo);
99    }
100}
101