1 /*************************************************************
2 Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved.
3 PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research
4 Group. If you use this software, you agree to the following: This
5 program package is purely experimental, and is licensed "as is".
6 Permission is granted to use, modify, and distribute this program
7 without charge for any purpose, provided this license/ disclaimer
8 notice appears in the copies.  No warranty or maintenance is given,
9 either expressed or implied.  In no event shall the author(s) be
10 liable to you or a third party for any special, incidental,
11 consequential, or other damages, arising out of the use or inability
12 to use the program for any purpose (or the loss of data), even if we
13 have been advised of such possibilities.  Any public reference or
14 advertisement of this source code should refer to it as the Portable
15 Video Research Group (PVRG) code, and not by any author(s) (or
16 Stanford University) name.
17 *************************************************************/
18 
19 /*
20 ************************************************************
21 stream.c
22 
23 This file is used for management of bit-aligned files.
24 
25 ************************************************************
26 */
27 
28 /*LABEL stream.c */
29 
30 /* Include files */
31 
32 #include "globals.h"
33 #include "marker.h"
34 #include "stream.h"
35 #include <stdlib.h> /* exit */
36 
37 /*PUBLIC*/
38 
39 extern void initstream();
40 extern void pushstream();
41 extern void popstream();
42 extern void bpushc();
43 extern int bgetc();
44 extern void bputc();
45 extern void mropen();
46 extern void mrclose();
47 extern void mwopen();
48 extern void swbytealign();
49 extern void mwclose();
50 extern long mwtell();
51 extern long mrtell();
52 extern void mwseek();
53 extern void mrseek();
54 extern int megetb();
55 extern void meputv();
56 extern int megetv();
57 extern int DoMarker();
58 extern int ScreenMarker();
59 extern void Resync();
60 extern void WriteResync();
61 extern int ReadResync();
62 extern int ScreenAllMarker();
63 extern int DoAllMarker();
64 
65 static int pgetc();
66 
67 /*PRIVATE*/
68 
69 /* External values */
70 
71 extern int ErrorValue;
72 extern IMAGE *CImage;
73 extern int Robust;         /* Whether to ignore scan markers and such */
74 
75 /* Masks */
76 int bit_set_mask[] = { /* This is 2^i at ith position */
77 0x00000001,0x00000002,0x00000004,0x00000008,
78 0x00000010,0x00000020,0x00000040,0x00000080,
79 0x00000100,0x00000200,0x00000400,0x00000800,
80 0x00001000,0x00002000,0x00004000,0x00008000,
81 0x00010000,0x00020000,0x00040000,0x00080000,
82 0x00100000,0x00200000,0x00400000,0x00800000,
83 0x01000000,0x02000000,0x04000000,0x08000000,
84 0x10000000,0x20000000,0x40000000,0x80000000};
85 int lmask[] = {        /* This is 2^{i+1}-1 */
86 0x00000001,0x00000003,0x00000007,0x0000000f,
87 0x0000001f,0x0000003f,0x0000007f,0x000000ff,
88 0x000001ff,0x000003ff,0x000007ff,0x00000fff,
89 0x00001fff,0x00003fff,0x00007fff,0x0000ffff,
90 0x0001ffff,0x0003ffff,0x0007ffff,0x000fffff,
91 0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
92 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,
93 0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
94 
95 #ifdef __OLD
96 int umask[] = {        /* This is -1 XOR 2^{i+1}-1 */
97 0xfffffffe,0xfffffffc,0xfffffff8,0xfffffff0,
98 0xffffffe0,0xffffffc0,0xffffff80,0xffffff00,
99 0xfffffe00,0xfffffc00,0xfffff800,0xfffff000,
100 0xffffe000,0xffffc000,0xffff8000,0xffff0000,
101 0xfffe0000,0xfffc0000,0xfff80000,0xfff00000,
102 0xffe00000,0xffc00000,0xff800000,0xff000000,
103 0xfe000000,0xfc000000,0xf8000000,0xf0000000,
104 0xe0000000,0xc0000000,0x80000000,0x00000000};
105 #endif
106 
107 /* Internally kept variables for global flag communication */
108 
109 int CleartoResync=0;       /* Return black blocks until last Resync reached*/
110 int ResyncEnable=0;         /* This enables the resync feature */
111 int ResyncCount=0;     /* This is the resync marker count */
112 int LastKnownResync=0;     /* This is the index of the next Resync */
113 int EndofFile=0;     /* End of file means read stream exhausted */
114 int EndofImage=0;     /* End of image means EOI image marker found */
115 
116 /* Static variables that keep internal state. */
117 
118 static FILE *swout;
119 static FILE *srin;
120 static unsigned int current_write_byte;
121 static unsigned int current_read_byte;
122 static unsigned int marker_read_byte;
123 static int read_position;
124 static int write_position;
125 static int InResync=0;
126 
127 /* Stack of variables to handle multiple streams. */
128 
129 static int Stack_Stream_Current= -1;
130 static int Stack_Stream_Active[NUMBER_OF_STREAMS];
131 static int Stack_Stream_CleartoResync[NUMBER_OF_STREAMS];
132 static int Stack_Stream_ResyncEnable[NUMBER_OF_STREAMS];
133 static int Stack_Stream_ResyncCount[NUMBER_OF_STREAMS];
134 static int Stack_Stream_LastKnownResync[NUMBER_OF_STREAMS];
135 static int Stack_Stream_EndofFile[NUMBER_OF_STREAMS];
136 static int Stack_Stream_EndofImage[NUMBER_OF_STREAMS];
137 static FILE * Stack_Stream_swout[NUMBER_OF_STREAMS];
138 static FILE * Stack_Stream_srin[NUMBER_OF_STREAMS];
139 static unsigned int Stack_Stream_current_write_byte[NUMBER_OF_STREAMS];
140 static unsigned int Stack_Stream_current_read_byte[NUMBER_OF_STREAMS];
141 static unsigned int Stack_Stream_marker_read_byte[NUMBER_OF_STREAMS];
142 static int Stack_Stream_read_position[NUMBER_OF_STREAMS];
143 static int Stack_Stream_write_position[NUMBER_OF_STREAMS];
144 
145 /*START*/
146 
147 /* STACK STREAM LIBRARY */
148 
149 /*BFUNC
150 
151 initstream() initializes all of the stream variables-- especially the
152 stack. Not necessary to call unless you wish to use more than one
153 stream variable.
154 
155 EFUNC*/
156 
initstream()157 void initstream()
158 {
159   BEGIN("initstream")
160   int i;
161 
162   Stack_Stream_Current= -1;
163   for(i=0;i<NUMBER_OF_STREAMS;i++)
164     {
165       Stack_Stream_Active[i]=0;
166       Stack_Stream_swout[i]=NULL;
167       Stack_Stream_srin[i]=NULL;
168     }
169 }
170 
171 /*BFUNC
172 
173 pushstream() pushes the currently active stream into its predefined
174 location.
175 
176 EFUNC*/
177 
pushstream()178 void pushstream()
179 {
180   BEGIN("pushstream")
181 
182   if (Stack_Stream_Current < 0) return;
183   Stack_Stream_CleartoResync[Stack_Stream_Current]=CleartoResync;
184   Stack_Stream_ResyncEnable[Stack_Stream_Current]=ResyncEnable;
185   Stack_Stream_ResyncCount[Stack_Stream_Current]=ResyncCount;
186   Stack_Stream_LastKnownResync[Stack_Stream_Current]=LastKnownResync;
187   Stack_Stream_EndofFile[Stack_Stream_Current]=EndofFile;
188   Stack_Stream_EndofImage[Stack_Stream_Current]=EndofImage;
189   Stack_Stream_swout[Stack_Stream_Current]=swout;
190   Stack_Stream_srin[Stack_Stream_Current]=srin;
191   Stack_Stream_current_write_byte[Stack_Stream_Current]=current_write_byte;
192   Stack_Stream_current_read_byte[Stack_Stream_Current]=current_read_byte;
193   Stack_Stream_marker_read_byte[Stack_Stream_Current]=marker_read_byte;
194   Stack_Stream_read_position[Stack_Stream_Current]=read_position;
195   Stack_Stream_write_position[Stack_Stream_Current]=write_position;
196 }
197 
198 /*BFUNC
199 
200 popstream() gets the specified stream from the location.  If there
201 is already a current active stream, it removes it.
202 
203 EFUNC*/
204 
popstream(index)205 void popstream(index)
206      int index;
207 {
208   BEGIN("popstream")
209 
210   if ((index < 0)||(!Stack_Stream_Active[index]))
211     {
212       WHEREAMI();
213       printf("Cannot pop non-existent stream.\n");
214       exit(ERROR_BOUNDS);
215     }
216   if (Stack_Stream_Current >=0) pushstream();
217   CleartoResync=Stack_Stream_CleartoResync[index];
218   ResyncEnable=Stack_Stream_ResyncEnable[index];
219   ResyncCount=Stack_Stream_ResyncCount[index];
220   LastKnownResync=Stack_Stream_LastKnownResync[index];
221   EndofFile=Stack_Stream_EndofFile[index];
222   EndofImage=Stack_Stream_EndofImage[index];
223   swout=Stack_Stream_swout[index];
224   srin=Stack_Stream_srin[index];
225   current_write_byte=Stack_Stream_current_write_byte[index];
226   current_read_byte=Stack_Stream_current_read_byte[index];
227   marker_read_byte=Stack_Stream_marker_read_byte[index];
228   read_position=Stack_Stream_read_position[index];
229   write_position=Stack_Stream_write_position[index];
230 }
231 
232 /* THAT'S ALL FOR THE STACK STREAM LIBRARY! */
233 
234 /* BUFFER LIBRARY */
235 
236 /*BFUNC
237 
238 brtell() is used to find the location in the read stream.
239 
240 EFUNC*/
241 
brtell()242 int brtell()
243   {BEGIN("brtell") return(ftell(srin));}
244 
245 /*BFUNC
246 
247 brseek() is used to find the location in the read stream.
248 
249 EFUNC*/
250 
brseek(offset,ptr)251 int brseek(offset,ptr)
252      int offset;
253      int ptr;
254   {BEGIN("brseek") return(fseek(srin,offset,ptr));}
255 
256 /*BFUNC
257 
258 bpushc() is used to unget a character value from the current stream.
259 
260 EFUNC*/
261 
bpushc(value)262 void bpushc(value)
263      int value;
264   {BEGIN("bpushc") ungetc(value,srin);}
265 
266 /*BFUNC
267 
268 bgetc() gets a character from the stream. It is byte aligned and
269 bypasses bit buffering.
270 
271 EFUNC*/
272 
bgetc()273 int bgetc()
274   {BEGIN("bgetc") return(getc(srin));}
275 
276 /*BFUNC
277 
278 bgetw() gets a msb word from the stream.
279 
280 EFUNC*/
281 
bgetw()282 int bgetw()
283   {BEGIN("bgetw") int fu; fu=getc(srin); return ((fu << 8)| getc(srin));}
284 
285 /*BFUNC
286 
287 bputc() puts a character into the stream. It is byte aligned and
288 bypasses the bit buffering.
289 
290 EFUNC*/
291 
bputc(c)292 void bputc(c)
293      int c;
294   {BEGIN("bputc") putc(c,swout);}
295 
296 /* PROTECTED MARKER GETS AND FETCHES */
297 
298 /*BFUNC
299 
300 pgetc() gets a character onto the stream but it checks to see
301 if there are any marker conflicts.
302 
303 EFUNC*/
304 
pgetc()305 static int pgetc()
306 {
307   BEGIN("pgetc")
308   int temp;
309 
310   if (CleartoResync)           /* If cleartoresync do not read from stream */
311     {
312       return(0);
313     }
314   if ((temp = bgetc())==MARKER_MARKER)   /* If MARKER then */
315     {
316       if ((temp = bgetc()))              /* if next is not 0xff, then marker */
317   {
318     WHEREAMI();
319     printf("Unanticipated marker detected.\n");
320     if (!ResyncEnable) DoAllMarker(); /* If no resync enabled */
321   }                                   /* could be marker */
322       else
323   {
324     return(MARKER_MARKER);        /* else truly 0xff */
325   }
326     }
327   return(temp);
328 }
329 
330 /*BMACRO
331 
332 pputc(stream,)
333      ) puts a value onto the stream; puts a value onto the stream, appending an extra '0' if it
334 matches the marker code.
335 
336 EMACRO*/
337 
338 #define pputc(val) {bputc(val); if (val==MARKER_MARKER) bputc(0);}
339 
340 /* MAIN ROUTINES */
341 
342 /*BFUNC
343 
344 mropen() opens a given filename as the input read stream.
345 
346 EFUNC*/
347 
mropen(filename,index)348 void mropen(filename,index)
349      char *filename;
350      int index;
351 {
352   BEGIN("mropen")
353 
354   if (Stack_Stream_Active[index])
355     {
356       WHEREAMI();
357       printf("%s cannot be opened because %d stream slot filled.\n",
358        filename,index);
359       exit(ERROR_BOUNDS);
360     }
361   if (Stack_Stream_Current!=index) pushstream();
362   current_read_byte=0;
363   read_position = -1;
364   if ((srin = fopen(filename,"rb"))==NULL)
365     {
366       WHEREAMI();
367       printf("Cannot read input file %s.\n",
368        filename);
369       exit(ERROR_INIT_FILE);
370     }
371   CleartoResync=0;
372   ResyncEnable=0;
373   ResyncCount=0;
374   LastKnownResync=0;
375   EndofFile=0;
376   EndofImage=1;    /* We start after "virtual" end of previous image */
377   Stack_Stream_Current= index;
378   Stack_Stream_Active[index]=1;
379 }
380 
381 /*BFUNC
382 
383 mrclose() closes the input read stream.
384 
385 EFUNC*/
386 
mrclose()387 void mrclose()
388 {
389   BEGIN("mrclose")
390   fclose(srin);
391   srin=NULL;
392   if (swout==NULL)
393     {
394       Stack_Stream_Active[Stack_Stream_Current]=0;
395       Stack_Stream_Current= -1;
396     }
397 }
398 
399 /*BFUNC
400 
401 mwopen() opens the stream for writing. Note that reading and
402 writing can occur simultaneously because the read and write
403 routines are independently buffered.
404 
405 EFUNC*/
406 
mwopen(filename,index)407 void mwopen(filename,index)
408      char *filename;
409      int index;
410 {
411   BEGIN("mwopen")
412 
413   if (Stack_Stream_Active[index])
414     {
415       WHEREAMI();
416       printf("%s cannot be opened because %d stream slot filled.\n",
417        filename,index);
418       exit(ERROR_BOUNDS);
419     }
420   if ((Stack_Stream_Current!=index)) pushstream();
421   current_write_byte=0;
422   write_position=7;
423   if ((swout = fopen(filename,"wb+"))==NULL)
424     {
425       WHEREAMI();
426       printf("Cannot open output file %s.\n",filename);
427       exit(ERROR_INIT_FILE);
428     }
429   Stack_Stream_Current= index;
430   Stack_Stream_Active[index]=1;
431 }
432 
433 /*BFUNC
434 
435 swbytealign() flushes the current bit-buffered byte out to the stream.
436 This is used before marker codes.
437 
438 EFUNC*/
439 
swbytealign()440 void swbytealign()
441 {
442   BEGIN("swbytealign")
443 
444   if (write_position !=7)
445     {
446       current_write_byte |= lmask[write_position];
447       pputc(current_write_byte);
448       write_position=7;
449       current_write_byte=0;
450     }
451 }
452 
453 /*BFUNC
454 
455 mwclose() closes the stream that has been opened for writing.
456 
457 EFUNC*/
458 
mwclose()459 void mwclose()
460 {
461   BEGIN("mwclose")
462 
463   swbytealign();
464   fclose(swout);
465   swout=NULL;
466   if (srin==NULL)
467     {
468       Stack_Stream_Active[Stack_Stream_Current]=0;
469       Stack_Stream_Current= -1;
470     }
471 }
472 
473 /*BFUNC
474 
475 mwtell() returns the bit position on the write stream.
476 
477 EFUNC*/
478 
mwtell()479 long mwtell()
480 {
481   BEGIN("mwtell")
482 
483   return((ftell(swout)<<3) + (7 - write_position));
484 }
485 
486 /*BFUNC
487 
488 mrtell() returns the bit position on the read stream.
489 
490 EFUNC*/
491 
mrtell()492 long mrtell()
493 {
494   BEGIN("mrtell")
495 
496   return((ftell(srin)<<3) - (read_position+1));
497 }
498 
499 /*BFUNC
500 
501 mwseek returns the bit position on the write stream.
502 
503 EFUNC*/
504 
mwseek(distance)505 void mwseek(distance)
506      long distance;
507 {
508   BEGIN("mwseek")
509   int length;
510 
511   if (write_position!=7)             /* Must flush out current byte */
512     {
513       putc(current_write_byte,swout);
514     }
515   fseek(swout,0,2L);                 /* Find end */
516   length = ftell(swout);
517   fseek(swout,((distance+7)>>3),0L);
518   if ((length<<3) <= distance)       /* Make sure we read clean stuff */
519     {
520       current_write_byte = 0;
521       write_position = 7 - (distance & 0x7);
522     }
523   else
524     {
525       current_write_byte = getc(swout);  /* if within bounds, then read byte */
526       write_position = 7 - (distance & 0x7);
527       fseek(swout,((distance+7)>>3),0L); /* Reset seek pointer for write */
528     }
529 }
530 
531 
532 /*BFUNC
533 
534 mrseek() jumps to a bit position on the read stream.
535 
536 EFUNC*/
537 
mrseek(distance)538 void mrseek(distance)
539      long distance;
540 {
541   BEGIN("mrseek")
542 
543   fseek(srin,(distance>>3),0L);       /* Go to location */
544   current_read_byte = bgetc();        /* read byte in */
545   read_position = 7 - (distance % 8);
546 }
547 
548 
549 /*BFUNC
550 
551 megetb() gets a bit from the read stream.
552 
553 EFUNC*/
554 
megetb()555 int megetb()
556 {
557   BEGIN("megetb")
558 
559   if (read_position < 0)
560     {
561       current_read_byte = pgetc();
562       read_position=7;
563     }
564   if (current_read_byte&bit_set_mask[read_position--])
565     {
566       return(1);
567     }
568   return(0);
569 }
570 
571 /*BFUNC
572 
573 meputv() puts n bits from b onto the writer stream.
574 
575 EFUNC*/
576 
meputv(n,b)577 void meputv(n,b)
578      int n;
579      int b;
580 {
581   BEGIN("meputv")
582   int p;
583 
584   n--;
585   b &= lmask[n];
586   p = n - write_position;
587   if (!p)                           /* Can do parallel save immediately */
588     {
589       current_write_byte |= b;
590       pputc(current_write_byte);
591       current_write_byte = 0;
592       write_position = 7;
593       return;
594     }
595   else if (p < 0)                   /* if can fit, we have to shift byte */
596     {
597       p = -p;
598       current_write_byte |= (b << p);
599       write_position = p-1;
600       return;
601     }
602   current_write_byte |= (b >> p);  /* cannot fit. we must do putc's */
603   pputc(current_write_byte);       /* Save off  remainder */
604   while(p > 7)                     /* Save off bytes while remaining > 7 */
605     {
606       p -= 8;
607       current_write_byte = (b >> p) & lmask[7];
608       pputc(current_write_byte);
609     }
610   if (!p)                          /* If zero then reset position */
611     {
612       write_position = 7;
613       current_write_byte = 0;
614     }
615   else                             /* Otherwise reset write byte buffer */
616     {
617       write_position = 8-p;
618       current_write_byte = (b << write_position) & lmask[7];
619       write_position--;
620     }
621 }
622 
623 /*BFUNC
624 
625 megetv() gets n bits from the read stream and returns it.
626 
627 EFUNC*/
628 
megetv(n)629 int megetv(n)
630      int n;
631 {
632   BEGIN("megetv")
633   int p,rv;
634 
635   n--;
636   p = n-read_position;
637   while(p > 0)
638     {
639       if (read_position>23)  /* If byte buffer contains almost entire word */
640   {
641     rv = (current_read_byte << p);  /* Manipulate buffer */
642     current_read_byte = pgetc();    /* Change read bytes */
643     rv |= (current_read_byte >> (8-p));
644     read_position = 7-p;
645     return(rv & lmask[n]);          /* Can return pending residual val */
646   }
647       current_read_byte = (current_read_byte << 8) | pgetc();
648       read_position += 8;                 /* else shift in new information */
649       p -= 8;
650     }
651   if (!p)                                 /* If position is zero */
652     {
653       read_position = -1;                 /* Can return current byte */
654       return(current_read_byte & lmask[n]);
655     }
656   p = -p;                                 /* Else reverse position and shift */
657   read_position = p-1;
658   return((current_read_byte >> p) & lmask[n]);
659 }
660 
661 
662 /*BFUNC
663 
664 DoMarker() performs marker analysis. We assume that the Current Marker
665 head has been read (0xFF) plus top information is at
666 marker\_read\_byte.
667 
668 EFUNC*/
669 
DoMarker()670 int DoMarker()
671 {
672   BEGIN("DoMarker")
673   int i,hin,lon,marker,length;
674 
675   current_read_byte = 0;
676   read_position= -1;                    /* Make sure we are byte-flush. */
677   while(marker_read_byte==MARKER_FIL)   /* Get rid of FIL markers */
678     {
679 #ifdef VERSION_1_0
680       if ((marker_read_byte = bgetc())!=MARKER_MARKER)
681   {
682     WHEREAMI();
683     printf("Unknown FIL marker. Bypassing.\n");
684     ErrorValue = ERROR_MARKER;
685     return(0);
686   }
687 #endif
688       marker_read_byte = bgetc();
689     }
690   lon = marker_read_byte & 0x0f;         /* Segregate between hi and lo */
691   hin = (marker_read_byte>>4) & 0x0f;    /* nybbles for the marker read byte */
692   marker = marker_read_byte;
693 
694   if (InResync)
695     {
696       if ((marker <0xd0)||(marker>0xd7))
697   {
698     WHEREAMI();
699     printf("Illegal resync marker found.\n");
700     return(0);
701   }
702     }
703   switch(hin)                            /* Pretty much self explanatory */
704     {
705     case 0x0c:                           /* Frame Style Marker */
706       switch(lon)
707   {
708   case 0x04:
709     ReadDht();
710     break;
711   case 0x00:
712   case 0x01:
713   case 0x03:
714     ReadSof(lon);
715     break;
716   case 0x08:
717   case 0x09:
718   case 0x0a:
719   case 0x0b:
720   case 0x0c:
721   case 0x0d:
722   case 0x0e:
723   case 0x0f:
724     WHEREAMI();
725     printf("Arithmetic coding not supported.\n");
726     length = bgetw();
727     for(i=2;i<length;i++)          /* Length adds 2 bytes itself */
728       bgetc();
729     break;
730   case 0x02:
731   case 0x05:
732   case 0x06:
733   case 0x07:
734   default:
735     WHEREAMI();
736     printf("Frame type %x not supported.\n",lon);
737     length = bgetw();
738     for(i=2;i<length;i++)          /* Length adds 2 bytes itself */
739       bgetc();
740     break;
741   }
742       break;
743     case 0x0d:  /* Resync Marker */
744       if (lon > 7)
745   {
746     switch(lon)
747       {
748       case 0x08:                    /* Start of Image */
749         EndofImage=0;               /* If End of Image occurs */
750         CImage->ImageSequence++;    /* reset, and increment sequence */
751         break;
752       case 0x09:                    /* End of Image */
753         EndofImage=1;
754         break;
755       case 0x0a:
756         ResyncCount=0;              /* SOS clears the resync count */
757         ReadSos();
758         break;
759       case 0x0b:
760         ReadDqt();
761         break;
762       case 0x0c:
763         ReadDnl();
764         break;
765       case 0x0d:
766         ReadDri();
767         break;
768       default:
769         WHEREAMI();
770         printf("Hierarchical markers found.\n");
771         length = bgetw();
772         for(i=2;i<length;i++)      /* Length adds 2 bytes itself */
773     {
774       bgetc();
775     }
776         break;
777       }
778   }
779       break;
780     case 0x0e: /* Application Specific */
781       length = bgetw();
782       for(i=2;i<length;i++) /* Length adds 2 bytes itself */
783   bgetc();
784       break;
785     case 0x0f: /* JPEG Specific */
786       length = bgetw();
787       for(i=2;i<length;i++) /* Length adds 2 bytes itself */
788   bgetc();
789       break;
790     default:
791       WHEREAMI();
792       printf("Bad marker byte %d.\n",marker);
793       Resync();
794       ErrorValue = ERROR_MARKER;
795       return(-1);
796       break;
797     }
798   return(marker);
799 }
800 
801 /*BFUNC
802 
803 ScreenMarker() looks to see what marker is present on the stream.  It
804 returns with the marker value read.
805 
806 EFUNC*/
807 
ScreenMarker()808 int ScreenMarker()
809 {
810   BEGIN("ScreenMarker")
811 
812   if (read_position!=7)                  /* Already read byte */
813     {
814       current_read_byte = 0;
815       read_position= -1;                 /* Consume byte to be flush */
816       if ((marker_read_byte=bgetc())==(unsigned int)EOF)
817   {
818     EndofFile=2;
819     return(EOF);
820   }
821     }
822   else                /* If flush, then marker byte is current read byte */
823     {
824       marker_read_byte = current_read_byte;
825     }
826   if (marker_read_byte!=MARKER_MARKER)    /* Not a marker, return -1. */
827     {
828       current_read_byte = marker_read_byte;
829       read_position=7;
830       return(-1);
831     }
832   while((marker_read_byte = bgetc())==MARKER_FIL)
833     {                                      /* Get rid of FIL markers */
834       if ((marker_read_byte = bgetc())!=MARKER_MARKER)
835   {
836     WHEREAMI();
837     printf("Unattached FIL marker.\n");
838     ErrorValue = ERROR_MARKER;
839     return(-1);
840   }
841       if (marker_read_byte == (unsigned int)EOF)        /* Found end of file */
842   {
843     EndofFile=2;
844     return(EOF);
845   }
846       marker_read_byte = bgetc();         /* Otherwise read another byte */
847     }                                     /* Call processor for markers */
848   if (marker_read_byte)  return(DoMarker());
849   else                                    /* Is a FF00 so don't process */
850     {
851       current_read_byte=MARKER_MARKER;     /* 255 actually read */
852       read_position=7;
853       return(-1);
854     }
855 }
856 
857 /*BFUNC
858 
859 Resync() does a resync action on the stream. This involves searching
860 for the next resync byte.
861 
862 EFUNC*/
863 
Resync()864 void Resync()
865 {
866   BEGIN("Resync")
867 
868   if (!ResyncEnable)
869     {
870       WHEREAMI();
871       printf("Resync without resync enabled\n");
872       printf("Fatal error.\n");
873       TerminateFile();
874       exit(ERROR_UNRECOVERABLE);
875     }
876   WHEREAMI();
877   printf("Attempting resynchronization.\n");
878   do
879     {
880       while((marker_read_byte = bgetc())!=MARKER_MARKER)
881   {
882     if (marker_read_byte==(unsigned int)EOF)
883       {
884         WHEREAMI();
885         printf("Attempt to resync at end of file.\n");
886         printf("Sorry.\n");
887         TerminateFile();
888         exit(ERROR_PREMATURE_EOF);
889       }
890   }
891     }
892   while(((marker_read_byte = bgetc()) & MARKER_RSC_MASK)!=MARKER_RSC);
893   LastKnownResync = marker_read_byte & 0x07;  /* Set up currently read */
894   WHEREAMI();                                 /* resync byte as future ref */
895   printf("Resync successful!\n");
896   /*
897     In general, we assume that we must add black space
898     until resynchronization. This is consistent under both
899     byte loss, byte gain, and byte corruption.
900     We assume corruption does not create new markers with
901     an RSC value--if so, we are probably dead, anyways.
902     */
903   CleartoResync=1;
904   ResyncCount = (LastKnownResync+1)&0x07;
905   current_read_byte = 0;
906   read_position = -1;
907   ResetCodec();  /* Reset the codec incase in a non-local jump. */
908 
909   printf("ResyncCount: %d  LastKnownResync: %d\n",
910    ResyncCount,LastKnownResync);
911 }
912 
913 /*BFUNC
914 
915 WriteResync() writes a resync marker out to the write stream.
916 
917 EFUNC*/
918 
WriteResync()919 void WriteResync()
920 {
921   BEGIN("WriteResync")
922 
923   swbytealign();                   /* This procedure writes a byte-aligned */
924   bputc(MARKER_MARKER);            /* resync marker. */
925   bputc((MARKER_RSC|(ResyncCount & 0x07)));
926   ResyncCount = (ResyncCount + 1) & 0x07;
927 }
928 
929 /*BFUNC
930 
931 ReadResync() looks for a resync marker on the stream. It returns a 0
932 if successful and a -1 if a search pass was required.
933 
934 EFUNC*/
935 
ReadResync()936 int ReadResync()
937 {
938   BEGIN("ReadResync")
939   int ValueRead;
940 
941   if (Robust) InResync=1;
942   while((ValueRead = ScreenMarker()) >= 0)
943     {
944       if ((ValueRead & MARKER_RSC_MASK)!=MARKER_RSC) /* Strange marker found */
945   {
946     if (ValueRead != MARKER_DNL)  /* DNL only other possibility */
947       {                           /* actually excluded, never reached */
948         WHEREAMI();               /* 11/19/91 ACH */
949         printf("Non-Resync marker found for resync.\n");
950         printf("Trying again.\n");
951       }
952   }
953       else
954   {
955     ValueRead = ValueRead & 0x07;  /* If so, then check resync count */
956     if (ValueRead != ResyncCount)
957       {
958         WHEREAMI();
959         printf("Bad resync counter. No search done.\n");
960       }
961     ResyncCount = (ResyncCount+1)&0x07;
962                                          /* Flush spurious markers. */
963     while((ValueRead = ScreenMarker()) >= 0);
964     InResync=0;
965     return(0);
966   }
967     }
968   WHEREAMI();
969   printf("Anticipated resync not found.\n");
970   Resync();
971   InResync=0;
972   return(-1);
973 }
974 
975 /*BFUNC
976 
977 ScreenAllMarker() looks for all the markers on the stream. It returns
978 a 0 if a marker has been found, -1 if no markers exist.
979 
980 EFUNC*/
981 
ScreenAllMarker()982 int ScreenAllMarker()
983 {
984   BEGIN("ScreenAllMarker")
985 
986   if (ScreenMarker()<0)
987     {
988       return(-1);
989     }
990   while(ScreenMarker()>=0);  /* Flush out all markers */
991   return(0);
992 }
993 
994 /*BFUNC
995 
996 DoAllMarker() is the same as ScreenAllMarker except we assume that the
997 prefix markerbyte (0xff) has been read and the second byte of the
998 prefix is in the marker\_byte variable. It returns a -1 if there is an
999 error in reading the marker.
1000 
1001 EFUNC*/
1002 
DoAllMarker()1003 int DoAllMarker()
1004 {
1005   BEGIN("DoAllMarker")
1006 
1007   if (DoMarker()<0)
1008     {
1009       return(-1);
1010     }
1011   while(ScreenMarker()>=0);   /* Flush out all markers */
1012   return(0);
1013 }
1014 
1015 /*END*/
1016