home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #4 / amigamamagazinepolishissue1998.iso / datatypes / gifanimdtc201.lha / gifanim_datatype / dispatch.c < prev    next >
C/C++ Source or Header  |  1998-03-23  |  92KB  |  2,491 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 2.1 (23.3.98)
  5. **  gifanim.datatype 2.1
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1997/1998 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* main includes */
  15. #include "classbase.h"
  16. #include "classdata.h"
  17.  
  18. /* ansi includes */
  19. #include <limits.h>
  20.  
  21. /*****************************************************************************/
  22. /* debugging */
  23.  
  24. #if 0
  25. void kprintf( STRPTR, ... );
  26. #define D( x ) x
  27. #else
  28. #define D( x )
  29. #endif
  30.  
  31. /*****************************************************************************/
  32.  
  33. /* decoder related local prototypes */
  34. static BOOL             ReadColorMap( struct ClassBase *, struct GIFAnimInstData *, UWORD, struct ColorRegister * );
  35. static void             DoExtension( struct ClassBase *, Object *, struct GIFAnimInstData *, TEXT );
  36. static int              GetDataBlock( struct ClassBase *, struct GIFAnimInstData *, UBYTE * );
  37. static int              GetCode( struct ClassBase *, struct GIFAnimInstData *, int, BOOL );
  38. static int              LWZReadByte( struct ClassBase *, struct GIFAnimInstData *, BOOL, int );
  39. static void             ReadImage( struct ClassBase *, struct GIFAnimInstData *, UBYTE *, UWORD, UWORD, UWORD, UWORD, UWORD, BOOL, BOOL, UWORD );
  40. static void             WriteDeltaPixelArray8Fast( struct BitMap *, UBYTE *, UBYTE * );
  41. static int              getbase2( int );
  42. static BOOL             ReadOK( struct ClassBase *, struct GIFDecoder *, void *, ULONG );
  43.  
  44. /*****************************************************************************/
  45.  
  46. /* local prototypes */
  47. static                 BOOL                 ScanFrames( struct ClassBase *, Object * );
  48. static                 struct FrameNode    *AllocFrameNode( struct ClassBase *, APTR );
  49. static                 struct FrameNode    *FindFrameNode( struct MinList *, ULONG );
  50. static                 void                 FreeFrameNodeResources( struct ClassBase *, struct GIFAnimInstData * );
  51. static                 struct BitMap       *AllocFrameBitMap( struct ClassBase *, struct GIFAnimInstData * );
  52. static                 void                 FreeFrameBitMap( struct ClassBase *, struct GIFAnimInstData *, struct BitMap * );
  53. static                 struct BitMap       *AllocBitMapPooled( struct ClassBase *, ULONG, ULONG, ULONG, APTR );
  54. static                 struct FrameNode    *GetPrevFrameNode( struct FrameNode *, ULONG );
  55. static                 void                 AttachSample( struct ClassBase *, struct GIFAnimInstData * );
  56.  
  57. /*****************************************************************************/
  58.  
  59. /* Create "gifanim.datatype" BOOPSI class */
  60. struct IClass *initClass( struct ClassBase *cb )
  61. {
  62.     struct IClass *cl;
  63.  
  64.     /* Create our class... */
  65.     if( cl = MakeClass( GIFANIMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct GIFAnimInstData ), 0UL ) )
  66.     {
  67. #define DTSTACKSIZE (16384UL)
  68.       cl -> cl_Dispatcher . h_Entry    = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
  69.       cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch;          /* see stackswap.c */
  70.       cl -> cl_Dispatcher . h_Data     = (APTR)DTSTACKSIZE;           /* see stackswap.c */
  71.       cl -> cl_UserData                = (ULONG)cb;
  72.  
  73.       AddClass( cl );
  74.     }
  75.  
  76.     return( cl );
  77. }
  78.  
  79.  
  80. /* class dispatcher */
  81. DISPATCHERFLAGS
  82. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  83. {
  84.     struct ClassBase        *cb = (struct ClassBase *)(cl -> cl_UserData);
  85.     struct GIFAnimInstData  *gaid;
  86.     ULONG                    retval = 0UL;
  87.  
  88.     switch( msg -> MethodID )
  89.     {
  90. /****** gifanim.datatype/OM_NEW **********************************************
  91. *
  92. *    NAME
  93. *        OM_NEW -- Create a gifanim.datatype object.
  94. *
  95. *    FUNCTION
  96. *        The OM_NEW method is used to create an instance of the
  97. *        gifanim.datatype class.  This method is passed to the superclass
  98. *        first. After this, gifanim.datatype parses the prefs file and makes
  99. *        a scan through the data to get index information. Frame bitmaps are
  100. *        loaded if the input stream isn't seekable, colormaps and the first
  101. *        frame are loaded immediately.
  102. *        If a sample was set in the prefs, it will be loaded and attached
  103. *        to the animation.
  104. *
  105. *    ATTRIBUTES
  106. *        The following attributes can be specified at creation time.
  107. *
  108. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  109. *            attribute. Only DTST_FILE and DTST_RAM are supported.
  110. *            If any other type was set in a given DTA_SourceType,
  111. *            OM_NEW will be rejected.
  112. *            Defaults to DTST_FILE.
  113. *
  114. *        DTA_Handle -- For DTST_FILE, a BPTR filehandle is expected. This
  115. *            handle will be created by datatypesclass depeding on the DTF_#?
  116. *            flag, which is DTF_BINARY here.  DTST_FILE, datatypesclass
  117. *            creates a file handle from the given DTA_Name and DTA_Handle
  118. *            (a BPTR returned by Lock).
  119. *            A DTST_RAM (create empty object) source type requires a NULL
  120. *            handle.
  121. *
  122. *    RESULT
  123. *        If the object was created a pointer to the object is returned,
  124. *        otherwise NULL is returned.
  125. *
  126. ******************************************************************************
  127. *
  128. */
  129.       case OM_NEW:
  130.       {
  131.           struct TagItem *ti;
  132.  
  133.           /* We only support DTST_FILE or DTST_RAM as source type */
  134.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  135.           {
  136.             if( ((ti -> ti_Data) != DTST_FILE) && ((ti -> ti_Data) != DTST_RAM) )
  137.             {
  138.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  139.  
  140.               break;
  141.             }
  142.           }
  143.  
  144.           if( retval = DoSuperMethodA( cl, o, msg ) )
  145.           {
  146.             /* Load frames... */
  147.             if( !ScanFrames( cb, (Object *)retval ) )
  148.             {
  149.               /* Something went fatally wrong, dispose object */
  150.               CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  151.               retval = 0UL;
  152.             }
  153.           }
  154.       }
  155.           break;
  156.  
  157. /****** gifanim.datatype/OM_DISPOSE ******************************************
  158. *
  159. *    NAME
  160. *        OM_DISPOSE -- Delete a gifanim.datatype object.
  161. *
  162. *    FUNCTION
  163. *        The OM_DISPOSE method is used to delete an instance of the
  164. *        gifanim.datatype class. This method is passed to the superclass when
  165. *        it has completed.
  166. *        This method frees all frame nodes and their contents (bitmaps,
  167. *        colormaps, samples etc.)
  168. *
  169. *    RESULT
  170. *        The object is deleted. 0UL is returned.
  171. *
  172. ******************************************************************************
  173. *
  174. */
  175.       case OM_DISPOSE:
  176.       {
  177.           LONG saved_ioerr = IoErr();
  178.  
  179.           /* Get a pointer to our object data */
  180.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  181.  
  182.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  183.           WaitBlit();
  184.  
  185.           /* Free colormaps etc. (e.g. all resources which are NOT free'ed on DeletePool below) */
  186.           FreeFrameNodeResources( cb, gaid );
  187.  
  188.           /* Free our key bitmap */
  189.           FreeBitMap( (gaid -> gaid_KeyBitMap) );
  190.  
  191.           /* Delete the frame pool */
  192.           DeletePool( (gaid -> gaid_Pool) );
  193.  
  194.           /* Close input file */
  195.           if( gaid -> gaid_FH )
  196.           {
  197.             Close( (gaid -> gaid_FH) );
  198.           }
  199.  
  200.           /* Close verbose output file */
  201.           if( gaid -> gaid_VerboseOutput )
  202.           {
  203.             Close( (gaid -> gaid_VerboseOutput) );
  204.           }
  205.  
  206.           /* Dispose object */
  207.           DoSuperMethodA( cl, o, msg );
  208.  
  209.           /* Restore Result2 */
  210.           SetIoErr( saved_ioerr );
  211.       }
  212.           break;
  213.  
  214. /* TEST TEST / Support for format change "on-the-fly" disabled here / TEST TEST  */
  215. #ifdef COMMENTED_OUT
  216.       case DTM_FRAMEBOX:
  217.       {
  218.           struct dtFrameBox *dtf = (struct dtFrameBox *)msg;
  219.  
  220.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  221.  
  222.           /* pass to superclas first */
  223.           retval = DoSuperMethodA( cl, o, msg );
  224.  
  225.           /* Does someone tell me in what for an environment (screen) I'll be attached to ? */
  226.           if( (dtf -> dtf_FrameFlags) & FRAMEF_SPECIFY )
  227.           {
  228.             if( dtf -> dtf_ContentsInfo )
  229.             {
  230.               if( dtf -> dtf_ContentsInfo -> fri_Screen )
  231.               {
  232.                 struct BitMap *bm = dtf -> dtf_ContentsInfo -> fri_Screen -> RastPort . BitMap;
  233.  
  234.                 /* Does we have a non-planar bitmap ? */
  235.                 if( !(GetBitMapAttr( bm, BMA_FLAGS ) & BMF_STANDARD) )
  236.                 {
  237.                   /* I assume here that the system is able to map a 24 bit bitmap into the screen
  238.                    * if it is deeper than 8 bit.
  239.                    */
  240.                   if( ((bm -> Depth) > 8UL) && ((dtf -> dtf_ContentsInfo -> fri_Dimensions . Depth) > 8UL) )
  241.                   {
  242.                     verbose_printf( cb, gaid, "using chunky bitmap\n" );
  243.                   }
  244.                 }
  245.               }
  246.             }
  247.           }
  248.       }
  249.           break;
  250. #endif /* COMMENTED_OUT */
  251.  
  252.       case OM_UPDATE:
  253.       {
  254.           if( DoMethod( o, ICM_CHECKLOOP ) )
  255.           {
  256.             break;
  257.           }
  258.       }
  259.       case OM_SET:
  260.       {
  261.           /* Pass the attributes to the animation class and force a refresh if we need it */
  262.           if( retval = DoSuperMethodA( cl, o, msg ) )
  263.           {
  264.             /* Top instance ? */
  265.             if( OCLASS( o ) == cl )
  266.             {
  267.               struct RastPort *rp;
  268.  
  269.               /* Get a pointer to the rastport */
  270.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  271.               {
  272.                 struct gpRender gpr;
  273.  
  274.                 /* Force a redraw */
  275.                 gpr . MethodID   = GM_RENDER;
  276.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  277.                 gpr . gpr_RPort  = rp;
  278.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  279.  
  280.                 DoMethodA( o, (Msg)(&gpr) );
  281.  
  282.                 /* Release the temporary rastport */
  283.                 ReleaseGIRPort( rp );
  284.  
  285.                 /* We did a refresh... */
  286.                 retval = 0UL;
  287.               }
  288.             }
  289.           }
  290.       }
  291.           break;
  292.  
  293. /****** gifanim.datatype/DTM_WRITE *******************************************
  294. *
  295. *    NAME
  296. *        DTM_WRITE -- Save data
  297. *
  298. *    FUNCTION
  299. *        This method saves the object's contents to disk.
  300. *
  301. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  302. *        superclass, animation.datatype, which writes a single IFF ILBM
  303. *        picture.
  304. *
  305. *        If dtw_mode is DTWM_RAW, the object saved an GIF Animation stream 
  306. *        to the filehandle given, starting with the current frame until
  307. *        the end is reached.
  308. *        The sequence saved can be controlled by the ADTA_Frame, ADTA_Frames
  309. *        and ADTA_FrameIncrement attributes (see TAGS section below).
  310. *
  311. *    TAGS
  312. *        When writing the local ("raw") format, GIF Animation, the following
  313. *        attributes are recognized:
  314. *
  315. *        ADTA_Frame (ULONG) - start frame, saving starts here.
  316. *            Defaults to the current frame displayed.
  317. *
  318. *        ADTA_Frames (ULONG) - the number of frames to be saved,
  319. *            Defaults to (max_num_of_frames - curr_frame).
  320. *
  321. *        ADTA_FrameIncrement (ULONG) - frame increment when saving.
  322. *            Defaults to 1, which means: "jump to next frame".
  323. *
  324. *    NOTE
  325. *        - Any sound attached to the animation will NOT be saved.
  326. *
  327. *        - A CTRL-D signal to the writing process aborts the save.
  328. *
  329. *    RESULT
  330. *        Returns 0 for failure (IoErr() returns result2), non-zero
  331. *        for success.
  332. *
  333. ******************************************************************************
  334. *
  335. */
  336.       case DTM_WRITE:
  337.       {
  338.           struct dtWrite *dtw;
  339.  
  340.           dtw = (struct dtWrite *)msg;
  341.  
  342.           /* Local data format requested ?... */
  343.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  344.           {
  345.             retval = SaveGIFAnim( cb, cl, o, dtw );
  346.           }
  347.           else
  348.           {
  349.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  350.             retval = DoSuperMethodA( cl, o, msg );
  351.           }
  352.       }
  353.           break;
  354.  
  355.  
  356. /****** gifanim.datatype/ADTM_LOADFRAME *****************************************
  357. *
  358. *    NAME
  359. *        ADTM_LOADFRAME -- Load frame
  360. *
  361. *    FUNCTION
  362. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  363. *        data of the animation.
  364. *        The given timestamp will be used to find a matching timestamp
  365. *        in the internal FrameNode list. If it was found, the corresponding
  366. *        timing, bitmap and colormap data are stored into the struct
  367. *        adtFrame. If the bitmap wasn't loaded, this method attempts to
  368. *        load it from disk.
  369. *
  370. *    RESULT
  371. *        the bitmap ptr if a bitmap was found,
  372. *        0 (and result2 with the reason).
  373. *
  374. ******************************************************************************
  375. *
  376. */
  377.       case ADTM_LOADFRAME:
  378.       {
  379.           struct adtFrame  *alf         = (struct adtFrame *)msg;
  380.           struct adtFrame   freeframe;
  381.           struct FrameNode *fn;
  382.           LONG              error       = 0L;
  383.  
  384.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  385.  
  386.           ObtainSemaphore( (&(gaid -> gaid_SigSem)) );
  387.  
  388.           /* Like "realloc": Free any given frame (the free is done AFTER the load to
  389.            * avoid that a frame which is loaded will be freed and then loaded again...
  390.            */
  391.           if( alf -> alf_UserData )
  392.           {
  393.             /* Copy message contents that we can call ADTM_UNLOADFRAME below */
  394.             freeframe = *alf;
  395.             alf -> alf_UserData = NULL; /* "freeframe" now owns the frame data to free ! */
  396.           }
  397.           else
  398.           {
  399.             /* No data to free... */
  400.             freeframe . alf_UserData = NULL;
  401.           }
  402.  
  403.           /* Find frame by timestamp */
  404.           if( fn = FindFrameNode( (&(gaid -> gaid_FrameList)), (alf -> alf_TimeStamp) ) )
  405.           {
  406.             /* Load bitmaps only if we don't cache the whole anim and
  407.              * if we have a filehandle to load from (an empty object created using DTST_RAM won't have this)...
  408.              */
  409.             if( (!(gaid -> gaid_LoadAll) == FALSE) && (gaid -> gaid_FH) )
  410.             {
  411.               /* If no bitmap is loaded, load it... */
  412.               if( (fn -> fn_BitMap) == NULL )
  413.               {
  414.                 ULONG animwidth  = (ULONG)(gaid -> gaid_PaddedWidth),
  415.                       animheight = (ULONG)(gaid -> gaid_Height);
  416.  
  417.                 /* Allocate array for chunkypixel data */
  418.                 if( fn -> fn_ChunkyMap = (UBYTE *)AllocVecPooled( cb, (gaid -> gaid_Pool), ((animwidth * animheight) + 256) ) )
  419.                 {
  420.                   /* Get a clean background to avoid that rubbish shows througth transparent parts */
  421.                   memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  422.  
  423.                   if( fn -> fn_BitMap = AllocFrameBitMap( cb, gaid ) )
  424.                   {
  425.                     struct FrameNode *worknode = fn;
  426.                     struct FrameNode *prevnode = NULL;
  427.                     ULONG             rollback = 0UL;
  428.                     UBYTE            *deltamap = NULL;
  429.  
  430.                     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  431.  
  432.                     /* See if we need a rollback (if TRUE, we copy (below) the previous chunkymap into our
  433.                      * current chunkymap as background. If Left/Top != 0 or transparent colors are present,
  434.                      * parts of this previous image will occur).
  435.                      */
  436.                     switch( fn -> fn_GIF89aDisposal )
  437.                     {
  438.                       case GIF89A_DISPOSE_NODISPOSE:
  439.                       case GIF89A_DISPOSE_RESTOREPREVIOUS:
  440.                       {
  441.                           do
  442.                           {
  443.                             worknode = GetPrevFrameNode( worknode, 1UL );
  444.  
  445.                             rollback++;
  446.                           } while( ((worknode -> fn_ChunkyMap) == NULL) && ((worknode -> fn_TimeStamp) != 0UL) );
  447.                       }
  448.                           break;
  449.                     }
  450.  
  451.                     if( ((worknode -> fn_ChunkyMap) == NULL) && ((worknode -> fn_TimeStamp) == 0UL) )
  452.                     {
  453.                       error_printf( cb, gaid, "first frame without bitmap ... !\n" );
  454.                     }
  455.  
  456.                     do
  457.                     {
  458.                       ULONG current = rollback;
  459.  
  460.                       worknode = fn;
  461.  
  462.                       while( current-- )
  463.                       {
  464.                         worknode = GetPrevFrameNode( worknode, 1UL );
  465.                       }
  466.  
  467.                       if( (worknode -> fn_ChunkyMap) && (worknode != fn) )
  468.                       {
  469.                         prevnode = worknode;
  470.                       }
  471.                       else
  472.                       {
  473.                         if( Seek( (gaid -> gaid_FH), ((worknode -> fn_BMOffset) - (gaid -> gaid_CurrFilePos)), OFFSET_CURRENT ) != (-1L) )
  474.                         {
  475.                           if( gifdec -> file_buffer = AllocVec( ((worknode -> fn_BMSize) + 16UL), MEMF_PUBLIC ) )
  476.                           {
  477.                             BOOL   useGlobalColormap;
  478.                             UWORD  bitPixel;
  479.                             UBYTE  buf[ 16 ];
  480.  
  481.                             /* Init buffer */
  482.                             gifdec -> buffer     = gifdec -> file_buffer;
  483.                             gifdec -> buffersize = worknode -> fn_BMSize;
  484.                             gifdec -> which_fh   = WHICHFH_BUFFER;
  485.  
  486.                             /* Fill buffer */
  487.                             if( Read( (gifdec -> file), (gifdec -> buffer), (gifdec -> buffersize) ) == (gifdec -> buffersize) )
  488.                             {
  489.                               if( !ReadOK( cb, gifdec, buf, 9 ) )
  490.                               {
  491.                                 error = IoErr();
  492.                                 D( kprintf( "couldn't read left/top/width/height\n" ) );
  493.                               }
  494.  
  495.                               useGlobalColormap = !BitSet( buf[ 8 ], LOCALCOLORMAP );
  496.  
  497.                               bitPixel = 1 << ((buf[ 8 ] & 0x07) + 1);
  498.  
  499.                               /* disposal method */
  500.                               switch( worknode -> fn_GIF89aDisposal )
  501.                               {
  502.                                 case GIF89A_DISPOSE_NOP:
  503.                                 {
  504.                                   /* Background not transparent ? */
  505.                                   if( ((worknode -> fn_GIF89aTransparent) == ~0U) ||
  506.                                       ((worknode -> fn_GIF89aTransparent) != 0U) )
  507.                                   {
  508.                                     /* Restore to color 0 */
  509.                                     memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  510.                                   }
  511.                                 }
  512.                                     break;
  513.  
  514.                                 case GIF89A_DISPOSE_NODISPOSE:
  515.                                 {
  516.                                     /* do not dispose prev image */
  517.  
  518.                                     /* Check if we have a prevnode link to the previous image.
  519.                                      * If this is NULL, we assume that our chunkymap already contain
  520.                                      * the previous image
  521.                                      */
  522.                                     if( prevnode )
  523.                                     {
  524.                                       CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  525. #ifdef DELTAWPA8
  526.                                       CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  527.                                       deltamap = prevnode -> fn_ChunkyMap;
  528. #endif /* DELTAWPA8 */
  529.                                     }
  530.                                     else
  531.                                     {
  532. #ifdef DELTAWPA8
  533.                                       deltamap = NULL;
  534. #endif /* DELTAWPA8 */
  535.                                     }
  536.                                 }
  537.                                     break;
  538.  
  539.                                 case GIF89A_DISPOSE_RESTOREBACKGROUND:
  540.                                 {
  541.                                     /* Background not transparent ? */
  542.                                     if( ((worknode -> fn_GIF89aTransparent) == ~0U) ||
  543.                                         ((worknode -> fn_GIF89aTransparent) != (gaid -> gaid_GIFDec . GifScreen . Background)) )
  544.                                     {
  545.                                       /* Restore to background color */
  546.                                       memset( (fn -> fn_ChunkyMap), (gaid -> gaid_GIFDec . GifScreen . Background), (size_t)(animwidth * animheight) );
  547.                                     }
  548.                                 }
  549.                                     break;
  550.  
  551.                                 case GIF89A_DISPOSE_RESTOREPREVIOUS:
  552.                                 {
  553.                                     /* restore image of previous frame */
  554.  
  555.                                     /* Check if we have a prevnode link to the previous image.
  556.                                      * If this is NULL, we assume that our chunkymap already contain
  557.                                      * the previous image
  558.                                      */
  559.                                     if( prevnode )
  560.                                     {
  561.                                       CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  562. #ifdef DELTAWPA8
  563.                                       CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  564.                                       deltamap = prevnode -> fn_ChunkyMap;
  565. #endif /* DELTAWPA8 */
  566.                                     }
  567.                                     else
  568.                                     {
  569. #ifdef DELTAWPA8
  570.                                       deltamap = NULL;
  571. #endif /* DELTAWPA8 */
  572.                                     }
  573.                                 }
  574.                                     break;
  575.  
  576.                                 default: /* GIF89A_DISPOSE_RESERVED4 - GIF89A_DISPOSE_RESERVED7 */
  577.                                 {
  578.                                     error_printf( cb, gaid, "unsupported disposal method %lu\n", (ULONG)(gaid -> gaid_GIFDec . Gif89 . disposal) );
  579.                                 }
  580.                                     break;
  581.                               }
  582.  
  583.                               if( !useGlobalColormap )
  584.                               {
  585.                                 /* Skip colormap (in buffer) */
  586.                                 gifdec -> buffer += (sizeof( struct ColorRegister ) * bitPixel);
  587.                               }
  588.  
  589.                               ReadImage( cb, gaid,
  590.                                          (fn -> fn_ChunkyMap),
  591.                                          (UWORD)animwidth,
  592.                                          LOHI2UINT16( buf[ 0 ], buf[ 1 ] ),
  593.                                          LOHI2UINT16( buf[ 2 ], buf[ 3 ] ),
  594.                                          LOHI2UINT16( buf[ 4 ], buf[ 5 ] ),
  595.                                          LOHI2UINT16( buf[ 6 ], buf[ 7 ] ),
  596.                                          BitSet( buf[ 8 ], INTERLACE ),
  597.                                          FALSE,
  598.                                          (worknode -> fn_GIF89aTransparent) );
  599.                             }
  600.  
  601.                             FreeVec( (gifdec -> file_buffer) );
  602.                             gifdec -> file_buffer = gifdec -> buffer = NULL;
  603.                           }
  604.  
  605.                           /* Bump file pos */
  606.                           gaid -> gaid_CurrFilePos = Seek( (gaid -> gaid_FH), 0L, OFFSET_CURRENT ); /* BUG: does not check for failure */
  607.                         }
  608.                         else
  609.                         {
  610.                           /* seek failed */
  611.                           error = IoErr();
  612.                           break;
  613.                         }
  614.  
  615.                         prevnode = NULL; /* a previous image is now in our chunkymap,
  616.                                           * we don't need the link anymore
  617.                                           */
  618.                       }
  619.                     } while( rollback-- );
  620.  
  621.                     if( error == 0L )
  622.                     {
  623.                       if( fn -> fn_ChunkyMap )
  624.                       {
  625.                         if( gaid -> gaid_UseChunkyMap )
  626.                         {
  627.                           WriteRGBPixelArray8( cb, (fn -> fn_BitMap), animwidth, animheight, (fn -> fn_ColorMap), (fn -> fn_ChunkyMap) );
  628.                         }
  629.                         else
  630.                         {
  631.                           WriteDeltaPixelArray8Fast( (fn -> fn_BitMap), (fn -> fn_ChunkyMap), deltamap );
  632.                         }
  633.                       }
  634.                     }
  635.                   }
  636.                   else
  637.                   {
  638.                     /* can't alloc bitmap */
  639.                     error = ERROR_NO_FREE_STORE;
  640.                   }
  641.                 }
  642.                 else
  643.                 {
  644.                   /* can't alloc chunkymap */
  645.                   error = ERROR_NO_FREE_STORE;
  646.                 }
  647.               }
  648.             }
  649.  
  650.             /* Store timing/context information */
  651.             alf -> alf_Duration = fn -> fn_Duration;
  652.             alf -> alf_Frame    = fn -> fn_Frame;
  653.             alf -> alf_UserData = (APTR)fn;        /* Links back to this FrameNode (used by ADTM_UNLOADFRAME) */
  654.  
  655.             /* Store bitmap information */
  656.             alf -> alf_BitMap = fn -> fn_BitMap;
  657.             alf -> alf_CMap   = ((gaid -> gaid_UseChunkyMap)?(NULL):(fn -> fn_CMap)); /* we does not use a colormap with a direct RGB-coded bitmap */
  658.  
  659.             /* Is there a sample to play ? */
  660.             if( fn -> fn_Sample )
  661.             {
  662.               /* Store sound information */
  663.               alf -> alf_Sample       = fn -> fn_Sample;
  664.               alf -> alf_SampleLength = fn -> fn_SampleLength;
  665.               alf -> alf_Period       = fn -> fn_Period;
  666.             }
  667.             else
  668.             {
  669.               /* No sound */
  670.               alf -> alf_Sample       = NULL;
  671.               alf -> alf_SampleLength = 0UL;
  672.               alf -> alf_Period       = 0UL;
  673.             }
  674.  
  675.             /* Frame "in use", even for a unsuccessful result; on error
  676.              * animation.datatype send an ADTM_UNLOADFRAME which frees
  677.              * allocated resources and decreases the "UseCount"...
  678.              */
  679.             fn -> fn_UseCount++;
  680.  
  681.             /* Return bitmap ptr of possible, 0UL and error cause otherwise */
  682.             retval = ((error)?(0UL):(ULONG)(alf -> alf_BitMap)); /* Result  */
  683.           }
  684.           else
  685.           {
  686.             /* no matching frame found */
  687.             error = ERROR_OBJECT_NOT_FOUND;
  688.           }
  689.  
  690.           /* Like "realloc": Free any given frame here */
  691.           if( freeframe . alf_UserData )
  692.           {
  693.             freeframe . MethodID = ADTM_UNLOADFRAME;
  694.             DoMethodA( o, (Msg)(&freeframe) );
  695.           }
  696.  
  697.           SetIoErr( error ); /* Result2 */
  698.  
  699.           ReleaseSemaphore( (&(gaid -> gaid_SigSem)) );
  700.       }
  701.           break;
  702.  
  703. /****** gifanim.datatype/ADTM_UNLOADFRAME ************************************
  704. *
  705. *    NAME
  706. *        ADTM_UNLOADFRAME -- Unload frame contents
  707. *
  708. *    FUNCTION
  709. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  710. *        animation frame.
  711. *
  712. *        This method frees the bitmap data found in adtFrame.
  713. *
  714. *    RESULT
  715. *        Returns always 0UL.
  716. *
  717. ******************************************************************************
  718. *
  719. */
  720.       case ADTM_UNLOADFRAME:
  721.       {
  722.           struct FrameNode *fn;
  723.           struct adtFrame  *alf;
  724.  
  725.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  726.           alf = (struct adtFrame *)msg;
  727.  
  728.           /* Free bitmaps only if we don't cache the whole anim */
  729.           if( (gaid -> gaid_LoadAll) == FALSE )
  730.           {
  731.             ObtainSemaphore( (&(gaid -> gaid_SigSem)) );
  732.  
  733.             if( fn = (struct FrameNode *)(alf -> alf_UserData) )
  734.             {
  735.               if( (fn -> fn_UseCount) > 0 )
  736.               {
  737.                 fn -> fn_UseCount--;
  738.  
  739.                 /* Free an existing bitmap if it isn't in use and if it is NOT the first bitmap */
  740.                 if( ((fn -> fn_UseCount) == 0) && (fn -> fn_BitMap) && (fn != (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head)) )
  741.                 {
  742.                   FreeFrameBitMap( cb, gaid, (fn -> fn_BitMap) );
  743.                   FreeVecPooled( cb, (gaid -> gaid_Pool), (fn -> fn_ChunkyMap) );
  744.                   fn -> fn_BitMap    = NULL;
  745.                   fn -> fn_ChunkyMap = NULL;
  746.                 }
  747.               }
  748.             }
  749.  
  750.             ReleaseSemaphore( (&(gaid -> gaid_SigSem)) );
  751.           }
  752.  
  753.           /* The frame has been freed ! */
  754.           alf -> alf_UserData = NULL;
  755.       }
  756.           break;
  757.  
  758.       /* Let the superclass handle everything else */
  759.       default:
  760.       {
  761.           retval = DoSuperMethodA( cl, o, msg );
  762.       }
  763.           break;
  764.     }
  765.  
  766.     return( retval );
  767. }
  768.  
  769.  
  770. static
  771. BOOL ScanFrames( struct ClassBase *cb, Object *o )
  772. {
  773.     struct GIFAnimInstData *gaid    = (struct GIFAnimInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  774.     LONG                    error   = 0L;
  775.     BOOL                    success = FALSE;
  776.  
  777.     InitSemaphore( (&(gaid -> gaid_SigSem)) );
  778.     NewList( (struct List *)(&(gaid -> gaid_FrameList)) );
  779.  
  780.     /* Create a memory pool for frame nodes */
  781.     if( gaid -> gaid_Pool = CreatePool( MEMF_PUBLIC, 8192UL, 8192UL ) )
  782.     {
  783.       BPTR                 fh;                             /* handle (file handle)      */
  784.       ULONG                sourcetype;                     /* type of stream (either DTST_FILE or DTST_RAM) */
  785.       ULONG                modeid /*= (ULONG)INVALID_ID*/; /* anim view mode                  */
  786.       ULONG                animwidth,                      /* anim width                      */
  787.                            animheight,                     /* anim height                     */
  788.                            animdepth;                      /* anim depth                      */
  789.       ULONG                timestamp  = 0UL;               /* timestamp                       */
  790.  
  791.       /* Prefs defaults */
  792.       gaid -> gaid_LoadAll = TRUE;              /* The decoder is too slow to allow realtime decoding of a
  793.                                                  * 576 * 124 * 8 GIF Image, even on a mc68040 :-((
  794.                                                  */
  795.       gaid -> gaid_ModeID  = (ULONG)INVALID_ID; /* no screen mode selected yet */
  796.       gaid -> gaid_Volume  = 64UL;
  797.  
  798.       /* Read prefs */
  799.       ReadENVPrefs( cb, gaid );
  800.  
  801.       /* Get file handle, handle type and BitMapHeader */
  802.       if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  803.                          DTA_Handle,        (&fh),
  804.                          DTA_Name,          (&(gaid -> gaid_ProjectName)),
  805.                          TAG_DONE ) == 3UL )
  806.       {
  807.         switch( sourcetype )
  808.         {
  809.           case DTST_FILE:
  810.           {
  811.               if( fh )
  812.               {
  813.                 BPTR lock;
  814.  
  815.                 if( lock = DupLockFromFH( fh ) )
  816.                 {
  817.                   /* Set up a filehandle for disk-based loading (random loading) */
  818.                   if( gaid -> gaid_FH = (LONG)OpenFromLock( lock ) )
  819.                   {
  820.                     success = TRUE;
  821.                   }
  822.                   else
  823.                   {
  824.                     /* failure */
  825.                     UnLock( lock );
  826.                   }
  827.                 }
  828.               }
  829.  
  830.               /* OpenFromLock failed ? - Then open by name :-( */
  831.               if( (gaid -> gaid_FH) == NULL )
  832.               {
  833.                 /* Set up a filehandle for disk-based loading (random loading) */
  834.                 if( gaid -> gaid_FH = (LONG)Open( (gaid -> gaid_ProjectName), MODE_OLDFILE ) )
  835.                 {
  836.                   success = TRUE;
  837.                 }
  838.                 else
  839.                 {
  840.                   /* Can't open file */
  841.                   error = IoErr();
  842.                 }
  843.               }
  844.           }
  845.               break;
  846.  
  847.           case DTST_RAM: /* empty object */
  848.           {
  849.               success = TRUE;
  850.           }
  851.               break;
  852.  
  853.           default:
  854.           {
  855.               /* unsupported source type */
  856.               error = ERROR_NOT_IMPLEMENTED;
  857.           }
  858.               break;
  859.         }
  860.  
  861.         /* Any error ? */
  862.         if( success )
  863.         {
  864.           /* Now we enter the next stage of testing... */
  865.           success = FALSE;
  866.  
  867.           if( fh )
  868.           {
  869.             struct GIFDecoder    *gifdec                           = (&(gaid -> gaid_GIFDec));
  870.             struct FrameNode     *fn;
  871.             ULONG                 numcmaps                         = 0UL; /* number of created cmaps */
  872.             UBYTE                 buf[ 16 ];
  873.             struct ColorRegister  localColorMap[ MAXCOLORMAPSIZE ] = { 0 };
  874.             struct ColorRegister  savedTransparentColor            = { 0 };
  875.             UBYTE                 c;
  876.             BOOL                  useGlobalColormap;
  877.             UWORD                 bitPixel;
  878.             UBYTE                 version[ 4 ];
  879.  
  880.             gifdec -> file                = fh;
  881.             gifdec -> Gif89 . transparent = (UWORD)~0U; /* means: no transparent color */
  882.  
  883.             /* Read "GIF" indentifer and version */
  884.             if( ReadOK( cb, gifdec, buf, 6 ) )
  885.             {
  886.               /* Is there the GIF signature ? */
  887.               if( !strncmp( (char *)buf, "GIF", 3 ) )
  888.               {
  889.                 strncpy( version, (char *)(buf + 3), 3 );
  890.                 version[ 3 ] = '\0';
  891.  
  892.                 /* Check if we support this GIF version */
  893.                 if( (!strcmp( version, "87a" )) ||
  894.                     (!strcmp( version, "89a" )) )
  895.                 {
  896.                   /* Read GIF Screen */
  897.                   if( ReadOK( cb, gifdec, buf, 7 ) )
  898.                   {
  899.                     struct FrameNode *prevnode = NULL;
  900.                     UBYTE            *deltamap = NULL;
  901.  
  902.                     gifdec -> GifScreen . Width           = LOHI2UINT16( buf[ 0 ], buf[ 1 ] );
  903.                     gifdec -> GifScreen . Height          = LOHI2UINT16( buf[ 2 ], buf[ 3 ] );
  904.                     gifdec -> GifScreen . BitPixel        = 2 << (buf[ 4 ] & 0x07);
  905.                     gifdec -> GifScreen . ColorResolution = (((buf[ 4 ] & 0x70) >> 3) + 1);
  906.                     gifdec -> GifScreen . Background      = buf[ 5 ];
  907.                     gifdec -> GifScreen . AspectRatio     = buf[ 6 ];
  908.  
  909.                                  gaid -> gaid_Width        = gifdec -> GifScreen . Width;
  910.                     animwidth  = gaid -> gaid_PaddedWidth  = (gaid -> gaid_UseChunkyMap)?(gaid -> gaid_Width):(((gaid -> gaid_Width) + 15UL) & ~15UL); /* align for c2p-wpa (c2c does not need padding) */
  911.                     animheight = gaid -> gaid_Height       = gifdec -> GifScreen . Height;
  912.                     animdepth  = gaid -> gaid_Depth        = (gaid -> gaid_UseChunkyMap)?(DIRECTRGB_DEPTH):((ULONG)getbase2( (gifdec -> GifScreen . BitPixel) ));
  913.  
  914.                     /* Global Colormap ? */
  915.                     if( BitSet( buf[ 4 ], LOCALCOLORMAP ) )
  916.                     {
  917.                       numcmaps++;
  918.  
  919.                       if( ReadColorMap( cb, gaid, (gifdec -> GifScreen . BitPixel), (gifdec -> GifScreen . ColorMap) ) )
  920.                       {
  921.                         error = IoErr();
  922.                         D( kprintf( "error reading global colormap\n" ) );
  923.                       }
  924.                     }
  925.                     else
  926.                     {
  927.                       /* No global colormap ? - Then the background color in the GifScreen is a NOP */
  928.                       gifdec -> GifScreen . Background = 0U;
  929.                     }
  930.  
  931.                     for( ;; )
  932.                     {
  933.                       /* Read chunk ID char */
  934.                       if( !ReadOK( cb, gifdec, (&c), 1 ) )
  935.                       {
  936.                         error = IoErr();
  937.                         D( kprintf( "EOF / read error on image data\n" ) );
  938.                       }
  939.  
  940.                       switch( c )
  941.                       {
  942.                         case ';': /* GIF terminator ? */
  943.                         {
  944.                             goto scandone;
  945.                         }
  946.  
  947.                         case '!': /* Extension ? */
  948.                         {
  949.                             if( !ReadOK( cb, gifdec, (&c), 1 ) )
  950.                             {
  951.                               error = IoErr();
  952.                               D( kprintf( "OF / read error on extension function code\n" ) );
  953.                             }
  954.  
  955.                             DoExtension( cb, o, gaid, c );
  956.                         }
  957.                             break;
  958.  
  959.                         case ',': /* Raster data start ? */
  960.                         {
  961.                             /* Create an prepare a new frame node */
  962.                             if( fn = AllocFrameNode( cb, (gaid -> gaid_Pool) ) )
  963.                             {
  964.                               if( (gaid -> gaid_LoadAll) || (timestamp == 0UL) )
  965.                               {
  966.                                 if( !(fn -> fn_BitMap = AllocFrameBitMap( cb, gaid ) ) )
  967.                                 {
  968.                                   error = ERROR_NO_FREE_STORE;
  969.                                 }
  970.  
  971.                                 /* Allocate array for chunkypixel data */
  972.                                 if( fn -> fn_ChunkyMap = (UBYTE *)AllocVecPooled( cb, (gaid -> gaid_Pool), ((animwidth * animheight) + 256) ) )
  973.                                 {
  974.                                   /* Get a clean background to avoid that rubbish shows througth transparent parts */
  975.                                   memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  976.                                 }
  977.                                 else
  978.                                 {
  979.                                   error = ERROR_NO_FREE_STORE;
  980.                                 }
  981.                               }
  982.  
  983.                               if( error == 0L )
  984.                               {
  985.                                 ULONG duration;
  986.  
  987.                                 /* Get position of bitmap */
  988.                                 fn -> fn_BMOffset = Seek( fh, 0L, OFFSET_CURRENT ); /* BUG: does not check for failure */
  989.  
  990.                                 D( kprintf( "pos %lu\n", (fn -> fn_BMOffset) ) );
  991.  
  992.                                 if( !ReadOK( cb, gifdec, buf, 9 ) )
  993.                                 {
  994.                                   error = IoErr();
  995.                                   D( kprintf( "couldn't read left/top/width/height\n" ) );
  996.                                 }
  997.  
  998.                                 /* Local color map ? */
  999.                                 useGlobalColormap = !BitSet( buf[ 8 ], LOCALCOLORMAP );
  1000.  
  1001.                                 /* Size of local color map */
  1002.                                 bitPixel = 1 << ((buf[ 8 ] & 0x07) + 1);
  1003.  
  1004.                                 /* Store GIF89a related attributes */
  1005.                                 fn -> fn_GIF89aDisposal    = gifdec -> Gif89 . disposal;    /* Store disposal mode for current frame  */
  1006.                                 fn -> fn_GIF89aTransparent = gifdec -> Gif89 . transparent; /* Store currents frame transparent color */
  1007.  
  1008.                                 if( fn -> fn_ChunkyMap )
  1009.                                 {
  1010.                                   /* disposal method */
  1011.                                   switch( fn -> fn_GIF89aDisposal )
  1012.                                   {
  1013.                                     case GIF89A_DISPOSE_NOP:
  1014.                                     {
  1015.                                         /* Background not transparent ? */
  1016.                                         if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
  1017.                                             ((fn -> fn_GIF89aTransparent) != 0U) )
  1018.                                         {
  1019.                                           /* restore to color 0 */
  1020.                                           memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  1021.                                         }
  1022.                                     }
  1023.                                         break;
  1024.  
  1025.                                     case GIF89A_DISPOSE_NODISPOSE:
  1026.                                     {
  1027.                                         /* do not dispose prev image */
  1028.  
  1029.                                         /* If we have a previous frame, copy it  */
  1030.                                         if( prevnode )
  1031.                                         {
  1032.                                           CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  1033. #ifdef DELTAWPA8
  1034.                                           CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  1035.                                           deltamap = prevnode -> fn_ChunkyMap;
  1036. #endif /* DELTAWPA8 */
  1037.                                         }
  1038.                                         else
  1039.                                         {
  1040.                                           /* Background not transparent ? */
  1041.                                           if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
  1042.                                               ((fn -> fn_GIF89aTransparent) != 0U) )
  1043.                                           {
  1044.                                             /* restore to color 0 */
  1045.                                             memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  1046.                                           }
  1047. #ifdef DELTAWPA8
  1048.                                           deltamap = NULL;
  1049. #endif /* DELTAWPA8 */
  1050.                                         }
  1051.                                     }
  1052.                                         break;
  1053.  
  1054.                                     case GIF89A_DISPOSE_RESTOREBACKGROUND:
  1055.                                     {
  1056.                                         /* Background not transparent ? */
  1057.                                         if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
  1058.                                             ((fn -> fn_GIF89aTransparent) != (gaid -> gaid_GIFDec . GifScreen . Background)) )
  1059.                                         {
  1060.                                           /* Restore to background color */
  1061.                                           memset( (fn -> fn_ChunkyMap), (gifdec -> GifScreen . Background), (size_t)(animwidth * animheight) );
  1062.                                         }
  1063.                                     }
  1064.                                         break;
  1065.  
  1066.                                     case GIF89A_DISPOSE_RESTOREPREVIOUS:
  1067.                                     {
  1068.                                         /* restore previous image  */
  1069.  
  1070.                                         /* If we have a previous frame, copy it  */
  1071.                                         if( prevnode )
  1072.                                         {
  1073.                                           CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  1074. #ifdef DELTAWPA8
  1075.                                           CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  1076.                                           deltamap = prevnode -> fn_ChunkyMap;
  1077. #endif /* DELTAWPA8 */
  1078.                                         }
  1079.                                         else
  1080.                                         {
  1081.                                           /* restore to color 0 */
  1082.                                           memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  1083. #ifdef DELTAWPA8
  1084.                                           deltamap = NULL;
  1085. #endif /* DELTAWPA8 */
  1086.                                         }
  1087.                                     }
  1088.                                         break;
  1089.  
  1090.                                     default: /* GIF89A_DISPOSE_RESERVED4 - GIF89A_DISPOSE_RESERVED7 */
  1091.                                     {
  1092.                                         error_printf( cb, gaid, "unsupported disposal method %lu\n", (ULONG)(gifdec -> Gif89 . disposal) );
  1093.                                     }
  1094.                                         break;
  1095.                                   }
  1096.                                 }
  1097.  
  1098.                                 /* Save transparent color (if we have one) */
  1099.                                 if( ((fn -> fn_GIF89aTransparent) != ~0U) && (timestamp != 0UL) )
  1100.                                 {
  1101.                                   savedTransparentColor = localColorMap[ (fn -> fn_GIF89aTransparent) ];
  1102.                                 }
  1103.  
  1104.                                 /* Get colormap */
  1105.                                 if( useGlobalColormap )
  1106.                                 {
  1107.                                   /* use global colormap and depth */
  1108.                                   bitPixel = gifdec -> GifScreen . BitPixel;
  1109.                                   memcpy( localColorMap, (gifdec -> GifScreen . ColorMap), (sizeof( struct ColorRegister ) * bitPixel) );
  1110.                                 }
  1111.                                 else
  1112.                                 {
  1113.                                   numcmaps++;
  1114.  
  1115.                                   if( ReadColorMap( cb, gaid, bitPixel, localColorMap ) )
  1116.                                   {
  1117.                                     error_printf( cb, gaid, "error reading local colormap\n" );
  1118.                                     error = IoErr();
  1119.                                   }
  1120.                                 }
  1121.  
  1122.                                 /* Restore transparent color (if we have one) */
  1123.                                 if( (fn -> fn_GIF89aTransparent) != ~0U )
  1124.                                 {
  1125.                                   localColorMap[ (fn -> fn_GIF89aTransparent) ] = savedTransparentColor;
  1126.                                 }
  1127.  
  1128.                                 if( !(gaid -> gaid_UseChunkyMap) )
  1129.                                 {
  1130.                                   /* The first palette must be moved to the object's palette */
  1131.                                   if( timestamp == 0UL )
  1132.                                   {
  1133.                                     if( !CMAP2Object( cb, o, (UBYTE *)localColorMap, (ULONG)(bitPixel * 3UL) ) )
  1134.                                     {
  1135.                                       /* can't alloc object's color table */
  1136.                                       error = ERROR_NO_FREE_STORE;
  1137.                                     }
  1138.                                   }
  1139.  
  1140.                                   /* Create a palette-per-frame colormap here */
  1141.                                   if( !(fn -> fn_CMap = CMAP2ColorMap( cb, (1UL << (ULONG)(gaid -> gaid_Depth)), (UBYTE *)localColorMap, (ULONG)(bitPixel * 3UL) )) )
  1142.                                   {
  1143.                                     /* can't alloc colormap */
  1144.                                     error = ERROR_NO_FREE_STORE;
  1145.                                   }
  1146.                                 }
  1147.  
  1148.                                 /* Copy colormap for 24 bit output */
  1149.                                 memcpy( (void *)(fn -> fn_ColorMap), (void *)localColorMap, (size_t)(sizeof( struct ColorRegister ) * bitPixel) );
  1150.  
  1151.                                 ReadImage( cb, gaid,
  1152.                                            (fn -> fn_ChunkyMap),
  1153.                                            (UWORD)animwidth,
  1154.                                            LOHI2UINT16( buf[ 0 ], buf[ 1 ] ),
  1155.                                            LOHI2UINT16( buf[ 2 ], buf[ 3 ] ),
  1156.                                            LOHI2UINT16( buf[ 4 ], buf[ 5 ] ),
  1157.                                            LOHI2UINT16( buf[ 6 ], buf[ 7 ] ),
  1158.                                            BitSet( buf[ 8 ], INTERLACE ),
  1159.                                            ((fn -> fn_BitMap) == NULL),
  1160.                                            (fn -> fn_GIF89aTransparent) );
  1161.  
  1162.                                 /* Get size of bitmap (curr_pos - start_of_bm) */
  1163.                                 fn -> fn_BMSize = Seek( fh, 0L, OFFSET_CURRENT ) - (fn -> fn_BMOffset); /* BUG: does not check for failure */
  1164.  
  1165.                                 if( fn -> fn_BitMap )
  1166.                                 {
  1167.                                   if( gaid -> gaid_UseChunkyMap )
  1168.                                   {
  1169.                                     WriteRGBPixelArray8( cb, (fn -> fn_BitMap), animwidth, animheight, (fn -> fn_ColorMap), (fn -> fn_ChunkyMap) );
  1170.                                   }
  1171.                                   else
  1172.                                   {
  1173.                                     WriteDeltaPixelArray8Fast( (fn -> fn_BitMap), (fn -> fn_ChunkyMap), deltamap );
  1174.                                   }
  1175.                                 }
  1176.  
  1177.                                 /* Bump timestamp... */
  1178.                                 if( ((gifdec -> Gif89 . delayTime) != ~0U) &&
  1179.                                     ((gifdec -> Gif89 . delayTime) > 1U)   &&
  1180.                                     ((gifdec -> Gif89 . delayTime) < 2000U) )
  1181.                                 {
  1182.                                   duration = (gifdec -> Gif89 . delayTime);
  1183.                                 }
  1184.                                 else
  1185.                                 {
  1186.                                   duration = 0UL;
  1187.                                 }
  1188.  
  1189.                                 fn -> fn_TimeStamp = timestamp;
  1190.                                 fn -> fn_Frame     = timestamp;
  1191.                                 fn -> fn_Duration  = duration;
  1192.  
  1193.                                 AddTail( (struct List *)(&(gaid -> gaid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
  1194.  
  1195.                                 prevnode = fn;
  1196.  
  1197.                                 /* Next frame starts at timestamp... */
  1198.                                 timestamp += (fn -> fn_Duration) + 1UL;
  1199.                               }
  1200.                             }
  1201.                         }
  1202.                             break;
  1203.  
  1204.                         default: /* Not a valid raster data start character ? */
  1205.                         {
  1206.                             error_printf( cb, gaid, "invalid character 0x%02x, ignoring\n", (int)c );
  1207.                         }
  1208.                             break;
  1209.                       }
  1210.  
  1211.                       /* on error break */
  1212.                       if( error )
  1213.                       {
  1214.                         break;
  1215.                       }
  1216.                     }
  1217.  
  1218. scandone:
  1219.                     /* Any frames ? */
  1220.                     if( timestamp && (error == 0L) && numcmaps )
  1221.                     {
  1222.                       if( numcmaps == 1UL )
  1223.                       {
  1224.                         /* We only have a global colormap and no colormap changes (or a direct RGB bitmap),
  1225.                          * delete first colormap (a colormap in the first frames indicates following colormap
  1226.                          * changes)
  1227.                          */
  1228.                         struct FrameNode *firstnode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1229.  
  1230.                         if( firstnode -> fn_CMap )
  1231.                         {
  1232.                           FreeColorMap( (firstnode -> fn_CMap) );
  1233.                           firstnode -> fn_CMap = NULL;
  1234.                         }
  1235.                       }
  1236.                       else
  1237.                       {
  1238.                         /* All frames must have a colormap, therefore we replicate the colormap
  1239.                          * from the previous colormap if one is missing
  1240.                          */
  1241.                         struct FrameNode *worknode,
  1242.                                          *nextnode;
  1243.                         struct ColorMap  *currcm = NULL;
  1244.  
  1245.                         verbose_printf( cb, gaid, "Animation has palette changes per frame\n" );
  1246.  
  1247.                         worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1248.  
  1249.                         while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1250.                         {
  1251.                           if( worknode -> fn_CMap )
  1252.                           {
  1253.                             /* Current node contains colormap, this are the colors for the following frames... */
  1254.                             currcm = worknode -> fn_CMap;
  1255.                           }
  1256.                           else
  1257.                           {
  1258.                             if( currcm )
  1259.                             {
  1260.                               /* Copy colormap from previous one... */
  1261.                               if( !(worknode -> fn_CMap = CopyColorMap( cb, currcm )) )
  1262.                               {
  1263.                                 /* Can't copy/alloc colormap */
  1264.                                 error = ERROR_NO_FREE_STORE;
  1265.                               }
  1266.                             }
  1267.                             else
  1268.                             {
  1269.                               verbose_printf( cb, gaid, "scan/load: no colormap, can't copy it\n" );
  1270.                             }
  1271.                           }
  1272.  
  1273.                           worknode = nextnode;
  1274.                         }
  1275.                       }
  1276.                     }
  1277.  
  1278.                     /* Check for required information */
  1279.                     if( error == 0L )
  1280.                     {
  1281.                       /* Any frames loaded ? */
  1282.                       if( timestamp == 0UL )
  1283.                       {
  1284.                         /* not enougth frames (at least one required) */
  1285.                         error = DTERROR_NOT_ENOUGH_DATA;
  1286.                       }
  1287.                     }
  1288.  
  1289.                     /* Any error ? */
  1290.                     if( error == 0L )
  1291.                     {
  1292.                       struct FrameNode *firstfn = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head); /* short cut to the first FrameNode */
  1293.  
  1294.                       /* Alloc bitmap as key bitmap */
  1295.                       if( gaid -> gaid_UseChunkyMap )
  1296.                       {
  1297.                         gaid -> gaid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, (BMF_SPECIALFMT | SHIFT_PIXFMT( DIRECTRGB_PIXFMT )), NULL );
  1298.                       }
  1299.                       else
  1300.                       {
  1301.                         gaid -> gaid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, BMF_CLEAR, NULL );
  1302.                       }
  1303.  
  1304.                       if( gaid -> gaid_KeyBitMap )
  1305.                       {
  1306.                         if( (firstfn -> fn_BitMap) == NULL )
  1307.                         {
  1308.                           /* can't alloc first bitmap */
  1309.                           error = ERROR_NO_FREE_STORE;
  1310.                         }
  1311.  
  1312.                         if( error == 0L )
  1313.                         {
  1314.                           /* Copy first frame into key bitmap */
  1315.                           CopyBitMap( cb, (gaid -> gaid_KeyBitMap), (firstfn -> fn_BitMap), animwidth, animheight );
  1316.  
  1317.                           /* No screen mode id set by prefs ? */
  1318.                           if( (gaid -> gaid_ModeID) != (ULONG)INVALID_ID )
  1319.                           {
  1320.                             modeid = gaid -> gaid_ModeID;
  1321.                           }
  1322.                           else
  1323.                           {
  1324.                             if( gaid -> gaid_UseChunkyMap )
  1325.                             {
  1326.                               /* We don't have fixed values for cybergfx mode id's, therefore we have to ask for them */
  1327.                               if( (modeid = BestCModeIDTags( CYBRBIDTG_NominalWidth,  animwidth,
  1328.                                                              CYBRBIDTG_NominalHeight, animheight,
  1329.                                                              CYBRBIDTG_Depth,         animdepth,
  1330.                                                              TAG_DONE )) == INVALID_ID )
  1331.                               {
  1332. #if 0
  1333.                                 error = 1L; /* inducate an error here :-( */
  1334. #else
  1335.                                 /* Workaround for CyberGFX bug :-( */
  1336.                                 if( (modeid = BestCModeIDTags( CYBRBIDTG_NominalWidth,  640UL,
  1337.                                                                CYBRBIDTG_NominalHeight, 480UL,
  1338.                                                                CYBRBIDTG_Depth,         animdepth,
  1339.                                                                TAG_DONE )) == INVALID_ID )
  1340.                                 {
  1341.                                   modeid = 0UL;
  1342.  
  1343.                                   error_printf( cb, gaid, "'CyberGFX bug' workaround failed, too\n" );
  1344.                                 }
  1345. #endif
  1346.  
  1347.                                 error_printf( cb, gaid, "No screenmode available for %lu/%lu/%lu\n", animwidth, animheight, animdepth );
  1348.                               }
  1349.                             }
  1350.                             else
  1351.                             {
  1352.                               /* BUG: Does currently not support SUPERHIRES modes */
  1353.                               if( animwidth >= 640UL )
  1354.                               {
  1355.                                 if( animheight >= 400 )
  1356.                                 {
  1357.                                   modeid = HIRESLACE_KEY;
  1358.                                 }
  1359.                                 else
  1360.                                 {
  1361.                                   modeid = HIRES_KEY;
  1362.                                 }
  1363.                               }
  1364.                               else
  1365.                               {
  1366.                                 if( animheight >= 400 )
  1367.                                 {
  1368.                                   modeid = LORESLACE_KEY;
  1369.                                 }
  1370.                                 else
  1371.                                 {
  1372.                                   modeid = LORES_KEY;
  1373.                                 }
  1374.                               }
  1375.                             }
  1376.                           }
  1377.  
  1378.                           /* No fps set by prefs ? */
  1379.                           if( (gaid -> gaid_FPS) == 0UL )
  1380.                           {
  1381.                             gaid -> gaid_FPS = 100; /* defaults to 100 fps. GIF 89a delay values counts in
  1382.                                                      * 1/100 sec steps. We set the alf_Duration field
  1383.                                                      * to this value (got from the GIF 89a extension).
  1384.                                                      */
  1385.                           }
  1386.  
  1387.                           AttachSample( cb, gaid );
  1388.  
  1389.                           verbose_printf( cb, gaid, "width %lu height %lu depth %lu frames %lu fps %lu\n",
  1390.                                           animwidth,
  1391.                                           animheight,
  1392.                                           animdepth,
  1393.                                           timestamp,
  1394.                                           (gaid -> gaid_FPS) );
  1395.  
  1396.                           /* Set misc attributes */
  1397.                           SetDTAttrs( o, NULL, NULL,
  1398.                                       DTA_ObjName,                                       (gaid -> gaid_ProjectName),
  1399.                                       DTA_TotalHoriz,                                    animwidth,
  1400.                                       DTA_TotalVert,                                     animheight,
  1401.                                       DTA_Repeat,                                        (gaid -> gaid_Repeat),
  1402.                                       ADTA_Width,                                        (gaid -> gaid_Width),
  1403.                                       ADTA_Height,                                       animheight,
  1404.                                       ADTA_Depth,                                        animdepth,
  1405.                                       ADTA_Frames,                                       timestamp,
  1406.                                       ADTA_FramesPerSecond,                              (gaid -> gaid_FPS),
  1407.                                       ADTA_ModeID,                                       modeid,
  1408.                                       ADTA_KeyFrame,                                     (gaid -> gaid_KeyBitMap),
  1409.                                       XTAG( (firstfn -> fn_Sample), ADTA_Sample       ), (firstfn -> fn_Sample),
  1410.                                       XTAG( (firstfn -> fn_Sample), ADTA_SampleLength ), ((firstfn -> fn_SampleLength) / ((firstfn -> fn_Duration) + 1UL)),
  1411.                                       XTAG( (firstfn -> fn_Sample), ADTA_Period       ), (firstfn -> fn_Period),
  1412.                                       XTAG( (firstfn -> fn_Sample), ADTA_Volume       ), (gaid -> gaid_Volume),
  1413.                                       TAG_DONE );
  1414.  
  1415.                           /* All done for now... */
  1416.                           success = TRUE;
  1417.                         }
  1418.                       }
  1419.                       else
  1420.                       {
  1421.                         /* can't alloc key bitmap */
  1422.                         error = ERROR_NO_FREE_STORE;
  1423.                       }
  1424.                     }
  1425.                   }
  1426.                   else
  1427.                   {
  1428.                     error = IoErr();
  1429.                     D( kprintf( "failed to read screen descriptor\n" ) );
  1430.                   }
  1431.                 }
  1432.                 else
  1433.                 {
  1434.                   error = DTERROR_UNKNOWN_COMPRESSION;
  1435.                   D( kprintf( "bad version number, not '87a' or '89a'\n" ) );
  1436.                 }
  1437.               }
  1438.               else
  1439.               {
  1440.                 error = ERROR_OBJECT_WRONG_TYPE;
  1441.                 D( kprintf( "not a GIF file\n" ) );
  1442.               }
  1443.             }
  1444.             else
  1445.             {
  1446.               error = IoErr();
  1447.               D( kprintf( "error reading magic number\n" ) );
  1448.             }
  1449.  
  1450.             /* Prepare decoder for dynamic frame access */
  1451.             gifdec -> file = gaid -> gaid_FH;
  1452.           }
  1453.           else
  1454.           {
  1455.             /* No file handle ? - Be sure we got a DTST_RAM sourcetype */
  1456.             if( sourcetype == DTST_RAM )
  1457.             {
  1458.               /* The object is used without any input file.
  1459.                * This "empty" object is used to run the encoder only...
  1460.                */
  1461.               success = TRUE;
  1462.             }
  1463.             else
  1464.             {
  1465.               /* No handle ! */
  1466.               error = ERROR_REQUIRED_ARG_MISSING;
  1467.             }
  1468.           }
  1469.         }
  1470.       }
  1471.       else
  1472.       {
  1473.         /* can't get required attributes from superclass */
  1474.         error = ERROR_OBJECT_WRONG_TYPE;
  1475.       }
  1476.     }
  1477.     else
  1478.     {
  1479.       /* no memory pool */
  1480.       error = ERROR_NO_FREE_STORE;
  1481.     }
  1482.  
  1483.     SetIoErr( error );
  1484.  
  1485.     return( success );
  1486. }
  1487.  
  1488.  
  1489. static
  1490. struct FrameNode *AllocFrameNode( struct ClassBase *cb, APTR pool )
  1491. {
  1492.     struct FrameNode *fn;
  1493.  
  1494.     if( fn = (struct FrameNode *)AllocPooled( pool, (ULONG)sizeof( struct FrameNode ) ) )
  1495.     {
  1496.       memset( fn, 0, sizeof( struct FrameNode ) );
  1497.     }
  1498.  
  1499.     return( fn );
  1500. }
  1501.  
  1502.  
  1503. static
  1504. struct FrameNode *FindFrameNode( struct MinList *fnl, ULONG timestamp )
  1505. {
  1506.     if( fnl )
  1507.     {
  1508.       struct FrameNode *worknode,
  1509.                        *nextnode,
  1510.                        *prevnode;
  1511.  
  1512.       prevnode = worknode = (struct FrameNode *)(fnl -> mlh_Head);
  1513.  
  1514.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1515.       {
  1516.         if( (worknode -> fn_TimeStamp) > timestamp )
  1517.         {
  1518.           return( prevnode );
  1519.         }
  1520.  
  1521.         prevnode = worknode;
  1522.         worknode = nextnode;
  1523.       }
  1524.  
  1525.       if( !IsListEmpty( ((struct List *)fnl) ) )
  1526.       {
  1527.         return( prevnode );
  1528.       }
  1529.     }
  1530.  
  1531.     return( NULL );
  1532. }
  1533.  
  1534.  
  1535. static
  1536. void FreeFrameNodeResources( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1537. {
  1538.     struct FrameNode *worknode;
  1539.  
  1540. /* The follwoing was used for debugging */
  1541. /* #define FREE_LIST_IN_REVERSE_ORDER 1 */
  1542.  
  1543. #ifdef FREE_LIST_IN_REVERSE_ORDER
  1544.     struct FrameNode *nextnode;
  1545.  
  1546.     worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1547.  
  1548.     while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1549. #else
  1550.     while( worknode = (struct FrameNode *)RemTail( (struct List *)(&(gaid -> gaid_FrameList)) ) )
  1551. #endif /* FREE_LIST_IN_REVERSE_ORDER */
  1552.     {
  1553.       if( worknode -> fn_CMap )
  1554.       {
  1555.         FreeColorMap( (worknode -> fn_CMap) );
  1556.         worknode -> fn_CMap = NULL;
  1557.       }
  1558.  
  1559.       if( worknode -> fn_BitMap )
  1560.       {
  1561.         FreeFrameBitMap( cb, gaid, (worknode -> fn_BitMap) );
  1562.         worknode -> fn_BitMap = NULL;
  1563.       }
  1564.  
  1565. #ifdef FREE_LIST_IN_REVERSE_ORDER
  1566.       worknode = nextnode;
  1567. #endif /* FREE_LIST_IN_REVERSE_ORDER */
  1568.     }
  1569. }
  1570.  
  1571.  
  1572. static
  1573. struct BitMap *AllocFrameBitMap( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1574. {
  1575.     if( gaid -> gaid_UseChunkyMap )
  1576.     {
  1577.       return( AllocBitMap( (ULONG)(gaid -> gaid_PaddedWidth), (ULONG)(gaid -> gaid_Height), (ULONG)(gaid -> gaid_Depth),
  1578.                            (BMF_SPECIALFMT | SHIFT_PIXFMT( DIRECTRGB_PIXFMT )), NULL ) );
  1579.     }
  1580.     else
  1581.     {
  1582.       return( AllocBitMapPooled( cb, (ULONG)(gaid -> gaid_PaddedWidth), (ULONG)(gaid -> gaid_Height), (ULONG)(gaid -> gaid_Depth), (gaid -> gaid_Pool) ) );
  1583.     }
  1584. }
  1585.  
  1586.  
  1587. static
  1588. void FreeFrameBitMap( struct ClassBase *cb, struct GIFAnimInstData *gaid, struct BitMap *bm )
  1589. {
  1590.     if( bm )
  1591.     {
  1592.       if( gaid -> gaid_UseChunkyMap )
  1593.       {
  1594.         FreeBitMap( bm );
  1595.       }
  1596.       else
  1597.       {
  1598.         FreeVecPooled( cb, (gaid -> gaid_Pool), bm );
  1599.       }
  1600.     }
  1601. }
  1602.  
  1603.  
  1604. /* This function assumes (0UL < depth) && (depth <= 8UL) */
  1605. static
  1606. struct BitMap *AllocBitMapPooled( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth, APTR pool )
  1607. {
  1608.     struct BitMap *bm;
  1609.  
  1610.     ULONG          planesize,
  1611.                    size;
  1612.  
  1613.     planesize = (ULONG)RASSIZE( width, height ) + 16UL;
  1614.     size      = ((ULONG)sizeof( struct BitMap )) + (planesize * depth) + width;
  1615.  
  1616.     if( bm = (struct BitMap *)AllocVecPooled( cb, pool, size ) )
  1617.     {
  1618.       UWORD    pl;
  1619.       PLANEPTR plane;
  1620.  
  1621.       InitBitMap( bm, depth, width, height );
  1622.  
  1623.       plane = (PLANEPTR)(bm + 1); /* First plane follows struct BitMap */
  1624.  
  1625.       /* Set up plane data */
  1626.       pl = 0U;
  1627.  
  1628.       /* Set up plane ptrs */
  1629.       while( pl < depth )
  1630.       {
  1631.         bm -> Planes[ pl ] = plane;
  1632.  
  1633.         plane = (PLANEPTR)(((UBYTE *)plane) + planesize + 8);
  1634.         pl++;
  1635.       }
  1636.  
  1637.       /* Clear the remaining plane ptrs */
  1638.       while( pl < 8U )
  1639.       {
  1640.         bm -> Planes[ pl ] = NULL;
  1641.  
  1642.         pl++;
  1643.       }
  1644.     }
  1645.  
  1646.     return( bm );
  1647. }
  1648.  
  1649.  
  1650. void OpenLogfile( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1651. {
  1652.     if( (gaid -> gaid_VerboseOutput) == NULL )
  1653.     {
  1654.       STRPTR confile;
  1655.  
  1656.       if( confile = (STRPTR)AllocVec( (((gaid -> gaid_ProjectName)?(strlen( (gaid -> gaid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  1657.       {
  1658.         mysprintf( cb, confile, "CON:////GIF Anim DataType %s/auto/wait/close/inactive",
  1659.                    ((gaid -> gaid_ProjectName)?(FilePart( (gaid -> gaid_ProjectName) )):(NULL)) );
  1660.  
  1661.         gaid -> gaid_VerboseOutput = Open( confile, MODE_READWRITE );
  1662.  
  1663.         FreeVec( confile );
  1664.       }
  1665.     }
  1666. }
  1667.  
  1668.  
  1669. void error_printf( struct ClassBase *cb, struct GIFAnimInstData *gaid, STRPTR format, ... )
  1670. {
  1671.     OpenLogfile( cb, gaid );
  1672.  
  1673.     if( gaid -> gaid_VerboseOutput )
  1674.     {
  1675.       VFPrintf( (gaid -> gaid_VerboseOutput), format, (APTR)((&format) + 1) );
  1676.     }
  1677. }
  1678.  
  1679.  
  1680. void verbose_printf( struct ClassBase *cb, struct GIFAnimInstData *gaid, STRPTR format, ... )
  1681. {
  1682.     if( gaid -> gaid_VerboseOutput )
  1683.     {
  1684.       VFPrintf( (gaid -> gaid_VerboseOutput), format, (APTR)((&format) + 1) );
  1685.     }
  1686. }
  1687.  
  1688.  
  1689. static
  1690. void AttachSample( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1691. {
  1692.     if( gaid -> gaid_Sample )
  1693.     {
  1694.       struct FrameNode *worknode,
  1695.                        *nextnode;
  1696.  
  1697.       ULONG             period          = gaid -> gaid_Period;
  1698.       ULONG             samplesperframe;
  1699.       BYTE             *sample          = gaid -> gaid_Sample;
  1700.  
  1701.       samplesperframe = (((SysBase -> ex_EClockFrequency) * 10UL) / (period * (gaid -> gaid_FPS) * 2UL));
  1702.  
  1703.       if( gaid -> gaid_SamplesPerFrame )
  1704.       {
  1705.         period = (period * samplesperframe) / (gaid -> gaid_SamplesPerFrame);
  1706.  
  1707.         samplesperframe = gaid -> gaid_SamplesPerFrame;
  1708.  
  1709.         verbose_printf( cb, gaid, "period corrected from %lu to %lu to match spf=%lu with fps=%lu\n",
  1710.                         (gaid -> gaid_Period), period, samplesperframe, (gaid -> gaid_FPS) );
  1711.       }
  1712.  
  1713.       verbose_printf( cb, gaid, "Attching samples (sysclock %lu period %lu fps %lu length %lu samplesperframe %lu)...\n",
  1714.                       (SysBase -> ex_EClockFrequency), period, (gaid -> gaid_FPS), (gaid -> gaid_SampleLength), samplesperframe );
  1715.  
  1716.       worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1717.  
  1718.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1719.       {
  1720.         worknode -> fn_Sample       = sample;
  1721.         worknode -> fn_SampleLength = samplesperframe * ((worknode -> fn_Duration) + 1UL);
  1722.         worknode -> fn_Period       = period;
  1723.  
  1724.         sample += worknode -> fn_SampleLength;
  1725.  
  1726.         /* End of sample reached ? */
  1727.         if( (ULONG)(sample - (gaid -> gaid_Sample)) > (gaid -> gaid_SampleLength) )
  1728.         {
  1729.           /* Cut last size of sample to fit */
  1730.           worknode -> fn_SampleLength -= (ULONG)(sample - (gaid -> gaid_Sample));
  1731.  
  1732.           break;
  1733.         }
  1734.  
  1735.         worknode = nextnode;
  1736.       }
  1737.     }
  1738. }
  1739.  
  1740.  
  1741. static
  1742. BOOL ReadColorMap( struct ClassBase *cb, struct GIFAnimInstData *gaid, UWORD numcolors, struct ColorRegister *color )
  1743. {
  1744.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  1745.  
  1746.     return( (BOOL)(!ReadOK( cb, gifdec, color, (ULONG)(sizeof( struct ColorRegister ) * numcolors) )) );
  1747. }
  1748.  
  1749.  
  1750. static
  1751. void DoExtension( struct ClassBase *cb, Object *o, struct GIFAnimInstData *gaid, TEXT label )
  1752. {
  1753.     struct GIFDecoder *gifdec     = (&(gaid -> gaid_GIFDec));
  1754.     UBYTE              buf[ 256 ] = { 0 };
  1755.     STRPTR             str;
  1756.  
  1757.     switch( label )
  1758.     {
  1759.       case 0x01:              /* Plain Text Extension */
  1760.       {
  1761.           UWORD lpos,
  1762.                 tpos,
  1763.                 width,
  1764.                 height,
  1765.                 cellw,
  1766.                 cellh,
  1767.                 foreground,
  1768.                 background;
  1769.  
  1770.           error_printf( cb, gaid, "'Plain text extension' not supported yet. Please send this animation to the author that"
  1771.                                   "this can be implemented\n" );
  1772.  
  1773.           (void)GetDataBlock( cb, gaid, buf );
  1774.  
  1775.           lpos       = LOHI2UINT16( buf[ 0 ], buf[ 1 ] );
  1776.           tpos       = LOHI2UINT16( buf[ 2 ], buf[ 3 ] );
  1777.           width      = LOHI2UINT16( buf[ 4 ], buf[ 5 ] );
  1778.           height     = LOHI2UINT16( buf[ 6 ], buf[ 7 ] );
  1779.           cellw      = buf[ 8 ];
  1780.           cellh      = buf[ 9 ];
  1781.           foreground = buf[ 10 ];
  1782.           background = buf[ 11 ];
  1783.  
  1784.           verbose_printf( cb, gaid, "Plain text: "
  1785.                                     "left %lu top %lu width %lu height %lu "
  1786.                                     "cell width %lu cell height %lu"
  1787.                                     "foreground %lu background %lu", lpos, tpos, width, height, cellw, cellh, foreground, background );
  1788.  
  1789.           while( GetDataBlock( cb, gaid, buf ) != 0 )
  1790.           {
  1791. #if 0
  1792.             PPM_ASSIGN( image[ ypos ][ xpos ], cmap[ CM_RED ][ v ], cmap[ CM_GREEN ][ v ], cmap[ CM_BLUE ][ v ] );
  1793.  
  1794.             index++;
  1795. #endif
  1796.  
  1797.             /* Clear buffer for next cycle */
  1798.             memset( (void *)buf, 0, sizeof( buf ) );
  1799.           }
  1800.  
  1801.           return;
  1802.       }
  1803.  
  1804.       case 0xf9:              /* Graphic Control Extension */
  1805.       {
  1806.           STRPTR fmt; /* Format string for verbose output (fmt changes if transparent color is set) */
  1807.  
  1808.           (void)GetDataBlock( cb, gaid, buf );
  1809.  
  1810.           /* Get "delta" mode (disposal of previous frame), input flag and the delay time in 1/100 sec) */
  1811.           gifdec -> Gif89 . disposal    = (buf[ 0 ] >> 2) & 0x7;
  1812.           gifdec -> Gif89 . inputFlag   = (buf[ 0 ] >> 1) & 0x1;
  1813.           gifdec -> Gif89 . delayTime   = LOHI2UINT16( buf[ 1 ], buf[ 2 ] );
  1814.  
  1815.           /* Any transparent color ? */
  1816.           if( buf[ 0 ] & 0x01 )
  1817.           {
  1818.             gifdec -> Gif89 . transparent = buf[ 3 ];
  1819.  
  1820.             fmt = "Graphic Control Extension: disposal %s (%lu)%s transparent %lu\n";
  1821.           }
  1822.           else
  1823.           {
  1824.             fmt = "Graphic Control Extension: disposal %s (%lu)%s\n";
  1825.           }
  1826.  
  1827.           /* Verbose output ? */
  1828.           if( gaid -> gaid_VerboseOutput )
  1829.           {
  1830.             STRPTR user_input = ((gifdec -> Gif89 . inputFlag)?(" user input requested"):(""));
  1831.             STRPTR disposal;
  1832.  
  1833.             switch( gifdec -> Gif89 . disposal )
  1834.             {
  1835.               case GIF89A_DISPOSE_NOP:                  disposal = "nop";                break;
  1836.               case GIF89A_DISPOSE_NODISPOSE:            disposal = "no dispose";         break;
  1837.               case GIF89A_DISPOSE_RESTOREBACKGROUND:    disposal = "restore background"; break;
  1838.               case GIF89A_DISPOSE_RESTOREPREVIOUS:      disposal = "restore previous";   break;
  1839.               default:                                  disposal = "reserved";           break;
  1840.             }
  1841.  
  1842.             verbose_printf( cb, gaid, fmt,
  1843.                                       disposal,
  1844.                                       (ULONG)(gifdec -> Gif89 . disposal),
  1845.                                       user_input,
  1846.                                       (gifdec -> Gif89 . transparent) );
  1847.           }
  1848.  
  1849.           /* Ignore remaining data... */
  1850.           while( GetDataBlock( cb, gaid, (UBYTE *)buf ) != 0 )
  1851.                   ;
  1852.  
  1853.           return;
  1854.       }
  1855.  
  1856.       case 0xfe:              /* Comment Extension */
  1857.       {
  1858.           STRPTR annotation;
  1859.  
  1860.           /* Get all comment extension chunks, and append them on the DTA_ObjAnnotation string we've created before */
  1861.           while( GetDataBlock( cb, gaid, buf ) != 0 )
  1862.           {
  1863.             ULONG  size;
  1864.             STRPTR oldannotation;
  1865.  
  1866.             buf[ 255 ] = '\0'; /* terminate explicitly */
  1867.  
  1868.             size = (ULONG)strlen( buf ) + 2UL;
  1869.  
  1870.             (void)GetDTAttrs( o, DTA_ObjAnnotation, (&oldannotation), TAG_DONE );
  1871.  
  1872.             if( oldannotation )
  1873.             {
  1874.               size += (ULONG)strlen( oldannotation ) + 2UL;
  1875.             }
  1876.  
  1877.             /* Allocate a temp buffer */
  1878.             if( annotation = (STRPTR)AllocMem( size, MEMF_ANY ) )
  1879.             {
  1880.               if( oldannotation )
  1881.               {
  1882.                 strcpy( annotation, oldannotation );
  1883.               }
  1884.               else
  1885.               {
  1886.                 annotation[ 0 ] = '\0'; /* terminate */
  1887.               }
  1888.  
  1889.               /* Append the new buffer */
  1890.               IBMPC2ISOLatin1( buf, (annotation + strlen( annotation )) );
  1891.  
  1892.               /* Store the comment */
  1893.               SetDTAttrs( o, NULL, NULL, DTA_ObjAnnotation, annotation, TAG_DONE );
  1894.  
  1895.               /* Free temp string */
  1896.               FreeMem( annotation, size );
  1897.             }
  1898.  
  1899.             /* Clear buffer for next cycle */
  1900.             memset( (void *)buf, 0, sizeof( buf ) );
  1901.           }
  1902.  
  1903.           /* After all, prompt the annotation to the user */
  1904.           (void)GetDTAttrs( o, DTA_ObjAnnotation, (&annotation), TAG_DONE );
  1905.  
  1906.           verbose_printf( cb, gaid, "Comment Extension: '%s'\n", annotation );
  1907.  
  1908.           return;
  1909.       }
  1910.  
  1911.       case 0xff:              /* Application Extension */
  1912.       {
  1913.           str = "Application Extension";
  1914.       }
  1915.           break;
  1916.  
  1917.       default:
  1918.       {
  1919.           mysprintf( cb, buf, "UNKNOWN (0x%02lx)", (long)label );
  1920.           str = buf;
  1921.       }
  1922.           break;
  1923.     }
  1924.  
  1925.     verbose_printf( cb, gaid, "got a '%s' extension\n", ((str)?(str):"") );
  1926.  
  1927.     /* skip extension data */
  1928.     while( GetDataBlock( cb, gaid, buf ) != 0 )
  1929.       ;
  1930.  
  1931.     return;
  1932. }
  1933.  
  1934.  
  1935. static
  1936. int GetDataBlock( struct ClassBase *cb, struct GIFAnimInstData *gaid, UBYTE *buf )
  1937. {
  1938.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  1939.     UBYTE              count;
  1940.  
  1941.     if( !ReadOK( cb, gifdec, &count, 1 ) )
  1942.     {
  1943.       error_printf( cb, gaid, "error in getting DataBlock size\n" );
  1944.  
  1945.       return( -1 );
  1946.     }
  1947.  
  1948.     gifdec -> ZeroDataBlock = (count == 0);
  1949.  
  1950.     if( (count != 0) && (!ReadOK( cb, gifdec, buf, (ULONG)count ) ) )
  1951.     {
  1952.       error_printf( cb, gaid, "error in reading DataBlock\n" );
  1953.  
  1954.       return( -1 );
  1955.     }
  1956.  
  1957.     return( count );
  1958. }
  1959.  
  1960.  
  1961. static
  1962. int GetCode( struct ClassBase *cb, struct GIFAnimInstData *gaid, int code_size, BOOL flag )
  1963. {
  1964.     int                i,
  1965.                        j,
  1966.                        ret;
  1967.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  1968.     UBYTE              count;
  1969.  
  1970.     if( flag )
  1971.     {
  1972.       gifdec -> GetCode . curbit  = 0;
  1973.       gifdec -> GetCode . lastbit = 0;
  1974.       gifdec -> GetCode . done    = FALSE;
  1975.  
  1976.       return( 0 );
  1977.     }
  1978.  
  1979.     if( (gifdec -> GetCode . curbit + code_size) >= gifdec -> GetCode . lastbit )
  1980.     {
  1981.       if( gifdec -> GetCode . done )
  1982.       {
  1983.         if( gifdec -> GetCode . curbit >= gifdec -> GetCode . lastbit )
  1984.           D( kprintf( "ran off the end of my bits\n" ) );
  1985.  
  1986.         return( -1 );
  1987.       }
  1988.  
  1989.       gifdec -> GetCode . buf[ 0 ] = gifdec -> GetCode . buf[ gifdec -> GetCode . last_byte - 2 ];
  1990.       gifdec -> GetCode . buf[ 1 ] = gifdec -> GetCode . buf[ gifdec -> GetCode . last_byte - 1 ];
  1991.  
  1992.       if( (count = GetDataBlock( cb, gaid, &gifdec -> GetCode . buf[ 2 ] ) ) == 0 )
  1993.         gifdec -> GetCode . done = TRUE;
  1994.  
  1995.       gifdec -> GetCode . last_byte = 2 + count;
  1996.       gifdec -> GetCode . curbit    = (gifdec -> GetCode . curbit - gifdec -> GetCode . lastbit) + 16;
  1997.       gifdec -> GetCode . lastbit   = (2 + count) * 8 ;
  1998.     }
  1999.  
  2000.     ret = 0;
  2001.  
  2002.     for( i = gifdec -> GetCode . curbit, j = 0; j < code_size ; i++, j++ )
  2003.       ret |= ((gifdec -> GetCode . buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  2004.  
  2005.     gifdec -> GetCode . curbit += code_size;
  2006.  
  2007.     return( ret );
  2008. }
  2009.  
  2010.  
  2011. static
  2012. int LWZReadByte( struct ClassBase *cb, struct GIFAnimInstData *gaid, BOOL flag, int input_code_size )
  2013. {
  2014.              int                code,
  2015.                                 incode;
  2016.     register int                i;
  2017.              struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  2018.  
  2019.     if( flag )
  2020.     {
  2021.       gifdec -> LWZReadByte . set_code_size = input_code_size;
  2022.       gifdec -> LWZReadByte . code_size     = gifdec -> LWZReadByte . set_code_size + 1;
  2023.       gifdec -> LWZReadByte . clear_code    = 1 << gifdec -> LWZReadByte . set_code_size ;
  2024.       gifdec -> LWZReadByte . end_code      = gifdec -> LWZReadByte . clear_code + 1;
  2025.       gifdec -> LWZReadByte . max_code_size = 2 * gifdec -> LWZReadByte . clear_code;
  2026.       gifdec -> LWZReadByte . max_code      = gifdec -> LWZReadByte . clear_code + 2;
  2027.  
  2028.       GetCode( cb, gaid, 0, TRUE );
  2029.  
  2030.       gifdec -> LWZReadByte . fresh = TRUE;
  2031.  
  2032.       /* Fill table with the codes... */
  2033.       for( i = 0 ; i < (gifdec -> LWZReadByte . clear_code) ; i++ )
  2034.       {
  2035.         gifdec -> LWZReadByte . table[ 0 ][ i ] = 0;
  2036.         gifdec -> LWZReadByte . table[ 1 ][ i ] = i;
  2037.       }
  2038.  
  2039.       /* ... and clear the remaining part  */
  2040.       for( ; i < (1 << MAX_LWZ_BITS) ; i++ )
  2041.       {
  2042.         gifdec -> LWZReadByte . table[ 0 ][ i ] =
  2043.           gifdec -> LWZReadByte . table[ 1 ][ 0 ] = 0;
  2044.       }
  2045.  
  2046.       /* Reset stack ptr */
  2047.       gifdec -> LWZReadByte . sp = gifdec -> LWZReadByte . stack;
  2048.  
  2049.       return( 0 );
  2050.     }
  2051.     else
  2052.     {
  2053.       if( gifdec -> LWZReadByte . fresh )
  2054.       {
  2055.         gifdec -> LWZReadByte . fresh = FALSE;
  2056.  
  2057.         do
  2058.         {
  2059.           gifdec -> LWZReadByte . firstcode = gifdec -> LWZReadByte . oldcode = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE );
  2060.         } while( gifdec -> LWZReadByte . firstcode == gifdec -> LWZReadByte . clear_code );
  2061.  
  2062.         return( gifdec -> LWZReadByte . firstcode );
  2063.       }
  2064.     }
  2065.  
  2066.     if( gifdec -> LWZReadByte . sp > gifdec -> LWZReadByte . stack )
  2067.     {
  2068.       return( *--gifdec -> LWZReadByte . sp );
  2069.     }
  2070.  
  2071.     while( (code = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE )) >= 0 )
  2072.     {
  2073.       if( code == gifdec -> LWZReadByte . clear_code )
  2074.       {
  2075.         for( i = 0 ; i < gifdec -> LWZReadByte . clear_code ; i++ )
  2076.         {
  2077.           gifdec -> LWZReadByte . table[ 0 ][ i ] = 0;
  2078.           gifdec -> LWZReadByte . table[ 1 ][ i ] = i;
  2079.         }
  2080.  
  2081.         for( ; i < (1 << MAX_LWZ_BITS) ; i++ )
  2082.         {
  2083.           gifdec -> LWZReadByte . table[ 0 ][ i ] =
  2084.             gifdec -> LWZReadByte . table[ 1 ][ i ] = 0;
  2085.         }
  2086.  
  2087.         gifdec -> LWZReadByte . code_size       = gifdec -> LWZReadByte . set_code_size + 1;
  2088.         gifdec -> LWZReadByte . max_code_size   = 2 * gifdec -> LWZReadByte . clear_code;
  2089.         gifdec -> LWZReadByte . max_code        = gifdec -> LWZReadByte . clear_code + 2;
  2090.         gifdec -> LWZReadByte . sp              = gifdec -> LWZReadByte . stack;
  2091.         gifdec -> LWZReadByte . firstcode       =
  2092.           gifdec -> LWZReadByte . oldcode       = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE );
  2093.  
  2094.         return( gifdec -> LWZReadByte . firstcode );
  2095.       }
  2096.       else
  2097.       {
  2098.         if( code == gifdec -> LWZReadByte . end_code )
  2099.         {
  2100.           int   count;
  2101.           UBYTE buf[ 260 ];
  2102.  
  2103.           if( gifdec -> ZeroDataBlock )
  2104.             return( -2 );
  2105.  
  2106.           while( (count = GetDataBlock( cb, gaid, buf )) > 0 )
  2107.             ;
  2108.  
  2109.           if( count != 0 )
  2110.             error_printf( cb, gaid, "missing EOD in data stream (common occurence)\n" );
  2111.  
  2112.           return( -2 );
  2113.         }
  2114.       }
  2115.  
  2116.       incode = code;
  2117.  
  2118.       if( code >= gifdec -> LWZReadByte . max_code )
  2119.       {
  2120.         *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . firstcode;
  2121.         code = gifdec -> LWZReadByte . oldcode;
  2122.       }
  2123.  
  2124.       while( code >= gifdec -> LWZReadByte . clear_code )
  2125.       {
  2126.         *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . table[ 1 ][ code ];
  2127.  
  2128.         if( code == gifdec -> LWZReadByte . table[ 0 ][ code ] )
  2129.           D( kprintf( "circular table entry BIG ERROR\n" ) );
  2130.  
  2131.         code = gifdec -> LWZReadByte . table[ 0 ][ code ];
  2132.       }
  2133.  
  2134.       *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . firstcode = gifdec -> LWZReadByte . table[ 1 ][ code ];
  2135.  
  2136.       if( (code = gifdec -> LWZReadByte . max_code) < (1 << MAX_LWZ_BITS ) )
  2137.       {
  2138.         gifdec -> LWZReadByte . table[ 0 ][ code ] = gifdec -> LWZReadByte . oldcode;
  2139.         gifdec -> LWZReadByte . table[ 1 ][ code ] = gifdec -> LWZReadByte . firstcode;
  2140.         gifdec -> LWZReadByte . max_code++;
  2141.  
  2142.         if( (gifdec -> LWZReadByte . max_code >= gifdec -> LWZReadByte . max_code_size) && (gifdec -> LWZReadByte . max_code_size < (1 << MAX_LWZ_BITS)) )
  2143.         {
  2144.           gifdec -> LWZReadByte . max_code_size *= 2;
  2145.           gifdec -> LWZReadByte . code_size++;
  2146.         }
  2147.       }
  2148.  
  2149.       gifdec -> LWZReadByte . oldcode = incode;
  2150.  
  2151.       if( gifdec -> LWZReadByte . sp > gifdec -> LWZReadByte . stack )
  2152.       {
  2153.         return( *--gifdec -> LWZReadByte . sp );
  2154.       }
  2155.     }
  2156.  
  2157.     return( code );
  2158. }
  2159.  
  2160.  
  2161. static
  2162. void ReadImage( struct ClassBase *cb, struct GIFAnimInstData *gaid, UBYTE *image,
  2163.                 UWORD imagewidth, UWORD left, UWORD top, UWORD len, UWORD height,
  2164.                 BOOL interlace, BOOL ignore, UWORD transparent )
  2165. {
  2166.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  2167.     UBYTE              c;
  2168.  
  2169.     /* Initialize the Compression routines */
  2170.     if( !ReadOK( cb, gifdec, &c, 1 ) )
  2171.       D( kprintf( "EOF / read error on image data\n" ) );
  2172.  
  2173.     /* If this is an "uninteresting picture" ignore it. */
  2174.     if( ignore )
  2175.     {
  2176.       D( kprintf( cb, gaid, "skipping gif image...\n" ) );
  2177.  
  2178.       /* Loop until end of raster data */
  2179.       for( ;; )
  2180.       {
  2181.         if( !ReadOK( cb, gifdec, &c, 1 ) )
  2182.           D( kprintf( "EOF / reading block byte count\n" ) );
  2183.  
  2184.         if( c == 0 )
  2185.         {
  2186.           D( kprintf( cb, gaid, "gif image done\n" ) );
  2187.           break;
  2188.         }
  2189.  
  2190.         /* Skip... */
  2191.         (void)Seek( (gifdec -> file), (long)c, OFFSET_CURRENT );
  2192.       }
  2193.     }
  2194.     else
  2195.     {
  2196.        WORD v;
  2197.       ULONG xpos    = 0UL,
  2198.             ypos    = 0UL,
  2199.             offset  = (top * imagewidth) + left,
  2200.             pass    = 0UL;
  2201.  
  2202.       if( LWZReadByte( cb, gaid, TRUE, c ) < 0 )
  2203.         D( kprintf( "error reading image\n" ) );
  2204.  
  2205.       D( kprintf( cb, gaid, "reading %lx %ld.%ld / %ld by %ld%s GIF image\n", image, left, top, len, height, interlace ? " interlaced" : "" ) );
  2206.  
  2207.       while( (v = LWZReadByte( cb, gaid, FALSE, c )) >= 0 )
  2208.       {
  2209.         /* Pixel transparent ? */
  2210.         if( (transparent == ~0U) ||
  2211.             (transparent != v) )
  2212.         {
  2213.           /* Store pixel */
  2214.           image[ offset + xpos ] = v;
  2215.         }
  2216.  
  2217.         xpos++;
  2218.  
  2219.         if( xpos == len )
  2220.         {
  2221.           xpos = 0UL;
  2222.  
  2223.           if( interlace )
  2224.           {
  2225.             switch( pass )
  2226.             {
  2227.               case 0UL:
  2228.               case 1UL: ypos += 8UL; break;
  2229.               case 2UL: ypos += 4UL; break;
  2230.               case 3UL: ypos += 2UL; break;
  2231.             }
  2232.  
  2233.             if( ypos >= height )
  2234.             {
  2235.               pass++;
  2236.  
  2237.               switch( pass )
  2238.               {
  2239.                 case 1UL: ypos = 4UL;  break;
  2240.                 case 2UL: ypos = 2UL;  break;
  2241.                 case 3UL: ypos = 1UL;  break;
  2242.                 default: goto fini;
  2243.               }
  2244.             }
  2245.           }
  2246.           else
  2247.           {
  2248.             ypos++;
  2249.           }
  2250.  
  2251.           offset = ((ypos + top) * imagewidth) + left;
  2252.         }
  2253.  
  2254.         if( ypos >= height )
  2255.           break;
  2256.       }
  2257.  
  2258. fini:
  2259.       if( LWZReadByte( cb, gaid, FALSE, c ) >= 0 )
  2260.       {
  2261.         verbose_printf( cb, gaid, "too much input data, ignoring extra...\n" );
  2262.       }
  2263.     }
  2264. }
  2265.  
  2266.  
  2267. /* got from my anim.datatype */
  2268. static
  2269. struct FrameNode *GetPrevFrameNode( struct FrameNode *currfn, ULONG interleave )
  2270. {
  2271.     struct FrameNode *worknode,
  2272.                      *prevnode;
  2273.  
  2274.     /* Get previous frame */
  2275.     worknode = currfn;
  2276.  
  2277.     while( prevnode = (struct FrameNode *)(worknode -> fn_Node . mln_Pred) )
  2278.     {
  2279.       if( (interleave-- == 0U) || ((prevnode -> fn_Node . mln_Pred) == NULL) )
  2280.       {
  2281.         break;
  2282.       }
  2283.  
  2284.       worknode = prevnode;
  2285.     }
  2286.  
  2287.     return( worknode );
  2288. }
  2289.  
  2290.  
  2291. /* WritePixelArray8 replacement by Peter McGavin (p.mcgavin@irl.cri.nz),
  2292.  * slightly adapted to fit here...
  2293.  */
  2294.  
  2295. static
  2296. void WriteDeltaPixelArray8Fast( struct BitMap *dest, UBYTE *source, UBYTE *prev )
  2297. {
  2298.              ULONG *plane[ 8 ] = { 0 };
  2299.     register ULONG *chunky     = (ULONG *)source, /* fetch 32 bits per cycle */
  2300.                    *prevchunky = (ULONG *)prev;
  2301.              ULONG  numcycles  = ((dest -> Rows) * (dest -> BytesPerRow)) / sizeof( ULONG ),
  2302.                     i;
  2303.  
  2304.     /* Copy plane ptrs */
  2305.     for( i = 0UL ; i < (dest -> Depth) ; i++ )
  2306.     {
  2307.       plane[ i ] = (ULONG *)(dest -> Planes[ i ]);
  2308.     }
  2309.  
  2310.     /* Fill unused planes with plane 0, which will be written last, all previous accesses
  2311.      * will be droped (assumes that a cache hides this "dummy" writes)
  2312.      */
  2313.     for( i ; i < 8UL ; i++ )
  2314.     {
  2315.       plane[ i ] = (ULONG *)(dest -> Planes[ 0 ]);
  2316.     }
  2317.  
  2318. #define merge( a, b, mask, shift ) \
  2319.       tmp = mask & (a ^ (b >> shift));   \
  2320.       a ^= tmp;                          \
  2321.       b ^= (tmp << shift)
  2322.  
  2323.     /* Check if we have to do the "delta" test */
  2324.     if( prevchunky )
  2325.     {
  2326.       /* Process bitmaps */
  2327.       for( i = 0UL ; i < numcycles ; i++ )
  2328.       {
  2329.         register ULONG b0, b1, b2, b3, b4, b5, b6, b7,
  2330.                        tmp;
  2331.  
  2332.         /* process 32 pixels */
  2333.         b0 = *chunky++;  b4 = *chunky++;
  2334.         b1 = *chunky++;  b5 = *chunky++;
  2335.         b2 = *chunky++;  b6 = *chunky++;
  2336.         b3 = *chunky++;  b7 = *chunky++;
  2337.  
  2338.         /* I use the '+' here to avoid that the compiler skips an expression.
  2339.          * WARNING: The code assumes that the code is executed in the sequence as it occurs here
  2340.          */
  2341.         if( (b0 != *prevchunky++) + (b4 != *prevchunky++) +
  2342.             (b1 != *prevchunky++) + (b5 != *prevchunky++) +
  2343.             (b2 != *prevchunky++) + (b6 != *prevchunky++) +
  2344.             (b3 != *prevchunky++) + (b7 != *prevchunky++) )
  2345.         {
  2346.           merge( b0, b2, 0x0000ffff, 16 );
  2347.           merge( b1, b3, 0x0000ffff, 16 );
  2348.           merge( b4, b6, 0x0000ffff, 16 );
  2349.           merge( b5, b7, 0x0000ffff, 16 );
  2350.  
  2351.           merge( b0, b1, 0x00ff00ff,  8 );
  2352.           merge( b2, b3, 0x00ff00ff,  8 );
  2353.           merge( b4, b5, 0x00ff00ff,  8 );
  2354.           merge( b6, b7, 0x00ff00ff,  8 );
  2355.  
  2356.           merge( b0, b4, 0x0f0f0f0f,  4 );
  2357.           merge( b1, b5, 0x0f0f0f0f,  4 );
  2358.           merge( b2, b6, 0x0f0f0f0f,  4 );
  2359.           merge( b3, b7, 0x0f0f0f0f,  4 );
  2360.  
  2361.           merge( b0, b2, 0x33333333,  2 );
  2362.           merge( b1, b3, 0x33333333,  2 );
  2363.           merge( b4, b6, 0x33333333,  2 );
  2364.           merge( b5, b7, 0x33333333,  2 );
  2365.  
  2366.           merge( b0, b1, 0x55555555,  1 );
  2367.           merge( b2, b3, 0x55555555,  1 );
  2368.           merge( b4, b5, 0x55555555,  1 );
  2369.           merge( b6, b7, 0x55555555,  1 );
  2370.  
  2371.           *plane[ 7 ]++ = b0;
  2372.           *plane[ 6 ]++ = b1;
  2373.           *plane[ 5 ]++ = b2;
  2374.           *plane[ 4 ]++ = b3;
  2375.           *plane[ 3 ]++ = b4;
  2376.           *plane[ 2 ]++ = b5;
  2377.           *plane[ 1 ]++ = b6;
  2378.           *plane[ 0 ]++ = b7;
  2379.         }
  2380.         else
  2381.         {
  2382.           plane[ 7 ]++;
  2383.           plane[ 6 ]++;
  2384.           plane[ 5 ]++;
  2385.           plane[ 4 ]++;
  2386.           plane[ 3 ]++;
  2387.           plane[ 2 ]++;
  2388.           plane[ 1 ]++;
  2389.           plane[ 0 ]++;
  2390.         }
  2391.       }
  2392.     }
  2393.     else
  2394.     {
  2395.       /* Process bitmaps */
  2396.       for( i = 0UL ; i < numcycles ; i++ )
  2397.       {
  2398.         register ULONG b0, b1, b2, b3, b4, b5, b6, b7,
  2399.                        tmp;
  2400.  
  2401.         /* process 32 pixels */
  2402.         b0 = *chunky++;  b4 = *chunky++;
  2403.         b1 = *chunky++;  b5 = *chunky++;
  2404.         b2 = *chunky++;  b6 = *chunky++;
  2405.         b3 = *chunky++;  b7 = *chunky++;
  2406.  
  2407.         merge( b0, b2, 0x0000ffff, 16 );
  2408.         merge( b1, b3, 0x0000ffff, 16 );
  2409.         merge( b4, b6, 0x0000ffff, 16 );
  2410.         merge( b5, b7, 0x0000ffff, 16 );
  2411.  
  2412.         merge( b0, b1, 0x00ff00ff,  8 );
  2413.         merge( b2, b3, 0x00ff00ff,  8 );
  2414.         merge( b4, b5, 0x00ff00ff,  8 );
  2415.         merge( b6, b7, 0x00ff00ff,  8 );
  2416.  
  2417.         merge( b0, b4, 0x0f0f0f0f,  4 );
  2418.         merge( b1, b5, 0x0f0f0f0f,  4 );
  2419.         merge( b2, b6, 0x0f0f0f0f,  4 );
  2420.         merge( b3, b7, 0x0f0f0f0f,  4 );
  2421.  
  2422.         merge( b0, b2, 0x33333333,  2 );
  2423.         merge( b1, b3, 0x33333333,  2 );
  2424.         merge( b4, b6, 0x33333333,  2 );
  2425.         merge( b5, b7, 0x33333333,  2 );
  2426.  
  2427.         merge( b0, b1, 0x55555555,  1 );
  2428.         merge( b2, b3, 0x55555555,  1 );
  2429.         merge( b4, b5, 0x55555555,  1 );
  2430.         merge( b6, b7, 0x55555555,  1 );
  2431.  
  2432.         *plane[ 7 ]++ = b0;
  2433.         *plane[ 6 ]++ = b1;
  2434.         *plane[ 5 ]++ = b2;
  2435.         *plane[ 4 ]++ = b3;
  2436.         *plane[ 3 ]++ = b4;
  2437.         *plane[ 2 ]++ = b5;
  2438.         *plane[ 1 ]++ = b6;
  2439.         *plane[ 0 ]++ = b7;
  2440.       }
  2441.     }
  2442. }
  2443.  
  2444.  
  2445. static
  2446. int getbase2( int x )
  2447. {
  2448.     int i = 0,
  2449.         j = 1;
  2450.  
  2451.     while( x > j )
  2452.     {
  2453.       j *= 2;
  2454.       i++;
  2455.     }
  2456.  
  2457.     return( i );
  2458. }
  2459.  
  2460.  
  2461.  
  2462.  
  2463. /* Read and test */
  2464. static
  2465. BOOL ReadOK( struct ClassBase *cb, struct GIFDecoder *gifdec, void *buffer, ULONG len )
  2466. {
  2467.     if( (gifdec -> which_fh) == WHICHFH_FILE )
  2468.     {
  2469.       return( (BOOL)(Read( (gifdec -> file), buffer, len ) == len) );
  2470.     }
  2471.     else
  2472.     {
  2473.       /* Check if the request fit in out buffer... */
  2474.       if( (((gifdec -> buffer) - (gifdec -> file_buffer)) + len) <= (gifdec -> buffersize) )
  2475.       {
  2476.         CopyMem( (gifdec -> buffer), buffer, len );
  2477.         gifdec -> buffer += len;
  2478.  
  2479.         return( TRUE );
  2480.       }
  2481.     }
  2482.  
  2483.     return( FALSE );
  2484. }
  2485.  
  2486.  
  2487.  
  2488.  
  2489.  
  2490.  
  2491.