
/*****************************************************************************/
/****  File sorgente gifparse.c                               	          ****/
/****  di Alberto Geneletti	version 1.0	giugno 1993               ****/
/****                                                                     ****/
/****  Constructor e Desctructor della classe GIFImage.                   ****/
/****  Permette di clonare un'oggetto PseudoColorImage per la codifica,   ****/
/****  di specificare un testo da aggiungere come CommentExtension, di    ****/
/****  settare la modalita' Interlace.                                    ****/
/****  Nel caso non sia specificata alcuna PseudoColorImage, viene effet- ****/
/****  tuata l'inizializzazione necessaria alla decodifica.               ****/
/****  In ogni caso viene sempre allocato il minimo indispensabile; si    ****/
/****  tiene inoltre traccia di quello che e' stato allocato in modo au-  ****/
/****  tomatico, in modo da non rischiare il crash liberando qualcosa che ****/
/****  sia stata passata sullo stack.                                     ****/
/*****************************************************************************/

#include <stdio.h>
#include <string.h>
#include "gif.h"


int OpenGIF(char *FileName, GIFImage *GIFIm)
{
	if(GIFIm->Status & FILE_OPEN) {
		CloseGIF(GIFIm);
   	}

   	if(!(GIFIm->FD = fopen(FileName,"rb"))) {
		return(FILE_NOT_FOUND);
	}

   	GIFIm->Status |= FILE_OPEN;

	/**** verifico la Signature ******************************************/

   	if(fread(GIFIm->Signature,1,6, GIFIm->FD) != 6) {
		CloseGIF(GIFIm);
		return(NOT_A_GIF_FILE);
   	}

   	if(memcmp((char *)GIFIm->Signature,"GIF",3)){
		CloseGIF(GIFIm);
		return(NOT_A_GIF_FILE);
   	}

	/**** Alloco e leggo lo Screen Descriptor ****************************/

   	if(!GIFIm->ScreenDescriptor)
		if(!(GIFIm->ScreenDescriptor = (ScreenDescriptor *)
			malloc(sizeof(ScreenDescriptor)) )) {
				CloseGIF(GIFIm);
				return(ALLOCATION_ERROR);
    		}
    		else
    			GIFIm->AllocationFlags |= AUTOALLOCATED_SCR_DESCRIPTOR;

   	if(fread((char *)GIFIm->ScreenDescriptor,1,sizeof(ScreenDescriptor),
		GIFIm->FD)!=sizeof(ScreenDescriptor) ) {
			CloseGIF(GIFIm);
			return(CORRUPTED_GIF_FILE);
   	}

   	GIFIm->Depth = (GIFIm->ScreenDescriptor->PackedFields & 7) + 1;
	
	/**** Alloco e leggo un'eventuale Global ColorMap ********************/

   	if(GIFIm->ScreenDescriptor->PackedFields &0x80) {

      		if(!GIFIm->GlobalColorMap) 
			if(!(GIFIm->GlobalColorMap = (Colormap *)
				malloc(sizeof(Colormap)))) {
					CloseGIF(GIFIm);
					return(ALLOCATION_ERROR);
       			}
       			else
      	 		GIFIm->AllocationFlags |= AUTOALLOCATED_GLOBAL_CMAP;
      
      		GIFIm->NGlobalColors =
      			(1 << (GIFIm->ScreenDescriptor->PackedFields & 7) + 1);

		GIFIm->NColors = GIFIm->NGlobalColors;
		GIFIm->ColorMap = GIFIm->GlobalColorMap;

      		if(fread((char *)&GIFIm->GlobalColorMap->Entry[0],1,
			GIFIm->NGlobalColors * 3,GIFIm->FD) !=
			GIFIm->NGlobalColors * 3) {
				CloseGIF(GIFIm);
				return(CORRUPTED_GIF_FILE);
      		}
   	}
        return(OK);
}


void CloseGIF(GIFImage *GIFIm)
{
  	if(GIFIm->Status & FILE_OPEN) {
    		fclose(GIFIm->FD);
    		GIFIm->Status &= ~FILE_OPEN;
    		GIFIm->FD = NULL;
  	}
}

int GetNextChunk(GIFImage *GIFIm)
{
int Separator;

if (GIFIm->Status & READING_DATA)
	IgnoreCurrentChunk(GIFIm);

if((Separator = fgetc(GIFIm->FD)) == EOF)
	return(CORRUPTED_GIF_FILE);

if(Separator==IMAGE_SEPARATOR) {

	/* Alloco e leggo l'Image Descriptor *********************************/

	if (!GIFIm->ImageDescriptor)
	   if (!(GIFIm->ImageDescriptor = ( ImageDescriptor *)
		malloc(sizeof( ImageDescriptor))))
			return(ALLOCATION_ERROR);
	   else
		GIFIm->AllocationFlags |= AUTOALLOCATED_IMG_DESCRIPTOR;

	if (fread((char *)GIFIm->ImageDescriptor,1,sizeof(ImageDescriptor),
		GIFIm->FD) != sizeof(ImageDescriptor))
			return(CORRUPTED_GIF_FILE);

	GIFIm->Width = GIFIm->ImageDescriptor->MSBWidth * 256
				+ GIFIm->ImageDescriptor->LSBWidth;
	GIFIm->Height = GIFIm->ImageDescriptor->MSBHeight * 256
				+ GIFIm->ImageDescriptor->LSBHeight;

	if(GIFIm->ImageDescriptor->PackedFields & 0x40)
		GIFIm->InterLace = TRUE;
	else
		GIFIm->InterLace = FALSE;

	/* Alloco e leggo un'eventuale Local ColorMap ************************/

	if(GIFIm->ImageDescriptor->PackedFields &0x80) {

	    if(!GIFIm->LocalColorMap)
		if(!(GIFIm->LocalColorMap =
			(Colormap *)malloc(sizeof(Colormap))))
			return(ALLOCATION_ERROR);
		else
			GIFIm->AllocationFlags |= AUTOALLOCATED_LOCAL_CMAP;

	    GIFIm->NLocalColors =
			(1 << (GIFIm->ImageDescriptor->PackedFields & 7) + 1);

		GIFIm->NColors = GIFIm->NLocalColors;
		GIFIm->ColorMap = GIFIm->LocalColorMap;

	    if(fread((char *)&GIFIm->LocalColorMap->Entry[0],1,
		GIFIm->NLocalColors * 3,GIFIm->FD)
		!= GIFIm->NLocalColors * 3)
			return(CORRUPTED_GIF_FILE);
	}

	if((GIFIm->InitialCodeSize = fgetc(GIFIm->FD)) == EOF)
		return(CORRUPTED_GIF_FILE);

	GIFIm->Status |= READING_DATA;
	return(IMAGE);
}

/********** Alloco e leggo eventuali blocchi di estensione ********************/

if(Separator==EXTENSION_INTRODUCER)

	switch(Separator=fgetc(GIFIm->FD)) {

		case EOF:
			return(CORRUPTED_GIF_FILE);

		case CONTROL :
			if (!GIFIm->GraphicControlExtension)
		  		if (!(GIFIm->GraphicControlExtension =
				(GraphicControlExtension *)
				malloc(sizeof(GraphicControlExtension))))
					return(ALLOCATION_ERROR);
		  	else
			GIFIm->AllocationFlags |= AUTOALLOCATED_GRAF_CTRL;

			if (fread((char *)GIFIm->GraphicControlExtension,1,
				sizeof(GraphicControlExtension),GIFIm->FD)
				!= sizeof( GraphicControlExtension))
					return(CORRUPTED_GIF_FILE);

			return(CONTROL);

		case COMMENT : 
			GIFIm->Status |= READING_DATA;
			return(COMMENT);

		case PLAINTEXT :
                	if (!GIFIm->PlainTextExtension)
				 if (!(GIFIm->PlainTextExtension =
				  	(PlainTextExtension *)
					malloc(sizeof( PlainTextExtension))))
						return(ALLOCATION_ERROR);
		 		else
					GIFIm->AllocationFlags |=
						 AUTOALLOCATED_PLAIN_TEXT;

			if (fread((char *)GIFIm->PlainTextExtension,1,
				sizeof(PlainTextExtension),GIFIm->FD)
				!= sizeof( PlainTextExtension))
					return(CORRUPTED_GIF_FILE);

			GIFIm->Status |= READING_DATA;
			return(PLAINTEXT);

		case APPLICATION : 

			if (!GIFIm->ApplicationExtension)
				if (!(GIFIm->ApplicationExtension =
					(ApplicationExtension *)
					malloc(sizeof( ApplicationExtension))))
						return(ALLOCATION_ERROR);
		 		else
					GIFIm->AllocationFlags |=
					AUTOALLOCATED_APPLICATION;

			if (fread((char *)GIFIm->ApplicationExtension,1,
				sizeof(ApplicationExtension),GIFIm->FD)
				!= sizeof( ApplicationExtension))
					return(CORRUPTED_GIF_FILE);

			GIFIm->Status |= READING_DATA;
			return(APPLICATION);

		default:
			return(UNKNOWN_EXTENSION);
	}

if(Separator==GIF_TERMINATOR)
	return(NO_MORE_CHUNKS);

return(CORRUPTED_GIF_FILE);
}


int GetBlockOfData(char *Buff, GIFImage *GIFIm)
{
	int BlockSize;

 	if((BlockSize = fgetc(GIFIm->FD)) == EOF)
		return(CORRUPTED_GIF_FILE);
 	if(BlockSize == 0) {
  		GIFIm->Status &= ~READING_DATA;
  		return(BlockSize);
 	}
 	if(fread(Buff,1,BlockSize,GIFIm->FD) != BlockSize) {
		return(CORRUPTED_GIF_FILE);
 	}

	return(BlockSize);
}


int IgnoreCurrentChunk(GIFImage *GIFIm)
{
	char Buf[256];
  	int Success;
  	
		while(((Success = GetBlockOfData(Buf,GIFIm)) != 0) &&
			Success != EOF);


	return(Success);
}


int GetCommentExtension(GIFImage *GIFIm)
{
	char buf[256];
	int Size;
	
	Size = GetBlockOfData(buf, GIFIm);

	if(!(GIFIm->CommentExtension = (char *)malloc(Size+1))) 
		return(ALLOCATION_ERROR);
	else
		GIFIm->AllocationFlags |= AUTOALLOCATED_COMMENT;

	memcpy(GIFIm->CommentExtension,buf,Size);
	GIFIm->CommentExtension[Size] = '\0';
	return(OK);
}


int LoadGIF(char *FileName,GIFImage *GIFIm)
{
	int ReturnCode;
	int ChunkType;

	if ((ReturnCode = OpenGIF(FileName,GIFIm)) == OK) {

 		while ((ChunkType = GetNextChunk(GIFIm)) != NO_MORE_CHUNKS)

			switch(ChunkType) {

				case IMAGE :
					if((ReturnCode = GetBitMap(GIFIm))
						!= OK)
				      			return(ReturnCode);
                      		   			break;
				case CONTROL :
					 break;

				case COMMENT :
					 if((ReturnCode = 
					   GetCommentExtension(GIFIm)) != OK)
				      			return(ReturnCode);
				   			break;

				case PLAINTEXT : if((ReturnCode =
					IgnoreCurrentChunk(GIFIm)) != OK)
				      			return(ReturnCode);
				   			break;

				case APPLICATION : if((ReturnCode =
					IgnoreCurrentChunk(GIFIm)) != OK)
				      			return(ReturnCode);
				   			break;

				case ALLOCATION_ERROR :
					return(ALLOCATION_ERROR);

				case CORRUPTED_GIF_FILE :
					return(CORRUPTED_GIF_FILE);
			}
		CloseGIF(GIFIm);
	}
	return(ReturnCode);
}







