/* Copyright 1990 by Christopher A. Wichura. See file GIFMachine.doc for full description of rights. */ #include "GIFMachine.h" #include #include #include #include struct GIFdescriptor gdesc; struct RGB **BitPlane; struct RGB GlobalColourTable[256]; extern UWORD *SHAMmem; extern BYTE *PlaneBuf; extern BOOL Laced; extern UBYTE *Planes[8]; ULONG ImageNumber; extern struct MinList CommentList; /* our version number stuff */ extern UBYTE __far VersionID[]; /* indicates which memory list to allocate from */ extern UWORD CurrentMem; /* the current GIF file handle */ BPTR GIFfh = NULL; /* here we have some defines relating to our GADS call */ #define ESC "\x9B" #define GIFMACH ESC "33;42mGIFMachine" ESC "32;40m" #define SPACES ESC "32m]\n [" ESC "33m" #define BRACES ESC "32m] [" ESC "33m" #define ARG_HELP "%s v%s\nCopyright \xA9 1990 by " \ ESC "4;33;42mChristopher A. Wichura" ESC "0;33;40m (" \ ESC "32mcaw" ESC "33m@" ESC "32mmiroc.chi.il.us" ESC "33m)\n\n" \ ESC "31mUsage: %s <" ESC "31mGIFfile(s)" ESC "32m> [" \ ESC "33mTO " ESC "31mDirectory | File" BRACES "ALL%s" \ "NOBORDER " ESC "32m<" ESC "31mLine Thresh" ESC "32m>] [" ESC \ "33mXCOMP" BRACES "DITHER%sXFLIP" BRACES "YFLIP" BRACES \ "DEEP" BRACES "BUFSIZE " ESC "32m<" ESC "31mSize in Kbytes" \ ESC "32m>]\n" ESC "31m" #define ARG_TEMPLATE "GIFfiles/M/A,TO/K,ALL/S,NOBORDER/K/N,XCOMP/S,DITHER/S,XFLIP/s,YFLIP/s,DEEP/S,BUFSIZE/K/N" #define ARG_FILES 0 #define ARG_TO 1 #define ARG_ALL 2 #define ARG_NOBORD 3 #define ARG_XCOMP 4 #define ARG_DITHER 5 #define ARG_FLIPX 6 #define ARG_FLIPY 7 #define ARG_DEEP 8 #define ARG_BUFSIZ 9 #define ARG_sizeof 10 /* we will make the argument array global so that other modules can get at the ARG_TO, ARG_ALL and ARG_XCOMP fields easily */ struct RDArgs *ArgsPtr; char *ArgArray[ARG_sizeof]; BOOL ArgToIsDir; /* size of the read buffered i/o space */ static ULONG BufSize = 2048; /* default size is 2k */ int NoBorderLineThresh = 0; /* some mem pointers used when we do dithering */ BYTE *CurrentLineErr[3]; BYTE *LastLineErr[3]; /* this flag says if we scaled the image */ BOOL DidXComp; /* we print this when the user hits the break key */ char *AbortMsg = "*** User Interruption!\n"; /* storage for our library bases */ struct Library *MathIeeeDoubBasBase = NULL; struct Library *IFFParseBase = NULL; /* storage for our anchor when looking for pattern matches */ struct Anchor { struct AnchorPath APath; char Path[256]; } *anchor = NULL; /* here we have our main routine */ int __regargs main(char *cmdptr, int cmdlen, struct WBStartup *WBMsg) { register char **FilesPtr; struct RDArgs MyArgs; InitMemory(); if (WBMsg) { WarnMustUseCLI(); MyExit(5); } if (!(MathIeeeDoubBasBase = OpenLibrary("mathieeedoubbas.library", 0))) { MyPrintf("Unable to access %s!\n", "mathieeedoubbas.library"); MyExit(5); } if (!(IFFParseBase = OpenLibrary("iffparse.library", 0))) { MyPrintf("Unable to access %s!\n", "iffparse.library"); MyExit(5); } memset ((char *)&MyArgs, 0, sizeof(struct RDArgs)); if (!(MyArgs.RDA_ExtHelp = (UBYTE *)MyAlloc(strlen(ARG_HELP) + (2 * strlen(GIFMACH)) + (2 * strlen(SPACES)) + strlen(VersionID) + 1))) { PutStr("Out of memory!\n"); MyExit(5); } MySPrintf((char *)MyArgs.RDA_ExtHelp, ARG_HELP, GIFMACH, VersionID, GIFMACH, SPACES, SPACES); if (!(ArgsPtr = ReadArgs(ARG_TEMPLATE, (LONG *)&ArgArray, &MyArgs))) { PrintFault(IoErr(), NULL); MyExit(5); } MyFree((char *)MyArgs.RDA_ExtHelp); if (ArgArray[ARG_TO]) ArgToIsDir = IsDir(ArgArray[ARG_TO]); if (ArgArray[ARG_NOBORD]) { NoBorderLineThresh = *((LONG *)ArgArray[ARG_NOBORD]); if (NoBorderLineThresh < 0 || NoBorderLineThresh > 100) { PutStr("Invalid NOBORDER line threshhold specified.\n"); MyExit(3); } } if (ArgArray[ARG_BUFSIZ]) BufSize = *((LONG *)ArgArray[ARG_BUFSIZ]) * 1024; if (!(FilesPtr = (char **)ArgArray[ARG_FILES])) { PutStr("No GIF files selected.\n"); MyExit(3); } InitDiff(); /* one time init for the RGBdiff function */ while (*FilesPtr) DoPattern(*FilesPtr++); MyExit(0); } void MyExit(ULONG result) { if (GIFfh) Close(GIFfh); if (IFFParseBase) CloseLibrary(IFFParseBase); if (MathIeeeDoubBasBase) CloseLibrary(MathIeeeDoubBasBase); if (anchor) MatchEnd(&anchor->APath); if (ArgsPtr) FreeArgs(ArgsPtr); FreeAll(1); FreeAll(0); XCEXIT(result); } /* this will walk through a pattern doing conversions */ void DoPattern(char *pat) { register int error; if (!(anchor = (struct Anchor *)MyAlloc(sizeof(struct Anchor)))) { PutStr("Out of memory!\n"); MyExit(10); } anchor->APath.ap_Strlen = sizeof(anchor->Path); anchor->APath.ap_Flags = APF_DOWILD; anchor->APath.ap_BreakBits = SIGBREAKF_CTRL_C; error = MatchFirst(pat, &anchor->APath); while (!error) { if (anchor->APath.ap_Info.fib_DirEntryType > 0) { if (ArgArray[ARG_ALL]) { if (!(anchor->APath.ap_Flags & APF_DIDDIR)) anchor->APath.ap_Flags |= APF_DODIR; anchor->APath.ap_Flags &= ~APF_DIDDIR; } } else Convert(anchor->APath.ap_Buf); error = MatchNext(&anchor->APath); } MatchEnd(&anchor->APath); MyFree((char *)anchor); anchor = NULL; switch(error) { case ERROR_BREAK: PutStr(AbortMsg); MyExit(ABORTEXITVAL); break; case ERROR_OBJECT_NOT_FOUND: PutStr("File not found.\n"); break; case ERROR_BUFFER_OVERFLOW: PutStr("Path too long!\n"); break; case ERROR_NO_MORE_ENTRIES: /* normal termination */ break; default: MyPrintf("I/O Error #%ld!\n", error); break; } } /* here we have the routine that gets ready to do the conversion */ void Convert(char *name) { register int index; char *basename; char *ptr; char sig[7]; int size; int error; int colours; LONG cmdcode; struct DateStamp StartTime, EndTime; CurrentMem++; if (!(GIFfh = Open(name, MODE_OLDFILE))) { MyPrintf("Error #%ld trying to open %s...\n", IoErr(), name); goto LeaveConvert; } SetVBuf(GIFfh, BUF_FULL, BufSize); sig[6] = NULL; if (FRead(GIFfh, sig, 1, 6) != 6 || strncmp("GIF", sig, 3)) { MyPrintf("%s is not a GIF file...\n", name); goto LeaveConvert; } MyPrintf("Converting %s ", name); basename = FilePart(name); ptr = basename + strlen(basename) - 4; if (!strnicmp(".gif", ptr, 4)) *ptr = NULL; size = strlen(basename) + 6; if (ArgArray[ARG_TO]) { if (ArgToIsDir) size += strlen(ArgArray[ARG_TO]) + 1; else size = strlen(ArgArray[ARG_TO]) + 1; } if (!(ptr = MyAlloc(size))) { PutStr("... Out of memory!\n"); goto LeaveConvert; } if (ArgArray[ARG_TO]) { strcpy(ptr, ArgArray[ARG_TO]); if (ArgToIsDir) { AddPart(ptr, basename, size); strcat(ptr, (ArgArray[ARG_DEEP] ? ".deep" : ".sham")); } } else { strcpy(ptr, basename); strcat(ptr, (ArgArray[ARG_DEEP] ? ".deep" : ".sham")); } MyPrintf("to %s...\n", ptr); DateStamp((LONG *)&StartTime); if (FRead(GIFfh, (char *)&gdesc, 1, 7) != 7) { PutStr("Error reading screen descriptor.\n"); goto LeaveConvert; } FlipWord(&gdesc.gd_Width); FlipWord(&gdesc.gd_Height); MyPrintf("Signature = \"%s\", Width = %ld, Height = %ld\n", sig, gdesc.gd_Width, gdesc.gd_Height); NewList((struct List *)&CommentList); DidXComp = 0; colours = 1L << ((gdesc.gd_ColInfo & 7) + 1); if (!(gdesc.gd_ColInfo & 1L << 7)) { PutStr("No global colour map supplied, using internal.\n"); for (index = 0; index < colours; index++) { GlobalColourTable[index].rgb_Red = GlobalColourTable[index].rgb_Green = GlobalColourTable[index].rgb_Blue = index; } } else { MyPrintf("Global colour map contains %ld entries.\n", colours); for (index = 0; index < colours; index++) { if (FRead(GIFfh, &GlobalColourTable[index], 1, 3) != 3) { MyPrintf("Error reading global colour #%ld.\n", index); goto LeaveConvert; } } } size = ((gdesc.gd_Width + 7) / 8) + 1; size += (size + 127) >> 7; if (!(BitPlane = (struct RGB **)MyAlloc(gdesc.gd_Height * sizeof(struct RGB *))) || !(SHAMmem = (UWORD *)MyAlloc(gdesc.gd_Height * 16 * sizeof(UWORD))) || !(PlaneBuf = (BYTE *)MyAlloc(size))) { PutStr("Out of memory trying to allocate picture.\n"); goto LeaveConvert; } size = (gdesc.gd_Width + 1) * sizeof(struct RGB); for (index = 0; index < gdesc.gd_Height; index++) if (!(BitPlane[index] = (struct RGB *)MyAlloc(size))) { PutStr("Out of memory trying to allocate picture.\n"); goto LeaveConvert; } size = ((gdesc.gd_Width + 7) / 8) + 1; for (index = 0; index < (ArgArray[ARG_DEEP] ? 8 : 6); index++) if (!(Planes[index] = (UBYTE *)MyAlloc(size))) { PutStr("Out of memory trying to allocate picture.\n"); goto LeaveConvert; } if (ArgArray[ARG_DITHER]) { size = gdesc.gd_Width * sizeof(BYTE); for (index = 0; index < 3; index++) if (!(CurrentLineErr[index] = (BYTE *)MyAlloc(size)) || !(LastLineErr[index] = (BYTE *)MyAlloc(size))) { PutStr("Out of memory trying to allocate picture.\n"); goto LeaveConvert; } } ImageNumber = 1; /* at this point we start looking for images, extensions or the gif terminator. we call the appropriate routine as we find each. */ for (error = FALSE; error == FALSE;) { if ((cmdcode = FGetC(GIFfh)) == -1) { PutStr("...I/O error reading GIF file.\n"); goto LeaveConvert; } switch(cmdcode) { case GIF_IMAGE: error = DoImage(GIFfh); break; case GIF_EXTENSION: error = DoExtension(GIFfh); break; case GIF_TERMINATOR: if (ArgArray[ARG_NOBORD]) StripBorder(); if (ArgArray[ARG_FLIPX]) DoXFlip(); if (ArgArray[ARG_FLIPY]) DoYFlip(); if (ArgArray[ARG_XCOMP]) { DoXComp(); DidXComp = 1; } if (gdesc.gd_Height > 200 && DidXComp) Laced = TRUE; else Laced = FALSE; if (!ArgArray[ARG_DEEP]) { if (ArgArray[ARG_DITHER]) DitherTo12(); else ReduceTo12(); GIFtoSHAM(); } error = WriteIFF(ptr, (BOOL)ArgArray[ARG_DEEP]); break; default: MyPrintf("...Unknown directive #%ld encountered.\n", cmdcode); error = TRUE; } } DateStamp((ULONG *)&EndTime); { register ULONG Hours; register ULONG Minutes; register ULONG Seconds; register ULONG Seconds2; Seconds = (EndTime.ds_Days * 86400) + (EndTime.ds_Minute * 60) + (EndTime.ds_Tick / TICKS_PER_SECOND); Seconds2 = (StartTime.ds_Days * 86400) + (StartTime.ds_Minute * 60) + (StartTime.ds_Tick / TICKS_PER_SECOND); Seconds -= Seconds2; Hours = Seconds / 3600; Seconds -= Hours * 3600; Minutes = Seconds / 60; Seconds -= Minutes * 60; MyPrintf("...Conversion time was %ld hour%s, %ld minute%s and %ld second%s.\n", Hours, (Hours != 1 ? "s" : ""), Minutes, (Minutes != 1 ? "s" : ""), Seconds, (Seconds != 1 ? "s" : "")); } LeaveConvert: FreeAll(CurrentMem--); if (GIFfh) { Close(GIFfh); GIFfh = NULL; } } /* this will check to see if we have a directory or not */ BOOL IsDir(char *name) { register BPTR lock; register BOOL result = FALSE; struct FileInfoBlock __aligned fib; if (lock = Lock(name, ACCESS_READ)) { if (Examine(lock, &fib)) { if (fib.fib_DirEntryType > 0) result = TRUE; } UnLock(lock); } return result; } /* this will convert a word from LSB/MSB to MSB/LSB */ void FlipWord(UWORD *word) { register UBYTE swap1; register UBYTE swap2; swap1 = *word & 0xFF; swap2 = (*word & 0xFF00) >> 8; *word = swap1 << 8 | swap2; }