home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / TGAUTL.ZIP / TGAPACK.C < prev    next >
C/C++ Source or Header  |  1990-03-26  |  25KB  |  1,142 lines

  1. /*
  2. ** Copyright (c) 1989, 1990
  3. ** Truevision, Inc.
  4. ** All Rights Reserverd
  5. **
  6. ** TGAPACK reads the contents of a Truevision(R) TGA(tm) File and provides
  7. ** the ability to compress the image data via run length encoding, or
  8. ** to uncompress images that have been stored in a run length encoded
  9. ** format.  The program only operates on files stored in the original
  10. ** TGA format.
  11. **
  12. ** USAGE:
  13. **        tgapack [options] [file1] [file2] ...
  14. **
  15. ** If no filenames are provided, the program will prompt for a file
  16. ** name.  If no extension is provided with a filename, the program
  17. ** will search for the file with ".tga", ".vst", ".icb", ".vda", or
  18. ** ".win" extension.  Options are specified by a leading '-'.
  19. ** If no options are provided, the program attempts to compress an
  20. ** uncompressed image.
  21. **
  22. ** Recognized options are:
  23. **
  24. **        -unpack            uncompressed a run length encoded image
  25. **        -32to24            compress a 32 bit image by eliminating alpha data
  26. **        -version        report version number of program
  27. */
  28.  
  29. #include <conio.h>
  30. #include <graph.h>
  31. #include <io.h>
  32. #include <malloc.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include "tga.h"
  39.  
  40. /*
  41. ** Define byte counts associated with extension areas for various
  42. ** versions of the TGA specification.
  43. */
  44. #define    EXT_SIZE_20    495            /* verison 2.0 extension size */
  45.  
  46. #define CBUFSIZE    2048        /* size of copy buffer */
  47. #define RLEBUFSIZ    512            /* size of largest possible RLE packet */
  48.  
  49.  
  50. extern void        main( int, char ** );
  51. extern int        CountDiffPixels( char *, int, int );
  52. extern long        CountRLEData( FILE *, unsigned int, unsigned int, int );
  53. extern int        CountSamePixels( char *, int, int );
  54. extern int        DisplayImageData( unsigned char *, int, int );
  55. extern UINT32    GetPixel( unsigned char *, int );
  56. extern int        OutputTGAFile( FILE *, FILE *, TGAFile * );
  57. extern int        ParseArgs( int, char ** );
  58. extern void        PrintImageType( int );
  59. extern void        PrintTGAInfo( TGAFile * );
  60. extern UINT8    ReadByte( FILE * );
  61. extern void        ReadCharField( FILE *, char *, int );
  62. extern UINT32    ReadLong( FILE * );
  63. extern int        ReadRLERow( unsigned char *, int, int, FILE * );
  64. extern UINT16    ReadShort( FILE * );
  65. extern int        RLEncodeRow( char *, char *, int, int );
  66. extern char        *SkipBlank( char * );
  67. extern void        StripAlpha( unsigned char *, int );
  68. extern int        WriteByte( UINT8, FILE * );
  69. extern int        WriteLong( UINT32, FILE * );
  70. extern int        WriteShort( UINT16, FILE * );
  71. extern int        WriteStr( char *, int, FILE * );
  72.  
  73.  
  74. /*
  75. ** String data for interpretting image orientation specification
  76. */
  77. char    *orientStr[] =
  78. {
  79.     "Bottom Left",
  80.     "Bottom Right",
  81.     "Top Left",
  82.     "Top Right"
  83. };
  84.  
  85. /*
  86. ** String data for interpretting interleave flag defined with VDA
  87. ** This field is now obsolete and should typically be set to zero.
  88. */
  89. char    *interleaveStr[] =
  90. {
  91.     "  Two Way (Even-Odd) Interleave (e.g., IBM Graphics Card Adapter), Obsolete",
  92.     "  Four Way Interleave (e.g., AT&T 6300 High Resolution), Obsolete",
  93. };
  94.  
  95.  
  96. /*
  97. ** Filename extensions used during file search
  98. */
  99. char    *extNames[] =
  100. {
  101.     ".tga",
  102.     ".vst",
  103.     ".icb",
  104.     ".vda",
  105.     ".win",
  106.     NULL
  107. };
  108.  
  109. TGAFile            f;                /* control structure of image data */
  110.  
  111. int                unPack;            /* when true, uncompress image data */
  112. int                noAlpha;        /* when true, converts 32 bit image to 24 */
  113.  
  114. int                inRawPacket;    /* flags processing state for RLE data */
  115. int                inRLEPacket;    /* flags processing state for RLE data */
  116. unsigned int    packetSize;    /* records current RLE packet size in bytes */
  117. char            rleBuf[RLEBUFSIZ];
  118.  
  119. char        copyBuf[CBUFSIZE];
  120.  
  121.  
  122. char        *versionStr =
  123. "Truevision(R) TGA(tm) File Compression Utility Version 1.3 - January 2, 1990";
  124.  
  125.  
  126. void
  127. main( argc, argv )
  128. int argc;
  129. char **argv;
  130. {
  131.     int            fileFound;
  132.     int            fileCount;
  133.     int            files;
  134.     char        *q;
  135.     FILE        *fp, *outFile;
  136.     int            i;
  137.     char        fileName[80];
  138.     char        outFileName[80];
  139.     struct stat    statbuf;
  140.  
  141.     unPack = 0;            /* default to compressing image data */
  142.     noAlpha = 0;        /* default to retaining all components of 32 bit */
  143.  
  144.     inRawPacket = inRLEPacket = 0;    /* initialize RLE processing flags */
  145.     packetSize = 0;
  146.     /*
  147.     ** The program can be invoked without an argument, in which case
  148.     ** the user will be prompted for the name of the image file to be
  149.     ** examined, or the image file name can be provided as an argument
  150.     ** to the command.
  151.     **
  152.     ** File names provided do not need to include the extension if
  153.     ** the image file extension is one of the standard strings common
  154.     ** to Truevision TGA image file names ( e.g., TGA, WIN, VST, VDA, ICB )
  155.     */
  156.     if ( argc == 1 )
  157.     {
  158.         puts( versionStr );
  159.         printf( "Enter name of file to examine: " );
  160.         gets( fileName );
  161.         if ( strlen( fileName ) == 0 ) exit( 0 );
  162.         fileCount = 1;
  163.     }
  164.     else
  165.     {
  166.         fileCount = ParseArgs( argc, argv );
  167.         if ( fileCount == 0 ) exit( 0 );
  168.         argv++;
  169.         while ( **argv == '-' ) argv++; 
  170.         strcpy( fileName, *argv );
  171.     }
  172.     for ( files = 0; files < fileCount; ++files )
  173.     {
  174.         if ( files != 0 )
  175.         {
  176.             argv++;
  177.             while ( **argv == '-' ) argv++; 
  178.             strcpy( fileName, *argv );
  179.         }
  180.         /*
  181.         ** See if we can find the file as specified or with one of the
  182.         ** standard filename extensions...
  183.         */
  184.         fileFound = 0;
  185.         if ( stat( fileName, &statbuf ) == 0 ) fileFound = 1;
  186.         else
  187.         {
  188.             /*
  189.             ** If there is already an extension specified, skip
  190.             ** the search for standard extensions
  191.             */
  192.             q = strchr( fileName, '.' );
  193.             if ( q != NULL )
  194.             {
  195.                 q = fileName + strlen( fileName );
  196.             }
  197.             else
  198.             {
  199.                 i = 0;
  200.                 strcat( fileName, extNames[i] );
  201.                 q = strchr( fileName, '.' );
  202.                 while ( extNames[i] != NULL )
  203.                 {
  204.                     strcpy( q, extNames[i] );
  205.                     if ( stat( fileName, &statbuf ) == 0 )
  206.                     {
  207.                         fileFound = 1;
  208.                         break;
  209.                     }
  210.                     ++i;
  211.                 }
  212.             }
  213.         }
  214.         if ( fileFound )
  215.         {
  216.             _clearscreen( _GCLEARSCREEN );
  217.             printf( "Processing TGA File: %s\n", fileName );
  218.             fp = fopen( fileName, "rb" );
  219.             /*
  220.             ** It would be nice to be able to read in the entire
  221.             ** structure with one fread, but compiler dependent
  222.             ** structure alignment precludes the simplistic approach.
  223.             ** Instead, fill each field individually, and use routines
  224.             ** that will allow code to execute on various hosts by
  225.             ** recompilation with particular compiler flags.
  226.             **
  227.             ** Start by reading the fields associated with the original
  228.             ** TGA format.
  229.             */
  230.             f.idLength = ReadByte( fp );
  231.             f.mapType = ReadByte( fp );
  232.             f.imageType = ReadByte( fp );
  233.             f.mapOrigin = ReadShort( fp );
  234.             f.mapLength = ReadShort( fp );
  235.             f.mapWidth = ReadByte( fp );
  236.             f.xOrigin = ReadShort( fp );
  237.             f.yOrigin = ReadShort( fp );
  238.             f.imageWidth = ReadShort( fp );
  239.             f.imageHeight = ReadShort( fp );
  240.             f.pixelDepth = ReadByte( fp );
  241.             f.imageDesc = ReadByte( fp );
  242.             memset( f.idString, 0, 256 );
  243.             if ( f.idLength > 0 )
  244.             {
  245.                 fread( f.idString, 1, f.idLength, fp );
  246.             }
  247.             /*
  248.             ** Now see if the file is the new (extended) TGA format.
  249.             */
  250.             if ( !fseek( fp, statbuf.st_size - 26, SEEK_SET ) )
  251.             {
  252.                 f.extAreaOffset = ReadLong( fp );
  253.                 f.devDirOffset = ReadLong( fp );
  254.                 fgets( f.signature, 18, fp );
  255.                 if ( strcmp( f.signature, "TRUEVISION-XFILE." ) )
  256.                 {
  257.                     /*
  258.                     ** Reset offset values since this is not a new TGA file
  259.                     */
  260.                     f.extAreaOffset = 0L;
  261.                     f.devDirOffset = 0L;
  262.                     
  263.                     strcpy( outFileName, fileName );
  264.                     i = strlen( fileName );
  265.                     outFileName[ i - 3 ] = '\0';    /* remove extension */
  266.                     strcat( outFileName, "$$$" );
  267.                     if ( ( outFile = fopen( outFileName, "wb" ) ) != NULL )
  268.                     {
  269.                         if ( OutputTGAFile( fp, outFile, &f ) < 0 )
  270.                         {
  271.                             fclose( outFile );
  272.                             unlink( outFileName );
  273.                         }
  274.                         else
  275.                         {
  276.                             fclose( outFile );
  277.                             fclose( fp );
  278.                             fp = (FILE *)0;
  279.                             unlink( fileName );
  280.                             rename( outFileName, fileName );
  281.                         }
  282.                     }
  283.                     else
  284.                     {
  285.                         puts( "Unable to create output file." );
  286.                     }
  287.                 }
  288.                 else puts( "Input file must be original TGA format." );
  289.             }
  290.             else
  291.             {
  292.                 puts( "Error seeking to end of file for possible extension data." );
  293.             }
  294.             if ( fp != NULL ) fclose( fp );
  295.         }
  296.         else
  297.         {
  298.             *q = '\0';
  299.             printf("Unable to open image file %s\n", fileName );
  300.         }
  301.     }
  302. }
  303.  
  304.  
  305.  
  306. /*
  307. ** Count pixels in buffer until two identical adjacent ones found
  308. */
  309.  
  310. int
  311. CountDiffPixels( p, bpp, pixCnt )
  312. char    *p;
  313. int        bpp;
  314. int        pixCnt;
  315. {
  316.     unsigned long    pixel;
  317.     unsigned long    nextPixel;
  318.     int                n;
  319.  
  320.     n = 0;
  321.     if ( pixCnt == 1 ) return( pixCnt );
  322.     pixel = GetPixel( p, bpp );
  323.     while ( pixCnt > 1 )
  324.     {
  325.         p += bpp;
  326.         nextPixel = GetPixel( p, bpp );
  327.         if ( nextPixel == pixel ) break;
  328.         pixel = nextPixel;
  329.         ++n;
  330.         --pixCnt;
  331.     }
  332.     if ( nextPixel == pixel ) return( n );
  333.     return( n + 1 );
  334. }
  335.  
  336.  
  337.  
  338. long
  339. CountRLEData( fp, x, y, bytesPerPixel )
  340. FILE            *fp;
  341. unsigned int    x;
  342. unsigned int    y;
  343. int                bytesPerPixel;
  344. {
  345.     long            n;
  346.     long            pixelCount;
  347.     long            totalPixels;
  348.     unsigned int    value;
  349.  
  350.     n = 0L;
  351.     pixelCount = 0L;
  352.     totalPixels = (long)x * (long)y;
  353.  
  354.     while ( pixelCount < totalPixels )
  355.     {
  356.         value = (unsigned int)ReadByte( fp );
  357.         n++;
  358.         if ( value & 0x80 )
  359.         {
  360.             n += bytesPerPixel;
  361.             pixelCount += (value & 0x7f) + 1;
  362.             if ( fread( copyBuf, 1, bytesPerPixel, fp ) != bytesPerPixel )
  363.             {
  364.                 puts( "Error counting RLE data." );
  365.                 return( 0L );
  366.             }
  367.         }
  368.         else
  369.         {
  370.             value++;
  371.             n += value * bytesPerPixel;
  372.             pixelCount += value;
  373.             if ( fread( copyBuf, bytesPerPixel, value, fp ) != value )
  374.             {
  375.                 puts( "Error counting raw data." );
  376.                 return( 0L );
  377.             }
  378.         }
  379.     }
  380.     return( n );
  381. }
  382.  
  383.  
  384.  
  385. int
  386. CountSamePixels( p, bpp, pixCnt )
  387. char    *p;
  388. int        bpp;
  389. int        pixCnt;
  390. {
  391.     unsigned long    pixel;
  392.     unsigned long    nextPixel;
  393.     int                n;
  394.  
  395.     n = 1;
  396.     pixel = GetPixel( p, bpp );
  397.     pixCnt--;
  398.     while ( pixCnt > 0 )
  399.     {
  400.         p += bpp;
  401.         nextPixel = GetPixel( p, bpp );
  402.         if ( nextPixel != pixel ) break;
  403.         ++n;
  404.         --pixCnt;
  405.     }
  406.     return( n );
  407. }
  408.  
  409.  
  410.  
  411.  
  412. int
  413. DisplayImageData( q, n, bpp )
  414. unsigned char *q;
  415. int    n;
  416. int    bpp;
  417. {
  418.     long i;
  419.     int j;
  420.     unsigned char a, b, c;
  421.  
  422.     i = 0;
  423.     while ( i < n ) 
  424.     {
  425.         printf( "%08lX: ", i );
  426.         switch ( bpp )
  427.         {
  428.         case 4:
  429.             for ( j = 0; j < 4; ++j )
  430.             {
  431.                 printf( "%08lx ", *(unsigned long *)q );
  432.                 q += 4;
  433.             }
  434.             i += 16;
  435.             break;
  436.         case 3:
  437.             for ( j = 0; j < 8; ++j )
  438.             {
  439.                 a = *q++;
  440.                 b = *q++;
  441.                 c = *q++;
  442.                 printf( "%02x%02x%02x ", c, b, a );
  443.             }
  444.             i += 24;
  445.             break;
  446.         case 2:
  447.             for ( j = 0; j < 8; ++j )
  448.             {
  449.                 printf( "%04x ", *(unsigned int *)q );
  450.                 q += 2;
  451.             }
  452.             i += 16;
  453.             break;
  454.         default:
  455.             for ( j = 0; j < 16; ++j )
  456.             {
  457.                 printf( "%02x ", *(unsigned char *)q++ );
  458.             }
  459.             i += 16;
  460.             break;
  461.         }
  462.         putchar( '\n' );
  463.     }
  464.     return( 0 );
  465. }
  466.  
  467.  
  468.  
  469. /*
  470. ** Retrieve a pixel value from a buffer.  The actual size and order
  471. ** of the bytes is not important since we are only using the value
  472. ** for comparisons with other pixels.
  473. */
  474.  
  475. unsigned long
  476. GetPixel( p, bpp )
  477. unsigned char    *p;
  478. int                bpp;        /* bytes per pixel */
  479. {
  480.     unsigned long    pixel;
  481.  
  482.     pixel = (unsigned long)*p++;
  483.     while ( bpp-- > 1 )
  484.     {
  485.         pixel <<= 8;
  486.         pixel |= (unsigned long)*p++;
  487.     }
  488.     return( pixel );
  489. }
  490.  
  491.  
  492.  
  493. int
  494. OutputTGAFile( ifp, ofp, sp )
  495. FILE        *ifp;        /* input file pointer */
  496. FILE        *ofp;        /* output file pointer */
  497. TGAFile        *sp;        /* output TGA structure */
  498. {
  499.     long            byteCount;
  500.     unsigned long    fileOffset;
  501.     int                i;
  502.     int                bytesPerPixel;
  503.     int                bCount;
  504.     int                rleCount;
  505.     unsigned char    *imageBuff;
  506.     unsigned char    *packBuff;
  507.     unsigned char    outType;
  508.     unsigned char    outDepth;
  509.     unsigned char    outDesc;
  510.  
  511.     /*
  512.     ** First, we need to determine what operation is to be performed.
  513.     ** We could be run length encoding an uncompressed image, or
  514.     ** we could be uncompressing an RLE image.  Or we could be compacting
  515.     ** a 32 bit image to a 24 bit image.
  516.     */
  517.     if ( noAlpha )
  518.     {
  519.         if ( sp->pixelDepth != 32 || sp->imageType != 2 )
  520.         {
  521.             puts( "Image file must be in 32 bit uncompressed format." );
  522.             return( -1 );
  523.         }
  524.         else
  525.         {
  526.             outDepth = 24;
  527.             outType = sp->imageType;
  528.             outDesc = sp->imageDesc & 0xf0;
  529.         }
  530.     }
  531.     else if ( !unPack && sp->imageType > 0 &&  sp->imageType < 4 )
  532.     {
  533.         outType = sp->imageType + 8;
  534.         outDepth = sp->pixelDepth;
  535.         outDesc = sp->imageDesc;
  536.     }
  537.     else if ( unPack && sp->imageType > 8 && sp->imageType < 12 )
  538.     {
  539.         outType = sp->imageType - 8;
  540.         outDepth = sp->pixelDepth;
  541.         outDesc = sp->imageDesc;
  542.     }
  543.     else
  544.     {
  545.         puts( "File type is inconsistent with requested operation." );
  546.         return( -1 );
  547.     }
  548.     /*
  549.     ** The output file was just opened, so the first data
  550.     ** to be written is the standard header based on the
  551.     ** original TGA specification.
  552.     */
  553.     if ( WriteByte( sp->idLength, ofp ) < 0 ) return( -1 );
  554.     if ( WriteByte( sp->mapType, ofp ) < 0 ) return( -1 );
  555.     if ( WriteByte( outType, ofp ) < 0 ) return( -1 );
  556.     if ( WriteShort( sp->mapOrigin, ofp ) < 0 ) return( -1 );
  557.     if ( WriteShort( sp->mapLength, ofp ) < 0 ) return( -1 );
  558.     if ( WriteByte( sp->mapWidth, ofp ) < 0 ) return( -1 );
  559.     if ( WriteShort( sp->xOrigin, ofp ) < 0 ) return( -1 );
  560.     if ( WriteShort( sp->yOrigin, ofp ) < 0 ) return( -1 );
  561.     if ( WriteShort( sp->imageWidth, ofp ) < 0 ) return( -1 );
  562.     if ( WriteShort( sp->imageHeight, ofp ) < 0 ) return( -1 );
  563.     if ( WriteByte( outDepth, ofp ) < 0 ) return( -1 );
  564.     if ( WriteByte( outDesc, ofp ) < 0 ) return( -1 );
  565.     if ( sp->idLength )
  566.     {
  567.         if ( WriteStr( sp->idString, sp->idLength, ofp ) < 0 )
  568.             return( -1 );
  569.     }
  570.     /*
  571.     ** Now we need to copy the color map data from the input file
  572.     ** to the output file.
  573.     */
  574.     byteCount = 18 + sp->idLength;
  575.     if ( fseek( ifp, byteCount, SEEK_SET ) != 0 ) return( -1 );
  576.     byteCount = ((sp->mapWidth + 7) >> 3) * (long)sp->mapLength;
  577.     fileOffset = 18 + sp->idLength + byteCount;
  578.     while ( byteCount > 0 )
  579.     {
  580.         if ( byteCount - CBUFSIZE < 0 )
  581.         {
  582.             fread( copyBuf, 1, (int)byteCount, ifp );
  583.             if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
  584.                 return( -1 );
  585.         }
  586.         else
  587.         {
  588.             fread( copyBuf, 1, CBUFSIZE, ifp );
  589.             if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
  590.                 return( -1 );
  591.         }
  592.         byteCount -= CBUFSIZE;
  593.     }
  594.     /*
  595.     ** Now process the image data.
  596.     */
  597.     bytesPerPixel = (sp->pixelDepth + 7) >> 3;
  598.     bCount = sp->imageWidth * bytesPerPixel;
  599.     if ( (imageBuff = malloc( bCount )) == NULL )
  600.     {
  601.         puts( "Unable to allocate image buffer" );
  602.         return( -1 );
  603.     }
  604.  
  605.     if ( noAlpha )
  606.     {
  607.         for ( i = 0; i < sp->imageHeight; ++i )
  608.         {
  609.             if ( fread( imageBuff, 1, bCount, ifp ) != bCount )
  610.             {
  611.                 puts( "Error reading uncompressed data." );
  612.                 free( imageBuff );
  613.                 return( -1 );
  614.             }
  615.             StripAlpha( imageBuff, bCount );
  616.             if ( fwrite( imageBuff, 1, bCount - sp->imageWidth, ofp ) !=
  617.                     bCount - sp->imageWidth )
  618.             {
  619.                 puts( "Error writing 24 bit image data." );
  620.                 free( imageBuff );
  621.                 return( -1 );
  622.             }
  623.         }
  624.     }
  625.     else if ( !unPack )
  626.     {
  627.         if ( (packBuff = malloc( sp->imageWidth * (bytesPerPixel + 1) )) == NULL )
  628.         {
  629.             puts( "Error allocating encoded buffer." );
  630.             free( imageBuff );
  631.             return( -1 );
  632.         }
  633.         for ( i = 0; i < sp->imageHeight; ++i )
  634.         {
  635.             if ( fread( imageBuff, 1, bCount, ifp ) != bCount )
  636.             {
  637.                 puts( "Error reading uncompressed data." );
  638.                 free( imageBuff );
  639.                 free( packBuff );
  640.                 return( -1 );
  641.             }
  642.             rleCount = RLEncodeRow( imageBuff, packBuff, sp->imageWidth,
  643.                             bytesPerPixel );
  644.             if ( fwrite( packBuff, 1, rleCount, ofp ) != rleCount )
  645.             {
  646.                 puts( "Error writing RLE image data." );
  647.                 free( imageBuff );
  648.                 free( packBuff );
  649.                 return( -1 );
  650.             }
  651.         }
  652.         free( packBuff );
  653.     }
  654.     else
  655.     {
  656.         /*
  657.         ** Uncompress image data
  658.         */
  659.         for ( i = 0; i < sp->imageHeight; ++i )
  660.         {
  661.             if ( ReadRLERow( imageBuff, bCount, bytesPerPixel, ifp ) < 0 )
  662.             {
  663.                 puts("Error reading RLE data." );
  664.                 free( imageBuff );
  665.                 return( -1 );
  666.             }
  667.             if ( fwrite( imageBuff, 1, bCount, ofp ) != bCount )
  668.             {
  669.                 puts("Error writing uncompressed data." );
  670.                 free( imageBuff );
  671.                 return( -1 );
  672.             }
  673.         }
  674.     }
  675.     free( imageBuff );
  676.  
  677.     return( 0 );
  678. }
  679.  
  680.  
  681.  
  682. int
  683. ParseArgs( argc, argv )
  684. int        argc;
  685. char    **argv;
  686. {
  687.     int        i;
  688.     int        n;
  689.     char    *p;
  690.  
  691.     n = 0;
  692.     for ( i = 1; i < argc; ++i )
  693.     {
  694.         p = *(++argv);
  695.         if ( *p == '-' )
  696.         {
  697.             p++;
  698.             if ( stricmp( p, "unpack" ) == 0 ) unPack = 1;
  699.             else if ( stricmp( p, "32to24" ) == 0 ) noAlpha = 1;
  700.             else if ( stricmp( p, "version" ) == 0 )
  701.             {
  702.                 puts( versionStr );
  703.                 exit( 0 );
  704.             }
  705.             else
  706.             {
  707.                 puts( "Usage: tgapack [options] [file1] [file2...]" );
  708.                 puts( "  where options can be:" );
  709.                 puts( "    -unpack\t\tuncompress image data" );
  710.                 puts( "    -32to24\t\tconvert 32 bit image to 24 bit image" );
  711.                 puts( "    -version\t\treport version number" );
  712.                 exit( 0 );
  713.             }
  714.         }
  715.         else ++n;
  716.     }
  717.     return( n );
  718. }
  719.  
  720.  
  721.  
  722.  
  723. void
  724. PrintImageType( Itype )
  725. register int Itype;
  726. {
  727.     if ( Itype > 255 || Itype < 0 )
  728.     {
  729.         puts("Illegal/Undefined Image Type");
  730.         return;
  731.     }
  732.  
  733.     if ( Itype > 127 )
  734.     {
  735.         puts("Unknown Image Type - Application Specific");
  736.         return;
  737.     }
  738.  
  739.     switch (Itype)
  740.     {
  741.     case 0:
  742.         puts("Unknown Image Type - No Image Data Present");
  743.         break;
  744.     case 1:
  745.         puts("Uncompressed Color Mapped Image (e.g., VDA/D, TARGA M8)");
  746.         break;
  747.     case 2:
  748.         puts("Uncompressed True Color Image (e.g., ICB, TARGA 16/24/32)");
  749.         break;
  750.     case 3:
  751.         puts("Uncompressed Black & White Image (e.g., TARGA 8/M8)");
  752.         break;
  753.     case 9:
  754.         puts("Run Length Encoded Color Mapped Image (e.g., VDA/D, TARGA M8)");
  755.         break;
  756.     case 10:
  757.         puts("Run Length Encoded True Color Image (e.g., ICB, TARGA 16/24/32)");
  758.         break;
  759.     case 11:
  760.         puts("Compressed Black & White Image (e.g., TARGA 8/M8)");
  761.         break;
  762.     case 32:
  763.     case 34:
  764.         puts("Compressed (Huffman/Delta/RLE) Color Mapped Image (e.g., VDA/D) - Obsolete");
  765.         break;
  766.     case 33:
  767.     case 35:
  768.         puts("Compressed (Huffman/Delta/RLE) Color Mapped Four Pass Image (e.g., VDA/D) - Obsolete");
  769.         break;
  770.     default:
  771.         puts("Unknown Image Type");
  772.         break;
  773.     }
  774. }
  775.  
  776.  
  777.  
  778.  
  779. void
  780. PrintTGAInfo( sp )
  781. TGAFile *sp;        /* TGA structure pointer */
  782. {
  783.     int    i;
  784.  
  785.     printf("ID Field Length          = %3d\n", sp->idLength);
  786.  
  787.     printf("Color Map Type           = %3d  (Color Map Data is ", sp->mapType);
  788.     if (sp->mapType) puts("Present)");
  789.     else puts("Absent)");  
  790.  
  791.     printf("Image Type               = %3d\n  ", sp->imageType);
  792.     PrintImageType( sp->imageType );
  793.  
  794.     printf("Color Map Origin         = 0x%04x (%5d)",
  795.         sp->mapOrigin, sp->mapOrigin);
  796.     puts( "  (First Index To Be Loaded)" );
  797.     printf("Color Map Length         = 0x%04x (%5d)\n",
  798.         sp->mapLength,sp->mapLength);
  799.     printf("Color Map Entry Size     = %6d\n", sp->mapWidth);
  800.  
  801.     printf("Image X-Origin, Y-Origin =  %05d, %05d\n",
  802.         sp->xOrigin, sp->yOrigin);
  803.     printf("Image Width, Height      =  %05d, %05d\n",
  804.             sp->imageWidth, sp->imageHeight);
  805.  
  806.     printf("Image Pixel Depth        = 0x%04x (%05d)\n",
  807.         sp->pixelDepth, sp->pixelDepth);
  808.     printf("Image Descriptor         = 0x%04x\n", sp->imageDesc);
  809.     printf("  %d Attribute Bits Per Pixel\n", sp->imageDesc & 0xf );
  810.     printf("  First Pixel Destination is ");
  811.  
  812.     i = (sp->imageDesc & 0x30) >> 4;
  813.     puts( orientStr[i] );
  814.  
  815.     i = (sp->imageDesc & 0xc0) >> 6;
  816.     if ( i > 0 && i < 3 ) puts( interleaveStr[i - 1] );
  817.  
  818.     if ( sp->idLength )
  819.     {
  820.         printf( "Image ID:\n  " );
  821.         puts( f.idString );
  822.     }
  823. }
  824.  
  825.  
  826. UINT8
  827. ReadByte( fp )
  828. FILE *fp;
  829. {
  830.     UINT8    value;
  831.  
  832. #if MSDOS
  833.     fread( &value, 1, 1, fp );
  834. #else
  835. #endif
  836.     return( value );
  837. }
  838.  
  839.  
  840. void
  841. ReadCharField( fp, p, n )
  842. FILE    *fp;
  843. char    *p;
  844. int        n;
  845. {
  846.     while ( n )
  847.     {
  848.         *p++ = (char)fgetc( fp );    /* no error check, no char conversion */
  849.         --n;
  850.     }
  851. }
  852.  
  853.  
  854.  
  855.  
  856. UINT32
  857. ReadLong( fp )
  858. FILE *fp;
  859. {
  860.     UINT32    value;
  861.  
  862. #if MSDOS
  863.     fread( &value, 4, 1, fp );
  864. #else
  865. #endif
  866.     return( value );
  867. }
  868.  
  869.  
  870.  
  871. int
  872. ReadRLERow( p, n, bpp, fp )
  873. unsigned char    *p;
  874. int        n;            /* buffer size in bytes */
  875. int        bpp;        /* bytes per pixel */
  876. FILE    *fp;
  877. {
  878.     unsigned int            value;
  879.     int                        i;
  880.     static unsigned char    *q;
  881.  
  882.     while ( n > 0 )
  883.     {
  884.         if ( inRLEPacket )
  885.         {
  886.             if ( packetSize * bpp > n )
  887.             {
  888.                 value = n / bpp;        /* calculate pixel count */
  889.                 packetSize -= value;
  890.                 n = 0;
  891.             }
  892.             else
  893.             {
  894.                 n -= packetSize * bpp;
  895.                 value = packetSize;
  896.                 packetSize = 0;
  897.                 inRLEPacket = 0;
  898.             }
  899.             while ( value > 0 )
  900.             {
  901.                 *p++ = rleBuf[0];
  902.                 if ( bpp > 1 ) *p++ = rleBuf[1];
  903.                 if ( bpp > 2 ) *p++ = rleBuf[2];
  904.                 if ( bpp > 3 ) *p++ = rleBuf[3];
  905.                 value--;
  906.             }
  907.         }
  908.         else if ( inRawPacket )
  909.         {
  910.             if ( packetSize * bpp > n )
  911.             {
  912.                 value = n;
  913.                 packetSize -= n / bpp;
  914.                 n = 0;
  915.             }
  916.             else
  917.             {
  918.                 value = packetSize * bpp;    /* calculate byte count */
  919.                 n -= value;
  920.                 inRawPacket = 0;
  921.             }
  922.             for ( i = 0; i < value; ++i ) *p++ = *q++;
  923.         }
  924.         else
  925.         {
  926.             /*
  927.             ** No accumulated data in buffers, so read from file
  928.             */
  929.             packetSize = (unsigned int)ReadByte( fp );
  930.             if ( packetSize & 0x80 )
  931.             {
  932.                 packetSize &= 0x7f;
  933.                 packetSize++;
  934.                 if ( packetSize * bpp > n )
  935.                 {
  936.                     value = n / bpp;        /* calculate pixel count */
  937.                     packetSize -= value;
  938.                     inRLEPacket = 1;
  939.                     n = 0;
  940.                 }
  941.                 else
  942.                 {
  943.                     n -= packetSize * bpp;
  944.                     value = packetSize;
  945.                 }
  946.                 if ( fread( rleBuf, 1, bpp, fp ) != bpp ) return( -1 );
  947.                 while ( value > 0 )
  948.                 {
  949.                     *p++ = rleBuf[0];
  950.                     if ( bpp > 1 ) *p++ = rleBuf[1];
  951.                     if ( bpp > 2 ) *p++ = rleBuf[2];
  952.                     if ( bpp > 3 ) *p++ = rleBuf[3];
  953.                     value--;
  954.                 }
  955.             }
  956.             else
  957.             {
  958.                 packetSize++;
  959.                 /*
  960.                 ** Maximum for packetSize is 128 so as long as RLEBUFSIZ
  961.                 ** is at least 512, and bpp is not greater than 4
  962.                 ** we can read in the entire raw packet with one operation.
  963.                 */
  964.                 if ( fread( rleBuf, bpp, packetSize, fp ) != packetSize )
  965.                     return( -1 );
  966.                 /*
  967.                 ** But is there enough room to copy them to our line buffer?
  968.                 */
  969.                 if ( packetSize * bpp > n )
  970.                 {
  971.                     value = n;                /* number of bytes remaining */
  972.                     packetSize -= n / bpp;
  973.                     inRawPacket = 1;
  974.                     n = 0;
  975.                 }
  976.                 else
  977.                 {
  978.                     value = packetSize * bpp;    /* calculate byte count */
  979.                     n -= value;
  980.                 }
  981.                 for ( i = 0, q = rleBuf; i < value; ++i ) *p++ = *q++;
  982.             }
  983.         }
  984.     }
  985.     return( 0 );
  986. }
  987.  
  988.  
  989.  
  990.  
  991. UINT16
  992. ReadShort( fp )
  993. FILE *fp;
  994. {
  995.     UINT16    value;
  996.  
  997. #if MSDOS
  998.     fread( &value, 2, 1, fp );
  999. #else
  1000. #endif
  1001.     return( value );
  1002. }
  1003.  
  1004.  
  1005.  
  1006. int
  1007. RLEncodeRow( p, q, n, bpp )
  1008. char    *p;            /* data to be encoded */
  1009. char    *q;            /* encoded buffer */
  1010. int        n;            /* number of pixels in buffer */
  1011. int        bpp;        /* bytes per pixel */
  1012. {
  1013.     int                diffCount;        /* pixel count until two identical */
  1014.     int                sameCount;        /* number of identical adjacent pixels */
  1015.     int                RLEBufSize;        /* count of number of bytes encoded */
  1016.  
  1017.     RLEBufSize = 0;
  1018.     while ( n > 0 )
  1019.     {
  1020.         diffCount = CountDiffPixels( p, bpp, n );
  1021.         sameCount = CountSamePixels( p, bpp, n );
  1022.         if ( diffCount > 128 ) diffCount = 128;
  1023.         if ( sameCount > 128 ) sameCount = 128;
  1024.         if ( diffCount > 0 )
  1025.         {
  1026.             /* create a raw packet */
  1027.             *q++ = (char)(diffCount - 1);
  1028.             n -= diffCount;
  1029.             RLEBufSize += (diffCount * bpp) + 1;
  1030.             while ( diffCount > 0 )
  1031.             {
  1032.                 *q++ = *p++;
  1033.                 if ( bpp > 1 ) *q++ = *p++;
  1034.                 if ( bpp > 2 ) *q++ = *p++;
  1035.                 if ( bpp > 3 ) *q++ = *p++;
  1036.                 diffCount--;
  1037.             }
  1038.         }
  1039.         if ( sameCount > 1 )
  1040.         {
  1041.             /* create a RLE packet */
  1042.             *q++ = (char)((sameCount - 1) | 0x80);
  1043.             n -= sameCount;
  1044.             RLEBufSize += bpp + 1;
  1045.             p += (sameCount - 1) * bpp;
  1046.             *q++ = *p++;
  1047.             if ( bpp > 1 ) *q++ = *p++;
  1048.             if ( bpp > 2 ) *q++ = *p++;
  1049.             if ( bpp > 3 ) *q++ = *p++;
  1050.         }
  1051.     }
  1052.     return( RLEBufSize );
  1053. }
  1054.  
  1055.  
  1056.  
  1057. char *
  1058. SkipBlank( p )
  1059. char    *p;
  1060. {
  1061.     while ( *p != '\0' && (*p == ' ' || *p == '\t') ) ++p;
  1062.     return( p );
  1063. }
  1064.  
  1065.  
  1066.  
  1067. void
  1068. StripAlpha( s, n )
  1069. unsigned char    *s;
  1070. int                n;
  1071. {
  1072.     int                i;
  1073.     unsigned char    *p;
  1074.  
  1075.     /*
  1076.     ** Copy the RGB components omitting the alpha.  Perform the
  1077.     ** copy in its own buffer.  This algorithm is probably
  1078.     ** specific to the 80x86 since byte orderring will be different
  1079.     ** on a 680x0 processor.
  1080.     */
  1081.     p = s;
  1082.     for ( i = 0; i < n; ++i )
  1083.     {
  1084.         if ( ( i % 4) == 3 ) ++p;
  1085.         else *s++ = *p++;
  1086.     }
  1087. }
  1088.  
  1089.  
  1090. int
  1091. WriteByte( uc, fp )
  1092. UINT8    uc;
  1093. FILE    *fp;
  1094. {
  1095. #ifdef MSDOS
  1096.     if ( fwrite( &uc, 1, 1, fp ) == 1 ) return( 0 );
  1097. #else
  1098. #endif
  1099.     return( -1 );
  1100. }
  1101.  
  1102.  
  1103.  
  1104. int
  1105. WriteLong( ul, fp )
  1106. UINT32    ul;
  1107. FILE    *fp;
  1108. {
  1109. #ifdef MSDOS
  1110.     if ( fwrite( &ul, 4, 1, fp ) == 1 ) return( 0 );
  1111. #else
  1112. #endif
  1113.     return( -1 );
  1114. }
  1115.  
  1116.  
  1117. int
  1118. WriteShort( us, fp )
  1119. UINT16    us;
  1120. FILE    *fp;
  1121. {
  1122. #ifdef MSDOS
  1123.     if ( fwrite( &us, 2, 1, fp ) == 1 ) return( 0 );
  1124. #else
  1125. #endif
  1126.     return( -1 );
  1127. }
  1128.  
  1129.  
  1130. int
  1131. WriteStr( p, n, fp )
  1132. char    *p;
  1133. int        n;
  1134. FILE    *fp;
  1135. {
  1136. #ifdef MSDOS
  1137.     if ( fwrite( p, 1, n, fp ) == n ) return( 0 );
  1138. #else
  1139. #endif
  1140.     return( -1 );
  1141. }
  1142.