-
Notifications
You must be signed in to change notification settings - Fork 52
/
rs.cc
153 lines (132 loc) · 4.47 KB
/
rs.cc
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "rs.hh"
#include <stdexcept>
#include <string.h>
#include <iostream>
extern "C" {
#include <fec.h>
}
using namespace std;
RSCodec::RSCodec(const std::vector<unsigned int>& roots, unsigned int fcr, unsigned int prim, unsigned int nroots, unsigned int pad, unsigned int bits)
: d_N((1<< (bits)) - pad -1),
d_K((1<< (bits)) - pad - 1 - nroots),
d_nroots(nroots),
d_bits(bits)
{
if(d_bits > 8)
throw std::runtime_error("This encoder supports 8 bits at most");
for(const auto& r : roots)
d_gfpoly |= (1<<r);
d_rs = init_rs_char(d_bits, d_gfpoly, fcr, prim, nroots, pad);
if(!d_rs)
throw std::runtime_error("Unable to initialize RS codec");
}
void RSCodec::encode(std::string& msg)
{
if(msg.size() > d_K)
throw std::runtime_error("Can't encode message longer than "+std::to_string(d_K)+" bytes");
msg.append(d_K - msg.size(), 0);
// void encode_rs_char(void *rs,unsigned char *data,
// unsigned char *parity);
uint8_t parity[d_nroots];
encode_rs_char(d_rs, (uint8_t*)msg.c_str(), parity);
msg.append((char*)&parity[0], (char*)&parity[d_nroots]);
}
int RSCodec::decode(const std::string& in, std::string& out, vector<unsigned int>* corrs)
{
// int decode_rs_char(void *rs,unsigned char *data,int *eras_pos,
// int no_eras);
unsigned char data[in.length()];
memcpy(data, in.c_str(), in.length());
vector<int> eras_pos;
int eras_no=0;
if(corrs) {
for(const auto& c : *corrs) {
eras_pos.push_back(c);
eras_no++;
}
}
eras_pos.resize(d_nroots);
int ret = decode_rs_char(d_rs, data, &eras_pos[0], eras_no);
/*
The decoder corrects the symbols "in place", returning the number of symbols in error. If the codeword is uncorrectable, -1 is returned and the data block is unchanged. If
eras_pos is non-null, it is used to return a list of corrected symbol positions, in no particular order. This means that the array passed through this parameter must have at
least nroots elements to prevent a possible buffer overflow.
*/
if(ret < 0)
throw std::runtime_error("Could not correct message");
if(corrs)
corrs->clear();
if(ret && corrs) {
for(int n=0; n < ret; ++n)
corrs->push_back(eras_pos.at(n));
}
out.assign((char*) data, (char*)data + d_N);
return ret;
}
RSCodec::~RSCodec()
{
if(d_rs)
free_rs_char(d_rs);
}
////
RSCodecInt::RSCodecInt(const std::vector<unsigned int>& roots, unsigned int fcr, unsigned int prim, unsigned int nroots, unsigned int pad, unsigned int bits)
: d_N((1<< (bits)) - pad -1),
d_K((1<< (bits)) - pad - 1 - nroots),
d_nroots(nroots),
d_bits(bits)
{
if(d_bits > 32)
throw std::runtime_error("This encoder supports 32 bits at most");
for(const auto& r : roots)
d_gfpoly |= (1<<r);
d_rs = init_rs_int(d_bits, d_gfpoly, fcr, prim, nroots, pad);
if(!d_rs)
throw std::runtime_error("Unable to initialize RS codec");
}
void RSCodecInt::encode(vector<unsigned int>& msg)
{
if(msg.size() > d_K)
throw std::runtime_error("Can't encode message longer than "+std::to_string(d_K)+" bytes");
msg.resize(d_K);
vector<unsigned int> parity(d_nroots);
encode_rs_int(d_rs, (int*)&msg[0], (int*)&parity[0]);
for(const auto& i : parity)
msg.push_back(i);
}
int RSCodecInt::decode(const std::vector<unsigned int>& in, std::vector<unsigned int>& out, vector<unsigned int>* corrs)
{
// int decode_rs_char(void *rs,unsigned char *data,int *eras_pos,
// int no_eras);
vector<unsigned int> data = in;
vector<unsigned int> eras_pos;
int eras_no=0;
if(corrs) {
for(const auto& c : *corrs) {
eras_pos.push_back(c);
eras_no++;
}
}
eras_pos.resize(d_nroots);
int ret = decode_rs_int(d_rs, (int*)&data[0], (int*)&eras_pos[0], eras_no);
/*
The decoder corrects the symbols "in place", returning the number of symbols in error. If the codeword is uncorrectable, -1 is returned and the data block is unchanged. If
eras_pos is non-null, it is used to return a list of corrected symbol positions, in no particular order. This means that the array passed through this parameter must have at
least nroots elements to prevent a possible buffer overflow.
*/
if(ret < 0)
throw std::runtime_error("Could not correct message");
if(corrs)
corrs->clear();
if(ret && corrs) {
for(int n=0; n < ret; ++n)
corrs->push_back(eras_pos[n]);
}
out = data;
out.resize(d_N);
return ret;
}
RSCodecInt::~RSCodecInt()
{
if(d_rs)
free_rs_int(d_rs);
}