63 lines
1.7 KiB
Dart
63 lines
1.7 KiB
Dart
// Copyright (c) 2023, Sudipto Chandra
|
|
// All rights reserved. Check LICENSE file for details.
|
|
|
|
import 'dart:typed_data';
|
|
|
|
import 'codec.dart';
|
|
|
|
abstract class BitDecoder extends HashlibConverter {
|
|
/// Creates a new [BitDecoder] instance.
|
|
const BitDecoder();
|
|
|
|
/// Converts [encoded] array of numbers with bit-length of [source] to an array
|
|
/// of numbers with bit-length of [target]. The [encoded] array will be treated
|
|
/// as a sequence of bits to convert.
|
|
///
|
|
/// If the [encoded] array contains negative numbers or numbers having more than
|
|
/// the [source] bits, it will be treated as the end of the input sequence.
|
|
///
|
|
/// After consuming all of input sequence, if there are some non-zero partial
|
|
/// word remains, it will throw [FormatException].
|
|
@override
|
|
List<int> convert(covariant List<int> encoded) {
|
|
int x, p, s, t, l, n, sb, tb;
|
|
sb = source;
|
|
tb = target;
|
|
if (sb < 2 || sb > 64) {
|
|
throw ArgumentError('The source bit length should be between 2 to 64');
|
|
}
|
|
if (tb < 2 || tb > 64) {
|
|
throw ArgumentError('The target bit length should be between 2 to 64');
|
|
}
|
|
|
|
l = encoded.length * sb;
|
|
var out = Uint8List(l ~/ tb);
|
|
|
|
// generate words from the input bits
|
|
p = n = t = l = 0;
|
|
s = 1 << (sb - 1);
|
|
s = s ^ (s - 1);
|
|
for (x in encoded) {
|
|
if (x < 0 || x > s) break;
|
|
p = (p << sb) ^ x;
|
|
t = (t << sb) ^ s;
|
|
n += sb;
|
|
while (n >= tb) {
|
|
n -= tb;
|
|
out[l++] = p >>> n;
|
|
t >>>= tb;
|
|
p &= t;
|
|
}
|
|
}
|
|
|
|
// p > 0 means that there is a non-zero partial word remaining
|
|
if (p > 0) {
|
|
throw FormatException('Invalid length');
|
|
}
|
|
|
|
if (l < out.length) {
|
|
return out.sublist(0, l);
|
|
}
|
|
return out;
|
|
}
|
|
}
|