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..c4fbdff --- /dev/null +++ b/psp2/menu.c @@ -0,0 +1,1288 @@ +#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_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", 333); + 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 */