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