|
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
|