void TextMessageParse( byte *pMemFile, int fileSize ) { char buf[512], trim[512]; char *pCurrentText=0, *pNameHeap; char currentName[512], nameHeap[ NAME_HEAP_SIZE ]; int lastNamePos; int mode = MSGFILE_NAME; // Searching for a message name int lineNumber, filePos, lastLinePos; int messageCount; client_textmessage_t textMessages[ MAX_MESSAGES ]; int i, nameHeapSize, textHeapSize, messageSize, nameOffset; lastNamePos = 0; lineNumber = 0; filePos = 0; lastLinePos = 0; messageCount = 0; CharacterSetBuild( &g_WhiteSpace, " \r\n\t" ); while( memfgets( pMemFile, fileSize, &filePos, buf, 512 ) != NULL ) { if(messageCount>=MAX_MESSAGES) { Sys_Error("tmessage::TextMessageParse : messageCount>=MAX_MESSAGES"); } TrimSpace( buf, trim ); switch( mode ) { case MSGFILE_NAME: if ( IsComment( trim ) ) // Skip comment lines break; if ( ParseDirective( trim ) ) // Is this a directive "$command"?, if so parse it and break break; if ( IsStartOfText( trim ) ) { mode = MSGFILE_TEXT; pCurrentText = (char*)(pMemFile + filePos); break; } if ( IsEndOfText( trim ) ) { Con_DPrintf("Unexpected '}' found, line %d\n", lineNumber ); return; } strcpy( currentName, trim ); break; case MSGFILE_TEXT: if ( IsEndOfText( trim ) ) { int length = strlen(currentName); // Save name on name heap if ( lastNamePos + length > 8192 ) { Con_DPrintf("Error parsing file!\n" ); return; } strcpy( nameHeap + lastNamePos, currentName ); // Terminate text in-place in the memory file (it's temporary memory that will be deleted) pMemFile[ lastLinePos - 1 ] = 0; // Save name/text on heap textMessages[ messageCount ] = gMessageParms; textMessages[ messageCount ].pName = nameHeap + lastNamePos; lastNamePos += strlen(currentName) + 1; textMessages[ messageCount ].pMessage = pCurrentText; messageCount++; // Reset parser to search for names mode = MSGFILE_NAME; break; } if ( IsStartOfText( trim ) ) { Con_DPrintf("Unexpected '{' found, line %d\n", lineNumber ); return; } break; } lineNumber++; lastLinePos = filePos; if ( messageCount >= MAX_MESSAGES ) { Con_Printf("WARNING: TOO MANY MESSAGES IN TITLES.TXT, MAX IS %d\n", MAX_MESSAGES ); break; } } Con_DPrintf("Parsed %d text messages\n", messageCount ); nameHeapSize = lastNamePos; textHeapSize = 0; for ( i = 0; i < messageCount; i++ ) textHeapSize += strlen( textMessages[i].pMessage ) + 1; messageSize = (messageCount * sizeof(client_textmessage_t)); // Must malloc because we need to be able to clear it after initialization gMessageTable = (client_textmessage_t *)malloc( textHeapSize + nameHeapSize + messageSize ); // Copy table over memcpy( gMessageTable, textMessages, messageSize ); // Copy Name heap pNameHeap = ((char *)gMessageTable) + messageSize; memcpy( pNameHeap, nameHeap, nameHeapSize ); nameOffset = pNameHeap - gMessageTable[0].pName; // Copy text & fixup pointers pCurrentText = pNameHeap + nameHeapSize; for ( i = 0; i < messageCount; i++ ) { gMessageTable[i].pName += nameOffset; // Adjust name pointer (parallel buffer) strcpy( pCurrentText, gMessageTable[i].pMessage ); // Copy text over gMessageTable[i].pMessage = pCurrentText; pCurrentText += strlen( pCurrentText ) + 1; } #if _DEBUG if ( (pCurrentText - (char *)gMessageTable) != (textHeapSize + nameHeapSize + messageSize) ) Con_Printf("Overflow text message buffer!!!!!\n"); #endif gMessageTableCount = messageCount; }
NOXREF void TextMessageParse(unsigned char *pMemFile, int fileSize) { NOXREFCHECK; char buf[512]; char trim[512]; char *pCurrentText; char *pNameHeap; char currentName[512]; char nameHeap[NAME_HEAP_SIZE]; int lastNamePos; int mode; int lineNumber; int filePos; int lastLinePos; int messageCount; client_textmessage_t textMessages[MAX_MESSAGES]; int i; int nameHeapSize; int textHeapSize; int messageSize; int nameOffset; lastNamePos = 0; lineNumber = 0; filePos = 0; lastLinePos = 0; messageCount = 0; mode = MSGFILE_NAME; while (memfgets(pMemFile, fileSize, &filePos, buf, 512) != NULL) { if(messageCount >= MAX_MESSAGES) Sys_Error("%s: messageCount >= MAX_MESSAGES", __func__); TrimSpace(buf, trim); switch (mode) { case MSGFILE_NAME: { if (IsComment(trim)) break; if (ParseDirective(trim)) break; if (IsStartOfText(trim)) { mode = MSGFILE_TEXT; pCurrentText = (char *)(pMemFile + filePos); break; } if (IsEndOfText(trim)) { Con_DPrintf("Unexpected '}' found, line %d\n", lineNumber); return; } Q_strncpy(currentName, trim, 511); currentName[511] = 0; break; } case MSGFILE_TEXT: { if (IsEndOfText(trim)) { int length = Q_strlen(currentName); if (lastNamePos + length > sizeof(nameHeap)) { Con_DPrintf("Error parsing file! length > %i bytes\n", sizeof(nameHeap)); return; } Q_strcpy(nameHeap + lastNamePos, currentName); pMemFile[lastLinePos - 1] = 0; textMessages[messageCount] = gMessageParms; textMessages[messageCount].pName = nameHeap + lastNamePos; lastNamePos += Q_strlen(currentName) + 1; textMessages[messageCount].pMessage = pCurrentText; messageCount++; mode = MSGFILE_NAME; break; } if (IsStartOfText(trim)) { Con_DPrintf("Unexpected '{' found, line %d\n", lineNumber); return; } break; } } lineNumber++; lastLinePos = filePos; } Con_DPrintf("Parsed %d text messages\n", messageCount); nameHeapSize = lastNamePos; textHeapSize = 0; for (i = 0; i < messageCount; i++) textHeapSize += Q_strlen(textMessages[i].pMessage) + 1; messageSize = (messageCount * sizeof(client_textmessage_t)); gMessageTable = (client_textmessage_t *)Mem_Malloc(textHeapSize + nameHeapSize + messageSize); Q_memcpy(gMessageTable, textMessages, messageSize); pNameHeap = ((char *)gMessageTable) + messageSize; Q_memcpy(pNameHeap, nameHeap, nameHeapSize); nameOffset = pNameHeap - gMessageTable[0].pName; pCurrentText = pNameHeap + nameHeapSize; for (i = 0; i < messageCount; i++) { gMessageTable[i].pName += nameOffset; Q_strcpy(pCurrentText, gMessageTable[i].pMessage); gMessageTable[i].pMessage = pCurrentText; pCurrentText += Q_strlen(pCurrentText) + 1; } gMessageTableCount = messageCount; }
// LoadPSF for Memory static PSFINFO *memLoadPSF(char *addr, long size, int level, int type) // Type==1 for just info load. { u8 *in,*out=0; u8 head[4]; u32 reserved; u32 complen; u32 crc32; uLongf outlen; PSFINFO *psfi=NULL; PSFINFO *tmpi=NULL; u32 poffset, plength; u32 offset = 0; if( addr == NULL || size == 0 ) return(0); memread((void*)(head), 4, addr, size, &offset); if(memcmp(head,"PSF\x01",4)) return(0); psfi=malloc(sizeof(PSFINFO)); memset(psfi,0,sizeof(PSFINFO)); psfi->stop=~0; psfi->fade=0; memread((void*)(&reserved), 4, addr, size, &offset); memread((void*)(&complen), 4, addr, size, &offset); complen=BFLIP32(complen); memread((void*)(&crc32), 4, addr, size, &offset); crc32=BFLIP32(crc32); memseek(reserved, size, &offset); if(type) { memseek(complen, size, &offset); } else { in=malloc(complen); out=malloc(1024*1024*2+0x800); if( !in || !out ) { free(psfi); return (0); } memread((void*)(in), complen, addr, size, &offset); outlen=1024*1024*2; uncompress(out,&outlen,in,complen); free(in); psxRegs->pc = out[0x10] | out[0x11]<<8 | out[0x12]<<16 | out[0x13]<<24; psxRegs->GPR.n.gp = out[0x14] | out[0x15]<<8 | out[0x16]<<16 | out[0x17]<<24; psxRegs->GPR.n.sp = out[0x30] | out[0x31]<<8 | out[0x32]<<16 | out[0x33]<<24; if (psxRegs->GPR.n.sp == 0) psxRegs->GPR.n.sp = 0x801fff00; #ifdef DEBUG fprintf(stderr, "%d Level: PC %x GP %x SP %x\n", level, psxRegs->pc, psxRegs->GPR.n.gp, psxRegs->GPR.n.sp); #endif if(level) { poffset = out[0x18] | out[0x19]<<8 | out[0x1a]<<16 | out[0x1b]<<24; poffset &= 0x3fffffff; // kill any MIPS cache segment indicators plength = out[0x1c] | out[0x1d]<<8 | out[0x1e]<<16 | out[0x1f]<<24; #ifdef DEBUG fprintf(stderr, "%d Level: offset %x plength: %d\n", level, poffset, plength); #endif LoadPSXMem(poffset,plength,out+0x800); free(out); // I don't really know how does this // work, but apparently it breaks the // loop that makes ff6 and ct to take // several seconds to start ... if( crc32 == 0xEFDE8EEE || crc32 == 0x545D9F65 ) psxMemWrite32(0x5A66C, 0); // Same as above for Popolocrois and Einhänder if( crc32 == 0xF535726 ) psxMemWrite32(0x5A990, 0); } } { u8 tagdata[5]; if( memread((void*)(tagdata), 5, addr, size, &offset) == 5 ) { if(!memcmp(tagdata,"[TAG]",5)) { char linebuf[1024]; while( memfgets(linebuf, 1024, addr, size, &offset)>0 ) { int x; char *key=0,*value=0; if(!GetKeyVal(linebuf,&key,&value)) { if(key) free(key); if(value) free(value); continue; } AddKV(&psfi->tags,key,value); if(!level) { static char *yoinks[8]={"title","artist","game","year","genre", "copyright","psfby","comment"}; char **yoinks2[8]={&psfi->title,&psfi->artist,&psfi->game,&psfi->year,&psfi->genre, &psfi->copyright,&psfi->psfby,&psfi->comment}; for(x=0;x<8;x++) if(!strcasecmp(key,yoinks[x])) *yoinks2[x]=value; if(!strcasecmp(key,"length")) psfi->stop=TimeToMS(value); else if(!strcasecmp(key,"fade")) psfi->fade=TimeToMS(value); } if(!strcasecmp(key,"_lib") && !type && __psflibs) { /* Search file name "value" from the __psflibs array */ int n, found = 0; for(n=0;n<__psflibs->count;n++) if( !strcasecmp(value, __psflibs->libn[n].name) ) { found = 1; break; } if(!found || !(tmpi=memLoadPSF(__psflibs->libn[n].addr, __psflibs->libn[n].size, level+1,0))) { free(key); free(value); if(!level) free(out); FreeTags(psfi->tags); free(psfi); return(0); } FreeTags(tmpi->tags); free(tmpi); } } } } } /* Now, if we're at level 0(main PSF), load the main executable, and any libN stuff*/ if(!level && !type) { poffset = out[0x18] | out[0x19]<<8 | out[0x1a]<<16 | out[0x1b]<<24; poffset &= 0x3fffffff; // kill any MIPS cache segment indicators plength = out[0x1c] | out[0x1d]<<8 | out[0x1e]<<16 | out[0x1f]<<24; // TODO - investigate: should i just make // plength = outlen-0x800? // Philosoma has an illegal "plength". *sigh* if (plength > (outlen-0x800)) { plength = outlen-0x800; } if( psfi->game ) { // Suikoden Tenmei has an illegal "plength". *sigh sigh* if( !strncmp(psfi->game, "Suikoden: Tenmei no Chikai", 26) ) { plength = outlen-0x800; } // Einhänder has an illegal "plength". *sigh sigh sigh* if( !strncmp(psfi->game, "Einhänder", 9) ) { plength = outlen-0x800; } } #ifdef DEBUG fprintf(stderr, "%d Level: offset %x plength: %d\n", level, poffset, plength); #endif LoadPSXMem(poffset,plength,out+0x800); free(out); } if(!type && __psflibs) /* Load libN */ { LIBNCACHE *cache; PSFTAG *tag; unsigned int libncount=0; unsigned int cur=0; tag=psfi->tags; while(tag) { if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) libncount++; tag=tag->next; } if(libncount) { cache=malloc(sizeof(LIBNCACHE)*libncount); tag=psfi->tags; while(tag) { if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) { cache[cur].num=atoi(&tag->key[4]); cache[cur].value=tag->value; cur++; } tag=tag->next; } qsort(cache, libncount, sizeof(LIBNCACHE), ccomp); for(cur=0;cur<libncount;cur++) { u32 ba[3]; if(cache[cur].num < 2) continue; ba[0]=psxRegs->pc; ba[1]=psxRegs->GPR.n.gp; ba[2]=psxRegs->GPR.n.sp; /* Search file name "value" from the __psflibs array */ int n, found = 0; for(n=0;n<__psflibs->count;n++) if( !strcasecmp(cache[cur].value, __psflibs->libn[n].name) ) { found = 1; break; } if(!found || !(tmpi=memLoadPSF(__psflibs->libn[n].addr,__psflibs->libn[n].size,level+1,0))) { //free(key); //free(value); //free(tmpfn); //fclose(fp); //return(0); } FreeTags(tmpi->tags); free(tmpi); psxRegs->pc=ba[0]; psxRegs->GPR.n.gp=ba[1]; psxRegs->GPR.n.sp=ba[2]; } free(cache); } // if(libncount) } // if(!type) return(psfi); }