1 // This file is part of par2cmdline (a PAR 2.0 compatible file verification and
2 // repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
3 //
4 // Copyright (c) 2003 Peter Brian Clements
5 // Copyright (c) 2019 Michael D. Nahas
6 //
7 // par2cmdline is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // par2cmdline is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21 #include "libpar2internal.h"
22
23 #ifdef _MSC_VER
24 #ifdef _DEBUG
25 #undef THIS_FILE
26 static char THIS_FILE[]=__FILE__;
27 #define new DEBUG_NEW
28 #endif
29 #endif
30
gcd(u32 a,u32 b)31 u32 gcd(u32 a, u32 b)
32 {
33 if (a && b)
34 {
35 while (a && b)
36 {
37 if (a>b)
38 {
39 a = a%b;
40 }
41 else
42 {
43 b = b%a;
44 }
45 }
46
47 return a+b;
48 }
49 else
50 {
51 return 0;
52 }
53 }
54
SetInput(const vector<bool> & present,std::ostream & sout,std::ostream & serr)55 template <> bool ReedSolomon<Galois8>::SetInput(const vector<bool> &present, std::ostream &sout, std::ostream &serr)
56 {
57 inputcount = (u32)present.size();
58
59 datapresentindex = new u32[inputcount];
60 datamissingindex = new u32[inputcount];
61 database = new G::ValueType[inputcount];
62
63 G::ValueType base = 1;
64
65 for (unsigned int index=0; index<inputcount; index++)
66 {
67 // Record the index of the file in the datapresentindex array
68 // or the datamissingindex array
69 if (present[index])
70 {
71 datapresentindex[datapresent++] = index;
72 }
73 else
74 {
75 datamissingindex[datamissing++] = index;
76 }
77
78 database[index] = base++;
79 }
80
81 return true;
82 }
83
SetInput(u32 count,std::ostream & sout,std::ostream & serr)84 template <> bool ReedSolomon<Galois8>::SetInput(u32 count, std::ostream &sout, std::ostream &serr)
85 {
86 inputcount = count;
87
88 datapresentindex = new u32[inputcount];
89 datamissingindex = new u32[inputcount];
90 database = new G::ValueType[inputcount];
91
92 G::ValueType base = 1;
93
94 for (unsigned int index=0; index<count; index++)
95 {
96 // Record that the file is present
97 datapresentindex[datapresent++] = index;
98
99 database[index] = base++;
100 }
101
102 return true;
103 }
104
InternalProcess(const Galois8 & factor,size_t size,const void * inputbuffer,void * outputbuffer)105 template <> bool ReedSolomon<Galois8>::InternalProcess(const Galois8 &factor, size_t size, const void *inputbuffer, void *outputbuffer)
106 {
107 #ifdef LONGMULTIPLY
108 // The 8-bit long multiplication tables
109 Galois8 *table = glmt->tables;
110
111 // Split the factor into Low and High bytes
112 unsigned int fl = (factor >> 0) & 0xff;
113
114 // Get the four separate multiplication tables
115 Galois8 *LL = &table[(0*256 + fl) * 256 + 0]; // factor.low * source.low
116
117 // Combine the four multiplication tables into two
118 unsigned int L[256];
119
120 unsigned int *pL = &L[0];
121
122 for (unsigned int i=0; i<256; i++)
123 {
124 *pL = *LL;
125
126 pL++;
127 LL++;
128 }
129
130 // Treat the buffers as arrays of 32-bit unsigned ints.
131 u32 *src4 = (u32 *)inputbuffer;
132 u32 *end4 = (u32 *)&((u8*)inputbuffer)[size & ~3];
133 u32 *dst4 = (u32 *)outputbuffer;
134
135 // Process the data
136 while (src4 < end4)
137 {
138 u32 s = *src4++;
139
140 // Use the two lookup tables computed earlier
141 *dst4++ ^= (L[(s >> 0) & 0xff] )
142 ^ (L[(s >> 8) & 0xff] << 8 )
143 ^ (L[(s >> 16)& 0xff] << 16)
144 ^ (L[(s >> 24)& 0xff] << 24);
145 }
146
147 // Process any left over bytes at the end of the buffer
148 if (size & 3)
149 {
150 u8 *src1 = &((u8*)inputbuffer)[size & ~3];
151 u8 *end1 = &((u8*)inputbuffer)[size];
152 u8 *dst1 = &((u8*)outputbuffer)[size & ~3];
153
154 // Process the data
155 while (src1 < end1)
156 {
157 u8 s = *src1++;
158 *dst1++ ^= L[s];
159 }
160 }
161 #else
162 // Treat the buffers as arrays of 16-bit Galois values.
163
164 Galois8 *src = (Galois8 *)inputbuffer;
165 Galois8 *end = (Galois8 *)&((u8*)inputbuffer)[size];
166 Galois8 *dst = (Galois8 *)outputbuffer;
167
168 // Process the data
169 while (src < end)
170 {
171 *dst++ += *src++ * factor;
172 }
173 #endif
174
175 return eSuccess;
176 }
177
178
179
180 ////////////////////////////////////////////////////////////////////////////////////////////
181
182
183
184 // Set which of the source files are present and which are missing
185 // and compute the base values to use for the vandermonde matrix.
SetInput(const vector<bool> & present,std::ostream & sout,std::ostream & serr)186 template <> bool ReedSolomon<Galois16>::SetInput(const vector<bool> &present, std::ostream &sout, std::ostream &serr)
187 {
188 inputcount = (u32)present.size();
189
190 datapresentindex = new u32[inputcount];
191 datamissingindex = new u32[inputcount];
192 database = new G::ValueType[inputcount];
193
194 unsigned int logbase = 0;
195
196 for (unsigned int index=0; index<inputcount; index++)
197 {
198 // Record the index of the file in the datapresentindex array
199 // or the datamissingindex array
200 if (present[index])
201 {
202 datapresentindex[datapresent++] = index;
203 }
204 else
205 {
206 datamissingindex[datamissing++] = index;
207 }
208
209 // Determine the next useable base value.
210 // Its log must must be relatively prime to 65535
211 while (gcd(G::Limit, logbase) != 1)
212 {
213 logbase++;
214 }
215 if (logbase >= G::Limit)
216 {
217 serr << "Too many input blocks for Reed Solomon matrix." << endl;
218 return false;
219 }
220 G::ValueType base = G(logbase++).ALog();
221
222 database[index] = base;
223 }
224
225 return true;
226 }
227
228 // Record that the specified number of source files are all present
229 // and compute the base values to use for the vandermonde matrix.
SetInput(u32 count,std::ostream & sout,std::ostream & serr)230 template <> bool ReedSolomon<Galois16>::SetInput(u32 count, std::ostream &sout, std::ostream &serr)
231 {
232 inputcount = count;
233
234 datapresentindex = new u32[inputcount];
235 datamissingindex = new u32[inputcount];
236 database = new G::ValueType[inputcount];
237
238 unsigned int logbase = 0;
239
240 for (unsigned int index=0; index<count; index++)
241 {
242 // Record that the file is present
243 datapresentindex[datapresent++] = index;
244
245 // Determine the next useable base value.
246 // Its log must must be relatively prime to 65535
247 while (gcd(G::Limit, logbase) != 1)
248 {
249 logbase++;
250 }
251 if (logbase >= G::Limit)
252 {
253 serr << "Too many input blocks for Reed Solomon matrix." << endl;
254 return false;
255 }
256 G::ValueType base = G(logbase++).ALog();
257
258 database[index] = base;
259 }
260
261 return true;
262 }
263
InternalProcess(const Galois16 & factor,size_t size,const void * inputbuffer,void * outputbuffer)264 template<> bool ReedSolomon<Galois16>::InternalProcess(const Galois16 &factor, size_t size, const void *inputbuffer, void *outputbuffer)
265 {
266 #ifdef LONGMULTIPLY
267 // The 8-bit long multiplication tables
268 Galois16 *table = glmt->tables;
269
270 // Split the factor into Low and High bytes
271 unsigned int fl = (factor >> 0) & 0xff;
272 unsigned int fh = (factor >> 8) & 0xff;
273
274 // Get the four separate multiplication tables
275 Galois16 *LL = &table[(0*256 + fl) * 256 + 0]; // factor.low * source.low
276 Galois16 *LH = &table[(1*256 + fl) * 256 + 0]; // factor.low * source.high
277 Galois16 *HL = &table[(1*256 + 0) * 256 + fh]; // factor.high * source.low
278 Galois16 *HH = &table[(2*256 + fh) * 256 + 0]; // factor.high * source.high
279
280 // Combine the four multiplication tables into two
281 unsigned int L[256];
282 unsigned int H[256];
283
284 #if __BYTE_ORDER == __LITTLE_ENDIAN
285 unsigned int *pL = &L[0];
286 unsigned int *pH = &H[0];
287 #else
288 unsigned int *pL = &H[0];
289 unsigned int *pH = &L[0];
290 #endif
291
292 for (unsigned int i=0; i<256; i++)
293 {
294 #if __BYTE_ORDER == __LITTLE_ENDIAN
295 *pL = *LL + *HL;
296 #else
297 unsigned int temp = *LL + *HL;
298 *pL = ((temp >> 8) & 0xff) | ((temp << 8) & 0xff00);
299 #endif
300
301 pL++;
302 LL++;
303 HL+=256;
304
305 #if __BYTE_ORDER == __LITTLE_ENDIAN
306 *pH = *LH + *HH;
307 #else
308 temp = *LH + *HH;
309 *pH = ((temp >> 8) & 0xff) | ((temp << 8) & 0xff00);
310 #endif
311
312 pH++;
313 LH++;
314 HH++;
315 }
316
317 // Treat the buffers as arrays of 32-bit unsigned ints.
318 u32 *src = (u32 *)inputbuffer;
319 u32 *end = (u32 *)&((u8*)inputbuffer)[size];
320 u32 *dst = (u32 *)outputbuffer;
321
322 // Process the data
323 while (src < end)
324 {
325 u32 s = *src++;
326
327 // Use the two lookup tables computed earlier
328 //#if __BYTE_ORDER == __LITTLE_ENDIAN
329 u32 d = *dst ^ (L[(s >> 0) & 0xff] )
330 ^ (H[(s >> 8) & 0xff] )
331 ^ (L[(s >> 16)& 0xff] << 16)
332 ^ (H[(s >> 24)& 0xff] << 16);
333 *dst++ = d;
334 //#else
335 // *dst++ ^= (L[(s >> 8) & 0xff] )
336 // ^ (H[(s >> 0) & 0xff] )
337 // ^ (L[(s >> 24)& 0xff] << 16)
338 // ^ (H[(s >> 16)& 0xff] << 16);
339 //#endif
340 }
341 #else
342 // Treat the buffers as arrays of 16-bit Galois values.
343
344 // BUG: This only works for __LITTLE_ENDIAN
345 Galois16 *src = (Galois16 *)inputbuffer;
346 Galois16 *end = (Galois16 *)&((u8*)inputbuffer)[size];
347 Galois16 *dst = (Galois16 *)outputbuffer;
348
349 // Process the data
350 while (src < end)
351 {
352 *dst++ += *src++ * factor;
353 }
354 #endif
355
356 return eSuccess;
357 }
358
359