home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 2 / MECOMP-CD-II.iso / amiga / datatypes / gifanim_datatype / dispatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-05-24  |  92.0 KB  |  2,532 lines

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