1 /* dvdisaster: Additional error correction for optical media.
2 * Copyright (C) 2004-2015 Carsten Gnoerlich.
3 *
4 * Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org
5 * Project homepage: http://www.dvdisaster.org
6 *
7 * This file is part of dvdisaster.
8 *
9 * dvdisaster is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * dvdisaster is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with dvdisaster. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "dvdisaster.h"
24
25 #include "rs02-includes.h"
26
27 /***
28 *** Local data package used during encoding
29 ***/
30
31 typedef struct
32 { Image *image;
33 Method *self;
34 RS02Widgets *wl;
35 RS02Layout *lay;
36 GaloisTables *gt;
37 ReedSolomonTables *rt;
38 EccHeader *eh;
39 unsigned char *data;
40 unsigned char *parity;
41 unsigned char *slice[256];
42 struct MD5Context md5Ctxt[256];
43 guint8 md5Sum[16*256];
44 guint8 eccSum[16];
45 char *msg;
46 int earlyTermination;
47 GTimer *timer;
48 } ecc_closure;
49
ecc_cleanup(gpointer data)50 static void ecc_cleanup(gpointer data)
51 { ecc_closure *ec = (ecc_closure*)data;
52 int i;
53
54 UnregisterCleanup();
55
56 if(Closure->guiMode)
57 { if(ec->earlyTermination && ec->wl)
58 SetLabelText(GTK_LABEL(ec->wl->encFootline),
59 _("<span %s>Aborted by unrecoverable error.</span>"),
60 Closure->redMarkup);
61 AllowActions(TRUE);
62 }
63
64 /*** We must invalidate the CRC cache as it does only cover the
65 data portion of the image, not the full RS02 enhanced image. */
66
67 if(Closure->crcCache)
68 ClearCrcCache();
69
70 /*** Clean up */
71
72 if(ec->image) CloseImage(ec->image);
73 if(ec->gt) FreeGaloisTables(ec->gt);
74 if(ec->rt) FreeReedSolomonTables(ec->rt);
75 if(ec->eh) g_free(ec->eh);
76 if(ec->lay) g_free(ec->lay);
77 if(ec->data) g_free(ec->data);
78 if(ec->parity) g_free(ec->parity);
79 if(ec->msg) g_free(ec->msg);
80 if(ec->timer) g_timer_destroy(ec->timer);
81
82 for(i=0; i<256; i++)
83 if(ec->slice[i])
84 g_free(ec->slice[i]);
85
86 g_free(ec);
87
88 if(Closure->guiMode)
89 g_thread_exit(0);
90 }
91
92 /***
93 *** Some sub tasks to be done during encoding
94 ***/
95
96 /*
97 * Abort encoding
98 */
99
abort_encoding(ecc_closure * ec,int truncate)100 static void abort_encoding(ecc_closure *ec, int truncate)
101 { RS02Widgets *wl = ec->wl;
102
103 if(truncate && ec->lay)
104 { if(!LargeTruncate(ec->image->file, (gint64)(2048*ec->lay->dataSectors)))
105 Stop(_("Could not truncate %s: %s\n"),Closure->imageName,strerror(errno));
106
107 if(Closure->stopActions == STOP_CURRENT_ACTION)
108 SetLabelText(GTK_LABEL(wl->encFootline),
109 _("<span %s>Aborted by user request!</span> (partial ecc data removed from image)"),
110 Closure->redMarkup);
111 }
112 else
113 { if(Closure->stopActions == STOP_CURRENT_ACTION)
114 SetLabelText(GTK_LABEL(wl->encFootline),
115 _("<span %s>Aborted by user request!</span>"),
116 Closure->redMarkup);
117 }
118
119 ec->earlyTermination = FALSE; /* suppress respective error message */
120
121 ecc_cleanup((gpointer)ec);
122 }
123
124
125 /*
126 * Remove already existing RS02 ecc data from the image.
127 */
128
remove_old_ecc(ecc_closure * ec)129 static void remove_old_ecc(ecc_closure *ec)
130 {
131 if(ec->image->eccHeader)
132 { gint64 data_sectors = uchar_to_gint64(ec->image->eccHeader->sectors);
133 guint64 data_bytes;
134 int answer;
135
136 if(Closure->confirmDeletion || !Closure->guiMode)
137 answer = ModalWarning(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, NULL,
138 _("Image \"%s\" already contains error correction information.\n"
139 "Truncating image to data part (%lld sectors).\n"),
140 Closure->imageName, data_sectors);
141 else answer = TRUE;
142
143 if(!answer)
144 abort_encoding(ec, FALSE);
145
146 if(ec->image->eccHeader->inLast != 2048)
147 data_bytes = (guint64)(2048*(data_sectors-1)+ec->image->eccHeader->inLast);
148 else data_bytes = (guint64)(2048*data_sectors);
149
150 if(!TruncateImage(ec->image, data_bytes))
151 Stop(_("Could not truncate %s: %s\n"),Closure->imageName,strerror(errno));
152
153 PrintLog(_("Image size is now"));
154 if(ec->image->inLast == 2048)
155 PrintLog(_(": %lld medium sectors.\n"), ec->image->sectorSize);
156 else PrintLog(_(": %lld medium sectors and %d bytes.\n"),
157 ec->image->sectorSize-1, ec->image->inLast);
158 }
159 }
160
161 /*
162 * Check the image for completeness and calculate the CRC sums
163 * if the respective data has not already been supplied by ReadLinear()
164 */
165
check_image(ecc_closure * ec)166 static void check_image(ecc_closure *ec)
167 { struct MD5Context image_md5;
168 RS02Layout *lay = ec->lay;
169 Image *image = ec->image;
170 gint64 sectors;
171 guint32 *crcptr;
172 int last_percent, percent;
173
174 /* Discard old CRC cache no matter what it contains.
175 * We will create a new one a few lines below.
176 * Note that it is very unusual to augment an image with ecc data
177 * which was just read from an actual medium, so optimizing
178 * for the cached CRCs is not necessary.
179 */
180
181 if(Closure->crcCache)
182 ClearCrcCache();
183
184 last_percent = 0;
185 MD5Init(&image_md5);
186
187 Closure->crcCache = crcptr = g_malloc(sizeof(guint32) * lay->dataSectors);
188
189 if(!LargeSeek(image->file, 0))
190 Stop(_("Failed seeking to start of image: %s\n"), strerror(errno));
191
192 for(sectors = 0; sectors < lay->dataSectors; sectors++)
193 { unsigned char buf[2048];
194 int expected,n,err;
195
196 if(Closure->stopActions) /* User hit the Stop button */
197 abort_encoding(ec, FALSE);
198
199 if(sectors < image->sectorSize-1) expected = 2048;
200 else
201 { memset(buf, 0, 2048);
202 expected = image->inLast;
203 }
204
205 n = LargeRead(image->file, buf, expected);
206 if(n != expected)
207 Stop(_("Failed reading sector %lld in image: %s"),sectors,strerror(errno));
208
209 /* Look for the dead sector marker */
210
211 err = CheckForMissingSector(buf, sectors, image->fpState == FP_PRESENT ? image->imageFP : NULL, FINGERPRINT_SECTOR);
212 if(err != SECTOR_PRESENT)
213 { if(err == SECTOR_MISSING)
214 Stop(_("Image contains unread(able) sectors.\n"
215 "Error correction information can only be\n"
216 "appended to complete (undamaged) images.\n"));
217 else
218 Stop(_("Sector %lld in the image is marked unreadable\n"
219 "and seems to come from a different medium.\n\n"
220 "The image was probably mastered from defective content.\n"
221 "For example it might contain one or more files which came\n"
222 "from a damaged medium which was NOT fully recovered.\n"
223 "This means that some files may have been silently corrupted.\n\n"
224 "Error correction information can only be\n"
225 "appended to complete (undamaged) images.\n"));
226 }
227
228 /* Update and cache the CRC sums */
229
230 *crcptr++ = Crc32(buf, 2048);
231 MD5Update(&image_md5, buf, n);
232
233 percent = (100*sectors)/(lay->eccSectors + lay->dataSectors);
234
235 if(last_percent != percent)
236 { PrintProgress(_("Preparing image (checksums, adding space): %3d%%") ,percent);
237
238 if(Closure->guiMode)
239 SetProgress(ec->wl->encPBar1, percent, 100);
240
241 last_percent = percent;
242 }
243 }
244
245 MD5Final(image->mediumSum, &image_md5);
246 }
247
248
249 /*
250 * Expand the image by lay->eccSectors.
251 * This avoids horrible file fragmentation under some file systems.
252 */
253
expand_image(ecc_closure * ec)254 static void expand_image(ecc_closure *ec)
255 { RS02Layout *lay = ec->lay;
256 Image *image = ec->image;
257 int last_percent, percent;
258 gint64 sectors;
259
260 /* If the file does not end at a sector boundary,
261 fill it up with zeros. */
262
263 if(image->inLast != 2048)
264 { int fill = 2048 - image->inLast;
265 int n;
266 unsigned char zeros[fill];
267
268 memset(zeros, 0, fill);
269
270 if(!LargeSeek(image->file, image->file->size))
271 Stop(_("Failed seeking to end of image: %s\n"), strerror(errno));
272
273 n = LargeWrite(image->file, zeros, fill);
274 if(n != fill)
275 Stop(_("Failed expanding the image: %s\n"), strerror(errno));
276 }
277
278 /* Now add the sectors needed for the ecc data */
279
280 if(!LargeSeek(image->file, 2048*lay->dataSectors))
281 Stop(_("Failed seeking to end of image: %s\n"), strerror(errno));
282
283 last_percent = 0;
284 for(sectors = 0; sectors < lay->eccSectors; sectors++)
285 { unsigned char buf[2048];
286 int n;
287
288 if(Closure->stopActions) /* User hit the Stop button */
289 abort_encoding(ec, TRUE);
290
291 CreateMissingSector(buf, lay->dataSectors+sectors,
292 image->imageFP, FINGERPRINT_SECTOR,
293 "RS02 generation placeholder");
294 n = LargeWrite(image->file, buf, 2048);
295 if(n != 2048)
296 Stop(_("Failed expanding the image: %s\n"), strerror(errno));
297
298 percent = (100*(sectors+lay->dataSectors)) / (lay->eccSectors + lay->dataSectors);
299 if(last_percent != percent)
300 { PrintProgress(_("Preparing image (checksums, adding space): %3d%%"), percent);
301
302 if(Closure->guiMode)
303 SetProgress(ec->wl->encPBar1, percent, 100);
304
305 last_percent = percent;
306 }
307 }
308
309 PrintProgress(_("Preparing image (checksums, adding space): %3d%%"), 100);
310 PrintProgress("\n");
311
312 if(Closure->guiMode)
313 SetProgress(ec->wl->encPBar1, 100, 100);
314 }
315
316 /*
317 * Write the RS02 CRC32 sums into the image file
318 */
319
write_crc(ecc_closure * ec)320 static void write_crc(ecc_closure *ec)
321 { RS02Layout *lay = ec->lay;
322 Image *image = ec->image;
323 EccHeader *eh = ec->eh;
324 gint64 crc_sector;
325 gint64 layer_sector;
326 gint64 layer_offset;
327 guint32 crc_buf[512], *crc_boot_ptr;
328 struct MD5Context md5ctxt;
329 int crc_idx,i;
330 int writepos=0;
331 layer_offset = lay->firstCrcLayerIndex + 1;
332 crc_sector = lay->dataSectors + 2;
333 crc_idx = 0;
334
335 /*** A copy of the CRCs for the lay->firstCrcLayerIndex ecc block
336 is copied into the EccHeader starting with byte position 2048. */
337
338 crc_boot_ptr = (guint32*)((char*)eh + 2048);
339 MD5Init(&md5ctxt);
340
341 /*** Calculate the CRCs */
342
343 if(!LargeSeek(image->file, 2048*crc_sector))
344 Stop(_("Failed seeking to sector %lld in image: %s"), crc_sector, strerror(errno));
345
346 for(layer_sector=0; layer_sector<lay->sectorsPerLayer; layer_sector++)
347 { gint64 layer_index = (layer_sector + layer_offset) % lay->sectorsPerLayer;
348
349 /* Write CRC sums for layer_index'th slice.
350 Some ecc blocks contain padding sectors >= lay->dataSectors.
351 CRCs for padding sectors are not written out,
352 so we have to keep in mind that there might be <= ndata CRC sums
353 per ecc blocks. */
354
355 for(i=0; i<lay->ndata; i++)
356 {
357 if(layer_index < lay->dataSectors)
358 { crc_buf[crc_idx++] = Closure->crcCache[layer_index];
359
360 if(layer_sector == lay->sectorsPerLayer - 1)
361 *crc_boot_ptr++ = Closure->crcCache[layer_index];
362
363 if(crc_idx >= 512)
364 { int n = LargeWrite(image->file, crc_buf, 2048);
365
366 if(n != 2048)
367 Stop(_("Failed writing to sector %lld in image: %s"), crc_sector, strerror(errno));
368 MD5Update(&md5ctxt, (unsigned char*)crc_buf, n);
369
370 crc_sector++;
371 crc_idx = 0;
372 }
373 writepos++;
374 layer_index += lay->sectorsPerLayer;
375 }
376 }
377 }
378
379 /* flush last CRC sector */
380
381 if(crc_idx)
382 { int n;
383
384 for(n=crc_idx; n<512; n++) /* pad unused portion of CRC buffer */
385 #ifdef HAVE_BIG_ENDIAN
386 crc_buf[n] = 0x47504c00;
387 #else
388 crc_buf[n] = 0x4c5047;
389 #endif
390 n = LargeWrite(image->file, crc_buf, 2048);
391
392 if(n != 2048)
393 Stop(_("Failed writing to sector %lld in image: %s"), crc_sector, strerror(errno));
394
395 MD5Update(&md5ctxt, (unsigned char*)crc_buf, n);
396 }
397
398 /* finish and store the md5sum */
399
400 MD5Final(eh->crcSum, &md5ctxt);
401 }
402
403 /*
404 * Fill in the necessary values for the EccHeader.
405 * Note that a copy of the CRC sums for ecc block lay->firstCrcLayerIndex + 1
406 * has been put at byte pos 2048 into the Eccheader by the previous function.
407 */
408
prepare_header(ecc_closure * ec)409 static void prepare_header(ecc_closure *ec)
410 { Image *image = ec->image;
411 EccHeader *eh = ec->eh;
412 RS02Layout *lay = ec->lay;
413
414 memcpy(eh->cookie, "*dvdisaster*", 12);
415 memcpy(eh->method, "RS02", 4);
416 eh->methodFlags[0] = 0;
417 memcpy(eh->mediumFP, image->imageFP, 16);
418 memcpy(eh->mediumSum, image->mediumSum, 16);
419 memcpy(eh->eccSum, ec->eccSum, 16);
420 gint64_to_uchar(eh->sectors, image->sectorSize);
421 eh->dataBytes = lay->ndata;
422 eh->eccBytes = lay->nroots;
423
424 eh->creatorVersion = Closure->version;
425 eh->neededVersion = 6600;
426 eh->fpSector = FINGERPRINT_SECTOR;
427 eh->inLast = image->inLast;
428 eh->sectorsAddedByEcc = lay->eccSectors;
429
430 eh->selfCRC = 0x4c5047;
431
432 #ifdef HAVE_BIG_ENDIAN
433 SwapEccHeaderBytes(eh);
434 eh->selfCRC = 0x47504c00;
435 #endif
436
437 eh->selfCRC = Crc32((unsigned char*)eh, sizeof(EccHeader));
438 }
439
440 /*
441 * Calculate the Reed-Solomon error correction code
442 */
443
create_reed_solomon(ecc_closure * ec)444 static void create_reed_solomon(ecc_closure *ec)
445 { RS02Layout *lay = ec->lay;
446 Image *image = ec->image;
447 int nroots = lay->nroots;
448 int ndata = lay->ndata;
449 gint64 b_idx, block_idx[256];
450 guint64 n_parity_blocks,n_layer_sectors;
451 guint64 n_parity_bytes,n_layer_bytes;
452 guint64 si,chunk;
453 int last_percent, percent, max_percent, progress;
454 int layer,i,j,k;
455 unsigned char *par_ptr;
456 int out_of_memory = 0;
457 static gint32 *gf_index_of; /* These need to be static globals */
458 static gint32 *rs_gpoly; /* for optimization reasons. */
459 static gint32 *enc_alpha_to;
460
461 /*** Show the second progress bar */
462
463 if(Closure->guiMode)
464 { ShowWidget(ec->wl->encPBar2);
465 ShowWidget(ec->wl->encLabel2);
466 }
467
468 /*** Adjust image bounds to include the CRC sectors */
469
470 image->sectorSize = lay->protectedSectors;
471
472 /*** Create table for Galois field math */
473
474 ec->gt = CreateGaloisTables(RS_GENERATOR_POLY);
475 ec->rt = CreateReedSolomonTables(ec->gt, RS_FIRST_ROOT, RS_PRIM_ELEM, nroots);
476
477 gf_index_of = ec->gt->indexOf;
478 enc_alpha_to = ec->gt->encAlphaTo;
479 rs_gpoly = ec->rt->gpoly;
480
481 /*** Allocate buffers for the parity calculation and image data caching.
482
483 The algorithm builds the parity file consecutively in chunks of n_parity_blocks.
484 We use all the amount of memory allowed by cacheMiB for caching the parity blocks. */
485
486 n_parity_blocks = ((guint64)Closure->cacheMiB<<20) / (guint64)nroots; /* 1 MiB = 2^20 */
487 n_parity_blocks >>= 1; /* two buffer sets for scrambling */
488 n_parity_blocks &= ~0x7ff; /* round down to multiple of 2048 */
489 n_parity_bytes = (guint64)nroots * n_parity_blocks;
490
491 /* Each chunk of parity blocks is built iteratively by processing the data in layers
492 (first all bytes at pos 0, then pos 1, until ndata layers have been processed).
493 So we need to buffer n_layer_bytes = n_parity_blocks of input data.
494 For practical reasons we require that the layer size is a multiple of the
495 medium sector size of 2048 bytes. */
496
497 n_layer_bytes = n_parity_blocks;
498 n_layer_sectors = n_parity_blocks/2048;
499
500 if(n_layer_sectors*2048 != n_parity_blocks)
501 Stop("Internal error: parity blocks are not a multiple of sector size.\n");
502
503 ec->parity = g_try_malloc(n_parity_bytes);
504 ec->data = g_try_malloc(n_layer_bytes);
505
506 /*** Create buffers for dividing the ecc information into nroots slices */
507
508 for(i=0; i<nroots; i++)
509 { ec->slice[i] = g_try_malloc(n_layer_bytes);
510 if(!ec->slice[i])
511 out_of_memory = 1;
512 }
513
514 if(out_of_memory || !ec->parity || !ec->data)
515 { LargeTruncate(image->file, (gint64)(2048*ec->lay->dataSectors));
516 Stop(_("Failed allocating memory for I/O cache.\n"
517 "Cache size is currently %d MiB.\n"
518 "Try reducing it.\n"),
519 Closure->cacheMiB);
520 }
521
522 /*** Setup the block counters for mapping medium sectors to ecc blocks
523 The image is divided into ndata layers;
524 with each layer spanning s lay->sectorsPerLayer sectors. */
525
526 for(b_idx=0, i=0; i<ndata; b_idx+=lay->sectorsPerLayer, i++)
527 block_idx[i] = b_idx;
528
529 /*** Initialize md5 contexts for checksumming the nroots slices */
530
531 for(i=0; i<nroots; i++)
532 MD5Init(&ec->md5Ctxt[i]);
533
534 /*** Create ecc information for the protected sectors portion of the image. */
535
536 max_percent = ndata * ((lay->sectorsPerLayer / n_layer_sectors) + 1);
537 progress = percent = 0;
538 last_percent = -1;
539 g_timer_start(ec->timer);
540
541 /* Process the image.
542 From each layer a chunk of n_layer_sectors is read in at once.
543 So after (lay->sectorsPerLayer/n_layer_sectors)+1 iterations
544 the whole image has been processed. */
545
546 for(chunk=0; chunk<lay->sectorsPerLayer; chunk+=n_layer_sectors)
547 { guint64 actual_layer_bytes,actual_layer_sectors;
548 int sp;
549
550 /* Prepare the parity data for the next chunk. */
551
552 memset(ec->parity, 0, n_parity_bytes);
553
554 /* The last chunk may contain fewer sectors. */
555
556 if(chunk+n_layer_sectors < lay->sectorsPerLayer)
557 actual_layer_sectors = n_layer_sectors;
558 else actual_layer_sectors = lay->sectorsPerLayer-chunk;
559
560 actual_layer_bytes = 2048*actual_layer_sectors;
561
562 /* Work each of the ndata data layers
563 into the parity data of the current chunk. */
564
565 sp = nroots - ndata % nroots; /* => (ndata + sp) mod nroots = 0 so that parity */
566 /* is aligned at sp=0 after ndata iterations */
567 if(sp==nroots) sp=0;
568
569 for(layer=0; layer<ndata; layer++)
570 { int offset = 0;
571 unsigned char *par_idx = ec->parity;
572
573 if(Closure->stopActions) /* User hit the Stop button */
574 abort_encoding(ec, TRUE);
575
576 /* Read the next data sectors of this layer. */
577
578 for(si=0; si<actual_layer_sectors; si++)
579 { RS02ReadSector(image, lay, ec->data+offset, block_idx[layer]);
580 block_idx[layer]++;
581 offset += 2048;
582 }
583
584 /* Now process the data bytes of the current layer. */
585
586 for(si=0; si<actual_layer_bytes; si++)
587 { register int feedback;
588
589 feedback = gf_index_of[ec->data[si] ^ par_idx[sp]];
590
591 if(feedback != GF_ALPHA0) /* non-zero feedback term */
592 { register int spk = sp+1;
593 register int *gpoly = rs_gpoly + nroots;
594
595 switch(nroots-spk) /* unrolled loop part1 */
596 {
597 case 170: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
598 case 169: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
599 case 168: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
600 case 167: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
601 case 166: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
602 case 165: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
603 case 164: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
604 case 163: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
605 case 162: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
606 case 161: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
607 case 160: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
608 case 159: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
609 case 158: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
610 case 157: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
611 case 156: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
612 case 155: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
613 case 154: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
614 case 153: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
615 case 152: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
616 case 151: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
617 case 150: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
618 case 149: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
619 case 148: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
620 case 147: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
621 case 146: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
622 case 145: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
623 case 144: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
624 case 143: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
625 case 142: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
626 case 141: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
627 case 140: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
628 case 139: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
629 case 138: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
630 case 137: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
631 case 136: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
632 case 135: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
633 case 134: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
634 case 133: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
635 case 132: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
636 case 131: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
637 case 130: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
638 case 129: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
639 case 128: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
640 case 127: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
641 case 126: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
642 case 125: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
643 case 124: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
644 case 123: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
645 case 122: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
646 case 121: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
647 case 120: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
648 case 119: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
649 case 118: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
650 case 117: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
651 case 116: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
652 case 115: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
653 case 114: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
654 case 113: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
655 case 112: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
656 case 111: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
657 case 110: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
658 case 109: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
659 case 108: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
660 case 107: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
661 case 106: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
662 case 105: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
663 case 104: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
664 case 103: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
665 case 102: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
666 case 101: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
667 case 100: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
668 case 99: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
669 case 98: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
670 case 97: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
671 case 96: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
672 case 95: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
673 case 94: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
674 case 93: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
675 case 92: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
676 case 91: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
677 case 90: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
678 case 89: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
679 case 88: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
680 case 87: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
681 case 86: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
682 case 85: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
683 case 84: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
684 case 83: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
685 case 82: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
686 case 81: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
687 case 80: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
688 case 79: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
689 case 78: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
690 case 77: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
691 case 76: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
692 case 75: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
693 case 74: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
694 case 73: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
695 case 72: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
696 case 71: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
697 case 70: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
698 case 69: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
699 case 68: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
700 case 67: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
701 case 66: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
702 case 65: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
703 case 64: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
704 case 63: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
705 case 62: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
706 case 61: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
707 case 60: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
708 case 59: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
709 case 58: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
710 case 57: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
711 case 56: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
712 case 55: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
713 case 54: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
714 case 53: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
715 case 52: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
716 case 51: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
717 case 50: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
718 case 49: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
719 case 48: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
720 case 47: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
721 case 46: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
722 case 45: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
723 case 44: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
724 case 43: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
725 case 42: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
726 case 41: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
727 case 40: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
728 case 39: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
729 case 38: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
730 case 37: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
731 case 36: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
732 case 35: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
733 case 34: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
734 case 33: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
735 case 32: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
736 case 31: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
737 case 30: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
738 case 29: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
739 case 28: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
740 case 27: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
741 case 26: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
742 case 25: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
743 case 24: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
744 case 23: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
745 case 22: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
746 case 21: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
747 case 20: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
748 case 19: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
749 case 18: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
750 case 17: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
751 case 16: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
752 case 15: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
753 case 14: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
754 case 13: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
755 case 12: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
756 case 11: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
757 case 10: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
758 case 9: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
759 case 8: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
760 case 7: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
761 case 6: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
762 case 5: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
763 case 4: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
764 case 3: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
765 case 2: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
766 case 1: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
767 }
768
769 spk = 0;
770
771 switch(sp) /* unrolled loop part2 */
772 {
773 case 170: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
774 case 169: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
775 case 168: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
776 case 167: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
777 case 166: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
778 case 165: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
779 case 164: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
780 case 163: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
781 case 162: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
782 case 161: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
783 case 160: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
784 case 159: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
785 case 158: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
786 case 157: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
787 case 156: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
788 case 155: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
789 case 154: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
790 case 153: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
791 case 152: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
792 case 151: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
793 case 150: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
794 case 149: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
795 case 148: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
796 case 147: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
797 case 146: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
798 case 145: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
799 case 144: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
800 case 143: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
801 case 142: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
802 case 141: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
803 case 140: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
804 case 139: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
805 case 138: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
806 case 137: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
807 case 136: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
808 case 135: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
809 case 134: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
810 case 133: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
811 case 132: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
812 case 131: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
813 case 130: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
814 case 129: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
815 case 128: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
816 case 127: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
817 case 126: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
818 case 125: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
819 case 124: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
820 case 123: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
821 case 122: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
822 case 121: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
823 case 120: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
824 case 119: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
825 case 118: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
826 case 117: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
827 case 116: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
828 case 115: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
829 case 114: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
830 case 113: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
831 case 112: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
832 case 111: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
833 case 110: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
834 case 109: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
835 case 108: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
836 case 107: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
837 case 106: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
838 case 105: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
839 case 104: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
840 case 103: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
841 case 102: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
842 case 101: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
843 case 100: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
844 case 99: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
845 case 98: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
846 case 97: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
847 case 96: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
848 case 95: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
849 case 94: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
850 case 93: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
851 case 92: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
852 case 91: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
853 case 90: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
854 case 89: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
855 case 88: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
856 case 87: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
857 case 86: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
858 case 85: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
859 case 84: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
860 case 83: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
861 case 82: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
862 case 81: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
863 case 80: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
864 case 79: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
865 case 78: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
866 case 77: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
867 case 76: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
868 case 75: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
869 case 74: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
870 case 73: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
871 case 72: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
872 case 71: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
873 case 70: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
874 case 69: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
875 case 68: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
876 case 67: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
877 case 66: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
878 case 65: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
879 case 64: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
880 case 63: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
881 case 62: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
882 case 61: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
883 case 60: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
884 case 59: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
885 case 58: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
886 case 57: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
887 case 56: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
888 case 55: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
889 case 54: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
890 case 53: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
891 case 52: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
892 case 51: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
893 case 50: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
894 case 49: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
895 case 48: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
896 case 47: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
897 case 46: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
898 case 45: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
899 case 44: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
900 case 43: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
901 case 42: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
902 case 41: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
903 case 40: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
904 case 39: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
905 case 38: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
906 case 37: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
907 case 36: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
908 case 35: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
909 case 34: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
910 case 33: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
911 case 32: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
912 case 31: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
913 case 30: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
914 case 29: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
915 case 28: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
916 case 27: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
917 case 26: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
918 case 25: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
919 case 24: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
920 case 23: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
921 case 22: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
922 case 21: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
923 case 20: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
924 case 19: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
925 case 18: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
926 case 17: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
927 case 16: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
928 case 15: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
929 case 14: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
930 case 13: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
931 case 12: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
932 case 11: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
933 case 10: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
934 case 9: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
935 case 8: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
936 case 7: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
937 case 6: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
938 case 5: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
939 case 4: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
940 case 3: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
941 case 2: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
942 case 1: par_idx[spk++] ^= enc_alpha_to[feedback + *--gpoly];
943 }
944
945 par_idx[sp] = enc_alpha_to[feedback + rs_gpoly[0]];
946 }
947 else /* zero feedback term */
948 par_idx[sp] = 0;
949
950 par_idx += nroots;
951 }
952
953 if(++sp>=nroots) sp=0; /* shift */
954
955 /* Report progress */
956
957 progress++;
958 percent = (1000*progress)/max_percent;
959 if(last_percent != percent)
960 {
961 if(Closure->guiMode)
962 SetProgress(ec->wl->encPBar2, percent, 1000);
963 else PrintProgress(_("Ecc generation: %3d.%1d%%"), percent/10, percent%10);
964
965 last_percent = percent;
966 }
967 }
968
969 /* The parity bytes have been prepared as sequences of nroots bytes for each
970 ecc block. Now we split them up into nroots slices and write them out. */
971
972 par_ptr = ec->parity;
973
974 for(si=0; si<actual_layer_sectors; si++)
975 { guint64 idx = 2048*si;
976
977 for(j=0; j<2048; j++, idx++)
978 { for(k=0; k<nroots; k++)
979 ec->slice[k][idx] = *par_ptr++;
980 }
981 }
982
983 for(k=0; k<nroots; k++)
984 { int idx=0;
985
986 for(si=0; si<actual_layer_sectors; si++, idx+=2048)
987 { gint64 s = RS02EccSectorIndex(lay, k, chunk + si);
988
989 if(!LargeSeek(image->file, 2048*s))
990 Stop(_("Failed seeking to sector %lld in image: %s"), s, strerror(errno));
991
992 if(LargeWrite(image->file, ec->slice[k]+idx, 2048) != 2048)
993 Stop(_("Failed writing to sector %lld in image: %s"), s, strerror(errno));
994
995 MD5Update(&ec->md5Ctxt[k], ec->slice[k]+idx, 2048);
996 }
997 }
998 }
999
1000 /*** We can store only one md5sum in the header,
1001 so lets produce a meta-checksum from all nroots md5sums */
1002
1003 for(i=0; i<nroots; i++)
1004 MD5Final(&ec->md5Sum[i*16], &ec->md5Ctxt[i]);
1005
1006 MD5Init(&ec->md5Ctxt[0]);
1007 MD5Update(&ec->md5Ctxt[0], ec->md5Sum, 16*nroots);
1008 MD5Final(ec->eccSum, &ec->md5Ctxt[0]);
1009
1010 /*** Restore image bounds to data portion */
1011
1012 image->sectorSize = lay->dataSectors;
1013 }
1014
1015 /***
1016 *** Append the parity information to the image
1017 ***/
1018
RS02Create(void)1019 void RS02Create(void)
1020 { Method *self = FindMethod("RS02");
1021 RS02Widgets *wl = (RS02Widgets*)self->widgetList;
1022 Image *image = NULL;
1023 RS02Layout *lay;
1024 ecc_closure *ec = g_malloc0(sizeof(ecc_closure));
1025
1026 ec->earlyTermination = TRUE;
1027 RegisterCleanup(_("Error correction data creation aborted"), ecc_cleanup, ec);
1028
1029 /*** Open image file */
1030
1031 PrintLog(_("\nOpening %s"), Closure->imageName);
1032
1033 image = OpenImageFromFile(Closure->imageName, O_RDWR, IMG_PERMS);
1034 if(!image)
1035 { PrintLog(": %s.\n", strerror(errno));
1036 Stop(_("Image file %s: %s."),Closure->imageName, strerror(errno));
1037 return;
1038 }
1039
1040 if(image->inLast == 2048)
1041 PrintLog(_(": %lld medium sectors.\n"), image->sectorSize);
1042 else PrintLog(_(": %lld medium sectors and %d bytes.\n"),
1043 image->sectorSize-1, image->inLast);
1044
1045 /*** Register the cleanup procedure for GUI mode */
1046
1047 ec->image = image;
1048 ec->self = self;
1049 ec->wl = wl;
1050 ec->eh = g_malloc0(sizeof(EccHeader));
1051 ec->timer = g_timer_new();
1052
1053 if(Closure->guiMode) /* Preliminary fill text for the head line */
1054 SetLabelText(GTK_LABEL(wl->encHeadline),
1055 _("<big>Augmenting the image with error correction data.</big>\n<i>%s</i>"),
1056 _("- checking image -"));
1057
1058 /*** If the image already contains error correction information, remove it. */
1059
1060 remove_old_ecc(ec);
1061
1062 /*** Calculate a suitable redundancy .*/
1063
1064 lay = ec->lay = CalcRS02Layout(image);
1065
1066 /*** Announce what we are going to do */
1067
1068 if(Closure->guiMode) /* Preliminary fill text for the head line */
1069 { ec->msg = g_strdup_printf(_("Encoding with Method RS02: %lld MiB data, %lld MiB ecc (%d roots; %4.1f%% redundancy)."),
1070 lay->dataSectors/512, lay->eccSectors/512, lay->nroots, lay->redundancy);
1071
1072 SetLabelText(GTK_LABEL(wl->encHeadline),
1073 _("<big>Augmenting the image with error correction data.</big>\n<i>%s</i>"),
1074 ec->msg);
1075 }
1076 else
1077 { ec->msg = g_strdup_printf(_("Augmenting image with Method RS02:\n %lld MiB data, %lld MiB ecc (%d roots; %4.1f%% redundancy)."),
1078 lay->dataSectors/512, lay->eccSectors/512, lay->nroots, lay->redundancy);
1079
1080 PrintLog("%s\n",ec->msg);
1081 }
1082
1083 /*** Warn if there is not enough space for ecc data */
1084
1085 if(lay->nroots < 8)
1086 Stop(_("Not enough space on medium left for error correction data.\n"
1087 "Data portion of image: %lld sect.; maximum possible size: %lld sect.\n"
1088 "If reducing the image size or using a larger medium is\n"
1089 "not an option, please create a separate error correction file."),
1090 lay->dataSectors, lay->mediumCapacity);
1091
1092 if(lay->redundancy < 20)
1093 { int answer;
1094
1095 answer = ModalWarning(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, NULL,
1096 _("Using redundancies below 20%%%% may not give\n"
1097 "the expected data loss protection.\n"));
1098
1099 if(!answer)
1100 abort_encoding(ec, FALSE);
1101 }
1102
1103 /*** Check image for completeness and fetch its CRC sums */
1104
1105 check_image(ec);
1106
1107 /*** Expand the image by lay->eccSectors. */
1108
1109 expand_image(ec);
1110
1111 /*** Distribute and write the CRC sums */
1112
1113 write_crc(ec);
1114
1115 /*** Create the Reed-Solomon parts of the ecc section */
1116
1117 create_reed_solomon(ec);
1118
1119 /*** Prepare the Ecc header
1120 and write all copies of the header out */
1121
1122 prepare_header(ec);
1123 WriteRS02Headers(image->file, ec->lay, ec->eh);
1124
1125 PrintTimeToLog(ec->timer, "for ECC generation.\n");
1126
1127 PrintProgress(_("Ecc generation: 100.0%%\n"));
1128 PrintLog(_("Image has been augmented with error correction data.\n"
1129 "New image size is %lld MiB (%lld sectors).\n"),
1130 (lay->dataSectors + lay->eccSectors)/512,
1131 lay->dataSectors+lay->eccSectors);
1132
1133 if(Closure->guiMode)
1134 { SetProgress(wl->encPBar2, 100, 100);
1135
1136 SetLabelText(GTK_LABEL(wl->encFootline),
1137 _("Image has been augmented with error correction data.\n"
1138 "New image size is %lld MiB (%lld sectors).\n"),
1139 (lay->dataSectors + lay->eccSectors)/512,
1140 lay->dataSectors+lay->eccSectors);
1141 }
1142
1143 /*** Clean up */
1144
1145 ec->earlyTermination = FALSE;
1146 ecc_cleanup((gpointer)ec);
1147 }
1148
1149