diff options
Diffstat (limited to 'Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp')
-rw-r--r-- | Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp b/Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp new file mode 100644 index 0000000000..69b3a91d76 --- /dev/null +++ b/Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com> + * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/BuiltinWrappers.h> + +#include "BooleanDecoder.h" + +namespace Gfx { + +/* 9.2.1 */ +ErrorOr<BooleanDecoder> BooleanDecoder::initialize(MaybeOwned<BigEndianInputBitStream> bit_stream, size_t size_in_bytes) +{ + VERIFY(bit_stream->is_aligned_to_byte_boundary()); + auto value = TRY(bit_stream->read_value<u8>()); + u8 range = 255; + u64 bits_left = (8 * size_in_bytes) - 8; + BooleanDecoder decoder { move(bit_stream), value, range, bits_left }; + if (TRY(decoder.read_bool(128))) + return Error::from_string_literal("Range decoder marker was non-zero"); + return decoder; +} + +/* 9.2.2 */ +ErrorOr<bool> BooleanDecoder::read_bool(u8 probability) +{ + auto split = 1u + (((m_range - 1u) * probability) >> 8u); + bool return_bool; + + if (m_value < split) { + m_range = split; + return_bool = false; + } else { + m_range -= split; + m_value -= split; + return_bool = true; + } + + if (m_range < 128) { + u8 bits_to_shift_into_range = count_leading_zeroes(m_range); + + if (bits_to_shift_into_range > m_bits_left) + return Error::from_string_literal("Range decoder is out of data"); + + m_range <<= bits_to_shift_into_range; + m_value = (m_value << bits_to_shift_into_range) | TRY(m_bit_stream->read_bits<u8>(bits_to_shift_into_range)); + m_bits_left -= bits_to_shift_into_range; + } + + return return_bool; +} + +ErrorOr<u8> BooleanDecoder::read_literal(u8 bits) +{ + u8 return_value = 0; + for (size_t i = 0; i < bits; i++) { + return_value = (2 * return_value) + TRY(read_bool(128)); + } + return return_value; +} + +/* 9.2.3 */ +ErrorOr<void> BooleanDecoder::finish_decode() +{ + while (m_bits_left > 0) { + auto padding_read_size = min(m_bits_left, 64); + auto padding_bits = TRY(m_bit_stream->read_bits(padding_read_size)); + m_bits_left -= padding_read_size; + + if (padding_bits != 0) + return Error::from_string_literal("Range decoder has non-zero padding element"); + } + + // FIXME: It is a requirement of bitstream conformance that enough padding bits are inserted to ensure that the final coded byte of a frame is not equal to a superframe marker. + // A byte b is equal to a superframe marker if and only if (b & 0xe0)is equal to 0xc0, i.e. if the most significant 3 bits are equal to 0b110. + return {}; +} + +} |