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

  1. /*
  2. ** Copyright (c) 1989, 1990
  3. ** Truevision, Inc.
  4. ** All Rights Reserverd
  5. **
  6. ** TGAEDIT reads the contents of a Truevision TGA(tm) File and provides
  7. ** the ability to edit various fields from the console.  It will also
  8. ** convert an original TGA file to the new extended TGA file format.
  9. **
  10. ** USAGE:
  11. **        tgaedit [options] [file1] [file2] ...
  12. **
  13. ** If no filenames are provided, the program will prompt for a file
  14. ** name.  If no extension is provided with a filename, the program
  15. ** will search for the file with ".tga", ".vst", ".icb", ".vda", or
  16. ** ".win" extension.  Options are specified by a leading '-'.
  17. **
  18. ** Recognized options are:
  19. **
  20. **        -noprompt        converts old TGA to new TGA without prompting for data
  21. **        -nostamp        omits creation of postage stamp
  22. **        -all            enables editing of all fields of TGA file, the
  23. **                        default only processes non-critical fields.
  24. **        -noextend        force output file to be old TGA format
  25. **        -nodev            disables copying of developer area
  26. **        -nocolor        disables copying of color correction table
  27. **        -noscan            disables copying of scan line offset table
  28. **        -version        report version number of program
  29. */
  30.  
  31. #include <conio.h>
  32. #include <graph.h>
  33. #include <io.h>
  34. #include <malloc.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include "tga.h"
  41.  
  42. /*
  43. ** Define byte counts associated with extension areas for various
  44. ** versions of the TGA specification.
  45. */
  46. #define    EXT_SIZE_20    495            /* verison 2.0 extension size */
  47.  
  48. #define    WARN        1            /* provides warning message during edit */
  49. #define    NOWARN        0
  50.  
  51. #define CBUFSIZE    2048        /* size of copy buffer */
  52. #define RLEBUFSIZ    512            /* size of largest possible RLE packet */
  53.  
  54.  
  55. extern void        main( int, char ** );
  56. extern int        CountDiffPixels( char *, int, int );
  57. extern long        CountRLEData( FILE *, unsigned int, unsigned int, int );
  58. extern int        CountSamePixels( char *, int, int );
  59. extern int        CreatePostageStamp( FILE *, TGAFile *, TGAFile * );
  60. extern int        DisplayImageData( unsigned char *, int, int );
  61. extern int        EditHexNumber( char *, long int, unsigned long int *, long int,
  62.                     long int, int );
  63. extern int        EditDecimalNumber( char *, long int, long int *, long int,
  64.                     long int, int );
  65. extern int        EditString( char *, int, char *, int );
  66. extern int        EditTGAFields( TGAFile * );
  67. extern UINT32    GetPixel( unsigned char *, int );
  68. extern int        OutputTGAFile( FILE *, FILE *, TGAFile *, TGAFile *, int,
  69.                     struct stat * );
  70. extern int        ParseArgs( int, char ** );
  71. extern void        PrintColorTable( TGAFile * );
  72. extern void        PrintExtendedTGA( TGAFile * );
  73. extern void        PrintImageType( int );
  74. extern void        PrintMonth( UINT16 );
  75. extern void        PrintScanLineTable( TGAFile * );
  76. extern void        PrintTGAInfo( TGAFile * );
  77. extern UINT8    ReadByte( FILE * );
  78. extern void        ReadCharField( FILE *, char *, int );
  79. extern int        ReadColorTable( FILE *, TGAFile * );
  80. extern int        ReadDeveloperDirectory( FILE *, TGAFile * );
  81. extern int        ReadExtendedTGA( FILE *, TGAFile * );
  82. extern UINT32    ReadLong( FILE * );
  83. extern int        ReadRLERow( unsigned char *, int, int, FILE * );
  84. extern int        ReadScanLineTable( FILE *, TGAFile * );
  85. extern UINT16    ReadShort( FILE * );
  86. extern int        RLEncodeRow( char *, char *, int, int );
  87. extern char        *SkipBlank( char * );
  88. extern int        WriteByte( UINT8, FILE * );
  89. extern int        WriteColorTable( FILE *, TGAFile * );
  90. extern int        WriteLong( UINT32, FILE * );
  91. extern int        WriteShort( UINT16, FILE * );
  92. extern int        WriteStr( char *, int, FILE * );
  93.  
  94.  
  95. /*
  96. ** String data for performing month conversions
  97. */
  98. char    *monthStr[] =
  99. {
  100.     "January",
  101.     "February",
  102.     "March",
  103.     "April",
  104.     "May",
  105.     "June",
  106.     "July",
  107.     "August",
  108.     "September",
  109.     "October",
  110.     "November",
  111.     "December"
  112. };
  113.  
  114. /*
  115. ** String data for interpretting image orientation specification
  116. */
  117. char    *orientStr[] =
  118. {
  119.     "Bottom Left",
  120.     "Bottom Right",
  121.     "Top Left",
  122.     "Top Right"
  123. };
  124.  
  125. /*
  126. ** String data for interpretting interleave flag defined with VDA
  127. ** This field is now obsolete and should typically be set to zero.
  128. */
  129. char    *interleaveStr[] =
  130. {
  131.     "  Two Way (Even-Odd) Interleave (e.g., IBM Graphics Card Adapter), Obsolete",
  132.     "  Four Way Interleave (e.g., AT&T 6300 High Resolution), Obsolete",
  133. };
  134.  
  135. /*
  136. ** Filename extensions used during file search
  137. */
  138. char    *extNames[] =
  139. {
  140.     ".tga",
  141.     ".vst",
  142.     ".icb",
  143.     ".vda",
  144.     ".win",
  145.     NULL
  146. };
  147.  
  148. TGAFile        f;                /* control structure of image data */
  149. TGAFile        nf;                /* edited version of input structure */
  150.  
  151. int            noPrompt;        /* when true, conversion done without prompts */
  152. int            noStamp;        /* when true, postage stamp omitted from output */
  153. int            noDev;            /* when true, developer area does not get copied */
  154. int            noColor;        /* when true, color correction table omitted */
  155. int            noScan;            /* when true, scan line table omitted */
  156. int            allFields;        /* when true, enables editing of all TGA fields */
  157. int            noExtend;        /* when true, output old TGA format */
  158.  
  159. char        rleBuf[RLEBUFSIZ];
  160.  
  161. char        copyBuf[CBUFSIZE];
  162.  
  163.  
  164. char        *versionStr =
  165. "Truevision(R) TGA(tm) File Edit Utility Version 2.0 - March 24, 1990";
  166.  
  167. char        *warnStr =
  168. "WARNING: Changing this value may cause loss or corruption of data.";
  169.  
  170. void
  171. main( argc, argv )
  172. int argc;
  173. char **argv;
  174. {
  175.     int            fileFound;
  176.     int            fileCount;
  177.     int            files;
  178.     char        *q;
  179.     FILE        *fp, *outFile;
  180.     long        fsize;
  181.     int            xTGA;            /* flags extended TGA file */
  182.     int            i;
  183.     char        fileName[80];
  184.     char        outFileName[80];
  185.     struct stat    statbuf;
  186.  
  187.     noPrompt = 0;        /* default to prompting for changes */
  188.     noStamp = 0;        /* default to creating postage stamp */
  189.     noDev = 0;            /* default to copying developer area, if present */
  190.     noColor = 0;        /* default to copying color correction table */
  191.     noScan = 0;            /* default to copying scan line offset table */
  192.     allFields = 0;        /* default to non-critical fields */
  193.     noExtend = 0;        /* defalut to output new extended TGA format */
  194.  
  195.     /*
  196.     ** The program can be invoked without an argument, in which case
  197.     ** the user will be prompted for the name of the image file to be
  198.     ** examined, or the image file name can be provided as an argument
  199.     ** to the command.
  200.     **
  201.     ** File names provided do not need to include the extension if
  202.     ** the image file extension is one of the standard strings common
  203.     ** to Truevision TGA image file names ( e.g., TGA, WIN, VST, VDA, ICB )
  204.     */
  205.     if ( argc == 1 )
  206.     {
  207.         puts( versionStr );
  208.         printf( "Enter name of file to examine: " );
  209.         gets( fileName );
  210.         if ( strlen( fileName ) == 0 ) exit(0);
  211.         fileCount = 1;
  212.     }
  213.     else
  214.     {
  215.         fileCount = ParseArgs( argc, argv );
  216.         if ( fileCount == 0 ) exit( 0 );
  217.         argv++;
  218.         while ( **argv == '-' ) argv++; 
  219.         strcpy( fileName, *argv );
  220.     }
  221.     for ( files = 0; files < fileCount; ++files )
  222.     {
  223.         if ( files != 0 )
  224.         {
  225.             argv++;
  226.             while ( **argv == '-' ) argv++; 
  227.             strcpy( fileName, *argv );
  228.         }
  229.         /*
  230.         ** See if we can find the file as specified or with one of the
  231.         ** standard filename extensions...
  232.         */
  233.         fileFound = 0;
  234.         if ( stat( fileName, &statbuf ) == 0 ) fileFound = 1;
  235.         else
  236.         {
  237.             /*
  238.             ** If there is already an extension specified, skip
  239.             ** the search for standard extensions
  240.             */
  241.             q = strchr( fileName, '.' );
  242.             if ( q != NULL )
  243.             {
  244.                 q = fileName + strlen( fileName );
  245.             }
  246.             else
  247.             {
  248.                 i = 0;
  249.                 strcat( fileName, extNames[i] );
  250.                 q = strchr( fileName, '.' );
  251.                 while ( extNames[i] != NULL )
  252.                 {
  253.                     strcpy( q, extNames[i] );
  254.                     if ( stat( fileName, &statbuf ) == 0 )
  255.                     {
  256.                         fileFound = 1;
  257.                         break;
  258.                     }
  259.                     ++i;
  260.                 }
  261.             }
  262.         }
  263.         if ( fileFound )
  264.         {
  265.             _clearscreen( _GCLEARSCREEN );
  266.             printf( "Editing TGA File: %s\n", fileName );
  267.             fp = fopen( fileName, "rb" );
  268.             /*
  269.             ** It would be nice to be able to read in the entire
  270.             ** structure with one fread, but compiler dependent
  271.             ** structure alignment precludes the simplistic approach.
  272.             ** Instead, fill each field individually, and use routines
  273.             ** that will allow code to execute on various hosts by
  274.             ** recompilation with particular compiler flags.
  275.             **
  276.             ** Start by reading the fields associated with the original
  277.             ** TGA format.
  278.             */
  279.             f.idLength = ReadByte( fp );
  280.             f.mapType = ReadByte( fp );
  281.             f.imageType = ReadByte( fp );
  282.             f.mapOrigin = ReadShort( fp );
  283.             f.mapLength = ReadShort( fp );
  284.             f.mapWidth = ReadByte( fp );
  285.             f.xOrigin = ReadShort( fp );
  286.             f.yOrigin = ReadShort( fp );
  287.             f.imageWidth = ReadShort( fp );
  288.             f.imageHeight = ReadShort( fp );
  289.             f.pixelDepth = ReadByte( fp );
  290.             f.imageDesc = ReadByte( fp );
  291.             memset( f.idString, 0, 256 );
  292.             if ( f.idLength > 0 )
  293.             {
  294.                 fread( f.idString, 1, f.idLength, fp );
  295.             }
  296.             /*
  297.             ** Now see if the file is the new (extended) TGA format.
  298.             */
  299.             xTGA = 0;
  300.             if ( !fseek( fp, statbuf.st_size - 26, SEEK_SET ) )
  301.             {
  302.                 f.extAreaOffset = ReadLong( fp );
  303.                 f.devDirOffset = ReadLong( fp );
  304.                 fgets( f.signature, 18, fp );
  305.                 if ( strcmp( f.signature, "TRUEVISION-XFILE." ) )
  306.                 {
  307.                     /*
  308.                     ** Reset offset values since this is not a new TGA file
  309.                     */
  310.                     f.extAreaOffset = 0L;
  311.                     f.devDirOffset = 0L;
  312.                 }
  313.                 else xTGA = 1;
  314.                 /*
  315.                 ** If the file is an original TGA file, and falls into
  316.                 ** one of the uncompressed image types, we can perform
  317.                 ** an additional file size check with very little effort.
  318.                 */
  319.                 if ( f.imageType > 0 && f.imageType < 4 && !xTGA )
  320.                 {
  321.                     /*
  322.                     ** Based on the header info, we should be able to calculate
  323.                     ** the input file size.
  324.                     */
  325.                     fsize = 18;    /* size of header in bytes */
  326.                     fsize += f.idLength;
  327.                     /* expect 8, 15, 16, 24, or 32 bits per map entry */
  328.                     fsize += ((f.mapWidth + 7) >> 3) * (long)f.mapLength;
  329.                     fsize += ((f.pixelDepth + 7) >> 3) * (long)f.imageWidth *
  330.                                 f.imageHeight;
  331.                     if ( fsize != statbuf.st_size )
  332.                     {
  333.                         /*
  334.                         ** Report the error, but continue to process file.
  335.                         */
  336.                         puts( "Image File Format Error." );
  337.                         printf("  Uncompressed File Size Should Be %ld Bytes\n",
  338.                             fsize );
  339.                     }
  340.                 }
  341.                 if ( xTGA && f.extAreaOffset )
  342.                 {
  343.                     if ( ReadExtendedTGA( fp, &f ) < 0 ) exit(1);
  344.                 }
  345.                 if ( xTGA && f.devDirOffset )
  346.                 {
  347.                     if ( ReadDeveloperDirectory( fp, &f ) < 0 ) exit(1);
  348.                 }
  349.                 if ( !noPrompt )
  350.                 {
  351.                     printf( "Press ENTER to continue: " );
  352.                     gets( outFileName );
  353.                 }
  354.                 /*
  355.                 ** Now that we have gathered all this data from the input
  356.                 ** file, ask the user which fields should be changed.
  357.                 */
  358.                 nf = f;
  359.                 if ( noPrompt || EditTGAFields( &nf ) >= 0 )
  360.                 {
  361.                     if ( !noPrompt ) puts( "(Updating File)" );
  362.                     /*
  363.                     ** If the changes were successful, write out a new
  364.                     ** file with the changed data
  365.                     */
  366.                     strcpy( outFileName, fileName );
  367.                     i = strlen( fileName );
  368.                     outFileName[ i - 3 ] = '\0';    /* remove extension */
  369.                     strcat( outFileName, "$$$" );
  370.                     if ( ( outFile = fopen( outFileName, "wb" ) ) != NULL )
  371.                     {
  372.                         if ( OutputTGAFile( fp, outFile, &f, &nf, xTGA, &statbuf ) < 0 )
  373.                         {
  374.                             fclose( outFile );
  375.                             unlink( outFileName );
  376.                             puts( "Error writing output file. No changes made." );
  377.                         }
  378.                         else
  379.                         {
  380.                             fclose( outFile );
  381.                             fclose( fp );
  382.                             fp = (FILE *)0;
  383.                             unlink( fileName );
  384.                             rename( outFileName, fileName );
  385.                         }
  386.                     }
  387.                     else
  388.                     {
  389.                         puts( "Unable to create output file." );
  390.                     }
  391.                 }
  392.             }
  393.             else
  394.             {
  395.                 puts( "Error seeking to end of file for possible extension data." );
  396.             }
  397.             if ( f.scanLineTable ) free( f.scanLineTable );
  398.             if ( f.postStamp ) free( f.postStamp );
  399.             if ( f.colorCorrectTable ) free( f.colorCorrectTable );
  400.             if ( f.devDirs ) free( f.devDirs );
  401.             if ( fp != NULL ) fclose( fp );
  402.         }
  403.         else
  404.         {
  405.             *q = '\0';
  406.             printf("Unable to open image file %s\n", fileName );
  407.         }
  408.     }
  409. }
  410.  
  411.  
  412.  
  413. /*
  414. ** Count pixels in buffer until two identical adjacent ones found
  415. */
  416.  
  417. int
  418. CountDiffPixels( p, bpp, pixCnt )
  419. char    *p;
  420. int        bpp;
  421. int        pixCnt;
  422. {
  423.     unsigned long    pixel;
  424.     unsigned long    nextPixel;
  425.     int                n;
  426.  
  427.     n = 0;
  428.     if ( pixCnt == 1 ) return( pixCnt );
  429.     pixel = GetPixel( p, bpp );
  430.     while ( pixCnt > 1 )
  431.     {
  432.         p += bpp;
  433.         nextPixel = GetPixel( p, bpp );
  434.         if ( nextPixel == pixel ) break;
  435.         pixel = nextPixel;
  436.         ++n;
  437.         --pixCnt;
  438.     }
  439.     if ( nextPixel == pixel ) return( n );
  440.     return( n + 1 );
  441. }
  442.  
  443.  
  444.  
  445. long
  446. CountRLEData( fp, x, y, bytesPerPixel )
  447. FILE            *fp;
  448. unsigned int    x;
  449. unsigned int    y;
  450. int                bytesPerPixel;
  451. {
  452.     long            n;
  453.     long            pixelCount;
  454.     long            totalPixels;
  455.     unsigned int    value;
  456.  
  457.     n = 0L;
  458.     pixelCount = 0L;
  459.     totalPixels = (long)x * (long)y;
  460.  
  461.     while ( pixelCount < totalPixels )
  462.     {
  463.         value = (unsigned int)ReadByte( fp );
  464.         n++;
  465.         if ( value & 0x80 )
  466.         {
  467.             n += bytesPerPixel;
  468.             pixelCount += (value & 0x7f) + 1;
  469.             if ( fread( copyBuf, 1, bytesPerPixel, fp ) != bytesPerPixel )
  470.             {
  471.                 puts( "Error counting RLE data." );
  472.                 return( 0L );
  473.             }
  474.         }
  475.         else
  476.         {
  477.             value++;
  478.             n += value * bytesPerPixel;
  479.             pixelCount += value;
  480.             if ( fread( copyBuf, bytesPerPixel, value, fp ) != value )
  481.             {
  482.                 puts( "Error counting raw data." );
  483.                 return( 0L );
  484.             }
  485.         }
  486.     }
  487.     return( n );
  488. }
  489.  
  490.  
  491.  
  492. int
  493. CountSamePixels( p, bpp, pixCnt )
  494. char    *p;
  495. int        bpp;
  496. int        pixCnt;
  497. {
  498.     unsigned long    pixel;
  499.     unsigned long    nextPixel;
  500.     int                n;
  501.  
  502.     n = 1;
  503.     pixel = GetPixel( p, bpp );
  504.     pixCnt--;
  505.     while ( pixCnt > 0 )
  506.     {
  507.         p += bpp;
  508.         nextPixel = GetPixel( p, bpp );
  509.         if ( nextPixel != pixel ) break;
  510.         ++n;
  511.         --pixCnt;
  512.     }
  513.     return( n );
  514. }
  515.  
  516.  
  517.  
  518. int
  519. CreatePostageStamp( fp, isp, sp )
  520. FILE    *fp;
  521. TGAFile    *isp;
  522. TGAFile    *sp;
  523. {
  524.     int            i;
  525.     int            j;
  526.     int            dx, dy;
  527.     int            dxAdj;
  528.     int            imageXAdj, imageYAdj;
  529.     int            maxY;
  530.     int            bufSize;
  531.     int            bytesPerPixel;
  532.     int            stampSize;
  533.     long int    fileOffset;
  534.     unsigned char    *p, *q;
  535.     unsigned char    *rowBuf;
  536.  
  537.     /*
  538.     ** Create a postage stamp if reasonable to do so...
  539.     ** Since the postage stamp size is set to 64 x 64, we
  540.     ** require the image to be at least twice this resolution
  541.     ** before it makes sense to increase the file size by 50%.
  542.     ** The handling of run length encoded data also represents
  543.     ** a more troublesome problem.
  544.     */
  545.     if ( sp->imageWidth > 127 && sp->imageHeight > 127 )
  546.     {
  547.         /*
  548.         ** The postage stamp is created by sampling the image data.
  549.         ** The adjustment values cause the samples to be taken from
  550.         ** the middle of the skipped range, as well as from the middle
  551.         ** of the image.
  552.         */
  553.         dx = sp->imageWidth >> 6;
  554.         dxAdj = dx >> 1;
  555.         imageXAdj = ( sp->imageWidth % 64 ) >> 1;
  556.         dy = sp->imageHeight >> 6;
  557.         imageYAdj = ( sp->imageHeight % 64 ) >> 1;
  558.         maxY = 64 * dy + imageYAdj;
  559.  
  560.         bytesPerPixel = ( sp->pixelDepth + 7 ) >> 3;
  561.         bufSize = bytesPerPixel * sp->imageWidth;
  562.  
  563.         stampSize = 64 * 64 * bytesPerPixel;
  564.         if ( ( sp->postStamp = malloc( stampSize ) ) == NULL )
  565.             return( -1 );
  566.         memset( sp->postStamp, 0, stampSize );
  567.         fileOffset = 18 + isp->idLength + 
  568.             ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
  569.         if ( fseek( fp, fileOffset, SEEK_SET ) != 0 ) return( -1 );
  570.  
  571.         if ( ( rowBuf = malloc( bufSize ) ) != NULL )
  572.         {
  573.             q = sp->postStamp;
  574.             for ( i = 0; i < maxY; ++i )
  575.             {
  576.                 if ( sp->imageType > 0 && sp->imageType < 4 )
  577.                 {
  578.                     fread( rowBuf, 1, bufSize, fp );
  579.                 }
  580.                 else if ( sp->imageType > 8 && sp->imageType < 12 )
  581.                 {
  582.                     if ( ReadRLERow( rowBuf, bufSize, bytesPerPixel, fp ) < 0 )
  583.                     {
  584.                         puts( "Error reading RLE data during stamp creation." );
  585.                         return( -1 );
  586.                     }
  587.                 }
  588.                 else
  589.                 {
  590.                     puts( "Unknown Image Type." );
  591.                     sp->stampOffset = NULL;
  592.                     return( -1 );
  593.                 }
  594.                 if ( i < imageYAdj || ((i - imageYAdj) % dy) ) continue;
  595.                 p = rowBuf + ( bytesPerPixel * (imageXAdj + dxAdj) );
  596.                 for ( j = 0; j < 64; ++j )
  597.                 {
  598.                     *q++ = *p;
  599.                     if ( bytesPerPixel > 1 ) *q++ = *(p + 1);
  600.                     if ( bytesPerPixel > 2 ) *q++ = *(p + 2);
  601.                     if ( bytesPerPixel > 3 ) *q++ = *(p + 3);
  602.                     p += dx * bytesPerPixel;
  603.                 }
  604.             }
  605.             free( rowBuf );
  606.             sp->stampWidth = sp->stampHeight = 64;
  607.         }
  608.         else
  609.         {
  610.             puts( "Unable to create row buffer." );
  611.             return( -1 );
  612.         }
  613.     }
  614.     else
  615.     {
  616.         sp->stampOffset = NULL;
  617.     }
  618.     return( 0 );
  619. }
  620.  
  621.  
  622.  
  623.  
  624. int
  625. DisplayImageData( q, n, bpp )
  626. unsigned char *q;
  627. int    n;
  628. int    bpp;
  629. {
  630.     long i;
  631.     int j;
  632.     unsigned char a, b, c;
  633.  
  634.     i = 0;
  635.     while ( i < n ) 
  636.     {
  637.         printf( "%08lX: ", i );
  638.         switch ( bpp )
  639.         {
  640.         case 4:
  641.             for ( j = 0; j < 4; ++j )
  642.             {
  643.                 printf( "%08lx ", *(unsigned long *)q );
  644.                 q += 4;
  645.             }
  646.             i += 16;
  647.             break;
  648.         case 3:
  649.             for ( j = 0; j < 8; ++j )
  650.             {
  651.                 a = *q++;
  652.                 b = *q++;
  653.                 c = *q++;
  654.                 printf( "%02x%02x%02x ", c, b, a );
  655.             }
  656.             i += 24;
  657.             break;
  658.         case 2:
  659.             for ( j = 0; j < 8; ++j )
  660.             {
  661.                 printf( "%04x ", *(unsigned int *)q );
  662.                 q += 2;
  663.             }
  664.             i += 16;
  665.             break;
  666.         default:
  667.             for ( j = 0; j < 16; ++j )
  668.             {
  669.                 printf( "%02x ", *(unsigned char *)q++ );
  670.             }
  671.             i += 16;
  672.             break;
  673.         }
  674.         putchar( '\n' );
  675.     }
  676.     return( 0 );
  677. }
  678.  
  679.  
  680.  
  681. int
  682. EditDecimalNumber( s, n, retVal, min, max, warning )
  683. char    *s;
  684. long    n;
  685. long    *retVal;
  686. long    min;
  687. long    max;
  688. int        warning;
  689. {
  690.     int        i;
  691.     int        c;
  692.     char    *p;
  693.     char    str[20];
  694.  
  695.     do
  696.     {
  697.         _clearscreen( _GCLEARSCREEN );
  698.         puts( s );
  699.         printf( "%ld\n\n", n );
  700.         printf( "Enter new value (min = %ld, max = %ld), ESC for no change:\n",
  701.                 min, max );
  702.         if ( warning ) puts( warnStr );
  703.         p = str;
  704.         memset( str, 0, 20 );
  705.         for ( i = 0; i < 19; ++i )
  706.         {
  707.             c = getche();
  708.             if ( c == '\033' )
  709.             {
  710.                 putchar( '\n' );
  711.                 return( -1 );
  712.             }
  713.             if ( c == '\n' || c == '\r' )
  714.             {
  715.                 putch( '\n' );
  716.                 if ( *str == '\0' ) return( -1 );
  717.                 break;
  718.             }
  719.             if ( c == '\b' )
  720.             {
  721.                 if ( p > str ) --p;
  722.                 if ( i > 0 ) --i;
  723.                 *p = '\0';
  724.                 putch( ' ' );
  725.                 putch( '\b' );
  726.             }
  727.             else *p++ = (char)c;
  728.         }
  729.         *retVal = atol( str );
  730.     } while ( *retVal < min || *retVal > max );
  731.     return( 0 );
  732. }
  733.  
  734.  
  735.  
  736. int
  737. EditHexNumber( s, n, retVal, min, max, warning )
  738. char            *s;
  739. long            n;
  740. unsigned long    *retVal;
  741. long            min;
  742. long            max;
  743. int                warning;
  744. {
  745.     int        i;
  746.     int        c;
  747.     char    *p;
  748.     char    str[20];
  749.  
  750.     do
  751.     {
  752.         _clearscreen( _GCLEARSCREEN );
  753.         puts( s );
  754.         printf( "%lx\n\n", n );
  755.         printf( "Enter new hexadecimal value (min = %lx, max = %lx), ESC for no change:\n",
  756.                 min, max );
  757.         if ( warning ) puts( warnStr );
  758.         p = str;
  759.         memset( str, 0, 20 );
  760.         for ( i = 0; i < 19; ++i )
  761.         {
  762.             c = getche();
  763.             if ( c == '\033' )
  764.             {
  765.                 putchar( '\n' );
  766.                 return( -1 );
  767.             }
  768.             if ( c == '\n' || c == '\r' )
  769.             {
  770.                 putch( '\n' );
  771.                 if ( *str == '\0' ) return( -1 );
  772.                 break;
  773.             }
  774.             if ( c == '\b' )
  775.             {
  776.                 if ( p > str ) --p;
  777.                 if ( i > 0 ) --i;
  778.                 *p = '\0';
  779.                 putch( ' ' );
  780.                 putch( '\b' );
  781.             }
  782.             else *p++ = (char)c;
  783.         }
  784.         sscanf( str, "%lx", retVal );
  785.     } while ( *retVal < min || *retVal > max );
  786.     return( 0 );
  787. }
  788.  
  789.  
  790.  
  791. int
  792. EditString( is, il, os, ol )
  793. char    *is;
  794. int        il;
  795. char    *os;
  796. int        ol;
  797. {
  798.     int        i;
  799.     int        c;
  800.     char    *p;
  801.     char    *q;
  802.  
  803.     q = is;
  804.     for ( i = 0; i < il; ++i )
  805.     {
  806.         if ( i > 0 && (i % 80) == 0 ) putchar( '\n' );
  807.         if ( *q ) putchar( *q );
  808.         else break;
  809.         ++q;
  810.     }
  811.     printf( "\n\nEnter new string (max %d characters), ESC for no change:\n", ol );
  812.     p = os;
  813.     for ( i = 0; i < ol; ++i )
  814.     {
  815.         c = getche();
  816.         if ( c == '\033' )
  817.         {
  818.             putchar( '\n' );
  819.             return( -1 );
  820.         }
  821.         if ( c == '\n' || c == '\r' )
  822.         {
  823.             putch( '\n' );
  824.             /* remove blank string if found */
  825.             c = strlen( is );
  826.             if ( *os == '\0' && c > 0 && SkipBlank( is ) != (is + c) )
  827.                 return( -1 );
  828.             break;
  829.         }
  830.         if ( c == '\b' )
  831.         {
  832.             if ( p > os ) --p;
  833.             if ( i > 0 ) --i;
  834.             *p = '\0';
  835.             putch( ' ' );
  836.             putch( '\b' );
  837.         }
  838.         else *p++ = (char)c;
  839.     }
  840.     return( 0 );
  841. }
  842.  
  843.  
  844.  
  845. int
  846. EditTGAFields( sp )
  847. TGAFile    *sp;
  848. {
  849.     long    value;
  850.     char    txt[256];
  851.  
  852.     if ( allFields )
  853.     {
  854.         if ( EditDecimalNumber( "Color Map Type:",
  855.             (long)sp->mapType, &value, 0L, 1L, WARN ) == 0 )
  856.         {
  857.             sp->mapType = (UINT8)value;
  858.         }
  859.         if ( EditDecimalNumber( "Image Type:",
  860.             (long)sp->imageType, &value, 0L, 11L, WARN ) == 0 )
  861.         {
  862.             sp->imageType = (UINT8)value;
  863.         }
  864.         if ( EditDecimalNumber( "Color Map Origin:",
  865.             (long)sp->mapOrigin, &value, 0L, 65535L, WARN ) == 0 )
  866.         {
  867.             sp->mapOrigin = (UINT16)value;
  868.         }
  869.         if ( EditDecimalNumber( "Color Map Length:",
  870.             (long)sp->mapLength, &value, 0L, 65535L, WARN ) == 0 )
  871.         {
  872.             sp->mapLength = (UINT16)value;
  873.         }
  874.         if ( EditDecimalNumber( "Color Map Entry Size:",
  875.             (long)sp->mapWidth, &value, 0L, 32L, WARN ) == 0 )
  876.         {
  877.             sp->mapWidth = (UINT8)value;
  878.         }
  879.         if ( EditDecimalNumber( "Image X Origin:",
  880.             (long)sp->xOrigin, &value, 0L, 65535L, NOWARN ) == 0 )
  881.         {
  882.             sp->xOrigin = (UINT16)value;
  883.         }
  884.         if ( EditDecimalNumber( "Image Y Origin:",
  885.             (long)sp->yOrigin, &value, 0L, 65535L, NOWARN ) == 0 )
  886.         {
  887.             sp->yOrigin = (UINT16)value;
  888.         }
  889.         if ( EditDecimalNumber( "Image Width:",
  890.             (long)sp->imageWidth, &value, 0L, 65535L, WARN ) == 0 )
  891.         {
  892.             sp->imageWidth = (UINT16)value;
  893.         }
  894.         if ( EditDecimalNumber( "Image Height:",
  895.             (long)sp->imageHeight, &value, 0L, 65535L, WARN ) == 0 )
  896.         {
  897.             sp->imageHeight = (UINT16)value;
  898.         }
  899.         if ( EditDecimalNumber( "Pixel Depth:",
  900.             (long)sp->pixelDepth, &value, 0L, 32L, WARN ) == 0 )
  901.         {
  902.             sp->pixelDepth = (UINT8)value;
  903.         }
  904.         if ( EditHexNumber( "Image Descriptor:",
  905.             (long)sp->imageDesc, &value, 0L, 0xffL, NOWARN ) == 0 )
  906.         {
  907.             sp->imageDesc = (UINT8)value;
  908.         }
  909.     }
  910.  
  911.     memset( txt, 0, 256 );
  912.     _clearscreen( _GCLEARSCREEN );
  913.     puts( "Current ID String:" );
  914.     if ( EditString( sp->idString, sp->idLength, txt, 255 ) == 0 )
  915.     {
  916.         strcpy( sp->idString, txt );
  917.         sp->idLength = (UINT8)strlen( sp->idString );
  918.     }
  919.  
  920.     /*
  921.     ** If creating old TGA format output, no need to edit remaining
  922.     ** fields...
  923.     */
  924.     if ( noExtend ) return( 0 );
  925.  
  926.     memset( txt, 0, 256 );
  927.     _clearscreen( _GCLEARSCREEN );
  928.     puts( "Author Name:" );
  929.     if ( EditString( sp->author, strlen( sp->author), txt, 40 ) == 0 )
  930.     {
  931.         strcpy( sp->author, txt );
  932.     }
  933.     memset( txt, 0, 256 );
  934.     _clearscreen( _GCLEARSCREEN );
  935.     puts( "Author Comments (line 1):" );
  936.     if ( EditString( &sp->authorCom[0][0], strlen( &sp->authorCom[0][0] ),
  937.             txt, 80 ) == 0 )
  938.     {
  939.         strcpy( &sp->authorCom[0][0], txt );
  940.     }
  941.     memset( txt, 0, 256 );
  942.     _clearscreen( _GCLEARSCREEN );
  943.     puts( "Author Comments (line 2):" );
  944.     if ( EditString( &sp->authorCom[1][0], strlen( &sp->authorCom[1][0] ),
  945.             txt, 80 ) == 0 )
  946.     {
  947.         strcpy( &sp->authorCom[1][0], txt );
  948.     }
  949.     memset( txt, 0, 256 );
  950.     _clearscreen( _GCLEARSCREEN );
  951.     puts( "Author Comments (line 3):" );
  952.     if ( EditString( &sp->authorCom[2][0], strlen( &sp->authorCom[2][0] ),
  953.             txt, 80 ) == 0 )
  954.     {
  955.         strcpy( &sp->authorCom[2][0], txt );
  956.     }
  957.     memset( txt, 0, 256 );
  958.     _clearscreen( _GCLEARSCREEN );
  959.     puts( "Author Comments (line 4):" );
  960.     if ( EditString( &sp->authorCom[3][0], strlen( &sp->authorCom[3][0] ),
  961.             txt, 80 ) == 0 )
  962.     {
  963.         strcpy( &sp->authorCom[3][0], txt );
  964.     }
  965.  
  966.     if ( EditDecimalNumber( "Date/Time Stamp (month):",
  967.         (long)sp->month, &value, 0L, 12L, NOWARN ) == 0 )
  968.     {
  969.         sp->month = (UINT16)value;
  970.     }
  971.  
  972.     if ( EditDecimalNumber( "Date/Time Stamp (day):",
  973.             (long)sp->day, &value, 0L, 31L, NOWARN ) == 0 )
  974.     {
  975.         sp->day = (UINT16)value;
  976.     }
  977.  
  978.     /*
  979.     ** Minimum and maximum year values are rather arbitrary...
  980.     */
  981.     if ( EditDecimalNumber( "Date/Time Stamp (year):",
  982.             (long)sp->year, &value, 1975L, 2200L, NOWARN ) == 0 )
  983.     {
  984.         sp->year = (UINT16)value;
  985.     }
  986.  
  987.     if ( EditDecimalNumber( "Date/Time Stamp (hour):",
  988.             (long)sp->hour, &value, 0L, 23L, NOWARN ) == 0 )
  989.     {
  990.         sp->hour = (UINT16)value;
  991.     }
  992.  
  993.     if ( EditDecimalNumber( "Date/Time Stamp (minute):",
  994.             (long)sp->minute, &value, 0L, 59L, NOWARN ) == 0 )
  995.     {
  996.         sp->minute = (UINT16)value;
  997.     }
  998.  
  999.     if ( EditDecimalNumber( "Date/Time Stamp (second):",
  1000.             (long)sp->second, &value, 0L, 59L, NOWARN ) == 0 )
  1001.     {
  1002.         sp->second = (UINT16)value;
  1003.     }
  1004.     memset( txt, 0, 256 );
  1005.     _clearscreen( _GCLEARSCREEN );
  1006.     puts( "Job Name/ID:" );
  1007.     if ( EditString( sp->jobID, strlen( sp->jobID), txt, 40 ) == 0 )
  1008.     {
  1009.         strcpy( sp->jobID, txt );
  1010.     }
  1011.  
  1012.     if ( EditDecimalNumber( "Job Time (hours):",
  1013.             (long)sp->jobHours, &value, 0L, 65535L, NOWARN ) == 0 )
  1014.     {
  1015.         sp->jobHours = (UINT16)value;
  1016.     }
  1017.  
  1018.     if ( EditDecimalNumber( "Job Time (minutes):",
  1019.             (long)sp->jobMinutes, &value, 0L, 59L, NOWARN ) == 0 )
  1020.     {
  1021.         sp->jobMinutes = (UINT16)value;
  1022.     }
  1023.  
  1024.     if ( EditDecimalNumber( "Job Time (seconds):",
  1025.             (long)sp->jobSeconds, &value, 0L, 59L, NOWARN ) == 0 )
  1026.     {
  1027.         sp->jobSeconds = (UINT16)value;
  1028.     }
  1029.  
  1030.     memset( txt, 0, 256 );
  1031.     _clearscreen( _GCLEARSCREEN );
  1032.     puts( "Software ID:" );
  1033.     if ( EditString( sp->softID, strlen( sp->softID), txt, 40 ) == 0 )
  1034.     {
  1035.         strcpy( sp->softID, txt );
  1036.     }
  1037.  
  1038.     if ( EditDecimalNumber( "Software Version Number * 100:",
  1039.             (long)sp->versionNum, &value, 0L, 65535L, NOWARN ) == 0 )
  1040.     {
  1041.         sp->versionNum = (UINT16)value;
  1042.     }
  1043.  
  1044.     memset( txt, 0, 256 );
  1045.     _clearscreen( _GCLEARSCREEN );
  1046.     puts( "Software Version Letter:" );
  1047.     if ( EditString( &sp->versionLet, strlen( &sp->versionLet), txt, 1 ) == 0 )
  1048.     {
  1049.         sp->versionLet = txt[0];
  1050.     }
  1051.     if ( sp->versionLet == '\0' ) sp->versionLet = ' ';
  1052.  
  1053.     if ( EditHexNumber( "Key Color (ARGB):",
  1054.             sp->keyColor, (unsigned long *)&value, 0L, 0xffffffffL, NOWARN ) == 0 )
  1055.     {
  1056.         sp->keyColor = (UINT32)value;
  1057.     }
  1058.  
  1059.     if ( EditDecimalNumber( "Pixel Aspect Ratio Numerator (width):",
  1060.             (long)sp->pixNumerator, &value, 0L, 32767L, NOWARN ) == 0 )
  1061.     {
  1062.         sp->pixNumerator = (UINT16)value;
  1063.     }
  1064.  
  1065.     if ( EditDecimalNumber( "Pixel Aspect Ratio Denominator (height):",
  1066.             (long)sp->pixDenominator, &value, 0L, 32767L, NOWARN ) == 0 )
  1067.     {
  1068.         sp->pixDenominator = (UINT16)value;
  1069.     }
  1070.  
  1071.     if ( EditDecimalNumber( "Gamma Correction Ratio Numerator:",
  1072.             (long)sp->gammaNumerator, &value, 0L, 32767L, NOWARN ) == 0 )
  1073.     {
  1074.         sp->gammaNumerator = (UINT16)value;
  1075.     }
  1076.  
  1077.     if ( EditDecimalNumber( "Gamma Correction Ratio Denominator:",
  1078.             (long)sp->gammaDenominator, &value, 0L, 32767L, NOWARN ) == 0 )
  1079.     {
  1080.         sp->gammaDenominator = (UINT16)value;
  1081.     }
  1082.  
  1083.     if ( EditDecimalNumber( "Alpha Attributes Type:",
  1084.             (long)sp->alphaAttribute, &value, 0L, 255L, NOWARN ) == 0 )
  1085.     {
  1086.         sp->alphaAttribute = (UINT8)value;
  1087.     }
  1088.     /*
  1089.     ** Attempt to make the alpha descriptor fields consistent
  1090.     */
  1091.     if ( sp->alphaAttribute == 0 && (sp->imageDesc & 0xf) != 0 )
  1092.     {
  1093.         sp->alphaAttribute = 2;
  1094.     }
  1095.  
  1096.     return( 0 );    /* return 0 for success, -1 to abort */
  1097. }
  1098.  
  1099.  
  1100.  
  1101. /*
  1102. ** Retrieve a pixel value from a buffer.  The actual size and order
  1103. ** of the bytes is not important since we are only using the value
  1104. ** for comparisons with other pixels.
  1105. */
  1106.  
  1107. unsigned long
  1108. GetPixel( p, bpp )
  1109. unsigned char    *p;
  1110. int                bpp;        /* bytes per pixel */
  1111. {
  1112.     unsigned long    pixel;
  1113.  
  1114.     pixel = (unsigned long)*p++;
  1115.     while ( bpp-- > 1 )
  1116.     {
  1117.         pixel <<= 8;
  1118.         pixel |= (unsigned long)*p++;
  1119.     }
  1120.     return( pixel );
  1121. }
  1122.  
  1123.  
  1124.  
  1125. int
  1126. OutputTGAFile( ifp, ofp, isp, sp, xTGA, isbp )
  1127. FILE        *ifp;        /* input file pointer */
  1128. FILE        *ofp;        /* output file pointer */
  1129. TGAFile        *isp;        /* input TGA structure */
  1130. TGAFile        *sp;        /* output TGA structure */
  1131. int            xTGA;        /* flags input file as new TGA format */
  1132. struct stat    *isbp;
  1133. {
  1134.     long            byteCount;
  1135.     long            imageByteCount;
  1136.     unsigned long    fileOffset;
  1137.     int                i;
  1138.     int                bytesPerPixel;
  1139.  
  1140.     /*
  1141.     ** The output file was just opened, so the first data
  1142.     ** to be written is the standard header based on the
  1143.     ** original TGA specification.
  1144.     */
  1145.     if ( WriteByte( sp->idLength, ofp ) < 0 ) return( -1 );
  1146.     if ( WriteByte( sp->mapType, ofp ) < 0 ) return( -1 );
  1147.     if ( WriteByte( sp->imageType, ofp ) < 0 ) return( -1 );
  1148.     if ( WriteShort( sp->mapOrigin, ofp ) < 0 ) return( -1 );
  1149.     if ( WriteShort( sp->mapLength, ofp ) < 0 ) return( -1 );
  1150.     if ( WriteByte( sp->mapWidth, ofp ) < 0 ) return( -1 );
  1151.     if ( WriteShort( sp->xOrigin, ofp ) < 0 ) return( -1 );
  1152.     if ( WriteShort( sp->yOrigin, ofp ) < 0 ) return( -1 );
  1153.     if ( WriteShort( sp->imageWidth, ofp ) < 0 ) return( -1 );
  1154.     if ( WriteShort( sp->imageHeight, ofp ) < 0 ) return( -1 );
  1155.     if ( WriteByte( sp->pixelDepth, ofp ) < 0 ) return( -1 );
  1156.     if ( WriteByte( sp->imageDesc, ofp ) < 0 ) return( -1 );
  1157.     if ( sp->idLength )
  1158.     {
  1159.         if ( WriteStr( sp->idString, sp->idLength, ofp ) < 0 )
  1160.             return( -1 );
  1161.     }
  1162.     /*
  1163.     ** Now we need to copy the color map data from the input file
  1164.     ** to the output file.
  1165.     */
  1166.     byteCount = 18 + isp->idLength;
  1167.     if ( fseek( ifp, byteCount, SEEK_SET ) != 0 ) return( -1 );
  1168.     byteCount = ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
  1169.     fileOffset = 18 + sp->idLength + byteCount;
  1170.     while ( byteCount > 0 )
  1171.     {
  1172.         if ( byteCount - CBUFSIZE < 0 )
  1173.         {
  1174.             fread( copyBuf, 1, (int)byteCount, ifp );
  1175.             if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
  1176.                 return( -1 );
  1177.         }
  1178.         else
  1179.         {
  1180.             fread( copyBuf, 1, CBUFSIZE, ifp );
  1181.             if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
  1182.                 return( -1 );
  1183.         }
  1184.         byteCount -= CBUFSIZE;
  1185.     }
  1186.     /*
  1187.     ** Similarly, the image data can now be copied.
  1188.     ** This gets a little trickier since the input image could
  1189.     ** be compressed or the file could be in the new TGA format...
  1190.     */
  1191.     bytesPerPixel = (isp->pixelDepth + 7) >> 3;
  1192.     if ( isp->imageType > 0 && isp->imageType < 4 )
  1193.     {
  1194.         byteCount = bytesPerPixel *
  1195.                     (long)isp->imageWidth *
  1196.                     (long)isp->imageHeight;
  1197.     }
  1198.     else if ( isp->imageType > 8 && isp->imageType < 12 )
  1199.     {
  1200.         imageByteCount = CountRLEData( ifp, isp->imageWidth,
  1201.                 isp->imageHeight, bytesPerPixel );
  1202.         /* Recalculate offset to beginning of image data */
  1203.         byteCount = 18 + isp->idLength;
  1204.         byteCount += ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
  1205.         if ( fseek( ifp, byteCount, SEEK_SET ) != 0 ) return( -1 );
  1206.         byteCount = imageByteCount;
  1207.     }
  1208.     else if ( !xTGA )
  1209.     {
  1210.         /*
  1211.         ** If the file is not an extended TGA file, we can
  1212.         ** calculate the image byte count based upon the size
  1213.         ** of the file (hopefully).
  1214.         */
  1215.         byteCount = 18 + isp->idLength;
  1216.         byteCount += ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
  1217.         byteCount = isbp->st_size - byteCount;
  1218.     }
  1219.     else
  1220.     {
  1221.         puts( "Cannot determine amount of image data" );
  1222.         return( -1 );
  1223.     }
  1224.     fileOffset += byteCount;
  1225.     while ( byteCount > 0 )
  1226.     {
  1227.         if ( byteCount - CBUFSIZE < 0 )
  1228.         {
  1229.             fread( copyBuf, 1, (int)byteCount, ifp );
  1230.             if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
  1231.                 return( -1 );
  1232.         }
  1233.         else
  1234.         {
  1235.             fread( copyBuf, 1, CBUFSIZE, ifp );
  1236.             if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
  1237.                 return( -1 );
  1238.         }
  1239.         byteCount -= CBUFSIZE;
  1240.     }
  1241.  
  1242.     if ( noExtend ) return( 0 );
  1243.  
  1244.     /*
  1245.     ** Attempt to preserve developer area if it exists in the input file
  1246.     */
  1247.     if ( !noDev && isp->devDirOffset != NULL )
  1248.     {
  1249.         if ( (sp->devDirs = malloc( sp->devTags * sizeof(DevDir) ) ) == NULL )
  1250.         {
  1251.             puts( "Failed to allocate memory for new developer directory." );
  1252.             return( -1 );
  1253.         }
  1254.         for ( i = 0; i < sp->devTags; ++i )
  1255.         {
  1256.             if ( fseek( ifp, isp->devDirs[i].tagOffset, SEEK_SET ) != 0 )
  1257.             {
  1258.                 puts( "Error seeking to developer entry." );
  1259.                 free( sp->devDirs );
  1260.                 return( -1 );
  1261.             }
  1262.             sp->devDirs[i].tagOffset = fileOffset;
  1263.             byteCount = isp->devDirs[i].tagSize;
  1264.             fileOffset += byteCount;
  1265.             while ( byteCount > 0 )
  1266.             {
  1267.                 if ( byteCount - CBUFSIZE < 0 )
  1268.                 {
  1269.                     fread( copyBuf, 1, (int)byteCount, ifp );
  1270.                     if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
  1271.                         return( -1 );
  1272.                 }
  1273.                 else
  1274.                 {
  1275.                     fread( copyBuf, 1, CBUFSIZE, ifp );
  1276.                     if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
  1277.                         return( -1 );
  1278.                 }
  1279.                 byteCount -= CBUFSIZE;
  1280.             }
  1281.         }
  1282.         sp->devDirOffset = fileOffset;
  1283.         WriteShort( sp->devTags, ofp );
  1284.         byteCount = (long)sp->devTags * sizeof( DevDir );
  1285.         if ( (long)fwrite( sp->devDirs, 1, (int)byteCount, ofp ) != byteCount )
  1286.         {
  1287.             puts( "Error writing developer area." );
  1288.             free( sp->devDirs );
  1289.             return( -1 );
  1290.         }
  1291.         fileOffset += byteCount + 2;
  1292.         free( sp->devDirs );
  1293.     }
  1294.  
  1295.     /*
  1296.     ** Unlike the figure in the specification, we will output
  1297.     ** the scan line table, the postage stamp, and the color
  1298.     ** correction table before we output the extension area.
  1299.     ** This simply makes the calculation of the offset values
  1300.     ** easier to manage...
  1301.     ** Copy the scan line table from the input file to
  1302.     ** the output file.  A future version could create the table
  1303.     ** if it does not already exist.
  1304.     */
  1305.     if ( !noScan && isp->scanLineOffset != 0L )
  1306.     {
  1307.         if ( fseek( ifp, isp->scanLineOffset, SEEK_SET ) != 0 )
  1308.             return( -1 );
  1309.         sp->scanLineOffset = fileOffset;
  1310.         for ( i = 0; i < sp->imageHeight; ++i )
  1311.         {
  1312.             if ( WriteLong( ReadLong( ifp ), ofp ) < 0 ) return( -1 );
  1313.         }
  1314.         fileOffset += sp->imageHeight * sizeof( UINT32 );
  1315.     }
  1316.  
  1317.     /*
  1318.     ** Either copy the postage stamp from the input file to
  1319.     ** the output file, or create one.
  1320.     */
  1321.     if ( !noStamp )
  1322.     {
  1323.         if ( isp->stampOffset != NULL )
  1324.         {
  1325.             if ( fseek( ifp, isp->stampOffset, SEEK_SET ) != 0 )
  1326.                 return( -1 );
  1327.             /*
  1328.             ** Since postage stamps are uncompressed, calculation
  1329.             ** of its size is straight forward.
  1330.             */
  1331.             byteCount = bytesPerPixel *
  1332.                         (long)isp->stampWidth *
  1333.                         (long)isp->stampHeight + 2;
  1334.  
  1335.             sp->stampOffset = fileOffset;
  1336.             fileOffset += byteCount;
  1337.             while ( byteCount > 0 )
  1338.             {
  1339.                 if ( byteCount - CBUFSIZE < 0 )
  1340.                 {
  1341.                     fread( copyBuf, 1, (int)byteCount, ifp );
  1342.                     if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
  1343.                         return( -1 );
  1344.                 }
  1345.                 else
  1346.                 {
  1347.                     fread( copyBuf, 1, CBUFSIZE, ifp );
  1348.                     if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
  1349.                         return( -1 );
  1350.                 }
  1351.                 byteCount -= CBUFSIZE;
  1352.             }
  1353.         }
  1354.         else
  1355.         {
  1356.             if ( (isp->imageType > 0 && isp->imageType < 4 ) ||
  1357.                  (isp->imageType > 8 && isp->imageType < 12 ) )
  1358.             {
  1359.                 if ( CreatePostageStamp( ifp, isp, sp ) >= 0 && sp->postStamp )
  1360.                 {
  1361.                     sp->stampOffset = fileOffset;
  1362.                     WriteByte( sp->stampWidth, ofp );
  1363.                     WriteByte( sp->stampHeight, ofp );
  1364.                     i = sp->stampWidth * sp->stampHeight *
  1365.                         bytesPerPixel;
  1366.                     fileOffset += i + 2;
  1367.                     if ( fwrite( sp->postStamp, 1, i, ofp ) != i )
  1368.                     {
  1369.                         puts( "Error writing postage stamp." );
  1370.                         return( -1 );
  1371.                     }
  1372.                 }
  1373.                 else
  1374.                 {
  1375.                     if ( sp->postStamp )
  1376.                         puts( "Error creating postage stamp." );
  1377.                     else
  1378.                         puts( "Image size too small for stamp" );
  1379.                     return( -1 );
  1380.                 }
  1381.             }
  1382.             else
  1383.             {
  1384.                 puts( "Do not know how to create postage stamp." );
  1385.             }
  1386.         }
  1387.     }
  1388.     else sp->stampOffset = 0L;
  1389.  
  1390.     /*
  1391.     ** Next copy the Color Correction Table to the output file
  1392.     */
  1393.     if ( !noColor && sp->colorCorrectTable != NULL )
  1394.     {
  1395.         sp->colorCorrectOffset = fileOffset;
  1396.         if ( WriteColorTable( ofp, sp ) < 0 ) return( -1 );
  1397.         fileOffset += 1024 * sizeof(UINT16);
  1398.     }
  1399.  
  1400.     /*
  1401.     ** Output TGA extension area - version 2.0 format
  1402.     */
  1403.     sp->extAreaOffset = fileOffset;
  1404.     if ( WriteShort( EXT_SIZE_20, ofp ) < 0 ) return( -1 );
  1405.     if ( WriteStr( sp->author, 41, ofp ) < 0 ) return( -1 );
  1406.     if ( WriteStr( &sp->authorCom[0][0], 81, ofp ) < 0 ) return( -1 );
  1407.     if ( WriteStr( &sp->authorCom[1][0], 81, ofp ) < 0 ) return( -1 );
  1408.     if ( WriteStr( &sp->authorCom[2][0], 81, ofp ) < 0 ) return( -1 );
  1409.     if ( WriteStr( &sp->authorCom[3][0], 81, ofp ) < 0 ) return( -1 );
  1410.     if ( WriteShort( sp->month, ofp ) < 0 ) return( -1 );
  1411.     if ( WriteShort( sp->day, ofp ) < 0 ) return( -1 );
  1412.     if ( WriteShort( sp->year, ofp ) < 0 ) return( -1 );
  1413.     if ( WriteShort( sp->hour, ofp ) < 0 ) return( -1 );
  1414.     if ( WriteShort( sp->minute, ofp ) < 0 ) return( -1 );
  1415.     if ( WriteShort( sp->second, ofp ) < 0 ) return( -1 );
  1416.     if ( WriteStr( sp->jobID, 41, ofp ) < 0 ) return( -1 );
  1417.     if ( WriteShort( sp->jobHours, ofp ) < 0 ) return( -1 );
  1418.     if ( WriteShort( sp->jobMinutes, ofp ) < 0 ) return( -1 );
  1419.     if ( WriteShort( sp->jobSeconds, ofp ) < 0 ) return( -1 );
  1420.     if ( WriteStr( sp->softID, 41, ofp ) < 0 ) return( -1 );
  1421.     if ( WriteShort( sp->versionNum, ofp ) < 0 ) return( -1 );
  1422.     if ( sp->versionLet == '\0' ) sp->versionLet = ' ';
  1423.     if ( WriteByte( sp->versionLet, ofp ) < 0 ) return( -1 );
  1424.     if ( WriteLong( sp->keyColor, ofp ) < 0 ) return( -1 );
  1425.     if ( WriteShort( sp->pixNumerator, ofp ) < 0 ) return( -1 );
  1426.     if ( WriteShort( sp->pixDenominator, ofp ) < 0 ) return( -1 );
  1427.     if ( WriteShort( sp->gammaNumerator, ofp ) < 0 ) return( -1 );
  1428.     if ( WriteShort( sp->gammaDenominator, ofp ) < 0 ) return( -1 );
  1429.     if ( WriteLong( sp->colorCorrectOffset, ofp ) < 0 ) return( -1 );
  1430.     if ( WriteLong( sp->stampOffset, ofp ) < 0 ) return( -1 );
  1431.     if ( WriteLong( sp->scanLineOffset, ofp ) < 0 ) return( -1 );
  1432.     if ( WriteByte( sp->alphaAttribute, ofp ) < 0 ) return( -1 );
  1433.  
  1434.     /*
  1435.     ** For now, simply output extended tag info
  1436.     */
  1437.     if ( WriteLong( sp->extAreaOffset, ofp ) < 0 ) return( -1 );
  1438.     if ( WriteLong( sp->devDirOffset, ofp ) < 0 ) return( -1 );
  1439.     if ( WriteStr( "TRUEVISION-XFILE.\0", 18, ofp ) < 0 ) return( -1 );
  1440.     return( 0 );
  1441. }
  1442.  
  1443.  
  1444.  
  1445. int
  1446. ParseArgs( argc, argv )
  1447. int        argc;
  1448. char    **argv;
  1449. {
  1450.     int        i;
  1451.     int        n;
  1452.     char    *p;
  1453.  
  1454.     n = 0;
  1455.     for ( i = 1; i < argc; ++i )
  1456.     {
  1457.         p = *(++argv);
  1458.         if ( *p == '-' )
  1459.         {
  1460.             p++;
  1461.             if ( stricmp( p, "noprompt" ) == 0 ) noPrompt = 1;
  1462.             else if ( stricmp( p, "nostamp" ) == 0 ) noStamp = 1;
  1463.             else if ( stricmp( p, "all" ) == 0 ) allFields = 1;
  1464.             else if ( stricmp( p, "noextend" ) == 0 ) noExtend = 1;
  1465.             else if ( stricmp( p, "nodev" ) == 0 ) noDev = 1;
  1466.             else if ( stricmp( p, "nocolor" ) == 0 ) noColor = 1;
  1467.             else if ( stricmp( p, "noscan" ) == 0 ) noScan = 1;
  1468.             else if ( stricmp( p, "version" ) == 0 )
  1469.             {
  1470.                 puts( versionStr );
  1471.                 exit( 0 );
  1472.             }
  1473.             else
  1474.             {
  1475.                 puts( "Usage: tgaedit [options] [file1] [file2...]" );
  1476.                 puts( "  where options can be:" );
  1477.                 puts( "    -noprompt\t\tprocess without prompting for changes" );
  1478.                 puts( "    -nostamp\t\tsuppress postage stamp" );
  1479.                 puts( "    -nodev\t\tsuppress developer area" );
  1480.                 puts( "    -nocolor\t\tsuppress color correction table" );
  1481.                 puts( "    -noscan\t\tsuppress scan line offset table" );
  1482.                 puts( "    -all\t\tallow editing of all TGA fields" );
  1483.                 puts( "    -noextend\t\toutput old TGA format" );
  1484.                 puts( "    -version\t\treport version number" );
  1485.                 exit( 0 );
  1486.             }
  1487.         }
  1488.         else ++n;
  1489.     }
  1490.     return( n );
  1491. }
  1492.  
  1493.  
  1494. void
  1495. PrintColorTable( sp )
  1496. TGAFile    *sp;
  1497. {
  1498.     unsigned int    n;
  1499.     UINT16            *p;
  1500.  
  1501.     puts( "Color Correction Table:" );
  1502.     p = sp->colorCorrectTable;
  1503.     for ( n = 0; n < 256; ++n )
  1504.     {
  1505.         printf( "Color Entry %3u: 0x%04x(%5u) A, ", n, *p, *p );
  1506.         ++p;
  1507.         printf( "0x%04x(%5u) R, ", *p, *p );
  1508.         ++p;
  1509.         printf( "0x%04x(%5u) G, ", *p, *p );
  1510.         ++p;
  1511.         printf( "0x%04x(%5u) B\n", *p, *p );
  1512.         ++p;
  1513.     }
  1514. }
  1515.  
  1516.  
  1517.  
  1518. void
  1519. PrintExtendedTGA( sp )
  1520. TGAFile *sp;        /* TGA structure pointer */
  1521. {
  1522.     register int    strSize;
  1523.     char            *blankChars = " \t";
  1524.  
  1525.     puts( "***** Extended TGA Fields *****" );
  1526.     printf( "Truevision TGA File Format Version: " );
  1527.     if ( sp->extSize == EXT_SIZE_20 ) puts( "2.0" );
  1528.     else printf( "UNKNOWN, extension size = %d\n", sp->extSize );
  1529.  
  1530.     /*
  1531.     ** Make sure the strings have length, and contain something
  1532.     ** other than blanks and tabs
  1533.     */
  1534.     strSize = strlen( sp->author );
  1535.     if ( strSize && strspn( sp->author, blankChars ) < strSize )
  1536.     {
  1537.         printf( "Author: %s\n", sp->author );
  1538.     }
  1539.     strSize = strlen( &sp->authorCom[0][0] );
  1540.     if ( strSize && strspn( &sp->authorCom[0][0], blankChars ) < strSize )
  1541.     {
  1542.         puts( "Author Comments:" );
  1543.         puts( &sp->authorCom[0][0] );
  1544.         strSize = strlen( &sp->authorCom[1][0] );
  1545.         if ( strSize && strspn( &sp->authorCom[1][0], blankChars ) < strSize )
  1546.         {
  1547.             puts( &sp->authorCom[1][0] );
  1548.         }
  1549.         strSize = strlen( &sp->authorCom[2][0] );
  1550.         if ( strSize && strspn( &sp->authorCom[2][0], blankChars ) < strSize )
  1551.         {
  1552.             puts( &sp->authorCom[2][0] );
  1553.         }
  1554.         strSize = strlen( &sp->authorCom[3][0] );
  1555.         if ( strSize && strspn( &sp->authorCom[3][0], blankChars ) < strSize )
  1556.         {
  1557.             puts( &sp->authorCom[3][0] );
  1558.         }
  1559.         puts( "[End of Author Comments]" );
  1560.     }
  1561.  
  1562.     if ( sp->month )
  1563.     {
  1564.         printf( "Date Image Saved: " );
  1565.         PrintMonth( sp->month );
  1566.         printf( " %02u, %4u at %02u:%02u:%02u\n", sp->day, sp->year,
  1567.             sp->hour, sp->minute, sp->second );
  1568.     }
  1569.  
  1570.     strSize = strlen( sp->jobID );
  1571.     if ( strSize && strspn( sp->jobID, blankChars ) < strSize )
  1572.     {
  1573.         printf( "Job Name/ID: %s\n", sp->jobID );
  1574.     }
  1575.  
  1576.     if ( sp->jobHours != 0 || sp->jobMinutes != 0 || sp->jobSeconds != 0 )
  1577.     {
  1578.         printf( "Job Elapsed Time: %02u:%02u:%02u\n", sp->jobHours,
  1579.             sp->jobMinutes, sp->jobSeconds );
  1580.     }
  1581.  
  1582.     strSize = strlen( sp->softID );
  1583.     if ( strSize && strspn( sp->softID, blankChars ) < strSize )
  1584.     {
  1585.         printf( "Software ID: %s\n", sp->softID );
  1586.     }
  1587.  
  1588.     if ( sp->versionNum != 0 || sp->versionLet != ' ' )
  1589.     {
  1590.         printf( "Software Version: %u.%u%c\n", sp->versionNum/100,
  1591.             sp->versionNum % 100, sp->versionLet );
  1592.     }
  1593.  
  1594.     printf( "Key Color: 0x%02lx(%ld) Alpha, 0x%02lx(%ld) Red, 0x%02lx(%ld) Green, 0x%02lx(%ld) Blue\n",
  1595.         sp->keyColor >> 24, sp->keyColor >> 24,
  1596.         (sp->keyColor >> 16) & 0xff, (sp->keyColor >> 16) & 0xff,
  1597.         (sp->keyColor >> 8) & 0xff, (sp->keyColor >> 8) & 0xff,
  1598.         sp->keyColor & 0xff, sp->keyColor & 0xff );
  1599.  
  1600.     if ( sp->pixNumerator != 0 && sp->pixDenominator != 0 )
  1601.     {
  1602.         printf( "Pixel Aspect Ratio: %f\n", (double)sp->pixNumerator /
  1603.             (double)sp->pixDenominator );
  1604.     }
  1605.  
  1606.     if ( sp->gammaDenominator != 0 )
  1607.     {
  1608.         printf( "Gamma Correction: %f\n", (double)sp->gammaNumerator /
  1609.             (double)sp->gammaDenominator );
  1610.     }
  1611.  
  1612.     printf( "Color Correction Offset = 0x%08lx\n", sp->colorCorrectOffset );
  1613.     if ( sp->colorCorrectOffset && sp->colorCorrectTable )
  1614.     {
  1615.         PrintColorTable( sp );
  1616.     }
  1617.     printf( "Postage Stamp Offset = 0x%08lx\n", sp->stampOffset );
  1618.     if ( sp->stampOffset )
  1619.     {
  1620.         printf( "Postage Stamp Width, Height: %3u, %3u\n",
  1621.                     sp->stampWidth, sp->stampHeight );
  1622.     }
  1623.     printf( "Scan Line Offset = 0x%08lx\n", sp->scanLineOffset );
  1624.     if ( sp->scanLineOffset && sp->scanLineTable )
  1625.     {
  1626.         PrintScanLineTable( sp );
  1627.     }
  1628.  
  1629.     switch (sp->alphaAttribute )
  1630.     {
  1631.     case 0:
  1632.         if ( (sp->imageDesc & 0xf) == 0 ) puts( "No Alpha Data Present" );
  1633.         else puts( "Inconsistent Alpha Data Specification" );
  1634.         break;
  1635.     case 1:
  1636.         puts( "Alpha Data Undefined and Can Be Ignored" );
  1637.         break;
  1638.     case 2:
  1639.         puts( "Alpha Data Undefined but Should Be Retained" );
  1640.         break;
  1641.     case 3:
  1642.         puts( "Useful Alpha Data Present" );
  1643.         break;
  1644.     case 4:
  1645.         puts( "Pre-Multiplied Alpha Data Present" );
  1646.         break;
  1647.     default:
  1648.         puts( "Undefined Alpha Attribute Field" );
  1649.         break;
  1650.     }
  1651. }
  1652.  
  1653.  
  1654.  
  1655. void
  1656. PrintImageType( Itype )
  1657. register int Itype;
  1658. {
  1659.     if ( Itype > 255 || Itype < 0 )
  1660.     {
  1661.         puts("Illegal/Undefined Image Type");
  1662.         return;
  1663.     }
  1664.  
  1665.     if ( Itype > 127 )
  1666.     {
  1667.         puts("Unknown Image Type - Application Specific");
  1668.         return;
  1669.     }
  1670.  
  1671.     switch (Itype)
  1672.     {
  1673.     case 0:
  1674.         puts("Unknown Image Type - No Image Data Present");
  1675.         break;
  1676.     case 1:
  1677.         puts("Uncompressed Color Mapped Image (e.g., VDA/D, TARGA M8)");
  1678.         break;
  1679.     case 2:
  1680.         puts("Uncompressed True Color Image (e.g., ICB, TARGA 16/24/32)");
  1681.         break;
  1682.     case 3:
  1683.         puts("Uncompressed Black & White Image (e.g., TARGA 8/M8)");
  1684.         break;
  1685.     case 9:
  1686.         puts("Run Length Encoded Color Mapped Image (e.g., VDA/D, TARGA M8)");
  1687.         break;
  1688.     case 10:
  1689.         puts("Run Length Encoded True Color Image (e.g., ICB, TARGA 16/24/32)");
  1690.         break;
  1691.     case 11:
  1692.         puts("Compressed Black & White Image (e.g., TARGA 8/M8)");
  1693.         break;
  1694.     case 32:
  1695.     case 34:
  1696.         puts("Compressed (Huffman/Delta/RLE) Color Mapped Image (e.g., VDA/D) - Obsolete");
  1697.         break;
  1698.     case 33:
  1699.     case 35:
  1700.         puts("Compressed (Huffman/Delta/RLE) Color Mapped Four Pass Image (e.g., VDA/D) - Obsolete");
  1701.         break;
  1702.     default:
  1703.         puts("Unknown Image Type");
  1704.         break;
  1705.     }
  1706. }
  1707.  
  1708.  
  1709. void
  1710. PrintMonth( month )
  1711. UINT16    month;
  1712. {
  1713.     if ( month > 0 && month < 13 ) printf( monthStr[month - 1] );
  1714.     else printf( "Month Error" );
  1715. }
  1716.  
  1717.  
  1718. void
  1719. PrintScanLineTable( sp )
  1720. TGAFile    *sp;
  1721. {
  1722.     UINT16    n;
  1723.     UINT32    *p;
  1724.  
  1725.     puts( "Scan Line Table:" );
  1726.     p = sp->scanLineTable;
  1727.     for ( n = 0; n < sp->imageHeight; ++n )
  1728.     {
  1729.         printf( "Scan Line %6u, Offset 0x%08lx(%8d)\n", n, *p, *p );
  1730.         ++p;
  1731.     }
  1732. }
  1733.  
  1734.  
  1735.  
  1736. void
  1737. PrintTGAInfo( sp )
  1738. TGAFile *sp;        /* TGA structure pointer */
  1739. {
  1740.     int    i;
  1741.  
  1742.     printf("ID Field Length          = %3d\n", sp->idLength);
  1743.  
  1744.     printf("Color Map Type           = %3d  (Color Map Data is ", sp->mapType);
  1745.     if (sp->mapType) puts("Present)");
  1746.     else puts("Absent)");  
  1747.  
  1748.     printf("Image Type               = %3d\n  ", sp->imageType);
  1749.     PrintImageType( sp->imageType );
  1750.  
  1751.     printf("Color Map Origin         = 0x%04x (%5d)",
  1752.         sp->mapOrigin, sp->mapOrigin);
  1753.     puts( "  (First Index To Be Loaded)" );
  1754.     printf("Color Map Length         = 0x%04x (%5d)\n",
  1755.         sp->mapLength,sp->mapLength);
  1756.     printf("Color Map Entry Size     = %6d\n", sp->mapWidth);
  1757.  
  1758.     printf("Image X-Origin, Y-Origin =  %05d, %05d\n",
  1759.         sp->xOrigin, sp->yOrigin);
  1760.     printf("Image Width, Height      =  %05d, %05d\n",
  1761.             sp->imageWidth, sp->imageHeight);
  1762.  
  1763.     printf("Image Pixel Depth        = 0x%04x (%05d)\n",
  1764.         sp->pixelDepth, sp->pixelDepth);
  1765.     printf("Image Descriptor         = 0x%04x\n", sp->imageDesc);
  1766.     printf("  %d Attribute Bits Per Pixel\n", sp->imageDesc & 0xf );
  1767.     printf("  First Pixel Destination is ");
  1768.  
  1769.     i = (sp->imageDesc & 0x30) >> 4;
  1770.     puts( orientStr[i] );
  1771.  
  1772.     i = (sp->imageDesc & 0xc0) >> 6;
  1773.     if ( i > 0 && i < 3 ) puts( interleaveStr[i - 1] );
  1774.  
  1775.     if ( sp->idLength )
  1776.     {
  1777.         printf( "Image ID:\n  " );
  1778.         puts( f.idString );
  1779.     }
  1780. }
  1781.  
  1782.  
  1783. UINT8
  1784. ReadByte( fp )
  1785. FILE *fp;
  1786. {
  1787.     UINT8    value;
  1788.  
  1789. #if MSDOS
  1790.     fread( &value, 1, 1, fp );
  1791. #else
  1792. #endif
  1793.     return( value );
  1794. }
  1795.  
  1796.  
  1797. void
  1798. ReadCharField( fp, p, n )
  1799. FILE    *fp;
  1800. char    *p;
  1801. int        n;
  1802. {
  1803.     while ( n )
  1804.     {
  1805.         *p++ = (char)fgetc( fp );    /* no error check, no char conversion */
  1806.         --n;
  1807.     }
  1808. }
  1809.  
  1810.  
  1811. int
  1812. ReadColorTable( fp, sp )
  1813. FILE    *fp;
  1814. TGAFile    *sp;
  1815. {
  1816.     UINT16    *p;
  1817.     UINT16    n;
  1818.  
  1819.     if ( !fseek( fp, sp->colorCorrectOffset, SEEK_SET ) )
  1820.     {
  1821.         if ( sp->colorCorrectTable = malloc( 1024 * sizeof( UINT16 ) ) )
  1822.         {
  1823.             p = sp->colorCorrectTable;
  1824.             for ( n = 0; n < 1024; ++n )
  1825.             {
  1826.                 *p++ = ReadShort( fp );
  1827.             }
  1828.         }
  1829.         else
  1830.         {
  1831.             puts( "Unable to allocate Color Correction Table." );
  1832.             return( -1 );
  1833.         }
  1834.     }
  1835.     else
  1836.     {
  1837.         printf( "Error seeking to Color Correction Table, offset = 0x%08lx\n",
  1838.             sp->colorCorrectOffset );
  1839.         return( -1 );
  1840.     }
  1841.     return( 0 );
  1842. }
  1843.  
  1844.  
  1845.  
  1846. int
  1847. ReadDeveloperDirectory( fp, sp )
  1848. FILE    *fp;
  1849. TGAFile    *sp;
  1850. {
  1851.     int                i;
  1852.  
  1853.     if ( !fseek( fp, sp->devDirOffset, SEEK_SET ) )
  1854.     {
  1855.         sp->devTags = ReadShort( fp );
  1856.         if ( (sp->devDirs = malloc( sp->devTags * sizeof(DevDir) )) == NULL )
  1857.         {
  1858.             puts( "Unable to allocate developer directory." );
  1859.             return( -1 );
  1860.         }
  1861.         for ( i = 0; i < sp->devTags; ++i )
  1862.         {
  1863.             sp->devDirs[i].tagValue = ReadShort( fp );
  1864.             sp->devDirs[i].tagOffset = ReadLong( fp );
  1865.             sp->devDirs[i].tagSize = ReadLong( fp );
  1866.         }
  1867.     }
  1868.     else
  1869.     {
  1870.         printf( "Error seeking to Developer Area at offset 0x%08lx\n",
  1871.             sp->devDirOffset );
  1872.         return(-1);
  1873.     }
  1874.     return( 0 );
  1875. }
  1876.  
  1877.  
  1878.  
  1879. int
  1880. ReadExtendedTGA( fp, sp )
  1881. FILE    *fp;
  1882. TGAFile    *sp;
  1883. {
  1884.     if ( !fseek( fp, sp->extAreaOffset, SEEK_SET ) )
  1885.     {
  1886.         sp->extSize = ReadShort( fp );
  1887.         memset( sp->author, 0, 41 );
  1888.         ReadCharField( fp, sp->author, 41 );
  1889.         memset( &sp->authorCom[0][0], 0, 81 );
  1890.         ReadCharField( fp, &sp->authorCom[0][0], 81 );
  1891.         memset( &sp->authorCom[1][0], 0, 81 );
  1892.         ReadCharField( fp, &sp->authorCom[1][0], 81 );
  1893.         memset( &sp->authorCom[2][0], 0, 81 );
  1894.         ReadCharField( fp, &sp->authorCom[2][0], 81 );
  1895.         memset( &sp->authorCom[3][0], 0, 81 );
  1896.         ReadCharField( fp, &sp->authorCom[3][0], 81 );
  1897.  
  1898.         sp->month = ReadShort( fp );
  1899.         sp->day = ReadShort( fp );
  1900.         sp->year = ReadShort( fp );
  1901.         sp->hour = ReadShort( fp );
  1902.         sp->minute = ReadShort( fp );
  1903.         sp->second = ReadShort( fp );
  1904.  
  1905.         memset( sp->jobID, 0, 41 );
  1906.         ReadCharField( fp, sp->jobID, 41 );
  1907.         sp->jobHours = ReadShort( fp );
  1908.         sp->jobMinutes = ReadShort( fp );
  1909.         sp->jobSeconds = ReadShort( fp );
  1910.  
  1911.         memset( sp->softID, 0, 41 );
  1912.         ReadCharField( fp, sp->softID, 41 );
  1913.         sp->versionNum = ReadShort( fp );
  1914.         sp->versionLet = ReadByte( fp );
  1915.  
  1916.         sp->keyColor = ReadLong( fp );
  1917.         sp->pixNumerator = ReadShort( fp );
  1918.         sp->pixDenominator = ReadShort( fp );
  1919.  
  1920.         sp->gammaNumerator = ReadShort( fp );
  1921.         sp->gammaDenominator = ReadShort( fp );
  1922.  
  1923.         sp->colorCorrectOffset = ReadLong( fp );
  1924.         sp->stampOffset = ReadLong( fp );
  1925.         sp->scanLineOffset = ReadLong( fp );
  1926.  
  1927.         sp->alphaAttribute = ReadByte( fp );
  1928.  
  1929.         sp->colorCorrectTable = (UINT16 *)0;
  1930.         if ( sp->colorCorrectOffset )
  1931.         {
  1932.             ReadColorTable( fp, sp );
  1933.         }
  1934.  
  1935.         sp->postStamp = (void *)0;
  1936.         if ( sp->stampOffset )
  1937.         {
  1938.             if ( !fseek( fp, sp->stampOffset, SEEK_SET ) )
  1939.             {
  1940.                 sp->stampWidth = ReadByte( fp );
  1941.                 sp->stampHeight = ReadByte( fp );
  1942.                 /*
  1943.                 ** Leave the processing of postage stamp data to
  1944.                 ** the output phase of the program.  All we really
  1945.                 ** need to know is whether it exists in the input file.
  1946.                 */
  1947.             }
  1948.             else
  1949.             {
  1950.                 printf( "Error seeking to Postage Stamp, offset = 0x%08lx\n",
  1951.                     sp->stampOffset );
  1952.             }
  1953.         }
  1954.  
  1955.         sp->scanLineTable = (UINT32 *)0;
  1956.         if ( sp->scanLineOffset )
  1957.         {
  1958.             ReadScanLineTable( fp, sp );
  1959.         }
  1960.     }
  1961.     else
  1962.     {
  1963.         printf( "Error seeking to Extended TGA Area, offset = 0x%08lx\n",
  1964.             sp->extAreaOffset );
  1965.         return( -1 );
  1966.     }
  1967.     return( 0 );
  1968. }
  1969.  
  1970.  
  1971. UINT32
  1972. ReadLong( fp )
  1973. FILE *fp;
  1974. {
  1975.     UINT32    value;
  1976.  
  1977. #if MSDOS
  1978.     fread( &value, 4, 1, fp );
  1979. #else
  1980. #endif
  1981.     return( value );
  1982. }
  1983.  
  1984.  
  1985.  
  1986. int
  1987. ReadRLERow( p, n, bpp, fp )
  1988. unsigned char    *p;
  1989. int        n;            /* buffer size in bytes */
  1990. int        bpp;        /* bytes per pixel */
  1991. FILE    *fp;
  1992. {
  1993.     unsigned int    value;
  1994.     int                i;
  1995.     unsigned char    *q;
  1996.  
  1997.     while ( n > 0 )
  1998.     {
  1999.         value = (unsigned int)ReadByte( fp );
  2000.         if ( value & 0x80 )
  2001.         {
  2002.             value &= 0x7f;
  2003.             value++;
  2004.             n -= value * bpp;
  2005.             if ( n < 0 ) return( -1 );
  2006.             if ( fread( rleBuf, 1, bpp, fp ) != bpp ) return( -1 );
  2007.             while ( value > 0 )
  2008.             {
  2009.                 *p++ = rleBuf[0];
  2010.                 if ( bpp > 1 ) *p++ = rleBuf[1];
  2011.                 if ( bpp > 2 ) *p++ = rleBuf[2];
  2012.                 if ( bpp > 3 ) *p++ = rleBuf[3];
  2013.                 value--;
  2014.             }
  2015.         }
  2016.         else
  2017.         {
  2018.             value++;
  2019.             n -= value * bpp;
  2020.             if ( n < 0 ) return( -1 );
  2021.             /*
  2022.             ** Maximum for value is 128 so as long as RLEBUFSIZ
  2023.             ** is at least 512, and bpp is not greater than 4
  2024.             ** we can read in the entire raw packet with one operation.
  2025.             */
  2026.             if ( fread( rleBuf, bpp, value, fp ) != value ) return( -1 );
  2027.             for ( i = 0, q = rleBuf; i < (value * bpp); ++i ) *p++ = *q++;
  2028.         }
  2029.     }
  2030.     return( 0 );
  2031. }
  2032.  
  2033.  
  2034.  
  2035. int
  2036. ReadScanLineTable( fp, sp )
  2037. FILE    *fp;
  2038. TGAFile    *sp;
  2039. {
  2040.     UINT32    *p;
  2041.     UINT16    n;
  2042.  
  2043.     if ( !fseek( fp, sp->scanLineOffset, SEEK_SET ) )
  2044.     {
  2045.         if ( sp->scanLineTable = malloc( sp->imageHeight << 2 ) )
  2046.         {
  2047.             p = sp->scanLineTable;
  2048.             for ( n = 0; n < sp->imageHeight; ++n )
  2049.             {
  2050.                 *p++ = ReadShort( fp );
  2051.             }
  2052.         }
  2053.         else
  2054.         {
  2055.             puts( "Unable to allocate Scan Line Table." );
  2056.             return( -1 );
  2057.         }
  2058.     }
  2059.     else
  2060.     {
  2061.         printf( "Error seeking to Scan Line Table, offset = 0x%08lx\n",
  2062.             sp->scanLineOffset );
  2063.         return( -1 );
  2064.     }
  2065.     return( 0 );
  2066. }
  2067.  
  2068.  
  2069. UINT16
  2070. ReadShort( fp )
  2071. FILE *fp;
  2072. {
  2073.     UINT16    value;
  2074.  
  2075. #if MSDOS
  2076.     fread( &value, 2, 1, fp );
  2077. #else
  2078. #endif
  2079.     return( value );
  2080. }
  2081.  
  2082.  
  2083.  
  2084. int
  2085. RLEncodeRow( p, q, n, bpp )
  2086. char    *p;            /* data to be encoded */
  2087. char    *q;            /* encoded buffer */
  2088. int        n;            /* number of pixels in buffer */
  2089. int        bpp;        /* bytes per pixel */
  2090. {
  2091.     int                diffCount;        /* pixel count until two identical */
  2092.     int                sameCount;        /* number of identical adjacent pixels */
  2093.     int                RLEBufSize;        /* count of number of bytes encoded */
  2094.  
  2095.     RLEBufSize = 0;
  2096.     while ( n > 0 )
  2097.     {
  2098.         diffCount = CountDiffPixels( p, bpp, n );
  2099.         sameCount = CountSamePixels( p, bpp, n );
  2100.         if ( diffCount > 128 ) diffCount = 128;
  2101.         if ( sameCount > 128 ) sameCount = 128;
  2102.         if ( diffCount > 0 )
  2103.         {
  2104.             /* create a raw packet */
  2105.             *q++ = (char)(diffCount - 1);
  2106.             n -= diffCount;
  2107.             RLEBufSize += (diffCount * bpp) + 1;
  2108.             while ( diffCount > 0 )
  2109.             {
  2110.                 *q++ = *p++;
  2111.                 if ( bpp > 1 ) *q++ = *p++;
  2112.                 if ( bpp > 2 ) *q++ = *p++;
  2113.                 if ( bpp > 3 ) *q++ = *p++;
  2114.                 diffCount--;
  2115.             }
  2116.         }
  2117.         if ( sameCount > 1 )
  2118.         {
  2119.             /* create a RLE packet */
  2120.             *q++ = (char)((sameCount - 1) | 0x80);
  2121.             n -= sameCount;
  2122.             RLEBufSize += bpp + 1;
  2123.             p += (sameCount - 1) * bpp;
  2124.             *q++ = *p++;
  2125.             if ( bpp > 1 ) *q++ = *p++;
  2126.             if ( bpp > 2 ) *q++ = *p++;
  2127.             if ( bpp > 3 ) *q++ = *p++;
  2128.         }
  2129.     }
  2130.     return( RLEBufSize );
  2131. }
  2132.  
  2133.  
  2134.  
  2135. char *
  2136. SkipBlank( p )
  2137. char    *p;
  2138. {
  2139.     while ( *p != '\0' && (*p == ' ' || *p == '\t') ) ++p;
  2140.     return( p );
  2141. }
  2142.  
  2143.  
  2144. int
  2145. WriteByte( uc, fp )
  2146. UINT8    uc;
  2147. FILE    *fp;
  2148. {
  2149. #ifdef MSDOS
  2150.     if ( fwrite( &uc, 1, 1, fp ) == 1 ) return( 0 );
  2151. #else
  2152. #endif
  2153.     return( -1 );
  2154. }
  2155.  
  2156.  
  2157. int
  2158. WriteColorTable( fp, sp )
  2159. FILE    *fp;
  2160. TGAFile    *sp;
  2161. {
  2162.     UINT16    *p;
  2163.     UINT16    n;
  2164.  
  2165.     p = sp->colorCorrectTable;
  2166.     for ( n = 0; n < 1024; ++n )
  2167.     {
  2168.         if ( WriteShort( *p++, fp ) < 0 ) return( -1 );
  2169.     }
  2170.     return( 0 );
  2171. }
  2172.  
  2173.  
  2174. int
  2175. WriteLong( ul, fp )
  2176. UINT32    ul;
  2177. FILE    *fp;
  2178. {
  2179. #ifdef MSDOS
  2180.     if ( fwrite( &ul, 4, 1, fp ) == 1 ) return( 0 );
  2181. #else
  2182. #endif
  2183.     return( -1 );
  2184. }
  2185.  
  2186.  
  2187. int
  2188. WriteShort( us, fp )
  2189. UINT16    us;
  2190. FILE    *fp;
  2191. {
  2192. #ifdef MSDOS
  2193.     if ( fwrite( &us, 2, 1, fp ) == 1 ) return( 0 );
  2194. #else
  2195. #endif
  2196.     return( -1 );
  2197. }
  2198.  
  2199.  
  2200. int
  2201. WriteStr( p, n, fp )
  2202. char    *p;
  2203. int        n;
  2204. FILE    *fp;
  2205. {
  2206. #ifdef MSDOS
  2207.     if ( fwrite( p, 1, n, fp ) == n ) return( 0 );
  2208. #else
  2209. #endif
  2210.     return( -1 );
  2211. }
  2212.