1 /*---------------------------------------------------------------------*
2 Project:  tc library
3 File:     TCScriptFile.cpp
4 
5 Copyright 1998-2001 Nintendo.  All rights reserved.
6 
7 These coded instructions, statements and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law.  They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12 
13 Change History:
14 
15  $Log: TCScriptFile.cpp,v $
16  Revision 1.1  2006/02/17 09:01:53  mitu
17  1st version
18 
19 
20     6    4/11/01 3:08p John
21     Updated header copyrights and pathname.
22 
23     5     3/09/01 3:21p John
24     Added better error checking for wrapS and wrapT modes.
25 
26     4     3/09/01 2:50p John
27     Modified TCProcessImKey.  Added ability to specify wrapS and wrapT mode
28     using TCS script file.
29 
30     3     8/10/00 6:03p Mikepc
31 
32     2     3/17/00 1:19p Mikepc
33     change tc to use indices numbered from 0.
34 
35     1     12/03/99 3:45p Ryan
36 
37     20    10/13/99 4:19p Mikepc
38 
39     18    10/08/99 2:45p Mikepc
40     update for tplConv portability: altered data structures, replaced
41     references to 'read tga code' with ' *fileFn, removed redundant
42     functions.  Changed some file conversion paths.
43 
44     17    9/17/99 12:57p Mikepc
45     palette entry format defaults to rgb565
46 
47     16    9/17/99 12:21p Mikepc
48     - arbitrary palette size has been removed- changed ReadTplTxtFile() to
49     reject CI4 and CI14_X2 as conversion formats.
50     - palette alpha layer has been removed- changed ProcessPlKey() to
51     default this to 0.
52 
53     15    9/16/99 8:47p Mikepc
54     updated code for auto-palette generation
55 
56     14    9/13/99 5:03p Mikepc
57     changed ProcessPlKey() to look for palette format RGB565 instead of
58     R5G6B5.
59 
60     13    9/09/99 7:02p Mikepc
61     in ProcessImKey, changed 2 conversion format values to match latest
62     gxEnum.h:  R5G6B5 to RGB565, and CMP to CMPR
63 
64     12     9/02/99 11:12a Mikepc
65     some code re-organization between files.
66     added code (verify.cpp) to invoke s3tc.exe from within tc program.
67     changed some routines to accommodate the new texture creation path.
68 
69     11    8/26/99 4:59p Mikepc
70     renamed file extensions from .c to .cpp.
71     .cpp extension allows addition of namespace protection to remove
72     potential name collisions with tool code.  Exceptions are CreateTplFile
73     and QuickConvert.  These are extern "C" linked.
74 
75     10    8/26/99 11:38a Mikepc
76 
77     9     8/26/99 11:03a Mikepc
78     tplCon rewrite for efficient memory usage, batch file processing
79     ability.
80 
81  $NoKeywords: $
82 
83 -----------------------------------------------------------------------*/
84 
85 #include <string.h>
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <ctype.h>
89 
90 #include <charPipeline/tc/TCCommon.h>
91 
92 #include "TCSrcImageList.h"
93 #include "TCImageList.h"
94 #include "TCPaletteList.h"
95 #include "TCTextureList.h"
96 #include "TCGXDefs.h"
97 
98 // path name and ptr for script file keys-
99 // was 'static', made global so it could be cleared
100 // each time for batch processing
101 char  PathName[NAME_SIZE];       // stores current file path name
102 char* PathPtr = NULL;
103 
104 /*>*******************************(*)*******************************<*/
105 static void TCProcessKeyName( char* lineBuff );
106 static void TCProcessSiKey	( u32 index, char* pathName, char* fileName );
107 static void TCProcessImKey	( u32 index, char* attList );
108 static void TCProcessPlKey	( u32 index, char* attList );
109 static void TCProcessTxKey	( u32 index, char* attList );
110 
111 static void TCGetKeyTokens	( char* lineBuff, char* leftSide,
112 							  char* rightSide );
113 
114 static void TCGetKeyNum		( char* srcStr, u32* num );
115 static void TCGetKeyString	( char* srcStr, char* dstStr );
116 static void TCStripBlanks	( char* srcStr, u32 leading, u32 trailing );
117 
118 /*>*******************************(*)*******************************<*/
119 // parse an ini-style text file
120 /*>*******************************(*)*******************************<*/
TCReadTplTxtFile(char * fileName)121 void TCReadTplTxtFile ( char* fileName )
122 {
123 	FILE* fp;
124 	char  lineBuff[NAME_SIZE];
125 	char* buffPtr;
126 
127 
128 	fp = fopen(fileName, "r");
129 	TCAssertMsg( (fp != NULL), "TCReadTplTextFile: couldn't open %s for read\n", fileName );
130 
131 	// read one line at a time until EOF is reached.
132 	// trim leading blanks while reading.
133 	while( (buffPtr = fgets(lineBuff, NAME_SIZE, fp)) != NULL )
134 	{
135 		// ensure that the .txt file line was not greater than (NAME_SIZE-1) characters
136 		// if the string is of size (NAME_SIZE-1), check if EOF or a newline was encountered at position 254
137 		if( (strlen(lineBuff)) == (NAME_SIZE - 1) )
138 		{
139 			if( (feof(fp)) == 0 )            // this is not the end of the file
140 			{
141 				if( lineBuff[ (NAME_SIZE - 2) ] != '\n' )  // fgets should always include a newline at a line's end
142 				                                           // except at the end of the file
143 				{
144 					TCErrorMsg( "TCReadTplTextFile: line exceeded %d characters in '%s'", (NAME_SIZE-1), fileName );
145 				}
146 			}
147 		}
148 
149 		TCStripBlanks( lineBuff, 1, 1 );
150 
151 		// identify the line type by its first character
152 
153 		if( lineBuff[0] == '\0' )                   // '\n' after StripBlanks()
154 		{
155 			continue;
156 		}
157 
158 		else if( lineBuff[0] == ';' )               // start of a comment
159 		{
160 			continue;
161 		}
162 
163 		else                                        // start of a possible key name
164 		{
165 			// take action depending on the type of this key
166 			TCProcessKeyName(lineBuff);
167 		}
168 	}
169 
170 	fclose(fp);
171 }
172 
173 /*>*******************************(*)*******************************<*/
174 // check the first few characters of a non-comment line for one of
175 // 'file', 'image', 'palette', 'texture'
176 // leading blanks will already have been stripped out when fgets was
177 // called for lineBuff so keyPtr should point to lineBuff on success
178 //
179 // note:  if a key can't be identified, the entire line is ignored
180 //
181 /*>*******************************(*)*******************************<*/
TCProcessKeyName(char * lineBuff)182 static void TCProcessKeyName ( char* lineBuff )
183 {
184 	char  leftSide[NAME_SIZE], rightSide[NAME_SIZE];
185 	char* keyPtr;
186 	u32   index;
187 
188 
189 	// split this key into left/right tokens, trim leading/trailing blanks
190 	TCGetKeyTokens( lineBuff, leftSide, rightSide);
191 
192 	// trim blanks and comments from the right side string
193 	TCGetKeyString( rightSide, rightSide );
194 
195     // convert everything to upper case
196     TCStrToUpper( leftSide  );
197     TCStrToUpper( rightSide );
198 
199 	// determine which key this is and get its number if needed
200 
201 	if( (keyPtr = strstr( leftSide, "PATH" )) == leftSide )          // path name key
202 	{
203 
204 		// no number component in path key name
205 
206 		// check for null path name
207 		if( ((strcmp(rightSide, "0")) == 0) || ((strcmp(rightSide, "NULL")) == 0) )
208 		{
209 			PathPtr = NULL;
210 		}
211 		else		// set a new path name
212 		{
213 			PathPtr = PathName;
214 			strcpy( PathPtr, rightSide );
215 		}
216 	}
217     else if( (keyPtr = strstr( leftSide, "FILE" )) == leftSide )      // source image (file name) key
218 	{
219 		TCGetKeyNum( (leftSide + strlen("FILE")), &index );
220 		TCProcessSiKey( index, PathPtr, rightSide );
221 	}
222 
223 	else if( (keyPtr = strstr( leftSide, "IMAGE" )) == leftSide )     // image key
224 	{
225 		TCGetKeyNum( (leftSide + strlen("IMAGE")), &index );
226 		TCProcessImKey(index, rightSide);
227 	}
228 	else if( (keyPtr = strstr( leftSide, "PALETTE" )) == leftSide )   // palette key
229 	{
230 		TCGetKeyNum( (leftSide + strlen("PALETTE")), &index );
231 	    TCProcessPlKey(index, rightSide);
232 	}
233 	else if( (keyPtr = strstr( leftSide, "TEXTURE" )) == leftSide )   // texture key
234 	{
235 		TCGetKeyNum( (leftSide + strlen("TEXTURE")), &index );
236 		TCProcessTxKey(index, rightSide);
237 	}
238 	else
239 	{
240 		;	   // unknown key- treat as a comment and ignore the whole line
241 	}
242 }
243 
244 /*>*******************************(*)*******************************<*/
245 // fetch source image data using this key as file name.
246 // create a new source image, identify layers, create layer names
247 // based on index and file name
248 /*>*******************************(*)*******************************<*/
TCProcessSiKey(u32 index,char * pathName,char * fileName)249 static void TCProcessSiKey ( u32 index, char* pathName, char* fileName )
250 {
251 	char        fullName[NAME_SIZE];
252 	u32         len;
253 	TCSrcImage* newSi;
254 
255 
256     // 'X'ed out index? ignore this key
257     if( index == TC_UNUSED )
258     {
259         return;
260     }
261 
262     TCAssertMsg( (fileName  != NULL), "TCProcessSiKey: NULL fileName for file %d\n", index    );
263     TCAssertMsg( (*fileName != '\0'), "TCProcessSiKey: NULL fileName for file %d\n", index    );
264 
265 
266 	len = 0;
267 	if( pathName != NULL )
268 	{
269 		len = strlen(pathName);
270 	}
271 
272 	len += strlen(fileName);
273     TCAssertMsg( (len <= (NAME_SIZE-1)), "TCProcessSiKey: length of (%s + path) > %d characters\n", (NAME_SIZE-1), fileName );
274 
275 	// build the source image name from the current path and file name
276 	if(pathName)
277 	{
278 		strcpy(fullName, pathName);
279 		strcat(fullName, fileName);
280 	}
281 	else
282 	{
283 		strcpy(fullName, fileName);
284 	}
285 
286 	// create a new source image and set its attributes
287 	newSi = TCNewSrcImage();
288 	TCAssertMsg( (newSi != NULL),"ProcessSiKey: couldn't allocate memory for new source image %d\n", index );
289 
290 	// set source image attributes
291 	// valid source file types depend on user-defined file reading functions
292 	// set by InstallFileReadFn() - invalid types will be caught by ReadFile()
293 	TCSetSrcImageFromFile( newSi, fullName, index );
294 }
295 
296 /*>*******************************(*)*******************************<*/
TCProcessImKey(u32 index,char * attList)297 static void TCProcessImKey( u32 index, char* attList )
298 {
299 	TCImage* newIm;
300 	char*  icPtr       = NULL, *iaPtr      = NULL, *fmtPtr     = NULL;
301     char*  minLODPtr   = NULL, *maxLODPtr  = NULL, *baseLODPtr = NULL;
302     char*  wrapSPtr    = NULL, *wrapTPtr   = NULL;
303 	u32    icNum       = 0, iaNum          = 0,    fmt         = 0;
304 	u32    minLOD      = 0, maxLOD         = 0,    baseLOD     = 0;
305     u32    wrapS       = 0, wrapT          = 0;
306 
307 
308     // 'X'ed out index? ignore this key
309     if( index == TC_UNUSED )
310     {
311         return;
312     }
313 
314     TCAssertMsg( (attList  != NULL), "TCProcessImKey: missing attribute list for image %d in script file\n", index );
315     TCAssertMsg( (*attList != '\0'), "TCProcessImKey: missing attribute list for image %d in script file\n", index );
316 
317 
318 	// split the attList string into tokens using commas as separators.
319 	// remove whitespace from around tokens.
320 	icPtr  = strtok( attList, "," );
321 	TCAssertMsg( (icPtr != NULL), "ProcessImKey: problem reading color index for image %d in script file\n", index );
322 
323 	iaPtr  = strtok( NULL,    "," );
324 	TCAssertMsg( (iaPtr != NULL), "ProcessImKey: problem reading alpha index for image %d in script file\n", index );
325 
326 	fmtPtr = strtok( NULL,    "," );
327 	TCAssertMsg( (fmtPtr != NULL), "ProcessImKey: problem reading output format for image %d in script file\n", index );
328 
329 	// mipmap information is optional
330 	// if present, there must be 3 more comma-separated values
331 	if( (minLODPtr = strtok( NULL,    "," )) != 0 )
332 	{
333     	TCStripBlanks( minLODPtr, 1,1 );
334         if( isdigit( *minLODPtr ) )
335         {
336             // Parse these three arguments as mipmap constants (minLOD, maxLOD, baseLOD)
337 		    maxLODPtr = strtok( NULL, "," );
338 		    TCAssertMsg( (maxLODPtr != NULL), "ProcessImKey: problem reading max LOD for image %d in script file\n", index );
339         	TCStripBlanks( maxLODPtr, 1,1 );
340             TCAssertMsg( (isdigit( *maxLODPtr )), "ProcessImKey: missing max LOD for image %d (should be a number)\n", index );
341 
342 		    baseLODPtr = strtok( NULL, "," );
343 		    TCAssertMsg( (baseLODPtr != NULL), "ProcessImKey: problem reading remap base LOD for image %d in script file\n", index );
344         	TCStripBlanks( baseLODPtr, 1,1 );
345             TCAssertMsg( (isdigit( *baseLODPtr )), "ProcessImKey: missing base LOD for image %d (should be a number)\n", index );
346 
347             // If two more args exist, parse as wrap modes (wrapS, wrapT)
348             if( (wrapSPtr = strtok( NULL, "," )) != 0 )
349             {
350 		        wrapTPtr = strtok( NULL, "" );
351 		        TCAssertMsg( (wrapTPtr != NULL), "ProcessImKey: problem reading wrapT mode for image %d in script file\n", index );
352             }
353         }
354         else
355         {
356             // Parse two arguments as wrap modes (wrapS, wrapT)
357             wrapSPtr = minLODPtr;
358             minLODPtr = NULL;
359 
360 		    wrapTPtr = strtok( NULL, "" );
361 		    TCAssertMsg( (wrapTPtr != NULL), "ProcessImKey: problem reading wrapT mode for image %d in script file\n", index );
362         }
363 	}
364 
365 	// strip whitespace from these tokens
366 	TCStripBlanks( icPtr,  1,1 );
367 	TCStripBlanks( iaPtr,  1,1 );
368 	TCStripBlanks( fmtPtr, 1,1 );
369     TCStripBlanks( wrapSPtr, 1, 1 );
370     TCStripBlanks( wrapTPtr, 1, 1 );
371 
372     // set the color and alpha layer indices:
373 
374     // color layer index is mandatory
375     TCGetKeyNum ( icPtr, &icNum );
376     TCAssertMsg( (icNum != TC_UNUSED), "TCProcessImKey: invalid color index for image %d in script file\n", index );
377 
378     // alpha layer index is optional.
379     // if no alpha layer, iaNum will be set to TC_UNUSED
380     TCGetKeyNum ( iaPtr, &iaNum );
381 
382 
383 	// set the final hw pixel format
384 	if( (strcmp(fmtPtr, "I4")) == 0 )
385 		fmt = TPL_IMAGE_TEXEL_FMT_I4;
386 	else if( (strcmp(fmtPtr, "I8")) == 0 )
387 		fmt = TPL_IMAGE_TEXEL_FMT_I8;
388 	else if( (strcmp(fmtPtr, "IA4")) == 0 )
389 		fmt = TPL_IMAGE_TEXEL_FMT_IA4;
390 	else if( (strcmp(fmtPtr, "IA8")) == 0 )
391 		fmt = TPL_IMAGE_TEXEL_FMT_IA8;
392 
393 	else if( (strcmp(fmtPtr, "RGB565")) == 0 )
394 		fmt = TPL_IMAGE_TEXEL_FMT_R5G6B5;
395 
396 	else if( (strcmp(fmtPtr, "RGB5A3")) == 0 )
397 		fmt = TPL_IMAGE_TEXEL_FMT_RGB5A3;
398 	else if( (strcmp(fmtPtr, "RGBA8")) == 0 )
399 		fmt = TPL_IMAGE_TEXEL_FMT_RGBA8;
400 
401 	else if( (strcmp(fmtPtr, "CI8")) == 0 )
402 		fmt = TPL_IMAGE_TEXEL_FMT_CI8;
403 
404     //=========================================================================================
405 	// note: input palette sizes other than 8-bit/ @256 entry are not supported in this version.
406     //       if output palette is CI4, tc will use the low 4-bits of each index.
407     //       if output palette is CI14_X2, tc will only create up to 256 'real' entries;
408     //       the remaining palette entries will be padded with zeroes.
409 
410 	else if( (strcmp(fmtPtr, "CI4")) == 0 )
411 		fmt = TPL_IMAGE_TEXEL_FMT_CI4;
412 	else if( (strcmp(fmtPtr, "CI14_X2")) == 0 )
413 		fmt = TPL_IMAGE_TEXEL_FMT_CI14_X2;
414 
415     //==========================================================================================
416 
417 	else if( (strcmp(fmtPtr, "CMPR")) == 0 )
418 		fmt = TPL_IMAGE_TEXEL_FMT_CMP;
419 
420 	else
421 		TCErrorMsg( "ProcessImKey: unknown output format '%s' for image %d in script file \n", fmtPtr, index );
422 
423 
424 	// if mipmap numbers are included, get their values
425 	if( minLODPtr )
426 		minLOD   = atoi( minLODPtr );
427 	if( maxLODPtr )
428 		maxLOD   = atoi( maxLODPtr );
429 	if( baseLODPtr )
430 		baseLOD  = atoi( baseLODPtr );
431 
432 	if( wrapSPtr )
433     {
434         if( (strcmp(wrapSPtr, "GX_REPEAT")) == 0 )
435 		    wrapS = TPL_WRAP_MODE_REPEAT;
436 	    else if( (strcmp(wrapSPtr, "GX_CLAMP")) == 0 )
437 		    wrapS = TPL_WRAP_MODE_CLAMP;
438 	    else if( (strcmp(wrapSPtr, "GX_MIRROR")) == 0 )
439 		    wrapS = TPL_WRAP_MODE_MIRROR;
440         else
441             TCErrorMsg( "ProcessImKey: unknown wrapS mode '%s' for image %d in script file \n", wrapSPtr, index );
442     }
443     else
444     {
445         // Wrap mode will be set to defaults in TCWriteTplFile by TCSetFilterModeByDim in TCTPLToolbox.cpp
446         // We have to wait until then since TCSetFilterModeByDim needs information we don't have right now
447         wrapS = TPL_WRAP_MODE_NONE;
448     }
449 
450     if( wrapTPtr )
451     {
452 	    if( (strcmp(wrapTPtr, "GX_REPEAT")) == 0 )
453 		    wrapT = TPL_WRAP_MODE_REPEAT;
454 	    else if( (strcmp(wrapTPtr, "GX_CLAMP")) == 0 )
455 		    wrapT = TPL_WRAP_MODE_CLAMP;
456 	    else if( (strcmp(wrapTPtr, "GX_MIRROR")) == 0 )
457 		    wrapT = TPL_WRAP_MODE_MIRROR;
458         else
459             TCErrorMsg( "ProcessImKey: unknown wrapT mode '%s' for image %d in script file \n", wrapTPtr, index );
460     }
461     else
462     {
463         // Wrap mode will be set to defaults in TCWriteTplFile by TCSetFilterModeByDim in TCTPLToolbox.cpp
464         // We have to wait until then since TCSetFilterModeByDim needs information we don't have right now
465         wrapT = TPL_WRAP_MODE_NONE;
466     }
467 
468 	// create a new Image structure and set its attributes.
469 	// 'index' is also used as the final tpl bank location
470 	newIm = TCNewImage();
471     TCAssertMsg( (newIm != NULL), "ProcessImKey: couldn't allocate new image %d\n", index );
472 
473 	// set new image attributes
474 	TCSetImageIndex(       newIm, index                   );
475 	TCSetImageLayerAtt(    newIm, icNum, iaNum            );
476     TCSetImageTexelFormat( newIm, fmt                     );
477     TCSetImageMipMap(      newIm, minLOD, maxLOD, baseLOD );
478     TCSetImageWrap(        newIm, wrapS, wrapT            );
479 }
480 
481 /*>*******************************(*)*******************************<*/
TCProcessPlKey(u32 index,char * attList)482 static void TCProcessPlKey ( u32 index, char* attList )
483 {
484 	char*      psPtr, *fmtPtr;
485 	u32        psNum,  fmt;
486 	TCPalette* newPl;
487 
488 
489     // 'X'ed out index? ignore this key
490     if( index == TC_UNUSED )
491     {
492         return;
493     }
494 
495     TCAssertMsg( (attList  != NULL), "TCProcessPlKey: missing attribute list for palette %d in script file\n", index );
496     TCAssertMsg( (*attList != '\0'), "TCProcessPlKey: missing attribute list for palette %d in script file\n", index );
497 
498 
499 	// split the attList string into tokens using commas as separators.
500 	// remove whitespace from around tokens.
501 	psPtr  = strtok( attList, "," );
502 	TCAssertMsg( (psPtr != NULL), "ProcessPlKey: problem reading file index for palette %d in script file\n", index );
503 
504 	fmtPtr = strtok( NULL,    ""  );
505 	TCAssertMsg( (fmtPtr != NULL), "ProcessPlKey: problem reading output format for palette %d in script file\n", index );
506 
507 
508 	// strip whitespace from these tokens
509 	TCStripBlanks( psPtr,    1,1 );
510 	TCStripBlanks( fmtPtr,   1,1 );
511 
512 	// set the palette color layer
513     // (color and alpha must come from the same source image)
514     TCGetKeyNum ( psPtr, &psNum );
515     TCAssertMsg( (psNum != TC_UNUSED), "TCProcessPlKey: invalid color index for palette %d in script file\n", index );
516 
517 	// set the palette entry format
518 	// note: IA8 format is not supported yet.
519 	if( (strcmp(fmtPtr, "RGB565")) == 0 )
520 	{
521 		fmt = TPL_PALETTE_ENTRY_FMT_R5G6B5;
522 	}
523 	else if( (strcmp(fmtPtr, "RGB5A3")) == 0 )
524 	{
525 		fmt = TPL_PALETTE_ENTRY_FMT_RGB5A3;
526 	}
527 	else if( (strcmp(fmtPtr, "IA8")) == 0 )
528 	{
529 		TCErrorMsg( "ProcessPlKey: tc does not support output format '%s'. (palette %d in script file)\n", fmtPtr, index );
530 	}
531 	else
532 	{
533 		TCErrorMsg( "ProcessPlKey: unknown output format '%s' for palette %d in script file\n", fmtPtr, index );
534 	}
535 
536 	// create a new Palette structure and set its attributes.
537 	// 'index' is also used as the implied bank location
538 	newPl = TCNewPalette();
539 	TCAssertMsg( (newPl != NULL), "ProcessPlKey: couldn't allocate palette %d\n", index );
540 
541 	// set palette values
542 	TCSetPaletteIndex(       newPl, index );
543     TCSetPaletteSrcImage(    newPl, psNum );
544     TCSetPaletteEntryFormat( newPl, fmt   );
545 }
546 
547 /*>*******************************(*)*******************************<*/
TCProcessTxKey(u32 index,char * attList)548 static void TCProcessTxKey ( u32 index, char* attList )
549 {
550 	char*      imPtr, *plPtr;
551 	u32        imNum,  plNum;
552 	TCTexture* newTx;
553 
554 
555     // 'X'ed out index? ignore this key
556     if( index == TC_UNUSED )
557     {
558         return;
559     }
560 
561     TCAssertMsg( (attList  != NULL), "TCProcessTxKey: missing attribute list for texture %d in script file\n", index );
562     TCAssertMsg( (*attList != '\0'), "TCProcessTxKey: missing attribute list for texture %d in script file\n", index );
563 
564 
565 	// split the attList string into tokens using commas as separators.
566 	// remove whitespace from around tokens.
567 	imPtr  = strtok( attList, "," );
568 	TCAssertMsg( (imPtr != NULL), "ProcessTxKey: problem reading image index for texture %d in script file\n", index );
569 
570 	plPtr  = strtok( NULL,    "," );
571 	TCAssertMsg( (plPtr != NULL), "ProcessTxKey: problem reading palette index for texture %d in script file\n", index );
572 
573 	// strip whitespace from these tokens
574 	TCStripBlanks( imPtr, 1,1 );
575 	TCStripBlanks( plPtr, 1,1 );
576 
577     // image index is mandatory
578     TCGetKeyNum ( imPtr, &imNum );
579     TCAssertMsg( (imNum != TC_UNUSED), "TCProcessTxKey: invalid image index for texture %d in script file\n", index );
580 
581     // palette index is optional.
582     // if no palette, plNum will be set to TC_UNUSED
583     TCGetKeyNum ( plPtr, &plNum );
584 
585 	// create a new Texture structure and set its attributes.
586 	// 'index' is also used as the implied bank location
587 	newTx = TCNewTexture();
588     TCAssertMsg( (newTx != NULL), "ProcessTxKey(): couldn't allocate new Texture %d\n", index );
589 
590     // set texture values
591 	TCSetTextureAttributes( newTx, index, imNum, plNum );
592 }
593 
594 /*>*******************************(*)*******************************<*/
595 // split lineBuff into two tokens separated by an '=' sign,
596 // strip away any leading/trailing whitespace
597 //
598 // note: while there is guaranteed to be at least a one character
599 //		 non-whitespace string for leftSide, rightSide may end up
600 //		 as NULL if no '=' was found.  this could happen if the
601 //		 'key' was actually just a line of text without a ';' comment
602 //		 delineator.  The problem will be caught by TCProcessKeyName().
603 /*>*******************************(*)*******************************<*/
TCGetKeyTokens(char * lineBuff,char * leftSide,char * rightSide)604 static void TCGetKeyTokens ( char* lineBuff, char* leftSide, char* rightSide )
605 {
606 	char* left, *right;
607 
608 
609     // safety check
610 	if( (lineBuff == NULL) || (leftSide == NULL) || (rightSide == NULL) )
611 	{
612 		return;
613 	}
614 
615 	*leftSide  = '\0';
616 	*rightSide = '\0';
617 
618 	if( *lineBuff == '\0')
619 	{
620 		return;
621 	}
622 
623 	// use the '=' sign as leftSide/rightSide separator
624 	if( (left = strtok( lineBuff, "=" )) == 0 )
625 	{
626 		return;
627 	}
628 
629 	strcpy(leftSide, left);
630 	TCStripBlanks( leftSide, 1, 1 );
631 
632 	if( (right = strtok( NULL,     ""  )) == 0 )
633 	{
634 		return;
635 	}
636 
637 	strcpy(rightSide, right);
638 	TCStripBlanks( rightSide, 1, 1 );
639 }
640 
641 /*>*******************************(*)*******************************<*/
642 // get the string equivalent of the key name ( the 'N' portion of 'keyN')
643 // and place it in dstStr.  num will hold the converted result.
644 // note: if *srcStr == TC_BLANK value (TCCommon.h),
645 //       *num will be set to TC_UNUSED
646 /*>*******************************(*)*******************************<*/
TCGetKeyNum(char * srcStr,u32 * num)647 static void TCGetKeyNum ( char* srcStr, u32* num )
648 {
649 	u32   found  = 0;
650 	char  numStr[10];
651     char* numPtr = NULL;
652 	char  subStr[NAME_SIZE];
653     char* subPtr = NULL;
654 
655 
656     // initialize *num
657     *num = TC_UNUSED;
658 
659 	// safety check
660 	if( (srcStr == NULL) || (*srcStr == '\0') )         // no string; return TC_UNUSED
661 	{
662 		return;
663 	}
664 
665 	strcpy(subStr, srcStr);                             // if no string left after 'TCStripBlanks,
666 	TCStripBlanks(subStr, 1, 1);                        // while loop will not execute;
667                                                         // return TC_UNUSED
668 
669 
670 	subPtr = subStr;                                    // collect base-10 digits from
671 	numPtr = numStr;
672     while( *subPtr != '\0' )                            // *subStr to the first non-digit value
673 	{
674         if( (isdigit(*subPtr)) != 0 )
675         {
676             found = 1;
677 		    *numPtr++ = *subPtr++;
678 		    continue;
679         }
680 
681         break;  // reached only if *subStr was not a base-10 digit
682 	}
683 	*numPtr = '\0';
684 
685 
686 	if(found)                                          // number found - convert to int value
687 	{
688 	    *num = (u32)atoi(numStr);
689     }
690 }
691 
692 /*>*******************************(*)*******************************<*/
693 // check the right side string for any ';' delineated comments.
694 // leading/trailing blanks have already been stripped
695 //
696 // note: src and dst may be the same address, so a temporary string is used
697 /*>*******************************(*)*******************************<*/
TCGetKeyString(char * srcStr,char * dstStr)698 static void TCGetKeyString( char* srcStr, char* dstStr )
699 {
700 	char* name;
701 	char  tmp[NAME_SIZE];
702 	u32   count = 0;
703 
704 
705     // safety check
706 	if( (srcStr == NULL) || (dstStr == NULL) )
707 	{
708 		return;
709 	}
710 
711 	// srcStr could be an empty string
712 	if( *srcStr == '\0')
713 	{
714         *dstStr = '\0';
715 		return;
716 	}
717 
718 	// strip away any trailing comment- if the whole string was a comment, return.
719 	if( (name = strtok(srcStr, ";")) == 0 )
720 	{
721 		*dstStr = '\0';
722 		return;
723 	}
724 
725 	// trim any trailing blanks between the name and any removed comment
726 	TCStripBlanks(name, 0, 1 );
727 
728 	// copy out the modified name
729 	count = 0;
730 	while(  (tmp[count] = name[count]) != '\0' )
731 	{
732 		count++;
733 	}
734 	count = 0;
735 	while( (dstStr[count] = tmp[count]) != '\0' )
736 	{
737 		count++;
738 	}
739 }
740 
741 /*>*******************************(*)*******************************<*/
742 // strip leading and trailing blanks from a string.
743 // if leading or trailing == 1, strip blanks from the indicated end
744 // else if leading or trailing == 0, do not strip blanks from the
745 // indicated end
746 /*>*******************************(*)*******************************<*/
TCStripBlanks(char * srcStr,u32 leading,u32 trailing)747 static void TCStripBlanks ( char* srcStr, u32 leading, u32 trailing )
748 {
749 	u32   i,        len;
750 	char* startPtr, *endPtr;
751 	char  tmpStr[NAME_SIZE];
752 
753 
754 	if( srcStr == NULL )
755 	{
756 		return;
757 	}
758 
759 	len = strlen(srcStr);
760 	if( (len == 0) || (len > (NAME_SIZE-1)) )
761 	{
762         TCErrorMsg( "TCStripBlanks: invalid string length %d for string '%s'\n", srcStr );
763 	}
764 
765 
766 	startPtr = srcStr;
767 
768 	// strip leading blanks
769 	if( leading == 1 )
770 	{
771 		while( (*startPtr != '\0') && ( (isspace(*startPtr)) != 0 ) )
772 		{
773 			startPtr++;
774 		}
775 	}
776 
777 	// strip trailing blanks
778 	if( trailing == 1 )
779 	{
780 		if( *startPtr != '\0')
781 		{
782 			endPtr = startPtr + (strlen(startPtr)) - 1;
783 
784 			while( (endPtr >= startPtr) && ((isspace(*endPtr)) != 0) )
785 			{
786 				endPtr--;
787 			}
788 
789 			endPtr++;
790 			*endPtr = '\0';
791 		}
792 	}
793 
794 	// replace the original string with the stripped string
795 	len = strlen(startPtr);
796 	for(i=0; i <= len; i++) // include the '\0'
797 	{
798 		tmpStr[i] = startPtr[i];
799 	}
800 	for(i=0; i <= len; i++)
801 	{
802 		srcStr[i] = tmpStr[i];
803 	}
804 }
805 
806 /*>*******************************(*)*******************************<*/
807