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 io.c
21 
22 This package is used to manipulate the raw image files.
23 
24 There are two standards: block based, assumed to be in sizes of the
25 DCT block, herein defined as BlockWidth and BlockHeight; and a special
26 case, two-line-based, assumed to be of two lines per.
27 
28 ************************************************************
29 */
30 
31 /*LABEL io.c */
32 
33 /* Include definitions. */
34 #include "globals.h"
35 #ifdef SYSV
36 #include <sys/fcntl.h>
37 #include <sys/unistd.h>
38 #endif
39 #include <stdlib.h> /* malloc */
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <string.h> /* memcpy */
44 #include <assert.h> /* memcpy */
45 #ifdef WIN32
46 #include <io.h> /* lseek on win32 */
47 #endif
48 
49 
50 /* Functions which are local and which are exported. */
51 
52 /*PUBLIC*/
53 
54 static BUFFER *MakeXBuffer();
55 static void WriteXBuffer();
56 static void ReadXBuffer();
57 static void ReadResizeBuffer();
58 static void FlushBuffer();
59 static void BlockMoveTo();
60 static void ReadXBound();
61 static void WriteXBound();
62 
63 static void LineMoveTo();
64 
65 extern void ReadBlock();
66 extern void WriteBlock();
67 extern void ResizeIob();
68 extern void RewindIob();
69 extern void FlushIob();
70 extern void SeekEndIob();
71 extern void CloseIob();
72 extern void MakeIob();
73 extern void PrintIob();
74 extern void InstallIob();
75 extern void TerminateFile();
76 
77 extern void ReadLine();
78 extern void ReadPreambleLine();
79 extern void WriteLine();
80 extern void LineResetBuffers();
81 
82 
83 /*PRIVATE*/
84 
85 /* External variables */
86 extern int Loud;
87 extern int PointTransform;   /* Used for shifting the pels from the I/O */
88 extern IMAGE *CImage;
89 extern FRAME *CFrame;
90 extern SCAN *CScan;
91 
92 /* Internal variables. */
93 static IOBUF *Iob=NULL;               /* Internal I/O buffer. */
94 static int BlockWidth = BLOCKWIDTH;   /* Block width. */
95 static int BlockHeight = BLOCKHEIGHT; /* Block height. */
96 
97 /* Buffer calculation information */
98 
99 #define BufferIndex(i,iobuf) (iobuf)->blist[(i)]
100 #define TrueBufferPos(buffer) (((buffer)->currentoffs - \
101 ((buffer)->tptr - (buffer)->bptr))/buffer->wsize)
102 
103 
104 /*START*/
105 /*BFUNC
106 
107 MakeXBuffer() constructs a holding buffer for the stream input. It
108 takes up a size passed into it and returns the appropriate buffer
109 structure.
110 
111 EFUNC*/
112 
MakeXBuffer(nelem,wsize)113 static BUFFER *MakeXBuffer(nelem,wsize)
114      int nelem;
115      int wsize;
116 {
117   BEGIN("MakeXBuffer")
118   BUFFER *temp;
119 
120   if (!(temp = MakeStructure(BUFFER)))     /* Make structure */
121     {
122       WHEREAMI();
123       printf("Cannot allocate buffer structure.\n");
124       exit(ERROR_MEMORY);
125     }
126   temp->disable=0;                          /* Not disabled */
127   temp->wsize = wsize;                      /* Set up word size */
128   temp->size=nelem*wsize;                   /* Set up size, offset */
129   temp->currentoffs = 0;
130   temp->streamoffs = 0;
131   if (!(temp->space =(unsigned char *)     /* Allocate buffer space */
132   calloc(temp->size+1,sizeof(unsigned char))))
133     {
134       WHEREAMI();
135       printf("Cannot allocate buffer memory.\n");
136       exit(ERROR_MEMORY);
137     }
138   temp->tptr = temp->bptr = temp->space;
139   return(temp);
140 }
141 
142 /*BFUNC
143 
144 ResizeIob() is used to resize the Iob height and width to conform to
145 that of the CScan. This is used for the dynamic Number-of-lines
146 rescaling.
147 
148 EFUNC*/
149 
ResizeIob()150 void ResizeIob()
151 {
152   BEGIN("ResizeIob")
153   int index;
154 
155   for(index=0;index<CScan->NumberComponents;index++)
156     {
157       CScan->Iob[index]->width = CFrame->Width[CScan->ci[index]];
158       CScan->Iob[index]->height = CFrame->Height[CScan->ci[index]];
159     }
160 }
161 
162 /*BFUNC
163 
164 MakeIob() is used to create an Iob structure for use in the CScan
165 structure. An Iob consists of several Buffer structures with some
166 additional sizing information. The input flags set up the parameters
167 of the stream.
168 
169 EFUNC*/
170 
MakeIob(type,flags,wsize)171 void MakeIob(type,flags,wsize)
172      int type;
173      int flags;
174      int wsize;
175 {
176   BEGIN("MakeIob")
177   int index,sofs;
178   BUFFER **current;
179   IOBUF *temp;
180 
181   for(index=0;index<CScan->NumberComponents;index++) /* Make IOBUF */
182     {                                                /* For each component */
183       if (!(temp = MakeStructure(IOBUF)))
184   {
185     WHEREAMI();
186     printf("Cannot allocate IOBUF structure.\n");
187     exit(ERROR_MEMORY);
188   }
189       temp->linelastdefault=(1<<(CFrame->DataPrecision-PointTransform-1));
190       temp->type = type;
191       temp->wsize = wsize;
192       temp->hpos=0;
193       temp->vpos=0;
194       temp->width = CFrame->Width[CScan->ci[index]];  /* Set up widthxheight */
195       temp->height = CFrame->Height[CScan->ci[index]];
196       if (CScan->NumberComponents==1)
197   {
198     temp->hor = 1;               /* For non-interleaved mode the freq */
199     temp->ver = 1;               /* is always 1x1 */
200   }
201       else
202   {
203     temp->hor = CFrame->hf[CScan->ci[index]];       /* and hf x vf */
204     temp->ver = CFrame->vf[CScan->ci[index]];
205   }
206       switch(temp->type)
207   {
208   case IOB_BLOCK:             /* BLOCK TYPE */
209     temp->num = temp->ver*BlockHeight;
210     break;
211   case IOB_LINE:             /* LINE TYPE */
212     temp->num = temp->ver + 1;
213     break;
214   default:
215     WHEREAMI();
216     printf("Illegal type specified: %d.\n",type);
217     exit(ERROR_BOUNDS);
218   }
219       temp->flags = flags;                            /* and also flags */
220       if (!(temp->blist =                             /*Set up buffer list */
221       (BUFFER **) calloc(temp->num,sizeof(BUFFER *))))
222   {
223     WHEREAMI();
224     printf("Cannot allocate Iob bufferlist.\n");
225     exit(ERROR_MEMORY);
226   }
227      if( CFrame->tmpfile )
228   {
229       temp->file = CFrame->tmpfile;
230   }
231     else
232   {
233       if ((temp->file =                               /* Open file */
234      open(CFrame->ComponentFileName[CScan->ci[index]],
235     flags,UMASK)) < 0)
236   {
237     WHEREAMI();
238     printf("Cannot open file %s.\n",
239      CFrame->ComponentFileName[CScan->ci[index]]);
240     exit(ERROR_INIT_FILE);
241   }               /* Make buffer for every line of component in MDU */
242   }
243 
244       for(sofs=0,current=temp->blist;current<temp->blist+temp->num;current++)
245   {
246     *current = MakeXBuffer(CFrame->BufferSize, wsize);
247     (*current)->streamoffs = sofs;
248     (*current)->iob = temp;
249     (*current)->data_linelast = temp->linelastdefault;
250     if (!temp->height || (current - temp->blist) < temp->height-1)
251       {
252         sofs += CFrame->Width[CScan->ci[index]]*wsize;
253       }
254   }
255       CScan->Iob[index] = temp;
256     }
257 }
258 
259 /*BFUNC
260 
261 PrintIob() is used to print the current input buffer to the stdio
262 stream.
263 
264 EFUNC*/
265 
PrintIob()266 void PrintIob()
267 {
268   BEGIN("PrintIob")
269 
270   if (Iob)
271     {
272       printf("*** Iob ID: %p ***\n",(void*)Iob);
273       printf("Number of Buffers: %d  Width: %d  Height: %d\n",
274        Iob->num,Iob->width,Iob->height);
275       printf("hpos: %d  vpos: %d  hor-freq: %d  ver-freq: %d\n",
276        Iob->hpos,Iob->vpos,Iob->hor,Iob->ver);
277       printf("filed: %d  flags: %d  BufferListId: %p\n",
278        Iob->file,Iob->flags,(void*)Iob->blist);
279     }
280   else
281     {
282       printf("*** Iob ID: NULL ***\n");
283     }
284 }
285 
286 /*BFUNC
287 
288 WriteXBuffer() writes out len elements from storage out to the buffer
289 structure specified.  This is can result in a multiple of len bytes
290 being written out depending on the element structure.
291 
292 EFUNC*/
293 
WriteXBuffer(len,storage,buffer)294 static void WriteXBuffer(len,storage,buffer)
295      int len;
296      int *storage;
297      BUFFER *buffer;
298 {
299   BEGIN("WriteXBuffer")
300   int diff,wout;
301 
302   if (buffer->disable)
303     {
304       WHEREAMI();
305       printf("Attempting to write to disabled buffer!\n");
306     }
307   /* printf("Writing:%d bytes\n",len);*/
308   diff = buffer->size - (buffer->bptr - buffer->space); /* Find room left */
309   diff = diff/buffer->wsize;                        /* Scale by element # */
310   if(len > diff)
311     {                                     /* Put as many elems in */
312       WriteXBuffer(diff,storage,buffer);  /* If no room, then flush current */
313       FlushBuffer(buffer);                /* buffer out to disk */
314       len -= diff;
315       storage += diff;
316     }
317   switch(buffer->wsize)   /* Because of compatibility differences between */
318     {                     /* UNIX implementations, we are forced to do this */
319     case 1:               /* explicit ordering of bytes... */
320       while(len--)        /* Write the rest of the buffer out to the disk */
321   {
322     wout = *(storage++)<<PointTransform;
323   *(buffer->bptr++) = (unsigned char) wout;
324   }
325       break;
326     case 2:
327       while(len--)        /* Write the rest of the buffer out to the disk */
328   {
329     wout = *(storage++)<<PointTransform;
330     *(buffer->bptr++) = (unsigned char) (wout>>8)&0xff;
331     *(buffer->bptr++) = (unsigned char) wout&0xff;
332   }
333       break;
334     case 3:
335       while(len--)        /* Write the rest of the buffer out to the disk */
336   {
337     wout = *(storage++)<<PointTransform;
338     *(buffer->bptr++) = (unsigned char) (wout>>16)&0xff;
339     *(buffer->bptr++) = (unsigned char) (wout>>8)&0xff;
340     *(buffer->bptr++) = (unsigned char) wout&0xff;
341   }
342       break;
343     case 4:
344       while(len--)        /* Write the rest of the buffer out to the disk */
345   {
346     wout = *(storage++)<<PointTransform;
347     *(buffer->bptr++) = (unsigned char) (wout>>24)&0xff;
348     *(buffer->bptr++) = (unsigned char) (wout>>16)&0xff;
349     *(buffer->bptr++) = (unsigned char) (wout>>8)&0xff;
350     *(buffer->bptr++) = (unsigned char) wout&0xff;
351   }
352       break;
353     default:
354       WHEREAMI();
355       printf("Illegal word size in characters %d.\n",buffer->wsize);
356       exit(ERROR_BOUNDS);
357       break;
358     }
359 }
360 
361 /*BFUNC
362 
363 ReadXBuffer() is fetches len amount of elements into storage from the
364 buffer structure.  This may actually amount to an arbitrary number of
365 characters depending on the word size.
366 
367 EFUNC*/
368 
ReadXBuffer(len,storage,buffer)369 static void ReadXBuffer(len,storage,buffer)
370      int len;
371      int *storage;
372      BUFFER *buffer;
373 {
374   BEGIN("ReadXBuffer")
375   int i,numchars,maxelem,rin;
376 
377   if (buffer->disable)
378     {
379       for(i=0;i<len;i++) *(storage++)=buffer->data_linelast;
380       return;
381     }
382 
383   numchars = len*buffer->wsize;
384                                    /* The following command recurses because */
385                                    /* it's slightly more efficient that way */
386                                    /* when the probability of recursion is */
387                                    /* negligible. */
388   while (numchars > buffer->size)  /* We ask more than the buffer can handle */
389     {                              /* Inefficient for small buffer sizes */
390       maxelem = buffer->size/buffer->wsize;
391       ReadXBuffer(maxelem, storage, buffer); /* Split up into several reads */
392       storage += maxelem;
393       len -= maxelem;
394       numchars -= maxelem*buffer->wsize;
395     }
396   if(numchars > (buffer->tptr - buffer->bptr)) /* If we request > bytes */
397     ReadResizeBuffer(numchars,buffer);       /* Read those bytes in */
398   switch(buffer->wsize)                 /* Again, explicit input of bytes */
399     {
400     case 1:
401       while(len--)                      /* Now copy over to storage */
402   {
403     rin = (int) *(buffer->bptr++);
404     *(storage++) = rin >> PointTransform;
405   }
406       break;
407     case 2:
408       while(len--)                      /* Now copy over to storage */
409   {
410     rin = (((int)*(buffer->bptr++))<<8);
411     rin |= *(buffer->bptr++);
412     *(storage++) = rin >> PointTransform;
413   }
414       break;
415     case 3:
416       while(len--)                      /* Now copy over to storage */
417   {
418     rin = (((int)*(buffer->bptr++))<<16);
419     rin |= (((int)*(buffer->bptr++))<<8);
420     rin |= (*(buffer->bptr++));
421     *(storage++) = rin >> PointTransform;
422   }
423       break;
424     case 4:
425       while(len--)                      /* Now copy over to storage */
426   {
427     rin = (((int)*(buffer->bptr++))<<24);
428     rin |= (((int)*(buffer->bptr++))<<16);
429     rin |= (((int)*(buffer->bptr++))<<8);
430     rin |= (*(buffer->bptr++));
431     *(storage++) = rin >> PointTransform;
432   }
433       break;
434     default:
435       WHEREAMI();
436       printf("Illegal word size in characters %d.\n",buffer->wsize);
437       exit(ERROR_BOUNDS);
438       break;
439     }
440 #ifdef IO_DEBUG
441   WHEREAMI();
442   printf("last read: %d",*(storage-1));
443   printf("\n");
444 #endif
445 }
446 
447 /*BFUNC
448 
449 ReadResizeBuffer() reads len bytes from the stream and puts it
450 into the buffer.
451 
452 EFUNC*/
453 
ReadResizeBuffer(len,buffer)454 static void ReadResizeBuffer(len,buffer)
455      int len;
456      BUFFER *buffer;
457 {
458   BEGIN("ReadResizeBuffer")
459   int retval,diff,location,amount;
460 
461   diff = buffer->tptr - buffer->bptr;        /* Find out the current usage */
462   if (len > buffer->size-1)                  /* calculate if we can hold it */
463     {
464       WHEREAMI();
465       printf("Length Request Too Large.\n");
466       exit(ERROR_PARAMETER);
467     }
468 #ifdef IO_DEBUG
469   printf("SPACE: %x BPTR: %x DIFF: %d\n",buffer->space,buffer->bptr,diff);
470   printf("ReadLseek %d\n",buffer->streamoffs+buffer->currentoffs);
471 #endif
472   assert( diff >= 0 );
473   memcpy(buffer->space,buffer->bptr,diff);   /* Move buffer down. */
474   buffer->bptr = buffer->space;              /* Reset pointers. */
475   buffer->tptr = buffer->space + diff;
476 
477   location = buffer->streamoffs+buffer->currentoffs;
478   amount = buffer->size-(buffer->tptr - buffer->space);
479   lseek(buffer->iob->file,location,SEEK_SET);
480 #ifdef IO_DEBUG
481   printf("Read: Filed %d  Buf: %x  NBytes: %d\n",
482    buffer->iob->file,buffer->tptr,amount);
483 #endif
484   if ((retval = read(buffer->iob->file,      /* Do the read */
485          buffer->tptr,
486          amount)) < 0)
487     {
488       WHEREAMI();
489       printf("Cannot Resize.\n");
490       exit(ERROR_READ);
491     }
492 #ifdef IO_DEBUG
493   printf("ReadReturn numbytes %d\n",retval);
494 #endif
495   buffer->tptr += retval;                   /* Alter pointers */
496   buffer->currentoffs += retval;
497 }
498 
499 /*BFUNC
500 
501 FlushBuffer() saves the rest of the bytes in the buffer out to the
502 disk.
503 
504 EFUNC*/
505 
FlushBuffer(buffer)506 static void FlushBuffer(buffer)
507      BUFFER *buffer;
508 {
509   BEGIN("FlushBuffer")
510   int retval;
511 
512 #ifdef IO_DEBUG
513   printf("WriteLseek %d\n",buffer->streamoffs+buffer->currentoffs);
514 #endif
515   lseek(buffer->iob->file,buffer->streamoffs+buffer->currentoffs,SEEK_SET);
516   if ((retval = write(buffer->iob->file,
517           buffer->space,
518           (buffer->bptr - buffer->space))) < 0)
519     {
520       WHEREAMI();
521       printf("Cannot flush buffer.\n");
522       exit(ERROR_WRITE);
523     }
524   buffer->currentoffs += (buffer->bptr - buffer->space);
525   buffer->bptr = buffer->space;
526 }
527 
528 /*BFUNC
529 
530 ReadBlock() is used to get a block from the current Iob. This function
531 returns (for the JPEG case) 64 bytes in the store integer array.  It
532 is stored in row-major form; that is, the row index changes least
533 rapidly.
534 
535 EFUNC*/
536 
ReadBlock(store)537 void ReadBlock(store)
538      int *store;
539 {
540   BEGIN("ReadBlock")
541   int i,voffs;
542 
543   voffs = (Iob->vpos % Iob->ver)*BlockHeight;  /* Find current v offset*/
544 #ifdef IO_DEBUG
545   for(i=0;i<BlockHeight;i++)
546     {
547       printf("%d Iob %x\n",i,Iob->blist[i]->Iob);
548     }
549 #endif
550   for(i=voffs;i<voffs+BlockHeight;i++)         /* Use voffs to index into */
551     {                                          /* Buffer list of IOB */
552 #ifdef IO_DEBUG
553       printf("%d Iob %x\n",i,Iob->blist[i]->Iob);
554 #endif
555       ReadXBound(BlockWidth,store,Iob->blist[i]);  /* get blockwidth elms */
556       store+=BlockWidth;                    /* Storage array & increment */
557     }                                       /* by blockwidth */
558   if ((++Iob->hpos % Iob->hor)==0)          /* Increment MDU block pos */
559     {
560       if ((++Iob->vpos % Iob->ver) == 0)
561   {
562     if (Iob->hpos < CScan->MDUWide*Iob->hor)
563       {
564         Iob->vpos -= Iob->ver;
565       }
566     else
567       {
568         Iob->hpos = 0;                /* If at end of raster width*/
569         BlockMoveTo();                /* Reload buffers from start */
570       }                               /* of next line. */
571   }
572       else
573   {
574     Iob->hpos -= Iob->hor;
575   }
576     }
577 }
578 
579 /*BFUNC
580 
581 WriteBlock() writes an array of data in the integer array pointed to
582 by store out to the driver specified by the IOB.  The integer array is
583 stored in row-major form, that is, the first row of (8) elements, the
584 second row of (8) elements....
585 
586 EFUNC*/
587 
WriteBlock(store)588 void WriteBlock(store)
589      int *store;
590 {
591   BEGIN("WriteBlock")
592   int i,voffs;
593 
594   voffs = (Iob->vpos % Iob->ver)*BlockHeight;  /* Find vertical buffer offs. */
595   for(i=voffs;i<voffs+BlockHeight;i++)
596     {
597       if (!Iob->height || (((Iob->vpos/Iob->ver)*BlockHeight + i) <
598          Iob->height))
599   {
600     WriteXBound(BlockWidth,store,Iob->blist[i]); /* write Block elms */
601     store+=BlockWidth;                   /* Iob indexed by offset */
602   }
603     }
604   if ((++Iob->hpos % Iob->hor)==0)             /* Increment block position */
605     {                                          /* in MDU. */
606       if ((++Iob->vpos % Iob->ver) == 0)
607   {
608     if (Iob->hpos < CScan->MDUWide*Iob->hor)
609       {
610         Iob->vpos -= Iob->ver;
611       }
612     else
613       {
614         Iob->hpos = 0;                  /* If at end of image (width) */
615         FlushIob();                     /* Flush current IOB and */
616         BlockMoveTo();                  /* Move to next lower MDU line */
617       }
618   }
619       else
620   {
621     Iob->hpos -= Iob->hor;
622   }
623     }
624 }
625 
626 
627 /*BFUNC
628 
629 BlockMoveTo() is used to move to a specific vertical and horizontal
630 location (block wise) specified by the current Iob. That means you set
631 the current Iob parameters and then call BlockMoveTo().
632 
633 EFUNC*/
634 
BlockMoveTo()635 static void BlockMoveTo()
636 {
637   BEGIN("BlockMoveTo")
638   int i,vertical,horizontal;
639 
640   if (Loud > MUTE)
641     {
642       WHEREAMI();
643       printf("%p  Moving To [Horizontal:Vertical] [%d:%d] \n",
644        (void*)Iob,Iob->hpos,Iob->vpos);
645     }
646   horizontal =  Iob->hpos * BlockWidth;    /* Calculate actual */
647   vertical = Iob->vpos * BlockHeight;      /* Pixel position */
648   for(i=0;i<Iob->ver*BlockHeight;i++)
649     {
650       if (Iob->height)
651   {
652     vertical =
653       ((vertical < Iob->height) ?
654        vertical : Iob->height-1);
655   }
656       Iob->blist[i]->tptr =                /* Reset pointer space */
657   Iob->blist[i]->bptr =              /* To show no contents */
658     Iob->blist[i]->space;
659       Iob->blist[i]->currentoffs = horizontal* Iob->wsize;/* reset h offset */
660       Iob->blist[i]->streamoffs = vertical * Iob->width *
661   Iob->wsize;                                       /* Reset v offset */
662       vertical++;
663     }
664 }
665 
666 /*BFUNC
667 
668 RewindIob() brings all the pointers to the start of the file. The reset
669 does not flush the buffers if writing.
670 
671 EFUNC*/
672 
RewindIob()673 void RewindIob()
674 {
675   BEGIN("RewindIob")
676   int i;
677 
678   switch(Iob->type)
679     {
680     case IOB_BLOCK:
681       BlockWidth = BLOCKWIDTH;   /* Block width. */
682       BlockHeight = BLOCKHEIGHT; /* Block height. */
683       for(i=0;i<Iob->ver*BlockHeight;i++)
684   {
685     Iob->blist[i]->tptr =
686       Iob->blist[i]->bptr =
687         Iob->blist[i]->space;
688     Iob->blist[i]->currentoffs = 0;
689     Iob->blist[i]->streamoffs = i * Iob->width * Iob->wsize;
690   }
691       Iob->hpos = Iob->vpos = 0;
692       break;
693     case IOB_LINE:
694       Iob->linelastdefault=(1<<(CFrame->DataPrecision-PointTransform-1));
695       for(i= 0;i<Iob->ver+1;i++)
696   {
697     Iob->blist[i]->tptr =
698       Iob->blist[i]->bptr =
699         Iob->blist[i]->space;
700     Iob->blist[i]->currentoffs = 0;
701     if (!i)
702       {
703         Iob->blist[i]->streamoffs = 0;
704         Iob->blist[i]->disable=1;
705       }
706     else
707       {
708         Iob->blist[i]->streamoffs = (i-1) * Iob->width * Iob->wsize;
709         Iob->blist[i]->disable=0;
710       }
711     Iob->blist[i]->data_linelast = Iob->linelastdefault;
712   }
713       Iob->hpos = 0;
714       Iob->vpos = -1;
715       break;
716     default:
717       WHEREAMI();
718       printf("Bad IOB type: %d\n",Iob->type);
719       break;
720     }
721 }
722 
723 /*BFUNC
724 
725 FlushIob() is used to flush all the buffers in the current Iob. This
726 is done at the conclusion of a write on the current buffers.
727 
728 EFUNC*/
729 
FlushIob()730 void FlushIob()
731 {
732   BEGIN("FlushIob")
733   int i;
734 
735   if (Loud > MUTE)
736     printf("IOB: %p  Flushing buffers\n",(void*)Iob);
737   switch(Iob->type)
738     {
739     case IOB_BLOCK:
740       for(i=0;i<Iob->ver*BlockHeight;i++)
741   FlushBuffer(Iob->blist[i]);
742       break;
743     case IOB_LINE:
744       Iob->blist[0]->data_linelast=Iob->linelastdefault;
745       for(i=1;i<Iob->ver+1;i++)
746   {
747     Iob->blist[i]->data_linelast=Iob->linelastdefault;
748     FlushBuffer(Iob->blist[i]);
749   }
750       break;
751     default:
752       WHEREAMI();
753       printf("Illegal IOB type: %d.\n",Iob->type);
754       break;
755     }
756 }
757 
758 /*BFUNC
759 
760 SeekEndIob() is used to seek the end of all the buffers in the current
761 Iob. This is done at the conclusion of a write, to avoid DNL problems.
762 
763 EFUNC*/
764 
SeekEndIob()765 void SeekEndIob()
766 {
767   BEGIN("SeekEndIob")
768   int size,tsize;
769   static unsigned char Terminator[] = {0x80,0x00};
770 
771   size = lseek(Iob->file,0,SEEK_END);
772   tsize = Iob->width*Iob->height*Iob->wsize;
773   if (size !=  tsize)
774     {
775       WHEREAMI();
776       printf("End not flush, making flush (actual: %d != target:%d)\n",
777        size,tsize);
778 
779       if (size<tsize)
780   {
781     lseek(Iob->file,tsize-1,SEEK_SET);         /* Seek and terminate */
782     write(Iob->file,Terminator,1);
783   }
784       else if (size > tsize)
785   {
786 #ifdef NOTRUNCATE
787     WHEREAMI();
788     printf("file is too large, only first %d bytes valid\n",
789      tsize);
790 #else
791 #ifdef WIN32
792     chsize(Iob->file,tsize); /* no ftruncate on WIN32... */
793 #else
794     ftruncate(Iob->file,tsize);                   /* simply truncate*/
795 #endif
796 #endif
797   }
798     }
799 }
800 
801 
802 /*BFUNC
803 
804 CloseIob() is used to close the current Iob.
805 
806 EFUNC*/
807 
CloseIob()808 void CloseIob()
809 {
810   BEGIN("CloseIob")
811 
812   if( !CFrame->tmpfile ) /* if file is closed we loose it for good */
813 {
814   close(Iob->file);
815 }
816 }
817 
818 /*BFUNC
819 
820 ReadXBound() reads nelem elements of information from the specified
821 buffer.  It detects to see whether a load is necessary or not, or
822 whether the current buffer is out of the image width bounds.
823 
824 EFUNC*/
825 
ReadXBound(nelem,cstore,buffer)826 static void ReadXBound(nelem,cstore,buffer)
827      int nelem;
828      int *cstore;
829      BUFFER *buffer;
830 {
831   BEGIN("ReadXBound")
832   int i,diff;
833 
834   if ((diff = buffer->iob->width - TrueBufferPos(buffer)) <= nelem)
835     {
836 #ifdef IO_DEBUG
837       printf("ReadBound: Trailing Edge Detected. Diff: %d\n",diff);
838 #endif
839       if (diff <= 0)
840   {
841     for(i=0;i<nelem;i++)       /* Pure outside bounds */
842       *(cstore++) = buffer->overflow;
843   }
844       else
845   {
846     ReadXBuffer(diff,cstore,buffer);
847     buffer->overflow = (unsigned int) cstore[diff-1];
848     for(i=diff;i<nelem;i++)     /* Replicate to bounds */
849       cstore[i] = cstore[i-1];
850   }
851     }
852   else
853     ReadXBuffer(nelem,cstore,buffer);
854 }
855 
856 /*BFUNC
857 
858 WriteXBound() writes the integer array input to the buffer. It checks
859 to see whether the bounds of the image width are exceeded, if so, the
860 excess information is ignored.
861 
862 EFUNC*/
863 
WriteXBound(nelem,cstore,buffer)864 static void WriteXBound(nelem,cstore,buffer)
865      int nelem;
866      int *cstore;
867      BUFFER *buffer;
868 {
869   BEGIN("WriteXBound")
870   int diff;
871 
872   if ((diff = buffer->iob->width - TrueBufferPos(buffer)) <= nelem)
873     {                           /* Diff is balance to write to disk */
874       if (diff > 0)             /* Write balance out to disk */
875   WriteXBuffer(diff,cstore,buffer);
876     }
877   else                          /* If more than numberelem, then can put all */
878     WriteXBuffer(nelem,cstore,buffer);       /* to the buffer. */
879 }
880 
881 /*BFUNC
882 
883 InstallIob() is used to install the Iob in the current scan as the
884 real Iob.
885 
886 EFUNC*/
887 
InstallIob(index)888 void InstallIob(index)
889      int index;
890 {
891   BEGIN("InstallIob")
892 
893   if (!(Iob = CScan->Iob[index]))
894     {
895       WHEREAMI();
896       printf("Warning, NULL Iob installed.\n");
897     }
898 }
899 
900 
901 /*BFUNC
902 
903 TerminateFile() is a function that ensures that the entire file
904 defined by the Iob is properly flush with the filesize specifications.
905 This function is used when some fatal error occurs.
906 
907 EFUNC*/
908 
909 
TerminateFile()910 void TerminateFile()
911 {
912   BEGIN("TerminateFile")
913   int i,size;
914   static unsigned char Terminator[] = {0x80,0x00};
915 
916   if (CFrame->GlobalHeight)
917     {
918       printf("> GH:%d  GW:%d  R:%d\n",
919        CFrame->GlobalHeight,
920        CFrame->GlobalWidth,
921        CFrame->ResyncInterval);
922       for(i=0;i<CScan->NumberComponents;i++)
923   {
924     if (CScan->Iob[i])
925       {
926         printf(">> C:%d  N:%s  H:%d  W:%d  hf:%d  vf:%d\n",
927          CScan->ci[i],
928          CFrame->ComponentFileName[CScan->ci[i]],
929          CFrame->Height[CScan->ci[i]],
930          CFrame->Width[CScan->ci[i]],
931          CFrame->hf[CScan->ci[i]],
932          CFrame->vf[CScan->ci[i]]);
933         InstallIob(i);
934         FlushIob();
935         size = lseek(CScan->Iob[i]->file,0,SEEK_END);
936         if (size !=
937       CFrame->Width[CScan->ci[i]]*CFrame->Height[CScan->ci[i]]*
938       CScan->Iob[i]->wsize)
939     {                                      /* Terminate file */
940       lseek(CScan->Iob[i]->file,           /* by seeking to end */
941       (CFrame->Width[CScan->ci[i]]*  /* And writing byte */
942        CFrame->Height[CScan->ci[i]]*
943        CScan->Iob[i]->wsize)-1,      /* Making flush with */
944       SEEK_SET);                           /* Original size  */
945       write(CScan->Iob[i]->file,Terminator,1);
946     }
947       }
948   }
949     }
950   else
951     {
952       WHEREAMI();
953       printf("Unknown number of lines. Cannot flush file.\n");
954     }
955 }
956 
957 
958 /*BFUNC
959 
960 ReadLine() reads in the lines required by the lossless function.  The
961 array *store should be large enough to handle the line information
962 read.
963 
964 In total, there should be (HORIZONTALFREQUENCY+1) * nelem
965 (VERTICALFREQUENCY+1) elements in the *store array.  This forms a
966 matrix with each line consisting of:
967 
968 [PastPredictor 1 element]  nelem* [HORIZONTALFREQUENCY elements]
969 
970 And there are (VERTICALFREQUENCY+1) of such lines in the matrix:
971 
972 Previous line (2**Precision-1) if beyond specifications of window
973 Active line 1...
974 ...
975 Active line VERTICALFREQUENCY...
976 
977 
978 EFUNC*/
979 
ReadLine(nelem,store)980 void ReadLine(nelem,store)
981      int nelem;
982      int *store;
983 {
984   BEGIN("ReadLine")
985   int i;
986 
987   for(i=0;i<Iob->ver+1;i++)         /* Use voffs to index into */
988     {                                          /* Buffer list of IOB */
989 #ifdef IO_DEBUG
990       printf("%d Iob %x\n",i,Iob->blist[i]->Iob);
991 #endif
992       *(store++)=Iob->blist[i]->data_linelast;
993       ReadXBound(Iob->hor*nelem,store,Iob->blist[i]);
994       store+=Iob->hor*nelem;
995       Iob->blist[i]->data_linelast = *(store-1);
996     }
997   Iob->hpos += Iob->hor*nelem;
998   if (Iob->hpos >= CScan->MDUWide*Iob->hor)
999     {
1000       Iob->vpos += Iob->ver;
1001       Iob->hpos = 0;                /* If at end of raster width*/
1002       LineMoveTo();                 /* Reload buffers from start */
1003     }                               /* of next line. */
1004 }
1005 
1006 /*BFUNC
1007 
1008 ReadPreambleLine() reads the first line of the *store array for the
1009 WriteLine() companion command.  It reads it so that prediction can be
1010 accomplished with minimum effort and storage.
1011 
1012 This command is executed before decoding a particular line for the
1013 prediction values; WriteLine() is called after the decoding is done.
1014 
1015 EFUNC*/
1016 
ReadPreambleLine(nelem,store)1017 void ReadPreambleLine(nelem,store)
1018      int nelem;
1019      int *store;
1020 {
1021   BEGIN("ReadPreambleLine")
1022   int i;
1023   int preamblelength=1;
1024 
1025   for(i=0;i<Iob->ver+1;i++)         /* Use voffs to index into */
1026     {                                          /* Buffer list of IOB */
1027 #ifdef IO_DEBUG
1028       printf("%d Iob %x\n",i,Iob->blist[i]->Iob);
1029 #endif
1030       if (i<preamblelength)
1031   {
1032     *(store++)=Iob->blist[i]->data_linelast;
1033     ReadXBound(Iob->hor*nelem,store,Iob->blist[i]);
1034     store+=Iob->hor*nelem;
1035     Iob->blist[i]->data_linelast = *(store-1);
1036   }
1037       else
1038   {
1039     *(store) = Iob->blist[i]->data_linelast;
1040     store += Iob->hor*nelem+1;
1041   }
1042     }
1043 }
1044 
1045 
1046 /*BFUNC
1047 
1048 WriteLine() is used to write a particular line out to the IOB.  The
1049 line must be of the proper form in the array for this function to
1050 work.
1051 
1052 In total, there should be (HORIZONTALFREQUENCY+1) * nelem
1053 (VERTICALFREQUENCY+1) elements in the *store array.  This forms a
1054 matrix with each line consisting of:
1055 
1056 [PastPredictor 1 element]  nelem* [HORIZONTALFREQUENCY elements]
1057 
1058 And there are (VERTICALFREQUENCY+1) of such lines in the matrix:
1059 
1060 Previous line (2**Precision-1) if beyond specifications of window
1061 Active line 1...
1062 ...
1063 Active line VERTICALFREQUENCY...
1064 
1065 
1066 EFUNC*/
1067 
WriteLine(nelem,store)1068 void WriteLine(nelem,store)
1069      int nelem;
1070      int *store;
1071 {
1072   BEGIN("WriteLine")
1073   int i;
1074 
1075   store += Iob->hor*nelem+1;        /* Get rid of first line */
1076   for(i=1;i<Iob->ver+1;i++)         /* Use voffs to index into */
1077     {                               /* Buffer list of IOB */
1078 #ifdef IO_DEBUG
1079       printf("WriteLine: %d  Store: %d Iobblist: %x\n",
1080        i,*(store+1),Iob->blist[i]);
1081 #endif
1082 
1083       WriteXBound(Iob->hor*nelem,store+1,Iob->blist[i]);
1084       store+=(Iob->hor*nelem)+1;
1085       Iob->blist[i]->data_linelast = *(store-1);
1086     }
1087   Iob->hpos += Iob->hor*nelem;
1088   if (Iob->hpos >= CScan->MDUWide*Iob->hor)
1089     {
1090       Iob->vpos += Iob->ver;
1091       Iob->hpos = 0;                /* If at end of raster width*/
1092       FlushIob();                   /* Flush current IOB and */
1093       LineMoveTo();                 /* Reload buffers from start */
1094     }                               /* of next line. */
1095 }
1096 
1097 /*BFUNC
1098 
1099 LineResetBuffers() resets all of the line buffers to the
1100 (2\^DataPrecision-1) state.  The previous state is the default
1101 prediction.  This commmand is used for resynchronization. The
1102 implementation here does a trivial resetting.
1103 
1104 EFUNC */
1105 
LineResetBuffers()1106 extern void LineResetBuffers()
1107 {
1108   BEGIN("LineResetBuffers")
1109   int i;
1110 
1111   if (Iob->type!=IOB_LINE)
1112     {
1113       WHEREAMI();
1114       printf("Attempting to line reset a non-line buffer!\n");
1115       exit(ERROR_PARAMETER);
1116     }
1117   for(i=0;i<Iob->ver+1;i++)
1118     Iob->blist[i]->data_linelast = Iob->linelastdefault;
1119 }
1120 
1121 /*BFUNC
1122 
1123 LineMoveTo() is used to move to a specific vertical and horizontal
1124 location (line wise) specified by the current Iob. That means you set
1125 the current Iob parameters and then call LineMoveTo().
1126 
1127 EFUNC*/
1128 
LineMoveTo()1129 static void LineMoveTo()
1130 {
1131   BEGIN("LineMoveTo")
1132   int i,vertical,horizontal;
1133 
1134   if (Loud > MUTE)
1135     {
1136       WHEREAMI();
1137       printf("%p  Moving To [Horizontal:Vertical] [%d:%d] \n",
1138        (void*)Iob,Iob->hpos,Iob->vpos);
1139     }
1140   horizontal =  Iob->hpos;
1141   vertical = Iob->vpos;
1142   for(i=0;i<Iob->ver+1;i++)
1143     {                                     /* Reset last element read */
1144       if (vertical<0)
1145   {
1146     Iob->blist[i]->disable=1;
1147     continue;
1148   }
1149       Iob->blist[i]->disable=0;
1150       Iob->blist[i]->data_linelast=Iob->linelastdefault;
1151       if (Iob->height)
1152   {
1153     vertical =
1154       ((vertical < Iob->height) ?
1155        vertical : Iob->height-1);
1156   }
1157       Iob->blist[i]->tptr =                /* Reset pointer space */
1158   Iob->blist[i]->bptr =              /* To show no contents */
1159     Iob->blist[i]->space;
1160       Iob->blist[i]->currentoffs = horizontal* Iob->wsize; /* Reset h offset */
1161       Iob->blist[i]->streamoffs = vertical * Iob->width *
1162   Iob->wsize;                                        /* Reset v offset */
1163       vertical++;
1164     }
1165 }
1166 
1167 
1168 
1169 /*END*/
1170