diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..577fae8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +psp2/*.o +psp2/*.elf +psp2/*.velf +psp2/build_vita/* +psp2/*.a diff --git a/core/tremor/sharedbook.c b/core/tremor/sharedbook.c index 8e07492..3fd379d 100644 --- a/core/tremor/sharedbook.c +++ b/core/tremor/sharedbook.c @@ -34,7 +34,7 @@ int _ilog(unsigned int v){ } /* 32 bit float (not IEEE; nonnormalized mantissa + - biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm + biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm Why not IEEE? It's just not that important here. */ #define VQ_FEXP 10 @@ -77,12 +77,12 @@ ogg_uint32_t *_make_words(long *l,long n,long sparsecount){ long length=l[i]; if(length>0){ ogg_uint32_t entry=marker[length]; - + /* when we claim a node for an entry, we also claim the nodes below it (pruning off the imagined tree that may have dangled from it) as well as blocking the use of any nodes directly above for leaves */ - + /* update ourself */ if(length<32 && (entry>>length)){ /* error condition; the lengths must specify an overpopulated tree */ @@ -90,12 +90,12 @@ ogg_uint32_t *_make_words(long *l,long n,long sparsecount){ return(NULL); } r[count++]=entry; - + /* Look to see if the next shorter marker points to the node above. if so, update it and repeat. */ { for(j=length;j>0;j--){ - + if(marker[j]&1){ /* have to jump branches */ if(j==1) @@ -108,7 +108,7 @@ ogg_uint32_t *_make_words(long *l,long n,long sparsecount){ marker[j]++; } } - + /* prune the tree; the implicit invariant says all the longer markers were dangling from our just-taken node. Dangle them from our *new* node. */ @@ -121,7 +121,7 @@ ogg_uint32_t *_make_words(long *l,long n,long sparsecount){ }else if(sparsecount==0)count++; } - + /* bitreverse the words because our bitwise packer/unpacker is LSb endian */ for(i=0,count=0;idim;k++){ int index= (j/indexdiv)%quantvals; - int point=0; + ogg_int32_t point=0; int val=VFLOAT_MULTI(delta,delpoint, abs(b->quantlist[index]),&point); val=VFLOAT_ADD(mindel,minpoint,val,point,&point); val=VFLOAT_ADD(last,lastpoint,val,point,&point); - + if(b->q_sequencep){ - last=val; + last=val; lastpoint=point; } - + if(sparsemap){ r[sparsemap[count]*b->dim+k]=val; rp[sparsemap[count]*b->dim+k]=point; @@ -244,15 +244,15 @@ ogg_int32_t *_book_unquantize(const static_codebook *b,int n,int *sparsemap, int lastpoint=0; for(k=0;kdim;k++){ - int point=0; + ogg_int32_t point=0; int val=VFLOAT_MULTI(delta,delpoint, abs(b->quantlist[j*b->dim+k]),&point); val=VFLOAT_ADD(mindel,minpoint,val,point,&point); val=VFLOAT_ADD(last,lastpoint,val,point,&point); - + if(b->q_sequencep){ - last=val; + last=val; lastpoint=point; } @@ -274,7 +274,7 @@ ogg_int32_t *_book_unquantize(const static_codebook *b,int n,int *sparsemap, for(j=0;jdim;j++) if(rp[j]<*maxpoint) r[j]>>=*maxpoint-rp[j]; - + _ogg_free(rp); return(r); } @@ -324,7 +324,7 @@ int vorbis_book_init_decode(codebook *c,const static_codebook *s){ int i,j,n=0,tabn; int *sortindex; memset(c,0,sizeof(*c)); - + /* count actually used entries */ for(i=0;ientries;i++) if(s->lengthlist[i]>0) @@ -335,20 +335,20 @@ int vorbis_book_init_decode(codebook *c,const static_codebook *s){ c->dim=s->dim; if(n>0){ - /* two different remappings go on here. - + /* two different remappings go on here. + First, we collapse the likely sparse codebook down only to actually represented values/words. This collapsing needs to be indexed as map-valueless books are used to encode original entry positions as integers. - + Second, we reorder all vectors, including the entry index above, by sorted bitreversed codeword to allow treeless decode. */ - + /* perform sort */ ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries); ogg_uint32_t **codep=(ogg_uint32_t **)alloca(sizeof(*codep)*n); - + if(codes==NULL)goto err_out; for(i=0;icodelist[sortindex[i]]=codes[i]; _ogg_free(codes); - - - + + + c->valuelist=_book_unquantize(s,n,sortindex,&c->binarypoint); c->dec_index=(int *)_ogg_malloc(n*sizeof(*c->dec_index)); - + for(n=0,i=0;ientries;i++) if(s->lengthlist[i]>0) c->dec_index[sortindex[n++]]=i; - + c->dec_codelengths=(char *)_ogg_malloc(n*sizeof(*c->dec_codelengths)); for(n=0,i=0;ientries;i++) if(s->lengthlist[i]>0) c->dec_codelengths[sortindex[n++]]=s->lengthlist[i]; - + c->dec_firsttablen=_ilog(c->used_entries)-4; /* this is magic */ if(c->dec_firsttablen<5)c->dec_firsttablen=5; if(c->dec_firsttablen>8)c->dec_firsttablen=8; - + tabn=1<dec_firsttablen; c->dec_firsttable=(ogg_uint32_t *)_ogg_calloc(tabn,sizeof(*c->dec_firsttable)); c->dec_maxlength=0; - + for(i=0;idec_maxlengthdec_codelengths[i]) c->dec_maxlength=c->dec_codelengths[i]; @@ -401,26 +401,26 @@ int vorbis_book_init_decode(codebook *c,const static_codebook *s){ c->dec_firsttable[orig|(j<dec_codelengths[i])]=i+1; } } - + /* now fill in 'unused' entries in the firsttable with hi/lo search hints for the non-direct-hits */ { ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen); long lo=0,hi=0; - + for(i=0;idec_firsttablen); if(c->dec_firsttable[bitreverse(word)]==0){ while((lo+1)codelist[lo+1]<=word)lo++; while( hi=(c->codelist[hi]&mask))hi++; - + /* we only actually have 15 bits per hint to play with here. In order to overflow gracefully (nothing breaks, efficiency just drops), encode as the difference from the extremes. */ { unsigned long loval=lo; unsigned long hival=n-hi; - + if(loval>0x7fff)loval=0x7fff; if(hival>0x7fff)hival=0x7fff; c->dec_firsttable[bitreverse(word)]= @@ -436,4 +436,3 @@ int vorbis_book_init_decode(codebook *c,const static_codebook *s){ vorbis_book_clear(c); return(-1); } - diff --git a/core/vdp_render.c b/core/vdp_render.c index 43fccec..13f7102 100644 --- a/core/vdp_render.c +++ b/core/vdp_render.c @@ -143,7 +143,7 @@ INLINE void WRITE_LONG(void *address, uint32 data) atex = atex_table[(ATTR >> 29) & 7]; \ src = (uint32 *)&bg_pattern_cache[((ATTR & 0x03FF0000) >> 9 | (ATTR & 0x18000000) >> 10 | (LINE)) ^ ((ATTR & 0x10000000) >> 22)]; -/* +/* One column = 2 tiles Two pattern attributes are written in VRAM as two consecutives 16-bit words: @@ -264,7 +264,7 @@ INLINE void WRITE_LONG(void *address, uint32 data) /* This might be faster or slower than original method, depending on */ /* architecture (x86, PowerPC), cache size, memory access speed, etc... */ -#ifdef LSB_FIRST +#ifdef LSB_FIRST #define DRAW_BG_TILE(SRC_A, SRC_B) \ *lb++ = table[((SRC_B << 8) & 0xff00) | (SRC_A & 0xff)]; \ *lb++ = table[(SRC_B & 0xff00) | ((SRC_A >> 8) & 0xff)]; \ @@ -279,7 +279,7 @@ INLINE void WRITE_LONG(void *address, uint32 data) #endif #ifdef ALIGN_LONG -#ifdef LSB_FIRST +#ifdef LSB_FIRST #define DRAW_BG_COLUMN(ATTR, LINE, SRC_A, SRC_B) \ GET_LSB_TILE(ATTR, LINE) \ SRC_A = READ_LONG((uint32 *)lb); \ @@ -325,7 +325,7 @@ INLINE void WRITE_LONG(void *address, uint32 data) DRAW_BG_TILE(SRC_A, SRC_B) \ SRC_A = READ_LONG((uint32 *)lb); \ SRC_B = (src[1] | atex); \ - DRAW_BG_TILE(SRC_A, SRC_B) + DRAW_BG_TILE(SRC_A, SRC_B) #define DRAW_BG_COLUMN_IM2(ATTR, LINE, SRC_A, SRC_B) \ GET_MSB_TILE_IM2(ATTR, LINE) \ SRC_A = READ_LONG((uint32 *)lb); \ @@ -343,7 +343,7 @@ INLINE void WRITE_LONG(void *address, uint32 data) DRAW_BG_TILE(SRC_A, SRC_B) #endif #else /* NOT ALIGNED */ -#ifdef LSB_FIRST +#ifdef LSB_FIRST #define DRAW_BG_COLUMN(ATTR, LINE, SRC_A, SRC_B) \ GET_LSB_TILE(ATTR, LINE) \ SRC_A = *(uint32 *)(lb); \ @@ -470,8 +470,11 @@ INLINE void WRITE_LONG(void *address, uint32 data) /* 5:5:5 RGB */ #elif defined(USE_15BPP_RENDERING) +#if defined(USE_ABGR) +#define MAKE_PIXEL(r,g,b) ((1 << 15) | (b) << 11 | ((b) >> 3) << 10 | (g) << 6 | ((g) >> 3) << 5 | (r) << 1 | (r) >> 3) +#else #define MAKE_PIXEL(r,g,b) ((1 << 15) | (r) << 11 | ((r) >> 3) << 10 | (g) << 6 | ((g) >> 3) << 5 | (b) << 1 | (b) >> 3) - +#endif /* 5:6:5 RGB */ #elif defined(USE_16BPP_RENDERING) #define MAKE_PIXEL(r,g,b) ((r) << 12 | ((r) >> 3) << 11 | (g) << 7 | ((g) >> 2) << 5 | (b) << 1 | (b) >> 3) @@ -573,7 +576,7 @@ static uint8 linebuf[2][0x200]; static uint8 spr_ovr; /* Sprite parsing lists */ -typedef struct +typedef struct { uint16 ypos; uint16 xpos; @@ -620,7 +623,7 @@ static void make_name_lut(void) if ((vrow > height) || vcol > width) { /* Invalid settings (unused) */ - name_lut[i] = -1; + name_lut[i] = -1; } else { @@ -691,8 +694,8 @@ static uint32 make_lut_bg(uint32 bx, uint32 ax) int bf = (bx & 0x7F); int bp = (bx & 0x40); int b = (bx & 0x0F); - - int af = (ax & 0x7F); + + int af = (ax & 0x7F); int ap = (ax & 0x40); int a = (ax & 0x0F); @@ -712,8 +715,8 @@ static uint32 make_lut_bg_ste(uint32 bx, uint32 ax) int bf = (bx & 0x7F); int bp = (bx & 0x40); int b = (bx & 0x0F); - - int af = (ax & 0x7F); + + int af = (ax & 0x7F); int ap = (ax & 0x40); int a = (ax & 0x0F); @@ -761,7 +764,7 @@ static uint32 make_lut_bgobj(uint32 bx, uint32 sx) int bs = (bx & 0x80); int bp = (bx & 0x40); int b = (bx & 0x0F); - + int sf = (sx & 0x3F); int sp = (sx & 0x40); int s = (sx & 0x0F); @@ -897,7 +900,7 @@ static uint32 make_lut_bgobj_ste(uint32 bx, uint32 sx) } } else - { + { c = (bf | bi); } } @@ -914,7 +917,7 @@ static uint32 make_lut_bgobj_ste(uint32 bx, uint32 sx) static uint32 make_lut_bgobj_m4(uint32 bx, uint32 sx) { int c; - + int bf = (bx & 0x3F); int bs = (bx & 0x80); int bp = (bx & 0x20); @@ -971,7 +974,7 @@ static void palette_init(void) /* GG mode : xxxx (0-15) */ /* */ /* with x = original CRAM value (2, 3 or 4-bit) */ - /* (*) 2-bit CRAM value is expanded to 4-bit */ + /* (*) 2-bit CRAM value is expanded to 4-bit */ /************************************************/ /* Initialize Mode 5 pixel color look-up tables */ @@ -1308,7 +1311,7 @@ void render_bg_m3(int line) do { color = pg[*nt++ << 3]; - + *lb++ = 0x10 | ((color >> 4) & 0x0F); *lb++ = 0x10 | ((color >> 4) & 0x0F); *lb++ = 0x10 | ((color >> 4) & 0x0F); @@ -1346,7 +1349,7 @@ void render_bg_m3x(int line) do { color = pg[*nt++ << 3]; - + *lb++ = 0x10 | ((color >> 4) & 0x0F); *lb++ = 0x10 | ((color >> 4) & 0x0F); *lb++ = 0x10 | ((color >> 4) & 0x0F); @@ -1394,10 +1397,10 @@ void render_bg_m4(int line) int column; uint16 *nt; uint32 attr, atex, *src; - + /* 32 x 8 pixels */ int width = 32; - + /* Horizontal scrolling */ int index = ((reg[0] & 0x40) && (line < 0x10)) ? 0x100 : reg[0x08]; int shift = index & 7; @@ -1422,7 +1425,7 @@ void render_bg_m4(int line) { /* Vertical scroll mask */ v_line = v_line % 256; - + /* Pattern name Table */ nt = (uint16 *)&vram[(0x3700 & nt_mask) + ((v_line >> 3) << 6)]; } @@ -1727,7 +1730,7 @@ void render_bg_m5_vs(int line) atbuf = nt[index & pf_col_mask]; DRAW_COLUMN(atbuf, v_line) } - + if (w == (line >= a)) { /* Window takes up entire line */ @@ -1755,7 +1758,7 @@ void render_bg_m5_vs(int line) #else shift = (xscroll >> 16) & 0x0F; index = pf_col_mask + start + 1 - ((xscroll >> 20) & pf_col_mask); -#endif +#endif if(shift) { @@ -2315,7 +2318,7 @@ void render_bg_m5(int line) /* Plane B name table */ nt = (uint32 *)&vram[ntbb + (((v_line >> 3) << pf_shift) & 0x1FC0)]; - + /* Pattern row index */ v_line = (v_line & 7) << 3; @@ -2330,7 +2333,7 @@ void render_bg_m5(int line) atbuf = nt[(index-1) & pf_col_mask]; DRAW_BG_COLUMN(atbuf, v_line, xscroll, yscroll) } - + for(column = 0; column < width; column++, index++) { atbuf = nt[index & pf_col_mask]; @@ -2555,7 +2558,7 @@ void render_bg_m5_im2(int line) /* Window vertical range (cell 0-31) */ int a = (reg[18] & 0x1F) << 3; - + /* Window position (0=top, 1=bottom) */ int w = (reg[18] >> 7) & 1; @@ -2714,7 +2717,7 @@ void render_bg_m5_im2_vs(int line) /* Window vertical range (cell 0-31) */ uint32 a = (reg[18] & 0x1F) << 3; - + /* Window position (0=top, 1=bottom) */ uint32 w = (reg[18] >> 7) & 1; @@ -3037,7 +3040,7 @@ void render_obj_m4(int line) /* Default sprite width */ int width = 8; - + /* Sprite Generator address mask (LSB is masked for 8x16 sprites) */ uint16 sg_mask = (~0x1C0 ^ (reg[6] << 6)) & (~((reg[1] & 0x02) >> 1)); @@ -3099,7 +3102,7 @@ void render_obj_m4(int line) { /* Draw sprite pattern (zoomed sprites are rendered at half speed) */ DRAW_SPRITE_TILE_ACCURATE_2X(end,0,lut[5]) - + /* 315-5124 VDP specific */ if (system_hw < SYSTEM_SMS2) { @@ -3697,7 +3700,7 @@ void parse_satb_m4(int line) /* Y position */ int ypos; - + /* Sprite list for next line */ object_info_t *object_info = obj_info[(line + 1) & 1]; @@ -3837,11 +3840,11 @@ void parse_satb_m5(int line) break; } - /* Update sprite list (only name, attribute & xpos are parsed from VRAM) */ + /* Update sprite list (only name, attribute & xpos are parsed from VRAM) */ object_info->attr = p[link + 2]; object_info->xpos = p[link + 3] & 0x1ff; object_info->ypos = ypos; - object_info->size = size & 0x0f; + object_info->size = size & 0x0f; /* Increment Sprite count */ ++count; @@ -3851,7 +3854,7 @@ void parse_satb_m5(int line) } } - /* Read link data from internal SAT cache */ + /* Read link data from internal SAT cache */ link = (q[link + 1] & 0x7F) << 2; /* Stop parsing if link data points to first entry (#0) or after the last entry (#64 in H32 mode, #80 in H40 mode) */ diff --git a/core/vdp_render.h b/core/vdp_render.h index 3d7dc93..add94b8 100644 --- a/core/vdp_render.h +++ b/core/vdp_render.h @@ -51,11 +51,17 @@ /* 5:5:5 RGB */ #elif defined(USE_15BPP_RENDERING) +#if defined(USE_ABGR) +#define PIXEL(r,g,b) ((1 << 15) | ((b) << 10) | ((g) << 5) | (r)) +#define GET_B(pixel) (((pixel) & 0x7c00) >> 10) +#define GET_G(pixel) (((pixel) & 0x03e0) >> 5) +#define GET_R(pixel) (((pixel) & 0x001f) >> 0) +#else #define PIXEL(r,g,b) ((1 << 15) | ((r) << 10) | ((g) << 5) | (b)) #define GET_R(pixel) (((pixel) & 0x7c00) >> 10) #define GET_G(pixel) (((pixel) & 0x03e0) >> 5) #define GET_B(pixel) (((pixel) & 0x001f) >> 0) - +#endif /* 5:6:5 RGB */ #elif defined(USE_16BPP_RENDERING) #define PIXEL(r,g,b) (((r) << 11) | ((g) << 5) | (b)) @@ -134,4 +140,3 @@ extern void (*parse_satb)(int line); extern void (*update_bg_pattern_cache)(int index); #endif /* _RENDER_H_ */ - diff --git a/psp2/Makefile b/psp2/Makefile new file mode 100644 index 0000000..36bb06a --- /dev/null +++ b/psp2/Makefile @@ -0,0 +1,180 @@ + +# Makefile for genplus SDL +# +# (c) 1999, 2000, 2001, 2002, 2003 Charles MacDonald +# modified by Eke-Eke +# +# Defines : +# -DLSB_FIRST : for little endian systems. +# -DLOGERROR : enable message logging +# -DLOGVDP : enable VDP debug messages +# -DLOGSOUND : enable AUDIO debug messages +# -DLOG_SCD : enable SCD debug messages +# -DLOG_CDD : enable CDD debug messages +# -DLOG_CDC : enable CDC debug messages +# -DLOG_PCM : enable PCM debug messages +# -DLOGSOUND : enable AUDIO debug messages +# -D8BPP_RENDERING - configure for 8-bit pixels (RGB332) +# -D15BPP_RENDERING - configure for 15-bit pixels (RGB555) +# -D16BPP_RENDERING - configure for 16-bit pixels (RGB565) +# -D32BPP_RENDERING - configure for 32-bit pixels (RGB888) + +NAME = gen_vita +PSP_APP_NAME=GENPLUSGXVITA +PSP_APP_VER=1.7.5 + +CC = arm-vita-eabi-gcc +CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing -ansi -std=c11 \ +-pedantic-errors -fno-unwind-tables -fno-asynchronous-unwind-tables -ftree-vectorize \ +-mfloat-abi=hard -ffast-math -fsingle-precision-constant -ftree-vectorizer-verbose=2 -fopt-info-vec-optimized -funroll-loops +#-g -ggdb -pg +#-fomit-frame-pointer +LDFLAGS = -Wl,-q +DEFINES = -DPSP_APP_NAME=\"$(PSP_APP_NAME)\" -DPSP_APP_VER=\"$(PSP_APP_VER)\" \ + -DLSB_FIRST -DUSE_15BPP_RENDERING -DUSE_LIBTREMOR -DALT_RENDERER -DALIGN_LONG -DHAVE_ALLOCA_H -DUSE_ABGR +SRCDIR = ../core +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/z80 -I$(SRCDIR)/m68k -I$(SRCDIR)/sound -I$(SRCDIR)/input_hw -I$(SRCDIR)/cart_hw -I$(SRCDIR)/cart_hw/svp -I$(SRCDIR)/cd_hw -I$(SRCDIR)/ntsc -I$(SRCDIR)/tremor -I$(SRCDIR)/../psp2 +LIBS = -lpsplib -lvita2d -lfreetype -lpng -lz -lm -lSceDisplay_stub -lSceGxm_stub \ + -lSceCtrl_stub -lSceAudio_stub -lSceRtc_stub -lScePower_stub -lSceAppUtil_stub +#-ldebugnet -lSceNet_stub -lSceNetCtl_stub + +OBJDIR = ./build_vita + +OBJECTS = $(OBJDIR)/z80.o + +OBJECTS += $(OBJDIR)/m68kcpu.o \ + $(OBJDIR)/s68kcpu.o + +OBJECTS += $(OBJDIR)/genesis.o \ + $(OBJDIR)/vdp_ctrl.o \ + $(OBJDIR)/vdp_render.o \ + $(OBJDIR)/system.o \ + $(OBJDIR)/io_ctrl.o \ + $(OBJDIR)/mem68k.o \ + $(OBJDIR)/memz80.o \ + $(OBJDIR)/membnk.o \ + $(OBJDIR)/state.o \ + $(OBJDIR)/loadrom.o + +OBJECTS += $(OBJDIR)/input.o \ + $(OBJDIR)/gamepad.o \ + $(OBJDIR)/lightgun.o \ + $(OBJDIR)/mouse.o \ + $(OBJDIR)/activator.o \ + $(OBJDIR)/xe_1ap.o \ + $(OBJDIR)/teamplayer.o \ + $(OBJDIR)/paddle.o \ + $(OBJDIR)/sportspad.o \ + $(OBJDIR)/terebi_oekaki.o \ + $(OBJDIR)/graphic_board.o + +OBJECTS += $(OBJDIR)/sound.o \ + $(OBJDIR)/sn76489.o \ + $(OBJDIR)/ym2413.o \ + $(OBJDIR)/ym2612.o + +OBJECTS += $(OBJDIR)/blip_buf.o + +OBJECTS += $(OBJDIR)/eq.o + +OBJECTS += $(OBJDIR)/sram.o \ + $(OBJDIR)/svp.o \ + $(OBJDIR)/ssp16.o \ + $(OBJDIR)/ggenie.o \ + $(OBJDIR)/areplay.o \ + $(OBJDIR)/eeprom_93c.o \ + $(OBJDIR)/eeprom_i2c.o \ + $(OBJDIR)/eeprom_spi.o \ + $(OBJDIR)/md_cart.o \ + $(OBJDIR)/sms_cart.o + +OBJECTS += $(OBJDIR)/scd.o \ + $(OBJDIR)/cdd.o \ + $(OBJDIR)/cdc.o \ + $(OBJDIR)/gfx.o \ + $(OBJDIR)/pcm.o \ + $(OBJDIR)/cd_cart.o + +OBJECTS += $(OBJDIR)/sms_ntsc.o \ + $(OBJDIR)/md_ntsc.o + +OBJECTS += $(OBJDIR)/main.o \ + $(OBJDIR)/emumain.o \ + $(OBJDIR)/menu.o \ + $(OBJDIR)/config.o \ + $(OBJDIR)/error.o \ + $(OBJDIR)/unzip.o \ + $(OBJDIR)/fileio.o + +OBJECTS += $(OBJDIR)/bitwise.o \ + $(OBJDIR)/block.o \ + $(OBJDIR)/codebook.o \ + $(OBJDIR)/floor0.o \ + $(OBJDIR)/floor1.o \ + $(OBJDIR)/framing.o \ + $(OBJDIR)/info.o \ + $(OBJDIR)/mapping0.o \ + $(OBJDIR)/mdct.o \ + $(OBJDIR)/registry.o \ + $(OBJDIR)/res012.o \ + $(OBJDIR)/sharedbook.o \ + $(OBJDIR)/synthesis.o \ + $(OBJDIR)/vorbisfile.o \ + $(OBJDIR)/window.o + + +all: $(NAME).velf + +$(NAME).velf: $(NAME).elf + #advice from xyzz strip before create elf + arm-vita-eabi-strip -g $< + #i put db.json there use your location + vita-elf-create $< $@ db.json + +$(NAME).elf: $(OBJDIR) $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@ + +$(OBJDIR) : + @[ -d $@ ] || mkdir -p $@ + +$(OBJDIR)/%.o : $(SRCDIR)/%.c $(SRCDIR)/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/sound/%.c $(SRCDIR)/sound/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/input_hw/%.c $(SRCDIR)/input_hw/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/%.c $(SRCDIR)/cart_hw/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c $(SRCDIR)/cart_hw/svp/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cd_hw/%.c $(SRCDIR)/cd_hw/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/z80/%.c $(SRCDIR)/z80/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/m68k/%.c + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/ntsc/%.c $(SRCDIR)/ntsc/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c $(SRCDIR)/tremor/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/../psp2/%.c $(SRCDIR)/../psp2/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +clean: + rm -f $(OBJECTS) $(NAME).velf $(NAME).elf diff --git a/psp2/config.c b/psp2/config.c new file mode 100644 index 0000000..93f2ae3 --- /dev/null +++ b/psp2/config.c @@ -0,0 +1,54 @@ + +#include "osd.h" + +t_config config; + +void set_config_defaults(void) +{ + int i; + + /* sound options */ + config.psg_preamp = 150; + config.fm_preamp = 100; + config.hq_fm = 0; + config.psgBoostNoise = 1; + config.filter = 1; + config.low_freq = 200; + config.high_freq = 8000; + config.lg = 1.0; + config.mg = 1.0; + config.hg = 1.0; + config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */ + config.dac_bits = 14; + config.ym2413 = 2; /* = AUTO (0 = always OFF, 1 = always ON) */ + config.mono = 0; + + /* system options */ + config.system = 0; /* = AUTO (or SYSTEM_SG, SYSTEM_MARKIII, SYSTEM_SMS, SYSTEM_SMS2, SYSTEM_GG, SYSTEM_MD) */ + config.region_detect = 0; /* = AUTO (1 = USA, 2 = EUROPE, 3 = JAPAN/NTSC, 4 = JAPAN/PAL) */ + config.vdp_mode = 0; /* = AUTO (1 = NTSC, 2 = PAL) */ + config.master_clock = 0; /* = AUTO (1 = NTSC, 2 = PAL) */ + config.force_dtack = 0; + config.addr_error = 1; + config.bios = 0; + config.lock_on = 0; /* = OFF (can be TYPE_SK, TYPE_GG & TYPE_AR) */ + config.ntsc = 0; + config.lcd = 0; /* 0.8 fixed point */ + + /* display options */ + config.overscan = 0; /* 3 = all borders (0 = no borders , 1 = vertical borders only, 2 = horizontal borders only) */ + config.gg_extra = 0; /* 1 = show extended Game Gear screen (256x192) */ + config.render = 0; /* 1 = double resolution output (only when interlaced mode 2 is enabled) */ + + /* controllers options */ + input.system[0] = SYSTEM_GAMEPAD; + input.system[1] = SYSTEM_GAMEPAD; + config.gun_cursor[0] = 1; + config.gun_cursor[1] = 1; + config.invert_mouse = 0; + for (i=0;i +#include +#include "time.h" +#include + +#define SCE_KERNEL_OK 0 + +#include "psplib/pl_rewind.h" +#include "psplib/pl_file.h" +#include "psplib/pl_snd.h" +#include "psplib/pl_perf.h" +#include "psplib/pl_util.h" +#include "psplib/pl_psp.h" +#include "psplib/video.h" +#include "psplib/ctrl.h" + +#include "shared.h" +#include "sound.h" +#include "system.h" +#include "md_ntsc.h" +#include "sms_ntsc.h" + +//#include + +#define ip_server "192.168.1.130" +#define port_server 18194 + +PspImage *Screen; +pl_rewind Rewinder; + +static pl_perf_counter FpsCounter; +static int ClearScreen; +static int ScreenX, ScreenY, ScreenW, ScreenH; +static int TicksPerUpdate; +static u32 TicksPerSecond; +static u64 LastTick; +static u64 CurrentTick; +static int Frame; + +static int Rewinding; + +extern pl_file_path CurrentGame; +extern EmulatorOptions Options; +extern const u64 ButtonMask[]; +extern const int ButtonMapId[]; +extern struct ButtonConfig ActiveConfig; +extern char *ScreenshotPath; + +static short soundbuffer[SOUND_SAMPLES*2*10]; +static int soundPosWrite = 0; +static int soundPosRead = 0; +static SceUID console_mtx; + + + +static inline void RenderVideo(); +static void AudioCallback(pl_snd_sample* buf, + unsigned int samples, + void *userdata); +void MixerCallback(int16 **stream, int16 **output, int length); +md_ntsc_t *md_ntsc; +sms_ntsc_t *sms_ntsc; + +int bEmulate; + +void osd_input_update() +{ + + /* Reset input */ + input.pad[0] = 0; + input.analog[0][0] = 0x7F; + + static SceCtrlData pad; + static int autofire_status = 0; + + /* Check the input */ + if (pspCtrlPollControls(&pad)) + { + if (--autofire_status < 0) + autofire_status = Options.AutoFire; + + /* Parse input */ + int i, on, code; + for (i = 0; ButtonMapId[i] >= 0; i++) + { + code = ActiveConfig.ButtonMap[ButtonMapId[i]]; + on = (pad.buttons & ButtonMask[i]) == ButtonMask[i]; + + /* Check to see if a button set is pressed. If so, unset it, so it */ + /* doesn't trigger any other combination presses. */ + if (on) pad.buttons &= ~ButtonMask[i]; + + if (code & AFI) + { + if (on && (autofire_status == 0)) + input.pad[0] |= CODE_MASK(code); + continue; + } + else if (code & JOY) + { + if (on) { + input.pad[0] |= CODE_MASK(code); + } + continue; + } + else if (code & SYS) + { + if (on) + { + if (CODE_MASK(code) == (INPUT_START)) + input.system[0] |= INPUT_START; + } + continue; + } + + + if (code & SPC) + { + switch (CODE_MASK(code)) + { + case SPC_MENU: + if (on) bEmulate=0; + break; + case SPC_REWIND: + Rewinding = on; + break; + } + } + } + } + + return; + } + +void InitEmulator() +{ + + //debugNetInit(ip_server,port_server,DEBUG); + + set_config_defaults(); + + ClearScreen = 0; + + /* Initialize screen buffer */ + Screen = pspImageCreateVram(720, 576, PSP_IMAGE_16BPP); + + // pspImageClear(Screen, 0x8000); + + console_mtx = sceKernelCreateSema("sound_sema", 0, 0, 1, 0); + /*if (console_mtx > 0) { + debugNetPrintf(DEBUG,"Sound Mutex UID: 0x%08X\n", console_mtx); + }*/ + + /* Set up bitmap structure */ + memset(&bitmap, 0, sizeof(t_bitmap)); + bitmap.width = Screen->Width; + bitmap.height = Screen->Height; + bitmap.pitch = (bitmap.width * 2); + bitmap.data = (unsigned char *)Screen->Pixels; + bitmap.viewport.changed = 3; + + pl_snd_set_callback(0, AudioCallback, NULL); +} + +void RunEmulator() +{ + float ratio; + //debugNetPrintf(DEBUG,"RunEmulator\n"); + + pspImageClear(Screen, 0); + //debugNetPrintf(DEBUG,"ImageClear\n"); + + + if(bitmap.viewport.changed & 1) + { + bitmap.viewport.changed &= ~1; + + /* source bitmap */ + Screen->Viewport.Width = bitmap.viewport.w+2*bitmap.viewport.x; + Screen->Viewport.Height = bitmap.viewport.h+2*bitmap.viewport.y; + + } + + /* Recompute screen size/position */ + switch (Options.DisplayMode) + { + default: + case DISPLAY_MODE_UNSCALED: + ScreenW = Screen->Viewport.Width; + ScreenH = Screen->Viewport.Height; + break; + case DISPLAY_MODE_FIT_HEIGHT: + ratio = (float)SCR_HEIGHT / (float)Screen->Viewport.Height; + ScreenW = (float)bitmap.viewport.w * ratio - 2; + ScreenH = SCR_HEIGHT; + break; + case DISPLAY_MODE_FILL_SCREEN: + ScreenW = SCR_WIDTH; + ScreenH = SCR_HEIGHT; + break; + case DISPLAY_MODE_2X: + ScreenW = Screen->Viewport.Width*2; + ScreenH = Screen->Viewport.Height*2; + break; + case DISPLAY_MODE_3X: + ScreenW = Screen->Viewport.Width*3; + ScreenH = Screen->Viewport.Height*3; + break; + } + //debugNetPrintf(DEBUG,"screensize %d %d\n" ,Screen->Viewport.Width ,Screen->Viewport.Height); + + ScreenX = (SCR_WIDTH / 2) - (ScreenW / 2); + ScreenY = (SCR_HEIGHT / 2) - (ScreenH / 2); + + /* Init performance counter */ + pl_perf_init_counter(&FpsCounter); + + /* Recompute update frequency */ + TicksPerSecond = sceRtcGetTickResolution(); + if (Options.UpdateFreq) + { + TicksPerUpdate = TicksPerSecond + / (Options.UpdateFreq / (Options.Frameskip + 1)); + sceRtcGetCurrentTick(&LastTick); + } + Frame = 0; + ClearScreen = 2; + Rewinding = 0; + +//pl_rewind_realloc(&Rewinder); + + int frames_until_save = 0; + + /* Resume sound */ + pl_snd_resume(0); + + /* Wait for V. refresh */ + pspVideoWaitVSync(); + + bEmulate = 1; + /* Main emulation loop */ + while (!ExitPSP&&bEmulate) + { + /* Rewind/save state */ + /*if (!Rewinding) + { + if (--frames_until_save <= 0) + { + frames_until_save = Options.RewindSaveRate; + pl_rewind_save(&Rewinder); + } + } + else + { + frames_until_save = Options.RewindSaveRate; + if (!pl_rewind_restore(&Rewinder)) + continue; + }*/ + + /* Run the system emulation for a frame */ + if (++Frame <= Options.Frameskip) + { + /* Skip frame */ + if (system_hw == SYSTEM_MCD) + { + system_frame_scd(1); + } + else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD) + { + system_frame_gen(1); + } + else + { + system_frame_sms(1); + } + } + else + { + if (system_hw == SYSTEM_MCD) + { + system_frame_scd(0); + } + else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD) + { + system_frame_gen(0); + } + else + { + system_frame_sms(0); + } + + Frame = 0; + /* Display */ + if(bitmap.viewport.changed & 1) + { + bitmap.viewport.changed &= ~1; + + /* source bitmap */ + Screen->Viewport.Width = bitmap.viewport.w+2*bitmap.viewport.x; + Screen->Viewport.Height = bitmap.viewport.h+2*bitmap.viewport.y; + + /* Recompute screen size/position */ + switch (Options.DisplayMode) + { + default: + case DISPLAY_MODE_UNSCALED: + ScreenW = Screen->Viewport.Width; + ScreenH = Screen->Viewport.Height; + break; + case DISPLAY_MODE_FIT_HEIGHT: + ratio = (float)SCR_HEIGHT / (float)Screen->Viewport.Height; + ScreenW = (float)bitmap.viewport.w * ratio - 2; + ScreenH = SCR_HEIGHT; + break; + case DISPLAY_MODE_FILL_SCREEN: + ScreenW = SCR_WIDTH; + ScreenH = SCR_HEIGHT; + break; + case DISPLAY_MODE_2X: + ScreenW = Screen->Viewport.Width*2; + ScreenH = Screen->Viewport.Height*2; + break; + case DISPLAY_MODE_3X: + ScreenW = Screen->Viewport.Width*3; + ScreenH = Screen->Viewport.Height*3; + break; + } + + ScreenX = (SCR_WIDTH / 2) - (ScreenW / 2); + ScreenY = (SCR_HEIGHT / 2) - (ScreenH / 2); + + } + //debugNetPrintf(DEBUG,"main %d %d \n",soundPosRead,soundPosWrite); + int size = audio_update(&soundbuffer[soundPosRead])*2; + //debugNetPrintf(DEBUG,"filling %d \n",size); + + soundPosRead +=size; + if(soundPosRead+size>=(SOUND_SAMPLES*2*10)){ + soundPosRead = 0; + } + if((soundPosRead-soundPosWrite)>=(SOUND_SAMPLES*2)||(soundPosRead-soundPosWrite)<0){ + sceKernelSignalSema(console_mtx, 1); //lock + } + RenderVideo(); + + } + } + + /* Stop sound */ + pl_snd_pause(0); +} + +void TrashEmulator() +{ + pl_rewind_destroy(&Rewinder); + + /* Trash screen */ + if (Screen) pspImageDestroy(Screen); + + if (CurrentGame[0] != '\0') + { + /* Release emulation resources */ + audio_shutdown(); + error_shutdown(); + } + //debugNetFinish(); + +} + + + +void RenderVideo() +{ + /* Update the display */ + pspVideoBegin(); + + /* Clear the buffer first, if necessary */ + if (ClearScreen >= 0) + { + ClearScreen--; + pspVideoClearScreen(); + } + + pspVideoPutImage(Screen, ScreenX, ScreenY, ScreenW, ScreenH); + + /* Show FPS counter */ + if (Options.ShowFps) + { + static char fps_display[32]; + sprintf(fps_display, " %3.02f", pl_perf_update_counter(&FpsCounter)); + + int width = pspFontGetTextWidth(&PspStockFont, fps_display); + int height = pspFontGetLineHeight(&PspStockFont); + + pspVideoFillRect(SCR_WIDTH - width, 0, SCR_WIDTH, height, PSP_COLOR_BLACK); + pspVideoPrint(&PspStockFont, SCR_WIDTH - width, 0, fps_display, PSP_COLOR_WHITE); + } + + pspVideoEnd(); + + /* Wait if needed */ + if (Options.UpdateFreq) + { + do { sceRtcGetCurrentTick(&CurrentTick); } + while (CurrentTick - LastTick < TicksPerUpdate); + LastTick = CurrentTick; + } + + /* Wait for VSync signal */ + if (Options.VSync) + pspVideoWaitVSync(); + + /* Swap buffers */ + pspVideoSwapBuffers(); +} + +static void AudioCallback(pl_snd_sample *buf, + unsigned int samples, + void *userdata) +{ + int i; + //debugNetPrintf(DEBUG,"wait %d %d \n",totalSamples,samples); + if (!Rewinding) + { + short* ptr_s = (short*)buf; + //debugNetPrintf(DEBUG,"wait %d %d \n",soundPosRead,soundPosWrite); + if((soundPosRead-soundPosWrite)=(SOUND_SAMPLES*2*10)){ + soundPosWrite = 0; + } + } + else /* Render silence */ + for (i = 0; i < samples; i++) + buf[i].stereo.l = buf[i].stereo.r = 0; +} diff --git a/psp2/emumain.h b/psp2/emumain.h new file mode 100644 index 0000000..25fe1f6 --- /dev/null +++ b/psp2/emumain.h @@ -0,0 +1,77 @@ +#ifndef _EMUMAIN_H +#define _EMUMAIN_H + + +#define int32 int32_t +#define int16 int16_t +#define u32 uint32_t +#define u64 uint64_t +#define ScePspDateTime SceDateTime + +#define SOUND_FREQUENCY 48000 +#define SOUND_SAMPLES 832 + +void InitEmulator(); +void RunEmulator(); +void TrashEmulator(); + +#define DISPLAY_MODE_UNSCALED 0 +#define DISPLAY_MODE_FIT_HEIGHT 1 +#define DISPLAY_MODE_FILL_SCREEN 2 +#define DISPLAY_MODE_2X 3 +#define DISPLAY_MODE_3X 4 + +#define JOY 0x10000 +#define SYS 0x20000 +#define SPC 0x40000 +#define AFI 0x80000 + +#define CODE_MASK(x) (x & 0xffff) + +#define SPC_MENU 1 +#define SPC_REWIND 2 + +#define MAP_BUTTONS 18 + +#define MAP_ANALOG_UP 0 +#define MAP_ANALOG_DOWN 1 +#define MAP_ANALOG_LEFT 2 +#define MAP_ANALOG_RIGHT 3 +#define MAP_BUTTON_UP 4 +#define MAP_BUTTON_DOWN 5 +#define MAP_BUTTON_LEFT 6 +#define MAP_BUTTON_RIGHT 7 +#define MAP_BUTTON_SQUARE 8 +#define MAP_BUTTON_CROSS 9 +#define MAP_BUTTON_CIRCLE 10 +#define MAP_BUTTON_TRIANGLE 11 +#define MAP_BUTTON_LTRIGGER 12 +#define MAP_BUTTON_RTRIGGER 13 +#define MAP_BUTTON_SELECT 14 +#define MAP_BUTTON_START 15 +#define MAP_BUTTON_LRTRIGGERS 16 +#define MAP_BUTTON_STARTSELECT 17 + +typedef struct +{ + int ShowFps; + int ControlMode; + int ClockFreq; + int DisplayMode; + int VSync; + int UpdateFreq; + int Frameskip; + int VertStrip; + int SoundEngine; + int SoundBoost; + int AutoFire; + int RewindSaveRate; + int RewindReplayDelay; +} EmulatorOptions; + +struct ButtonConfig +{ + unsigned int ButtonMap[MAP_BUTTONS]; +}; + +#endif // _EMUMAIN_H diff --git a/psp2/error.c b/psp2/error.c new file mode 100644 index 0000000..c731b30 --- /dev/null +++ b/psp2/error.c @@ -0,0 +1,35 @@ +/* + error.c -- + Error logging +*/ + +#include "osd.h" + +static FILE *error_log; + +void error_init(void) +{ +#ifdef LOGERROR + error_log = fopen("error.log","w"); +#endif +} + +void error_shutdown(void) +{ +#ifdef LOGERROR + if(error_log) fclose(error_log); +#endif +} + +void error(char *format, ...) +{ +#ifdef LOGERROR + if (log_error) + { + va_list ap; + va_start(ap, format); + if(error_log) vfprintf(error_log, format, ap); + va_end(ap); + } +#endif +} diff --git a/psp2/error.h b/psp2/error.h new file mode 100644 index 0000000..b38883d --- /dev/null +++ b/psp2/error.h @@ -0,0 +1,10 @@ +#ifndef _ERROR_H_ +#define _ERROR_H_ + +/* Function prototypes */ +void error_init(void); +void error_shutdown(void); +void error(char *format, ...); + +#endif /* _ERROR_H_ */ + diff --git a/psp2/fileio.c b/psp2/fileio.c new file mode 100644 index 0000000..7108bc3 --- /dev/null +++ b/psp2/fileio.c @@ -0,0 +1,154 @@ +/* + * fileio.c + * + * Load a normal file, or ZIP/GZ archive into ROM buffer. + * Returns loaded ROM size (zero if an error occured) + * + * + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald + * modified by Eke-Eke (Genesis Plus GX) + * + * Redistribution and use of this code or any derivative works are permitted + * provided that the following conditions are met: + * + * - Redistributions may not be sold, nor may they be used in a commercial + * product or activity. + * + * - Redistributions that are modified from the original source must include the + * complete source code, including the source code for all components used by a + * binary built from the modified sources. However, as a special exception, the + * source code distributed need not include anything that is normally distributed + * (in either source or binary form) with the major components (compiler, kernel, + * and so on) of the operating system on which the executable runs, unless that + * component itself accompanies the executable. + * + * - Redistributions must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************/ + +#include "shared.h" +#include + +static int check_zip(char *filename); + +int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension) +{ + int size = 0; + + if(check_zip(filename)) + { + unz_file_info info; + int ret = 0; + char fname[256]; + + /* Attempt to open the archive */ + unzFile *fd = unzOpen(filename); + if (!fd) return 0; + + /* Go to first file in archive */ + ret = unzGoToFirstFile(fd); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Get file informations and update filename */ + ret = unzGetCurrentFileInfo(fd, &info, fname, 256, NULL, 0, NULL, 0); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Compressed filename extension */ + if (extension) + { + strncpy(extension, &fname[strlen(fname) - 3], 3); + extension[3] = 0; + } + + /* Open the file for reading */ + ret = unzOpenCurrentFile(fd); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Retrieve uncompressed file size */ + size = info.uncompressed_size; + if(size > maxsize) + { + size = maxsize; + } + + /* Read (decompress) the file */ + ret = unzReadCurrentFile(fd, buffer, size); + if(ret != size) + { + unzCloseCurrentFile(fd); + unzClose(fd); + return 0; + } + + /* Close the current file */ + ret = unzCloseCurrentFile(fd); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Close the archive */ + ret = unzClose(fd); + if(ret != UNZ_OK) return 0; + } + /*else + { + gzFile *gd = gzopen(filename, "rb"); + if (!gd) return 0; + + size = gzread(gd, buffer, maxsize); + + if (extension) + { + strncpy(extension, &filename[strlen(filename) - 3], 3); + extension[3] = 0; + } + + gzclose(gd); + }*/ + + /* Return loaded ROM size */ + return size; +} + +/* + Verifies if a file is a ZIP archive or not. + Returns: 1= ZIP archive, 0= not a ZIP archive +*/ +static int check_zip(char *filename) +{ + uint8 buf[2]; + FILE *fd = fopen(filename, "rb"); + if(!fd) return (0); + fread(buf, 2, 1, fd); + fclose(fd); + if(memcmp(buf, "PK", 2) == 0) return (1); + return (0); +} diff --git a/psp2/fileio.h b/psp2/fileio.h new file mode 100644 index 0000000..30db2e0 --- /dev/null +++ b/psp2/fileio.h @@ -0,0 +1,48 @@ +/* + * fileio.c + * + * Load a normal file, or ZIP/GZ archive. + * Returns loaded ROM size (zero if an error occured) + * + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald + * modified by Eke-Eke (Genesis Plus GX) + * + * Redistribution and use of this code or any derivative works are permitted + * provided that the following conditions are met: + * + * - Redistributions may not be sold, nor may they be used in a commercial + * product or activity. + * + * - Redistributions that are modified from the original source must include the + * complete source code, including the source code for all components used by a + * binary built from the modified sources. However, as a special exception, the + * source code distributed need not include anything that is normally distributed + * (in either source or binary form) with the major components (compiler, kernel, + * and so on) of the operating system on which the executable runs, unless that + * component itself accompanies the executable. + * + * - Redistributions must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************/ + +#ifndef _FILEIO_H_ +#define _FILEIO_H_ + +/* Function prototypes */ +extern int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension); + +#endif /* _FILEIO_H_ */ diff --git a/psp2/main.c b/psp2/main.c new file mode 100644 index 0000000..bc87788 --- /dev/null +++ b/psp2/main.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include +#include +#include "psplib/pl_snd.h" +#include "psplib/video.h" +#include "psplib/pl_psp.h" +#include "psplib/ctrl.h" +#include + +#include "menu.h" +#include "emumain.h" + + +PSP2_MODULE_INFO(0,1,PSP_APP_NAME) +//PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER) + +static void ExitCallback(void* arg) +{ + ExitPSP = 1; +} + +int main(int argc,char *argv[]) +{ + /* Initialize PSP */ + pl_psp_init("cache0:/GENPlusVITA/"); + pl_snd_init(SOUND_SAMPLES, 1); + pspCtrlInit(); + pspVideoInit(); + + /* Initialize callbacks */ + pl_psp_register_callback(PSP_EXIT_CALLBACK, + ExitCallback, + NULL); + pl_psp_start_callback_thread(); + + /* Start emulation */ + InitMenu(); + DisplayMenu(); + TrashMenu(); + + /* Release PSP resources */ + pl_snd_shutdown(); + pspVideoShutdown(); + pl_psp_shutdown(); + + return(0); +} diff --git a/psp2/main.h b/psp2/main.h new file mode 100644 index 0000000..dfa5d8d --- /dev/null +++ b/psp2/main.h @@ -0,0 +1,11 @@ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#define MAX_INPUTS 8 + +extern int debug_on; +extern int log_error; +extern int sdl_input_update(void); + +#endif /* _MAIN_H_ */ diff --git a/psp2/menu.c b/psp2/menu.c new file mode 100644 index 0000000..8da45ec --- /dev/null +++ b/psp2/menu.c @@ -0,0 +1,1289 @@ +#include "menu.h" + +#include +#include + +#include +#include +#include +#include + +#include "emumain.h" + + +#include "shared.h" + +#include "psplib/pl_file.h" +#include "psplib/image.h" +#include "psplib/ui.h" +#include "psplib/pl_menu.h" +#include "psplib/ctrl.h" +#include "psplib/pl_util.h" +#include "psplib/pl_psp.h" +#include "psplib/pl_ini.h" +#include "psplib/pl_rewind.h" + +#define TAB_QUICKLOAD 0 +#define TAB_STATE 1 +#define TAB_CONTROL 2 +#define TAB_OPTION 3 +#define TAB_SYSTEM 4 +#define TAB_ABOUT 5 +#define TAB_MAX TAB_SYSTEM + +#define OPTION_DISPLAY_MODE 0x01 +#define OPTION_SYNC_FREQ 0x02 +#define OPTION_FRAMESKIP 0x03 +#define OPTION_VSYNC 0x04 +#define OPTION_CLOCK_FREQ 0x05 +#define OPTION_SHOW_FPS 0x06 +#define OPTION_CONTROL_MODE 0x07 +#define OPTION_ANIMATE 0x08 +#define OPTION_AUTOFIRE 0x09 +#define OPTION_REWIND_SAVE_RATE 0x0A +#define OPTION_REWIND_REPLAY_DELAY 0x0B + +#define SYSTEM_SCRNSHOT 0x11 +#define SYSTEM_RESET 0x12 +#define SYSTEM_VERT_STRIP 0x13 +#define SYSTEM_SOUND_ENGINE 0x14 +#define SYSTEM_SOUND_BOOST 0x15 + +extern PspImage *Screen; +extern pl_rewind Rewinder; + +EmulatorOptions Options; + +static int ControlsModified; +static int TabIndex; +static int ResumeEmulation; +static PspImage *Background; +static PspImage *NoSaveIcon; + +static const char *QuickloadFilter[] = { "BIN", "SMS", "GG", "ZIP", '\0' }, + PresentSlotText[] = "\026\244\020 Save\t\026\001\020 Load\t\026\243\020 Delete", + EmptySlotText[] = "\026\244\020 Save", + ControlHelpText[] = "\026\250\020 Change mapping\t\026\243\020 Load defaults"; + +pl_file_path CurrentGame = "", + GamePath, + SaveStatePath, + ScreenshotPath; + +#define SET_AS_CURRENT_GAME(filename) \ + strncpy(CurrentGame, filename, sizeof(CurrentGame) - 1) +#define CURRENT_GAME (CurrentGame) +#define GAME_LOADED (CurrentGame[0] != '\0') + +#define WIDTH 256 +#define HEIGHT 192 + +/* Tab labels */ +static const char *TabLabel[] = +{ + "Game", + "Save/Load", + "Controls", + "Options", + "System", + "About" +}; + +static void LoadOptions(); +static int SaveOptions(); + +static void InitButtonConfig(); +static int SaveButtonConfig(); +static int LoadButtonConfig(); + +static void DisplayStateTab(); +static PspImage* LoadStateIcon(const char *path); +static int LoadState(const char *path); +static PspImage* SaveState(const char *path, PspImage *icon); + +static int OnMenuItemChanged(const struct PspUiMenu *uimenu, pl_menu_item* item, + const pl_menu_option* option); +static int OnMenuOk(const void *uimenu, const void* sel_item); +static int OnMenuButtonPress(const struct PspUiMenu *uimenu, + pl_menu_item* sel_item, u32 button_mask); + +static int OnSplashButtonPress(const struct PspUiSplash *splash, + u32 button_mask); +static void OnSplashRender(const void *uiobject, const void *null); + +static int OnGenericCancel(const void *uiobject, const void *param); +static void OnGenericRender(const void *uiobject, const void *item_obj); +static int OnGenericButtonPress(const PspUiFileBrowser *browser, + const char *path, u32 button_mask); + +static int OnSaveStateOk(const void *gallery, const void *item); +static int OnSaveStateButtonPress(const PspUiGallery *gallery, + pl_menu_item* item, u32 button_mask); + +static int OnQuickloadOk(const void *browser, const void *path); + +void OnSystemRender(const void *uiobject, const void *item_obj); + +/* Menu options */ +PL_MENU_OPTIONS_BEGIN(ToggleOptions) + PL_MENU_OPTION("Disabled", 0) + PL_MENU_OPTION("Enabled", 1) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ScreenSizeOptions) + PL_MENU_OPTION("Actual size", DISPLAY_MODE_UNSCALED) + PL_MENU_OPTION("4:3 scaled (2x)", DISPLAY_MODE_2X) + PL_MENU_OPTION("4:3 scaled (3x)", DISPLAY_MODE_3X) + PL_MENU_OPTION("4:3 scaled (fit height)", DISPLAY_MODE_FIT_HEIGHT) + PL_MENU_OPTION("16:9 scaled (fit screen)", DISPLAY_MODE_FILL_SCREEN) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(FrameLimitOptions) + PL_MENU_OPTION("Disabled", 0) + PL_MENU_OPTION("60 fps (NTSC)", 60) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(FrameSkipOptions) + PL_MENU_OPTION("No skipping", 0) + PL_MENU_OPTION("Skip 1 frame", 1) + PL_MENU_OPTION("Skip 2 frames", 2) + PL_MENU_OPTION("Skip 3 frames", 3) + PL_MENU_OPTION("Skip 4 frames", 4) + PL_MENU_OPTION("Skip 5 frames", 5) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(PspClockFreqOptions) + PL_MENU_OPTION("222 MHz", 222) + PL_MENU_OPTION("266 MHz", 266) + PL_MENU_OPTION("300 MHz", 300) + PL_MENU_OPTION("333 MHz", 333) + PL_MENU_OPTION("444 MHz", 444) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(AutofireOptions) + PL_MENU_OPTION("Once every 3 frames", 2) + PL_MENU_OPTION("Once every 10 frames", 9) + PL_MENU_OPTION("Once every 30 frames", 29) + PL_MENU_OPTION("Once every 60 frames", 59) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ControlModeOptions) + PL_MENU_OPTION("\026\242\020 cancels, \026\241\020 confirms (US)", 0) + PL_MENU_OPTION("\026\241\020 cancels, \026\242\020 confirms (Japan)", 1) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(RewindSaveRateOptions) + PL_MENU_OPTION("Smoother", 2) + PL_MENU_OPTION("Longer", 5) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(RewindReplayDelayOptions) + PL_MENU_OPTION("50 ms", 50) + PL_MENU_OPTION("100 ms", 100) + PL_MENU_OPTION("500 ms", 500) + PL_MENU_OPTION("1 s", 1000) + PL_MENU_OPTION("2 s", 2000) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ButtonMapOptions) + /* Unmapped */ + PL_MENU_OPTION("None", 0) + /* Special */ + PL_MENU_OPTION("Special: Open Menu", SPC|SPC_MENU) + PL_MENU_OPTION("Special: Rewind", SPC|SPC_REWIND) + /* Joystick */ + PL_MENU_OPTION("Joystick Up", JOY|INPUT_UP) + PL_MENU_OPTION("Joystick Down", JOY|INPUT_DOWN) + PL_MENU_OPTION("Joystick Left", JOY|INPUT_LEFT) + PL_MENU_OPTION("Joystick Right", JOY|INPUT_RIGHT) + PL_MENU_OPTION("Joystick Button A", JOY|INPUT_A) + PL_MENU_OPTION("Joystick Button B", JOY|INPUT_B) + PL_MENU_OPTION("Joystick Button C", JOY|INPUT_C) + PL_MENU_OPTION("Joystick Button I (autofire)", AFI|INPUT_BUTTON1) + PL_MENU_OPTION("Joystick Button II (autofire)", AFI|INPUT_BUTTON2) + /* Joystick */ + PL_MENU_OPTION("Start (GG) / Pause (SMS)", JOY|INPUT_START) +PL_MENU_OPTIONS_END + +/* Menu items */ +PL_MENU_ITEMS_BEGIN(OptionMenuDef) + PL_MENU_HEADER("Video") + PL_MENU_ITEM("Screen size", OPTION_DISPLAY_MODE, ScreenSizeOptions, + "\026\250\020 Change screen size") + PL_MENU_HEADER("Input") + PL_MENU_ITEM("Rate of autofire", OPTION_AUTOFIRE, AutofireOptions, + "\026\250\020 Adjust rate of autofire") + PL_MENU_HEADER("Performance") + PL_MENU_ITEM("Frame limiter", OPTION_SYNC_FREQ, FrameLimitOptions, + "\026\250\020 Change screen update frequency") + PL_MENU_ITEM("Frame skipping", OPTION_FRAMESKIP, FrameSkipOptions, + "\026\250\020 Change number of frames skipped per update") + PL_MENU_ITEM("VSync", OPTION_VSYNC, ToggleOptions, + "\026\250\020 Enable to reduce tearing; disable to increase speed") + PL_MENU_ITEM("PSP clock frequency", OPTION_CLOCK_FREQ, PspClockFreqOptions, + "\026\250\020 Larger values: faster emulation, faster battery depletion (default: 222MHz)") + PL_MENU_ITEM("Show FPS counter", OPTION_SHOW_FPS, ToggleOptions, + "\026\250\020 Show/hide the frames-per-second counter") +/* + PL_MENU_HEADER("Time rewind") + PL_MENU_ITEM("Rewind recording mode", OPTION_REWIND_SAVE_RATE, + RewindSaveRateOptions, "\026\250\020 Change rewind saving frequency") + PL_MENU_ITEM("Rewind delay", OPTION_REWIND_REPLAY_DELAY, + RewindReplayDelayOptions, "\026\250\020 Change delay between frames") +*/ + PL_MENU_HEADER("Menu") + PL_MENU_ITEM("Button mode", OPTION_CONTROL_MODE, ControlModeOptions, + "\026\250\020 Change OK and Cancel button mapping") + PL_MENU_ITEM("Animations", OPTION_ANIMATE, ToggleOptions, + "\026\250\020 Enable/disable in-menu animations") +PL_MENU_ITEMS_END +PL_MENU_ITEMS_BEGIN(ControlMenuDef) + PL_MENU_ITEM(PSP_CHAR_ANALUP, MAP_ANALOG_UP, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALDOWN, MAP_ANALOG_DOWN, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALLEFT, MAP_ANALOG_LEFT, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALRIGHT, MAP_ANALOG_RIGHT, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_UP, MAP_BUTTON_UP, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_DOWN, MAP_BUTTON_DOWN, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LEFT, MAP_BUTTON_LEFT, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_RIGHT, MAP_BUTTON_RIGHT, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SQUARE, MAP_BUTTON_SQUARE, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_CROSS, MAP_BUTTON_CROSS, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_CIRCLE, MAP_BUTTON_CIRCLE, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_TRIANGLE, MAP_BUTTON_TRIANGLE, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LTRIGGER, MAP_BUTTON_LTRIGGER, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_RTRIGGER, MAP_BUTTON_RTRIGGER, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SELECT, MAP_BUTTON_SELECT, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_START, MAP_BUTTON_START, ButtonMapOptions, + ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LTRIGGER"+"PSP_CHAR_RTRIGGER, + MAP_BUTTON_LRTRIGGERS, ButtonMapOptions, ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_START"+"PSP_CHAR_SELECT, + MAP_BUTTON_STARTSELECT, ButtonMapOptions, ControlHelpText) +PL_MENU_ITEMS_END +PL_MENU_ITEMS_BEGIN(SystemMenuDef) + PL_MENU_HEADER("Video") + PL_MENU_ITEM("Vertical bar", SYSTEM_VERT_STRIP, ToggleOptions, + "\026\250\020 Show/hide the leftmost vertical bar (SMS)") + PL_MENU_HEADER("System") + PL_MENU_ITEM("Reset", SYSTEM_RESET, NULL, "\026\001\020 Reset") + PL_MENU_ITEM("Save screenshot", SYSTEM_SCRNSHOT, NULL, + "\026\001\020 Save screenshot") +PL_MENU_ITEMS_END + +PspUiSplash SplashScreen = +{ + OnSplashRender, + OnGenericCancel, + OnSplashButtonPress, + NULL +}; + +PspUiGallery SaveStateGallery = +{ + OnGenericRender, /* OnRender() */ + OnSaveStateOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnSaveStateButtonPress, /* OnButtonPress() */ + NULL /* Userdata */ +}; + +PspUiMenu OptionUiMenu = +{ + OnGenericRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ +}; + +PspUiMenu ControlUiMenu = +{ + OnGenericRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ +}; + +PspUiFileBrowser QuickloadBrowser = +{ + OnGenericRender, + OnQuickloadOk, + OnGenericCancel, + OnGenericButtonPress, + QuickloadFilter, + 0 +}; + +PspUiMenu SystemUiMenu = +{ + OnSystemRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ +}; + +/* Game configuration (includes button maps) */ +struct ButtonConfig ActiveConfig; + +/* Default configuration */ +struct ButtonConfig DefaultConfig = +{ + { + JOY|INPUT_UP, /* Analog Up */ + JOY|INPUT_DOWN, /* Analog Down */ + JOY|INPUT_LEFT, /* Analog Left */ + JOY|INPUT_RIGHT, /* Analog Right */ + JOY|INPUT_UP, /* D-pad Up */ + JOY|INPUT_DOWN, /* D-pad Down */ + JOY|INPUT_LEFT, /* D-pad Left */ + JOY|INPUT_RIGHT, /* D-pad Right */ + JOY|INPUT_A,/* Square */ + JOY|INPUT_B,/* Cross */ + JOY|INPUT_C,/* Circle */ + 0, /* Triangle */ + 0, /* L Trigger */ + 0, /* R Trigger */ + 0, /* Select */ + JOY|INPUT_START, + /* Start */ + SPC|SPC_MENU, /* L+R Triggers */ + 0, /* Start+Select */ + } +}; + +/* Button masks */ +const u64 ButtonMask[] = +{ + PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER, + PSP_CTRL_START | PSP_CTRL_SELECT, + PSP_CTRL_ANALUP, PSP_CTRL_ANALDOWN, + PSP_CTRL_ANALLEFT, PSP_CTRL_ANALRIGHT, + PSP_CTRL_UP, PSP_CTRL_DOWN, + PSP_CTRL_LEFT, PSP_CTRL_RIGHT, + PSP_CTRL_SQUARE, PSP_CTRL_CROSS, + PSP_CTRL_CIRCLE, PSP_CTRL_TRIANGLE, + PSP_CTRL_LTRIGGER, PSP_CTRL_RTRIGGER, + PSP_CTRL_SELECT, PSP_CTRL_START, + 0 /* End */ +}; + +/* Button map ID's */ +const int ButtonMapId[] = +{ + MAP_BUTTON_LRTRIGGERS, + MAP_BUTTON_STARTSELECT, + MAP_ANALOG_UP, MAP_ANALOG_DOWN, + MAP_ANALOG_LEFT, MAP_ANALOG_RIGHT, + MAP_BUTTON_UP, MAP_BUTTON_DOWN, + MAP_BUTTON_LEFT, MAP_BUTTON_RIGHT, + MAP_BUTTON_SQUARE, MAP_BUTTON_CROSS, + MAP_BUTTON_CIRCLE, MAP_BUTTON_TRIANGLE, + MAP_BUTTON_LTRIGGER, MAP_BUTTON_RTRIGGER, + MAP_BUTTON_SELECT, MAP_BUTTON_START, + -1 /* End */ +}; + +void InitMenu() +{ + /* Reset variables */ + TabIndex = TAB_ABOUT; + Background = NULL; + + /* Initialize paths */ + sprintf(SaveStatePath, "%ssavedata/", pl_psp_get_app_directory()); + sprintf(ScreenshotPath, "%sscreenshot/", pl_psp_get_app_directory()); + sprintf(GamePath, "%s", pl_psp_get_app_directory()); + + if (!pl_file_exists(SaveStatePath)) + pl_file_mkdir_recursive(SaveStatePath); + + /* Initialize options */ + LoadOptions(); + + InitEmulator(); + + /* Load the background image */ + pl_file_path background; + snprintf(background, sizeof(background) - 1, "%sbackground.png", + pl_psp_get_app_directory()); + Background = pspImageLoadPng(background); + //Background = pspImageLoadPng("background.png"); + + /* Init NoSaveState icon image */ + NoSaveIcon = pspImageCreate(136, 114, PSP_IMAGE_16BPP); + pspImageClear(NoSaveIcon, RGB(0x0c,0,0x3f)); + + /* Initialize state menu */ + int i; + pl_menu_item *item; + for (i = 0; i < 10; i++) + { + item = pl_menu_append_item(&SaveStateGallery.Menu, i, NULL); + pl_menu_set_item_help_text(item, EmptySlotText); + } + + /* Initialize menus */ + pl_menu_create(&SystemUiMenu.Menu, SystemMenuDef); + pl_menu_create(&OptionUiMenu.Menu, OptionMenuDef); + pl_menu_create(&ControlUiMenu.Menu, ControlMenuDef); + + /* Load default configuration */ + LoadButtonConfig(); + + /* Initialize UI components */ + UiMetric.Background = Background; + UiMetric.Font = &PspStockFont; + UiMetric.Left = 16; + UiMetric.Top = 48; + UiMetric.Right = 944; + UiMetric.Bottom = 500; + UiMetric.OkButton = (!Options.ControlMode) ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!Options.ControlMode) ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; + UiMetric.ScrollbarColor = PSP_COLOR_GRAY; + UiMetric.ScrollbarBgColor = 0x44ffffff; + UiMetric.ScrollbarWidth = 10; + UiMetric.TextColor = PSP_COLOR_GRAY; + UiMetric.SelectedColor = PSP_COLOR_YELLOW; + UiMetric.SelectedBgColor = COLOR(0xff,0xff,0xff,0x44); + UiMetric.StatusBarColor = PSP_COLOR_WHITE; + UiMetric.BrowserFileColor = PSP_COLOR_GRAY; + UiMetric.BrowserDirectoryColor = PSP_COLOR_YELLOW; + UiMetric.GalleryIconsPerRow = 5; + UiMetric.GalleryIconMarginWidth = 8; + UiMetric.MenuItemMargin = 20; + UiMetric.MenuSelOptionBg = PSP_COLOR_BLACK; + UiMetric.MenuOptionBoxColor = PSP_COLOR_GRAY; + UiMetric.MenuOptionBoxBg = COLOR(0, 0, 33, 0xBB); + UiMetric.MenuDecorColor = PSP_COLOR_YELLOW; + UiMetric.DialogFogColor = COLOR(0, 0, 0, 88); + UiMetric.TitlePadding = 4; + + UiMetric.TitleColor = PSP_COLOR_WHITE; + UiMetric.MenuFps = 30; + UiMetric.TabBgColor = COLOR(0x74,0x74,0xbe,0xff); + UiMetric.BrowserScreenshotPath = ScreenshotPath; + UiMetric.BrowserScreenshotDelay = 30; +} + +void DisplayMenu() +{ + int i; + pl_menu_item *item; + + /* Menu loop */ + do + { + ResumeEmulation = 0; + + /* Set normal clock frequency */ + pl_psp_set_clock_freq(222); + /* Set buttons to autorepeat */ + pspCtrlSetPollingMode(PSP_CTRL_AUTOREPEAT); + + do + { + /* Display appropriate tab */ + switch (TabIndex) + { + case TAB_STATE: + DisplayStateTab(); + break; + case TAB_CONTROL: + /* Load current button mappings */ + for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) + pl_menu_select_option_by_value(item, (void*)ActiveConfig.ButtonMap[i]); + + ControlsModified = 0; + pspUiOpenMenu(&ControlUiMenu, NULL); + + if (ControlsModified) + SaveButtonConfig(); + + break; + case TAB_QUICKLOAD: + pspUiOpenBrowser(&QuickloadBrowser, + (GAME_LOADED) ? CURRENT_GAME : GamePath); + break; + case TAB_SYSTEM: + item = pl_menu_find_item_by_id(&SystemUiMenu.Menu, SYSTEM_VERT_STRIP); + pl_menu_select_option_by_value(item, (void*)Options.VertStrip); + pspUiOpenMenu(&SystemUiMenu, NULL); + break; + case TAB_OPTION: + /* Init menu options */ + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_DISPLAY_MODE); + pl_menu_select_option_by_value(item, (void*)Options.DisplayMode); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_SYNC_FREQ); + pl_menu_select_option_by_value(item, (void*)Options.UpdateFreq); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_FRAMESKIP); + pl_menu_select_option_by_value(item, (void*)(int)Options.Frameskip); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_VSYNC); + pl_menu_select_option_by_value(item, (void*)Options.VSync); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CLOCK_FREQ); + pl_menu_select_option_by_value(item, (void*)Options.ClockFreq); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_SHOW_FPS); + pl_menu_select_option_by_value(item, (void*)Options.ShowFps); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CONTROL_MODE); + pl_menu_select_option_by_value(item, (void*)Options.ControlMode); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_ANIMATE); + pl_menu_select_option_by_value(item, (void*)UiMetric.Animate); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_AUTOFIRE); + pl_menu_select_option_by_value(item, (void*)Options.AutoFire); + + if ((item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_REWIND_SAVE_RATE))) + pl_menu_select_option_by_value(item, (void*)Options.RewindSaveRate); + if ((item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_REWIND_REPLAY_DELAY))) + pl_menu_select_option_by_value(item, (void*)Options.RewindReplayDelay); + + pspUiOpenMenu(&OptionUiMenu, NULL); + break; + case TAB_ABOUT: + pspUiSplashScreen(&SplashScreen); + break; + } + } while (!ExitPSP && !ResumeEmulation); + + if (!ExitPSP) + { + /* Set clock frequency during emulation */ + pl_psp_set_clock_freq(Options.ClockFreq); + /* Set buttons to normal mode */ + pspCtrlSetPollingMode(PSP_CTRL_NORMAL); + + /* Resume emulation */ + if (ResumeEmulation) + { + if (UiMetric.Animate) pspUiFadeout(); + RunEmulator(); + if (UiMetric.Animate) pspUiFadeout(); + } + } + } while (!ExitPSP); +} + +int OnGenericCancel(const void *uiobject, const void* param) +{ + if (GAME_LOADED) ResumeEmulation = 1; + return 1; +} + +void OnSplashRender(const void *splash, const void *null) +{ + int fh, i, x, y, height; + const char *lines[] = + { + PSP_APP_NAME" version "PSP_APP_VER" ("__DATE__")", + "\026https://github.com/frangarcj/Genesis-Plus-GX", + " ", + "2015 Frangarcj", + "2006 eke-eke", + "1998-2004 Charles MacDonald", + NULL + }; + + fh = pspFontGetLineHeight(UiMetric.Font); + + for (i = 0; lines[i]; i++); + height = fh * (i - 1); + + /* Render lines */ + for (i = 0, y = SCR_HEIGHT / 2 - height / 2; lines[i]; i++, y += fh) + { + x = SCR_WIDTH / 2 - pspFontGetTextWidth(UiMetric.Font, lines[i]) / 2; + pspVideoPrint(UiMetric.Font, x, y, lines[i], PSP_COLOR_GRAY); + } + + /* Render PSP status */ + OnGenericRender(splash, null); +} + +int OnSplashButtonPress(const struct PspUiSplash *splash, + u32 button_mask) +{ + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +/* Handles drawing of generic items */ +void OnGenericRender(const void *uiobject, const void *item_obj) +{ + /* Draw tabs */ + int height = pspFontGetLineHeight(UiMetric.Font); + int width; + int i, x; + for (i = 0, x = 5; i <= TAB_MAX; i++, x += width + 10) + { + width = -10; + + if (!GAME_LOADED && (i == TAB_STATE || i == TAB_SYSTEM)) + continue; + + /* Determine width of text */ + width = pspFontGetTextWidth(UiMetric.Font, TabLabel[i]); + + /* Draw background of active tab */ + if (i == TabIndex) + pspVideoFillRect(x - 5, 0, x + width + 5, height + 1, UiMetric.TabBgColor); + + /* Draw name of tab */ + pspVideoPrint(UiMetric.Font, x, 0, TabLabel[i], PSP_COLOR_WHITE); + } +} + +int OnGenericButtonPress(const PspUiFileBrowser *browser, + const char *path, u32 button_mask) +{ + int tab_index; + + /* If L or R are pressed, switch tabs */ + if (button_mask & PSP_CTRL_LTRIGGER) + { + TabIndex--; + do + { + tab_index = TabIndex; + if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex--; + if (TabIndex < 0) TabIndex = TAB_MAX; + } while (tab_index != TabIndex); + } + else if (button_mask & PSP_CTRL_RTRIGGER) + { + TabIndex++; + do + { + tab_index = TabIndex; + if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex++; + if (TabIndex > TAB_MAX) TabIndex = 0; + } while (tab_index != TabIndex); + } + else if ((button_mask & (PSP_CTRL_START | PSP_CTRL_SELECT)) + == (PSP_CTRL_START | PSP_CTRL_SELECT)) + { + if (pl_util_save_vram_seq(ScreenshotPath, "ui")) + pspUiAlert("Saved successfully"); + else + pspUiAlert("ERROR: Not saved"); + return 0; + } + else return 0; + + return 1; +} + +int OnMenuItemChanged(const struct PspUiMenu *uimenu, + pl_menu_item* item, const pl_menu_option* option) +{ + if (uimenu == &ControlUiMenu) + { + ControlsModified = 1; + ActiveConfig.ButtonMap[item->id] = (unsigned int)option->value; + } + else + { + switch(item->id) + { + case SYSTEM_VERT_STRIP: + Options.VertStrip = (int)option->value; + break; + case OPTION_DISPLAY_MODE: + Options.DisplayMode = (int)option->value; + break; + case OPTION_SYNC_FREQ: + Options.UpdateFreq = (int)option->value; + break; + case OPTION_FRAMESKIP: + Options.Frameskip = (int)option->value; + break; + case OPTION_VSYNC: + Options.VSync = (int)option->value; + break; + case OPTION_CLOCK_FREQ: + Options.ClockFreq = (int)option->value; + break; + case OPTION_SHOW_FPS: + Options.ShowFps = (int)option->value; + break; + case OPTION_CONTROL_MODE: + Options.ControlMode = (int)option->value; + UiMetric.OkButton = (!(int)option->value) ? PSP_CTRL_CROSS + : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!(int)option->value) ? PSP_CTRL_CIRCLE + : PSP_CTRL_CROSS; + break; + case OPTION_ANIMATE: + UiMetric.Animate = (int)option->value; + break; + case OPTION_AUTOFIRE: + Options.AutoFire = (int)option->value; + break; + case OPTION_REWIND_SAVE_RATE: + Options.RewindSaveRate = (int)option->value; + break; + case OPTION_REWIND_REPLAY_DELAY: + Options.RewindReplayDelay = (int)option->value; + break; + } + + SaveOptions(); + + } + + + + return 1; +} + +int OnMenuOk(const void *uimenu, const void* sel_item) +{ + if (uimenu == &ControlUiMenu) + { + /* Save to MS */ + if (SaveButtonConfig()) + pspUiAlert("Changes saved"); + else + pspUiAlert("ERROR: Changes not saved"); + } + else if (uimenu == &SystemUiMenu) + { + switch (((const pl_menu_item*)sel_item)->id) + { + case SYSTEM_RESET: + + /* Reset system */ + if (pspUiConfirm("Reset the system?")) + { + ResumeEmulation = 1; + system_reset(); + pl_rewind_reset(&Rewinder); + return 1; + } + break; + + case SYSTEM_SCRNSHOT: + + /* Save screenshot */ + if (!pl_util_save_image_seq(ScreenshotPath, + pl_file_get_filename(CURRENT_GAME), + Screen)) + pspUiAlert("ERROR: Screenshot not saved"); + else + pspUiAlert("Screenshot saved successfully"); + break; + } + } + + return 0; +} + +int OnMenuButtonPress(const struct PspUiMenu *uimenu, + pl_menu_item* sel_item, + u32 button_mask) +{ + if (uimenu == &ControlUiMenu) + { + if (button_mask & PSP_CTRL_TRIANGLE) + { + pl_menu_item *item; + int i; + + /* Load default mapping */ + InitButtonConfig(); + ControlsModified = 1; + + /* Modify the menu */ + for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) + pl_menu_select_option_by_value(item, (void*)DefaultConfig.ButtonMap[i]); + + return 0; + } + } + + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +int OnQuickloadOk(const void *browser, const void *path) +{ + int first_time = 0; + if (!GAME_LOADED) + first_time = 1; + + if (!load_rom((char*)path)) + { + pspUiAlert("Error loading cartridge"); + return 0; + } + + SET_AS_CURRENT_GAME((char*)path); + pl_file_get_parent_directory((const char*)path, + GamePath, + sizeof(GamePath)); + + /* Reset selected state */ + SaveStateGallery.Menu.selected = NULL; + + if (first_time) + { + pspUiFlashMessage("Initializing for first-time use\nPlease wait..."); + audio_init(SOUND_FREQUENCY, 0); + system_init(); + //error_init(); + system_reset(); + } + else{ + system_init(); + system_reset(); + audio_reset(); + } + pl_rewind_reset(&Rewinder); + + ResumeEmulation = 1; + return 1; +} + +int OnSaveStateOk(const void *gallery, const void *item) +{ + if (!GAME_LOADED) + return 0; + + char *path; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + + path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, + ((const pl_menu_item*)item)->id); + + if (pl_file_exists(path) && pspUiConfirm("Load state?")) + { + if (LoadState(path)) + { + ResumeEmulation = 1; + pl_rewind_reset(&Rewinder); + pl_menu_find_item_by_id(&(((const PspUiGallery*)gallery)->Menu), + ((const pl_menu_item*)item)->id); + free(path); + + return 1; + } + pspUiAlert("ERROR: State failed to load"); + } + + free(path); + return 0; +} + +int OnSaveStateButtonPress(const PspUiGallery *gallery, + pl_menu_item *sel, u32 button_mask) +{ + if (!GAME_LOADED) + return 0; + + if (button_mask & PSP_CTRL_SQUARE + || button_mask & PSP_CTRL_TRIANGLE) + { + char caption[32]; + char *path; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + + path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, sel->id); + + do /* not a real loop; flow control construct */ + { + if (button_mask & PSP_CTRL_SQUARE) + { + if (pl_file_exists(path) && !pspUiConfirm("Overwrite existing state?")) + break; + + pspUiFlashMessage("Saving, please wait ..."); + + PspImage *icon; + if (!(icon = SaveState(path, Screen))) + { + pspUiAlert("ERROR: State not saved"); + break; + } + + SceIoStat stat; + + /* Trash the old icon (if any) */ + if (sel->param && sel->param != NoSaveIcon) + pspImageDestroy((PspImage*)sel->param); + + /* Update icon, help text */ + sel->param = icon; + pl_menu_set_item_help_text(sel, PresentSlotText); + + /* Get file modification time/date */ + if (sceIoGetstat(path, &stat) < 0) + sprintf(caption, "ERROR"); + else + sprintf(caption, "%02i/%02i/%02i %02i:%02i", + stat.st_mtime.month, + stat.st_mtime.day, + stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, + stat.st_mtime.hour, + stat.st_mtime.minute); + + pl_menu_set_item_caption(sel, caption); + } + else if (button_mask & PSP_CTRL_TRIANGLE) + { + if (!pl_file_exists(path) || !pspUiConfirm("Delete state?")) + break; + + if (!pl_file_rm(path)) + { + pspUiAlert("ERROR: State not deleted"); + break; + } + + /* Trash the old icon (if any) */ + if (sel->param && sel->param != NoSaveIcon) + pspImageDestroy((PspImage*)sel->param); + + /* Update icon, caption */ + sel->param = NoSaveIcon; + pl_menu_set_item_help_text(sel, EmptySlotText); + pl_menu_set_item_caption(sel, "Empty"); + } + } while (0); + + if (path) free(path); + return 0; + } + + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +/* Handles any special drawing for the system menu */ +void OnSystemRender(const void *uiobject, const void *item_obj) +{ + int w, h, x, y; + w = Screen->Viewport.Width*1.5; + h = Screen->Viewport.Height*1.5; + x = SCR_WIDTH - w - 16; + y = SCR_HEIGHT - h - 80; + + /* Draw a small representation of the screen */ + pspVideoShadowRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_BLACK, 3); + pspVideoPutImage(Screen, x, y, w, h); + pspVideoDrawRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_GRAY); + + OnGenericRender(uiobject, item_obj); +} + +static void DisplayStateTab() +{ + if (!GAME_LOADED) { TabIndex++; return; } + + pl_menu_item *item, *sel; + SceIoStat stat; + char caption[32]; + ScePspDateTime latest; + + const char *config_name = pl_file_get_filename(CURRENT_GAME); + char *path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + char *game_name = strdup(config_name); + char *dot = strrchr(game_name, '.'); + if (dot) *dot='\0'; + + memset(&latest, 0, sizeof(latest)); + + /* Initialize icons */ + sel = SaveStateGallery.Menu.items; + for (item = SaveStateGallery.Menu.items; item; item = item->next) + { + sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, item->id); + + if (pl_file_exists(path)) + { + if (sceIoGetstat(path, &stat) < 0) + sprintf(caption, "ERROR"); + else + { + /* Determine the latest save state */ + if (pl_util_date_compare(&latest, &stat.st_mtime) < 0) + { + sel = item; + latest = stat.st_mtime; + } + + sprintf(caption, "%02i/%02i/%02i %02i:%02i", + stat.st_mtime.month, + stat.st_mtime.day, + stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, + stat.st_mtime.hour, + stat.st_mtime.minute); + } + + pl_menu_set_item_caption(item, caption); + item->param = LoadStateIcon(path); + pl_menu_set_item_help_text(item, PresentSlotText); + } + else + { + pl_menu_set_item_caption(item, "Empty"); + item->param = NoSaveIcon; + pl_menu_set_item_help_text(item, EmptySlotText); + } + + } + + free(path); + + /* Highlight the latest save state if none are selected */ + if (SaveStateGallery.Menu.selected == NULL) + SaveStateGallery.Menu.selected = sel; + + pspUiOpenGallery(&SaveStateGallery, game_name); + free(game_name); + + /* Destroy any icons */ + for (item = SaveStateGallery.Menu.items; item; item = item->next) + if (item->param != NULL && item->param != NoSaveIcon) + pspImageDestroy((PspImage*)item->param); +} + +/* Initialize game configuration */ +static void InitButtonConfig() +{ + memcpy(&ActiveConfig, &DefaultConfig, sizeof(struct ButtonConfig)); +} + +/* Load game configuration */ +static int LoadButtonConfig() +{ + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", + pl_psp_get_app_directory()); + + /* Open file for reading */ + FILE *file = fopen(path, "r"); + + /* If no configuration, load defaults */ + if (!file) + { + InitButtonConfig(); + return 1; + } + + /* Read contents of struct */ + int nread = fread(&ActiveConfig, sizeof(struct ButtonConfig), 1, file); + fclose(file); + + if (nread != 1) + { + InitButtonConfig(); + return 0; + } + + return 1; +} + +/* Save game configuration */ +static int SaveButtonConfig() +{ + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", pl_psp_get_app_directory()); + + /* Open file for writing */ + FILE *file = fopen(path, "w"); + if (!file) return 0; + + /* Write contents of struct */ + int nwritten = fwrite(&ActiveConfig, sizeof(struct ButtonConfig), 1, file); + fclose(file); + + return (nwritten == 1); +} + +/* Load options */ +void LoadOptions() +{ + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%ssmsplus.ini", pl_psp_get_app_directory()); + + /* Initialize INI structure */ + pl_ini_file init; + pl_ini_load(&init, path); + + /* Load values */ + Options.DisplayMode = pl_ini_get_int(&init, "Video", "Display Mode", DISPLAY_MODE_2X); + Options.UpdateFreq = pl_ini_get_int(&init, "Video", "Update Frequency", 60); + Options.Frameskip = pl_ini_get_int(&init, "Video", "Frameskip", 0); + Options.VSync = pl_ini_get_int(&init, "Video", "VSync", 0); + Options.ClockFreq = pl_ini_get_int(&init, "Video", "PSP Clock Frequency", 444); + Options.ShowFps = pl_ini_get_int(&init, "Video", "Show FPS", 0); + Options.ControlMode = pl_ini_get_int(&init, "Menu", "Control Mode", 0); + UiMetric.Animate = pl_ini_get_int(&init, "Menu", "Animate", 1); + Options.VertStrip = pl_ini_get_int(&init, "Game", "Vertical Strip", 1); + Options.AutoFire = pl_ini_get_int(&init, "Input", "Autofire", 2); + Options.RewindSaveRate = pl_ini_get_int(&init, "Enhancements", "Rewind Save Rate", 5); + Options.RewindReplayDelay = pl_ini_get_int(&init, "Enhancements", "Rewind Replay Delay", 50); + pl_ini_get_string(&init, "File", "Game Path", NULL, GamePath, sizeof(GamePath)); + + /* Clean up */ + pl_ini_destroy(&init); +} + +/* Save options */ +static int SaveOptions() +{ + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%ssmsplus.ini", pl_psp_get_app_directory()); + + /* Initialize INI structure */ + pl_ini_file init; + pl_ini_create(&init); + + /* Set values */ + pl_ini_set_int(&init, "Video", "Display Mode", Options.DisplayMode); + pl_ini_set_int(&init, "Video", "Update Frequency", Options.UpdateFreq); + pl_ini_set_int(&init, "Video", "Frameskip", Options.Frameskip); + pl_ini_set_int(&init, "Video", "VSync", Options.VSync); + pl_ini_set_int(&init, "Video", "PSP Clock Frequency",Options.ClockFreq); + pl_ini_set_int(&init, "Video", "Show FPS", Options.ShowFps); + pl_ini_set_int(&init, "Menu", "Control Mode", Options.ControlMode); + pl_ini_set_int(&init, "Menu", "Animate", UiMetric.Animate); + pl_ini_set_int(&init, "Game", "Vertical Strip", Options.VertStrip); + pl_ini_set_int(&init, "Input", "Autofire", Options.AutoFire); + pl_ini_set_int(&init, "Enhancements", "Rewind Save Rate", Options.RewindSaveRate); + pl_ini_set_int(&init, "Enhancements", "Rewind Replay Delay", Options.RewindReplayDelay); + pl_ini_set_string(&init, "File", "Game Path", GamePath); + + /* Save INI file */ + int status = pl_ini_save(&init, path); + + /* Clean up */ + pl_ini_destroy(&init); + + return status; +} + +/* Load state icon */ +PspImage* LoadStateIcon(const char *path) +{ + /* Open file for reading */ + FILE *f = fopen(path, "r"); + if (!f) return NULL; + + /* Load image */ + PspImage *image = pspImageLoadPngFd(f); + fclose(f); + + return image; +} + +/* Load state */ +int LoadState(const char *path) +{ + /* Open file for reading */ + FILE *f = fopen(path, "r"); + if (!f) return 0; + + /* Load image into temporary object */ + PspImage *image = pspImageLoadPngFd(f); + pspImageDestroy(image); + + //system_load_state(f); + fclose(f); + + return 1; +} + +/* Save state */ +PspImage* SaveState(const char *path, PspImage *icon) +{ + /* Open file for writing */ + FILE *f; + if (!(f = fopen(path, "w"))) + return NULL; + + /* Create thumbnail */ + PspImage *thumb; + thumb = (icon->Viewport.Width < 200) + ? pspImageCreateCopy(icon) : pspImageCreateThumbnail(icon); + if (!thumb) { fclose(f); return NULL; } + + /* Write the thumbnail */ + if (!pspImageSavePngFd(f, thumb)) + { + pspImageDestroy(thumb); + fclose(f); + return NULL; + } + + /* Save state */ + //system_save_state(f); + + fclose(f); + return thumb; +} + +/* Release menu resources */ +void TrashMenu() +{ + TrashEmulator(); + + /* Save options */ + SaveOptions(); + + /* Trash menus */ + pl_menu_destroy(&SystemUiMenu.Menu); + pl_menu_destroy(&OptionUiMenu.Menu); + pl_menu_destroy(&ControlUiMenu.Menu); + pl_menu_destroy(&SaveStateGallery.Menu); + + /* Trash images */ + if (Background) pspImageDestroy(Background); + if (NoSaveIcon) pspImageDestroy(NoSaveIcon); +} + +/* Save or load SRAM */ +void system_manage_sram(uint8 *sram, int slot, int mode) +{ + FILE *fd; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + char *path = (char*)malloc(sizeof(char) + * (strlen(SaveStatePath) + strlen(config_name) + 8)); + sprintf(path, "%s%s.srm", SaveStatePath, config_name); + + /*switch(mode) + { + case SRAM_SAVE: + if(sms.save) + { + fd = fopen(path, "w"); + if(fd) + { + fwrite(sram, 0x8000, 1, fd); + fclose(fd); + } + } + break; + + case SRAM_LOAD: + fd = fopen(path, "r"); + if(fd) + { + sms.save = 1; + fread(sram, 0x8000, 1, fd); + fclose(fd); + } + else + {*/ + /* No SRAM file, so initialize memory */ + /* memset(sram, 0x00, 0x8000); + } + break; + } + */ + free(path); +} diff --git a/psp2/menu.h b/psp2/menu.h new file mode 100644 index 0000000..364ab35 --- /dev/null +++ b/psp2/menu.h @@ -0,0 +1,8 @@ +#ifndef _MENU_H +#define _MENU_H + +void InitMenu(); +void DisplayMenu(); +void TrashMenu(); + +#endif diff --git a/psp2/osd.h b/psp2/osd.h new file mode 100644 index 0000000..e1a8ae4 --- /dev/null +++ b/psp2/osd.h @@ -0,0 +1,34 @@ + +#ifndef _OSD_H_ +#define _OSD_H_ + +#include +#include +#include +#include + +#include + +#include "shared.h" +#include "config.h" +#include "error.h" +#include "unzip.h" +#include "fileio.h" + +extern void osd_input_update(void); + + +#define GG_ROM "./ggenie.bin" +#define AR_ROM "./areplay.bin" +#define SK_ROM "./sk.bin" +#define SK_UPMEM "./sk2chip.bin" +#define CD_BIOS_US "./bios_CD_U.bin" +#define CD_BIOS_EU "./bios_CD_E.bin" +#define CD_BIOS_JP "./bios_CD_J.bin" +#define MD_BIOS "./bios_MD.bin" +#define MS_BIOS_US "./bios_U.sms" +#define MS_BIOS_EU "./bios_E.sms" +#define MS_BIOS_JP "./bios_J.sms" +#define GG_BIOS "./bios.gg" + +#endif /* _OSD_H_ */ diff --git a/psp2/unzip.c b/psp2/unzip.c new file mode 100644 index 0000000..ef52bc6 --- /dev/null +++ b/psp2/unzip.c @@ -0,0 +1,1294 @@ +/* unzip.c -- IO on .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Read unzip.h for more info +*/ + + +#include +#include +#include +#include +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else + #include +#endif + + +#ifndef local + #define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +const char unz_copyright[] = + " unzip 0.15 Copyright 1998 Gilles Vollant "; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte(fin,pi) + FILE *fin; + int *pi; +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir(fin) + FILE *fin; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen (path) + const char *path; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ +/* int err=UNZ_OK; */ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/psp2/unzip.h b/psp2/unzip.h new file mode 100644 index 0000000..a30f79c --- /dev/null +++ b/psp2/unzip.h @@ -0,0 +1,273 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */