view src/sexypsf/Misc.c @ 493:31d21ad70903 trunk

[svn] flac 113 plugin: stability fixes and a new option to disable bitrate update in player window during playback (saves cpu, this is the solution for most people playing flac and reporting high cpu usage)
author giacomo
date Sun, 21 Jan 2007 16:08:19 -0800
parents 3da1b8942b8b
children 2ebeb7816c5e
line wrap: on
line source

/*  Pcsx - Pc Psx Emulator
 *  Copyright (C) 1999-2002  Pcsx Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "audacious/vfs.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

#include "PsxCommon.h"
#include "driver.h"

// LOAD STUFF

typedef struct {
    unsigned char id[8];
    u32 text;                   
    u32 data;                    
    u32 pc0;
    u32 gp0;                     
    u32 t_addr;
    u32 t_size;
    u32 d_addr;                  
    u32 d_size;                  
    u32 b_addr;                  
    u32 b_size;                  
    u32 S_addr;//normal must a s not a S but error (???)
    u32 s_size;
    u32 SavedSP;
    u32 SavedFP;
    u32 SavedGP;
    u32 SavedRA;
    u32 SavedS0;
} PACKSTRUCT EXE_HEADER;

static long TimeToMS(const char *str)
{
             int x,c=0;
             int acc=0;
	     char s[100];

	     strncpy(s,str,100);
	     s[99]=0;

             for(x=strlen(s);x>=0;x--)
              if(s[x]=='.' || s[x]==',')
              {
               acc=atoi(s+x+1);
               s[x]=0;
              }
              else if(s[x]==':')
              {
               if(c==0) acc+=atoi(s+x+1)*10;
               else if(c==1) acc+=atoi(s+x+(x?1:0))*10*60;
               c++;
               s[x]=0;
              }
              else if(x==0)
	      {
               if(c==0) acc+=atoi(s+x)*10;
               else if(c==1) acc+=atoi(s+x)*10*60;
               else if(c==2) acc+=atoi(s+x)*10*60*60;
	      }
             acc*=100;  // To milliseconds.
	    return(acc);
}

char *GetFileWithBase(char *f, char *newfile)
{
  static char *ret;
  char *tp1;
                       
 #if PSS_STYLE==1
     tp1=((char *)strrchr(f,'/'));
 #else
     tp1=((char *)strrchr(f,'\\'));
  #if PSS_STYLE!=3
  {
     char *tp3;

     tp3=((char *)strrchr(f,'/'));
     if(tp1<tp3) tp1=tp3;
  }
  #endif
 #endif
     if(!tp1)
     {
      ret=malloc(strlen(newfile)+1);
      strcpy(ret,newfile);
     }
     else              
     {
      ret=malloc(tp1-f+2+strlen(newfile));	// 1(NULL), 1(/).
      memcpy(ret,f,tp1-f);
      ret[tp1-f]='/';
      ret[tp1-f+1]=0;
      strcat(ret,newfile);
     }
    return(ret);
}

static int GetKeyVal(char *buf, char **key, char **val)
{
 char *tmp;

 tmp=buf;

 /* First, convert any weirdo ASCII characters to spaces. */
 while(*tmp++) if(*tmp>0 && *tmp<0x20) *tmp=0x20;

 /* Strip off white space off end of string(which should be the "value"). */
 for(tmp=buf+strlen(buf)-1;tmp>=buf;tmp--)
 {
  if(*tmp != 0x20) break;
  *tmp=0;
 }

 /* Now, search for the first non-whitespace character. */
 while(*buf == 0x20) buf++; 

 tmp=buf;
 while((*buf != 0x20) && (*buf != '=')) 
 {
  if(!*buf) return(0);	/* Null character. */
  buf++;
 }

 /* Allocate memory, copy string, and terminate string. */
 if(!(*key=malloc(buf-tmp+1))) return(0);
 strncpy(*key,tmp,buf-tmp);
 (*key)[(buf-tmp)]=0;

 /* Search for "=" character. */
 while(*buf != '=')
 {
  if(!*buf) return(0);  /* Null character. */
  buf++;
 }

 buf++;	/* Skip over equals character. */

 /* Remove leading whitespace on value. */
 while(*buf == 0x20)
 {
  if(!*buf) return(0);  /* Null character. */
  buf++;
 }

 /* Allocate memory, and copy string over.  Trailing whitespace was eliminated
    earlier.
 */

 if(!(*val=malloc(strlen(buf)+1))) return(0);
 strcpy(*val,buf);

 //puts(*key);
 //puts(*val);

 return(1);
}

static void FreeTags(PSFTAG *tags)
{
 while(tags)
 {
  PSFTAG *tmp=tags->next;

  free(tags->key);
  free(tags->value);
  free(tags);

  tags=tmp;
 }
}

static void AddKV(PSFTAG **tag, char *key, char *val)
{
 PSFTAG *tmp;

 tmp=malloc(sizeof(PSFTAG));
 memset(tmp,0,sizeof(PSFTAG));

 tmp->key=key;
 tmp->value=val;
 tmp->next=0;

 if(!*tag) *tag=tmp;
 else 
 {
  PSFTAG *rec;
  rec=*tag;
  while(rec->next) rec=rec->next;
  rec->next=tmp;
 }

}

typedef struct {
	int num;
	char *value;
} LIBNCACHE;

static int ccomp(const void *v1, const void *v2)
{
 const LIBNCACHE *a1,*a2;
 a1=v1; a2=v2;

 return(a1->num - a2->num);
}

static PSFINFO *LoadPSF(char *path, int level, int type) // Type==1 for just info load.
{
        VFSFile *fp;
        EXE_HEADER tmpHead;
        unsigned char *in,*out=0;
	u8 head[4];
        u32 reserved;
        u32 complen;
        u32 crc32; 
        uLongf outlen;
	PSFINFO *psfi;
	PSFINFO *tmpi;

        if(!(fp=vfs_fopen(path,"rb")))
 	{
         printf("path %s failed to load\n", path);
	 return(0);
	}
 
	vfs_fread(head,1,4,fp);
	if(memcmp(head,"PSF\x01",4)) return(0);

	psfi=malloc(sizeof(PSFINFO));
	memset(psfi,0,sizeof(PSFINFO));
        psfi->stop=~0;
        psfi->fade=0; 

        vfs_fread(&reserved,1,4,fp);
        vfs_fread(&complen,1,4,fp);
	complen=BFLIP32(complen);

        vfs_fread(&crc32,1,4,fp);
	crc32=BFLIP32(crc32);

        vfs_fseek(fp,reserved,SEEK_CUR);

        if(type)
	 vfs_fseek(fp,complen,SEEK_CUR);
        else
        {
         in=malloc(complen);
         out=malloc(1024*1024*2+0x800);
         vfs_fread(in,1,complen,fp);
         outlen=1024*1024*2;
         uncompress(out,&outlen,in,complen);
         free(in);
         memcpy(&tmpHead,out,sizeof(EXE_HEADER));
         psxRegs.pc = BFLIP32(tmpHead.pc0);
         psxRegs.GPR.n.gp = BFLIP32(tmpHead.gp0);
         psxRegs.GPR.n.sp = BFLIP32(tmpHead.S_addr);
         if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;

 	 if(level)
 	 {
	  LoadPSXMem(BFLIP32(tmpHead.t_addr),BFLIP32(tmpHead.t_size),out+0x800);
          free(out);
	 }
        }

        {
         u8 tagdata[5];
         if(vfs_fread(tagdata,1,5,fp)==5)
         {
          if(!memcmp(tagdata,"[TAG]",5))
          {
           char linebuf[1024];

           while(vfs_fgets(linebuf,1024,fp))
           {
            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)
	    {
	     char *tmpfn;
	     /* Load file name "value" from the directory specified in
		the full path(directory + file name) "path"
	     */
	     tmpfn=GetFileWithBase(path,value);
	     if(!(tmpi=LoadPSF(tmpfn,level+1,0))) 
	     {
	      free(key);
	      free(value);
	      free(tmpfn);
 	      if(!level) free(out);
	      vfs_fclose(fp);
	      FreeTags(psfi->tags);
	      free(psfi);
	      return(0);
	     }
	     FreeTags(tmpi->tags);
	     free(tmpi);
	     free(tmpfn);
	    }
           }
          }
         }
        }  

        vfs_fclose(fp);

	/* Now, if we're at level 0(main PSF), load the main executable, and any libN stuff */
        if(!level && !type)
        {
         LoadPSXMem(BFLIP32(tmpHead.t_addr),BFLIP32(tmpHead.t_size),out+0x800);
	 free(out);
        }

	if(!type)	/* 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];
	   char *tmpfn;

 	   if(cache[cur].num < 2) continue;

	   ba[0]=psxRegs.pc;
	   ba[1]=psxRegs.GPR.n.gp;
	   ba[2]=psxRegs.GPR.n.sp;

           /* Load file name "value" from the directory specified in
                the full path(directory + file name) "path"
             */
           tmpfn=GetFileWithBase(path,cache[cur].value);
           if(!(tmpi=LoadPSF(tmpfn,level+1,0)))
           {
            //free(key);
            //free(value);
            //free(tmpfn);
            //vfs_fclose(fp);
            //return(0);
           }
           free(tmpfn);
	   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);
}

void sexypsf_freepsfinfo(PSFINFO *info)
{
 FreeTags(info->tags);
 free(info);
}

PSFINFO *sexypsf_getpsfinfo(char *path)
{
	PSFINFO *ret;
        if(!(ret=LoadPSF(path,0,1))) return(0);
        if(ret->stop==(u32)~0) ret->fade=0;
        ret->length=ret->stop+ret->fade;
        return(ret);	
}

PSFINFO *sexypsf_load(char *path) 
{
	PSFINFO *ret;

        psxInit();
        psxReset();

        SPUinit();
        SPUopen();

	if(!(ret=LoadPSF(path,0,0)))
	{
	 psxShutdown();
	 return(0);
	}

	if(ret->stop==(u32)~0) ret->fade=0; // Infinity+anything is still infinity...or is it?
	SPUsetlength(ret->stop,ret->fade);
	ret->length=ret->stop+ret->fade;

        return(ret);
}

void sexypsf_execute(void)
{
 psxCpu->Execute();
}