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