summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp')
-rw-r--r--Userland/Libraries/LibGfx/ImageFormats/BooleanDecoder.cpp82
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 {};
+}
+
+}