Blame codecparsers/jpegParser.cpp

Packit 1244b8
/*
Packit 1244b8
 * Copyright 2016 Intel Corporation
Packit 1244b8
 *
Packit 1244b8
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1244b8
 * you may not use this file except in compliance with the License.
Packit 1244b8
 * You may obtain a copy of the License at
Packit 1244b8
 *
Packit 1244b8
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1244b8
 *
Packit 1244b8
 * Unless required by applicable law or agreed to in writing, software
Packit 1244b8
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1244b8
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1244b8
 * See the License for the specific language governing permissions and
Packit 1244b8
 * limitations under the License.
Packit 1244b8
 *
Packit 1244b8
 * ----
Packit 1244b8
 *
Packit 1244b8
 * Part of IJG's libjpeg library (primarily jdmarker.c) was used as a reference
Packit 1244b8
 * while implementing this parser.  This implementation loosely reproduces some
Packit 1244b8
 * of the parsing logic found in the libjpeg jdmarker.c file.  Although, this
Packit 1244b8
 * logic has been refactored using C++-style syntax and data structures and
Packit 1244b8
 * adjusted appropriately to fit into the overall libyami framework.  Therefore,
Packit 1244b8
 * this implementation is considered to be partially derived from IJG's libjpeg.
Packit 1244b8
 *
Packit 1244b8
 * The following license preamble, below, is reproduced from libjpeg's
Packit 1244b8
 * jdmarker.c file.  The README.ijg is also provided with this file:
Packit 1244b8
 *
Packit 1244b8
 * Copyright (C) 1991-1998, Thomas G. Lane.
Packit 1244b8
 * Modified 2009-2013 by Guido Vollbeding.
Packit 1244b8
 * The jdmarker.c file is part of the Independent JPEG Group's software.
Packit 1244b8
 * For conditions of distribution and use, see the accompanying README.ijg file.
Packit 1244b8
 *
Packit 1244b8
 */
Packit 1244b8
Packit 1244b8
#ifdef HAVE_CONFIG_H
Packit 1244b8
#include "config.h"
Packit 1244b8
#endif
Packit 1244b8
Packit 1244b8
// primary header
Packit 1244b8
#include "jpegParser.h"
Packit 1244b8
Packit 1244b8
// library headers
Packit 1244b8
#include "common/log.h"
Packit 1244b8
Packit 1244b8
// system headers
Packit 1244b8
#include <algorithm>
Packit 1244b8
#include <cstring>
Packit 1244b8
Packit 1244b8
namespace YamiParser {
Packit 1244b8
namespace JPEG {
Packit 1244b8
Packit 1244b8
#define INPUT_BYTE(var, action) \
Packit 1244b8
    do { \
Packit 1244b8
        if (m_input.end()) { \
Packit 1244b8
            action; \
Packit 1244b8
        } \
Packit 1244b8
        var = m_input.read(8); \
Packit 1244b8
    } while(0)
Packit 1244b8
Packit 1244b8
#define INPUT_2BYTES(var, action) \
Packit 1244b8
    do { \
Packit 1244b8
        uint16_t b1, b2; \
Packit 1244b8
        INPUT_BYTE(b1, action); \
Packit 1244b8
        INPUT_BYTE(b2, action); \
Packit 1244b8
        var = ((b1 << 8) | b2) & 0xffff; \
Packit 1244b8
    } while(0)
Packit 1244b8
Packit 1244b8
const Defaults Defaults::s_instance;
Packit 1244b8
Packit 1244b8
Defaults::Defaults()
Packit 1244b8
    : m_acHuffTables()
Packit 1244b8
    , m_dcHuffTables()
Packit 1244b8
    , m_quantTables()
Packit 1244b8
{
Packit 1244b8
    // The following tables are from
Packit 1244b8
    // https://www.w3.org/Graphics/JPEG/itu-t81.pdf
Packit 1244b8
Packit 1244b8
    { // K.3.3.1 Luminance DC coefficients
Packit 1244b8
        std::array<uint8_t, 16> codes = {
Packit 1244b8
            0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
Packit 1244b8
            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Packit 1244b8
        };
Packit 1244b8
        std::array<uint8_t, 256> values = {
Packit 1244b8
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
Packit 1244b8
            0x08, 0x09, 0x0a, 0x0b
Packit 1244b8
        };
Packit 1244b8
Packit 1244b8
        m_dcHuffTables[0].reset(new HuffTable());
Packit 1244b8
        m_dcHuffTables[0]->codes.swap(codes);
Packit 1244b8
        m_dcHuffTables[0]->values.swap(values);
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    { // K.3.3.1 Chrominance DC coefficients
Packit 1244b8
        std::array<uint8_t, 16> codes = {
Packit 1244b8
            0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
Packit 1244b8
            0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
Packit 1244b8
        };
Packit 1244b8
        std::array<uint8_t, 256> values = {
Packit 1244b8
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
Packit 1244b8
            0x08, 0x09, 0x0a, 0x0b
Packit 1244b8
        };
Packit 1244b8
Packit 1244b8
        m_dcHuffTables[1].reset(new HuffTable());
Packit 1244b8
        m_dcHuffTables[1]->codes.swap(codes);
Packit 1244b8
        m_dcHuffTables[1]->values.swap(values);
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    { // K.3.3.2 Luminance AC coefficients
Packit 1244b8
        std::array<uint8_t, 16> codes = {
Packit 1244b8
            0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
Packit 1244b8
            0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d
Packit 1244b8
        };
Packit 1244b8
        std::array<uint8_t, 256> values = {
Packit 1244b8
            0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
Packit 1244b8
            0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
Packit 1244b8
            0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
Packit 1244b8
            0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
Packit 1244b8
            0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
Packit 1244b8
            0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
Packit 1244b8
            0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
Packit 1244b8
            0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
Packit 1244b8
            0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
Packit 1244b8
            0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
Packit 1244b8
            0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
Packit 1244b8
            0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
Packit 1244b8
            0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
Packit 1244b8
            0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
Packit 1244b8
            0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
Packit 1244b8
            0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
Packit 1244b8
            0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
Packit 1244b8
            0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
Packit 1244b8
            0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
Packit 1244b8
            0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
Packit 1244b8
            0xf9, 0xfa
Packit 1244b8
        };
Packit 1244b8
Packit 1244b8
        m_acHuffTables[0].reset(new HuffTable());
Packit 1244b8
        m_acHuffTables[0]->codes.swap(codes);
Packit 1244b8
        m_acHuffTables[0]->values.swap(values);
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    { // K.3.3.2 Chrominance AC coefficients
Packit 1244b8
        std::array<uint8_t, 16> codes = {
Packit 1244b8
            0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
Packit 1244b8
            0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
Packit 1244b8
        };
Packit 1244b8
        std::array<uint8_t, 256> values = {
Packit 1244b8
            0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
Packit 1244b8
            0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
Packit 1244b8
            0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
Packit 1244b8
            0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
Packit 1244b8
            0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
Packit 1244b8
            0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
Packit 1244b8
            0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
Packit 1244b8
            0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
Packit 1244b8
            0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
Packit 1244b8
            0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
Packit 1244b8
            0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
Packit 1244b8
            0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
Packit 1244b8
            0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
Packit 1244b8
            0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
Packit 1244b8
            0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
Packit 1244b8
            0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
Packit 1244b8
            0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
Packit 1244b8
            0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
Packit 1244b8
            0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
Packit 1244b8
            0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
Packit 1244b8
            0xf9, 0xfa
Packit 1244b8
        };
Packit 1244b8
Packit 1244b8
        m_acHuffTables[1].reset(new HuffTable());
Packit 1244b8
        m_acHuffTables[1]->codes.swap(codes);
Packit 1244b8
        m_acHuffTables[1]->values.swap(values);
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    static const std::array<uint8_t, 64> zigzag8x8 = {
Packit 1244b8
        0,   1,  8, 16,  9,  2,  3, 10,
Packit 1244b8
        17, 24, 32, 25, 18, 11,  4,  5,
Packit 1244b8
        12, 19, 26, 33, 40, 48, 41, 34,
Packit 1244b8
        27, 20, 13,  6,  7, 14, 21, 28,
Packit 1244b8
        35, 42, 49, 56, 57, 50, 43, 36,
Packit 1244b8
        29, 22, 15, 23, 30, 37, 44, 51,
Packit 1244b8
        58, 59, 52, 45, 38, 31, 39, 46,
Packit 1244b8
        53, 60, 61, 54, 47, 55, 62, 63
Packit 1244b8
    };
Packit 1244b8
Packit 1244b8
    { // Table K.1 Luminance quantization table values
Packit 1244b8
        std::array<uint16_t, DCTSIZE2> values = {
Packit 1244b8
            16,  11,  10,  16,  24,  40,  51,  61,
Packit 1244b8
            12,  12,  14,  19,  26,  58,  60,  55,
Packit 1244b8
            14,  13,  16,  24,  40,  57,  69,  56,
Packit 1244b8
            14,  17,  22,  29,  51,  87,  80,  62,
Packit 1244b8
            18,  22,  37,  56,  68, 109, 103,  77,
Packit 1244b8
            24,  35,  55,  64,  81, 104, 113,  92,
Packit 1244b8
            49,  64,  78,  87, 103, 121, 120, 101,
Packit 1244b8
            72,  92,  95,  98, 112, 100, 103,  99
Packit 1244b8
        };
Packit 1244b8
Packit 1244b8
        m_quantTables[0].reset(new QuantTable());
Packit 1244b8
        for (size_t i(0); i < DCTSIZE2; ++i)
Packit 1244b8
            m_quantTables[0]->values[i] = values[zigzag8x8[i]];
Packit 1244b8
        m_quantTables[0]->precision = 0; // 1-byte precision
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    { // Table K.2 Chrominance quantization table values
Packit 1244b8
        std::array<uint16_t, DCTSIZE2> values = {
Packit 1244b8
            17,  18,  24,  47,  99,  99,  99,  99,
Packit 1244b8
            18,  21,  26,  66,  99,  99,  99,  99,
Packit 1244b8
            24,  26,  56,  99,  99,  99,  99,  99,
Packit 1244b8
            47,  66,  99,  99,  99,  99,  99,  99,
Packit 1244b8
            99,  99,  99,  99,  99,  99,  99,  99,
Packit 1244b8
            99,  99,  99,  99,  99,  99,  99,  99,
Packit 1244b8
            99,  99,  99,  99,  99,  99,  99,  99,
Packit 1244b8
            99,  99,  99,  99,  99,  99,  99,  99
Packit 1244b8
        };
Packit 1244b8
Packit 1244b8
        m_quantTables[1].reset(new QuantTable());
Packit 1244b8
        for (size_t i(0); i < DCTSIZE2; ++i)
Packit 1244b8
            m_quantTables[1]->values[i] = values[zigzag8x8[i]];
Packit 1244b8
        m_quantTables[1]->precision = 0; // 1-byte precision
Packit 1244b8
    }
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
Parser::Parser(const uint8_t* data, const uint32_t size)
Packit 1244b8
    : m_input(data, size)
Packit 1244b8
    , m_data(data)
Packit 1244b8
    , m_size(size)
Packit 1244b8
    , m_current()
Packit 1244b8
    , m_frameHeader()
Packit 1244b8
    , m_scanHeader()
Packit 1244b8
    , m_quantTables()
Packit 1244b8
    , m_dcHuffTables()
Packit 1244b8
    , m_acHuffTables()
Packit 1244b8
    , m_arithDCL()
Packit 1244b8
    , m_arithDCU()
Packit 1244b8
    , m_arithACK()
Packit 1244b8
    , m_callbacks()
Packit 1244b8
    , m_sawSOI(false)
Packit 1244b8
    , m_sawEOI(false)
Packit 1244b8
    , m_sawSOS(false)
Packit 1244b8
    , m_restartInterval(0)
Packit 1244b8
{
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::skipBytes(const uint32_t nBytes)
Packit 1244b8
{
Packit 1244b8
    if ((static_cast<uint64_t>(nBytes) << 3)
Packit 1244b8
            > m_input.getRemainingBitsCount()) {
Packit 1244b8
        ERROR("Not enough bytes in stream");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    // BitReader only supports skipping a max of CACHEBYTES at a time
Packit 1244b8
    // for each call to skip.
Packit 1244b8
    const uint32_t nSkips = nBytes / BitReader::CACHEBYTES;
Packit 1244b8
    const uint32_t rem = nBytes % BitReader::CACHEBYTES;
Packit 1244b8
    for (uint32_t i(0); i < nSkips; ++i)
Packit 1244b8
        m_input.skip(BitReader::CACHEBYTES << 3);
Packit 1244b8
    m_input.skip(rem << 3);
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
void Parser::registerCallback(const Marker& marker, const Callback& callback)
Packit 1244b8
{
Packit 1244b8
    m_callbacks[marker].push_back(callback);
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
void Parser::registerStartOfFrameCallback(const Callback& callback)
Packit 1244b8
{
Packit 1244b8
    static const std::array<const Marker, 13> sofMarkers = {
Packit 1244b8
        M_SOF0, M_SOF1 , M_SOF2 , M_SOF3 , M_SOF5 , M_SOF6 , M_SOF7,
Packit 1244b8
        M_SOF9, M_SOF10, M_SOF11, M_SOF13, M_SOF14, M_SOF15 };
Packit 1244b8
Packit 1244b8
    for (size_t i(0); i < 13; ++i)
Packit 1244b8
        registerCallback(sofMarkers[i], callback);
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
Parser::CallbackResult Parser::notifyCallbacks() const
Packit 1244b8
{
Packit 1244b8
    const Callbacks::const_iterator match(m_callbacks.find(m_current.marker));
Packit 1244b8
    if (match != m_callbacks.end()) {
Packit 1244b8
        const CallbackList& callbacks = match->second;
Packit 1244b8
        const size_t nCallbacks = callbacks.size();
Packit 1244b8
        for (size_t i(0); i < nCallbacks; ++i)
Packit 1244b8
            if (callbacks[i]() == ParseSuspend)
Packit 1244b8
                return ParseSuspend;
Packit 1244b8
    }
Packit 1244b8
    return ParseContinue;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::firstMarker()
Packit 1244b8
{
Packit 1244b8
    uint32_t c, c2;
Packit 1244b8
Packit 1244b8
    INPUT_BYTE(c, return false);
Packit 1244b8
    INPUT_BYTE(c2, return false);
Packit 1244b8
    if (c != 0xFF || c2 != M_SOI) {
Packit 1244b8
        ERROR("No SOI found. Not a JPEG");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    m_current.marker = static_cast<Marker>(c2);
Packit 1244b8
    m_current.position = currentBytePosition() - 1;
Packit 1244b8
    m_current.length = 0; // set by marker parse routines when appropriate
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::nextMarker()
Packit 1244b8
{
Packit 1244b8
    if (m_input.getRemainingBitsCount() == 0)
Packit 1244b8
        return false;
Packit 1244b8
Packit 1244b8
    const uint8_t* const end = m_data + m_size - 1;
Packit 1244b8
    const uint8_t* const start = m_data + currentBytePosition();
Packit 1244b8
    const uint8_t* current = start;
Packit 1244b8
    const uint8_t* match;
Packit 1244b8
Packit 1244b8
    do {
Packit 1244b8
        match = std::find(current, end, 0xFF);
Packit 1244b8
        if (match == end) {
Packit 1244b8
            skipBytes(std::distance(start, match) + 1);
Packit 1244b8
            return false;
Packit 1244b8
        }
Packit 1244b8
        if (*(match + 1) < 0xFF && *(match + 1) >= M_SOF0)
Packit 1244b8
            break;
Packit 1244b8
        current = match + 1;
Packit 1244b8
    } while (true);
Packit 1244b8
Packit 1244b8
    skipBytes(std::distance(start, match) + 1);
Packit 1244b8
Packit 1244b8
    m_current.marker = static_cast<Marker>(m_input.read(8));
Packit 1244b8
    m_current.position = currentBytePosition() - 1;
Packit 1244b8
    m_current.length = 0; // set by marker parse routines when appropriate
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parse()
Packit 1244b8
{
Packit 1244b8
    while (true) {
Packit 1244b8
        if (!m_sawSOI) {
Packit 1244b8
            if (!firstMarker()) {
Packit 1244b8
                return false;
Packit 1244b8
            }
Packit 1244b8
        } else if (!nextMarker()) {
Packit 1244b8
            if (m_sawSOS && !m_sawEOI) {
Packit 1244b8
                // NOTE: By standard, a missing EOI technically means the image
Packit 1244b8
                // is corrupt.  However, there are many images in the wild where
Packit 1244b8
                // a missing EOI is the only corruption to the image (i.e. the
Packit 1244b8
                // entropy-coded data and headers are still intact).  This can
Packit 1244b8
                // happen, for example, when the image was encoded by a buggy
Packit 1244b8
                // application that forgets to append the EOI to the final
Packit 1244b8
                // image.  If a missing EOI is the only issue, then decoders can
Packit 1244b8
                // still successfully decode it.  However, a missing EOI does
Packit 1244b8
                // not necessarily mean the rest of the image is intact.  That
Packit 1244b8
                // is, there is no guarantee that the final decoded output will
Packit 1244b8
                // produce the desired result.  Either way, we insert a fake
Packit 1244b8
                // EOI marker here to give decoders a chance to decode the
Packit 1244b8
                // image.
Packit 1244b8
                WARNING("No EOI marker found on input... inserting one now");
Packit 1244b8
                m_current.marker = M_EOI;
Packit 1244b8
                m_current.position = currentBytePosition() - 1;
Packit 1244b8
                m_current.length = 0;
Packit 1244b8
            } else {
Packit 1244b8
                return m_sawEOI;
Packit 1244b8
            }
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        DEBUG("%s (byte:0x%02x position:%u)", __func__,
Packit 1244b8
            m_current.marker, m_current.position);
Packit 1244b8
Packit 1244b8
        bool parseSegment = false;
Packit 1244b8
Packit 1244b8
        switch (m_current.marker) {
Packit 1244b8
        case M_SOI:
Packit 1244b8
            parseSegment = parseSOI();
Packit 1244b8
            break;
Packit 1244b8
        case M_SOF0: // Baseline
Packit 1244b8
            parseSegment = parseSOF(true, false, false);
Packit 1244b8
            break;
Packit 1244b8
        case M_SOF1: // Extended sequential, Huffman
Packit 1244b8
            parseSegment = parseSOF(false, false, false);
Packit 1244b8
            break;
Packit 1244b8
        case M_SOF2: // Progressive, Huffman
Packit 1244b8
            parseSegment = parseSOF(false, true, false);
Packit 1244b8
            break;
Packit 1244b8
        case M_SOF9: // Extended sequential, arithmetic
Packit 1244b8
            parseSegment = parseSOF(false, false, true);
Packit 1244b8
            break;
Packit 1244b8
        case M_SOF10: // Progressive, arithmetic
Packit 1244b8
            parseSegment = parseSOF(false, true, true);
Packit 1244b8
            break;
Packit 1244b8
        case M_DAC:
Packit 1244b8
            parseSegment = parseDAC();
Packit 1244b8
            break;
Packit 1244b8
        case M_DHT:
Packit 1244b8
            parseSegment = parseDHT();
Packit 1244b8
            break;
Packit 1244b8
        case M_DQT:
Packit 1244b8
            parseSegment = parseDQT();
Packit 1244b8
            break;
Packit 1244b8
        case M_DRI:
Packit 1244b8
            parseSegment = parseDRI();
Packit 1244b8
            break;
Packit 1244b8
        case M_SOS:
Packit 1244b8
            parseSegment = parseSOS();
Packit 1244b8
            break;
Packit 1244b8
        case M_EOI:
Packit 1244b8
            parseSegment = parseEOI();
Packit 1244b8
            break;
Packit 1244b8
Packit 1244b8
        case M_APP0:
Packit 1244b8
        case M_APP1:
Packit 1244b8
        case M_APP2:
Packit 1244b8
        case M_APP3:
Packit 1244b8
        case M_APP4:
Packit 1244b8
        case M_APP5:
Packit 1244b8
        case M_APP6:
Packit 1244b8
        case M_APP7:
Packit 1244b8
        case M_APP8:
Packit 1244b8
        case M_APP9:
Packit 1244b8
        case M_APP10:
Packit 1244b8
        case M_APP11:
Packit 1244b8
        case M_APP12:
Packit 1244b8
        case M_APP13:
Packit 1244b8
        case M_APP14:
Packit 1244b8
        case M_APP15:
Packit 1244b8
            parseSegment = parseAPP();
Packit 1244b8
            break;
Packit 1244b8
Packit 1244b8
        case M_COM:
Packit 1244b8
        case M_RST0:
Packit 1244b8
        case M_RST1:
Packit 1244b8
        case M_RST2:
Packit 1244b8
        case M_RST3:
Packit 1244b8
        case M_RST4:
Packit 1244b8
        case M_RST5:
Packit 1244b8
        case M_RST6:
Packit 1244b8
        case M_RST7:
Packit 1244b8
            parseSegment = true;
Packit 1244b8
            break;
Packit 1244b8
Packit 1244b8
        /* Currently unsupported SOFn types */
Packit 1244b8
        case M_SOF3:  // Lossless, Huffman
Packit 1244b8
        case M_SOF5:  // Differential sequential, Huffman
Packit 1244b8
        case M_SOF6:  // Differential progressive, Huffman
Packit 1244b8
        case M_SOF7:  // Differential lossless, Huffman
Packit 1244b8
        case M_JPG:   // Reserved for JPEG extensions
Packit 1244b8
        case M_SOF11: // Lossless, arithmetic
Packit 1244b8
        case M_SOF13: // Differential sequential, arithmetic
Packit 1244b8
        case M_SOF14: // Differential progressive, arithmetic
Packit 1244b8
        case M_SOF15: // Differential lossless, arithmetic
Packit 1244b8
            //unsupported
Packit 1244b8
            ERROR("Unsupported marker encountered: 0x%02x", m_current.marker);
Packit 1244b8
            return false;
Packit 1244b8
Packit 1244b8
        default:
Packit 1244b8
            // unknown or unhandled marker
Packit 1244b8
            ERROR("Unknown or unhandled marker: 0x%02x", m_current.marker);
Packit 1244b8
            return false;
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        if (!parseSegment)
Packit 1244b8
            return false;
Packit 1244b8
Packit 1244b8
        if (notifyCallbacks() == ParseSuspend)
Packit 1244b8
            return true;
Packit 1244b8
    }
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseSOI()
Packit 1244b8
{
Packit 1244b8
    if (m_sawSOI) {
Packit 1244b8
        ERROR("Duplicate SOI encountered");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    m_sawSOI = true;
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseAPP()
Packit 1244b8
{
Packit 1244b8
    INPUT_2BYTES(m_current.length, return false);
Packit 1244b8
Packit 1244b8
    return skipBytes(m_current.length - 2);
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseSOF(bool isBaseline, bool isProgressive, bool isArithmetic)
Packit 1244b8
{
Packit 1244b8
    if (m_frameHeader) {
Packit 1244b8
        ERROR("Duplicate SOF encountered");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    INPUT_2BYTES(m_current.length, return false);
Packit 1244b8
Packit 1244b8
    m_frameHeader.reset(new FrameHeader);
Packit 1244b8
Packit 1244b8
    m_frameHeader->isBaseline = isBaseline;
Packit 1244b8
    m_frameHeader->isProgressive = isProgressive;
Packit 1244b8
    m_frameHeader->isArithmetic = isArithmetic;
Packit 1244b8
Packit 1244b8
    INPUT_BYTE(m_frameHeader->dataPrecision, return false);
Packit 1244b8
    INPUT_2BYTES(m_frameHeader->imageHeight, return false);
Packit 1244b8
    INPUT_2BYTES(m_frameHeader->imageWidth, return false);
Packit 1244b8
Packit 1244b8
    uint32_t numComponents;
Packit 1244b8
Packit 1244b8
    INPUT_BYTE(numComponents, return false);
Packit 1244b8
Packit 1244b8
    DEBUG("baseline      : %d", m_frameHeader->isBaseline);
Packit 1244b8
    DEBUG("progressive   : %d", m_frameHeader->isProgressive);
Packit 1244b8
    DEBUG("arithmetic    : %d", m_frameHeader->isArithmetic);
Packit 1244b8
    DEBUG("precision     : %d", m_frameHeader->dataPrecision);
Packit 1244b8
    DEBUG("image width   : %u", m_frameHeader->imageWidth);
Packit 1244b8
    DEBUG("image height  : %u", m_frameHeader->imageHeight);
Packit 1244b8
    DEBUG("num components: %d", numComponents);
Packit 1244b8
Packit 1244b8
    if (m_frameHeader->imageWidth <= 0 || m_frameHeader->imageHeight <= 0
Packit 1244b8
            || numComponents <= 0) {
Packit 1244b8
        ERROR("Empty image");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    if ((m_current.length - 8) != (numComponents * 3)
Packit 1244b8
            || numComponents > MAX_COMPS_IN_SCAN) {
Packit 1244b8
        ERROR("Bad length");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    m_frameHeader->components.resize(numComponents);
Packit 1244b8
    m_frameHeader->maxHSampleFactor = 0;
Packit 1244b8
    m_frameHeader->maxVSampleFactor = 0;
Packit 1244b8
Packit 1244b8
    for (size_t index(0); index < numComponents; ++index) {
Packit 1244b8
        int factor;
Packit 1244b8
        Component::Shared& component = m_frameHeader->components[index];
Packit 1244b8
        component.reset(new Component);
Packit 1244b8
        component->index = index;
Packit 1244b8
Packit 1244b8
        INPUT_BYTE(component->id, return false);
Packit 1244b8
        INPUT_BYTE(factor, return false);
Packit 1244b8
Packit 1244b8
        component->hSampleFactor = (factor >> 4) & 15;
Packit 1244b8
        component->vSampleFactor = factor & 15;
Packit 1244b8
Packit 1244b8
        if (component->hSampleFactor > m_frameHeader->maxHSampleFactor)
Packit 1244b8
            m_frameHeader->maxHSampleFactor = component->hSampleFactor;
Packit 1244b8
Packit 1244b8
        if (component->vSampleFactor > m_frameHeader->maxVSampleFactor)
Packit 1244b8
            m_frameHeader->maxVSampleFactor = component->vSampleFactor;
Packit 1244b8
Packit 1244b8
        INPUT_BYTE(component->quantTableNumber, return false);
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
static bool componentIdMatches(const int id, const Component::Shared& component)
Packit 1244b8
{
Packit 1244b8
    return id == component->id;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseSOS()
Packit 1244b8
{
Packit 1244b8
    using std::placeholders::_1;
Packit 1244b8
Packit 1244b8
    if (!m_frameHeader) {
Packit 1244b8
        ERROR("SOS Encountered before SOF");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    INPUT_2BYTES(m_current.length, return false);
Packit 1244b8
Packit 1244b8
    size_t numComponents;
Packit 1244b8
Packit 1244b8
    INPUT_BYTE(numComponents, return false);
Packit 1244b8
Packit 1244b8
    if (m_current.length != (numComponents * 2 + 6)
Packit 1244b8
            || numComponents < 1
Packit 1244b8
            || numComponents > MAX_COMPS_IN_SCAN) {
Packit 1244b8
        ERROR("Invalid SOS Length");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    m_scanHeader.reset(new ScanHeader);
Packit 1244b8
Packit 1244b8
    m_scanHeader->numComponents = numComponents;
Packit 1244b8
Packit 1244b8
    for (size_t i(0); i < numComponents; ++i)
Packit 1244b8
        m_scanHeader->components[i].reset();
Packit 1244b8
Packit 1244b8
    for (size_t i(0); i < numComponents; ++i) {
Packit 1244b8
        int id;
Packit 1244b8
        int c;
Packit 1244b8
Packit 1244b8
        INPUT_BYTE(id, return false);
Packit 1244b8
Packit 1244b8
        Components::iterator component = std::find_if(
Packit 1244b8
            m_frameHeader->components.begin(),
Packit 1244b8
            m_frameHeader->components.end(),
Packit 1244b8
            std::bind(&componentIdMatches, id, _1));
Packit 1244b8
Packit 1244b8
        if (component == m_frameHeader->components.end()
Packit 1244b8
                || m_scanHeader->components[(*component)->index]) {
Packit 1244b8
            ERROR("Bad Component Id (%d)", id);
Packit 1244b8
            return false;
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        INPUT_BYTE(c, return false);
Packit 1244b8
Packit 1244b8
        m_scanHeader->components[i] = *component;
Packit 1244b8
        (*component)->dcTableNumber = (c >> 4) & 15;
Packit 1244b8
        (*component)->acTableNumber = c & 15;
Packit 1244b8
Packit 1244b8
        /* This CSi (cc) should differ from the previous CSi */
Packit 1244b8
        for (size_t pi(0); pi < i; ++pi) {
Packit 1244b8
            if (m_scanHeader->components[pi] == (*component)) {
Packit 1244b8
                ERROR("Bad Component Id (%d)", id);
Packit 1244b8
                return false;
Packit 1244b8
            }
Packit 1244b8
        }
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    // The following are used only in progressive mode
Packit 1244b8
    // FIXME: validate these values according to JPEG specification
Packit 1244b8
    INPUT_BYTE(m_scanHeader->ss, return false);
Packit 1244b8
    INPUT_BYTE(m_scanHeader->se, return false);
Packit 1244b8
    INPUT_BYTE(m_scanHeader->ah, return false);
Packit 1244b8
Packit 1244b8
    m_scanHeader->al = m_scanHeader->ah & 15;
Packit 1244b8
    m_scanHeader->ah = (m_scanHeader->ah >> 4) & 15;
Packit 1244b8
Packit 1244b8
    m_sawSOS = true;
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseEOI()
Packit 1244b8
{
Packit 1244b8
    if (m_sawEOI) {
Packit 1244b8
        ERROR("Duplicate EOI encountered");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    m_sawEOI = true;
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseDAC()
Packit 1244b8
{
Packit 1244b8
    INPUT_2BYTES(m_current.length, return false);
Packit 1244b8
Packit 1244b8
    long length = m_current.length - 2;
Packit 1244b8
Packit 1244b8
    while (length > 0) {
Packit 1244b8
        size_t index;
Packit 1244b8
        int value;
Packit 1244b8
Packit 1244b8
        INPUT_BYTE(index, return false);
Packit 1244b8
        INPUT_BYTE(value, return false);
Packit 1244b8
Packit 1244b8
        length -= 2;
Packit 1244b8
Packit 1244b8
        if (index < 0 || index >= (2 * NUM_ARITH_TBLS)) {
Packit 1244b8
            ERROR("Invalid DAC Index");
Packit 1244b8
            return false;
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        if (index >= NUM_ARITH_TBLS) {
Packit 1244b8
            m_arithACK[index - NUM_ARITH_TBLS] = value;
Packit 1244b8
        } else {
Packit 1244b8
            m_arithDCL[index] = value & 15;
Packit 1244b8
            m_arithDCU[index] = (value >> 4) & 15;
Packit 1244b8
            if (m_arithDCL[index] > m_arithDCU[index]) {
Packit 1244b8
                ERROR("Invalid DAC Value");
Packit 1244b8
                return false;
Packit 1244b8
            }
Packit 1244b8
        }
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    if (length != 0) {
Packit 1244b8
        ERROR("Invalid DAC Length");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseDQT()
Packit 1244b8
{
Packit 1244b8
    INPUT_2BYTES(m_current.length, return false);
Packit 1244b8
Packit 1244b8
    long length = m_current.length - 2;
Packit 1244b8
Packit 1244b8
    while (length > 0) {
Packit 1244b8
        int c;
Packit 1244b8
Packit 1244b8
        INPUT_BYTE(c, return false);
Packit 1244b8
Packit 1244b8
        const size_t index = c & 15;
Packit 1244b8
        const int precision = (c >> 4) & 15;
Packit 1244b8
Packit 1244b8
        if (index >= NUM_QUANT_TBLS) {
Packit 1244b8
            ERROR("Invalid quant table index encountered");
Packit 1244b8
            return false;
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        QuantTable::Shared& quantTable = m_quantTables[index];
Packit 1244b8
        if (!quantTable)
Packit 1244b8
            quantTable.reset(new QuantTable);
Packit 1244b8
Packit 1244b8
        quantTable->precision = precision;
Packit 1244b8
Packit 1244b8
        for (size_t i(0); i < DCTSIZE2; ++i) {
Packit 1244b8
            if (precision)
Packit 1244b8
                INPUT_2BYTES(quantTable->values[i], return false);
Packit 1244b8
            else
Packit 1244b8
                INPUT_BYTE(quantTable->values[i], return false);
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        const uint32_t nbytes = precision ? 2 : 1;
Packit 1244b8
        length -= (DCTSIZE2 * nbytes) + 1;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    if (length != 0) {
Packit 1244b8
        ERROR("Bad DQT length");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseDHT()
Packit 1244b8
{
Packit 1244b8
    INPUT_2BYTES(m_current.length, return false);
Packit 1244b8
Packit 1244b8
    long length = m_current.length - 2;
Packit 1244b8
Packit 1244b8
    while (length > 16) {
Packit 1244b8
        size_t index;
Packit 1244b8
Packit 1244b8
        INPUT_BYTE(index, return false);
Packit 1244b8
Packit 1244b8
        long count = 0;
Packit 1244b8
        std::vector<uint8_t> codes(16, 0);
Packit 1244b8
        for (size_t i(0); i < 16; ++i) {
Packit 1244b8
            INPUT_BYTE(codes[i], return false);
Packit 1244b8
            count += codes[i];
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        length -= 1 + 16;
Packit 1244b8
Packit 1244b8
        if (count > 256 || count > length) {
Packit 1244b8
            ERROR("Bad Huff Table");
Packit 1244b8
            return false;
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        std::vector<uint8_t> huffval(256, 0);
Packit 1244b8
        for (long i(0); i < count; ++i)
Packit 1244b8
            INPUT_BYTE(huffval[i], return false);
Packit 1244b8
Packit 1244b8
        length -= count;
Packit 1244b8
Packit 1244b8
        HuffTables* huffTables;
Packit 1244b8
        if (index & 0x10) { /* AC table definition */
Packit 1244b8
            index -= 0x10;
Packit 1244b8
            huffTables = &m_acHuffTables;
Packit 1244b8
        } else { /* DC table definition */
Packit 1244b8
            huffTables = &m_dcHuffTables;
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        if (index < 0 || index >= NUM_HUFF_TBLS) {
Packit 1244b8
            ERROR("Bad Huff Table Index");
Packit 1244b8
            return false;
Packit 1244b8
        }
Packit 1244b8
Packit 1244b8
        HuffTable::Shared& huffTable = (*huffTables)[index];
Packit 1244b8
        if (!huffTable)
Packit 1244b8
            huffTable.reset(new HuffTable);
Packit 1244b8
Packit 1244b8
        std::memcpy(&huffTable->codes[0], &codes[0],
Packit 1244b8
                    sizeof(huffTable->codes));
Packit 1244b8
        std::memcpy(&huffTable->values[0], &huffval[0],
Packit 1244b8
                    sizeof(huffTable->values));
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    if (length != 0) {
Packit 1244b8
        ERROR("Bad DHT Length");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool Parser::parseDRI()
Packit 1244b8
{
Packit 1244b8
    INPUT_2BYTES(m_current.length, return false);
Packit 1244b8
Packit 1244b8
    if (m_current.length != 4) {
Packit 1244b8
        ERROR("Bad DRI Length");
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    INPUT_2BYTES(m_restartInterval, return false);
Packit 1244b8
Packit 1244b8
    return true;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
} // namespace JPEG
Packit 1244b8
} // namespace YamiParser