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