1 // Copyright (C) 2016 Lukas Lalinsky
2 // Distributed under the MIT license, see the LICENSE file for details.
3
4 #include "fingerprint_decompressor.h"
5 #include "debug.h"
6 #include "utils/pack_int3_array.h"
7 #include "utils/pack_int5_array.h"
8 #include "utils/unpack_int3_array.h"
9 #include "utils/unpack_int5_array.h"
10 #include "utils.h"
11
12 namespace chromaprint {
13
14 static const int kMaxNormalValue = 7;
15 static const int kNormalBits = 3;
16 static const int kExceptionBits = 5;
17
FingerprintDecompressor()18 FingerprintDecompressor::FingerprintDecompressor()
19 {
20 }
21
UnpackBits()22 void FingerprintDecompressor::UnpackBits()
23 {
24 int i = 0, last_bit = 0, value = 0;
25 for (size_t j = 0; j < m_bits.size(); j++) {
26 int bit = m_bits[j];
27 if (bit == 0) {
28 m_output[i] = (i > 0) ? value ^ m_output[i - 1] : value;
29 value = 0;
30 last_bit = 0;
31 i++;
32 continue;
33 }
34 bit += last_bit;
35 last_bit = bit;
36 value |= 1 << (bit - 1);
37 }
38 }
39
Decompress(const std::string & input)40 bool FingerprintDecompressor::Decompress(const std::string &input)
41 {
42 if (input.size() < 4) {
43 DEBUG("FingerprintDecompressor::Decompress() -- Invalid fingerprint (shorter than 4 bytes)");
44 return false;
45 }
46
47 m_algorithm = input[0];
48
49 const size_t num_values =
50 ((size_t)((unsigned char)(input[1])) << 16) |
51 ((size_t)((unsigned char)(input[2])) << 8) |
52 ((size_t)((unsigned char)(input[3])) );
53
54 size_t offset = 4;
55 m_bits.resize(GetUnpackedInt3ArraySize(input.size() - offset));
56 UnpackInt3Array(input.begin() + offset, input.end(), m_bits.begin());
57
58 size_t found_values = 0, num_exceptional_bits = 0;
59 for (size_t i = 0; i < m_bits.size(); i++) {
60 if (m_bits[i] == 0) {
61 found_values += 1;
62 if (found_values == num_values) {
63 m_bits.resize(i + 1);
64 break;
65 }
66 } else if (m_bits[i] == kMaxNormalValue) {
67 num_exceptional_bits += 1;
68 }
69 }
70
71 if (found_values != num_values) {
72 DEBUG("FingerprintDecompressor::Decompress() -- Invalid fingerprint (too short, not enough input for normal bits)");
73 return false;
74 }
75
76 offset += GetPackedInt3ArraySize(m_bits.size());
77 if (input.size() < offset + GetPackedInt5ArraySize(num_exceptional_bits)) {
78 DEBUG("FingerprintDecompressor::Decompress() -- Invalid fingerprint (too short, not enough input for exceptional bits)");
79 return false;
80 }
81
82 if (num_exceptional_bits) {
83 m_exceptional_bits.resize(GetUnpackedInt5ArraySize(GetPackedInt5ArraySize(num_exceptional_bits)));
84 UnpackInt5Array(input.begin() + offset, input.end(), m_exceptional_bits.begin());
85 for (size_t i = 0, j = 0; i < m_bits.size(); i++) {
86 if (m_bits[i] == kMaxNormalValue) {
87 m_bits[i] += m_exceptional_bits[j++];
88 }
89 }
90 }
91
92 m_output.assign(num_values, -1);
93
94 UnpackBits();
95 return true;
96 }
97
98 }; // namespace chromaprint
99