mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2024-11-22 23:39:50 +00:00
Initial commit.
This commit is contained in:
commit
e942ae84aa
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
*.o
|
||||
*.so
|
||||
*.dll
|
||||
*.dylib
|
||||
/old
|
||||
|
131
Makefile
Normal file
131
Makefile
Normal file
@ -0,0 +1,131 @@
|
||||
TARGET := libretro.so
|
||||
|
||||
MEDNAFEN_DIR := mednafen
|
||||
PSX_DIR := $(MEDNAFEN_DIR)/psx
|
||||
|
||||
PSX_SOURCES := $(PSX_DIR)/psx.cpp \
|
||||
$(PSX_DIR)/irq.cpp \
|
||||
$(PSX_DIR)/timer.cpp \
|
||||
$(PSX_DIR)/dma.cpp \
|
||||
$(PSX_DIR)/frontio.cpp \
|
||||
$(PSX_DIR)/sio.cpp \
|
||||
$(PSX_DIR)/cpu.cpp \
|
||||
$(PSX_DIR)/gte.cpp \
|
||||
$(PSX_DIR)/dis.cpp \
|
||||
$(PSX_DIR)/cdc.cpp \
|
||||
$(PSX_DIR)/spu.cpp \
|
||||
$(PSX_DIR)/gpu.cpp \
|
||||
$(PSX_DIR)/mdec.cpp \
|
||||
$(PSX_DIR)/input/gamepad.cpp \
|
||||
$(PSX_DIR)/input/dualanalog.cpp \
|
||||
$(PSX_DIR)/input/memcard.cpp \
|
||||
$(PSX_DIR)/input/multitap.cpp \
|
||||
$(PSX_DIR)/input/mouse.cpp
|
||||
|
||||
MEDNAFEN_SOURCES := $(MEDNAFEN_DIR)/cdrom/cdromif.cpp \
|
||||
$(MEDNAFEN_DIR)/mednafen.cpp \
|
||||
$(MEDNAFEN_DIR)/PSFLoader.cpp \
|
||||
$(MEDNAFEN_DIR)/error.cpp \
|
||||
$(MEDNAFEN_DIR)/math_ops.cpp \
|
||||
$(MEDNAFEN_DIR)/settings.cpp \
|
||||
$(MEDNAFEN_DIR)/netplay.cpp \
|
||||
$(MEDNAFEN_DIR)/general.cpp \
|
||||
$(MEDNAFEN_DIR)/player.cpp \
|
||||
$(MEDNAFEN_DIR)/cdplay.cpp \
|
||||
$(MEDNAFEN_DIR)/FileWrapper.cpp \
|
||||
$(MEDNAFEN_DIR)/state.cpp \
|
||||
$(MEDNAFEN_DIR)/tests.cpp \
|
||||
$(MEDNAFEN_DIR)/movie.cpp \
|
||||
$(MEDNAFEN_DIR)/endian.cpp \
|
||||
$(MEDNAFEN_DIR)/qtrecord.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/CDAccess.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/CDAccess_Image.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/CDUtility.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/lec.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/SimpleFIFO.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/audioreader.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/galois.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/pcecd.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/scsicd.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/recover-raw.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/l-ec.cpp \
|
||||
$(MEDNAFEN_DIR)/cdrom/crc32.cpp \
|
||||
$(MEDNAFEN_DIR)/memory.cpp \
|
||||
$(MEDNAFEN_DIR)/mempatcher.cpp \
|
||||
$(MEDNAFEN_DIR)/video/video.cpp \
|
||||
$(MEDNAFEN_DIR)/video/text.cpp \
|
||||
$(MEDNAFEN_DIR)/video/font-data.cpp \
|
||||
$(MEDNAFEN_DIR)/video/tblur.cpp \
|
||||
$(MEDNAFEN_DIR)/video/png.cpp \
|
||||
$(MEDNAFEN_DIR)/video/Deinterlacer.cpp \
|
||||
$(MEDNAFEN_DIR)/video/surface.cpp \
|
||||
$(MEDNAFEN_DIR)/video/resize.cpp \
|
||||
$(MEDNAFEN_DIR)/string/escape.cpp \
|
||||
$(MEDNAFEN_DIR)/string/ConvertUTF.cpp \
|
||||
$(MEDNAFEN_DIR)/sound/Blip_Buffer.cpp \
|
||||
$(MEDNAFEN_DIR)/sound/Fir_Resampler.cpp \
|
||||
$(MEDNAFEN_DIR)/sound/Stereo_Buffer.cpp \
|
||||
$(MEDNAFEN_DIR)/sound/WAVRecord.cpp \
|
||||
$(MEDNAFEN_DIR)/sound/sound.cpp \
|
||||
$(MEDNAFEN_DIR)/file.cpp \
|
||||
$(MEDNAFEN_DIR)/okiadpcm.cpp \
|
||||
$(MEDNAFEN_DIR)/md5.cpp
|
||||
|
||||
MPC_SRC := $(wildcard $(MEDNAFEN_DIR)/mpcdec/*.c)
|
||||
TREMOR_SRC := $(wildcard $(MEDNAFEN_DIR)/tremor/*.c)
|
||||
|
||||
SOURCES_C := $(MEDNAFEN_DIR)/trio/trio.c \
|
||||
$(MPC_SRC) \
|
||||
$(TREMOR_SRC) \
|
||||
$(MEDNAFEN_DIR)/trio/trionan.c \
|
||||
$(MEDNAFEN_DIR)/trio/triostr.c \
|
||||
$(MEDNAFEN_DIR)/string/world_strtod.c \
|
||||
$(MEDNAFEN_DIR)/compress/blz.c \
|
||||
$(MEDNAFEN_DIR)/compress/unzip.c \
|
||||
$(MEDNAFEN_DIR)/compress/minilzo.c \
|
||||
$(MEDNAFEN_DIR)/compress/quicklz.c \
|
||||
$(MEDNAFEN_DIR)/compress/ioapi.c \
|
||||
$(MEDNAFEN_DIR)/resampler/resample.c
|
||||
|
||||
LIBRETRO_SOURCES := libretro.cpp stubs.cpp
|
||||
|
||||
SOURCES := $(LIBRETRO_SOURCES) $(PSX_SOURCES) $(MEDNAFEN_SOURCES)
|
||||
OBJECTS := $(SOURCES:.cpp=.o) $(SOURCES_C:.c=.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
|
||||
LDFLAGS += -Wl,--no-undefined -fPIC -shared -lz -Wl,--version-script=link.T -pthread
|
||||
FLAGS += -ffast-math -msse -msse2 -funroll-loops -O3 -g -Wall -fPIC -fno-strict-overflow -fno-strict-aliasing
|
||||
FLAGS += -I. -Imednafen -Imednafen/include -Imednafen/intl -pthread
|
||||
|
||||
WARNINGS := -Wall \
|
||||
-Wno-narrowing \
|
||||
-Wno-unused-but-set-variable \
|
||||
-Wno-sign-compare \
|
||||
-Wno-unused-variable \
|
||||
-Wno-unused-function \
|
||||
-Wno-uninitialized \
|
||||
-Wno-unused-result \
|
||||
-Wno-overflow
|
||||
|
||||
FLAGS += -DLSB_FIRST -DHAVE_MKDIR -DSIZEOF_DOUBLE=8 $(WARNINGS) \
|
||||
-DMEDNAFEN_VERSION=\"0.9.22\" -DMEDNAFEN_VERSION_NUMERIC=922 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 \
|
||||
-DWANT_PSX_EMU -DSTDC_HEADERS
|
||||
|
||||
CXXFLAGS += $(FLAGS)
|
||||
CFLAGS += $(FLAGS) -std=gnu99
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(OBJECTS)
|
||||
|
||||
.PHONY: clean
|
197
libretro.cpp
Normal file
197
libretro.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
#include "mednafen/mednafen-types.h"
|
||||
#include "mednafen/mednafen.h"
|
||||
#include "mednafen/git.h"
|
||||
#include "mednafen/general.h"
|
||||
#include <iostream>
|
||||
#include "libretro.h"
|
||||
|
||||
static MDFNGI *game;
|
||||
static retro_video_refresh_t video_cb;
|
||||
static retro_audio_sample_t audio_cb;
|
||||
static retro_audio_sample_batch_t audio_batch_cb;
|
||||
static retro_environment_t environ_cb;
|
||||
static retro_input_poll_t input_poll_cb;
|
||||
static retro_input_state_t input_state_cb;
|
||||
|
||||
static MDFN_Surface *surf;
|
||||
|
||||
static uint16_t conv_buf[680 * 512] __attribute__((aligned(16)));
|
||||
static uint32_t mednafen_buf[680 * 512] __attribute__((aligned(16)));
|
||||
|
||||
void retro_init()
|
||||
{
|
||||
MDFN_PixelFormat pix_fmt(MDFN_COLORSPACE_RGB, 16, 8, 0, 24);
|
||||
surf = new MDFN_Surface(mednafen_buf, 680, 512, 680, pix_fmt);
|
||||
|
||||
std::vector<MDFNGI*> ext;
|
||||
MDFNI_InitializeModules(ext);
|
||||
|
||||
std::vector<MDFNSetting> settings;
|
||||
std::string home = getenv("HOME");
|
||||
home += "/.mednafen";
|
||||
MDFNI_Initialize(home.c_str(), settings);
|
||||
}
|
||||
|
||||
void retro_deinit()
|
||||
{
|
||||
//MDFNI_Kill();
|
||||
delete surf;
|
||||
surf = NULL;
|
||||
}
|
||||
|
||||
void retro_reset()
|
||||
{
|
||||
MDFNI_Reset();
|
||||
}
|
||||
|
||||
bool retro_load_game_special(unsigned, const struct retro_game_info *, size_t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool retro_load_game(const struct retro_game_info *info)
|
||||
{
|
||||
game = MDFNI_LoadGame("psx", info->path);
|
||||
return game;
|
||||
}
|
||||
|
||||
void retro_unload_game()
|
||||
{
|
||||
MDFNI_CloseGame();
|
||||
}
|
||||
|
||||
static inline uint16_t conv_pixel(uint32_t pix)
|
||||
{
|
||||
uint16_t r = (pix >> 19) & 0x1f;
|
||||
uint16_t g = (pix >> 11) & 0x1f;
|
||||
uint16_t b = (pix >> 3) & 0x1f;
|
||||
return (r << 10) | (g << 5) | (b << 0);
|
||||
}
|
||||
|
||||
void retro_run()
|
||||
{
|
||||
input_poll_cb();
|
||||
|
||||
static int16_t sound_buf[0x10000];
|
||||
static MDFN_Rect rects[512];
|
||||
|
||||
EmulateSpecStruct spec = {0};
|
||||
spec.surface = surf;
|
||||
spec.SoundRate = 44100;
|
||||
spec.SoundBuf = sound_buf;
|
||||
spec.LineWidths = rects;
|
||||
spec.SoundBufMaxSize = sizeof(sound_buf) / 2;
|
||||
spec.SoundVolume = 1.0;
|
||||
spec.soundmultiplier = 1.0;
|
||||
|
||||
MDFNI_Emulate(&spec);
|
||||
|
||||
unsigned width = rects[0].w;
|
||||
unsigned height = spec.DisplayRect.h;
|
||||
|
||||
for (unsigned i = 0; i < 680 * 512; i++)
|
||||
conv_buf[i] = conv_pixel(surf->pixels[i]);
|
||||
|
||||
video_cb(conv_buf, width, height, 680 << 1);
|
||||
|
||||
audio_batch_cb(spec.SoundBuf, spec.SoundBufSize);
|
||||
}
|
||||
|
||||
void retro_get_system_info(struct retro_system_info *info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->library_name = "Mednafen PSX";
|
||||
info->library_version = "0.9.22";
|
||||
info->need_fullpath = true;
|
||||
info->valid_extensions = "iso|ISO";
|
||||
}
|
||||
|
||||
void retro_get_system_av_info(struct retro_system_av_info *info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->timing.fps = 59.97;
|
||||
info->timing.sample_rate = 44100;
|
||||
info->geometry.base_width = game->nominal_width;
|
||||
info->geometry.base_height = game->nominal_height;
|
||||
info->geometry.max_width = 680;
|
||||
info->geometry.max_height = 480;
|
||||
info->geometry.aspect_ratio = 4.0 / 3.0;
|
||||
}
|
||||
|
||||
unsigned retro_get_region(void)
|
||||
{
|
||||
return RETRO_REGION_NTSC;
|
||||
}
|
||||
|
||||
unsigned retro_api_version(void)
|
||||
{
|
||||
return RETRO_API_VERSION;
|
||||
}
|
||||
|
||||
void retro_set_controller_port_device(unsigned port, unsigned device)
|
||||
{
|
||||
(void)port;
|
||||
(void)device;
|
||||
}
|
||||
|
||||
void retro_set_environment(retro_environment_t cb)
|
||||
{
|
||||
environ_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_audio_sample(retro_audio_sample_t cb)
|
||||
{
|
||||
audio_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
|
||||
{
|
||||
audio_batch_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_input_poll(retro_input_poll_t cb)
|
||||
{
|
||||
input_poll_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_input_state(retro_input_state_t cb)
|
||||
{
|
||||
input_state_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_video_refresh(retro_video_refresh_t cb)
|
||||
{
|
||||
video_cb = cb;
|
||||
}
|
||||
|
||||
size_t retro_serialize_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool retro_serialize(void *, size_t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool retro_unserialize(const void *, size_t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void *retro_get_memory_data(unsigned)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t retro_get_memory_size(unsigned)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void retro_cheat_reset(void)
|
||||
{}
|
||||
|
||||
void retro_cheat_set(unsigned, bool, const char *)
|
||||
{}
|
||||
|
312
libretro.h
Executable file
312
libretro.h
Executable file
@ -0,0 +1,312 @@
|
||||
#ifndef LIBRETRO_H__
|
||||
#define LIBRETRO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#else
|
||||
#if defined(_MSC_VER) && !defined(__cplusplus)
|
||||
#define bool unsigned char
|
||||
#define true 1
|
||||
#define false 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define RETRO_API_VERSION 1
|
||||
|
||||
#define RETRO_DEVICE_MASK 0xff
|
||||
#define RETRO_DEVICE_NONE 0
|
||||
#define RETRO_DEVICE_JOYPAD 1
|
||||
#define RETRO_DEVICE_MOUSE 2
|
||||
#define RETRO_DEVICE_KEYBOARD 3
|
||||
#define RETRO_DEVICE_LIGHTGUN 4
|
||||
#define RETRO_DEVICE_ANALOG 5
|
||||
|
||||
#define RETRO_DEVICE_JOYPAD_MULTITAP ((1 << 8) | RETRO_DEVICE_JOYPAD)
|
||||
#define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE ((1 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
#define RETRO_DEVICE_LIGHTGUN_JUSTIFIER ((2 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
#define RETRO_DEVICE_LIGHTGUN_JUSTIFIERS ((3 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
|
||||
#define RETRO_DEVICE_ID_JOYPAD_B 0
|
||||
#define RETRO_DEVICE_ID_JOYPAD_Y 1
|
||||
#define RETRO_DEVICE_ID_JOYPAD_SELECT 2
|
||||
#define RETRO_DEVICE_ID_JOYPAD_START 3
|
||||
#define RETRO_DEVICE_ID_JOYPAD_UP 4
|
||||
#define RETRO_DEVICE_ID_JOYPAD_DOWN 5
|
||||
#define RETRO_DEVICE_ID_JOYPAD_LEFT 6
|
||||
#define RETRO_DEVICE_ID_JOYPAD_RIGHT 7
|
||||
#define RETRO_DEVICE_ID_JOYPAD_A 8
|
||||
#define RETRO_DEVICE_ID_JOYPAD_X 9
|
||||
#define RETRO_DEVICE_ID_JOYPAD_L 10
|
||||
#define RETRO_DEVICE_ID_JOYPAD_R 11
|
||||
#define RETRO_DEVICE_ID_JOYPAD_L2 12
|
||||
#define RETRO_DEVICE_ID_JOYPAD_R2 13
|
||||
#define RETRO_DEVICE_ID_JOYPAD_L3 14
|
||||
#define RETRO_DEVICE_ID_JOYPAD_R3 15
|
||||
|
||||
#define RETRO_DEVICE_INDEX_ANALOG_LEFT 0
|
||||
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1
|
||||
#define RETRO_DEVICE_ID_ANALOG_X 0
|
||||
#define RETRO_DEVICE_ID_ANALOG_Y 1
|
||||
|
||||
#define RETRO_DEVICE_ID_MOUSE_X 0
|
||||
#define RETRO_DEVICE_ID_MOUSE_Y 1
|
||||
#define RETRO_DEVICE_ID_MOUSE_LEFT 2
|
||||
#define RETRO_DEVICE_ID_MOUSE_RIGHT 3
|
||||
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_X 0
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_Y 1
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_START 6
|
||||
|
||||
#define RETRO_REGION_NTSC 0
|
||||
#define RETRO_REGION_PAL 1
|
||||
|
||||
#define RETRO_MEMORY_MASK 0xff
|
||||
#define RETRO_MEMORY_SAVE_RAM 0
|
||||
#define RETRO_MEMORY_RTC 1
|
||||
#define RETRO_MEMORY_SYSTEM_RAM 2
|
||||
#define RETRO_MEMORY_VIDEO_RAM 3
|
||||
|
||||
#define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC)
|
||||
|
||||
#define RETRO_GAME_TYPE_BSX 0x101
|
||||
#define RETRO_GAME_TYPE_BSX_SLOTTED 0x102
|
||||
#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103
|
||||
#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104
|
||||
|
||||
|
||||
// Environment commands.
|
||||
#define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * --
|
||||
// Sets screen rotation of graphics.
|
||||
// Is only implemented if rotation can be accelerated by hardware.
|
||||
// Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, 270 degrees
|
||||
// counter-clockwise respectively.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 // bool * --
|
||||
// Boolean value whether or not the implementation should use overscan, or crop away overscan.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 // bool * --
|
||||
// Boolean value whether or not RetroArch supports frame duping,
|
||||
// passing NULL to video frame callback.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_VARIABLE 4 // struct retro_variable * --
|
||||
// Interface to aquire user-defined information from environment
|
||||
// that cannot feasibly be supported in a multi-system way.
|
||||
// Mostly used for obscure,
|
||||
// specific features that the user can tap into when neseccary.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_VARIABLES 5 // const struct retro_variable * --
|
||||
// Allows an implementation to signal the environment
|
||||
// which variables it might want to check for later using GET_VARIABLE.
|
||||
// 'data' points to an array of retro_variable structs terminated by a { NULL, NULL } element.
|
||||
// retro_variable::value should contain a human readable description of the key.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_MESSAGE 6 // const struct retro_message * --
|
||||
// Sets a message to be displayed in implementation-specific manner for a certain amount of 'frames'.
|
||||
// Should not be used for trivial messages, which should simply be logged to stderr.
|
||||
#define RETRO_ENVIRONMENT_SHUTDOWN 7 // N/A (NULL) --
|
||||
// Requests the frontend to shutdown.
|
||||
// Should only be used if game has a specific
|
||||
// way to shutdown the game from a menu item or similar.
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8
|
||||
// const unsigned * --
|
||||
// Gives a hint to the frontend how demanding this implementation
|
||||
// is on a system. E.g. reporting a level of 2 means
|
||||
// this implementation should run decently on all frontends
|
||||
// of level 2 and up.
|
||||
//
|
||||
// It can be used by the frontend to potentially warn
|
||||
// about too demanding implementations.
|
||||
//
|
||||
// The levels are "floating", but roughly defined as:
|
||||
// 1: Low-powered devices such as Raspberry Pi, smart phones, tablets, etc.
|
||||
// 2: Medium-spec consoles, such as PS3/360, with sub-par CPUs.
|
||||
// 3: Modern desktop/laptops with reasonably powerful CPUs.
|
||||
// 4: High-end desktops with very powerful CPUs.
|
||||
//
|
||||
// This function can be called on a per-game basis,
|
||||
// as certain games an implementation can play might be
|
||||
// particularily demanding.
|
||||
// If called, it should be called in retro_load_game().
|
||||
|
||||
struct retro_message
|
||||
{
|
||||
const char *msg; // Message to be displayed.
|
||||
unsigned frames; // Duration in frames of message.
|
||||
};
|
||||
|
||||
struct retro_system_info
|
||||
{
|
||||
const char *library_name; // Descriptive name of library. Should not contain any version numbers, etc.
|
||||
const char *library_version; // Descriptive version of core.
|
||||
|
||||
const char *valid_extensions; // A string listing probably rom extensions the core will be able to load, separated with pipe.
|
||||
// I.e. "bin|rom|iso".
|
||||
// Typically used for a GUI to filter out extensions.
|
||||
|
||||
bool need_fullpath; // If true, retro_load_game() is guaranteed to provide a valid pathname in retro_game_info::path.
|
||||
// ::data and ::size are both invalid.
|
||||
// If false, ::data and ::size are guaranteed to be valid, but ::path might not be valid.
|
||||
// This is typically set to true for libretro implementations that must load from file.
|
||||
// Implementations should strive for setting this to false, as it allows the frontend to perform patching, etc.
|
||||
|
||||
bool block_extract; // If true, the frontend is not allowed to extract any archives before loading the real ROM.
|
||||
// Necessary for certain libretro implementations that load games from zipped archives.
|
||||
};
|
||||
|
||||
struct retro_game_geometry
|
||||
{
|
||||
unsigned base_width; // Nominal video width of game.
|
||||
unsigned base_height; // Nominal video height of game.
|
||||
unsigned max_width; // Maximum possible width of game.
|
||||
unsigned max_height; // Maximum possible height of game.
|
||||
|
||||
float aspect_ratio; // Nominal aspect ratio of game. If aspect_ratio is <= 0.0,
|
||||
// an aspect ratio of base_width / base_height is assumed.
|
||||
// A frontend could override this setting if desired.
|
||||
};
|
||||
|
||||
struct retro_system_timing
|
||||
{
|
||||
double fps; // FPS of video content.
|
||||
double sample_rate; // Sampling rate of audio.
|
||||
};
|
||||
|
||||
struct retro_system_av_info
|
||||
{
|
||||
struct retro_game_geometry geometry;
|
||||
struct retro_system_timing timing;
|
||||
};
|
||||
|
||||
struct retro_variable
|
||||
{
|
||||
const char *key; // Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
|
||||
// If NULL, obtains the complete environment string if more complex parsing is necessary.
|
||||
// The environment string is formatted as key-value pairs delimited by semicolons as so:
|
||||
// "key1=value1;key2=value2;..."
|
||||
const char *value; // Value to be obtained. If key does not exist, it is set to NULL.
|
||||
};
|
||||
|
||||
struct retro_game_info
|
||||
{
|
||||
const char *path; // Path to game, UTF-8 encoded. Usually used as a reference.
|
||||
// May be NULL if rom was loaded from stdin or similar.
|
||||
// retro_system_info::need_fullpath guaranteed that this path is valid.
|
||||
const void *data; // Memory buffer of loaded game. Will be NULL if need_fullpath was set.
|
||||
size_t size; // Size of memory buffer.
|
||||
const char *meta; // String of implementation specific meta-data.
|
||||
};
|
||||
|
||||
// Callbacks
|
||||
//
|
||||
// Environment callback. Gives implementations a way of performing uncommon tasks. Extensible.
|
||||
typedef bool (*retro_environment_t)(unsigned cmd, void *data);
|
||||
|
||||
// Render a frame. Pixel format is 15-bit XRGB1555 native endian.
|
||||
// Width and height specify dimensions of buffer.
|
||||
// Pitch specifices length in bytes between two lines in buffer.
|
||||
typedef void (*retro_video_refresh_t)(const void *data, unsigned width, unsigned height, size_t pitch);
|
||||
|
||||
// Renders a single audio frame. Should only be used if implementation generates a single sample at a time.
|
||||
// Format is signed 16-bit native endian.
|
||||
typedef void (*retro_audio_sample_t)(int16_t left, int16_t right);
|
||||
// Renders multiple audio frames in one go. One frame is defined as a sample of left and right channels, interleaved.
|
||||
// I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
|
||||
// Only one of the audio callbacks must ever be used.
|
||||
typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data, size_t frames);
|
||||
|
||||
// Polls input.
|
||||
typedef void (*retro_input_poll_t)(void);
|
||||
// Queries for input for player 'port'. device will be masked with RETRO_DEVICE_MASK.
|
||||
// Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that have been set with retro_set_controller_port_device()
|
||||
// will still use the higher level RETRO_DEVICE_JOYPAD to request input.
|
||||
typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
|
||||
// Sets callbacks. retro_set_environment() is guaranteed to be called before retro_init().
|
||||
// The rest of the set_* functions are guaranteed to have been called before the first call to retro_run() is made.
|
||||
void retro_set_environment(retro_environment_t);
|
||||
void retro_set_video_refresh(retro_video_refresh_t);
|
||||
void retro_set_audio_sample(retro_audio_sample_t);
|
||||
void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
|
||||
void retro_set_input_poll(retro_input_poll_t);
|
||||
void retro_set_input_state(retro_input_state_t);
|
||||
|
||||
// Library global initialization/deinitialization.
|
||||
void retro_init(void);
|
||||
void retro_deinit(void);
|
||||
|
||||
// Must return RETRO_API_VERSION. Used to validate ABI compatibility when the API is revised.
|
||||
unsigned retro_api_version(void);
|
||||
|
||||
// Gets statically known system info. Pointers provided in *info must be statically allocated.
|
||||
// Can be called at any time, even before retro_init().
|
||||
void retro_get_system_info(struct retro_system_info *info);
|
||||
|
||||
// Gets information about system audio/video timings and geometry.
|
||||
// Can be called only after retro_load_game() has successfully completed.
|
||||
void retro_get_system_av_info(struct retro_system_av_info *info);
|
||||
|
||||
// Sets device to be used for player 'port'.
|
||||
void retro_set_controller_port_device(unsigned port, unsigned device);
|
||||
|
||||
// Resets the current game.
|
||||
void retro_reset(void);
|
||||
|
||||
// Runs the game for one video frame.
|
||||
// During retro_run(), input_poll callback must be called at least once.
|
||||
//
|
||||
// If a frame is not rendered for reasons where a game "dropped" a frame,
|
||||
// this still counts as a frame, and retro_run() should explicitly dupe a frame if GET_CAN_DUPE returns true.
|
||||
// In this case, the video callback can take a NULL argument for data.
|
||||
void retro_run(void);
|
||||
|
||||
// Returns the amount of data the implementation requires to serialize internal state (save states).
|
||||
// Beetween calls to retro_load_game() and retro_unload_game(), the returned size is never allowed to be larger than a previous returned value, to
|
||||
// ensure that the frontend can allocate a save state buffer once.
|
||||
size_t retro_serialize_size(void);
|
||||
|
||||
// Serializes internal state. If failed, or size is lower than retro_serialize_size(), it should return false, true otherwise.
|
||||
bool retro_serialize(void *data, size_t size);
|
||||
bool retro_unserialize(const void *data, size_t size);
|
||||
|
||||
void retro_cheat_reset(void);
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char *code);
|
||||
|
||||
// Loads a game.
|
||||
bool retro_load_game(const struct retro_game_info *game);
|
||||
|
||||
// Loads a "special" kind of game. Should not be used except in extreme cases.
|
||||
bool retro_load_game_special(
|
||||
unsigned game_type,
|
||||
const struct retro_game_info *info, size_t num_info
|
||||
);
|
||||
|
||||
// Unloads a currently loaded game.
|
||||
void retro_unload_game(void);
|
||||
|
||||
// Gets region of game.
|
||||
unsigned retro_get_region(void);
|
||||
|
||||
// Gets region of memory.
|
||||
void *retro_get_memory_data(unsigned id);
|
||||
size_t retro_get_memory_size(unsigned id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
351
mednafen/FileWrapper.cpp
Normal file
351
mednafen/FileWrapper.cpp
Normal file
@ -0,0 +1,351 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "mednafen.h"
|
||||
#include "FileWrapper.h"
|
||||
|
||||
#include <trio/trio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
// Some really bad preprocessor abuse follows to handle platforms that don't have fseeko and ftello...and of course
|
||||
// for largefile support on Windows:
|
||||
|
||||
#ifndef HAVE_FSEEKO
|
||||
#define fseeko fseek
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FTELLO
|
||||
#define ftello ftell
|
||||
#endif
|
||||
|
||||
#if SIZEOF_OFF_T == 4
|
||||
|
||||
#ifdef HAVE_FOPEN64
|
||||
#define fopen fopen64
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FTELLO64
|
||||
#undef ftello
|
||||
#define ftello ftello64
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSEEKO64
|
||||
#undef fseeko
|
||||
#define fseeko fseeko64
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSTAT64
|
||||
#define fstat fstat64
|
||||
#define stat stat64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// For special uses, IE in classes that take a path or a FileWrapper & in the constructor, and the FileWrapper non-pointer member
|
||||
// is in the initialization list for the path constructor but not the constructor with FileWrapper&
|
||||
#if 0
|
||||
FileWrapper::FileWrapper()
|
||||
{
|
||||
fp = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
FileWrapper::FileWrapper(FileWrapper &original) : OpenedMode(original.OpenedMode)
|
||||
{
|
||||
int fd;
|
||||
int duped_fd;
|
||||
|
||||
path_save = original.path_save;
|
||||
|
||||
original.flush();
|
||||
|
||||
fd = fileno(original.fp);
|
||||
if(-1 == (duped_fd = dup(fd)))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error duping file descriptor: %s"), ene.StrError()));
|
||||
}
|
||||
|
||||
if(!(fp = fdopen(duped_fd, (OpenedMode == MODE_READ) ? "rb" : "wb")))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error during fdopen(): %s"), ene.StrError()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
FileWrapper::FileWrapper(const char *path, const int mode, const char *purpose) : OpenedMode(mode)
|
||||
{
|
||||
path_save = std::string(path);
|
||||
|
||||
if(mode == MODE_READ)
|
||||
fp = fopen(path, "rb");
|
||||
else if(mode == MODE_WRITE)
|
||||
fp = fopen(path, "wb");
|
||||
else if(mode == MODE_WRITE_SAFE) // SO ANNOYING
|
||||
{
|
||||
int open_flags = O_WRONLY | O_CREAT | O_EXCL;
|
||||
|
||||
#ifdef O_BINARY
|
||||
open_flags |= O_BINARY;
|
||||
#elif defined(_O_BINARY)
|
||||
open_flags |= _O_BINARY;
|
||||
#endif
|
||||
|
||||
#if defined(S_IRGRP) && defined(S_IROTH)
|
||||
int tmpfd = open(path, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
#else
|
||||
int tmpfd = open(path, open_flags, S_IRUSR | S_IWUSR);
|
||||
#endif
|
||||
if(tmpfd == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
if(purpose)
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\" for \"%s\": %s"), path_save.c_str(), purpose, ene.StrError()));
|
||||
else
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
fp = fdopen(tmpfd, "wb");
|
||||
}
|
||||
|
||||
if(!fp)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
if(purpose)
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\" for \"%s\": %s"), path_save.c_str(), purpose, ene.StrError()));
|
||||
else
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
FileWrapper::~FileWrapper()
|
||||
{
|
||||
try
|
||||
{
|
||||
close();
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
MDFND_PrintError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void FileWrapper::close(void)
|
||||
{
|
||||
if(fp)
|
||||
{
|
||||
FILE *tmp = fp;
|
||||
|
||||
fp = NULL;
|
||||
|
||||
if(fclose(tmp) == EOF)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error closing opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64 FileWrapper::read(void *data, uint64 count, bool error_on_eof)
|
||||
{
|
||||
uint64 read_count;
|
||||
|
||||
clearerr(fp);
|
||||
|
||||
read_count = fread(data, 1, count, fp);
|
||||
|
||||
if(read_count != count)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
if(ferror(fp))
|
||||
throw(MDFN_Error(ene.Errno(), _("Error reading from opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
|
||||
if(error_on_eof)
|
||||
throw(MDFN_Error(ene.Errno(), _("Error reading from opened file \"%s\": %s"), path_save.c_str(), "EOF"));
|
||||
}
|
||||
|
||||
return(read_count);
|
||||
}
|
||||
|
||||
void FileWrapper::flush(void)
|
||||
{
|
||||
if(fflush(fp) == EOF)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error flushing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
void FileWrapper::write(const void *data, uint64 count)
|
||||
{
|
||||
if(fwrite(data, 1, count, fp) != count)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error writing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
int FileWrapper::scanf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
clearerr(fp);
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
ret = trio_vfscanf(fp, format, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if(ferror(fp))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error reading from opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
|
||||
//if(ret < 0 || ret == EOF)
|
||||
// throw(MDFN_Error(0, _("%s error on format string \"%s\""), "trio_vfscanf()", format));
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void FileWrapper::printf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
clearerr(fp);
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
trio_vfprintf(fp, format, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if(ferror(fp))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error writing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
void FileWrapper::put_char(int c)
|
||||
{
|
||||
if(fputc(c, fp) == EOF)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error writing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
void FileWrapper::put_string(const char *str)
|
||||
{
|
||||
write(str, strlen(str));
|
||||
}
|
||||
|
||||
// We need to decide whether to prohibit NULL characters in output and input strings via std::string.
|
||||
// Yes for correctness, no for potential security issues(though unlikely in context all things considered).
|
||||
void FileWrapper::put_string(const std::string &str)
|
||||
{
|
||||
write(str.data(), str.size());
|
||||
}
|
||||
|
||||
char *FileWrapper::get_line(char *buf_s, int buf_size)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
clearerr(fp);
|
||||
ret = ::fgets(buf_s, buf_size, fp);
|
||||
if(ferror(fp))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error reading line in opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
void FileWrapper::seek(int64 offset, int whence)
|
||||
{
|
||||
if(fseeko(fp, offset, whence) == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error seeking in opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
int64 FileWrapper::size(void)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if(fstat(fileno(fp), &buf) == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error getting the size of opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
|
||||
return(buf.st_size);
|
||||
|
||||
/* TODO for systems without fstat()?
|
||||
int64 orig_pos = tell();
|
||||
int64 ret;
|
||||
|
||||
seek(0, SEEK_END);
|
||||
|
||||
ret = tell();
|
||||
|
||||
seek(orig_pos, SEEK_SET);
|
||||
*/
|
||||
}
|
||||
|
||||
int64 FileWrapper::tell(void)
|
||||
{
|
||||
int64 offset;
|
||||
|
||||
offset = ftello(fp);
|
||||
|
||||
if(offset == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error getting position in opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
|
||||
return(offset);
|
||||
}
|
||||
|
||||
|
68
mednafen/FileWrapper.h
Normal file
68
mednafen/FileWrapper.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef __MDFN_FILEWRAPPER_H
|
||||
#define __MDFN_FILEWRAPPER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
// A stdio FILE wrapper(with some BSD and POSIXisms, and a little dash of Win32, thrown in for special behaviors)
|
||||
class FileWrapper
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
MODE_READ = 0,
|
||||
MODE_WRITE,
|
||||
MODE_WRITE_SAFE // Will throw an exception instead of overwriting an existing file.
|
||||
};
|
||||
|
||||
FileWrapper(const char *path, const int mode, const char *purpose = NULL);
|
||||
#if 0
|
||||
FileWrapper();
|
||||
#endif
|
||||
~FileWrapper();
|
||||
|
||||
uint64 read(void *data, uint64 count, bool error_on_eof = true);
|
||||
|
||||
void write(const void *data, uint64 count);
|
||||
|
||||
int scanf(const char *format, ...) MDFN_FORMATSTR(scanf, 2, 3);
|
||||
|
||||
void printf(const char *format, ...) MDFN_FORMATSTR(printf, 2, 3);
|
||||
|
||||
void put_char(int c);
|
||||
|
||||
void put_string(const char *str);
|
||||
void put_string(const std::string &str);
|
||||
|
||||
char *get_line(char *s, int size); // Same semantics as fgets(), for now
|
||||
|
||||
void seek(int64 offset, int whence);
|
||||
|
||||
int64 tell(void);
|
||||
|
||||
int64 size(void);
|
||||
|
||||
void flush(void);
|
||||
//void flushsync(void); // TODO: see fflush and fsync
|
||||
|
||||
void close(void); // Flushes and closes the underlying OS/C lib file. Calling any other method of this class after a call to
|
||||
// this method is illegal(except for the implicit call to the destructor).
|
||||
//
|
||||
// This is necessary since there can be errors when closing a file, and we can't safely throw an
|
||||
// exception from the destructor.
|
||||
//
|
||||
// Manually calling this method isn't strictly necessary, it'll be called from the destructor
|
||||
// automatically, but calling is strongly recommended when the file is opened for writing.
|
||||
private:
|
||||
|
||||
FileWrapper & operator=(const FileWrapper &); // Assignment operator
|
||||
FileWrapper(const FileWrapper &); // Copy constructor
|
||||
//FileWrapper(FileWrapper &); // Copy constructor
|
||||
|
||||
FILE *fp;
|
||||
std::string path_save;
|
||||
const int OpenedMode;
|
||||
};
|
||||
|
||||
#endif
|
335
mednafen/PSFLoader.cpp
Normal file
335
mednafen/PSFLoader.cpp
Normal file
@ -0,0 +1,335 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/*
|
||||
TODO:
|
||||
Time string parsing convenience functions.
|
||||
|
||||
Character set autodetect heuristics and conversion for when the "utf8" tag is missing.
|
||||
*/
|
||||
#include "mednafen.h"
|
||||
#include "PSFLoader.h"
|
||||
#include "mednafen-endian.h"
|
||||
#include "general.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <trio/trio.h>
|
||||
#include <ctype.h>
|
||||
//#include <iconv.h>
|
||||
|
||||
|
||||
PSFTags::PSFTags()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
PSFTags::~PSFTags()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PSFTags::AddTag(char *tag_line)
|
||||
{
|
||||
char *eq;
|
||||
|
||||
// Transform 0x01-0x1F -> 0x20
|
||||
for(unsigned int i = 0; i < strlen(tag_line); i++)
|
||||
if((unsigned char)tag_line[i] < 0x20)
|
||||
tag_line[i] = 0x20;
|
||||
|
||||
eq = strchr(tag_line, '=');
|
||||
|
||||
if(eq)
|
||||
{
|
||||
*eq = 0;
|
||||
|
||||
MDFN_trim(tag_line);
|
||||
MDFN_trim(eq + 1);
|
||||
|
||||
for(unsigned int i = 0; i < strlen(tag_line); i++)
|
||||
tag_line[i] = tolower(tag_line[i]);
|
||||
|
||||
if(TagExists(tag_line))
|
||||
tags[tag_line] = tags[std::string(tag_line)] + std::string(1, '\n') + std::string(eq + 1);
|
||||
else
|
||||
tags[tag_line] = std::string(eq + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static const char *DetectCharset(const uint8 *data, const uint32 data_size)
|
||||
{
|
||||
static const char *TestCharsets[] = { "UTF-8", /*"SJIS",*/ "WINDOWS-1252" };
|
||||
|
||||
for(unsigned int i = 0; i < sizeof(TestCharsets) / sizeof(TestCharsets[0]); i++)
|
||||
{
|
||||
iconv_t cd;
|
||||
|
||||
cd = iconv_open("UTF-32", TestCharsets[i]);
|
||||
if(cd != (iconv_t)-1)
|
||||
{
|
||||
size_t in_len = data_size;
|
||||
size_t out_len = data_size * 4 + 4;
|
||||
char *in_ptr = (char *)data;
|
||||
char *const out_ptr_mem = new char[out_len];
|
||||
char *out_ptr = out_ptr_mem;
|
||||
|
||||
if(iconv(cd, (ICONV_CONST char **)&in_ptr, &in_len, &out_ptr, &out_len) != (size_t)-1)
|
||||
{
|
||||
delete[] out_ptr_mem;
|
||||
return(TestCharsets[i]);
|
||||
}
|
||||
delete[] out_ptr_mem;
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
void PSFTags::LoadTags(const uint8 *data_in, uint32 size)
|
||||
{
|
||||
std::vector<char> tags_heap;
|
||||
char *data;
|
||||
char *spos;
|
||||
//const char *detected_charset = DetectCharset(data_in, size);
|
||||
|
||||
tags_heap.resize(size + 1);
|
||||
tags_heap[size] = 0;
|
||||
|
||||
memcpy(&tags_heap[0], data_in, size);
|
||||
|
||||
data = &tags_heap[0];
|
||||
spos = data;
|
||||
|
||||
while(size)
|
||||
{
|
||||
if(*data == 0x0A || *data == 0x00)
|
||||
{
|
||||
*data = 0;
|
||||
|
||||
if(data - spos)
|
||||
{
|
||||
if(*(data - 1) == 0xD) // handle \r
|
||||
*(data - 1) = 0;
|
||||
|
||||
AddTag(spos);
|
||||
}
|
||||
|
||||
spos = data + 1; // Skip \n for next tag
|
||||
}
|
||||
|
||||
size--;
|
||||
data++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int64 PSFTags::GetTagI(const char *name)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
|
||||
it = tags.find(name);
|
||||
if(it != tags.end())
|
||||
{
|
||||
long long ret = 0;
|
||||
std::string &tmp = tags[name];
|
||||
|
||||
trio_sscanf(tmp.c_str(), "%lld", &ret);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
return(0); // INT64_MIN
|
||||
}
|
||||
|
||||
bool PSFTags::TagExists(const char *name)
|
||||
{
|
||||
if(tags.find(name) != tags.end())
|
||||
return(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
std::string PSFTags::GetTag(const char *name)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
|
||||
it = tags.find(name);
|
||||
|
||||
if(it != tags.end())
|
||||
return(it->second);
|
||||
|
||||
return("");
|
||||
}
|
||||
|
||||
void PSFTags::EraseTag(const char *name)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
|
||||
it = tags.find(name);
|
||||
if(it != tags.end())
|
||||
tags.erase(it);
|
||||
}
|
||||
|
||||
PSFLoader::PSFLoader()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
PSFLoader::~PSFLoader()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool PSFLoader::TestMagic(uint8 version, MDFNFILE *fp)
|
||||
{
|
||||
if(fp->size < (3 + 1 + 4 + 4 + 4))
|
||||
return(false);
|
||||
|
||||
if(memcmp(fp->data, "PSF", 3))
|
||||
return(false);
|
||||
|
||||
if(fp->data[3] != version)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
PSFTags PSFLoader::LoadInternal(uint8 version, uint32 max_exe_size, MDFNFILE *fp, uint32 level, bool force_ignore_pcsp)
|
||||
{
|
||||
uint32 reserved_size, compressed_size, compressed_crc32;
|
||||
bool _lib_present = false;
|
||||
PSFTags tags;
|
||||
|
||||
std::vector<uint8> decompress_buffer;
|
||||
uLongf decompress_len;
|
||||
|
||||
if(!TestMagic(version, fp))
|
||||
throw(MDFN_Error(0, _("Not a PSF(version=0x%02x) file!"), version));
|
||||
|
||||
reserved_size = MDFN_de32lsb(fp->data + 4);
|
||||
compressed_size = MDFN_de32lsb(fp->data + 8);
|
||||
compressed_crc32 = MDFN_de32lsb(fp->data + 12);
|
||||
|
||||
if(fp->size < (16 + reserved_size + compressed_size))
|
||||
throw(MDFN_Error(0, _("PSF is missing at least %u bytes of data!"), 16 + reserved_size + compressed_size - fp->size));
|
||||
|
||||
if(crc32(0, fp->data + 16 + reserved_size, compressed_size) != compressed_crc32)
|
||||
throw(MDFN_Error(0, _("PSF compressed CRC32 mismatch(data is corrupt)!")));
|
||||
|
||||
|
||||
{
|
||||
const uint8 *tag_section = fp->data + 16 + reserved_size + compressed_size;
|
||||
uint32 tag_section_size = fp->size - 16 - reserved_size - compressed_size;
|
||||
|
||||
if(tag_section_size > 5 && !memcmp(tag_section, "[TAG]", 5))
|
||||
tags.LoadTags(tag_section + 5, tag_section_size - 5);
|
||||
}
|
||||
|
||||
//
|
||||
// Handle minipsf simple _lib
|
||||
//
|
||||
|
||||
if(level < 15)
|
||||
{
|
||||
if(tags.TagExists("_lib"))
|
||||
{
|
||||
std::string tp = tags.GetTag("_lib");
|
||||
|
||||
if(!MDFN_IsFIROPSafe(tp))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting."), tp.c_str()));
|
||||
}
|
||||
|
||||
MDFNFILE subfile(MDFN_MakeFName(MDFNMKF_AUX, 0, tp.c_str()).c_str(), NULL, NULL);
|
||||
|
||||
LoadInternal(version, max_exe_size, &subfile, level + 1);
|
||||
|
||||
_lib_present = true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
decompress_buffer.resize(max_exe_size);
|
||||
decompress_len = max_exe_size;
|
||||
switch( uncompress((Bytef *)&decompress_buffer[0], &decompress_len, (const Bytef *)(fp->data + 16 + reserved_size), compressed_size) )
|
||||
{
|
||||
default:
|
||||
throw(MDFN_Error(0, "zlib unknown error"));
|
||||
|
||||
case Z_OK: break;
|
||||
|
||||
case Z_MEM_ERROR:
|
||||
throw(MDFN_Error(0, "zlib Z_MEM_ERROR"));
|
||||
|
||||
case Z_BUF_ERROR:
|
||||
throw(MDFN_Error(0, _("PSF decompressed size exceeds maximum allowed!")));
|
||||
|
||||
case Z_DATA_ERROR:
|
||||
throw(MDFN_Error(0, _("PSF compressed data is bad.")));
|
||||
}
|
||||
|
||||
HandleReserved(fp->data + 16, reserved_size);
|
||||
HandleEXE(&decompress_buffer[0], decompress_len, force_ignore_pcsp | _lib_present);
|
||||
decompress_buffer.resize(0);
|
||||
|
||||
//
|
||||
// handle libN
|
||||
//
|
||||
if(level < 15)
|
||||
{
|
||||
for(unsigned int n = 2; n <= INT_MAX; n++)
|
||||
{
|
||||
char tmpbuf[32];
|
||||
|
||||
trio_snprintf(tmpbuf, 32, "_lib%d", (int)n);
|
||||
|
||||
if(tags.TagExists(tmpbuf))
|
||||
{
|
||||
MDFNFILE subfile(MDFN_MakeFName(MDFNMKF_AUX, 0, tags.GetTag(tmpbuf).c_str()).c_str(), NULL, NULL);
|
||||
|
||||
LoadInternal(version, max_exe_size, &subfile, level + 1, true);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(tags);
|
||||
}
|
||||
|
||||
PSFTags PSFLoader::Load(uint8 version, uint32 max_exe_size, MDFNFILE *fp)
|
||||
{
|
||||
return(LoadInternal(version, max_exe_size, fp, 0, false));
|
||||
}
|
||||
|
||||
void PSFLoader::HandleReserved(const uint8 *data, uint32 len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PSFLoader::HandleEXE(const uint8 *data, uint32 len, bool ignore_pcsp)
|
||||
{
|
||||
|
||||
}
|
||||
|
49
mednafen/PSFLoader.h
Normal file
49
mednafen/PSFLoader.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef __MDFN_PSFLOADER_H
|
||||
#define __MDFN_PSFLOADER_H
|
||||
|
||||
#include <map>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class PSFTags
|
||||
{
|
||||
public:
|
||||
|
||||
PSFTags();
|
||||
~PSFTags();
|
||||
|
||||
int64 GetTagI(const char *name);
|
||||
std::string GetTag(const char *name);
|
||||
bool TagExists(const char *name);
|
||||
|
||||
void LoadTags(const uint8 *data, uint32 size);
|
||||
void EraseTag(const char *name);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void AddTag(char *tag_line);
|
||||
std::map<std::string, std::string> tags;
|
||||
};
|
||||
|
||||
class PSFLoader
|
||||
{
|
||||
public:
|
||||
PSFLoader();
|
||||
~PSFLoader();
|
||||
|
||||
static bool TestMagic(uint8 version, MDFNFILE *fp);
|
||||
|
||||
PSFTags Load(uint8 version, uint32 max_exe_size, MDFNFILE *fp);
|
||||
|
||||
virtual void HandleReserved(const uint8 *data, uint32 len);
|
||||
virtual void HandleEXE(const uint8 *data, uint32 len, bool ignore_pcsp = false);
|
||||
|
||||
private:
|
||||
|
||||
PSFTags LoadInternal(uint8 version, uint32 max_exe_size, MDFNFILE *fp, uint32 level, bool force_ignore_pcsp = false);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
565
mednafen/cdplay.cpp
Normal file
565
mednafen/cdplay.cpp
Normal file
@ -0,0 +1,565 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
//#include <mednafen/mednafen.h>
|
||||
#include "mednafen.h"
|
||||
#include "cdrom/cdromif.h"
|
||||
#include "netplay.h"
|
||||
#include <blip/Blip_Buffer.h>
|
||||
#include <trio/trio.h>
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
#include <mednafen/resampler/resampler.h>
|
||||
|
||||
namespace MDFN_IEN_CDPLAY
|
||||
{
|
||||
|
||||
static std::vector<double> sqrt_lut; //[65536];
|
||||
static std::vector<double> sin_lut; //[65536];
|
||||
static SpeexResamplerState *resampler = NULL;
|
||||
|
||||
static uint8 *controller_ptr;
|
||||
static uint8 last_controller;
|
||||
|
||||
enum
|
||||
{
|
||||
PLAYMODE_PAUSE = -1,
|
||||
PLAYMODE_STOP = 0,
|
||||
PLAYMODE_PLAY = 1,
|
||||
PLAYMODE_SCAN_FORWARD = 2,
|
||||
PLAYMODE_SCAN_REVERSE = 3,
|
||||
};
|
||||
|
||||
static int PlayMode;
|
||||
static uint32 PlaySector;
|
||||
static int16 CDDABuffer[588 * 2];
|
||||
|
||||
static int16 ResampBuffer[588 * 2][2]; // Resampler input buffer, * 2 for resampler leftovers
|
||||
static uint32 ResampBufferPos;
|
||||
static uint32 PrevRate;
|
||||
static unsigned int CurrentDisc;
|
||||
|
||||
static std::vector<CDIF *> *cdifs;
|
||||
|
||||
static int32 CurrentATLI;
|
||||
|
||||
struct AudioTrackInfo
|
||||
{
|
||||
inline AudioTrackInfo(unsigned disc_, int32 track_, int32 lba_, int32 final_lba_)
|
||||
{
|
||||
disc = disc_;
|
||||
track = track_;
|
||||
lba = lba_;
|
||||
final_lba = final_lba_;
|
||||
}
|
||||
|
||||
unsigned disc;
|
||||
int32 track;
|
||||
int32 lba;
|
||||
int32 final_lba; // Inclusive.
|
||||
};
|
||||
|
||||
static std::vector<AudioTrackInfo> AudioTrackList;
|
||||
|
||||
static void InitLUT(void);
|
||||
|
||||
static int LoadCD(std::vector<CDIF *> *CDInterfaces)
|
||||
{
|
||||
cdifs = CDInterfaces;
|
||||
|
||||
AudioTrackList.clear();
|
||||
|
||||
for(unsigned disc = 0; disc < cdifs->size(); disc++)
|
||||
{
|
||||
TOC toc;
|
||||
|
||||
(*cdifs)[disc]->ReadTOC(&toc);
|
||||
|
||||
for(int32 track = toc.first_track; track <= toc.last_track; track++)
|
||||
{
|
||||
if(!(toc.tracks[track].control & 0x4))
|
||||
{
|
||||
AudioTrackList.push_back(AudioTrackInfo(disc, track, toc.tracks[track].lba, toc.tracks[track + 1].lba - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!AudioTrackList.size())
|
||||
{
|
||||
puts("Audio track doesn't exist");
|
||||
return(0);
|
||||
}
|
||||
|
||||
CurrentATLI = 0;
|
||||
PlaySector = AudioTrackList[CurrentATLI].lba;
|
||||
PlayMode = PLAYMODE_PLAY; //STOP;
|
||||
|
||||
{
|
||||
int err;
|
||||
resampler = speex_resampler_init(2, 44100, (int)48000, 5, &err);
|
||||
PrevRate = 48000;
|
||||
}
|
||||
//resampler.buffer_size(588 * 2 + 100);
|
||||
//resampler.time_ratio((double)44100 / 48000, 0.9965);
|
||||
ResampBufferPos = 0;
|
||||
|
||||
InitLUT();
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
|
||||
{
|
||||
CDUtility::TOC magic_toc;
|
||||
|
||||
for(unsigned i = 0; i < CDInterfaces->size(); i++)
|
||||
{
|
||||
(*CDInterfaces)[i]->ReadTOC(&magic_toc);
|
||||
|
||||
// If any audio track is found, return true.
|
||||
for(int32 track = magic_toc.first_track; track <= magic_toc.last_track; track++)
|
||||
if(!(magic_toc.tracks[track].control & 0x4))
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
static void CloseGame(void)
|
||||
{
|
||||
if(resampler)
|
||||
{
|
||||
speex_resampler_destroy(resampler);
|
||||
resampler = NULL;
|
||||
}
|
||||
sin_lut.resize(0);
|
||||
sqrt_lut.resize(0);
|
||||
}
|
||||
|
||||
static uint8 SubQBuf[3][0xC];
|
||||
|
||||
static void GenSubQFromSubPW(uint8 *SubPWBuf)
|
||||
{
|
||||
uint8 sq[0xC];
|
||||
|
||||
memset(sq, 0, 0xC);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
sq[i >> 3] |= ((SubPWBuf[i] & 0x40) >> 6) << (7 - (i & 7));
|
||||
|
||||
if(!subq_check_checksum(sq))
|
||||
puts("SubQ checksum error!");
|
||||
else
|
||||
{
|
||||
uint8 adr = sq[0] & 0xF;
|
||||
|
||||
if(adr <= 0x3)
|
||||
memcpy(SubQBuf[adr], sq, 0xC);
|
||||
}
|
||||
}
|
||||
static const int lobes = 2;
|
||||
static const int oversample_shift = 7; //1; //7;
|
||||
static const int oversample = 1 << oversample_shift;
|
||||
static const int oversample_mo = oversample - 1;
|
||||
|
||||
static void InitLUT(void)
|
||||
{
|
||||
sqrt_lut.resize(65536);
|
||||
sin_lut.resize(65536);
|
||||
|
||||
for(int i = 0; i < 65536; i++)
|
||||
sqrt_lut[i] = sqrt((double)i / 65536);
|
||||
|
||||
for(int i = 0; i < 65536; i++)
|
||||
sin_lut[i] = sin((double)i * M_PI * 2 / 65536);
|
||||
}
|
||||
|
||||
static void Emulate(EmulateSpecStruct *espec)
|
||||
{
|
||||
uint8 sector_buffer[2352 + 96];
|
||||
uint8 new_controller = *controller_ptr;
|
||||
|
||||
espec->MasterCycles = 588;
|
||||
|
||||
//printf("%d %d\n", toc.tracks[100].lba, AudioTrackList[AudioTrackList.size() - 1] + 1);
|
||||
|
||||
if(PlaySector > AudioTrackList[CurrentATLI].final_lba)
|
||||
{
|
||||
if((CurrentATLI + 1) < AudioTrackList.size())
|
||||
CurrentATLI++;
|
||||
else
|
||||
{
|
||||
CurrentATLI = 0;
|
||||
PlayMode = PLAYMODE_STOP;
|
||||
}
|
||||
|
||||
PlaySector = AudioTrackList[CurrentATLI].lba;
|
||||
}
|
||||
|
||||
if(PlayMode == PLAYMODE_STOP || PlayMode == PLAYMODE_PAUSE)
|
||||
{
|
||||
//memset(CDDABuffer, 0, sizeof(CDDABuffer));
|
||||
for(int i = 0; i < 588; i++)
|
||||
{
|
||||
ResampBuffer[ResampBufferPos][0] = 0;
|
||||
ResampBuffer[ResampBufferPos][1] = 0;
|
||||
ResampBufferPos++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*cdifs)[AudioTrackList[CurrentATLI].disc]->ReadRawSector(sector_buffer, PlaySector);
|
||||
GenSubQFromSubPW(sector_buffer + 2352);
|
||||
|
||||
for(int i = 0; i < 588 * 2; i++)
|
||||
{
|
||||
CDDABuffer[i] = MDFN_de16lsb(§or_buffer[i * sizeof(int16)]);
|
||||
|
||||
ResampBuffer[ResampBufferPos + (i >> 1)][i & 1] = CDDABuffer[i] / 2;
|
||||
}
|
||||
ResampBufferPos += 588;
|
||||
}
|
||||
|
||||
if(espec->SoundBuf)
|
||||
{
|
||||
if((int)espec->SoundRate == 44100)
|
||||
{
|
||||
memcpy(espec->SoundBuf, ResampBuffer, ResampBufferPos * 2 * sizeof(int16));
|
||||
espec->SoundBufSize = ResampBufferPos;
|
||||
ResampBufferPos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
spx_uint32_t in_len;
|
||||
spx_uint32_t out_len;
|
||||
|
||||
if(PrevRate != (uint32)espec->SoundRate)
|
||||
{
|
||||
speex_resampler_set_rate(resampler, 44100, (uint32)espec->SoundRate);
|
||||
PrevRate = (uint32)espec->SoundRate;
|
||||
}
|
||||
|
||||
in_len = ResampBufferPos;
|
||||
out_len = 524288; // FIXME, real size.
|
||||
|
||||
speex_resampler_process_interleaved_int(resampler, (const spx_int16_t *)ResampBuffer, &in_len, (spx_int16_t *)espec->SoundBuf, &out_len);
|
||||
|
||||
assert(in_len <= ResampBufferPos);
|
||||
|
||||
if((ResampBufferPos - in_len) > 0)
|
||||
memmove(ResampBuffer, ResampBuffer + in_len, (ResampBufferPos - in_len) * sizeof(int16) * 2);
|
||||
|
||||
ResampBufferPos -= in_len;
|
||||
|
||||
//printf("%d\n", ResampBufferPos);
|
||||
assert((ResampBufferPos + 588) <= (sizeof(ResampBuffer) / sizeof(int16) / 2));
|
||||
|
||||
espec->SoundBufSize = out_len;
|
||||
}
|
||||
}
|
||||
// for(int i = 0; i < espec->SoundBufSize * 2; i++)
|
||||
// espec->SoundBuf[i] = (rand() & 0x7FFF) - 0x4000; //(rand() * 192) >> 8
|
||||
|
||||
if(!espec->skip)
|
||||
{
|
||||
char tmpbuf[256];
|
||||
const MDFN_PixelFormat &format = espec->surface->format;
|
||||
uint32 *pixels = espec->surface->pixels;
|
||||
uint32 text_color = format.MakeColor(0xE0, 0xE0, 0xE0);
|
||||
uint32 text_shadow_color = format.MakeColor(0x20, 0x20, 0x20);
|
||||
uint32 cur_sector = PlaySector;
|
||||
|
||||
espec->DisplayRect.x = 0;
|
||||
espec->DisplayRect.y = 0;
|
||||
|
||||
espec->DisplayRect.w = 320;
|
||||
espec->DisplayRect.h = 240;
|
||||
|
||||
espec->surface->Fill(0, 0, 0, 0);
|
||||
|
||||
{
|
||||
uint32 color_table[256];
|
||||
|
||||
for(int i = 0; i < 170; i++)
|
||||
{
|
||||
int m = 255 * i / 170;
|
||||
|
||||
color_table[i] = format.MakeColor(m, 0, m);
|
||||
|
||||
//printf("%d %d %08x\n", m, i, color_table[i]);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 588; i++)
|
||||
{
|
||||
int32 unip_samp;
|
||||
int32 next_unip_samp;
|
||||
|
||||
unip_samp = ((CDDABuffer[i * 2 + 0] + CDDABuffer[i * 2 + 1]) >> 1) + 32768;
|
||||
next_unip_samp = ((CDDABuffer[(i * 2 + 2) % 1176] + CDDABuffer[(i * 2 + 3) % 1176]) >> 1) + 32768;
|
||||
|
||||
for(int osi = 0; osi < oversample; osi++)
|
||||
{
|
||||
double sample;
|
||||
int x;
|
||||
int y;
|
||||
double x_raw, y_raw;
|
||||
double x_raw2, y_raw2;
|
||||
double x_raw_prime, y_raw_prime;
|
||||
|
||||
sample = (double)(unip_samp * (oversample - osi) + next_unip_samp * osi) / (oversample * 65536);
|
||||
|
||||
int32 theta_i = (int64)65536 * (i * oversample + osi) / (oversample * 588);
|
||||
int32 theta_i_alt = (int64)65536 * (i * oversample + osi) / (oversample * 588);
|
||||
|
||||
double radius = sin_lut[(lobes * theta_i) & 0xFFFF]; // * sin_lut[(16384 + (theta_i)) & 0xFFFF];
|
||||
double radius2 = sin_lut[(lobes * (theta_i + 1)) & 0xFFFF]; // * sin_lut[(16384 + ((theta_i + 1))) & 0xFFFF];
|
||||
|
||||
x_raw = radius * sin_lut[(16384 + theta_i_alt) & 0xFFFF];
|
||||
y_raw = radius * sin_lut[theta_i_alt & 0xFFFF];
|
||||
|
||||
x_raw2 = radius2 * sin_lut[(16384 + theta_i_alt + 1) & 0xFFFF];
|
||||
y_raw2 = radius2 * sin_lut[(theta_i_alt + 1) & 0xFFFF];
|
||||
|
||||
// Approximation, of course.
|
||||
x_raw_prime = (x_raw2 - x_raw) / (1 * M_PI * 2 / 65536);
|
||||
y_raw_prime = (y_raw2 - y_raw) / (1 * M_PI * 2 / 65536);
|
||||
|
||||
// printf("%f %f\n", y_raw_prime, sin_lut[(16384 + lobes * theta_i_alt) & 0xFFFF] + sin_lut[(16384 + theta_i_alt) & 0xFFFF]);
|
||||
|
||||
if(x_raw_prime || y_raw_prime)
|
||||
{
|
||||
x_raw_prime = x_raw_prime / sqrt(x_raw_prime * x_raw_prime + y_raw_prime * y_raw_prime);
|
||||
y_raw_prime = y_raw_prime / sqrt(x_raw_prime * x_raw_prime + y_raw_prime * y_raw_prime);
|
||||
}
|
||||
|
||||
x_raw += (sample - 0.5) * y_raw_prime / 2;
|
||||
y_raw += (sample - 0.5) * -x_raw_prime / 2;
|
||||
|
||||
x = 160 + 100 * x_raw;
|
||||
y = 120 + 100 * y_raw;
|
||||
|
||||
if((x >= 0 && x < 320) && (y >= 0 && y < 240))
|
||||
pixels[x + y * espec->surface->pitch32] = format.MakeColor(255, 255, 255); //color_table[(int)(sample * 150)]; //x * x + y * y; //format.MakeColor(sample * 255, 0, sample * 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TOC toc;
|
||||
|
||||
(*cdifs)[AudioTrackList[CurrentATLI].disc]->ReadTOC(&toc);
|
||||
|
||||
trio_snprintf(tmpbuf, 256, "Disc: %d/%d", AudioTrackList[CurrentATLI].disc + 1, cdifs->size());
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
trio_snprintf(tmpbuf, 256, "Track: %d/%d", AudioTrackList[CurrentATLI].track, toc.last_track);
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
trio_snprintf(tmpbuf, 256, "Sector: %d/%d", cur_sector, toc.tracks[100].lba - 1);
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
}
|
||||
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)"SubQ", text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
//trio_snprintf(tmpbuf, 256, "Q-Mode: %01x", SubQBuf[1][0] & 0xF);
|
||||
//DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
//pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
trio_snprintf(tmpbuf, 256, "Track: %d", BCD_to_U8(SubQBuf[1][1]));
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
trio_snprintf(tmpbuf, 256, "Index: %d", BCD_to_U8(SubQBuf[1][2]));
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
|
||||
trio_snprintf(tmpbuf, 256, "Relative: %02d:%02d:%02d", BCD_to_U8(SubQBuf[1][3]), BCD_to_U8(SubQBuf[1][4]), BCD_to_U8(SubQBuf[1][5]));
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
|
||||
trio_snprintf(tmpbuf, 256, "Absolute: %02d:%02d:%02d", BCD_to_U8(SubQBuf[1][7]), BCD_to_U8(SubQBuf[1][8]), BCD_to_U8(SubQBuf[1][9]));
|
||||
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
|
||||
pixels += 22 * espec->surface->pitch32;
|
||||
}
|
||||
|
||||
if(PlayMode != PLAYMODE_STOP && PlayMode != PLAYMODE_PAUSE)
|
||||
PlaySector++;
|
||||
|
||||
if(!(last_controller & 0x1) && (new_controller & 1))
|
||||
{
|
||||
PlayMode = (PlayMode == PLAYMODE_PLAY) ? PLAYMODE_PAUSE : PLAYMODE_PLAY;
|
||||
}
|
||||
|
||||
if(!(last_controller & 0x2) && (new_controller & 2)) // Stop
|
||||
{
|
||||
PlayMode = PLAYMODE_STOP;
|
||||
PlaySector = AudioTrackList[CurrentATLI].lba;
|
||||
}
|
||||
|
||||
if(!(last_controller & 0x4) && (new_controller & 4))
|
||||
{
|
||||
if(CurrentATLI < (AudioTrackList.size() - 1))
|
||||
CurrentATLI++;
|
||||
|
||||
PlaySector = AudioTrackList[CurrentATLI].lba;
|
||||
}
|
||||
|
||||
if(!(last_controller & 0x8) && (new_controller & 8))
|
||||
{
|
||||
if(CurrentATLI)
|
||||
CurrentATLI--;
|
||||
|
||||
PlaySector = AudioTrackList[CurrentATLI].lba;
|
||||
}
|
||||
|
||||
if(!(last_controller & 0x10) && (new_controller & 0x10))
|
||||
{
|
||||
CurrentATLI = std::min<int>(CurrentATLI + 10, AudioTrackList.size() - 1);
|
||||
PlaySector = AudioTrackList[CurrentATLI].lba;
|
||||
}
|
||||
|
||||
if(!(last_controller & 0x20) && (new_controller & 0x20))
|
||||
{
|
||||
CurrentATLI = std::max<int>(CurrentATLI - 10, 0);
|
||||
PlaySector = AudioTrackList[CurrentATLI].lba;
|
||||
}
|
||||
|
||||
|
||||
last_controller = new_controller;
|
||||
}
|
||||
|
||||
static const FileExtensionSpecStruct KnownExtensions[] =
|
||||
{
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void SetInput(int port, const char *type, void *ptr)
|
||||
{
|
||||
controller_ptr = (uint8 *)ptr;
|
||||
}
|
||||
|
||||
static void DoSimpleCommand(int cmd)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case MDFNNPCMD_POWER:
|
||||
case MDFNNPCMD_RESET: break;
|
||||
}
|
||||
}
|
||||
|
||||
static MDFNSetting CDPlaySettings[] =
|
||||
{
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const InputDeviceInputInfoStruct IDII[] =
|
||||
{
|
||||
{ "play_pause", "Play/Pause", 0, IDIT_BUTTON, NULL },
|
||||
{ "stop", "Stop", 1, IDIT_BUTTON, NULL },
|
||||
{ "next_track", "Next Track", 2, IDIT_BUTTON, NULL },
|
||||
{ "previous_track", "Previous Track", 3, IDIT_BUTTON, NULL },
|
||||
|
||||
{ "next_track_10", "Next Track 10", 4, IDIT_BUTTON, NULL },
|
||||
{ "previous_track_10", "Previous Track 10", 5, IDIT_BUTTON, NULL },
|
||||
|
||||
{ "scan_forward", "Scan Forward", 6, IDIT_BUTTON, NULL },
|
||||
{ "scan_reverse", "Scan Reverse", 7, IDIT_BUTTON, NULL },
|
||||
|
||||
//{ "reverse_seek", "Reverse Seek", 1, IDIT_BUTTON, NULL },
|
||||
//{ "forward_seek", "Forward Seek", 2, IDIT_BUTTON, NULL },
|
||||
//{ "fast_reverse_seek", "Fast Reverse Seek", 3, IDIT_BUTTON, NULL },
|
||||
//{ "fast_forward_seek", "Fast Forward Seek", 4, IDIT_BUTTON, NULL },
|
||||
};
|
||||
|
||||
static InputDeviceInfoStruct InputDeviceInfo[] =
|
||||
{
|
||||
{
|
||||
"controller",
|
||||
"Controller",
|
||||
NULL,
|
||||
sizeof(IDII) / sizeof(InputDeviceInputInfoStruct),
|
||||
IDII,
|
||||
}
|
||||
};
|
||||
|
||||
static const InputPortInfoStruct PortInfo[] =
|
||||
{
|
||||
{ 0, "builtin", "Built-In", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo }
|
||||
};
|
||||
|
||||
static InputInfoStruct InputInfo =
|
||||
{
|
||||
sizeof(PortInfo) / sizeof(InputPortInfoStruct),
|
||||
PortInfo
|
||||
};
|
||||
}
|
||||
|
||||
using namespace MDFN_IEN_CDPLAY;
|
||||
|
||||
MDFNGI EmulatedCDPlay =
|
||||
{
|
||||
"cdplay",
|
||||
"Mednafen Test CD-DA Player",
|
||||
KnownExtensions,
|
||||
MODPRIO_INTERNAL_EXTRA_LOW,
|
||||
NULL, // Debug info
|
||||
&InputInfo, //
|
||||
NULL,
|
||||
NULL,
|
||||
LoadCD,
|
||||
TestMagicCD,
|
||||
CloseGame,
|
||||
NULL,
|
||||
NULL, // Layer names, null-delimited
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, //StateAction,
|
||||
Emulate,
|
||||
SetInput,
|
||||
DoSimpleCommand,
|
||||
CDPlaySettings,
|
||||
MDFN_MASTERCLOCK_FIXED(44100),
|
||||
75 * 65536 * 256,
|
||||
false, // Multires possible?
|
||||
|
||||
320, // lcm_width
|
||||
240, // lcm_height
|
||||
NULL, // Dummy
|
||||
|
||||
|
||||
320, // Nominal width
|
||||
240, // Nominal height
|
||||
512, // Framebuffer width
|
||||
256, // Framebuffer height
|
||||
|
||||
2, // Number of output sound channels
|
||||
};
|
||||
|
58
mednafen/cdrom/CDAccess.cpp
Normal file
58
mednafen/cdrom/CDAccess.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../mednafen.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "CDAccess.h"
|
||||
#include "CDAccess_Image.h"
|
||||
|
||||
#ifdef HAVE_LIBCDIO
|
||||
#include "CDAccess_Physical.h"
|
||||
#endif
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
CDAccess::CDAccess()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDAccess::~CDAccess()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDAccess *cdaccess_open(const char *path)
|
||||
{
|
||||
CDAccess *ret;
|
||||
struct stat stat_buf;
|
||||
|
||||
#ifdef HAVE_LIBCDIO
|
||||
if(path == NULL || (!stat(path, &stat_buf) && !S_ISREG(stat_buf.st_mode)))
|
||||
ret = new CDAccess_Physical(path);
|
||||
else
|
||||
#endif
|
||||
ret = new CDAccess_Image(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
26
mednafen/cdrom/CDAccess.h
Normal file
26
mednafen/cdrom/CDAccess.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __MDFN_CDROMFILE_H
|
||||
#define __MDFN_CDROMFILE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "CDUtility.h"
|
||||
|
||||
class CDAccess
|
||||
{
|
||||
public:
|
||||
|
||||
CDAccess();
|
||||
virtual ~CDAccess();
|
||||
|
||||
virtual void Read_Raw_Sector(uint8 *buf, int32 lba) = 0;
|
||||
|
||||
virtual void Read_TOC(CDUtility::TOC *toc) = 0;
|
||||
|
||||
virtual bool Is_Physical(void) = 0;
|
||||
|
||||
virtual void Eject(bool eject_status) = 0; // Eject a disc if it's physical, otherwise NOP. Returns true on success(or NOP), false on error
|
||||
};
|
||||
|
||||
CDAccess *cdaccess_open(const char *path);
|
||||
|
||||
#endif
|
959
mednafen/cdrom/CDAccess_Image.cpp
Normal file
959
mednafen/cdrom/CDAccess_Image.cpp
Normal file
@ -0,0 +1,959 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
Notes and TODO:
|
||||
|
||||
POSTGAP in CUE sheets may not be handled properly, should the directive automatically increment the index number?
|
||||
|
||||
INDEX nn where 02 <= nn <= 99 is not supported in CUE sheets.
|
||||
|
||||
TOC reading code is extremely barebones, leaving out support for more esoteric features.
|
||||
|
||||
A PREGAP statement in the first track definition in a CUE sheet may not work properly(depends on what is proper);
|
||||
it will be added onto the implicit default 00:02:00 of pregap.
|
||||
|
||||
Trying to read sectors at an LBA of less than 0 is not supported. TODO: support it(at least up to -150).
|
||||
*/
|
||||
|
||||
#define _CDROMFILE_INTERNAL
|
||||
#include "../mednafen.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <trio/trio.h>
|
||||
|
||||
#include "../general.h"
|
||||
#include "../mednafen-endian.h"
|
||||
#include "../FileWrapper.h"
|
||||
|
||||
#include "CDAccess.h"
|
||||
#include "CDAccess_Image.h"
|
||||
|
||||
#include "audioreader.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
enum
|
||||
{
|
||||
CDRF_SUBM_NONE = 0,
|
||||
CDRF_SUBM_RW = 1,
|
||||
CDRF_SUBM_RW_RAW = 2
|
||||
};
|
||||
|
||||
// Disk-image(rip) track/sector formats
|
||||
enum
|
||||
{
|
||||
DI_FORMAT_AUDIO = 0x00,
|
||||
DI_FORMAT_MODE1 = 0x01,
|
||||
DI_FORMAT_MODE1_RAW = 0x02,
|
||||
DI_FORMAT_MODE2 = 0x03,
|
||||
DI_FORMAT_MODE2_FORM1 = 0x04,
|
||||
DI_FORMAT_MODE2_FORM2 = 0x05,
|
||||
DI_FORMAT_MODE2_RAW = 0x06,
|
||||
_DI_FORMAT_COUNT
|
||||
};
|
||||
|
||||
static const int32 DI_Size_Table[7] =
|
||||
{
|
||||
2352, // Audio
|
||||
2048, // MODE1
|
||||
2352, // MODE1 RAW
|
||||
2336, // MODE2
|
||||
2048, // MODE2 Form 1
|
||||
2324, // Mode 2 Form 2
|
||||
2352
|
||||
};
|
||||
|
||||
static const char *DI_CDRDAO_Strings[7] =
|
||||
{
|
||||
"AUDIO",
|
||||
"MODE1",
|
||||
"MODE1_RAW",
|
||||
"MODE2",
|
||||
"MODE2_FORM1",
|
||||
"MODE2_FORM2",
|
||||
"MODE2_RAW"
|
||||
};
|
||||
|
||||
static const char *DI_CUE_Strings[7] =
|
||||
{
|
||||
"AUDIO",
|
||||
"MODE1/2048",
|
||||
"MODE1/2352",
|
||||
|
||||
// FIXME: These are just guesses:
|
||||
"MODE2/2336",
|
||||
"MODE2/2048",
|
||||
"MODE2/2324",
|
||||
"MODE2/2352"
|
||||
};
|
||||
|
||||
static char *UnQuotify(char *src, char *dest)
|
||||
{
|
||||
bool in_quote = 0;
|
||||
bool already_normal = 0;
|
||||
|
||||
while(*src)
|
||||
{
|
||||
if(*src == ' ' || *src == '\t')
|
||||
{
|
||||
if(!in_quote)
|
||||
{
|
||||
if(already_normal)
|
||||
break;
|
||||
else
|
||||
{
|
||||
src++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(*src == '"')
|
||||
{
|
||||
if(in_quote)
|
||||
{
|
||||
src++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
in_quote = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest = *src;
|
||||
already_normal = 1;
|
||||
dest++;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
|
||||
*dest = 0;
|
||||
return(src);
|
||||
}
|
||||
|
||||
uint32 CDAccess_Image::GetSectorCount(CDRFILE_TRACK_INFO *track)
|
||||
{
|
||||
if(track->DIFormat == DI_FORMAT_AUDIO)
|
||||
{
|
||||
if(track->AReader)
|
||||
return(((track->AReader->FrameCount() * 4) - track->FileOffset) / 2352);
|
||||
else
|
||||
{
|
||||
struct stat stat_buf;
|
||||
fstat(fileno(track->fp), &stat_buf);
|
||||
|
||||
//printf("%d %d %d\n", (int)stat_buf.st_size, (int)track->FileOffset, (int)stat_buf.st_size - (int)track->FileOffset);
|
||||
if(track->SubchannelMode)
|
||||
return((stat_buf.st_size - track->FileOffset) / (2352 + 96));
|
||||
else
|
||||
return((stat_buf.st_size - track->FileOffset) / 2352);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat stat_buf;
|
||||
|
||||
if(fstat(fileno(track->fp), &stat_buf))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw MDFN_Error(ene.Errno(), "%s", ene.StrError());
|
||||
}
|
||||
|
||||
return((stat_buf.st_size - track->FileOffset) / DI_Size_Table[track->DIFormat]);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
CDAccess_Image::~CDAccess_Image()
|
||||
{
|
||||
for(int32 track = FirstTrack; track < (FirstTrack + NumTracks); track++)
|
||||
{
|
||||
CDRFILE_TRACK_INFO *this_track = &Tracks[track];
|
||||
|
||||
if(this_track->FirstFileInstance)
|
||||
{
|
||||
if(Tracks[track].AReader)
|
||||
{
|
||||
delete Tracks[track].AReader;
|
||||
Tracks[track].AReader = NULL;
|
||||
}
|
||||
else if(this_track->fp)
|
||||
fclose(this_track->fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length)
|
||||
{
|
||||
long offset = 0; // In bytes!
|
||||
long tmp_long;
|
||||
int m, s, f;
|
||||
uint32 sector_mult;
|
||||
long sectors;
|
||||
std::string efn;
|
||||
|
||||
efn = MDFN_EvalFIP(base_dir, filename);
|
||||
|
||||
if(NULL == (track->fp = fopen(efn.c_str(), "rb")))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw MDFN_Error(ene.Errno(), _("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError());
|
||||
}
|
||||
|
||||
if(strlen(filename) >= 4 && !strcasecmp(filename + strlen(filename) - 4, ".wav"))
|
||||
{
|
||||
track->AReader = AR_Open(track->fp);
|
||||
|
||||
if(!track->AReader)
|
||||
throw MDFN_Error(0, "TODO ERROR");
|
||||
}
|
||||
|
||||
sector_mult = DI_Size_Table[track->DIFormat];
|
||||
|
||||
if(track->SubchannelMode)
|
||||
sector_mult += 96;
|
||||
|
||||
if(binoffset && trio_sscanf(binoffset, "%ld", &tmp_long) == 1)
|
||||
{
|
||||
offset += tmp_long;
|
||||
}
|
||||
|
||||
if(msfoffset && trio_sscanf(msfoffset, "%d:%d:%d", &m, &s, &f) == 3)
|
||||
{
|
||||
offset += ((m * 60 + s) * 75 + f) * sector_mult;
|
||||
}
|
||||
|
||||
track->FileOffset = offset; // Make sure this is set before calling GetSectorCount()!
|
||||
sectors = GetSectorCount(track);
|
||||
//printf("Track: %d, offset: %ld, %ld\n", tracknum, offset, sectors);
|
||||
|
||||
if(length)
|
||||
{
|
||||
tmp_long = sectors;
|
||||
|
||||
if(trio_sscanf(length, "%d:%d:%d", &m, &s, &f) == 3)
|
||||
tmp_long = (m * 60 + s) * 75 + f;
|
||||
else if(track->DIFormat == DI_FORMAT_AUDIO)
|
||||
{
|
||||
char *endptr = NULL;
|
||||
|
||||
tmp_long = strtol(length, &endptr, 10);
|
||||
|
||||
// Error?
|
||||
if(endptr == length)
|
||||
{
|
||||
tmp_long = sectors;
|
||||
}
|
||||
else
|
||||
tmp_long /= 588;
|
||||
|
||||
}
|
||||
|
||||
if(tmp_long > sectors)
|
||||
{
|
||||
throw MDFN_Error(0, _("Length specified in TOC file for track %d is too large by %ld sectors!\n"), tracknum, (long)(tmp_long - sectors));
|
||||
}
|
||||
sectors = tmp_long;
|
||||
}
|
||||
|
||||
track->FirstFileInstance = 1;
|
||||
track->sectors = sectors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CDAccess_Image::ImageOpen(const char *path)
|
||||
{
|
||||
FileWrapper fp(path, FileWrapper::MODE_READ);
|
||||
bool IsTOC = FALSE;
|
||||
char linebuf[512];
|
||||
int32 active_track = -1;
|
||||
int32 AutoTrackInc = 1; // For TOC
|
||||
CDRFILE_TRACK_INFO TmpTrack;
|
||||
std::string file_base, file_ext;
|
||||
|
||||
memset(&TmpTrack, 0, sizeof(TmpTrack));
|
||||
|
||||
MDFN_GetFilePathComponents(path, &base_dir, &file_base, &file_ext);
|
||||
|
||||
if(!strcasecmp(file_ext.c_str(), ".toc"))
|
||||
{
|
||||
puts("TOC file detected.");
|
||||
IsTOC = true;
|
||||
}
|
||||
// Assign opposite maximum values so our tests will work!
|
||||
FirstTrack = 99;
|
||||
LastTrack = 0;
|
||||
|
||||
while(fp.get_line(linebuf, 512) != NULL)
|
||||
{
|
||||
char cmdbuf[512], raw_args[512], args[4][512];
|
||||
int argcount = 0;
|
||||
|
||||
raw_args[0] = 0;
|
||||
cmdbuf[0] = 0;
|
||||
|
||||
args[0][0] = args[1][0] = args[2][0] = args[3][0] = 0;
|
||||
|
||||
MDFN_trim(linebuf);
|
||||
|
||||
if(IsTOC)
|
||||
{
|
||||
// Handle TOC format comments
|
||||
char *ss_loc = strstr(linebuf, "//");
|
||||
if(ss_loc)
|
||||
{
|
||||
ss_loc[0] = '\n';
|
||||
ss_loc[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(trio_sscanf(linebuf, "%s %[^\r\n]", cmdbuf, raw_args) < 1)
|
||||
continue; // Skip blank lines
|
||||
|
||||
UnQuotify(UnQuotify(UnQuotify(UnQuotify(raw_args, args[0]), args[1]), args[2]), args[3]);
|
||||
if(args[0][0])
|
||||
{
|
||||
argcount++;
|
||||
if(args[1][0])
|
||||
{
|
||||
argcount++;
|
||||
if(args[2][0])
|
||||
{
|
||||
argcount++;
|
||||
if(args[3][0])
|
||||
{
|
||||
argcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(IsTOC)
|
||||
{
|
||||
if(!strcasecmp(cmdbuf, "TRACK"))
|
||||
{
|
||||
if(active_track >= 0)
|
||||
{
|
||||
memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
|
||||
memset(&TmpTrack, 0, sizeof(TmpTrack));
|
||||
active_track = -1;
|
||||
}
|
||||
|
||||
if(AutoTrackInc > 99)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid track number: %d"), AutoTrackInc));
|
||||
}
|
||||
|
||||
active_track = AutoTrackInc++;
|
||||
if(active_track < FirstTrack)
|
||||
FirstTrack = active_track;
|
||||
if(active_track > LastTrack)
|
||||
LastTrack = active_track;
|
||||
|
||||
int format_lookup;
|
||||
for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
|
||||
{
|
||||
if(!strcasecmp(args[0], DI_CDRDAO_Strings[format_lookup]))
|
||||
{
|
||||
TmpTrack.DIFormat = format_lookup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(format_lookup == _DI_FORMAT_COUNT)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid track format: %s"), args[0]));
|
||||
}
|
||||
|
||||
if(TmpTrack.DIFormat == DI_FORMAT_AUDIO)
|
||||
TmpTrack.RawAudioMSBFirst = TRUE; // Silly cdrdao...
|
||||
|
||||
if(!strcasecmp(args[1], "RW"))
|
||||
{
|
||||
TmpTrack.SubchannelMode = CDRF_SUBM_RW;
|
||||
throw(MDFN_Error(0, _("\"RW\" format subchannel data not supported, only \"RW_RAW\" is!")));
|
||||
}
|
||||
else if(!strcasecmp(args[1], "RW_RAW"))
|
||||
TmpTrack.SubchannelMode = CDRF_SUBM_RW_RAW;
|
||||
|
||||
} // end to TRACK
|
||||
else if(!strcasecmp(cmdbuf, "SILENCE"))
|
||||
{
|
||||
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "ZERO"))
|
||||
{
|
||||
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "FILE") || !strcasecmp(cmdbuf, "AUDIOFILE"))
|
||||
{
|
||||
const char *binoffset = NULL;
|
||||
const char *msfoffset = NULL;
|
||||
const char *length = NULL;
|
||||
|
||||
if(args[1][0] == '#')
|
||||
{
|
||||
binoffset = args[1] + 1;
|
||||
msfoffset = args[2];
|
||||
length = args[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
msfoffset = args[1];
|
||||
length = args[2];
|
||||
}
|
||||
//printf("%s, %s, %s, %s\n", args[0], binoffset, msfoffset, length);
|
||||
ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, msfoffset, length);
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "DATAFILE"))
|
||||
{
|
||||
const char *binoffset = NULL;
|
||||
const char *length = NULL;
|
||||
|
||||
if(args[1][0] == '#')
|
||||
{
|
||||
binoffset = args[1] + 1;
|
||||
length = args[2];
|
||||
}
|
||||
else
|
||||
length = args[1];
|
||||
|
||||
ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, NULL, length);
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "INDEX"))
|
||||
{
|
||||
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "PREGAP"))
|
||||
{
|
||||
if(active_track < 0)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Command %s is outside of a TRACK definition!\n"), cmdbuf));
|
||||
}
|
||||
int m,s,f;
|
||||
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
|
||||
TmpTrack.pregap = (m * 60 + s) * 75 + f;
|
||||
} // end to PREGAP
|
||||
else if(!strcasecmp(cmdbuf, "START"))
|
||||
{
|
||||
if(active_track < 0)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Command %s is outside of a TRACK definition!\n"), cmdbuf));
|
||||
}
|
||||
int m,s,f;
|
||||
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
|
||||
TmpTrack.pregap = (m * 60 + s) * 75 + f;
|
||||
}
|
||||
} /*********** END TOC HANDLING ************/
|
||||
else // now for CUE sheet handling
|
||||
{
|
||||
if(!strcasecmp(cmdbuf, "FILE"))
|
||||
{
|
||||
if(active_track >= 0)
|
||||
{
|
||||
memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
|
||||
memset(&TmpTrack, 0, sizeof(TmpTrack));
|
||||
active_track = -1;
|
||||
}
|
||||
|
||||
if(!MDFN_IsFIROPSafe(args[0]))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting.\n"), args[0]));
|
||||
}
|
||||
|
||||
std::string efn = MDFN_EvalFIP(base_dir, args[0]);
|
||||
|
||||
if(NULL == (TmpTrack.fp = fopen(efn.c_str(), "rb")))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError()));
|
||||
}
|
||||
TmpTrack.FirstFileInstance = 1;
|
||||
if(!strcasecmp(args[1], "BINARY"))
|
||||
{
|
||||
//TmpTrack.Format = TRACK_FORMAT_DATA;
|
||||
//struct stat stat_buf;
|
||||
//fstat(fileno(TmpTrack.fp), &stat_buf);
|
||||
//TmpTrack.sectors = stat_buf.st_size; // / 2048;
|
||||
}
|
||||
else if(!strcasecmp(args[1], "OGG") || !strcasecmp(args[1], "VORBIS") || !strcasecmp(args[1], "WAVE") || !strcasecmp(args[1], "WAV") || !strcasecmp(args[1], "PCM")
|
||||
|| !strcasecmp(args[1], "MPC") || !strcasecmp(args[1], "MP+"))
|
||||
{
|
||||
TmpTrack.AReader = AR_Open(TmpTrack.fp);
|
||||
if(!TmpTrack.AReader)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Unsupported audio track file format: %s\n"), args[0]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(MDFN_Error(0, _("Unsupported track format: %s\n"), args[1]));
|
||||
}
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "TRACK"))
|
||||
{
|
||||
if(active_track >= 0)
|
||||
{
|
||||
memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
|
||||
TmpTrack.FirstFileInstance = 0;
|
||||
TmpTrack.pregap = 0;
|
||||
TmpTrack.pregap_dv = 0;
|
||||
TmpTrack.postgap = 0;
|
||||
TmpTrack.index[0] = -1;
|
||||
TmpTrack.index[1] = 0;
|
||||
}
|
||||
active_track = atoi(args[0]);
|
||||
|
||||
if(active_track < FirstTrack)
|
||||
FirstTrack = active_track;
|
||||
if(active_track > LastTrack)
|
||||
LastTrack = active_track;
|
||||
|
||||
int format_lookup;
|
||||
for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
|
||||
{
|
||||
if(!strcasecmp(args[1], DI_CUE_Strings[format_lookup]))
|
||||
{
|
||||
TmpTrack.DIFormat = format_lookup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(format_lookup == _DI_FORMAT_COUNT)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid track format: %s\n"), args[0]));
|
||||
}
|
||||
|
||||
if(active_track < 0 || active_track > 99)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid track number: %d\n"), active_track));
|
||||
}
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "INDEX"))
|
||||
{
|
||||
if(active_track >= 0)
|
||||
{
|
||||
int m,s,f;
|
||||
trio_sscanf(args[1], "%d:%d:%d", &m, &s, &f);
|
||||
|
||||
if(!strcasecmp(args[0], "01") || !strcasecmp(args[0], "1"))
|
||||
TmpTrack.index[1] = (m * 60 + s) * 75 + f;
|
||||
else if(!strcasecmp(args[0], "00") || !strcasecmp(args[0], "0"))
|
||||
TmpTrack.index[0] = (m * 60 + s) * 75 + f;
|
||||
}
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "PREGAP"))
|
||||
{
|
||||
if(active_track >= 0)
|
||||
{
|
||||
int m,s,f;
|
||||
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
|
||||
TmpTrack.pregap = (m * 60 + s) * 75 + f;
|
||||
}
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "POSTGAP"))
|
||||
{
|
||||
if(active_track >= 0)
|
||||
{
|
||||
int m,s,f;
|
||||
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
|
||||
TmpTrack.postgap = (m * 60 + s) * 75 + f;
|
||||
}
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "REM"))
|
||||
{
|
||||
|
||||
}
|
||||
else if(!strcasecmp(cmdbuf, "CDTEXTFILE") || !strcasecmp(cmdbuf, "FLAGS") || !strcasecmp(cmdbuf, "CATALOG") || !strcasecmp(cmdbuf, "ISRC") ||
|
||||
!strcasecmp(cmdbuf, "TITLE") || !strcasecmp(cmdbuf, "PERFORMER") || !strcasecmp(cmdbuf, "SONGWRITER"))
|
||||
{
|
||||
MDFN_printf(_("Unsupported CUE sheet directive: \"%s\".\n"), cmdbuf); // FIXME, generic logger passed by pointer to constructor
|
||||
}
|
||||
else
|
||||
{
|
||||
throw MDFN_Error(0, _("Unknown CUE sheet directive \"%s\".\n"), cmdbuf);
|
||||
}
|
||||
} // end of CUE sheet handling
|
||||
} // end of fgets() loop
|
||||
|
||||
if(active_track >= 0)
|
||||
memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
|
||||
|
||||
if(FirstTrack > LastTrack)
|
||||
{
|
||||
throw(MDFN_Error(0, _("No tracks found!\n")));
|
||||
}
|
||||
|
||||
FirstTrack = FirstTrack;
|
||||
NumTracks = 1 + LastTrack - FirstTrack;
|
||||
|
||||
int32 RunningLBA = 0;
|
||||
int32 LastIndex = 0;
|
||||
long FileOffset = 0;
|
||||
|
||||
for(int x = FirstTrack; x < (FirstTrack + NumTracks); x++)
|
||||
{
|
||||
if(Tracks[x].DIFormat == DI_FORMAT_AUDIO)
|
||||
Tracks[x].Format = CD_TRACK_FORMAT_AUDIO;
|
||||
else
|
||||
Tracks[x].Format = CD_TRACK_FORMAT_DATA;
|
||||
|
||||
if(IsTOC)
|
||||
{
|
||||
RunningLBA += Tracks[x].pregap;
|
||||
Tracks[x].LBA = RunningLBA;
|
||||
RunningLBA += Tracks[x].sectors;
|
||||
RunningLBA += Tracks[x].postgap;
|
||||
}
|
||||
else // else handle CUE sheet...
|
||||
{
|
||||
if(Tracks[x].FirstFileInstance)
|
||||
{
|
||||
LastIndex = 0;
|
||||
FileOffset = 0;
|
||||
}
|
||||
|
||||
RunningLBA += Tracks[x].pregap;
|
||||
|
||||
Tracks[x].pregap_dv = 0;
|
||||
|
||||
if(Tracks[x].index[0] != -1)
|
||||
Tracks[x].pregap_dv = Tracks[x].index[1] - Tracks[x].index[0];
|
||||
|
||||
FileOffset += Tracks[x].pregap_dv * DI_Size_Table[Tracks[x].DIFormat];
|
||||
|
||||
RunningLBA += Tracks[x].pregap_dv;
|
||||
|
||||
Tracks[x].LBA = RunningLBA;
|
||||
|
||||
// Make sure FileOffset this is set before the call to GetSectorCount()
|
||||
Tracks[x].FileOffset = FileOffset;
|
||||
Tracks[x].sectors = GetSectorCount(&Tracks[x]);
|
||||
|
||||
if((x + 1) >= (FirstTrack + NumTracks) || Tracks[x+1].FirstFileInstance)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix the sector count if we have multiple tracks per one binary image file.
|
||||
if(Tracks[x + 1].index[0] == -1)
|
||||
Tracks[x].sectors = Tracks[x + 1].index[1] - Tracks[x].index[1];
|
||||
else
|
||||
Tracks[x].sectors = Tracks[x + 1].index[0] - Tracks[x].index[1]; //Tracks[x + 1].index - Tracks[x].index;
|
||||
}
|
||||
|
||||
//printf("Poo: %d %d\n", x, Tracks[x].sectors);
|
||||
RunningLBA += Tracks[x].sectors;
|
||||
RunningLBA += Tracks[x].postgap;
|
||||
|
||||
//printf("%d, %ld %d %d %d %d\n", x, FileOffset, Tracks[x].index, Tracks[x].pregap, Tracks[x].sectors, Tracks[x].LBA);
|
||||
|
||||
FileOffset += Tracks[x].sectors * DI_Size_Table[Tracks[x].DIFormat];
|
||||
} // end to cue sheet handling
|
||||
} // end to track loop
|
||||
|
||||
total_sectors = RunningLBA;
|
||||
}
|
||||
|
||||
CDAccess_Image::CDAccess_Image(const char *path)
|
||||
{
|
||||
ImageOpen(path);
|
||||
}
|
||||
|
||||
void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
|
||||
{
|
||||
bool TrackFound = FALSE;
|
||||
uint8 SimuQ[0xC];
|
||||
|
||||
memset(buf + 2352, 0, 96);
|
||||
|
||||
MakeSubPQ(lba, buf + 2352);
|
||||
|
||||
subq_deinterleave(buf + 2352, SimuQ);
|
||||
|
||||
for(int32 track = FirstTrack; track < (FirstTrack + NumTracks); track++)
|
||||
{
|
||||
CDRFILE_TRACK_INFO *ct = &Tracks[track];
|
||||
|
||||
if(lba >= (ct->LBA - ct->pregap_dv - ct->pregap) && lba < (ct->LBA + ct->sectors + ct->postgap))
|
||||
{
|
||||
TrackFound = TRUE;
|
||||
|
||||
// Handle pregap and postgap reading
|
||||
if(lba < (ct->LBA - ct->pregap_dv) || lba >= (ct->LBA + ct->sectors))
|
||||
{
|
||||
//printf("Pre/post-gap read, LBA=%d(LBA-track_start_LBA=%d)\n", lba, lba - ct->LBA);
|
||||
memset(buf, 0, 2352); // Null sector data, per spec
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ct->AReader)
|
||||
{
|
||||
int16 AudioBuf[588 * 2];
|
||||
int frames_read = ct->AReader->Read((ct->FileOffset / 4) + (lba - ct->LBA) * 588, AudioBuf, 588);
|
||||
|
||||
ct->LastSamplePos += frames_read;
|
||||
|
||||
if(frames_read < 0 || frames_read > 588) // This shouldn't happen.
|
||||
{
|
||||
printf("Error: frames_read out of range: %d\n", frames_read);
|
||||
frames_read = 0;
|
||||
}
|
||||
|
||||
if(frames_read < 588)
|
||||
memset((uint8 *)AudioBuf + frames_read * 2 * sizeof(int16), 0, (588 - frames_read) * 2 * sizeof(int16));
|
||||
|
||||
for(int i = 0; i < 588 * 2; i++)
|
||||
MDFN_en16lsb(buf + i * 2, AudioBuf[i]);
|
||||
}
|
||||
else // Binary, woo.
|
||||
{
|
||||
long SeekPos = ct->FileOffset;
|
||||
long LBARelPos = lba - ct->LBA;
|
||||
|
||||
SeekPos += LBARelPos * DI_Size_Table[ct->DIFormat];
|
||||
|
||||
if(ct->SubchannelMode)
|
||||
SeekPos += 96 * (lba - ct->LBA);
|
||||
|
||||
fseek(ct->fp, SeekPos, SEEK_SET);
|
||||
|
||||
switch(ct->DIFormat)
|
||||
{
|
||||
case DI_FORMAT_AUDIO:
|
||||
fread(buf, 1, 2352, ct->fp);
|
||||
|
||||
if(ct->RawAudioMSBFirst)
|
||||
Endian_A16_Swap(buf, 588 * 2);
|
||||
break;
|
||||
|
||||
case DI_FORMAT_MODE1:
|
||||
fread(buf + 12 + 3 + 1, 1, 2048, ct->fp);
|
||||
encode_mode1_sector(lba + 150, buf);
|
||||
break;
|
||||
|
||||
case DI_FORMAT_MODE1_RAW:
|
||||
case DI_FORMAT_MODE2_RAW:
|
||||
fread(buf, 1, 2352, ct->fp);
|
||||
break;
|
||||
|
||||
case DI_FORMAT_MODE2:
|
||||
fread(buf + 16, 1, 2336, ct->fp);
|
||||
encode_mode2_sector(lba + 150, buf);
|
||||
break;
|
||||
|
||||
|
||||
// FIXME: M2F1, M2F2, does sub-header come before or after user data(standards say before, but I wonder
|
||||
// about cdrdao...).
|
||||
case DI_FORMAT_MODE2_FORM1:
|
||||
fread(buf + 24, 1, 2048, ct->fp);
|
||||
//encode_mode2_form1_sector(lba + 150, buf);
|
||||
break;
|
||||
|
||||
case DI_FORMAT_MODE2_FORM2:
|
||||
fread(buf + 24, 1, 2324, ct->fp);
|
||||
//encode_mode2_form2_sector(lba + 150, buf);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if(ct->SubchannelMode)
|
||||
fread(buf + 2352, 1, 96, ct->fp);
|
||||
}
|
||||
} // end if audible part of audio track read.
|
||||
break;
|
||||
} // End if LBA is in range
|
||||
} // end track search loop
|
||||
|
||||
if(!TrackFound)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Could not find track for sector %u!"), lba));
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(qbuf[0] & 0x40)
|
||||
{
|
||||
uint8 dummy_buf[2352 + 96];
|
||||
bool any_mismatch = FALSE;
|
||||
|
||||
memcpy(dummy_buf + 16, buf + 16, 2048);
|
||||
memset(dummy_buf + 2352, 0, 96);
|
||||
|
||||
MakeSubPQ(lba, dummy_buf + 2352);
|
||||
encode_mode1_sector(lba + 150, dummy_buf);
|
||||
|
||||
for(int i = 0; i < 2352 + 96; i++)
|
||||
{
|
||||
if(dummy_buf[i] != buf[i])
|
||||
{
|
||||
printf("Mismatch at %d, %d: %02x:%02x; ", lba, i, dummy_buf[i], buf[i]);
|
||||
any_mismatch = TRUE;
|
||||
}
|
||||
}
|
||||
if(any_mismatch)
|
||||
puts("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
//subq_deinterleave(buf + 2352, qbuf);
|
||||
//printf("%02x\n", qbuf[0]);
|
||||
//printf("%02x\n", buf[12 + 3]);
|
||||
}
|
||||
|
||||
void CDAccess_Image::MakeSubPQ(int32 lba, uint8 *SubPWBuf)
|
||||
{
|
||||
uint8 buf[0xC];
|
||||
int32 track;
|
||||
uint32 lba_relative;
|
||||
uint32 ma, sa, fa;
|
||||
uint32 m, s, f;
|
||||
uint8 pause_or = 0x00;
|
||||
bool track_found = FALSE;
|
||||
|
||||
for(track = FirstTrack; track < (FirstTrack + NumTracks); track++)
|
||||
{
|
||||
if(lba >= (Tracks[track].LBA - Tracks[track].pregap_dv - Tracks[track].pregap) && lba < (Tracks[track].LBA + Tracks[track].sectors + Tracks[track].postgap))
|
||||
{
|
||||
track_found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%d %d\n", Tracks[1].LBA, Tracks[1].sectors);
|
||||
|
||||
if(!track_found)
|
||||
{
|
||||
printf("MakeSubPQ error for sector %u!", lba);
|
||||
track = FirstTrack;
|
||||
}
|
||||
|
||||
lba_relative = abs((int32)lba - Tracks[track].LBA);
|
||||
|
||||
f = (lba_relative % 75);
|
||||
s = ((lba_relative / 75) % 60);
|
||||
m = (lba_relative / 75 / 60);
|
||||
|
||||
fa = (lba + 150) % 75;
|
||||
sa = ((lba + 150) / 75) % 60;
|
||||
ma = ((lba + 150) / 75 / 60);
|
||||
|
||||
uint8 adr = 0x1; // Q channel data encodes position
|
||||
uint8 control = (Tracks[track].Format == CD_TRACK_FORMAT_AUDIO) ? 0x00 : 0x04;
|
||||
|
||||
// Handle pause(D7 of interleaved subchannel byte) bit, should be set to 1 when in pregap or postgap.
|
||||
if((lba < Tracks[track].LBA) || (lba >= Tracks[track].LBA + Tracks[track].sectors))
|
||||
{
|
||||
//printf("pause_or = 0x80 --- %d\n", lba);
|
||||
pause_or = 0x80;
|
||||
}
|
||||
|
||||
// Handle pregap between audio->data track
|
||||
{
|
||||
int32 pg_offset = (int32)lba - Tracks[track].LBA;
|
||||
|
||||
// If we're more than 2 seconds(150 sectors) from the real "start" of the track/INDEX 01, and the track is a data track,
|
||||
// and the preceding track is an audio track, encode it as audio.
|
||||
if(pg_offset < -150)
|
||||
{
|
||||
if(Tracks[track].Format == CD_TRACK_FORMAT_DATA && (FirstTrack < track) &&
|
||||
Tracks[track - 1].Format == CD_TRACK_FORMAT_AUDIO)
|
||||
{
|
||||
//printf("Pregap part 1 audio->data: lba=%d track_lba=%d\n", lba, Tracks[track].LBA);
|
||||
control = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
memset(buf, 0, 0xC);
|
||||
buf[0] = (adr << 0) | (control << 4);
|
||||
buf[1] = U8_to_BCD(track);
|
||||
|
||||
if(lba < Tracks[track].LBA) // Index is 00 in pregap
|
||||
buf[2] = U8_to_BCD(0x00);
|
||||
else
|
||||
buf[2] = U8_to_BCD(0x01);
|
||||
|
||||
// Track relative MSF address
|
||||
buf[3] = U8_to_BCD(m);
|
||||
buf[4] = U8_to_BCD(s);
|
||||
buf[5] = U8_to_BCD(f);
|
||||
|
||||
buf[6] = 0; // Zerroooo
|
||||
|
||||
// Absolute MSF address
|
||||
buf[7] = U8_to_BCD(ma);
|
||||
buf[8] = U8_to_BCD(sa);
|
||||
buf[9] = U8_to_BCD(fa);
|
||||
|
||||
subq_generate_checksum(buf);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
SubPWBuf[i] |= (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | pause_or;
|
||||
}
|
||||
|
||||
void CDAccess_Image::Read_TOC(TOC *toc)
|
||||
{
|
||||
toc->Clear();
|
||||
|
||||
toc->first_track = FirstTrack;
|
||||
toc->last_track = FirstTrack + NumTracks - 1;
|
||||
toc->disc_type = DISC_TYPE_CDDA_OR_M1; // FIXME
|
||||
|
||||
for(int i = toc->first_track; i <= toc->last_track; i++)
|
||||
{
|
||||
toc->tracks[i].lba = Tracks[i].LBA;
|
||||
toc->tracks[i].adr = ADR_CURPOS;
|
||||
toc->tracks[i].control = 0x0;
|
||||
|
||||
if(Tracks[i].Format != CD_TRACK_FORMAT_AUDIO)
|
||||
toc->tracks[i].control |= 0x4;
|
||||
}
|
||||
|
||||
toc->tracks[100].lba = total_sectors;
|
||||
toc->tracks[100].adr = ADR_CURPOS;
|
||||
toc->tracks[100].control = 0x00; // Audio...
|
||||
|
||||
// Convenience leadout track duplication.
|
||||
if(toc->last_track < 99)
|
||||
toc->tracks[toc->last_track + 1] = toc->tracks[100];
|
||||
}
|
||||
|
||||
bool CDAccess_Image::Is_Physical(void)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
void CDAccess_Image::Eject(bool eject_status)
|
||||
{
|
||||
|
||||
}
|
||||
|
93
mednafen/cdrom/CDAccess_Image.h
Normal file
93
mednafen/cdrom/CDAccess_Image.h
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef __MDFN_CDACCESS_IMAGE_H
|
||||
#define __MDFN_CDACCESS_IMAGE_H
|
||||
|
||||
class AudioReader;
|
||||
|
||||
struct CDRFILE_TRACK_INFO
|
||||
{
|
||||
int32 LBA;
|
||||
|
||||
CDUtility::CD_Track_Format_t Format;
|
||||
uint32 DIFormat;
|
||||
|
||||
int32 pregap;
|
||||
int32 pregap_dv;
|
||||
|
||||
int32 postgap;
|
||||
|
||||
int32 index[2];
|
||||
|
||||
int32 sectors; // Not including pregap sectors!
|
||||
FILE *fp;
|
||||
bool FirstFileInstance;
|
||||
bool RawAudioMSBFirst;
|
||||
long FileOffset;
|
||||
unsigned int SubchannelMode;
|
||||
|
||||
uint32 LastSamplePos;
|
||||
|
||||
AudioReader *AReader;
|
||||
};
|
||||
#if 0
|
||||
struct Medium_Chunk
|
||||
{
|
||||
int64 Offset; // Offset in [..TODO..]
|
||||
uint32 DIFormat;
|
||||
|
||||
FILE *fp;
|
||||
bool FirstFileInstance;
|
||||
bool RawAudioMSBFirst;
|
||||
unsigned int SubchannelMode;
|
||||
|
||||
uint32 LastSamplePos;
|
||||
AudioReader *AReader;
|
||||
};
|
||||
|
||||
struct CD_Chunk
|
||||
{
|
||||
int32 LBA;
|
||||
int32 Track;
|
||||
int32 Index;
|
||||
bool DataType;
|
||||
|
||||
Medium_Chunk Medium;
|
||||
};
|
||||
|
||||
static std::vector<CD_Chunk> Chunks;
|
||||
#endif
|
||||
|
||||
class CDAccess_Image : public CDAccess
|
||||
{
|
||||
public:
|
||||
|
||||
CDAccess_Image(const char *path);
|
||||
virtual ~CDAccess_Image();
|
||||
|
||||
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
|
||||
|
||||
virtual void Read_TOC(CDUtility::TOC *toc);
|
||||
|
||||
virtual bool Is_Physical(void);
|
||||
|
||||
virtual void Eject(bool eject_status);
|
||||
private:
|
||||
|
||||
int32 NumTracks;
|
||||
int32 FirstTrack;
|
||||
int32 LastTrack;
|
||||
int32 total_sectors;
|
||||
CDRFILE_TRACK_INFO Tracks[100]; // Track #0(HMM?) through 99
|
||||
|
||||
std::string base_dir;
|
||||
|
||||
void ImageOpen(const char *path);
|
||||
|
||||
// MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf.
|
||||
void MakeSubPQ(int32 lba, uint8 *SubPWBuf);
|
||||
|
||||
void ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length);
|
||||
uint32 GetSectorCount(CDRFILE_TRACK_INFO *track);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
358
mednafen/cdrom/CDAccess_Physical.cpp
Normal file
358
mednafen/cdrom/CDAccess_Physical.cpp
Normal file
@ -0,0 +1,358 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define EXTERNAL_LIBCDIO_CONFIG_H 1
|
||||
|
||||
#include "../mednafen.h"
|
||||
#include "../general.h"
|
||||
|
||||
#include "CDAccess.h"
|
||||
#include "CDAccess_Physical.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/mmc.h>
|
||||
|
||||
#if LIBCDIO_VERSION_NUM >= 83
|
||||
#include <cdio/mmc_cmds.h>
|
||||
#endif
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
void CDAccess_Physical::DetermineFeatures(void)
|
||||
{
|
||||
uint8 buf[256];
|
||||
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
|
||||
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE_10);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
cdb.field[2] = 0x2A;
|
||||
|
||||
cdb.field[7] = sizeof(buf) >> 8;
|
||||
cdb.field[8] = sizeof(buf) & 0xFF;
|
||||
|
||||
if(mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
sizeof(buf),
|
||||
buf))
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC [MODE SENSE 10] command failed.")));
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8 *pd = &buf[8];
|
||||
|
||||
if(pd[0] != 0x2A || pd[1] < 0x14)
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC [MODE SENSE 10] command returned bogus data for mode page 0x2A.")));
|
||||
}
|
||||
|
||||
if(!(pd[4] & 0x10))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Drive does not support reading Mode 2 Form 1 sectors.")));
|
||||
}
|
||||
|
||||
if(!(pd[4] & 0x20))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Drive does not support reading Mode 2 Form 2 sectors.")));
|
||||
}
|
||||
|
||||
if(!(pd[5] & 0x01))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Reading CD-DA sectors via \"READ CD\" is not supported.")));
|
||||
}
|
||||
|
||||
if(!(pd[5] & 0x02))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Read CD-DA sectors via \"READ CD\" are not positionally-accurate.")));
|
||||
}
|
||||
|
||||
if(!(pd[5] & 0x04))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Reading raw subchannel data via \"READ CD\" is not supported.")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDAccess_Physical::PreventAllowMediumRemoval(bool prevent)
|
||||
{
|
||||
#if 0
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
uint8 buf[8];
|
||||
|
||||
cdb.field[0] = 0x1E;
|
||||
cdb.field[1] = 0x00;
|
||||
cdb.field[2] = 0x00;
|
||||
cdb.field[3] = 0x00;
|
||||
cdb.field[4] = 0x00; //prevent;
|
||||
cdb.field[5] = 0x00;
|
||||
|
||||
printf("%d\n", mmc_run_cmd_len (p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb, 6,
|
||||
SCSI_MMC_DATA_READ, 0, buf));
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CDAccess_Physical::ReadPhysDiscInfo(unsigned retry)
|
||||
{
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
uint8 toc_buffer[8192];
|
||||
int64 start_time = time(NULL);
|
||||
int cdio_rc;
|
||||
|
||||
cdb.field[0] = 0x43; // Read TOC
|
||||
cdb.field[1] = 0x00;
|
||||
cdb.field[2] = 0x00; // Format 0000b
|
||||
cdb.field[3] = 0x00;
|
||||
cdb.field[4] = 0x00;
|
||||
cdb.field[5] = 0x00;
|
||||
cdb.field[6] = 0x01; // Track number
|
||||
cdb.field[7] = sizeof(toc_buffer) >> 8;
|
||||
cdb.field[8] = sizeof(toc_buffer) & 0xFF;
|
||||
cdb.field[9] = 0x00;
|
||||
|
||||
memset(toc_buffer, 0, sizeof(toc_buffer));
|
||||
|
||||
while((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
sizeof(toc_buffer),
|
||||
toc_buffer)))
|
||||
{
|
||||
if(!retry || time(NULL) >= (start_time + retry))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Error reading disc TOC.")));
|
||||
}
|
||||
}
|
||||
|
||||
PhysTOC.Clear();
|
||||
|
||||
PhysTOC.first_track = toc_buffer[2];
|
||||
PhysTOC.last_track = toc_buffer[3];
|
||||
|
||||
if(PhysTOC.first_track < 1 || PhysTOC.first_track > 99)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid first track: %d\n"), PhysTOC.first_track));
|
||||
}
|
||||
|
||||
if(PhysTOC.last_track > 99 || PhysTOC.last_track < PhysTOC.first_track)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid last track: %d\n"), PhysTOC.last_track));
|
||||
}
|
||||
|
||||
int32 len_counter = MDFN_de16msb(&toc_buffer[0]) - 2;
|
||||
uint8 *tbi = &toc_buffer[4];
|
||||
|
||||
assert(len_counter >= 0);
|
||||
assert((len_counter & 7) == 0);
|
||||
|
||||
while(len_counter)
|
||||
{
|
||||
uint8 adr = tbi[1] >> 4;
|
||||
uint8 control = tbi[1] & 0xF;
|
||||
uint8 tnum = tbi[2];
|
||||
uint32 lba = MDFN_de32msb(&tbi[4]);
|
||||
|
||||
if(tnum == 0xAA)
|
||||
{
|
||||
PhysTOC.tracks[100].adr = adr;
|
||||
PhysTOC.tracks[100].control = control;
|
||||
PhysTOC.tracks[100].lba = lba;
|
||||
}
|
||||
else if(tnum >= PhysTOC.first_track && tnum <= PhysTOC.last_track)
|
||||
{
|
||||
PhysTOC.tracks[tnum].adr = adr;
|
||||
PhysTOC.tracks[tnum].control = control;
|
||||
PhysTOC.tracks[tnum].lba = lba;
|
||||
}
|
||||
|
||||
tbi += 8;
|
||||
len_counter -= 8;
|
||||
}
|
||||
|
||||
// Convenience leadout track duplication.
|
||||
if(PhysTOC.last_track < 99)
|
||||
PhysTOC.tracks[PhysTOC.last_track + 1] = PhysTOC.tracks[100];
|
||||
}
|
||||
|
||||
void CDAccess_Physical::Read_TOC(TOC *toc)
|
||||
{
|
||||
*toc = PhysTOC;
|
||||
}
|
||||
|
||||
void CDAccess_Physical::Read_Raw_Sector(uint8 *buf, int32 lba)
|
||||
{
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
int cdio_rc;
|
||||
|
||||
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
|
||||
CDIO_MMC_SET_READ_TYPE (cdb.field, CDIO_MMC_READ_TYPE_ANY);
|
||||
CDIO_MMC_SET_READ_LBA (cdb.field, lba);
|
||||
CDIO_MMC_SET_READ_LENGTH24(cdb.field, 1);
|
||||
|
||||
if(SkipSectorRead[(lba >> 3) & 0xFFFF] & (1 << (lba & 7)))
|
||||
{
|
||||
printf("Read(skipped): %d\n", lba);
|
||||
memset(buf, 0, 2352);
|
||||
|
||||
cdb.field[9] = 0x00;
|
||||
cdb.field[10] = 0x01;
|
||||
|
||||
if((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
96,
|
||||
buf + 2352)))
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC Read Error; libcdio return code %d"), cdio_rc));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cdb.field[9] = 0xF8;
|
||||
cdb.field[10] = 0x01;
|
||||
|
||||
if((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
2352 + 96,
|
||||
buf)))
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC Read Error; libcdio return code %d"), cdio_rc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CDAccess_Physical::CDAccess_Physical(const char *path)
|
||||
{
|
||||
char **devices = NULL;
|
||||
char **parseit = NULL;
|
||||
|
||||
p_cdio = NULL;
|
||||
|
||||
cdio_init();
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
try
|
||||
{
|
||||
devices = cdio_get_devices(DRIVER_DEVICE);
|
||||
parseit = devices;
|
||||
if(parseit)
|
||||
{
|
||||
MDFN_printf(_("Connected physical devices:\n"));
|
||||
MDFN_indent(1);
|
||||
while(*parseit)
|
||||
{
|
||||
MDFN_printf("%s\n", *parseit);
|
||||
parseit++;
|
||||
}
|
||||
MDFN_indent(-1);
|
||||
}
|
||||
|
||||
if(!parseit || parseit == devices)
|
||||
{
|
||||
throw(MDFN_Error(0, _("No CDROM drives detected(or no disc present).")));
|
||||
}
|
||||
|
||||
if(devices)
|
||||
{
|
||||
cdio_free_device_list(devices);
|
||||
devices = NULL;
|
||||
}
|
||||
|
||||
p_cdio = cdio_open_cd(path); //, DRIVER_UNKNOWN); //NULL, DRIVER_UNKNOWN);
|
||||
if(!p_cdio)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Unknown error opening physical CD")));
|
||||
}
|
||||
|
||||
//PreventAllowMediumRemoval(true);
|
||||
ReadPhysDiscInfo(0);
|
||||
|
||||
//
|
||||
// Determine how we can read this CD.
|
||||
//
|
||||
DetermineFeatures();
|
||||
|
||||
memset(SkipSectorRead, 0, sizeof(SkipSectorRead));
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
if(devices)
|
||||
cdio_free_device_list(devices);
|
||||
|
||||
if(p_cdio)
|
||||
cdio_destroy((CdIo *)p_cdio);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
CDAccess_Physical::~CDAccess_Physical()
|
||||
{
|
||||
cdio_destroy((CdIo *)p_cdio);
|
||||
}
|
||||
|
||||
bool CDAccess_Physical::Is_Physical(void)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
void CDAccess_Physical::Eject(bool eject_status)
|
||||
{
|
||||
int cdio_rc;
|
||||
|
||||
#if LIBCDIO_VERSION_NUM >= 83
|
||||
if((cdio_rc = mmc_start_stop_unit((CdIo *)p_cdio, eject_status, false, 0, 0)) != 0)
|
||||
{
|
||||
if(cdio_rc != DRIVER_OP_UNSUPPORTED) // Don't error out if it's just an unsupported operation.
|
||||
throw(MDFN_Error(0, _("Error ejecting medium;; libcdio return code %d"), cdio_rc));
|
||||
}
|
||||
#else
|
||||
if((cdio_rc = mmc_start_stop_media((CdIo *)p_cdio, eject_status, false, 0)) != 0)
|
||||
{
|
||||
if(cdio_rc != DRIVER_OP_UNSUPPORTED) // Don't error out if it's just an unsupported operation.
|
||||
throw(MDFN_Error(0, _("Error ejecting medium;; libcdio return code %d"), cdio_rc));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!eject_status)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReadPhysDiscInfo(10);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
#if LIBCDIO_VERSION_NUM >= 83
|
||||
mmc_start_stop_unit((CdIo *)p_cdio, true, false, 0, 0); // Eject disc, if possible.
|
||||
#else
|
||||
mmc_start_stop_media((CdIo *)p_cdio, true, false, 0); // Eject disc, if possible.
|
||||
#endif
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
mednafen/cdrom/CDAccess_Physical.h
Normal file
36
mednafen/cdrom/CDAccess_Physical.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef __MDFN_CDACCESS_PHYSICAL_H
|
||||
#define __MDFN_CDACCESS_PHYSICAL_H
|
||||
|
||||
// Don't include <cdio.h> here, else it will pollute with its #define's.
|
||||
|
||||
class CDAccess_Physical : public CDAccess
|
||||
{
|
||||
public:
|
||||
|
||||
CDAccess_Physical(const char *path);
|
||||
virtual ~CDAccess_Physical();
|
||||
|
||||
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
|
||||
|
||||
virtual void Read_TOC(CDUtility::TOC *toc);
|
||||
|
||||
virtual bool Is_Physical(void);
|
||||
|
||||
virtual void Eject(bool eject_status);
|
||||
private:
|
||||
|
||||
void *p_cdio;
|
||||
|
||||
void DetermineFeatures(void);
|
||||
void PhysOpen(const char *path);
|
||||
void ReadPhysDiscInfo(unsigned retry);
|
||||
|
||||
void PreventAllowMediumRemoval(bool prevent);
|
||||
|
||||
CDUtility::TOC PhysTOC;
|
||||
|
||||
// TODO: 1-bit per sector on the physical CD. If set, don't read that sector.
|
||||
uint8 SkipSectorRead[65536];
|
||||
};
|
||||
|
||||
#endif
|
176
mednafen/cdrom/CDUtility.cpp
Normal file
176
mednafen/cdrom/CDUtility.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../mednafen.h"
|
||||
#include "CDUtility.h"
|
||||
#include "dvdisaster.h"
|
||||
#include "lec.h"
|
||||
|
||||
// Kill_LEC_Correct();
|
||||
|
||||
|
||||
namespace CDUtility
|
||||
{
|
||||
|
||||
// lookup table for crc calculation
|
||||
static uint16 subq_crctab[256] =
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
|
||||
|
||||
static bool CDUtility_Inited = false;
|
||||
|
||||
void CDUtility_Init(void)
|
||||
{
|
||||
if(!CDUtility_Inited)
|
||||
{
|
||||
Init_LEC_Correct();
|
||||
|
||||
CDUtility_Inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_mode0_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode0_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode1_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode1_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_form1_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_form2_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
bool edc_check(const uint8 *sector_data, bool xa)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
return(CheckEDC(sector_data, xa));
|
||||
}
|
||||
|
||||
bool edc_lec_check_correct(uint8 *sector_data, bool xa)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
return(ValidateRawSector(sector_data, xa));
|
||||
}
|
||||
|
||||
|
||||
bool subq_check_checksum(const uint8 *SubQBuf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
uint16 stored_crc = 0;
|
||||
|
||||
stored_crc = SubQBuf[0xA] << 8;
|
||||
stored_crc |= SubQBuf[0xB];
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
|
||||
|
||||
crc = ~crc;
|
||||
|
||||
return(crc == stored_crc);
|
||||
}
|
||||
|
||||
void subq_generate_checksum(uint8 *buf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
|
||||
|
||||
// Checksum
|
||||
buf[0xa] = ~(crc >> 8);
|
||||
buf[0xb] = ~(crc);
|
||||
}
|
||||
|
||||
void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
|
||||
{
|
||||
memset(qbuf, 0, 0xC);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
{
|
||||
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
|
||||
{
|
||||
assert(subq_check_checksum(subq_input));
|
||||
|
||||
|
||||
subq_generate_checksum(subq_output);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
210
mednafen/cdrom/CDUtility.h
Normal file
210
mednafen/cdrom/CDUtility.h
Normal file
@ -0,0 +1,210 @@
|
||||
#ifndef __MDFN_CDROM_CDUTILITY_H
|
||||
#define __MDFN_CDROM_CDUTILITY_H
|
||||
|
||||
namespace CDUtility
|
||||
{
|
||||
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
|
||||
// It will also be called automatically if needed for the first time a function in this namespace that requires
|
||||
// the initialization function to be called is called, for potential
|
||||
// usage in constructors of statically-declared objects.
|
||||
void CDUtility_Init(void);
|
||||
|
||||
// Quick definitions here:
|
||||
//
|
||||
// ABA - Absolute block address, synonymous to absolute MSF
|
||||
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a
|
||||
//
|
||||
// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
|
||||
// lba = aba - 150
|
||||
|
||||
|
||||
// Track formats(more abstract and simple)
|
||||
typedef enum
|
||||
{
|
||||
CD_TRACK_FORMAT_AUDIO = 0x00,
|
||||
CD_TRACK_FORMAT_DATA = 0x01,
|
||||
//CDRF_FORMAT_CDI = 0x02
|
||||
} CD_Track_Format_t;
|
||||
|
||||
enum
|
||||
{
|
||||
ADR_NOQINFO = 0x00,
|
||||
ADR_CURPOS = 0x01,
|
||||
ADR_MCN = 0x02,
|
||||
ADR_ISRC = 0x03
|
||||
};
|
||||
|
||||
|
||||
struct TOC_Track
|
||||
{
|
||||
uint8 adr;
|
||||
uint8 control;
|
||||
uint32 lba;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DISC_TYPE_CDDA_OR_M1 = 0x00,
|
||||
DISC_TYPE_CD_I = 0x10,
|
||||
DISC_TYPE_CD_XA = 0x20
|
||||
};
|
||||
|
||||
struct TOC
|
||||
{
|
||||
INLINE TOC()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
INLINE void Clear(void)
|
||||
{
|
||||
first_track = last_track = 0;
|
||||
disc_type = 0;
|
||||
|
||||
memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
|
||||
}
|
||||
|
||||
INLINE int FindTrackByLBA(uint32 LBA)
|
||||
{
|
||||
for(int32 track = first_track; track <= (last_track + 1); track++)
|
||||
{
|
||||
if(track == (last_track + 1))
|
||||
{
|
||||
if(LBA < tracks[100].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(LBA < tracks[track].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint8 first_track;
|
||||
uint8 last_track;
|
||||
uint8 disc_type;
|
||||
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
|
||||
// Also, for convenience, tracks[last_track + 1] will always refer
|
||||
// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).
|
||||
};
|
||||
|
||||
//
|
||||
// Address conversion functions.
|
||||
//
|
||||
static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
|
||||
{
|
||||
return(f_a + 75 * s_a + 75 * 60 * m_a);
|
||||
}
|
||||
|
||||
static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
*m_a = aba / 75 / 60;
|
||||
*s_a = (aba - *m_a * 75 * 60) / 75;
|
||||
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
|
||||
}
|
||||
|
||||
static INLINE int32 ABA_to_LBA(uint32 aba)
|
||||
{
|
||||
return(aba - 150);
|
||||
}
|
||||
|
||||
static INLINE uint32 LBA_to_ABA(int32 lba)
|
||||
{
|
||||
return(lba + 150);
|
||||
}
|
||||
|
||||
static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
|
||||
{
|
||||
return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
|
||||
}
|
||||
|
||||
static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
|
||||
}
|
||||
|
||||
//
|
||||
// BCD conversion functions
|
||||
//
|
||||
static INLINE bool BCD_is_valid(uint8 bcd_number)
|
||||
{
|
||||
if((bcd_number & 0xF0) >= 0xA0)
|
||||
return(false);
|
||||
|
||||
if((bcd_number & 0x0F) >= 0x0A)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
static INLINE uint8 BCD_to_U8(uint8 bcd_number)
|
||||
{
|
||||
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
|
||||
}
|
||||
|
||||
static INLINE uint8 U8_to_BCD(uint8 num)
|
||||
{
|
||||
return( ((num / 10) << 4) + (num % 10) );
|
||||
}
|
||||
|
||||
// should always perform the conversion, even if the bcd number is invalid.
|
||||
static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number)
|
||||
{
|
||||
*out_number = BCD_to_U8(bcd_number);
|
||||
|
||||
if(!BCD_is_valid(bcd_number))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
//
|
||||
// Sector data encoding functions(to full 2352 bytes raw sector).
|
||||
//
|
||||
// sector_data must be able to contain at least 2352 bytes.
|
||||
void encode_mode0_sector(uint32 aba, uint8 *sector_data);
|
||||
void encode_mode1_sector(uint32 aba, uint8 *sector_data); // 2048 bytes of user data at offset 16
|
||||
void encode_mode2_sector(uint32 aba, uint8 *sector_data); // 2336 bytes of user data at offset 16
|
||||
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data); // 2048+8 bytes of user data at offset 16
|
||||
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16
|
||||
|
||||
//
|
||||
// User data error detection and correction
|
||||
//
|
||||
|
||||
// Check EDC of a mode 1 or mode 2 form 1 sector.
|
||||
// Returns "true" if checksum is ok(matches).
|
||||
// Returns "false" if checksum mismatch.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_check(const uint8 *sector_data, bool xa);
|
||||
|
||||
// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
|
||||
// Returns "true" if errors weren't detected, or they were corrected succesfully.
|
||||
// Returns "false" if errors couldn't be corrected.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_lec_check_correct(uint8 *sector_data, bool xa);
|
||||
|
||||
//
|
||||
// Subchannel(Q in particular) functions
|
||||
//
|
||||
|
||||
// Returns false on checksum mismatch, true on match.
|
||||
bool subq_check_checksum(const uint8 *subq_buf);
|
||||
|
||||
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
|
||||
// in subq_buf.
|
||||
void subq_generate_checksum(uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
|
||||
void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);
|
||||
|
||||
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
|
||||
// Only valid for ADR_CURPOS.
|
||||
// subq_input must pass subq_check_checksum().
|
||||
// TODO
|
||||
//void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output);
|
||||
}
|
||||
|
||||
#endif
|
7
mednafen/cdrom/Makefile.am.inc
Normal file
7
mednafen/cdrom/Makefile.am.inc
Normal file
@ -0,0 +1,7 @@
|
||||
mednafen_SOURCES += cdrom/audioreader.cpp cdrom/cdromif.cpp cdrom/scsicd.cpp cdrom/pcecd.cpp
|
||||
mednafen_SOURCES += cdrom/CDUtility.cpp cdrom/crc32.cpp cdrom/galois.cpp cdrom/l-ec.cpp cdrom/recover-raw.cpp
|
||||
mednafen_SOURCES += cdrom/lec.cpp cdrom/CDAccess.cpp cdrom/CDAccess_Image.cpp
|
||||
|
||||
if HAVE_LIBCDIO
|
||||
mednafen_SOURCES += cdrom/CDAccess_Physical.cpp
|
||||
endif
|
6
mednafen/cdrom/SimpleFIFO.cpp
Normal file
6
mednafen/cdrom/SimpleFIFO.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "../mednafen.h"
|
||||
#include "SimpleFIFO.h"
|
||||
|
||||
|
||||
|
||||
|
107
mednafen/cdrom/SimpleFIFO.h
Normal file
107
mednafen/cdrom/SimpleFIFO.h
Normal file
@ -0,0 +1,107 @@
|
||||
#ifndef __MDFN_SIMPLEFIFO_H
|
||||
#define __MDFN_SIMPLEFIFO_H
|
||||
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../math_ops.h"
|
||||
|
||||
template<typename T>
|
||||
class SimpleFIFO
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
SimpleFIFO(uint32 the_size) // Size should be a power of 2!
|
||||
{
|
||||
data.resize(round_up_pow2(the_size));
|
||||
size = the_size;
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
INLINE ~SimpleFIFO()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
INLINE uint32 CanRead(void)
|
||||
{
|
||||
return(in_count);
|
||||
}
|
||||
|
||||
INLINE uint32 CanWrite(void)
|
||||
{
|
||||
return(size - in_count);
|
||||
}
|
||||
|
||||
INLINE T ReadUnit(bool peek = false)
|
||||
{
|
||||
T ret;
|
||||
|
||||
assert(in_count > 0);
|
||||
|
||||
ret = data[read_pos];
|
||||
|
||||
if(!peek)
|
||||
{
|
||||
read_pos = (read_pos + 1) & (data.size() - 1);
|
||||
in_count--;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
INLINE uint8 ReadByte(bool peek = false)
|
||||
{
|
||||
assert(sizeof(T) == 1);
|
||||
|
||||
return(ReadUnit(peek));
|
||||
}
|
||||
|
||||
INLINE void Write(const T *happy_data, uint32 happy_count)
|
||||
{
|
||||
assert(CanWrite() >= happy_count);
|
||||
|
||||
while(happy_count)
|
||||
{
|
||||
data[write_pos] = *happy_data;
|
||||
|
||||
write_pos = (write_pos + 1) & (data.size() - 1);
|
||||
in_count++;
|
||||
happy_data++;
|
||||
happy_count--;
|
||||
}
|
||||
}
|
||||
|
||||
INLINE void WriteUnit(const T& wr_data)
|
||||
{
|
||||
Write(&wr_data, 1);
|
||||
}
|
||||
|
||||
INLINE void WriteByte(const T& wr_data)
|
||||
{
|
||||
assert(sizeof(T) == 1);
|
||||
Write(&wr_data, 1);
|
||||
}
|
||||
|
||||
|
||||
INLINE void Flush(void)
|
||||
{
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
//private:
|
||||
std::vector<T> data;
|
||||
uint32 size;
|
||||
uint32 read_pos; // Read position
|
||||
uint32 write_pos; // Write position
|
||||
uint32 in_count; // Number of units in the FIFO
|
||||
};
|
||||
|
||||
|
||||
#endif
|
338
mednafen/cdrom/audioreader.cpp
Normal file
338
mednafen/cdrom/audioreader.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../mednafen.h"
|
||||
#include "audioreader.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../tremor/ivorbisfile.h"
|
||||
#include "../mpcdec/mpcdec.h"
|
||||
|
||||
#ifdef HAVE_LIBSNDFILE
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <trio/trio.h>
|
||||
|
||||
#include "../general.h"
|
||||
#include "../mednafen-endian.h"
|
||||
|
||||
AudioReader::AudioReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AudioReader::~AudioReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int64 AudioReader::Read_(int16 *buffer, int64 frames)
|
||||
{
|
||||
abort();
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool AudioReader::Seek_(int64 frame_offset)
|
||||
{
|
||||
abort();
|
||||
return(false);
|
||||
}
|
||||
|
||||
int64 AudioReader::FrameCount(void)
|
||||
{
|
||||
abort();
|
||||
return(0);
|
||||
}
|
||||
|
||||
class OggVorbisReader : public AudioReader
|
||||
{
|
||||
public:
|
||||
OggVorbisReader(FILE *fp)
|
||||
{
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
lseek(fileno(fp), 0, SEEK_SET);
|
||||
|
||||
if(ov_open(fp, &ovfile, NULL, 0))
|
||||
throw(0);
|
||||
}
|
||||
|
||||
~OggVorbisReader()
|
||||
{
|
||||
ov_clear(&ovfile);
|
||||
}
|
||||
|
||||
int64 Read_(int16 *buffer, int64 frames)
|
||||
{
|
||||
uint8 *tw_buf = (uint8 *)buffer;
|
||||
int cursection = 0;
|
||||
long toread = frames * sizeof(int16) * 2;
|
||||
|
||||
while(toread > 0)
|
||||
{
|
||||
long didread = ov_read(&ovfile, (char*)tw_buf, toread, &cursection);
|
||||
|
||||
if(didread == 0)
|
||||
break;
|
||||
|
||||
tw_buf = (uint8 *)tw_buf + didread;
|
||||
toread -= didread;
|
||||
}
|
||||
|
||||
return(frames - toread / sizeof(int16) / 2);
|
||||
}
|
||||
|
||||
bool Seek_(int64 frame_offset)
|
||||
{
|
||||
ov_pcm_seek(&ovfile, frame_offset);
|
||||
return(true);
|
||||
}
|
||||
|
||||
int64 FrameCount(void)
|
||||
{
|
||||
return(ov_pcm_total(&ovfile, -1));
|
||||
}
|
||||
|
||||
private:
|
||||
OggVorbis_File ovfile;
|
||||
};
|
||||
|
||||
class MPCReader : public AudioReader
|
||||
{
|
||||
public:
|
||||
MPCReader(FILE *fp)
|
||||
{
|
||||
mpc_status err;
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
demux = NULL;
|
||||
memset(&reader, 0, sizeof(reader));
|
||||
memset(&si, 0, sizeof(si));
|
||||
memset(MPCBuffer, 0, sizeof(MPCBuffer));
|
||||
MPCBufferOffs = 0;
|
||||
MPCBufferIn = 0;
|
||||
|
||||
if((err = mpc_reader_init_stdio_stream(&reader, fp)) < 0)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Error initializing MusePack decoder!\n")));
|
||||
}
|
||||
|
||||
if(!(demux = mpc_demux_init(&reader)))
|
||||
{
|
||||
throw(0);
|
||||
}
|
||||
mpc_demux_get_info(demux, &si);
|
||||
|
||||
if(si.channels != 2)
|
||||
{
|
||||
mpc_demux_exit(demux);
|
||||
demux = NULL;
|
||||
throw MDFN_Error(0, _("MusePack stream has wrong number of channels(%d); the correct number is 2."), si.channels);
|
||||
}
|
||||
|
||||
if(si.sample_freq != 44100)
|
||||
{
|
||||
mpc_demux_exit(demux);
|
||||
demux = NULL;
|
||||
throw MDFN_Error(0, _("MusePack stream has wrong samplerate(%d Hz); the current samplerate is 44100 Hz."), si.sample_freq);
|
||||
}
|
||||
}
|
||||
|
||||
~MPCReader()
|
||||
{
|
||||
if(demux)
|
||||
{
|
||||
mpc_demux_exit(demux);
|
||||
demux = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int64 Read_(int16 *buffer, int64 frames)
|
||||
{
|
||||
mpc_status err;
|
||||
int16 *cowbuf = (int16 *)buffer;
|
||||
int32 toread = frames * 2;
|
||||
|
||||
while(toread > 0)
|
||||
{
|
||||
int32 tmplen;
|
||||
|
||||
if(!MPCBufferIn)
|
||||
{
|
||||
mpc_frame_info fi;
|
||||
memset(&fi, 0, sizeof(fi));
|
||||
|
||||
fi.buffer = MPCBuffer;
|
||||
if((err = mpc_demux_decode(demux, &fi)) < 0 || fi.bits == -1)
|
||||
return(frames - toread / 2);
|
||||
|
||||
MPCBufferIn = fi.samples * 2;
|
||||
MPCBufferOffs = 0;
|
||||
}
|
||||
|
||||
tmplen = MPCBufferIn;
|
||||
|
||||
if(tmplen >= toread)
|
||||
tmplen = toread;
|
||||
|
||||
for(int x = 0; x < tmplen; x++)
|
||||
{
|
||||
#ifdef MPC_FIXED_POINT
|
||||
int32 samp = MPCBuffer[MPCBufferOffs + x] >> MPC_FIXED_POINT_FRACTPART;
|
||||
#else
|
||||
#warning Floating-point MPC decoding path not tested.
|
||||
int32 samp = (int32)(MPCBuffer[MPCBufferOffs + x] * 32767);
|
||||
#endif
|
||||
if(samp < -32768)
|
||||
samp = -32768;
|
||||
|
||||
if(samp > 32767)
|
||||
samp = 32767;
|
||||
|
||||
*cowbuf = (int16)samp;
|
||||
cowbuf++;
|
||||
}
|
||||
|
||||
MPCBufferOffs += tmplen;
|
||||
toread -= tmplen;
|
||||
MPCBufferIn -= tmplen;
|
||||
}
|
||||
|
||||
return(frames - toread / 2);
|
||||
}
|
||||
|
||||
bool Seek_(int64 frame_offset)
|
||||
{
|
||||
MPCBufferOffs = 0;
|
||||
MPCBufferIn = 0;
|
||||
|
||||
if(mpc_demux_seek_sample(demux, frame_offset) < 0)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
int64 FrameCount(void)
|
||||
{
|
||||
return(mpc_streaminfo_get_length_samples(&si));
|
||||
}
|
||||
|
||||
private:
|
||||
mpc_reader reader;
|
||||
mpc_demux *demux;
|
||||
mpc_streaminfo si;
|
||||
|
||||
MPC_SAMPLE_FORMAT MPCBuffer[MPC_DECODER_BUFFER_LENGTH];
|
||||
|
||||
uint32 MPCBufferIn;
|
||||
uint32 MPCBufferOffs;
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBSNDFILE
|
||||
class SFReader : public AudioReader
|
||||
{
|
||||
public:
|
||||
|
||||
SFReader(FILE *fp)
|
||||
{
|
||||
memset(&sfinfo, 0, sizeof(sfinfo));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
lseek(fileno(fp), 0, SEEK_SET);
|
||||
sf = sf_open_fd(fileno(fp), SFM_READ, &sfinfo, 0);
|
||||
if(!sf)
|
||||
throw(0);
|
||||
}
|
||||
|
||||
~SFReader()
|
||||
{
|
||||
sf_close(sf);
|
||||
}
|
||||
|
||||
int64 Read_(int16 *buffer, int64 frames)
|
||||
{
|
||||
return(sf_read_short(sf, (short*)buffer, frames * 2) / 2);
|
||||
}
|
||||
|
||||
bool Seek_(int64 frame_offset)
|
||||
{
|
||||
// FIXME error condition
|
||||
if(sf_seek(sf, frame_offset, SEEK_SET) != frame_offset)
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
|
||||
int64 FrameCount(void)
|
||||
{
|
||||
return(sfinfo.frames);
|
||||
}
|
||||
|
||||
private:
|
||||
SNDFILE *sf;
|
||||
SF_INFO sfinfo;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
AudioReader *AR_Open(FILE *fp)
|
||||
{
|
||||
AudioReader *AReader = NULL;
|
||||
|
||||
if(!AReader)
|
||||
{
|
||||
try
|
||||
{
|
||||
AReader = new MPCReader(fp);
|
||||
}
|
||||
catch(int i)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if(!AReader)
|
||||
{
|
||||
try
|
||||
{
|
||||
AReader = new OggVorbisReader(fp);
|
||||
}
|
||||
catch(int i)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_LIBSNDFILE
|
||||
if(!AReader)
|
||||
{
|
||||
try
|
||||
{
|
||||
AReader = new SFReader(fp);
|
||||
}
|
||||
catch(int i)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return(AReader);
|
||||
}
|
||||
|
71
mednafen/cdrom/audioreader.h
Normal file
71
mednafen/cdrom/audioreader.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef __MDFN_AUDIOREADER_H
|
||||
#define __MDFN_AUDIOREADER_H
|
||||
|
||||
class MDFN_Object
|
||||
{
|
||||
public:
|
||||
INLINE MDFN_Object()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
INLINE ~MDFN_Object()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void *operator new(size_t bcount)
|
||||
{
|
||||
void *ret = calloc(1, bcount);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Error allocating %llu bytes of memory."), (unsigned long long)bcount));
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static void operator delete(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
class AudioReader : public MDFN_Object
|
||||
{
|
||||
public:
|
||||
AudioReader();
|
||||
virtual ~AudioReader();
|
||||
|
||||
virtual int64 Read_(int16 *buffer, int64 frames);
|
||||
virtual bool Seek_(int64 frame_offset);
|
||||
|
||||
virtual int64 FrameCount(void);
|
||||
INLINE int64 Read(int64 frame_offset, int16 *buffer, int64 frames)
|
||||
{
|
||||
int64 ret;
|
||||
|
||||
//if(frame_offset >= 0)
|
||||
{
|
||||
if(LastReadPos != frame_offset)
|
||||
{
|
||||
//puts("SEEK");
|
||||
if(!Seek_(frame_offset))
|
||||
return(0);
|
||||
LastReadPos = frame_offset;
|
||||
}
|
||||
}
|
||||
ret = Read_(buffer, frames);
|
||||
LastReadPos += ret;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
private:
|
||||
int64 LastReadPos;
|
||||
};
|
||||
|
||||
|
||||
AudioReader *AR_Open(FILE *fp);
|
||||
|
||||
#endif
|
470
mednafen/cdrom/cdromif.cpp
Normal file
470
mednafen/cdrom/cdromif.cpp
Normal file
@ -0,0 +1,470 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../mednafen.h"
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <trio/trio.h>
|
||||
#include "cdromif.h"
|
||||
#include "CDAccess.h"
|
||||
#include "../general.h"
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
CDIF_Message::CDIF_Message()
|
||||
{
|
||||
message = 0;
|
||||
|
||||
memset(args, 0, sizeof(args));
|
||||
}
|
||||
|
||||
CDIF_Message::CDIF_Message(unsigned int message_, uint32 arg0, uint32 arg1, uint32 arg2, uint32 arg3)
|
||||
{
|
||||
message = message_;
|
||||
args[0] = arg0;
|
||||
args[1] = arg1;
|
||||
args[2] = arg2;
|
||||
args[3] = arg3;
|
||||
}
|
||||
|
||||
CDIF_Message::CDIF_Message(unsigned int message_, const std::string &str)
|
||||
{
|
||||
message = message_;
|
||||
str_message = str;
|
||||
}
|
||||
|
||||
CDIF_Message::~CDIF_Message()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDIF_Queue::CDIF_Queue()
|
||||
{
|
||||
ze_mutex = MDFND_CreateMutex();
|
||||
}
|
||||
|
||||
CDIF_Queue::~CDIF_Queue()
|
||||
{
|
||||
MDFND_DestroyMutex(ze_mutex);
|
||||
}
|
||||
|
||||
// Returns FALSE if message not read, TRUE if it was read. Will always return TRUE if "blocking" is set.
|
||||
// Will throw MDFN_Error if the read message code is CDIF_MSG_FATAL_ERROR
|
||||
bool CDIF_Queue::Read(CDIF_Message *message, bool blocking)
|
||||
{
|
||||
TryAgain:
|
||||
|
||||
MDFND_LockMutex(ze_mutex);
|
||||
|
||||
if(ze_queue.size() > 0)
|
||||
{
|
||||
*message = ze_queue.front();
|
||||
ze_queue.pop();
|
||||
MDFND_UnlockMutex(ze_mutex);
|
||||
|
||||
if(message->message == CDIF_MSG_FATAL_ERROR)
|
||||
throw MDFN_Error(0, "%s", message->str_message.c_str());
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
else if(blocking)
|
||||
{
|
||||
MDFND_UnlockMutex(ze_mutex);
|
||||
MDFND_Sleep(1);
|
||||
goto TryAgain;
|
||||
}
|
||||
else
|
||||
{
|
||||
MDFND_UnlockMutex(ze_mutex);
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void CDIF_Queue::Write(const CDIF_Message &message)
|
||||
{
|
||||
MDFND_LockMutex(ze_mutex);
|
||||
|
||||
ze_queue.push(message);
|
||||
|
||||
MDFND_UnlockMutex(ze_mutex);
|
||||
}
|
||||
|
||||
|
||||
void CDIF::RT_EjectDisc(bool eject_status, bool skip_actual_eject)
|
||||
{
|
||||
int32 old_de = DiscEjected;
|
||||
|
||||
DiscEjected = eject_status;
|
||||
|
||||
if(old_de != DiscEjected)
|
||||
{
|
||||
if(!skip_actual_eject)
|
||||
disc_cdaccess->Eject(eject_status);
|
||||
|
||||
if(!eject_status) // Re-read the TOC
|
||||
{
|
||||
disc_cdaccess->Read_TOC(&disc_toc);
|
||||
|
||||
if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
|
||||
{
|
||||
throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
|
||||
}
|
||||
}
|
||||
|
||||
SBWritePos = 0;
|
||||
ra_lba = 0;
|
||||
ra_count = 0;
|
||||
last_read_lba = ~0U;
|
||||
memset(SectorBuffers, 0, SBSize * sizeof(CDIF_Sector_Buffer));
|
||||
}
|
||||
}
|
||||
|
||||
struct RTS_Args
|
||||
{
|
||||
CDIF *cdif_ptr;
|
||||
const char *device_name;
|
||||
};
|
||||
|
||||
static int ReadThreadStart_C(void *v_arg)
|
||||
{
|
||||
RTS_Args *args = (RTS_Args *)v_arg;
|
||||
|
||||
if(args->device_name)
|
||||
{
|
||||
char device_name[strlen(args->device_name) + 1];
|
||||
|
||||
strcpy(device_name, args->device_name);
|
||||
|
||||
return args->cdif_ptr->ReadThreadStart(device_name);
|
||||
}
|
||||
else
|
||||
return args->cdif_ptr->ReadThreadStart(NULL);
|
||||
}
|
||||
|
||||
int CDIF::ReadThreadStart(const char *device_name)
|
||||
{
|
||||
bool Running = TRUE;
|
||||
|
||||
DiscEjected = true;
|
||||
SBWritePos = 0;
|
||||
ra_lba = 0;
|
||||
ra_count = 0;
|
||||
last_read_lba = ~0U;
|
||||
|
||||
try
|
||||
{
|
||||
disc_cdaccess = cdaccess_open(device_name ? device_name : NULL);
|
||||
RT_EjectDisc(false, true);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what())));
|
||||
return(0);
|
||||
}
|
||||
|
||||
is_phys_cache = disc_cdaccess->Is_Physical();
|
||||
|
||||
EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE));
|
||||
|
||||
while(Running)
|
||||
{
|
||||
CDIF_Message msg;
|
||||
|
||||
// Only do a blocking-wait for a message if we don't have any sectors to read-ahead.
|
||||
// MDFN_DispMessage("%d %d %d\n", last_read_lba, ra_lba, ra_count);
|
||||
if(ReadThreadQueue.Read(&msg, ra_count ? FALSE : TRUE))
|
||||
{
|
||||
switch(msg.message)
|
||||
{
|
||||
case CDIF_MSG_DIEDIEDIE:
|
||||
Running = FALSE;
|
||||
break;
|
||||
|
||||
case CDIF_MSG_EJECT:
|
||||
try
|
||||
{
|
||||
RT_EjectDisc(msg.args[0]);
|
||||
EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE));
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what())));
|
||||
}
|
||||
break;
|
||||
|
||||
case CDIF_MSG_READ_SECTOR:
|
||||
{
|
||||
static const int max_ra = 16;
|
||||
static const int initial_ra = 1;
|
||||
static const int speedmult_ra = 2;
|
||||
uint32 new_lba = msg.args[0];
|
||||
|
||||
assert((unsigned int)max_ra < (SBSize / 4));
|
||||
|
||||
if(last_read_lba != ~0U && new_lba == (last_read_lba + 1))
|
||||
{
|
||||
int how_far_ahead = ra_lba - new_lba;
|
||||
|
||||
if(how_far_ahead <= max_ra)
|
||||
ra_count = std::min(speedmult_ra, 1 + max_ra - how_far_ahead);
|
||||
else
|
||||
ra_count++;
|
||||
}
|
||||
else if(new_lba != last_read_lba)
|
||||
{
|
||||
ra_lba = new_lba;
|
||||
ra_count = initial_ra;
|
||||
}
|
||||
|
||||
last_read_lba = new_lba;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't read >= the "end" of the disc, silly snake. Slither.
|
||||
if(ra_count && ra_lba == disc_toc.tracks[100].lba)
|
||||
{
|
||||
ra_count = 0;
|
||||
//printf("Ephemeral scarabs: %d!\n", ra_lba);
|
||||
}
|
||||
|
||||
if(ra_count)
|
||||
{
|
||||
uint8 tmpbuf[2352 + 96];
|
||||
bool error_condition = false;
|
||||
|
||||
try
|
||||
{
|
||||
disc_cdaccess->Read_Raw_Sector(tmpbuf, ra_lba);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
MDFN_PrintError(_("Sector %u read error: %s"), ra_lba, e.what());
|
||||
memset(tmpbuf, 0, sizeof(tmpbuf));
|
||||
error_condition = true;
|
||||
}
|
||||
|
||||
MDFND_LockMutex(SBMutex);
|
||||
|
||||
SectorBuffers[SBWritePos].lba = ra_lba;
|
||||
memcpy(SectorBuffers[SBWritePos].data, tmpbuf, 2352 + 96);
|
||||
SectorBuffers[SBWritePos].valid = TRUE;
|
||||
SectorBuffers[SBWritePos].error = error_condition;
|
||||
SBWritePos = (SBWritePos + 1) % SBSize;
|
||||
|
||||
MDFND_UnlockMutex(SBMutex);
|
||||
|
||||
ra_lba++;
|
||||
ra_count--;
|
||||
}
|
||||
}
|
||||
|
||||
if(disc_cdaccess)
|
||||
{
|
||||
delete disc_cdaccess;
|
||||
disc_cdaccess = NULL;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
CDIF::CDIF(const char *device_name)
|
||||
{
|
||||
CDIF_Message msg;
|
||||
RTS_Args s;
|
||||
|
||||
SBMutex = MDFND_CreateMutex();
|
||||
UnrecoverableError = false;
|
||||
|
||||
s.cdif_ptr = this;
|
||||
s.device_name = device_name;
|
||||
|
||||
CDReadThread = MDFND_CreateThread(ReadThreadStart_C, &s);
|
||||
EmuThreadQueue.Read(&msg);
|
||||
}
|
||||
|
||||
|
||||
CDIF::~CDIF()
|
||||
{
|
||||
bool thread_murdered_with_kitchen_knife = false;
|
||||
|
||||
try
|
||||
{
|
||||
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_DIEDIEDIE));
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
MDFND_PrintError(e.what());
|
||||
MDFND_KillThread(CDReadThread);
|
||||
thread_murdered_with_kitchen_knife = true;
|
||||
}
|
||||
|
||||
if(!thread_murdered_with_kitchen_knife)
|
||||
MDFND_WaitThread(CDReadThread, NULL);
|
||||
|
||||
if(SBMutex)
|
||||
{
|
||||
MDFND_DestroyMutex(SBMutex);
|
||||
SBMutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CDIF::ValidateRawSector(uint8 *buf)
|
||||
{
|
||||
int mode = buf[12 + 3];
|
||||
|
||||
if(mode != 0x1 && mode != 0x2)
|
||||
return(false);
|
||||
|
||||
if(!edc_lec_check_correct(buf, mode == 2))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool CDIF::ReadRawSector(uint8 *buf, uint32 lba)
|
||||
{
|
||||
bool found = FALSE;
|
||||
bool error_condition = false;
|
||||
|
||||
if(UnrecoverableError)
|
||||
{
|
||||
memset(buf, 0, 2352 + 96);
|
||||
return(false);
|
||||
}
|
||||
|
||||
// This shouldn't happen, the emulated-system-specific CDROM emulation code should make sure the emulated program doesn't try
|
||||
// to read past the last "real" sector of the disc.
|
||||
if(lba >= disc_toc.tracks[100].lba)
|
||||
{
|
||||
printf("Attempt to read LBA %d, >= LBA %d\n", lba, disc_toc.tracks[100].lba);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
|
||||
|
||||
do
|
||||
{
|
||||
MDFND_LockMutex(SBMutex);
|
||||
|
||||
for(int i = 0; i < SBSize; i++)
|
||||
{
|
||||
if(SectorBuffers[i].valid && SectorBuffers[i].lba == lba)
|
||||
{
|
||||
error_condition = SectorBuffers[i].error;
|
||||
memcpy(buf, SectorBuffers[i].data, 2352 + 96);
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
MDFND_UnlockMutex(SBMutex);
|
||||
|
||||
if(!found)
|
||||
MDFND_Sleep(1);
|
||||
} while(!found);
|
||||
|
||||
return(!error_condition);
|
||||
}
|
||||
|
||||
void CDIF::HintReadSector(uint32 lba)
|
||||
{
|
||||
if(UnrecoverableError)
|
||||
return;
|
||||
|
||||
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
|
||||
}
|
||||
|
||||
int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if(UnrecoverableError)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
while(nSectors--)
|
||||
{
|
||||
uint8 tmpbuf[2352 + 96];
|
||||
|
||||
if(!ReadRawSector(tmpbuf, lba))
|
||||
{
|
||||
puts("CDIF Raw Read error");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if(!ValidateRawSector(tmpbuf))
|
||||
{
|
||||
MDFN_DispMessage(_("Uncorrectable data at sector %d"), lba);
|
||||
MDFN_PrintError(_("Uncorrectable data at sector %d"), lba);
|
||||
return(false);
|
||||
}
|
||||
|
||||
const int mode = tmpbuf[12 + 3];
|
||||
|
||||
if(!ret)
|
||||
ret = mode;
|
||||
|
||||
if(mode == 1)
|
||||
{
|
||||
memcpy(pBuf, &tmpbuf[12 + 4], 2048);
|
||||
}
|
||||
else if(mode == 2)
|
||||
{
|
||||
memcpy(pBuf, &tmpbuf[12 + 4 + 8], 2048);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
|
||||
return(false);
|
||||
}
|
||||
|
||||
pBuf += 2048;
|
||||
lba++;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void CDIF::ReadTOC(CDUtility::TOC *read_target)
|
||||
{
|
||||
*read_target = disc_toc;
|
||||
}
|
||||
|
||||
bool CDIF::Eject(bool eject_status)
|
||||
{
|
||||
if(UnrecoverableError)
|
||||
return(false);
|
||||
|
||||
try
|
||||
{
|
||||
CDIF_Message msg;
|
||||
|
||||
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_EJECT, eject_status));
|
||||
EmuThreadQueue.Read(&msg);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
MDFN_PrintError(_("Error on eject/insert attempt: %s"), e.what());
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
152
mednafen/cdrom/cdromif.h
Normal file
152
mednafen/cdrom/cdromif.h
Normal file
@ -0,0 +1,152 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __MDFN_CDROM_CDROMIF_H
|
||||
#define __MDFN_CDROM_CDROMIF_H
|
||||
|
||||
#include "CDUtility.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
typedef CDUtility::TOC CD_TOC;
|
||||
|
||||
enum
|
||||
{
|
||||
// Status/Error messages
|
||||
CDIF_MSG_DONE = 0, // Read -> emu. args: No args.
|
||||
CDIF_MSG_INFO, // Read -> emu. args: str_message
|
||||
CDIF_MSG_FATAL_ERROR, // Read -> emu. args: *TODO ARGS*
|
||||
|
||||
//
|
||||
// Command messages.
|
||||
//
|
||||
CDIF_MSG_DIEDIEDIE, // Emu -> read
|
||||
|
||||
CDIF_MSG_READ_SECTOR, /* Emu -> read
|
||||
args[0] = lba
|
||||
*/
|
||||
|
||||
CDIF_MSG_EJECT, // Emu -> read, args[0]; 0=insert, 1=eject
|
||||
};
|
||||
|
||||
class CDIF_Message
|
||||
{
|
||||
public:
|
||||
|
||||
CDIF_Message();
|
||||
CDIF_Message(unsigned int message_, uint32 arg0 = 0, uint32 arg1 = 0, uint32 arg2 = 0, uint32 arg3 = 0);
|
||||
CDIF_Message(unsigned int message_, const std::string &str);
|
||||
~CDIF_Message();
|
||||
|
||||
unsigned int message;
|
||||
uint32 args[4];
|
||||
void *parg;
|
||||
std::string str_message;
|
||||
};
|
||||
|
||||
class CDIF_Queue
|
||||
{
|
||||
public:
|
||||
|
||||
CDIF_Queue();
|
||||
~CDIF_Queue();
|
||||
|
||||
bool Read(CDIF_Message *message, bool blocking = TRUE);
|
||||
|
||||
void Write(const CDIF_Message &message);
|
||||
|
||||
private:
|
||||
std::queue<CDIF_Message> ze_queue;
|
||||
MDFN_Mutex *ze_mutex;
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool valid;
|
||||
bool error;
|
||||
uint32 lba;
|
||||
uint8 data[2352 + 96];
|
||||
} CDIF_Sector_Buffer;
|
||||
|
||||
class CDAccess;
|
||||
|
||||
// TODO: prohibit copy constructor
|
||||
class CDIF
|
||||
{
|
||||
public:
|
||||
|
||||
CDIF(const char *device_name);
|
||||
~CDIF();
|
||||
|
||||
void ReadTOC(CDUtility::TOC *read_target);
|
||||
|
||||
void HintReadSector(uint32 lba);
|
||||
bool ReadRawSector(uint8 *buf, uint32 lba);
|
||||
|
||||
// Call for mode 1 or mode 2 form 1 only.
|
||||
bool ValidateRawSector(uint8 *buf);
|
||||
|
||||
// Utility/Wrapped functions
|
||||
// Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
|
||||
// Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
|
||||
int ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors);
|
||||
|
||||
// Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
|
||||
// Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
|
||||
bool Eject(bool eject_status);
|
||||
|
||||
inline bool IsPhysical(void) { return is_phys_cache; }
|
||||
|
||||
// FIXME: Semi-private:
|
||||
int ReadThreadStart(const char *device_name);
|
||||
|
||||
private:
|
||||
|
||||
bool is_phys_cache;
|
||||
CDUtility::TOC disc_toc;
|
||||
CDAccess *disc_cdaccess;
|
||||
MDFN_Thread *CDReadThread;
|
||||
|
||||
// Queue for messages to the read thread.
|
||||
CDIF_Queue ReadThreadQueue;
|
||||
|
||||
// Queue for messages to the emu thread.
|
||||
CDIF_Queue EmuThreadQueue;
|
||||
|
||||
|
||||
enum { SBSize = 256 };
|
||||
CDIF_Sector_Buffer SectorBuffers[SBSize];
|
||||
|
||||
uint32 SBWritePos;
|
||||
|
||||
MDFN_Mutex *SBMutex;
|
||||
bool UnrecoverableError;
|
||||
|
||||
|
||||
//
|
||||
// Read-thread-only:
|
||||
//
|
||||
void RT_EjectDisc(bool eject_status, bool skip_actual_eject = false);
|
||||
|
||||
uint32 ra_lba;
|
||||
int ra_count;
|
||||
uint32 last_read_lba;
|
||||
bool DiscEjected;
|
||||
};
|
||||
|
||||
#endif
|
130
mednafen/cdrom/crc32.cpp
Normal file
130
mednafen/cdrom/crc32.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* CRC32 code based upon public domain code by Ross Williams (see notes below)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
/***
|
||||
*** EDC checksum used in CDROM sectors
|
||||
***/
|
||||
|
||||
/*****************************************************************/
|
||||
/* */
|
||||
/* CRC LOOKUP TABLE */
|
||||
/* ================ */
|
||||
/* The following CRC lookup table was generated automagically */
|
||||
/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
|
||||
/* Program V1.0 using the following model parameters: */
|
||||
/* */
|
||||
/* Width : 4 bytes. */
|
||||
/* Poly : 0x8001801BL */
|
||||
/* Reverse : TRUE. */
|
||||
/* */
|
||||
/* For more information on the Rocksoft^tm Model CRC Algorithm, */
|
||||
/* see the document titled "A Painless Guide to CRC Error */
|
||||
/* Detection Algorithms" by Ross Williams */
|
||||
/* (ross@guest.adelaide.edu.au.). This document is likely to be */
|
||||
/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
unsigned long edctable[256] =
|
||||
{
|
||||
0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
|
||||
0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
|
||||
0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
|
||||
0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
|
||||
0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
|
||||
0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
|
||||
0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
|
||||
0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
|
||||
0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
|
||||
0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
|
||||
0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
|
||||
0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
|
||||
0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
|
||||
0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
|
||||
0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
|
||||
0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
|
||||
0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
|
||||
0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
|
||||
0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
|
||||
0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
|
||||
0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
|
||||
0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
|
||||
0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
|
||||
0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
|
||||
0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
|
||||
0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
|
||||
0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
|
||||
0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
|
||||
0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
|
||||
0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
|
||||
0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
|
||||
0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
|
||||
0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
|
||||
0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
|
||||
0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
|
||||
0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
|
||||
0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
|
||||
0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
|
||||
0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
|
||||
0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
|
||||
0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
|
||||
0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
|
||||
0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
|
||||
0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
|
||||
0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
|
||||
0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
|
||||
0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
|
||||
0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
|
||||
0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
|
||||
0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
|
||||
0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
|
||||
0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
|
||||
0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
|
||||
0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
|
||||
0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
|
||||
0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
|
||||
0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
|
||||
0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
|
||||
0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
|
||||
0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
|
||||
0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
|
||||
0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
|
||||
0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
|
||||
0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
|
||||
};
|
||||
|
||||
/*
|
||||
* CDROM EDC calculation
|
||||
*/
|
||||
|
||||
uint32 EDCCrc32(const unsigned char *data, int len)
|
||||
{
|
||||
uint32 crc = 0;
|
||||
|
||||
while(len--)
|
||||
crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return crc;
|
||||
}
|
173
mednafen/cdrom/dvdisaster.h
Normal file
173
mednafen/cdrom/dvdisaster.h
Normal file
@ -0,0 +1,173 @@
|
||||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef DVDISASTER_H
|
||||
#define DVDISASTER_H
|
||||
|
||||
/* "Dare to be gorgeous and unique.
|
||||
* But don't ever be cryptic or otherwise unfathomable.
|
||||
* Make it unforgettably great."
|
||||
*
|
||||
* From "A Final Note on Style",
|
||||
* Amiga Intuition Reference Manual, 1986, p. 231
|
||||
*/
|
||||
|
||||
/***
|
||||
*** I'm too lazy to mess with #include dependencies.
|
||||
*** Everything #includeable is rolled up herein...
|
||||
*/
|
||||
|
||||
#include "../mednafen-types.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/***
|
||||
*** dvdisaster.c
|
||||
***/
|
||||
|
||||
void PrepareDeadSector(void);
|
||||
|
||||
void CreateEcc(void);
|
||||
void FixEcc(void);
|
||||
void Verify(void);
|
||||
|
||||
uint32 EDCCrc32(const unsigned char*, int);
|
||||
|
||||
/***
|
||||
*** galois.c
|
||||
***
|
||||
* This is currently the hardcoded GF(2**8).
|
||||
* int32 gives abundant space for the GF.
|
||||
* Squeezing it down to uint8 won't probably gain much,
|
||||
* so we implement this defensively here.
|
||||
*
|
||||
* Note that some performance critical stuff needs to
|
||||
* be #included from galois-inlines.h
|
||||
*/
|
||||
|
||||
/* Galois field parameters for 8bit symbol Reed-Solomon code */
|
||||
|
||||
#define GF_SYMBOLSIZE 8
|
||||
#define GF_FIELDSIZE (1<<GF_SYMBOLSIZE)
|
||||
#define GF_FIELDMAX (GF_FIELDSIZE-1)
|
||||
#define GF_ALPHA0 GF_FIELDMAX
|
||||
|
||||
/* Lookup tables for Galois field arithmetic */
|
||||
|
||||
typedef struct _GaloisTables
|
||||
{ int32 gfGenerator; /* GF generator polynomial */
|
||||
int32 *indexOf; /* log */
|
||||
int32 *alphaTo; /* inverse log */
|
||||
int32 *encAlphaTo; /* inverse log optimized for encoder */
|
||||
} GaloisTables;
|
||||
|
||||
/* Lookup and working tables for the ReedSolomon codecs */
|
||||
|
||||
typedef struct _ReedSolomonTables
|
||||
{ GaloisTables *gfTables;/* from above */
|
||||
int32 *gpoly; /* RS code generator polynomial */
|
||||
int32 fcr; /* first consecutive root of RS generator polynomial */
|
||||
int32 primElem; /* primitive field element */
|
||||
int32 nroots; /* degree of RS generator polynomial */
|
||||
int32 ndata; /* data bytes per ecc block */
|
||||
} ReedSolomonTables;
|
||||
|
||||
GaloisTables* CreateGaloisTables(int32);
|
||||
void FreeGaloisTables(GaloisTables*);
|
||||
|
||||
ReedSolomonTables *CreateReedSolomonTables(GaloisTables*, int32, int32, int);
|
||||
void FreeReedSolomonTables(ReedSolomonTables*);
|
||||
|
||||
/***
|
||||
*** l-ec.c
|
||||
***/
|
||||
|
||||
#define N_P_VECTORS 86 /* 43 16bit p vectors */
|
||||
#define P_VECTOR_SIZE 26 /* using RS(26,24) ECC */
|
||||
|
||||
#define N_Q_VECTORS 52 /* 26 16bit q vectors */
|
||||
#define Q_VECTOR_SIZE 45 /* using RS(45,43) ECC */
|
||||
|
||||
#define P_PADDING 229 /* padding values for */
|
||||
#define Q_PADDING 210 /* shortened RS code */
|
||||
|
||||
int PToByteIndex(int, int);
|
||||
int QToByteIndex(int, int);
|
||||
void ByteIndexToP(int, int*, int*);
|
||||
void ByteIndexToQ(int, int*, int*);
|
||||
|
||||
void GetPVector(unsigned char*, unsigned char*, int);
|
||||
void SetPVector(unsigned char*, unsigned char*, int);
|
||||
void FillPVector(unsigned char*, unsigned char, int);
|
||||
void AndPVector(unsigned char*, unsigned char, int);
|
||||
void OrPVector(unsigned char*, unsigned char, int);
|
||||
|
||||
void GetQVector(unsigned char*, unsigned char*, int);
|
||||
void SetQVector(unsigned char*, unsigned char*, int);
|
||||
void FillQVector(unsigned char*, unsigned char, int);
|
||||
void AndQVector(unsigned char*, unsigned char, int);
|
||||
void OrQVector(unsigned char*, unsigned char, int);
|
||||
|
||||
int DecodePQ(ReedSolomonTables*, unsigned char*, int, int*, int);
|
||||
|
||||
int CountC2Errors(unsigned char*);
|
||||
|
||||
/***
|
||||
*** misc.c
|
||||
***/
|
||||
|
||||
char* sgettext(char*);
|
||||
char* sgettext_utf8(char*);
|
||||
|
||||
int64 uchar_to_int64(unsigned char*);
|
||||
void int64_to_uchar(unsigned char*, int64);
|
||||
|
||||
void CalcSectors(int64, int64*, int*);
|
||||
|
||||
/***
|
||||
*** recover-raw.c
|
||||
***/
|
||||
|
||||
#define CD_RAW_SECTOR_SIZE 2352
|
||||
#define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
|
||||
|
||||
int CheckEDC(const unsigned char*, bool);
|
||||
int CheckMSF(unsigned char*, int);
|
||||
|
||||
|
||||
int ValidateRawSector(unsigned char *frame, bool xaMode);
|
||||
bool Init_LEC_Correct(void);
|
||||
void Kill_LEC_Correct(void);
|
||||
|
||||
|
||||
#endif /* DVDISASTER_H */
|
40
mednafen/cdrom/galois-inlines.h
Normal file
40
mednafen/cdrom/galois-inlines.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
/*
|
||||
* The following routine is performance critical.
|
||||
*/
|
||||
|
||||
static inline int mod_fieldmax(int x)
|
||||
{
|
||||
while (x >= GF_FIELDMAX)
|
||||
{
|
||||
x -= GF_FIELDMAX;
|
||||
x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
156
mednafen/cdrom/galois.cpp
Normal file
156
mednafen/cdrom/galois.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
#include "galois-inlines.h"
|
||||
|
||||
/***
|
||||
*** Galois field arithmetic.
|
||||
***
|
||||
* Calculations are done over the extension field GF(2**n).
|
||||
* Be careful not to overgeneralize these arithmetics;
|
||||
* they only work for the case of GF(p**n) with p being prime.
|
||||
*/
|
||||
|
||||
/* Initialize the Galois field tables */
|
||||
|
||||
|
||||
GaloisTables* CreateGaloisTables(int32 gf_generator)
|
||||
{
|
||||
GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
|
||||
int32 b,log;
|
||||
|
||||
/* Allocate the tables.
|
||||
The encoder uses a special version of alpha_to which has the mod_fieldmax()
|
||||
folded into the table. */
|
||||
|
||||
gt->gfGenerator = gf_generator;
|
||||
|
||||
gt->indexOf = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->alphaTo = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->encAlphaTo = (int32 *)calloc(2*GF_FIELDSIZE, sizeof(int32));
|
||||
|
||||
/* create the log/ilog values */
|
||||
|
||||
for(b=1, log=0; log<GF_FIELDMAX; log++)
|
||||
{ gt->indexOf[b] = log;
|
||||
gt->alphaTo[log] = b;
|
||||
b = b << 1;
|
||||
if(b & GF_FIELDSIZE)
|
||||
b = b ^ gf_generator;
|
||||
}
|
||||
|
||||
if(b!=1)
|
||||
{
|
||||
printf("Failed to create the Galois field log tables!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* we're even closed using infinity (makes things easier) */
|
||||
|
||||
gt->indexOf[0] = GF_ALPHA0; /* log(0) = inf */
|
||||
gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */
|
||||
|
||||
for(b=0; b<2*GF_FIELDSIZE; b++)
|
||||
gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
|
||||
|
||||
return gt;
|
||||
}
|
||||
|
||||
void FreeGaloisTables(GaloisTables *gt)
|
||||
{
|
||||
if(gt->indexOf) free(gt->indexOf);
|
||||
if(gt->alphaTo) free(gt->alphaTo);
|
||||
if(gt->encAlphaTo) free(gt->encAlphaTo);
|
||||
|
||||
free(gt);
|
||||
}
|
||||
|
||||
/***
|
||||
*** Create the the Reed-Solomon generator polynomial
|
||||
*** and some auxiliary data structures.
|
||||
*/
|
||||
|
||||
ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
|
||||
int32 first_consecutive_root,
|
||||
int32 prim_elem,
|
||||
int nroots_in)
|
||||
{ ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));
|
||||
int32 i,j,root;
|
||||
|
||||
rt->gfTables = gt;
|
||||
rt->fcr = first_consecutive_root;
|
||||
rt->primElem = prim_elem;
|
||||
rt->nroots = nroots_in;
|
||||
rt->ndata = GF_FIELDMAX - rt->nroots;
|
||||
|
||||
rt->gpoly = (int32 *)calloc((rt->nroots+1), sizeof(int32));
|
||||
|
||||
/* Create the RS code generator polynomial */
|
||||
|
||||
rt->gpoly[0] = 1;
|
||||
|
||||
for(i=0, root=first_consecutive_root*prim_elem; i<rt->nroots; i++, root+=prim_elem)
|
||||
{ rt->gpoly[i+1] = 1;
|
||||
|
||||
/* Multiply gpoly by alpha**(root+x) */
|
||||
|
||||
for(j=i; j>0; j--)
|
||||
{
|
||||
if(rt->gpoly[j] != 0)
|
||||
rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
|
||||
else
|
||||
rt->gpoly[j] = rt->gpoly[j-1];
|
||||
}
|
||||
|
||||
rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
|
||||
}
|
||||
|
||||
/* Store the polynomials index for faster encoding */
|
||||
|
||||
for(i=0; i<=rt->nroots; i++)
|
||||
rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
|
||||
|
||||
#if 0
|
||||
/* for the precalculated unrolled loops only */
|
||||
|
||||
for(i=gt->nroots-1; i>0; i--)
|
||||
PrintCLI(
|
||||
" par_idx[((++spk)&%d)] ^= enc_alpha_to[feedback + %3d];\n",
|
||||
nroots-1,gt->gpoly[i]);
|
||||
|
||||
PrintCLI(" par_idx[sp] = enc_alpha_to[feedback + %3d];\n",
|
||||
gt->gpoly[0]);
|
||||
#endif
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
void FreeReedSolomonTables(ReedSolomonTables *rt)
|
||||
{
|
||||
if(rt->gpoly) free(rt->gpoly);
|
||||
|
||||
free(rt);
|
||||
}
|
478
mednafen/cdrom/l-ec.cpp
Normal file
478
mednafen/cdrom/l-ec.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
#include "galois-inlines.h"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/***
|
||||
*** Mapping between cd frame and parity vectors
|
||||
***/
|
||||
|
||||
/*
|
||||
* Mapping of frame bytes to P/Q Vectors
|
||||
*/
|
||||
|
||||
int PToByteIndex(int p, int i)
|
||||
{ return 12 + p + i*86;
|
||||
}
|
||||
|
||||
void ByteIndexToP(int b, int *p, int *i)
|
||||
{ *p = (b-12)%86;
|
||||
*i = (b-12)/86;
|
||||
}
|
||||
|
||||
int QToByteIndex(int q, int i)
|
||||
{ int offset = 12 + (q & 1);
|
||||
|
||||
if(i == 43) return 2248+q;
|
||||
if(i == 44) return 2300+q;
|
||||
|
||||
q&=~1;
|
||||
return offset + (q*43 + i*88) % 2236;
|
||||
}
|
||||
|
||||
void ByteIndexToQ(int b, int *q, int *i)
|
||||
{ int x,y,offset;
|
||||
|
||||
if(b >= 2300)
|
||||
{ *i = 44;
|
||||
*q = (b-2300);
|
||||
return;
|
||||
}
|
||||
|
||||
if(b >= 2248)
|
||||
{ *i = 43;
|
||||
*q = (b-2248);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = b&1;
|
||||
b = (b-12)/2;
|
||||
x = b/43;
|
||||
y = (b-(x*43))%26;
|
||||
*i = b-(x*43);
|
||||
*q = 2*((x+26-y)%26)+offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are 86 vectors of P-parity, yielding a RS(26,24) code.
|
||||
*/
|
||||
|
||||
void GetPVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
data[i] = frame[w_idx];
|
||||
}
|
||||
|
||||
void SetPVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] = data[i];
|
||||
}
|
||||
|
||||
void FillPVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] = data;
|
||||
}
|
||||
|
||||
void OrPVector(unsigned char *frame, unsigned char value, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] |= value;
|
||||
}
|
||||
|
||||
void AndPVector(unsigned char *frame, unsigned char value, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] &= value;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are 52 vectors of Q-parity, yielding a RS(45,43) code.
|
||||
*/
|
||||
|
||||
void GetQVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
data[i] = frame[(w_idx % 2236) + offset];
|
||||
|
||||
data[43] = frame[2248 + n];
|
||||
data[44] = frame[2300 + n];
|
||||
}
|
||||
|
||||
void SetQVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] = data[i];
|
||||
|
||||
frame[2248 + n] = data[43];
|
||||
frame[2300 + n] = data[44];
|
||||
}
|
||||
|
||||
void FillQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] = data;
|
||||
|
||||
frame[2248 + n] = data;
|
||||
frame[2300 + n] = data;
|
||||
}
|
||||
|
||||
void OrQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] |= data;
|
||||
|
||||
frame[2248 + n] |= data;
|
||||
frame[2300 + n] |= data;
|
||||
}
|
||||
|
||||
void AndQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] &= data;
|
||||
|
||||
frame[2248 + n] &= data;
|
||||
frame[2300 + n] &= data;
|
||||
}
|
||||
|
||||
/***
|
||||
*** C2 error counting
|
||||
***/
|
||||
|
||||
int CountC2Errors(unsigned char *frame)
|
||||
{ int i,count = 0;
|
||||
frame += 2352;
|
||||
|
||||
for(i=0; i<294; i++, frame++)
|
||||
{ if(*frame & 0x01) count++;
|
||||
if(*frame & 0x02) count++;
|
||||
if(*frame & 0x04) count++;
|
||||
if(*frame & 0x08) count++;
|
||||
if(*frame & 0x10) count++;
|
||||
if(*frame & 0x20) count++;
|
||||
if(*frame & 0x40) count++;
|
||||
if(*frame & 0x80) count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/***
|
||||
*** L-EC error correction for CD raw data sectors
|
||||
***/
|
||||
|
||||
/*
|
||||
* These could be used from ReedSolomonTables,
|
||||
* but hardcoding them is faster.
|
||||
*/
|
||||
|
||||
#define NROOTS 2
|
||||
#define LEC_FIRST_ROOT 0 //GF_ALPHA0
|
||||
#define LEC_PRIM_ELEM 1
|
||||
#define LEC_PRIMTH_ROOT 1
|
||||
|
||||
/*
|
||||
* Calculate the error syndrome
|
||||
*/
|
||||
|
||||
int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
int *erasure_list, int erasure_count)
|
||||
{ GaloisTables *gt = rt->gfTables;
|
||||
int syndrome[NROOTS];
|
||||
int lambda[NROOTS+1];
|
||||
int omega[NROOTS+1];
|
||||
int b[NROOTS+1];
|
||||
int reg[NROOTS+1];
|
||||
int root[NROOTS];
|
||||
int loc[NROOTS];
|
||||
int syn_error;
|
||||
int deg_lambda,lambda_roots;
|
||||
int deg_omega;
|
||||
int shortened_size = GF_FIELDMAX - padding;
|
||||
int corrected = 0;
|
||||
int i,j,k;
|
||||
int r,el;
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
|
||||
syn_error = 0;
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ syn_error |= syndrome[i];
|
||||
syndrome[i] = gt->indexOf[syndrome[i]];
|
||||
}
|
||||
|
||||
/*** If the syndrome is zero, everything is fine. */
|
||||
|
||||
if(!syn_error)
|
||||
return 0;
|
||||
|
||||
/*** Initialize lambda to be the erasure locator polynomial */
|
||||
|
||||
lambda[0] = 1;
|
||||
lambda[1] = lambda[2] = 0;
|
||||
|
||||
erasure_list[0] += padding;
|
||||
erasure_list[1] += padding;
|
||||
|
||||
if(erasure_count > 2) /* sanity check */
|
||||
erasure_count = 0;
|
||||
|
||||
if(erasure_count > 0)
|
||||
{ lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
|
||||
|
||||
for(i=1; i<erasure_count; i++)
|
||||
{ int u = mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[i]));
|
||||
|
||||
for(j=i+1; j>0; j--)
|
||||
{ int tmp = gt->indexOf[lambda[j-1]];
|
||||
|
||||
if(tmp != GF_ALPHA0)
|
||||
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
b[i] = gt->indexOf[lambda[i]];
|
||||
|
||||
/*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
|
||||
|
||||
r = erasure_count; /* r is the step number */
|
||||
el = erasure_count;
|
||||
|
||||
/* Compute discrepancy at the r-th step in poly-form */
|
||||
|
||||
while(++r <= NROOTS)
|
||||
{ int discr_r = 0;
|
||||
|
||||
for(i=0; i<r; i++)
|
||||
if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
|
||||
discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
|
||||
|
||||
discr_r = gt->indexOf[discr_r];
|
||||
|
||||
if(discr_r == GF_ALPHA0)
|
||||
{ /* B(x) = x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
else
|
||||
{ int t[NROOTS+1];
|
||||
|
||||
/* T(x) = lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(b[i] != GF_ALPHA0)
|
||||
t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
|
||||
else t[i+1] = lambda[i+1];
|
||||
}
|
||||
|
||||
if(2*el <= r+erasure_count-1)
|
||||
{ el = r + erasure_count - el;
|
||||
|
||||
/* B(x) <-- inv(discr_r) * lambda(x) */
|
||||
for(i=0; i<=NROOTS; i++)
|
||||
b[i] = (lambda[i] == 0) ? GF_ALPHA0
|
||||
: mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
|
||||
}
|
||||
else
|
||||
{ /* 2 lines below: B(x) <-- x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
|
||||
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/*** Convert lambda to index form and compute deg(lambda(x)) */
|
||||
|
||||
deg_lambda = 0;
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
{ lambda[i] = gt->indexOf[lambda[i]];
|
||||
if(lambda[i] != GF_ALPHA0)
|
||||
deg_lambda = i;
|
||||
}
|
||||
|
||||
/*** Find roots of the error+erasure locator polynomial by Chien search */
|
||||
|
||||
memcpy(reg+1, lambda+1, NROOTS*sizeof(reg[0]));
|
||||
lambda_roots = 0; /* Number of roots of lambda(x) */
|
||||
|
||||
for(i=1, k=LEC_PRIMTH_ROOT-1; i<=GF_FIELDMAX; i++, k=mod_fieldmax(k+LEC_PRIMTH_ROOT))
|
||||
{ int q=1; /* lambda[0] is always 0 */
|
||||
|
||||
for(j=deg_lambda; j>0; j--)
|
||||
{ if(reg[j] != GF_ALPHA0)
|
||||
{ reg[j] = mod_fieldmax(reg[j] + j);
|
||||
q ^= gt->alphaTo[reg[j]];
|
||||
}
|
||||
}
|
||||
|
||||
if(q != 0) continue; /* Not a root */
|
||||
|
||||
/* store root in index-form and the error location number */
|
||||
|
||||
root[lambda_roots] = i;
|
||||
loc[lambda_roots] = k;
|
||||
|
||||
/* If we've already found max possible roots, abort the search to save time */
|
||||
|
||||
if(++lambda_roots == deg_lambda) break;
|
||||
}
|
||||
|
||||
/* deg(lambda) unequal to number of roots => uncorrectable error detected
|
||||
This is not reliable for very small numbers of roots, e.g. nroots = 2 */
|
||||
|
||||
if(deg_lambda != lambda_roots)
|
||||
{ return -1;
|
||||
}
|
||||
|
||||
/* Compute err+eras evaluator poly omega(x) = syn(x)*lambda(x)
|
||||
(modulo x**nroots). in index form. Also find deg(omega). */
|
||||
|
||||
deg_omega = deg_lambda-1;
|
||||
|
||||
for(i=0; i<=deg_omega; i++)
|
||||
{ int tmp = 0;
|
||||
|
||||
for(j=i; j>=0; j--)
|
||||
{ if((syndrome[i - j] != GF_ALPHA0) && (lambda[j] != GF_ALPHA0))
|
||||
tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
|
||||
}
|
||||
|
||||
omega[i] = gt->indexOf[tmp];
|
||||
}
|
||||
|
||||
/* Compute error values in poly-form.
|
||||
num1 = omega(inv(X(l))),
|
||||
num2 = inv(X(l))**(FIRST_ROOT-1) and
|
||||
den = lambda_pr(inv(X(l))) all in poly-form. */
|
||||
|
||||
for(j=lambda_roots-1; j>=0; j--)
|
||||
{ int num1 = 0;
|
||||
int num2;
|
||||
int den;
|
||||
int location = loc[j];
|
||||
|
||||
for(i=deg_omega; i>=0; i--)
|
||||
{ if(omega[i] != GF_ALPHA0)
|
||||
num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
|
||||
}
|
||||
|
||||
num2 = gt->alphaTo[mod_fieldmax(root[j] * (LEC_FIRST_ROOT - 1) + GF_FIELDMAX)];
|
||||
den = 0;
|
||||
|
||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
||||
|
||||
for(i=MIN(deg_lambda, NROOTS-1) & ~1; i>=0; i-=2)
|
||||
{ if(lambda[i+1] != GF_ALPHA0)
|
||||
den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
|
||||
}
|
||||
|
||||
/* Apply error to data */
|
||||
|
||||
if(num1 != 0 && location >= padding)
|
||||
{
|
||||
corrected++;
|
||||
data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
|
||||
+ GF_FIELDMAX - gt->indexOf[den])];
|
||||
|
||||
/* If no erasures were given, at most one error was corrected.
|
||||
Return its position in erasure_list[0]. */
|
||||
|
||||
if(!erasure_count)
|
||||
erasure_list[0] = location-padding;
|
||||
}
|
||||
#if 1
|
||||
else return -3;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
}
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
#if 1
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i])
|
||||
return -2;
|
||||
#endif
|
||||
|
||||
return corrected;
|
||||
}
|
||||
|
||||
|
691
mednafen/cdrom/lec.cpp
Normal file
691
mednafen/cdrom/lec.cpp
Normal file
@ -0,0 +1,691 @@
|
||||
/* cdrdao - write audio CD-Rs in disc-at-once mode
|
||||
*
|
||||
* Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lec.h"
|
||||
|
||||
#define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */
|
||||
|
||||
#define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */
|
||||
|
||||
#define LEC_HEADER_OFFSET 12
|
||||
#define LEC_DATA_OFFSET 16
|
||||
#define LEC_MODE1_DATA_LEN 2048
|
||||
#define LEC_MODE1_EDC_OFFSET 2064
|
||||
#define LEC_MODE1_INTERMEDIATE_OFFSET 2068
|
||||
#define LEC_MODE1_P_PARITY_OFFSET 2076
|
||||
#define LEC_MODE1_Q_PARITY_OFFSET 2248
|
||||
#define LEC_MODE2_FORM1_DATA_LEN (2048+8)
|
||||
#define LEC_MODE2_FORM1_EDC_OFFSET 2072
|
||||
#define LEC_MODE2_FORM2_DATA_LEN (2324+8)
|
||||
#define LEC_MODE2_FORM2_EDC_OFFSET 2348
|
||||
|
||||
|
||||
typedef u_int8_t gf8_t;
|
||||
|
||||
static u_int8_t GF8_LOG[256];
|
||||
static gf8_t GF8_ILOG[256];
|
||||
|
||||
static const class Gf8_Q_Coeffs_Results_01 {
|
||||
private:
|
||||
u_int16_t table[43][256];
|
||||
public:
|
||||
Gf8_Q_Coeffs_Results_01();
|
||||
~Gf8_Q_Coeffs_Results_01() {}
|
||||
const u_int16_t *operator[] (int i) const { return &table[i][0]; }
|
||||
operator const u_int16_t *() const { return &table[0][0]; }
|
||||
} CF8_Q_COEFFS_RESULTS_01;
|
||||
|
||||
static const class CrcTable {
|
||||
private:
|
||||
u_int32_t table[256];
|
||||
public:
|
||||
CrcTable();
|
||||
~CrcTable() {}
|
||||
u_int32_t operator[](int i) const { return table[i]; }
|
||||
operator const u_int32_t *() const { return table; }
|
||||
} CRCTABLE;
|
||||
|
||||
static const class ScrambleTable {
|
||||
private:
|
||||
u_int8_t table[2340];
|
||||
public:
|
||||
ScrambleTable();
|
||||
~ScrambleTable() {}
|
||||
u_int8_t operator[](int i) const { return table[i]; }
|
||||
operator const u_int8_t *() const { return table; }
|
||||
} SCRAMBLE_TABLE;
|
||||
|
||||
/* Creates the logarithm and inverse logarithm table that is required
|
||||
* for performing multiplication in the GF(8) domain.
|
||||
*/
|
||||
static void gf8_create_log_tables()
|
||||
{
|
||||
u_int8_t log;
|
||||
u_int16_t b;
|
||||
|
||||
for (b = 0; b <= 255; b++) {
|
||||
GF8_LOG[b] = 0;
|
||||
GF8_ILOG[b] = 0;
|
||||
}
|
||||
|
||||
b = 1;
|
||||
|
||||
for (log = 0; log < 255; log++) {
|
||||
GF8_LOG[(u_int8_t)b] = log;
|
||||
GF8_ILOG[log] = (u_int8_t)b;
|
||||
|
||||
b <<= 1;
|
||||
|
||||
if ((b & 0x100) != 0)
|
||||
b ^= GF8_PRIM_POLY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Addition in the GF(8) domain: just the XOR of the values.
|
||||
*/
|
||||
#define gf8_add(a, b) (a) ^ (b)
|
||||
|
||||
|
||||
/* Multiplication in the GF(8) domain: add the logarithms (modulo 255)
|
||||
* and return the inverse logarithm. Not used!
|
||||
*/
|
||||
#if 0
|
||||
static gf8_t gf8_mult(gf8_t a, gf8_t b)
|
||||
{
|
||||
int16_t sum;
|
||||
|
||||
if (a == 0 || b == 0)
|
||||
return 0;
|
||||
|
||||
sum = GF8_LOG[a] + GF8_LOG[b];
|
||||
|
||||
if (sum >= 255)
|
||||
sum -= 255;
|
||||
|
||||
return GF8_ILOG[sum];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Division in the GF(8) domain: Like multiplication but logarithms a
|
||||
* subtracted.
|
||||
*/
|
||||
static gf8_t gf8_div(gf8_t a, gf8_t b)
|
||||
{
|
||||
int16_t sum;
|
||||
|
||||
assert(b != 0);
|
||||
|
||||
if (a == 0)
|
||||
return 0;
|
||||
|
||||
sum = GF8_LOG[a] - GF8_LOG[b];
|
||||
|
||||
if (sum < 0)
|
||||
sum += 255;
|
||||
|
||||
return GF8_ILOG[sum];
|
||||
}
|
||||
|
||||
Gf8_Q_Coeffs_Results_01::Gf8_Q_Coeffs_Results_01()
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t c;
|
||||
gf8_t GF8_COEFFS_HELP[2][45];
|
||||
u_int8_t GF8_Q_COEFFS[2][45];
|
||||
|
||||
|
||||
gf8_create_log_tables();
|
||||
|
||||
/* build matrix H:
|
||||
* 1 1 ... 1 1
|
||||
* a^44 a^43 ... a^1 a^0
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_COEFFS_HELP[0][j] = 1; /* e0 */
|
||||
GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */
|
||||
}
|
||||
|
||||
|
||||
/* resolve equation system for parity byte 0 and 1 */
|
||||
|
||||
/* e1' = e1 + e0 */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j],
|
||||
GF8_COEFFS_HELP[0][j]);
|
||||
}
|
||||
|
||||
/* e1'' = e1' / (a^1 + 1) */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]);
|
||||
}
|
||||
|
||||
/* e0' = e0 + e1 / a^1 */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j],
|
||||
gf8_div(GF8_COEFFS_HELP[1][j],
|
||||
GF8_ILOG[1]));
|
||||
}
|
||||
|
||||
/* e0'' = e0' / (1 + 1 / a^1) */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the products of 0..255 with all of the Q coefficients in
|
||||
* advance. When building the scalar product between the data vectors
|
||||
* and the P/Q vectors the individual products can be looked up in
|
||||
* this table
|
||||
*
|
||||
* The P parity coefficients are just a subset of the Q coefficients so
|
||||
* that we do not need to create a separate table for them.
|
||||
*/
|
||||
|
||||
for (j = 0; j < 43; j++) {
|
||||
|
||||
table[j][0] = 0;
|
||||
|
||||
for (i = 1; i < 256; i++) {
|
||||
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]];
|
||||
if (c >= 255) c -= 255;
|
||||
table[j][i] = GF8_ILOG[c];
|
||||
|
||||
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]];
|
||||
if (c >= 255) c -= 255;
|
||||
table[j][i] |= GF8_ILOG[c]<<8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'.
|
||||
*/
|
||||
static u_int32_t mirror_bits(u_int32_t d, int bits)
|
||||
{
|
||||
int i;
|
||||
u_int32_t r = 0;
|
||||
|
||||
for (i = 0; i < bits; i++) {
|
||||
r <<= 1;
|
||||
|
||||
if ((d & 0x1) != 0)
|
||||
r |= 0x1;
|
||||
|
||||
d >>= 1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide
|
||||
* and reversed (i.e. the bit stream is divided by the EDC_POLY with the
|
||||
* LSB first order).
|
||||
*/
|
||||
CrcTable::CrcTable ()
|
||||
{
|
||||
u_int32_t i, j;
|
||||
u_int32_t r;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
r = mirror_bits(i, 8);
|
||||
|
||||
r <<= 24;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if ((r & 0x80000000) != 0) {
|
||||
r <<= 1;
|
||||
r ^= EDC_POLY;
|
||||
}
|
||||
else {
|
||||
r <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
r = mirror_bits(r, 32);
|
||||
|
||||
table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates the CRC of given data with given lengths based on the
|
||||
* table lookup algorithm.
|
||||
*/
|
||||
static u_int32_t calc_edc(u_int8_t *data, int len)
|
||||
{
|
||||
u_int32_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
crc = CRCTABLE[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Build the scramble table as defined in the yellow book. The bytes
|
||||
12 to 2351 of a sector will be XORed with the data of this table.
|
||||
*/
|
||||
ScrambleTable::ScrambleTable()
|
||||
{
|
||||
u_int16_t i, j;
|
||||
u_int16_t reg = 1;
|
||||
u_int8_t d;
|
||||
|
||||
for (i = 0; i < 2340; i++) {
|
||||
d = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
d >>= 1;
|
||||
|
||||
if ((reg & 0x1) != 0)
|
||||
d |= 0x80;
|
||||
|
||||
if ((reg & 0x1) != ((reg >> 1) & 0x1)) {
|
||||
reg >>= 1;
|
||||
reg |= 0x4000; /* 15-bit register */
|
||||
}
|
||||
else {
|
||||
reg >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
table[i] = d;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calc EDC for a MODE 1 sector
|
||||
*/
|
||||
static void calc_mode1_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16);
|
||||
|
||||
sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Calc EDC for a XA form 1 sector
|
||||
*/
|
||||
static void calc_mode2_form1_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
|
||||
LEC_MODE2_FORM1_DATA_LEN);
|
||||
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Calc EDC for a XA form 2 sector
|
||||
*/
|
||||
static void calc_mode2_form2_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
|
||||
LEC_MODE2_FORM2_DATA_LEN);
|
||||
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Writes the sync pattern to the given sector.
|
||||
*/
|
||||
static void set_sync_pattern(u_int8_t *sector)
|
||||
{
|
||||
sector[0] = 0;
|
||||
|
||||
sector[1] = sector[2] = sector[3] = sector[4] = sector[5] =
|
||||
sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff;
|
||||
|
||||
sector[11] = 0;
|
||||
}
|
||||
|
||||
|
||||
static u_int8_t bin2bcd(u_int8_t b)
|
||||
{
|
||||
return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f);
|
||||
}
|
||||
|
||||
/* Builds the sector header.
|
||||
*/
|
||||
static void set_sector_header(u_int8_t mode, u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75));
|
||||
sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60);
|
||||
sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75);
|
||||
sector[LEC_HEADER_OFFSET + 3] = mode;
|
||||
}
|
||||
|
||||
/* Calculate the P parities for the sector.
|
||||
* The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
|
||||
*/
|
||||
static void calc_P_parity(u_int8_t *sector)
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t p01_msb, p01_lsb;
|
||||
u_int8_t *p_lsb_start;
|
||||
u_int8_t *p_lsb;
|
||||
u_int8_t *p0, *p1;
|
||||
u_int8_t d0,d1;
|
||||
|
||||
p_lsb_start = sector + LEC_HEADER_OFFSET;
|
||||
|
||||
p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
|
||||
p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
|
||||
|
||||
for (i = 0; i <= 42; i++) {
|
||||
p_lsb = p_lsb_start;
|
||||
|
||||
p01_lsb = p01_msb = 0;
|
||||
|
||||
for (j = 19; j <= 42; j++) {
|
||||
d0 = *p_lsb;
|
||||
d1 = *(p_lsb+1);
|
||||
|
||||
p01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
|
||||
p01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
|
||||
|
||||
p_lsb += 2 * 43;
|
||||
}
|
||||
|
||||
*p0 = p01_lsb;
|
||||
*(p0 + 1) = p01_msb;
|
||||
|
||||
*p1 = p01_lsb>>8;
|
||||
*(p1 + 1) = p01_msb>>8;
|
||||
|
||||
p0 += 2;
|
||||
p1 += 2;
|
||||
|
||||
p_lsb_start += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the Q parities for the sector.
|
||||
* The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
|
||||
*/
|
||||
static void calc_Q_parity(u_int8_t *sector)
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t q01_lsb, q01_msb;
|
||||
u_int8_t *q_lsb_start;
|
||||
u_int8_t *q_lsb;
|
||||
u_int8_t *q0, *q1, *q_start;
|
||||
u_int8_t d0,d1;
|
||||
|
||||
q_lsb_start = sector + LEC_HEADER_OFFSET;
|
||||
|
||||
q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
||||
q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
||||
q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
|
||||
|
||||
for (i = 0; i <= 25; i++) {
|
||||
q_lsb = q_lsb_start;
|
||||
|
||||
q01_lsb = q01_msb = 0;
|
||||
|
||||
for (j = 0; j <= 42; j++) {
|
||||
d0 = *q_lsb;
|
||||
d1 = *(q_lsb+1);
|
||||
|
||||
q01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
|
||||
q01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
|
||||
|
||||
q_lsb += 2 * 44;
|
||||
|
||||
if (q_lsb >= q_start) {
|
||||
q_lsb -= 2 * 1118;
|
||||
}
|
||||
}
|
||||
|
||||
*q0 = q01_lsb;
|
||||
*(q0 + 1) = q01_msb;
|
||||
|
||||
*q1 = q01_lsb>>8;
|
||||
*(q1 + 1) = q01_msb>>8;
|
||||
|
||||
q0 += 2;
|
||||
q1 += 2;
|
||||
|
||||
q_lsb_start += 2 * 43;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encodes a MODE 0 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide
|
||||
*/
|
||||
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
u_int16_t i;
|
||||
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(0, adr, sector);
|
||||
|
||||
sector += 16;
|
||||
|
||||
for (i = 0; i < 2336; i++)
|
||||
*sector++ = 0;
|
||||
}
|
||||
|
||||
/* Encodes a MODE 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(1, adr, sector);
|
||||
|
||||
calc_mode1_edc(sector);
|
||||
|
||||
/* clear the intermediate field */
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0;
|
||||
|
||||
calc_P_parity(sector);
|
||||
calc_Q_parity(sector);
|
||||
}
|
||||
|
||||
/* Encodes a MODE 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Encodes a XA form 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
|
||||
calc_mode2_form1_edc(sector);
|
||||
|
||||
/* P/Q partiy must not contain the sector header so clear it */
|
||||
sector[LEC_HEADER_OFFSET] =
|
||||
sector[LEC_HEADER_OFFSET + 1] =
|
||||
sector[LEC_HEADER_OFFSET + 2] =
|
||||
sector[LEC_HEADER_OFFSET + 3] = 0;
|
||||
|
||||
calc_P_parity(sector);
|
||||
calc_Q_parity(sector);
|
||||
|
||||
/* finally add the sector header */
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Encodes a XA form 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
|
||||
calc_mode2_form2_edc(sector);
|
||||
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Scrambles and byte swaps an encoded sector.
|
||||
* 'sector' must be 2352 byte wide.
|
||||
*/
|
||||
void lec_scramble(u_int8_t *sector)
|
||||
{
|
||||
u_int16_t i;
|
||||
const u_int8_t *stable = SCRAMBLE_TABLE;
|
||||
u_int8_t *p = sector;
|
||||
u_int8_t tmp;
|
||||
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
/* just swap bytes of sector sync */
|
||||
tmp = *p;
|
||||
*p = *(p + 1);
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
for (;i < (2352 / 2); i++) {
|
||||
/* scramble and swap bytes */
|
||||
tmp = *p ^ *stable++;
|
||||
*p = *(p + 1) ^ *stable++;
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *infile;
|
||||
char *outfile;
|
||||
int fd_in, fd_out;
|
||||
u_int8_t buffer1[2352];
|
||||
u_int8_t buffer2[2352];
|
||||
u_int32_t lba;
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < 2048; i++)
|
||||
buffer1[i + 16] = 234;
|
||||
|
||||
lba = 150;
|
||||
|
||||
for (i = 0; i < 100000; i++) {
|
||||
lec_encode_mode1_sector(lba, buffer1);
|
||||
lec_scramble(buffer2);
|
||||
lba++;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (argc != 3)
|
||||
return 1;
|
||||
|
||||
infile = argv[1];
|
||||
outfile = argv[2];
|
||||
|
||||
|
||||
if ((fd_in = open(infile, O_RDONLY)) < 0) {
|
||||
perror("Cannot open input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd_out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
|
||||
perror("Cannot open output file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lba = 150;
|
||||
|
||||
do {
|
||||
if (read(fd_in, buffer1, 2352) != 2352)
|
||||
break;
|
||||
|
||||
switch (*(buffer1 + 12 + 3)) {
|
||||
case 1:
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048);
|
||||
|
||||
lec_encode_mode1_sector(lba, buffer2);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ((*(buffer1 + 12 + 4 + 2) & 0x20) != 0) {
|
||||
/* form 2 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2324 + 8);
|
||||
lec_encode_mode2_form2_sector(lba, buffer2);
|
||||
}
|
||||
else {
|
||||
/* form 1 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048 + 8);
|
||||
lec_encode_mode2_form1_sector(lba, buffer2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(buffer1, buffer2, 2352) != 0) {
|
||||
printf("Verify error at lba %ld\n", lba);
|
||||
}
|
||||
|
||||
lec_scramble(buffer2);
|
||||
write(fd_out, buffer2, 2352);
|
||||
|
||||
lba++;
|
||||
} while (1);
|
||||
|
||||
close(fd_in);
|
||||
close(fd_out);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
77
mednafen/cdrom/lec.h
Normal file
77
mednafen/cdrom/lec.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* cdrdao - write audio CD-Rs in disc-at-once mode
|
||||
*
|
||||
* Copyright (C) 1998-2002 Andreas Mueller <mueller@daneb.ping.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LEC_H__
|
||||
#define __LEC_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef uint32_t u_int32_t;
|
||||
typedef uint16_t u_int16_t;
|
||||
typedef uint8_t u_int8_t;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/* Encodes a MODE 0 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide
|
||||
*/
|
||||
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a MODE 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a MODE 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a XA form 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a XA form 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Scrambles and byte swaps an encoded sector.
|
||||
* 'sector' must be 2352 byte wide.
|
||||
*/
|
||||
void lec_scramble(u_int8_t *sector);
|
||||
|
||||
#endif
|
1165
mednafen/cdrom/pcecd.cpp
Normal file
1165
mednafen/cdrom/pcecd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
66
mednafen/cdrom/pcecd.h
Normal file
66
mednafen/cdrom/pcecd.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef __PCE_CDROM_H
|
||||
#define __PCE_CDROM_H
|
||||
|
||||
#include <blip/Blip_Buffer.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double CDDA_Volume;
|
||||
|
||||
unsigned int CD_Speed;
|
||||
|
||||
double ADPCM_Volume;
|
||||
|
||||
bool ADPCM_LPF;
|
||||
} PCECD_Settings;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
CD_GSREG_BSY = 0,
|
||||
CD_GSREG_REQ, // RO
|
||||
CD_GSREG_MSG, // RO
|
||||
CD_GSREG_CD, // RO
|
||||
CD_GSREG_IO, // RO
|
||||
CD_GSREG_SEL,
|
||||
|
||||
CD_GSREG_ADPCM_CONTROL,
|
||||
CD_GSREG_ADPCM_FREQ,
|
||||
CD_GSREG_ADPCM_CUR,
|
||||
CD_GSREG_ADPCM_WRADDR,
|
||||
CD_GSREG_ADPCM_RDADDR,
|
||||
CD_GSREG_ADPCM_LENGTH,
|
||||
CD_GSREG_ADPCM_PLAYNIBBLE,
|
||||
|
||||
CD_GSREG_ADPCM_PLAYING,
|
||||
CD_GSREG_ADPCM_HALFREACHED,
|
||||
CD_GSREG_ADPCM_ENDREACHED,
|
||||
};
|
||||
|
||||
uint32 PCECD_GetRegister(const unsigned int id, char *special, const uint32 special_len);
|
||||
void PCECD_SetRegister(const unsigned int id, const uint32 value);
|
||||
|
||||
|
||||
int32 PCECD_Run(uint32 in_timestamp) MDFN_WARN_UNUSED_RESULT;
|
||||
void PCECD_ResetTS(void);
|
||||
|
||||
bool PCECD_Init(const PCECD_Settings *settings, void (*irqcb)(bool), double master_clock, unsigned int ocm, Blip_Buffer *soundbuf_l, Blip_Buffer *soundbuf_r);
|
||||
bool PCECD_SetSettings(const PCECD_Settings *settings);
|
||||
|
||||
void PCECD_Close();
|
||||
|
||||
// Returns number of cycles until next CD event.
|
||||
int32 PCECD_Power(uint32 timestamp) MDFN_WARN_UNUSED_RESULT;
|
||||
|
||||
uint8 PCECD_Read(uint32 timestamp, uint32, int32 &next_event, const bool PeekMode = false);
|
||||
int32 PCECD_Write(uint32 timestamp, uint32, uint8 data) MDFN_WARN_UNUSED_RESULT;
|
||||
|
||||
bool PCECD_IsBRAMEnabled();
|
||||
|
||||
int PCECD_StateAction(StateMem *sm, int load, int data_only);
|
||||
|
||||
void ADPCM_PeekRAM(uint32 Address, uint32 Length, uint8 *Buffer);
|
||||
void ADPCM_PokeRAM(uint32 Address, uint32 Length, const uint8 *Buffer);
|
||||
|
||||
#endif
|
||||
|
203
mednafen/cdrom/recover-raw.cpp
Normal file
203
mednafen/cdrom/recover-raw.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
|
||||
static ReedSolomonTables *rt = NULL;
|
||||
|
||||
bool Init_LEC_Correct(void)
|
||||
{
|
||||
gt = CreateGaloisTables(0x11d);
|
||||
rt = CreateReedSolomonTables(gt, 0, 1, 10);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void Kill_LEC_Correct(void)
|
||||
{
|
||||
FreeGaloisTables(gt);
|
||||
FreeReedSolomonTables(rt);
|
||||
}
|
||||
|
||||
/***
|
||||
*** CD level CRC calculation
|
||||
***/
|
||||
|
||||
/*
|
||||
* Test raw sector against its 32bit CRC.
|
||||
* Returns TRUE if frame is good.
|
||||
*/
|
||||
|
||||
int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
|
||||
{
|
||||
unsigned int expected_crc, real_crc;
|
||||
unsigned int crc_base = xa_mode ? 2072 : 2064;
|
||||
|
||||
expected_crc = cd_frame[crc_base + 0] << 0;
|
||||
expected_crc |= cd_frame[crc_base + 1] << 8;
|
||||
expected_crc |= cd_frame[crc_base + 2] << 16;
|
||||
expected_crc |= cd_frame[crc_base + 3] << 24;
|
||||
|
||||
if(xa_mode)
|
||||
real_crc = EDCCrc32(cd_frame+16, 2056);
|
||||
else
|
||||
real_crc = EDCCrc32(cd_frame, 2064);
|
||||
|
||||
if(expected_crc == real_crc)
|
||||
return(1);
|
||||
else
|
||||
{
|
||||
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
*** A very simple L-EC error correction.
|
||||
***
|
||||
* Perform just one pass over the Q and P vectors to see if everything
|
||||
* is okay respectively correct minor errors. This is pretty much the
|
||||
* same stuff the drive is supposed to do in the final L-EC stage.
|
||||
*/
|
||||
|
||||
static int simple_lec(unsigned char *frame)
|
||||
{
|
||||
unsigned char byte_state[2352];
|
||||
unsigned char p_vector[P_VECTOR_SIZE];
|
||||
unsigned char q_vector[Q_VECTOR_SIZE];
|
||||
unsigned char p_state[P_VECTOR_SIZE];
|
||||
int erasures[Q_VECTOR_SIZE], erasure_count;
|
||||
int ignore[2];
|
||||
int p_failures, q_failures;
|
||||
int p_corrected, q_corrected;
|
||||
int p,q;
|
||||
|
||||
/* Setup */
|
||||
|
||||
memset(byte_state, 0, 2352);
|
||||
|
||||
p_failures = q_failures = 0;
|
||||
p_corrected = q_corrected = 0;
|
||||
|
||||
/* Perform Q-Parity error correction */
|
||||
|
||||
for(q=0; q<N_Q_VECTORS; q++)
|
||||
{ int err;
|
||||
|
||||
/* We have no erasure information for Q vectors */
|
||||
|
||||
GetQVector(frame, q_vector, q);
|
||||
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
|
||||
|
||||
/* See what we've got */
|
||||
|
||||
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
|
||||
{ q_failures++;
|
||||
FillQVector(byte_state, 1, q);
|
||||
}
|
||||
else /* Correctable */
|
||||
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{ SetQVector(frame, q_vector, q);
|
||||
q_corrected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform P-Parity error correction */
|
||||
|
||||
for(p=0; p<N_P_VECTORS; p++)
|
||||
{ int err,i;
|
||||
|
||||
/* Try error correction without erasure information */
|
||||
|
||||
GetPVector(frame, p_vector, p);
|
||||
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
|
||||
|
||||
/* If unsuccessful, try again using erasures.
|
||||
Erasure information is uncertain, so try this last. */
|
||||
|
||||
if(err < 0 || err > 2)
|
||||
{ GetPVector(byte_state, p_state, p);
|
||||
erasure_count = 0;
|
||||
|
||||
for(i=0; i<P_VECTOR_SIZE; i++)
|
||||
if(p_state[i])
|
||||
erasures[erasure_count++] = i;
|
||||
|
||||
if(erasure_count > 0 && erasure_count <= 2)
|
||||
{ GetPVector(frame, p_vector, p);
|
||||
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
|
||||
}
|
||||
}
|
||||
|
||||
/* See what we've got */
|
||||
|
||||
if(err < 0) /* Uncorrectable. */
|
||||
{ p_failures++;
|
||||
}
|
||||
else /* Correctable. */
|
||||
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{ SetPVector(frame, p_vector, p);
|
||||
p_corrected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sum up */
|
||||
|
||||
if(q_failures || p_failures || q_corrected || p_corrected)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***
|
||||
*** Validate CD raw sector
|
||||
***/
|
||||
|
||||
int ValidateRawSector(unsigned char *frame, bool xaMode)
|
||||
{
|
||||
int lec_did_sth = FALSE;
|
||||
|
||||
/* Do simple L-EC.
|
||||
It seems that drives stop their internal L-EC as soon as the
|
||||
EDC is okay, so we may see uncorrected errors in the parity bytes.
|
||||
Since we are also interested in the user data only and doing the
|
||||
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
|
||||
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
{
|
||||
lec_did_sth = simple_lec(frame);
|
||||
}
|
||||
/* Test internal sector checksum again */
|
||||
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
{
|
||||
/* EDC failure in RAW sector */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
269
mednafen/cdrom/scsicd-pce-commands.inc
Normal file
269
mednafen/cdrom/scsicd-pce-commands.inc
Normal file
@ -0,0 +1,269 @@
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xD8 - SAPSP *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_SAPSP(const uint8 *cdb)
|
||||
{
|
||||
uint32 new_read_sec_start;
|
||||
|
||||
//printf("Set audio start: %02x %02x %02x %02x %02x %02x %02x\n", cdb[9], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6]);
|
||||
switch (cdb[9] & 0xc0)
|
||||
{
|
||||
default: SCSIDBG("Unknown SAPSP 9: %02x\n", cdb[9]);
|
||||
case 0x00:
|
||||
new_read_sec_start = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
new_read_sec_start = AMSF_to_LBA(BCD_to_U8(cdb[2]), BCD_to_U8(cdb[3]), BCD_to_U8(cdb[4]));
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
int track = BCD_to_U8(cdb[2]);
|
||||
|
||||
if(!track)
|
||||
track = 1;
|
||||
else if(track == toc.last_track + 1)
|
||||
track = 100;
|
||||
else if(track > toc.last_track)
|
||||
{
|
||||
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_END_OF_VOLUME);
|
||||
return;
|
||||
}
|
||||
new_read_sec_start = toc.tracks[track].lba;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("%lld\n", (long long)(monotonic_timestamp - pce_lastsapsp_timestamp) * 1000 / System_Clock);
|
||||
if(cdda.CDDAStatus == CDDASTATUS_PLAYING && new_read_sec_start == read_sec_start && ((int64)(monotonic_timestamp - pce_lastsapsp_timestamp) * 1000 / System_Clock) < 190)
|
||||
{
|
||||
pce_lastsapsp_timestamp = monotonic_timestamp;
|
||||
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
pce_lastsapsp_timestamp = monotonic_timestamp;
|
||||
|
||||
read_sec = read_sec_start = new_read_sec_start;
|
||||
read_sec_end = toc.tracks[100].lba;
|
||||
|
||||
|
||||
cdda.CDDAReadPos = 588;
|
||||
|
||||
cdda.CDDAStatus = CDDASTATUS_PAUSED;
|
||||
cdda.PlayMode = PLAYMODE_SILENT;
|
||||
|
||||
if(cdb[1])
|
||||
{
|
||||
cdda.PlayMode = PLAYMODE_NORMAL;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
}
|
||||
|
||||
if(read_sec < toc.tracks[100].lba)
|
||||
Cur_CDIF->HintReadSector(read_sec);
|
||||
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xD9 - SAPEP *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_SAPEP(const uint8 *cdb)
|
||||
{
|
||||
uint32 new_read_sec_end;
|
||||
|
||||
//printf("Set audio end: %02x %02x %02x %02x %02x %02x %02x\n", cdb[9], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6]);
|
||||
|
||||
switch (cdb[9] & 0xc0)
|
||||
{
|
||||
default: SCSIDBG("Unknown SAPEP 9: %02x\n", cdb[9]);
|
||||
|
||||
case 0x00:
|
||||
new_read_sec_end = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
new_read_sec_end = BCD_to_U8(cdb[4]) + 75 * (BCD_to_U8(cdb[3]) + 60 * BCD_to_U8(cdb[2]));
|
||||
new_read_sec_end -= 150;
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
int track = BCD_to_U8(cdb[2]);
|
||||
|
||||
if(!track)
|
||||
track = 1;
|
||||
else if(track == toc.last_track + 1)
|
||||
track = 100;
|
||||
else if(track > toc.last_track)
|
||||
{
|
||||
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_END_OF_VOLUME);
|
||||
return;
|
||||
}
|
||||
new_read_sec_end = toc.tracks[track].lba;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
read_sec_end = new_read_sec_end;
|
||||
|
||||
switch(cdb[1]) // PCE CD(TODO: Confirm these, and check the mode mask):
|
||||
{
|
||||
default:
|
||||
case 0x03: cdda.PlayMode = PLAYMODE_NORMAL;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
break;
|
||||
|
||||
case 0x02: cdda.PlayMode = PLAYMODE_INTERRUPT;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
break;
|
||||
|
||||
case 0x01: cdda.PlayMode = PLAYMODE_LOOP;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
break;
|
||||
|
||||
case 0x00: cdda.PlayMode = PLAYMODE_SILENT;
|
||||
cdda.CDDAStatus = CDDASTATUS_STOPPED;
|
||||
break;
|
||||
}
|
||||
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xDA - Pause *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_PAUSE(const uint8 *cdb)
|
||||
{
|
||||
if(cdda.CDDAStatus != CDDASTATUS_STOPPED) // Hmm, should we give an error if it tries to pause and it's already paused?
|
||||
{
|
||||
cdda.CDDAStatus = CDDASTATUS_PAUSED;
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
}
|
||||
else // Definitely give an error if it tries to pause when no track is playing!
|
||||
{
|
||||
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_AUDIO_NOT_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xDD - Read Subchannel Q *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_READSUBQ(const uint8 *cdb)
|
||||
{
|
||||
uint8 *SubQBuf = cd.SubQBuf[QMode_Time];
|
||||
uint8 data_in[8192];
|
||||
|
||||
memset(data_in, 0x00, 10);
|
||||
|
||||
data_in[2] = SubQBuf[1]; // Track
|
||||
data_in[3] = SubQBuf[2]; // Index
|
||||
data_in[4] = SubQBuf[3]; // M(rel)
|
||||
data_in[5] = SubQBuf[4]; // S(rel)
|
||||
data_in[6] = SubQBuf[5]; // F(rel)
|
||||
data_in[7] = SubQBuf[7]; // M(abs)
|
||||
data_in[8] = SubQBuf[8]; // S(abs)
|
||||
data_in[9] = SubQBuf[9]; // F(abs)
|
||||
|
||||
if(cdda.CDDAStatus == CDDASTATUS_PAUSED)
|
||||
data_in[0] = 2; // Pause
|
||||
else if(cdda.CDDAStatus == CDDASTATUS_PLAYING || cdda.CDDAStatus == CDDASTATUS_SCANNING) // FIXME: Is this the correct status code for scanning playback?
|
||||
data_in[0] = 0; // Playing
|
||||
else
|
||||
data_in[0] = 3; // Stopped
|
||||
|
||||
DoSimpleDataIn(data_in, 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xDE - Get Directory Info *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_GETDIRINFO(const uint8 *cdb)
|
||||
{
|
||||
// Problems:
|
||||
// Returned data lengths on real PCE are not confirmed.
|
||||
// Mode 0x03 behavior not tested on real PCE
|
||||
|
||||
uint8 data_in[2048];
|
||||
uint32 data_in_size = 0;
|
||||
|
||||
memset(data_in, 0, sizeof(data_in));
|
||||
|
||||
switch(cdb[1])
|
||||
{
|
||||
default: MDFN_DispMessage("Unknown GETDIRINFO Mode: %02x", cdb[1]);
|
||||
printf("Unknown GETDIRINFO Mode: %02x", cdb[1]);
|
||||
case 0x0:
|
||||
data_in[0] = U8_to_BCD(toc.first_track);
|
||||
data_in[1] = U8_to_BCD(toc.last_track);
|
||||
|
||||
data_in_size = 2;
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
{
|
||||
uint8 m, s, f;
|
||||
|
||||
LBA_to_AMSF(toc.tracks[100].lba, &m, &s, &f);
|
||||
|
||||
data_in[0] = U8_to_BCD(m);
|
||||
data_in[1] = U8_to_BCD(s);
|
||||
data_in[2] = U8_to_BCD(f);
|
||||
|
||||
data_in_size = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
{
|
||||
uint8 m, s, f;
|
||||
int track = BCD_to_U8(cdb[2]);
|
||||
|
||||
if(!track)
|
||||
track = 1;
|
||||
else if(cdb[2] == 0xAA)
|
||||
{
|
||||
track = 100;
|
||||
}
|
||||
else if(track > 99)
|
||||
{
|
||||
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
|
||||
|
||||
data_in[0] = U8_to_BCD(m);
|
||||
data_in[1] = U8_to_BCD(s);
|
||||
data_in[2] = U8_to_BCD(f);
|
||||
data_in[3] = toc.tracks[track].control;
|
||||
data_in_size = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DoSimpleDataIn(data_in, data_in_size);
|
||||
}
|
||||
|
3107
mednafen/cdrom/scsicd.cpp
Normal file
3107
mednafen/cdrom/scsicd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
101
mednafen/cdrom/scsicd.h
Normal file
101
mednafen/cdrom/scsicd.h
Normal file
@ -0,0 +1,101 @@
|
||||
#ifndef __PCFX_SCSICD_H
|
||||
#define __PCFX_SCSICD_H
|
||||
|
||||
#include <blip/Blip_Buffer.h>
|
||||
|
||||
typedef int32 scsicd_timestamp_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Data bus(FIXME: we should have a variable for the target and the initiator, and OR them together to be truly accurate).
|
||||
uint8 DB;
|
||||
|
||||
uint32 signals;
|
||||
|
||||
// Signals under our(the "target") control.
|
||||
//bool BSY, MSG, CD, REQ, IO;
|
||||
|
||||
// Signals under the control of the initiator(not us!)
|
||||
//bool kingACK, kingRST, kingSEL, kingATN;
|
||||
} scsicd_bus_t;
|
||||
|
||||
extern scsicd_bus_t cd_bus; // Don't access this structure directly by name outside of scsicd.c, but use the macros below.
|
||||
|
||||
// Signals under our(the "target") control.
|
||||
#define SCSICD_IO_mask 0x001
|
||||
#define SCSICD_CD_mask 0x002
|
||||
#define SCSICD_MSG_mask 0x004
|
||||
#define SCSICD_REQ_mask 0x008
|
||||
#define SCSICD_BSY_mask 0x010
|
||||
|
||||
// Signals under the control of the initiator(not us!)
|
||||
#define SCSICD_kingRST_mask 0x020
|
||||
#define SCSICD_kingACK_mask 0x040
|
||||
#define SCSICD_kingATN_mask 0x080
|
||||
#define SCSICD_kingSEL_mask 0x100
|
||||
|
||||
#define BSY_signal ((const bool)(cd_bus.signals & SCSICD_BSY_mask))
|
||||
#define ACK_signal ((const bool)(cd_bus.signals & SCSICD_kingACK_mask))
|
||||
#define RST_signal ((const bool)(cd_bus.signals & SCSICD_kingRST_mask))
|
||||
#define MSG_signal ((const bool)(cd_bus.signals & SCSICD_MSG_mask))
|
||||
#define SEL_signal ((const bool)(cd_bus.signals & SCSICD_kingSEL_mask))
|
||||
#define REQ_signal ((const bool)(cd_bus.signals & SCSICD_REQ_mask))
|
||||
#define IO_signal ((const bool)(cd_bus.signals & SCSICD_IO_mask))
|
||||
#define CD_signal ((const bool)(cd_bus.signals & SCSICD_CD_mask))
|
||||
#define ATN_signal ((const bool)(cd_bus.signals & SCSICD_kingATN_mask))
|
||||
|
||||
#define DB_signal ((const uint8)cd_bus.DB)
|
||||
|
||||
#define SCSICD_GetDB() DB_signal
|
||||
#define SCSICD_GetBSY() BSY_signal
|
||||
#define SCSICD_GetIO() IO_signal
|
||||
#define SCSICD_GetCD() CD_signal
|
||||
#define SCSICD_GetMSG() MSG_signal
|
||||
#define SCSICD_GetREQ() REQ_signal
|
||||
|
||||
// Should we phase out getting these initiator-driven signals like this(the initiator really should keep track of them itself)?
|
||||
#define SCSICD_GetACK() ACK_signal
|
||||
#define SCSICD_GetRST() RST_signal
|
||||
#define SCSICD_GetSEL() SEL_signal
|
||||
#define SCSICD_GetATN() ATN_signal
|
||||
|
||||
void SCSICD_Power(scsicd_timestamp_t system_timestamp);
|
||||
void SCSICD_SetDB(uint8 data);
|
||||
|
||||
// These SCSICD_Set* functions are kind of misnomers, at least in comparison to the SCSICD_Get* functions...
|
||||
// They will set/clear the bits corresponding to the KING's side of the bus.
|
||||
void SCSICD_SetACK(bool set);
|
||||
void SCSICD_SetSEL(bool set);
|
||||
void SCSICD_SetRST(bool set);
|
||||
void SCSICD_SetATN(bool set);
|
||||
|
||||
uint32 SCSICD_Run(scsicd_timestamp_t);
|
||||
void SCSICD_ResetTS(void);
|
||||
|
||||
enum
|
||||
{
|
||||
SCSICD_PCE = 1,
|
||||
SCSICD_PCFX
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCSICD_IRQ_DATA_TRANSFER_DONE = 1,
|
||||
SCSICD_IRQ_DATA_TRANSFER_READY,
|
||||
SCSICD_IRQ_MAGICAL_REQ,
|
||||
};
|
||||
|
||||
void SCSICD_GetCDDAValues(int16 &left, int16 &right);
|
||||
|
||||
void SCSICD_SetLog(void (*logfunc)(const char *, const char *, ...));
|
||||
|
||||
void SCSICD_Init(int type, int CDDATimeDiv, Blip_Buffer *leftbuf, Blip_Buffer *rightbuf, uint32 TransferRate, uint32 SystemClock, void (*IRQFunc)(int), void (*SSCFunc)(uint8, int));
|
||||
void SCSICD_Close(void);
|
||||
|
||||
void SCSICD_SetTransferRate(uint32 TransferRate);
|
||||
void SCSICD_SetCDDAVolume(double left, double right);
|
||||
int SCSICD_StateAction(StateMem *sm, int load, int data_only, const char *sname);
|
||||
|
||||
void SCSICD_SetDisc(bool tray_open, CDIF *cdif, bool no_emu_side_effects = false);
|
||||
|
||||
#endif
|
35
mednafen/clamp.h
Normal file
35
mednafen/clamp.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __MDFN_CLAMP_H
|
||||
#define __MDFN_CLAMP_H
|
||||
|
||||
static INLINE int32 clamp_to_u8(int32 i)
|
||||
{
|
||||
if(i & 0xFFFFFF00)
|
||||
i = (((~i) >> 30) & 0xFF);
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
|
||||
static INLINE int32 clamp_to_u16(int32 i)
|
||||
{
|
||||
if(i & 0xFFFF0000)
|
||||
i = (((~i) >> 31) & 0xFFFF);
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
template<typename T, typename U, typename V> static INLINE void clamp(T *val, U minimum, V maximum)
|
||||
{
|
||||
if(*val < minimum)
|
||||
{
|
||||
//printf("Warning: clamping to minimum(%d)\n", (int)minimum);
|
||||
*val = minimum;
|
||||
}
|
||||
if(*val > maximum)
|
||||
{
|
||||
//printf("Warning: clamping to maximum(%d)\n", (int)maximum);
|
||||
*val = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
1
mednafen/compress/Makefile.am.inc
Normal file
1
mednafen/compress/Makefile.am.inc
Normal file
@ -0,0 +1 @@
|
||||
mednafen_SOURCES += compress/minilzo.c compress/quicklz.c compress/blz.cpp compress/ioapi.c compress/unzip.c
|
982
mednafen/compress/blz.c
Normal file
982
mednafen/compress/blz.c
Normal file
@ -0,0 +1,982 @@
|
||||
/* Configuration macros. If undefined, it is automatically configured, otherwise its
|
||||
value (0 or 1) determines the setting. */
|
||||
|
||||
/* Enable/disable use of negative/positive sign for faster high bit testing */
|
||||
/*#define BLZ_USE_SIGN 1 */
|
||||
|
||||
/* Enable/disable fast version that makes unaligned memory accesses. Fast version
|
||||
uses all the following flags. Portable version only uses BLZ_USE_SIGN flag. */
|
||||
/*#define BLZ_FAST 1 */
|
||||
|
||||
/* Enable/disable use count leading zeros operation */
|
||||
/*#define BLZ_FAST_CLZ 1 */
|
||||
|
||||
/* Big/little endian override. Only needs to be set if assertion in blz_pack() fails.
|
||||
Can happen on processors which support both byte orders and are using the less-common
|
||||
one, like little-endian PowerPC or big-endian ARM. */
|
||||
/*#define BLZ_BIG_ENDIAN 1 */
|
||||
|
||||
/* Restricted pointer keyword. Auto configured for GCC and Microsoft, others might
|
||||
use plain restrict. */
|
||||
/*#define BLZ_RESTRICT restrict */
|
||||
|
||||
/* blz 0.9.1. http://www.slack.net/~ant/ */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "blz.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Copyright (C) 2007 Shay Green. This module is free software; you can
|
||||
redistribute it and/or modify it under the terms of the GNU General Public
|
||||
License, version 2 or later, as published by the Free Software Foundation.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details. You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
|
||||
|
||||
/* Comments with percentages are how often the condition is true */
|
||||
|
||||
/* Data format: [32-bit length] [block 1] [block 2] ... [32-bit data 0] [16-bit data 0]
|
||||
|
||||
block: [32 bits] [symbol 0] [symbol 1] ... [symbol 30]
|
||||
|
||||
Bits tell whether a symbol is a literal byte (1) or match (0), starting at bit 0.
|
||||
Highest bit set is an end marker, so a block can have at most 31 symbols.
|
||||
Matches are encoded in three ways.
|
||||
|
||||
Short match [3-bit length | 13-bit offset]
|
||||
Mid match [5-bit length] [16-bit offset]
|
||||
Long match [8-bit data 0] [32-bit length] [32-bit offset] */
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
|
||||
/* Automatically optimize for known processors. Thanks http://predef.sourceforge.net/ */
|
||||
|
||||
#define BLZ_PPC (defined (__POWERPC__) || defined (__ppc__) || defined (_M_PPC) || defined (_POWER))
|
||||
|
||||
#if BLZ_PPC || defined (__m68k__)
|
||||
#ifndef BLZ_BIG_ENDIAN
|
||||
#define BLZ_BIG_ENDIAN 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BLZ_PPC || defined (__m68k__) || defined (__i386__) || defined (__x86_64__) || \
|
||||
defined (_M_IX86) || defined (_M_X64)
|
||||
#ifndef BLZ_FAST
|
||||
#define BLZ_FAST 1
|
||||
#endif
|
||||
#ifndef BLZ_FAST_CLZ
|
||||
#define BLZ_FAST_CLZ 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BLZ_RESTRICT
|
||||
#if __GNUC__ >= 3 || _MSC_VER
|
||||
#define BLZ_RESTRICT __restrict
|
||||
#else
|
||||
#define BLZ_RESTRICT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if INT_MAX != 0x7FFFFFFF || !BLZ_USE_SIGN
|
||||
typedef unsigned bits_t;
|
||||
#define TOP_BIT( n ) ((n) & 0x80000000u)
|
||||
#define ALL_BITS( n ) ((n) & 0xFFFFFFFFu)
|
||||
#else
|
||||
typedef int bits_t;
|
||||
#define TOP_BIT( n ) ((n) < 0)
|
||||
#define ALL_BITS( n ) (n)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**** Fast version ****/
|
||||
|
||||
#if BLZ_FAST
|
||||
|
||||
char const blz_version [] = "fast";
|
||||
|
||||
#if defined (HAVE_STDINT_H)
|
||||
#include <stdint.h>
|
||||
#elif defined (HAVE_INTTYPES_H)
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#if USHRT_MAX != 0xFFFF || UINT_MAX != 0xFFFFFFFF
|
||||
#error "Short must be 16 bits and int must be 32 bits"
|
||||
#endif
|
||||
/* macros instead of typedefs in case std headers have these typedefs */
|
||||
#define uint16_t unsigned short
|
||||
#define uint32_t unsigned int
|
||||
#define int32_t signed int
|
||||
#endif
|
||||
|
||||
#ifndef GET16
|
||||
#define GET16( addr ) (*(uint16_t const*) (addr))
|
||||
#define GET32( addr ) (*(uint32_t const*) (addr))
|
||||
#define GET32S( addr ) (*( int32_t const*) (addr))
|
||||
#define SET16( addr, in ) (void) (*(uint16_t*) (addr) = (uint16_t) (in))
|
||||
#define SET32( addr, in ) (void) (*(uint32_t*) (addr) = (uint32_t) (in))
|
||||
#endif
|
||||
|
||||
#if BLZ_BIG_ENDIAN
|
||||
#define BIG_LITTLE( big, little ) (big)
|
||||
#else
|
||||
#define BIG_LITTLE( big, little ) (little)
|
||||
#endif
|
||||
|
||||
#if BLZ_FAST_CLZ
|
||||
/* CLZ: count leading zeros, CTZ: count trailing zeros */
|
||||
#if __GNUC__ >= 4
|
||||
#define CLZ __builtin_clz
|
||||
#define CTZ __builtin_ctz
|
||||
#elif BLZ_PPC && (__GNUC__ >= 3 || __MWERKS__)
|
||||
#if __GNUC__
|
||||
#include <ppc_intrinsics.h>
|
||||
#endif
|
||||
#define CLZ __cntlzw
|
||||
#define CTZ( n ) (32 - __cntlzw( ((n) - 1) & ~(n) ))
|
||||
#endif
|
||||
|
||||
#ifdef CLZ
|
||||
#define COUNT_MATCH( n ) (BIG_LITTLE( CLZ( n ), CTZ( n ) ) >> 3)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CALC_HASH( n ) BIG_LITTLE( (n >> 20) ^ (n >> 8 & 0xFFF), ((n >> 12) ^ n) & 0xFFF )
|
||||
|
||||
#if BLZ_BIG_ENDIAN && BLZ_PPC
|
||||
/* optimizes out two instructions (unless compiler is really smart) */
|
||||
typedef int dict_entry_t;
|
||||
#define DICT_SHIFT( x, y ) \
|
||||
(((x) / ((1u << (y)) / sizeof (byte*))) & (0xFFF * sizeof (byte*)))
|
||||
#define DICT_ENTRY( d, n ) (DICT_SHIFT( n, 20 ) ^ DICT_SHIFT( n, 8 ))
|
||||
#define USE_ENTRY( d, o ) *(byte const**) ((byte*) d + o)
|
||||
#else
|
||||
typedef byte const** dict_entry_t;
|
||||
#define DICT_ENTRY( d, n ) &d [CALC_HASH( n )]
|
||||
#define USE_ENTRY( d, o ) *o
|
||||
#endif
|
||||
|
||||
/* Pack */
|
||||
|
||||
#define PRE_GOTO() \
|
||||
data = GET32( in )
|
||||
|
||||
#define GOTO_NEXT \
|
||||
if ( !TOP_BIT( bits ) ) /* 97% */ \
|
||||
goto match;\
|
||||
goto flush;
|
||||
|
||||
enum { in_max_offset = 11 }; /* 8+ byte match just before end will read this far ahead */
|
||||
|
||||
static int blz_pack_( byte const* const in_min, int const size,
|
||||
void* const out_min, blz_pack_t* const dict )
|
||||
{
|
||||
/* On 32-bit x86, only dict, in_max, out_max, and bits_out don't fit in registers */
|
||||
byte const* BLZ_RESTRICT in = in_min;
|
||||
byte const* const in_max = in + size - in_max_offset;
|
||||
|
||||
byte* out = (byte*) out_min;
|
||||
byte* const out_max = out + size;
|
||||
byte* out_bits;
|
||||
|
||||
bits_t bits = 2;
|
||||
unsigned data;
|
||||
|
||||
in += 4;
|
||||
SET32( out, size );
|
||||
out_bits = (out += 8);
|
||||
|
||||
literal_sub_4: /* Literal byte */
|
||||
{
|
||||
int const t = in [-4];
|
||||
in -= 3;
|
||||
PRE_GOTO();
|
||||
*out++ = t;
|
||||
if ( TOP_BIT( ++bits ) ) /* 3% */
|
||||
goto flush;
|
||||
}
|
||||
|
||||
match: /* Check for match and update dict */
|
||||
{
|
||||
/* calc dict entry and check for end of input */
|
||||
dict_entry_t const dict_offset = DICT_ENTRY( dict->dict, data );
|
||||
byte const* const BLZ_RESTRICT match = USE_ENTRY( dict->dict, dict_offset );
|
||||
bits <<= 1;
|
||||
if ( in >= in_max ) /* 1% */
|
||||
goto final_bytes;
|
||||
|
||||
/* read first 4 bytes of match and check match distance */
|
||||
{
|
||||
unsigned const match_first = GET32( match - 4 );
|
||||
if ( match > in ) /* 1% */
|
||||
goto literal;
|
||||
|
||||
/* compare first four bytes and update dict */
|
||||
USE_ENTRY( dict->dict, dict_offset ) = (in += 4);
|
||||
if ( (data ^= match_first) != 0 ) /* 74% */
|
||||
{
|
||||
int off = in - match;
|
||||
if ( BIG_LITTLE( data >> 8, data & 0x00FFFFFF ) ) /* 57% */
|
||||
goto literal_sub_4;
|
||||
if ( off >= (1 << 13) ) /* 19% */
|
||||
goto literal_sub_4;
|
||||
|
||||
/* 3 byte match */
|
||||
--in;
|
||||
PRE_GOTO();
|
||||
SET16( out, BIG_LITTLE( (1 << 13) | off, (off << 3) + 1 ) );
|
||||
out += 2;
|
||||
GOTO_NEXT
|
||||
}
|
||||
}
|
||||
|
||||
if ( (data = GET32( in ) ^ GET32( match )) != 0 ) /* 78% */
|
||||
{
|
||||
/* 4-7 byte match */
|
||||
int off = in - match;
|
||||
int len;
|
||||
#ifdef COUNT_MATCH
|
||||
len = COUNT_MATCH( data );
|
||||
in += len;
|
||||
len += 2;
|
||||
#else
|
||||
len = 2;
|
||||
if ( !(data & BIG_LITTLE( 0xFF000000, 0x000000FF )) ) /* 48% 5-7 byte match */
|
||||
{
|
||||
++in;
|
||||
len = 3;
|
||||
if ( !(data & BIG_LITTLE( 0x00FF0000, 0x0000FFFF )) ) /* 47% 6-7 byte match */
|
||||
{
|
||||
++in;
|
||||
len = 4;
|
||||
if ( !BIG_LITTLE( data >> 8, data & 0x00FF0000 ) ) /* 37% 7 byte match */
|
||||
{
|
||||
++in;
|
||||
len = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
PRE_GOTO(); /* TODO: could avoid this in 4-byte case since it's already read */
|
||||
|
||||
/* Encode offset and length */
|
||||
if ( off < (1 << 13) ) /* 82% */
|
||||
{
|
||||
/* LLLOOOOO OOOOOOOO */
|
||||
SET16( out, BIG_LITTLE( (len << 13) | off, (off << 3) + len ) );
|
||||
out += 2;
|
||||
GOTO_NEXT
|
||||
}
|
||||
|
||||
/* unsigned cast and <= helps PowerPC */
|
||||
if ( (unsigned) off <= (1 << 16) - 1 ) /* 91% */
|
||||
{
|
||||
/* 000LLLLL OOOOOOOO OOOOOOOO */
|
||||
*out = BIG_LITTLE( len, len << 3 );
|
||||
SET16( out + 1, off );
|
||||
out += 3;
|
||||
GOTO_NEXT
|
||||
}
|
||||
|
||||
in -= 2;
|
||||
in -= len;
|
||||
goto literal;
|
||||
}
|
||||
{
|
||||
/* 8+ byte match */
|
||||
byte const* const start = in + 2;
|
||||
int off = match - in;
|
||||
in += 4;
|
||||
{
|
||||
/* compare 4 bytes at a time */
|
||||
int temp;
|
||||
do
|
||||
{
|
||||
data = GET32( in );
|
||||
temp = GET32( in + off );
|
||||
if ( in >= in_max ) /* 1% */
|
||||
goto hit_end;
|
||||
in += 4;
|
||||
}
|
||||
while ( !(data ^= temp) ); /* 73% */
|
||||
|
||||
/* determine which of the 4 bytes matched */
|
||||
#ifdef COUNT_MATCH
|
||||
in += COUNT_MATCH( data );
|
||||
#else
|
||||
if ( !(data & BIG_LITTLE( 0xFF000000, 0x000000FF )) ) /* 64% */
|
||||
{
|
||||
++in;
|
||||
if ( !(data & BIG_LITTLE( 0x00FF0000, 0x0000FFFF )) ) /* 58% */
|
||||
{
|
||||
++in;
|
||||
if ( !BIG_LITTLE( data >> 8, data & 0x00FF0000 ) ) /* 45% */
|
||||
++in;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
hit_end:
|
||||
|
||||
/* Encode offset and length */
|
||||
{
|
||||
int len = in - start;
|
||||
in -= 4;
|
||||
off = -off;
|
||||
PRE_GOTO();
|
||||
|
||||
if ( len < (1 << 5) ) /* 90% */
|
||||
{
|
||||
/* unsigned cast and <= helps PowerPC */
|
||||
if ( (unsigned) off <= (1 << 16) - 1 ) /* 98% */
|
||||
{
|
||||
/* 000LLLLL OOOOOOOO OOOOOOOO */
|
||||
*out = BIG_LITTLE( len, len << 3 );
|
||||
SET16( out + 1, off );
|
||||
out += 3;
|
||||
GOTO_NEXT
|
||||
}
|
||||
|
||||
if ( len <= 9 - 2 ) /* 52% */
|
||||
{
|
||||
/* TODO: lame */
|
||||
in -= 2;
|
||||
in -= len;
|
||||
goto literal;
|
||||
}
|
||||
}
|
||||
|
||||
/* 00000000 OOOOOOOO OOOOOOOO OOOOOOOO OOOOOOOO LLLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL */
|
||||
*out = 0;
|
||||
SET32( out + 1, off );
|
||||
SET32( out + 5, len );
|
||||
out += 9;
|
||||
GOTO_NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* These two are at bottom of loop to make branches here positive and branches back
|
||||
negative, which helps CPUs that lack dynamic branch prediction */
|
||||
|
||||
literal: /* Literal byte */
|
||||
{
|
||||
int const t = *in++;
|
||||
PRE_GOTO();
|
||||
*out++ = t;
|
||||
if ( !TOP_BIT( ++bits ) ) /* 97% */
|
||||
goto match;
|
||||
}
|
||||
|
||||
flush: /* Flush bits */
|
||||
out += 4;
|
||||
SET32( out_bits - 4, (bits << 1) + 1 );
|
||||
out_bits = out;
|
||||
bits = 1;
|
||||
if ( out < out_max ) /* 99% */
|
||||
goto match;
|
||||
return -1; /* no compression */
|
||||
|
||||
final_bytes:
|
||||
/* Right-justify and flush final bits */
|
||||
#ifdef CLZ
|
||||
SET32( out_bits - 4, (bits + 1) << (CLZ( bits ) + 1) );
|
||||
#else
|
||||
++bits;
|
||||
if ( !(bits & 0xFFFF0000u) )
|
||||
bits <<= 16;
|
||||
|
||||
if ( !TOP_BIT( bits ) )
|
||||
while ( !TOP_BIT( bits <<= 1 ) ) { }
|
||||
bits <<= 1;
|
||||
|
||||
SET32( out_bits - 4, bits );
|
||||
#endif
|
||||
|
||||
/* Remaining bytes should be in narrow range */
|
||||
assert( in_max + in_max_offset - in >= in_max_offset - 6 );
|
||||
assert( in_max + in_max_offset - in <= in_max_offset + 1 );
|
||||
|
||||
{
|
||||
/* Copy final bytes */
|
||||
unsigned t0 = GET32( in_max + (in_max_offset - 12) );
|
||||
unsigned t1 = GET32( in_max + (in_max_offset - 8) );
|
||||
unsigned t2 = GET32( in_max + (in_max_offset - 4) );
|
||||
SET32( out, 0 ); /* End marker */
|
||||
SET32( out + 4, t0 );
|
||||
SET32( out + 8, t1 );
|
||||
SET32( out + 12, t2 );
|
||||
out += 16;
|
||||
}
|
||||
|
||||
return out - (byte*) out_min;
|
||||
}
|
||||
|
||||
int blz_pack( void const* in_min, int size, void* out, blz_pack_t* dict )
|
||||
{
|
||||
byte const* in = (byte const*) in_min;
|
||||
assert( (unsigned) size <= 0x7FFFFFFF );
|
||||
if ( size >= 31 && dict ) /* 31 repeated bytes compress to 34 bytes */
|
||||
{
|
||||
/* clear dict */
|
||||
byte const** dout = dict->dict;
|
||||
int count;
|
||||
in += 4;
|
||||
for ( count = 0x1000; count--; )
|
||||
*dout++ = in;
|
||||
in -= 4;
|
||||
|
||||
{
|
||||
int out_size = blz_pack_( in, size, out, dict );
|
||||
if ( (unsigned) out_size < (unsigned) size + 4 )
|
||||
return out_size;
|
||||
}
|
||||
}
|
||||
SET32( out, -size );
|
||||
memcpy( (byte*) out + 4, in, size );
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
/* If these assertions fail, enable the appropriate byte order macro at the
|
||||
top of this file */
|
||||
static byte const data [5] = { 0x12, 0x34, 0x56, 0x78, 0x9A };
|
||||
assert( GET32( data ) == BIG_LITTLE( 0x12345678, 0x78563412 ) );
|
||||
assert( GET32( data + 1 ) == BIG_LITTLE( 0x3456789A, 0x9A785634 ) );
|
||||
|
||||
{
|
||||
volatile bits_t i = 0x40000000;
|
||||
assert( !TOP_BIT( i ) && TOP_BIT( i << 1 ) && !TOP_BIT( i << 2 ) && !ALL_BITS( i << 2 ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return size + 4;
|
||||
}
|
||||
|
||||
/* Unpack */
|
||||
|
||||
int blz_size( void const* in )
|
||||
{
|
||||
int n = GET32S( in );
|
||||
if ( n < 0 )
|
||||
n = -n;
|
||||
return n;
|
||||
}
|
||||
|
||||
int blz_unpack( void const* in_min, void* out_min )
|
||||
{
|
||||
int out_size = GET32S( in_min );
|
||||
byte const* BLZ_RESTRICT in = (byte const*) in_min + 4;
|
||||
byte* out = (byte*) out_min;
|
||||
|
||||
if ( out_size > 0 )
|
||||
{
|
||||
byte* const out_end = out + out_size;
|
||||
|
||||
/* Everything fits in registers, even on 32-bit x86 */
|
||||
unsigned data;
|
||||
bits_t bits;
|
||||
|
||||
refill: /* Refill bits */
|
||||
bits = GET32( in );
|
||||
in += 4;
|
||||
data = GET16( in );
|
||||
if ( TOP_BIT( bits ) ) /* 48% */
|
||||
goto literal;
|
||||
if ( !bits ) /* 1% */
|
||||
goto final_bytes;
|
||||
|
||||
match: { /* Matching symbol */
|
||||
int off;
|
||||
bits <<= 1;
|
||||
off = BIG_LITTLE( data & 0x1FFF, data >> 3 );
|
||||
if ( !BIG_LITTLE( data >>= 13, data &= 0x07 ) ) /* 14% */
|
||||
goto long_match;
|
||||
copy_bytes:
|
||||
/*assert( data > 0 && (size_t) off <= (size_t) (out - (byte*) out_min) );*/
|
||||
|
||||
/* Copy bytes */
|
||||
off = -off;
|
||||
{
|
||||
byte* const end = out + 2 + data;
|
||||
SET32( out, GET32( out + off ) );
|
||||
if ( data > 2 ) /* 30% */
|
||||
{
|
||||
out += 4;
|
||||
do
|
||||
{
|
||||
SET32( out, GET32( out + off ) );
|
||||
out += 4;
|
||||
}
|
||||
while ( out < end ); /* 55% */
|
||||
}
|
||||
out = end;
|
||||
}
|
||||
in += 2;
|
||||
|
||||
data = GET16( in );
|
||||
if ( !TOP_BIT( bits ) ) /* 60% */
|
||||
goto match;
|
||||
literal:
|
||||
if ( ALL_BITS( bits <<= 1 ) == 0 ) /* 7% */
|
||||
goto refill;
|
||||
|
||||
/* Literal byte */
|
||||
*out++ = BIG_LITTLE( data >> 8, data );
|
||||
++in;
|
||||
|
||||
data = GET16( in );
|
||||
if ( TOP_BIT( bits ) ) /* 60% */
|
||||
goto literal;
|
||||
|
||||
/* Start decoding match */
|
||||
bits <<= 1;
|
||||
off = BIG_LITTLE( data & 0x1FFF, data >> 3 );
|
||||
if ( BIG_LITTLE( data >>= 13, data &= 0x07 ) != 0 ) /* 86% */
|
||||
goto copy_bytes;
|
||||
|
||||
/* Longer match encodings */
|
||||
long_match:
|
||||
data = BIG_LITTLE( off >> 8, off & 0x1F );
|
||||
++in;
|
||||
off = GET16( in );
|
||||
if ( data ) /* 92% */
|
||||
goto copy_bytes;
|
||||
|
||||
off = GET32( in );
|
||||
data = GET32( in + 4 );
|
||||
in += 6;
|
||||
goto copy_bytes;
|
||||
}
|
||||
|
||||
final_bytes: /* Copy final bytes */
|
||||
{
|
||||
unsigned t0 = GET32( in );
|
||||
unsigned t1 = GET32( in + 4 );
|
||||
unsigned t2 = GET32( in + 8 );
|
||||
SET32( out_end - 12, t0 );
|
||||
SET32( out_end - 8, t1 );
|
||||
SET32( out_end - 4, t2 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( out, in, (out_size = -out_size) );
|
||||
}
|
||||
return out_size;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/**** Slow version ****/
|
||||
|
||||
char const blz_version [] = "slow";
|
||||
|
||||
/* Makes heavy use of pre-increment since that is more efficient on popular RISC processors */
|
||||
|
||||
/* Pack */
|
||||
|
||||
#define PRE_GOTO( off ) \
|
||||
{\
|
||||
data = (in [off + 2] << 16) | (in [off + 1] << 8);\
|
||||
data |= *(in += off);\
|
||||
}
|
||||
|
||||
#define GOTO_NEXT \
|
||||
if ( !TOP_BIT( bits ) ) /* 97% */ \
|
||||
goto match;\
|
||||
goto flush;
|
||||
|
||||
enum { in_max_offset = 9 }; /* 8+ byte match just before end will read this far ahead */
|
||||
|
||||
static int blz_pack_( byte const* const in_min, int size,
|
||||
void* const out_min, blz_pack_t* const dict )
|
||||
{
|
||||
byte const* BLZ_RESTRICT in = in_min;
|
||||
byte const* const in_max = in + size - in_max_offset;
|
||||
|
||||
byte* out = (byte*) out_min;
|
||||
byte* const out_max = out + size;
|
||||
byte* out_bits;
|
||||
|
||||
unsigned data;
|
||||
bits_t bits = 2;
|
||||
|
||||
out [0] = size;
|
||||
out [1] = size >> 8;
|
||||
out [2] = size >> 16;
|
||||
out [3] = size >> 24;
|
||||
out [4] = in [0];
|
||||
out [5] = in [1];
|
||||
in += 2;
|
||||
out_bits = (out += 9);
|
||||
|
||||
literal: /* Literal byte */
|
||||
{
|
||||
int const t = *in;
|
||||
PRE_GOTO( 1 );
|
||||
*++out = t;
|
||||
if ( TOP_BIT( ++bits ) ) /* 3% */
|
||||
goto flush;
|
||||
}
|
||||
|
||||
match: /* Check for match and update dict */
|
||||
{
|
||||
/* get then update dict entry and handle end of input */
|
||||
int off = (data >> 12) ^ (data & 0xFFF);
|
||||
byte const* const BLZ_RESTRICT match = dict->dict [off];
|
||||
bits <<= 1;
|
||||
dict->dict [off] = in;
|
||||
if ( in >= in_max ) /* 1% */
|
||||
goto final_bytes;
|
||||
|
||||
/* compare first 3 bytes and pre-read 4th bytes */
|
||||
data ^= match [0];
|
||||
data ^= match [1] << 8;
|
||||
{
|
||||
unsigned const in3 = in [3];
|
||||
unsigned const match3 = match [3];
|
||||
if ( data != ((unsigned) match [2] << 16) ) /* 42% first 3 bytes don't match */
|
||||
goto literal;
|
||||
|
||||
off = in - match;
|
||||
if ( in3 != match3 ) /* 53% 3 byte match */
|
||||
{
|
||||
if ( off >= (1 << 13) ) /* 19% too far */
|
||||
goto literal;
|
||||
|
||||
/* LLLhhhhh llllllll */
|
||||
PRE_GOTO( 3 );
|
||||
*(out += 2) = off;
|
||||
out [-1] = (off >> 8) | (1 << 5);
|
||||
GOTO_NEXT
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* 4-7 byte match */
|
||||
int len = 2 << 5;
|
||||
if ( *(in += 4) == match [4] ) /* 59% */
|
||||
{
|
||||
len = 3 << 5;
|
||||
if ( *++in == match [5] ) /* 66% */
|
||||
{
|
||||
len = 4 << 5;
|
||||
if ( *++in == match [6] ) /* 71% */
|
||||
{
|
||||
len = 5 << 5;
|
||||
if ( *++in == match [7] ) /* 75% */
|
||||
goto long_match;
|
||||
}
|
||||
}
|
||||
}
|
||||
PRE_GOTO( 0 );
|
||||
|
||||
/* Encode offset and length */
|
||||
if ( off < (1 << 13) ) /* 82% */
|
||||
{
|
||||
/* LLLhhhhh llllllll */
|
||||
*(out += 2) = off;
|
||||
out [-1] = (off >> 8) | len;
|
||||
GOTO_NEXT
|
||||
}
|
||||
|
||||
len >>= 5;
|
||||
if ( off < (1 << 16) ) /* 91% */
|
||||
{
|
||||
/* 000LLLLL llllllll hhhhhhhh */
|
||||
out [1] = len;
|
||||
out [2] = off;
|
||||
*(out += 3) = off >> 8;
|
||||
GOTO_NEXT
|
||||
}
|
||||
in -= 2;
|
||||
in -= len;
|
||||
goto literal;
|
||||
}
|
||||
|
||||
long_match:
|
||||
{
|
||||
/* 8+ byte match */
|
||||
byte const* const start = in - 4;
|
||||
off = -off;
|
||||
++in;
|
||||
{
|
||||
int x, y;
|
||||
do
|
||||
{
|
||||
x = *in;
|
||||
y = in [off];
|
||||
if ( in >= in_max )
|
||||
break;
|
||||
++in;
|
||||
}
|
||||
while ( x == y ); /* 92% */
|
||||
}
|
||||
|
||||
/* Encode offset and length */
|
||||
{
|
||||
int len = in - start;
|
||||
PRE_GOTO( -1 );
|
||||
off = -off;
|
||||
|
||||
if ( len < (1 << 5) ) /* 90% */
|
||||
{
|
||||
out [1] = len;
|
||||
if ( off < (1 << 16) ) /* 98% */
|
||||
{
|
||||
/* 000LLLLL llllllll hhhhhhhh */
|
||||
out [2] = off;
|
||||
*(out += 3) = off >> 8;
|
||||
GOTO_NEXT
|
||||
}
|
||||
|
||||
if ( len <= 9 - 2 ) /* 52% */
|
||||
{
|
||||
/* TODO: lame */
|
||||
in -= 2;
|
||||
in -= len;
|
||||
goto literal;
|
||||
}
|
||||
}
|
||||
|
||||
/* 8-bit 0, 32-bit offset, 32-bit length */
|
||||
out [1] = 0;
|
||||
out [2] = off;
|
||||
out [3] = off >> 8;
|
||||
out [4] = off >> 16;
|
||||
out [5] = off >> 24;
|
||||
out [6] = len;
|
||||
out [7] = len >> 8;
|
||||
out [8] = len >> 16;
|
||||
*(out += 9) = len >> 24;
|
||||
GOTO_NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This is at bottom of loop to make branches here positive and branches back
|
||||
negative, which helps CPUs that lack dynamic branch prediction */
|
||||
|
||||
flush: /* Flush bits */
|
||||
out += 4;
|
||||
out_bits [-3] = (bits << 1) + 1;
|
||||
out_bits [-2] = bits >> 7;
|
||||
out_bits [-1] = bits >> 15;
|
||||
out_bits [ 0] = bits >> 23;
|
||||
out_bits = out;
|
||||
bits = 1;
|
||||
if ( out < out_max ) /* 99% */
|
||||
goto match;
|
||||
return -1; /* no compression */
|
||||
|
||||
final_bytes:
|
||||
/* Right-justify and flush final bits */
|
||||
{
|
||||
++bits;
|
||||
if ( (bits & 0xFFFF0000) == 0 )
|
||||
bits <<= 16;
|
||||
|
||||
if ( !TOP_BIT( bits ) )
|
||||
while ( !TOP_BIT( bits <<= 1 ) ) { }
|
||||
bits <<= 1;
|
||||
|
||||
out_bits [-3] = bits;
|
||||
out_bits [-2] = bits >> 8;
|
||||
out_bits [-1] = bits >> 16;
|
||||
out_bits [ 0] = bits >> 24;
|
||||
}
|
||||
|
||||
{
|
||||
byte const* const end = in_max + in_max_offset;
|
||||
|
||||
/* Remaining bytes should be in narrow range */
|
||||
assert( end - in >= in_max_offset - 6 );
|
||||
assert( end - in <= in_max_offset + 1 );
|
||||
|
||||
/* End marker */
|
||||
out [1] = 0;
|
||||
out [2] = 0;
|
||||
out [3] = 0;
|
||||
*(out += 4) = 0;
|
||||
|
||||
/* Copy final bytes */
|
||||
do
|
||||
{
|
||||
*++out = *in++;
|
||||
}
|
||||
while ( in < end );
|
||||
}
|
||||
|
||||
return out + 1 - (byte*) out_min;
|
||||
}
|
||||
|
||||
int blz_pack( void const* in_min, int size, void* out, blz_pack_t* dict )
|
||||
{
|
||||
byte const* in = (byte const*) in_min;
|
||||
assert( (unsigned) size <= 0x7FFFFFFF );
|
||||
if ( size >= 21 && dict ) /* 21 repeated bytes compress to 24 bytes */
|
||||
{
|
||||
/* clear dict */
|
||||
byte const** dout = dict->dict;
|
||||
int count;
|
||||
in += 1; /* avoid match at beginning since out is one less in unpack */
|
||||
for ( count = 0x1000; count--; )
|
||||
*dout++ = in;
|
||||
in -= 1;
|
||||
|
||||
{
|
||||
int out_size = blz_pack_( in, size, out, dict );
|
||||
if ( (unsigned) out_size < (unsigned) size + 4 )
|
||||
return out_size;
|
||||
}
|
||||
}
|
||||
((byte*) out) [0] = size;
|
||||
((byte*) out) [1] = size >> 8;
|
||||
((byte*) out) [2] = size >> 16;
|
||||
((byte*) out) [3] = 0x80 | (size >> 24);
|
||||
memcpy( (byte*) out + 4, in, size );
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
volatile bits_t i = 0x40000000;
|
||||
assert( !TOP_BIT( i ) && TOP_BIT( i << 1 ) && !TOP_BIT( i << 2 ) && !ALL_BITS( i << 2 ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
return size + 4;
|
||||
}
|
||||
|
||||
/* Unpack */
|
||||
|
||||
int blz_size( void const* in_ )
|
||||
{
|
||||
byte const* in = (byte const*) in_;
|
||||
return in [0] | (in [1] << 8) | (in [2] << 16) | (in [3] << 24 & 0x7F);
|
||||
}
|
||||
|
||||
int blz_unpack( void const* in_min, void* out_min )
|
||||
{
|
||||
byte const* BLZ_RESTRICT in = (byte const*) in_min;
|
||||
byte* out = (byte*) out_min;
|
||||
bits_t out_size = in [0] | (in [1] << 8) | (in [2] << 16) | (in [3] << 24);
|
||||
in += 4;
|
||||
|
||||
if ( !TOP_BIT( out_size ) )
|
||||
{
|
||||
byte* const out_max = out + out_size - 2;
|
||||
unsigned data; /* usually holds next input byte, read ahead of time */
|
||||
bits_t bits;
|
||||
|
||||
*out = in [0];
|
||||
*++out = in [1];
|
||||
in += 2;
|
||||
|
||||
refill: { /* Refill bits */
|
||||
bits_t first = (in [3] << 24);
|
||||
bits = in [0] | first | (in [1] << 8) | (in [2] << 16);
|
||||
data = *(in += 4);
|
||||
if ( TOP_BIT( first ) ) /* 48% */
|
||||
goto literal;
|
||||
if ( !bits ) /* 1% */
|
||||
goto final_bytes;
|
||||
}
|
||||
|
||||
match: { /* Matching symbol */
|
||||
int len, off;
|
||||
bits <<= 1;
|
||||
off = *++in;
|
||||
len = data >> 5;
|
||||
data &= 0x1F;
|
||||
if ( !len ) /* 17% */
|
||||
goto long_match;
|
||||
|
||||
copy_bytes: /* Copy len+2 bytes from out-off to out */
|
||||
off |= data << 8;
|
||||
{
|
||||
byte const* match = out - off;
|
||||
/*assert( len > 0 && (size_t) (match - (byte*) out_min) < (size_t) out_size );*/
|
||||
|
||||
/* match may = out + 1, so can't read ahead at all */
|
||||
out [1] = match [1];
|
||||
*(out += 2) = match [2];
|
||||
data = *(match += 3);
|
||||
if ( --len ) /* 50% */
|
||||
{
|
||||
do
|
||||
{
|
||||
*++out = data;
|
||||
data = *++match;
|
||||
}
|
||||
while ( --len ); /* 80% */
|
||||
}
|
||||
*++out = data;
|
||||
}
|
||||
|
||||
data = *++in;
|
||||
if ( !TOP_BIT( bits ) ) /* 58% */
|
||||
goto match;
|
||||
literal:
|
||||
if ( ALL_BITS( bits <<= 1 ) == 0 ) /* 7% */
|
||||
goto refill;
|
||||
|
||||
/* Literal byte */
|
||||
*++out = data;
|
||||
data = *++in;
|
||||
if ( TOP_BIT( bits ) ) /* 60% */
|
||||
goto literal;
|
||||
|
||||
/* Start decoding match */
|
||||
bits <<= 1;
|
||||
off = *++in;
|
||||
len = data >> 5;
|
||||
data &= 0x1F;
|
||||
if ( len ) /* 82% */
|
||||
goto copy_bytes;
|
||||
|
||||
long_match: /* Longer match encodings */
|
||||
len = data;
|
||||
data = *++in;
|
||||
if ( len ) /* 93% */
|
||||
goto copy_bytes;
|
||||
|
||||
off |= in [1] << 16;
|
||||
off |= in [2] << 24;
|
||||
len = in [3];
|
||||
len |= in [4] << 8;
|
||||
len |= in [5] << 16;
|
||||
len |= *(in += 6) << 24;
|
||||
goto copy_bytes;
|
||||
}
|
||||
|
||||
final_bytes: /* Copy final bytes */
|
||||
do
|
||||
{
|
||||
*++out = data;
|
||||
data = *++in;
|
||||
}
|
||||
while ( out < out_max );
|
||||
*++out = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( out, in, out_size ^= 0x80000000u );
|
||||
}
|
||||
return out_size;
|
||||
}
|
||||
|
||||
#endif
|
40
mednafen/compress/blz.h
Normal file
40
mednafen/compress/blz.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* Fast data compressor for keeping data compressed in memory. Data format subject
|
||||
to change, so not suitable for long-term storage or transfer between computers. */
|
||||
|
||||
/* blz 0.9.1 */
|
||||
#ifndef BLZ_H
|
||||
#define BLZ_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* All functions are thread-safe */
|
||||
|
||||
/* Temporary buffer type that you must allocate. Does NOT need to be cleared
|
||||
before calling blz_pack(), and can be freed immediately afterwards. */
|
||||
typedef struct blz_pack_t { unsigned char const* dict [0x1000]; } blz_pack_t;
|
||||
|
||||
/* Compresses data_size bytes from data_in to packed_out and returns packed size,
|
||||
at most data_size + blz_worst_case. Requires data_size + blz_pack_extra bytes
|
||||
allocated to packed_out. Requires that data_size be 0 to 0x7FFFFFFF (2 GB).
|
||||
If temp is NULL, stores data uncompressed. */
|
||||
enum { blz_pack_extra = 320 };
|
||||
enum { blz_worst_case = 4 };
|
||||
int blz_pack( void const* data_in, int data_size, void* packed_out, blz_pack_t* temp );
|
||||
|
||||
/* Decompresses from packed_in to data_out and returns original data size.
|
||||
Does NOT do any consistency checking, so corrupt data can crash program. */
|
||||
int blz_unpack( void const* packed_in, void* data_out );
|
||||
|
||||
/* Size of original data before compression */
|
||||
int blz_size( void const* packed_in );
|
||||
|
||||
/* String describing version of blz. Currently either "fast" or "slow". */
|
||||
extern char const blz_version [];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
180
mednafen/compress/ioapi.c
Normal file
180
mednafen/compress/ioapi.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* ioapi.c -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "zlib.h"
|
||||
#ifndef OF
|
||||
#define OF(a) a
|
||||
#endif
|
||||
#include "ioapi.h"
|
||||
|
||||
|
||||
|
||||
/* 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
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func OF((
|
||||
voidpf opaque,
|
||||
const char* filename,
|
||||
int mode));
|
||||
|
||||
uLong ZCALLBACK fread_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
void* buf,
|
||||
uLong size));
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
const void* buf,
|
||||
uLong size));
|
||||
|
||||
long ZCALLBACK ftell_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
long ZCALLBACK fseek_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
uLong offset,
|
||||
int origin));
|
||||
|
||||
int ZCALLBACK fclose_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
int ZCALLBACK ferror_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
|
||||
voidpf opaque;
|
||||
const char* filename;
|
||||
int mode;
|
||||
{
|
||||
FILE* file = NULL;
|
||||
const char* mode_fopen = NULL;
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
|
||||
mode_fopen = "rb";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
|
||||
mode_fopen = "r+b";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
||||
mode_fopen = "wb";
|
||||
|
||||
if ((filename!=NULL) && (mode_fopen != NULL))
|
||||
file = fopen(filename, mode_fopen);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK fread_file_func (opaque, stream, buf, size)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
void* buf;
|
||||
uLong size;
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
const void* buf;
|
||||
uLong size;
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ZCALLBACK ftell_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
long ret;
|
||||
ret = ftell((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
uLong offset;
|
||||
int origin;
|
||||
{
|
||||
int fseek_origin=0;
|
||||
long ret;
|
||||
switch (origin)
|
||||
{
|
||||
case ZLIB_FILEFUNC_SEEK_CUR :
|
||||
fseek_origin = SEEK_CUR;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END :
|
||||
fseek_origin = SEEK_END;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET :
|
||||
fseek_origin = SEEK_SET;
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
ret = 0;
|
||||
fseek((FILE *)stream, offset, fseek_origin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK fclose_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
int ret;
|
||||
ret = fclose((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK ferror_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
int ret;
|
||||
ret = ferror((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fill_fopen_filefunc (pzlib_filefunc_def)
|
||||
zlib_filefunc_def* pzlib_filefunc_def;
|
||||
{
|
||||
pzlib_filefunc_def->zopen_file = fopen_file_func;
|
||||
pzlib_filefunc_def->zread_file = fread_file_func;
|
||||
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
|
||||
pzlib_filefunc_def->ztell_file = ftell_file_func;
|
||||
pzlib_filefunc_def->zseek_file = fseek_file_func;
|
||||
pzlib_filefunc_def->zclose_file = fclose_file_func;
|
||||
pzlib_filefunc_def->zerror_file = ferror_file_func;
|
||||
pzlib_filefunc_def->opaque = NULL;
|
||||
}
|
75
mednafen/compress/ioapi.h
Normal file
75
mednafen/compress/ioapi.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
*/
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#define _ZLIBIOAPI_H
|
||||
|
||||
|
||||
#define ZLIB_FILEFUNC_SEEK_CUR (1)
|
||||
#define ZLIB_FILEFUNC_SEEK_END (2)
|
||||
#define ZLIB_FILEFUNC_SEEK_SET (0)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_READ (1)
|
||||
#define ZLIB_FILEFUNC_MODE_WRITE (2)
|
||||
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
|
||||
#define ZLIB_FILEFUNC_MODE_CREATE (8)
|
||||
|
||||
|
||||
#ifndef ZCALLBACK
|
||||
|
||||
#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
|
||||
#define ZCALLBACK CALLBACK
|
||||
#else
|
||||
#define ZCALLBACK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
|
||||
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
|
||||
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
|
||||
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
|
||||
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
|
||||
|
||||
typedef struct zlib_filefunc_def_s
|
||||
{
|
||||
open_file_func zopen_file;
|
||||
read_file_func zread_file;
|
||||
write_file_func zwrite_file;
|
||||
tell_file_func ztell_file;
|
||||
seek_file_func zseek_file;
|
||||
close_file_func zclose_file;
|
||||
testerror_file_func zerror_file;
|
||||
voidpf opaque;
|
||||
} zlib_filefunc_def;
|
||||
|
||||
|
||||
|
||||
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
|
||||
|
||||
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
|
||||
#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
|
||||
#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
|
||||
#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
412
mednafen/compress/lzoconf.h
Normal file
412
mednafen/compress/lzoconf.h
Normal file
@ -0,0 +1,412 @@
|
||||
/* lzoconf.h -- configuration for the LZO real-time data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LZOCONF_H_INCLUDED
|
||||
#define __LZOCONF_H_INCLUDED
|
||||
|
||||
#define LZO_VERSION 0x2010
|
||||
#define LZO_VERSION_STRING "2.01"
|
||||
#define LZO_VERSION_DATE "Jun 27 2005"
|
||||
|
||||
/* internal Autoconf configuration file - only used when building LZO */
|
||||
#if defined(LZO_HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// LZO requires a conforming <limits.h>
|
||||
************************************************************************/
|
||||
|
||||
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
|
||||
# error "invalid CHAR_BIT"
|
||||
#endif
|
||||
#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
|
||||
# error "check your compiler installation"
|
||||
#endif
|
||||
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
|
||||
# error "your limits.h macros are broken"
|
||||
#endif
|
||||
|
||||
/* get OS and architecture defines */
|
||||
#ifndef __LZODEFS_H_INCLUDED
|
||||
#include "lzodefs.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
|
||||
#if !defined(LZO_UINT32_C)
|
||||
# if (UINT_MAX < LZO_0xffffffffL)
|
||||
# define LZO_UINT32_C(c) c ## UL
|
||||
# else
|
||||
# define LZO_UINT32_C(c) ((c) + 0U)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* memory checkers */
|
||||
#if !defined(__LZO_CHECKER)
|
||||
# if defined(__BOUNDS_CHECKING_ON)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__CHECKER__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__INSURE__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__PURIFY__)
|
||||
# define __LZO_CHECKER 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// integral and pointer types
|
||||
************************************************************************/
|
||||
|
||||
/* lzo_uint should match size_t */
|
||||
#if !defined(LZO_UINT_MAX)
|
||||
# if defined(LZO_ABI_LLP64) /* WIN64 */
|
||||
# if defined(LZO_OS_WIN64)
|
||||
typedef unsigned __int64 lzo_uint;
|
||||
typedef __int64 lzo_int;
|
||||
# else
|
||||
typedef unsigned long long lzo_uint;
|
||||
typedef long long lzo_int;
|
||||
# endif
|
||||
# define LZO_UINT_MAX 0xffffffffffffffffull
|
||||
# define LZO_INT_MAX 9223372036854775807LL
|
||||
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
|
||||
# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */
|
||||
typedef unsigned int lzo_uint;
|
||||
typedef int lzo_int;
|
||||
# define LZO_UINT_MAX UINT_MAX
|
||||
# define LZO_INT_MAX INT_MAX
|
||||
# define LZO_INT_MIN INT_MIN
|
||||
# elif (ULONG_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned long lzo_uint;
|
||||
typedef long lzo_int;
|
||||
# define LZO_UINT_MAX ULONG_MAX
|
||||
# define LZO_INT_MAX LONG_MAX
|
||||
# define LZO_INT_MIN LONG_MIN
|
||||
# else
|
||||
# error "lzo_uint"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Integral types with 32 bits or more. */
|
||||
#if !defined(LZO_UINT32_MAX)
|
||||
# if (UINT_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned int lzo_uint32;
|
||||
typedef int lzo_int32;
|
||||
# define LZO_UINT32_MAX UINT_MAX
|
||||
# define LZO_INT32_MAX INT_MAX
|
||||
# define LZO_INT32_MIN INT_MIN
|
||||
# elif (ULONG_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned long lzo_uint32;
|
||||
typedef long lzo_int32;
|
||||
# define LZO_UINT32_MAX ULONG_MAX
|
||||
# define LZO_INT32_MAX LONG_MAX
|
||||
# define LZO_INT32_MIN LONG_MIN
|
||||
# else
|
||||
# error "lzo_uint32"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The larger type of lzo_uint and lzo_uint32. */
|
||||
#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
|
||||
# define lzo_xint lzo_uint
|
||||
#else
|
||||
# define lzo_xint lzo_uint32
|
||||
#endif
|
||||
|
||||
/* Memory model that allows to access memory at offsets of lzo_uint. */
|
||||
#if !defined(__LZO_MMODEL)
|
||||
# if (LZO_UINT_MAX <= UINT_MAX)
|
||||
# define __LZO_MMODEL
|
||||
# elif defined(LZO_HAVE_MM_HUGE_PTR)
|
||||
# define __LZO_MMODEL_HUGE 1
|
||||
# define __LZO_MMODEL __huge
|
||||
# else
|
||||
# define __LZO_MMODEL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* no typedef here because of const-pointer issues */
|
||||
#define lzo_bytep unsigned char __LZO_MMODEL *
|
||||
#define lzo_charp char __LZO_MMODEL *
|
||||
#define lzo_voidp void __LZO_MMODEL *
|
||||
#define lzo_shortp short __LZO_MMODEL *
|
||||
#define lzo_ushortp unsigned short __LZO_MMODEL *
|
||||
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
|
||||
#define lzo_int32p lzo_int32 __LZO_MMODEL *
|
||||
#define lzo_uintp lzo_uint __LZO_MMODEL *
|
||||
#define lzo_intp lzo_int __LZO_MMODEL *
|
||||
#define lzo_xintp lzo_xint __LZO_MMODEL *
|
||||
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
|
||||
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
|
||||
/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */
|
||||
#define lzo_byte unsigned char __LZO_MMODEL
|
||||
|
||||
typedef int lzo_bool;
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// function types
|
||||
************************************************************************/
|
||||
|
||||
/* name mangling */
|
||||
#if !defined(__LZO_EXTERN_C)
|
||||
# ifdef __cplusplus
|
||||
# define __LZO_EXTERN_C extern "C"
|
||||
# else
|
||||
# define __LZO_EXTERN_C extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* calling convention */
|
||||
#if !defined(__LZO_CDECL)
|
||||
# define __LZO_CDECL __lzo_cdecl
|
||||
#endif
|
||||
|
||||
/* DLL export information */
|
||||
#if !defined(__LZO_EXPORT1)
|
||||
# define __LZO_EXPORT1
|
||||
#endif
|
||||
#if !defined(__LZO_EXPORT2)
|
||||
# define __LZO_EXPORT2
|
||||
#endif
|
||||
|
||||
/* __cdecl calling convention for public C and assembly functions */
|
||||
#if !defined(LZO_PUBLIC)
|
||||
# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
|
||||
#endif
|
||||
#if !defined(LZO_EXTERN)
|
||||
# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
|
||||
#endif
|
||||
#if !defined(LZO_PRIVATE)
|
||||
# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
|
||||
#endif
|
||||
|
||||
/* function types */
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
|
||||
/* Callback interface. Currently only the progress indicator ("nprogress")
|
||||
* is used, but this may change in a future release. */
|
||||
|
||||
struct lzo_callback_t;
|
||||
typedef struct lzo_callback_t lzo_callback_t;
|
||||
#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
|
||||
|
||||
/* malloc & free function types */
|
||||
typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
|
||||
(lzo_callback_p self, lzo_uint items, lzo_uint size);
|
||||
typedef void (__LZO_CDECL *lzo_free_func_t)
|
||||
(lzo_callback_p self, lzo_voidp ptr);
|
||||
|
||||
/* a progress indicator callback function */
|
||||
typedef void (__LZO_CDECL *lzo_progress_func_t)
|
||||
(lzo_callback_p, lzo_uint, lzo_uint, int);
|
||||
|
||||
struct lzo_callback_t
|
||||
{
|
||||
/* custom allocators (set to 0 to disable) */
|
||||
lzo_alloc_func_t nalloc; /* [not used right now] */
|
||||
lzo_free_func_t nfree; /* [not used right now] */
|
||||
|
||||
/* a progress indicator callback function (set to 0 to disable) */
|
||||
lzo_progress_func_t nprogress;
|
||||
|
||||
/* NOTE: the first parameter of nalloc/nfree/nprogress callbacks ("self")
|
||||
* points back to this struct, so you are free to store some extra
|
||||
* info in the following variables. */
|
||||
lzo_voidp user1;
|
||||
lzo_xint user2;
|
||||
lzo_xint user3;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// error codes and prototypes
|
||||
************************************************************************/
|
||||
|
||||
/* Error codes for the compression/decompression functions. Negative
|
||||
* values are errors, positive values will be used for special but
|
||||
* normal events.
|
||||
*/
|
||||
#define LZO_E_OK 0
|
||||
#define LZO_E_ERROR (-1)
|
||||
#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */
|
||||
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
|
||||
#define LZO_E_INPUT_OVERRUN (-4)
|
||||
#define LZO_E_OUTPUT_OVERRUN (-5)
|
||||
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
|
||||
#define LZO_E_EOF_NOT_FOUND (-7)
|
||||
#define LZO_E_INPUT_NOT_CONSUMED (-8)
|
||||
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
|
||||
|
||||
|
||||
#ifndef lzo_sizeof_dict_t
|
||||
# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
|
||||
#endif
|
||||
|
||||
/* lzo_init() should be the first function you call.
|
||||
* Check the return code !
|
||||
*
|
||||
* lzo_init() is a macro to allow checking that the library and the
|
||||
* compiler's view of various types are consistent.
|
||||
*/
|
||||
#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
|
||||
(int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
|
||||
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
|
||||
(int)sizeof(lzo_callback_t))
|
||||
LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
|
||||
|
||||
/* version functions (useful for shared libraries) */
|
||||
LZO_EXTERN(unsigned) lzo_version(void);
|
||||
LZO_EXTERN(const char *) lzo_version_string(void);
|
||||
LZO_EXTERN(const char *) lzo_version_date(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
|
||||
|
||||
/* string functions */
|
||||
LZO_EXTERN(int)
|
||||
lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
|
||||
|
||||
/* checksum functions */
|
||||
LZO_EXTERN(lzo_uint32)
|
||||
lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len);
|
||||
LZO_EXTERN(lzo_uint32)
|
||||
lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len);
|
||||
LZO_EXTERN(const lzo_uint32p)
|
||||
lzo_get_crc32_table(void);
|
||||
|
||||
/* misc. */
|
||||
LZO_EXTERN(int) _lzo_config_check(void);
|
||||
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
|
||||
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
|
||||
typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
|
||||
|
||||
/* align a char pointer on a boundary that is a multiple of `size' */
|
||||
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
|
||||
#define LZO_PTR_ALIGN_UP(_ptr,_size) \
|
||||
((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// deprecated macros - only for backward compatibility with LZO v1.xx
|
||||
************************************************************************/
|
||||
|
||||
#if defined(LZO_CFG_COMPAT)
|
||||
|
||||
#define __LZOCONF_H 1
|
||||
|
||||
#if defined(LZO_ARCH_I086)
|
||||
# define __LZO_i386 1
|
||||
#elif defined(LZO_ARCH_I386)
|
||||
# define __LZO_i386 1
|
||||
#endif
|
||||
|
||||
#if defined(LZO_OS_DOS16)
|
||||
# define __LZO_DOS 1
|
||||
# define __LZO_DOS16 1
|
||||
#elif defined(LZO_OS_DOS32)
|
||||
# define __LZO_DOS 1
|
||||
#elif defined(LZO_OS_WIN16)
|
||||
# define __LZO_WIN 1
|
||||
# define __LZO_WIN16 1
|
||||
#elif defined(LZO_OS_WIN32)
|
||||
# define __LZO_WIN 1
|
||||
#endif
|
||||
|
||||
#define __LZO_CMODEL
|
||||
#define __LZO_DMODEL
|
||||
#define __LZO_ENTRY __LZO_CDECL
|
||||
#define LZO_EXTERN_CDECL LZO_EXTERN
|
||||
#define LZO_ALIGN LZO_PTR_ALIGN_UP
|
||||
|
||||
#define lzo_compress_asm_t lzo_compress_t
|
||||
#define lzo_decompress_asm_t lzo_decompress_t
|
||||
|
||||
#endif /* LZO_CFG_COMPAT */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
1482
mednafen/compress/lzodefs.h
Normal file
1482
mednafen/compress/lzodefs.h
Normal file
File diff suppressed because it is too large
Load Diff
3743
mednafen/compress/minilzo.c
Normal file
3743
mednafen/compress/minilzo.c
Normal file
File diff suppressed because it is too large
Load Diff
103
mednafen/compress/minilzo.h
Normal file
103
mednafen/compress/minilzo.h
Normal file
@ -0,0 +1,103 @@
|
||||
/* minilzo.h -- mini subset of the LZO real-time data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* the full LZO package can be found at
|
||||
* http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MINILZO_H
|
||||
#define __MINILZO_H
|
||||
|
||||
#define MINILZO_VERSION 0x2010
|
||||
|
||||
#ifdef __LZOCONF_H
|
||||
# error "you cannot use both LZO and miniLZO"
|
||||
#endif
|
||||
|
||||
#undef LZO_HAVE_CONFIG_H
|
||||
#include "lzoconf.h"
|
||||
|
||||
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
|
||||
# error "version mismatch in header files"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
|
||||
/* Memory required for the wrkmem parameter.
|
||||
* When the required size is 0, you can also pass a NULL pointer.
|
||||
*/
|
||||
|
||||
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
|
||||
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
|
||||
#define LZO1X_MEM_DECOMPRESS (0)
|
||||
|
||||
|
||||
/* compression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
/* decompression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
/* safe decompression with overrun testing */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
888
mednafen/compress/quicklz.c
Normal file
888
mednafen/compress/quicklz.c
Normal file
@ -0,0 +1,888 @@
|
||||
// QuickLZ data compression library
|
||||
// Copyright (C) 2006-2008 Lasse Mikkel Reinhold
|
||||
// lar@quicklz.com
|
||||
//
|
||||
// QuickLZ can be used for free under the GPL-1 or GPL-2 license (where anything
|
||||
// released into public must be open source) or under a commercial license if such
|
||||
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
|
||||
// does not cover derived or ported versions created by third parties under GPL.
|
||||
|
||||
#include "quicklz.h"
|
||||
|
||||
int qlz_get_setting(int setting)
|
||||
{
|
||||
switch (setting)
|
||||
{
|
||||
case 0: return COMPRESSION_LEVEL;
|
||||
case 1: return SCRATCH_COMPRESS;
|
||||
case 2: return SCRATCH_DECOMPRESS;
|
||||
case 3: return STREAMING_MODE_VALUE;
|
||||
#ifdef test_rle
|
||||
case 4: return 1;
|
||||
#else
|
||||
case 4: return 0;
|
||||
#endif
|
||||
#ifdef speedup_incompressible
|
||||
case 5: return 1;
|
||||
#else
|
||||
case 5: return 0;
|
||||
#endif
|
||||
#ifdef memory_safe
|
||||
case 6: return 1;
|
||||
#else
|
||||
case 6: return 0;
|
||||
#endif
|
||||
case 7: return QLZ_VERSION_MAJOR;
|
||||
case 8: return QLZ_VERSION_MINOR;
|
||||
case 9: return QLZ_VERSION_REVISION;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static __inline unsigned int hash_func(unsigned int i)
|
||||
{
|
||||
return ((i >> 12) ^ i) & 0x0fff;
|
||||
}
|
||||
|
||||
static __inline unsigned int fast_read(void const *src, unsigned int bytes)
|
||||
{
|
||||
#ifndef X86X64
|
||||
unsigned char *p = (unsigned char*)src;
|
||||
switch (bytes)
|
||||
{
|
||||
case 4:
|
||||
return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24);
|
||||
case 3:
|
||||
return(*p | *(p + 1) << 8 | *(p + 2) << 16);
|
||||
case 2:
|
||||
return(*p | *(p + 1) << 8);
|
||||
case 1:
|
||||
return(*p);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
if (bytes >= 1 && bytes <= 4)
|
||||
return *((unsigned int*)src);
|
||||
else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline void fast_write(unsigned int f, void *dst, unsigned int bytes)
|
||||
{
|
||||
#ifndef X86X64
|
||||
unsigned char *p = (unsigned char*)dst;
|
||||
|
||||
switch (bytes)
|
||||
{
|
||||
case 4:
|
||||
*p = (unsigned char)f;
|
||||
*(p + 1) = (unsigned char)(f >> 8);
|
||||
*(p + 2) = (unsigned char)(f >> 16);
|
||||
*(p + 3) = (unsigned char)(f >> 24);
|
||||
return;
|
||||
case 3:
|
||||
*p = (unsigned char)f;
|
||||
*(p + 1) = (unsigned char)(f >> 8);
|
||||
*(p + 2) = (unsigned char)(f >> 16);
|
||||
return;
|
||||
case 2:
|
||||
*p = (unsigned char)f;
|
||||
*(p + 1) = (unsigned char)(f >> 8);
|
||||
return;
|
||||
case 1:
|
||||
*p = (unsigned char)f;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
switch (bytes)
|
||||
{
|
||||
case 4:
|
||||
*((unsigned int*)dst) = f;
|
||||
return;
|
||||
case 3:
|
||||
*((unsigned int*)dst) = f;
|
||||
return;
|
||||
case 2:
|
||||
#if COMPRESSION_LEVEL == 0
|
||||
// 2 byte writes are common in level 0
|
||||
*((unsigned short int*)dst) = (unsigned short int)f;
|
||||
#else
|
||||
*((unsigned int*)dst) = f;
|
||||
#endif
|
||||
return;
|
||||
case 1:
|
||||
*((unsigned char*)dst) = (unsigned char)f;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, unsigned int n)
|
||||
{
|
||||
// cannot be replaced by overlap handling of memmove() due to LZSS algorithm
|
||||
#ifndef X86X64
|
||||
|
||||
if(n > 8 && src + n < dst)
|
||||
memcpy(dst, src, n);
|
||||
else
|
||||
{
|
||||
unsigned char *end = dst + n;
|
||||
while(dst < end)
|
||||
{
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (n < 5)
|
||||
*((unsigned int*)dst) = *((unsigned int*)src);
|
||||
else
|
||||
{
|
||||
unsigned char *end = dst + n;
|
||||
while(dst < end)
|
||||
{
|
||||
*((unsigned int*)dst) = *((unsigned int*)src);
|
||||
dst = dst + 4;
|
||||
src = src + 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline unsigned int fast_read_safe(void const *src, unsigned int bytes, const unsigned char *invalid)
|
||||
{
|
||||
#ifdef memory_safe
|
||||
if ((const unsigned char *)src + 4 > (const unsigned char *)invalid)
|
||||
return 0xffffffff;
|
||||
#endif
|
||||
invalid = invalid;
|
||||
return fast_read(src, bytes);
|
||||
}
|
||||
|
||||
unsigned int qlz_compress_core(const void *source, unsigned char *destination, unsigned int size, const unsigned char *hashtable[][AND + 1], const unsigned char *first_valid, unsigned char *hash_counter)
|
||||
{
|
||||
const unsigned char *source_c = (const unsigned char*)source;
|
||||
unsigned char *destination_c = (unsigned char*)destination;
|
||||
const unsigned char *last_byte = source_c + size - 1;
|
||||
const unsigned char *src = source_c;
|
||||
unsigned char *cword_ptr = destination_c;
|
||||
unsigned char *dst = destination_c + 4;
|
||||
unsigned int cword_val = 1U << 31;
|
||||
const unsigned char *guarantee_uncompressed = last_byte - 8;
|
||||
|
||||
#ifdef speedup_incompressible
|
||||
unsigned char *prev_dst = dst;
|
||||
const unsigned char *prev_src = src;
|
||||
#endif
|
||||
|
||||
hash_counter = hash_counter;
|
||||
first_valid = first_valid;
|
||||
|
||||
// save first 4 bytes uncompressed
|
||||
while(src < source_c + 4 && src < guarantee_uncompressed)
|
||||
{
|
||||
cword_val = (cword_val >> 1);
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
|
||||
while(src < guarantee_uncompressed)
|
||||
{
|
||||
unsigned int fetch;
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
// check if destinationc pointer could exceed destination buffer
|
||||
if (dst > destination_c + size)
|
||||
return 0;
|
||||
|
||||
// store control word
|
||||
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, 4);
|
||||
cword_ptr = dst;
|
||||
dst += 4;
|
||||
cword_val = 1U << 31;
|
||||
|
||||
#ifdef speedup_incompressible
|
||||
// check if source chunk is compressible
|
||||
if (dst - prev_dst > src - prev_src && src > source_c + 1000)
|
||||
{
|
||||
int q;
|
||||
for(q = 0; q < 30 && src + 31 < guarantee_uncompressed && dst + 35 < destination_c + size; q++)
|
||||
{
|
||||
|
||||
#if(COMPRESSION_LEVEL == 0)
|
||||
int w;
|
||||
for(w = 0; w < 31; w++)
|
||||
{
|
||||
fetch = fast_read(src + w, 4);
|
||||
*(unsigned int*)&hashtable[hash_func(fetch)][0] = fast_read(src + w, 4);
|
||||
hashtable[hash_func(fetch)][1] = src + w;
|
||||
}
|
||||
#endif
|
||||
fast_write((1U << 31), dst - 4, 4);
|
||||
memcpy(dst, src, 31);
|
||||
|
||||
dst += 4*8 - 1 + 4;
|
||||
src += 4*8 - 1;
|
||||
prev_src = src;
|
||||
prev_dst = dst;
|
||||
cword_ptr = dst - 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef test_rle
|
||||
// check for rle sequence
|
||||
if (fast_read(src, 4) == fast_read(src + 1, 4))
|
||||
{
|
||||
const unsigned char *orig_src;
|
||||
fetch = fast_read(src, 4);
|
||||
orig_src = src;
|
||||
do src = src + 4; while (src <= guarantee_uncompressed - 4 && fetch == fast_read(src, 4));
|
||||
if((src - orig_src) <= 2047)
|
||||
{
|
||||
fast_write(((fetch & 0xff) << 16) | (unsigned int)((src - orig_src) << 4) | 15, dst, 4);
|
||||
dst = dst + 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_write(((fetch & 0xff) << 16) | 15, dst, 4);
|
||||
fast_write((unsigned int)(src - orig_src), dst + 3, 4);
|
||||
dst = dst + 7;
|
||||
}
|
||||
cword_val = (cword_val >> 1) | (1 << 31);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const unsigned char *o;
|
||||
unsigned int hash, matchlen;
|
||||
|
||||
#if(COMPRESSION_LEVEL < 2)
|
||||
unsigned int cached;
|
||||
|
||||
fetch = fast_read(src, 4);
|
||||
hash = hash_func(fetch);
|
||||
|
||||
cached = fetch ^ *(unsigned int*)&hashtable[hash][0];
|
||||
*(unsigned int*)&hashtable[hash][0] = fetch;
|
||||
|
||||
o = hashtable[hash][1];
|
||||
hashtable[hash][1] = src;
|
||||
|
||||
#else
|
||||
unsigned char c;
|
||||
unsigned int k, m;
|
||||
const unsigned char *offset2 = 0;
|
||||
|
||||
fetch = fast_read(src, 4);
|
||||
hash = hash_func(fetch);
|
||||
|
||||
matchlen = 0;
|
||||
c = hash_counter[hash];
|
||||
for(k = 0; k < AND + 1; k++)
|
||||
{
|
||||
o = hashtable[hash][(c - k) & AND];
|
||||
if(o > first_valid && o < src - 3 && *(src + matchlen) == *(o + matchlen) && (fast_read(o, 3) & 0xffffff) == (fetch & 0xffffff) && src - o < 131071)
|
||||
{
|
||||
size_t remaining;
|
||||
remaining = guarantee_uncompressed - src;
|
||||
m = 3;
|
||||
if (fast_read(o, 4) == fetch)
|
||||
{
|
||||
while(*(o + m) == *(src + m) && m < remaining)
|
||||
m++;
|
||||
}
|
||||
if (m > matchlen)
|
||||
{
|
||||
matchlen = m;
|
||||
offset2 = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
o = offset2;
|
||||
c = (hash_counter[hash] + 1) & AND;
|
||||
hash_counter[hash] = c;
|
||||
hashtable[hash][c] = src;
|
||||
#endif
|
||||
|
||||
#if(COMPRESSION_LEVEL == 0)
|
||||
if (o != 0 && (cached & 0xffffff) == 0 && src - o > 3)
|
||||
#elif(COMPRESSION_LEVEL == 1)
|
||||
if ((cached & 0xffffff) == 0 && o > first_valid && o < src - 3 && ((fast_read(o, 3) ^ fast_read(src, 3)) & 0xffffff) == 0 && src - o < 131071)
|
||||
#elif(COMPRESSION_LEVEL > 1)
|
||||
if(matchlen == 3)
|
||||
#endif
|
||||
{
|
||||
unsigned int offset;
|
||||
offset = (unsigned int)(src - o);
|
||||
|
||||
#if(COMPRESSION_LEVEL < 2)
|
||||
if (cached & 0xffffffff)
|
||||
#endif
|
||||
{
|
||||
#if (COMPRESSION_LEVEL > 2)
|
||||
unsigned int u;
|
||||
for(u = 1; u < 3; u++)
|
||||
{
|
||||
hash = hash_func(fast_read(src + u, 4));
|
||||
c = (hash_counter[hash] + 1) & AND;
|
||||
hash_counter[hash] = c;
|
||||
hashtable[hash][c] = src + u;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (COMPRESSION_LEVEL == 0)
|
||||
cword_val = (cword_val >> 1) | (1U << 31);
|
||||
fast_write(3 | (hash << 4), dst, 2);
|
||||
src += 3;
|
||||
dst += 2;
|
||||
#else
|
||||
|
||||
if(offset <= 63)
|
||||
{
|
||||
// encode lz match
|
||||
*dst = (unsigned char)(offset << 2);
|
||||
cword_val = (cword_val >> 1) | (1U << 31);
|
||||
src += 3;
|
||||
dst++;
|
||||
}
|
||||
else if (offset <= 16383)
|
||||
{
|
||||
// encode lz match
|
||||
unsigned int f = (offset << 2) | 1;
|
||||
fast_write(f, dst, 2);
|
||||
cword_val = (cword_val >> 1) | (1U << 31);
|
||||
src += 3;
|
||||
dst += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// encode literal
|
||||
*dst = *src;
|
||||
src++;
|
||||
dst++;
|
||||
cword_val = (cword_val >> 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if(COMPRESSION_LEVEL > 1)
|
||||
}
|
||||
else if(matchlen > 3)
|
||||
{
|
||||
#elif(COMPRESSION_LEVEL < 2)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// encode lz match
|
||||
unsigned int offset;
|
||||
|
||||
#if(COMPRESSION_LEVEL < 2)
|
||||
const unsigned char *old_src = src;
|
||||
offset = (unsigned int)(src - o);
|
||||
cword_val = (cword_val >> 1) | (1U << 31);
|
||||
|
||||
src += 3;
|
||||
while(*(o + (src - old_src)) == *src && src < guarantee_uncompressed)
|
||||
src++;
|
||||
matchlen = (unsigned int)(src - old_src);
|
||||
#else
|
||||
unsigned int u;
|
||||
offset = (unsigned int)(src - o);
|
||||
cword_val = (cword_val >> 1) | (1U << 31);
|
||||
|
||||
#if (COMPRESSION_LEVEL > 2)
|
||||
for(u = 1; u < matchlen; u++)
|
||||
#else
|
||||
for(u = 1; u < matchlen && u < 5; u++)
|
||||
#endif
|
||||
{
|
||||
hash = hash_func(fast_read(src + u, 4));
|
||||
c = (hash_counter[hash] + 1) & AND;
|
||||
hash_counter[hash] = c;
|
||||
hashtable[hash][c] = src + u;
|
||||
}
|
||||
src += matchlen;
|
||||
#endif
|
||||
|
||||
#if (COMPRESSION_LEVEL == 0)
|
||||
if (matchlen < 15)
|
||||
{
|
||||
fast_write(matchlen | (hash << 4), dst, 2);
|
||||
dst += 2;
|
||||
}
|
||||
else if (matchlen < 255)
|
||||
{
|
||||
fast_write(hash << 4, dst, 2);
|
||||
*(dst + 2) = (unsigned char)matchlen;
|
||||
dst += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_write(hash << 4, dst, 2);
|
||||
*(dst + 2) = 0;
|
||||
fast_write(matchlen, dst + 3, 4);
|
||||
dst += 7;
|
||||
}
|
||||
#else
|
||||
if (matchlen <= 18 && offset <= 1023)
|
||||
{
|
||||
unsigned int f = ((matchlen - 3) << 2) | (offset << 6) | 2;
|
||||
fast_write(f, dst, 2);
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
else if(matchlen <= 34 && offset <= 65535)
|
||||
{
|
||||
unsigned int f = ((matchlen - 3) << 3) | (offset << 8) | 3;
|
||||
fast_write(f, dst, 3);
|
||||
dst += 3;
|
||||
}
|
||||
else if (matchlen >= 3)
|
||||
{
|
||||
if (matchlen <= 2050)
|
||||
{
|
||||
unsigned int f = ((matchlen - 3) << 4) | (offset << 15) | 7;
|
||||
fast_write(f, dst, 4);
|
||||
dst += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_write(7, dst, 4);
|
||||
fast_write(matchlen, dst + 4, 4);
|
||||
fast_write(offset, dst + 8, 4);
|
||||
dst += 12;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// encode literal
|
||||
*dst = *src;
|
||||
src++;
|
||||
dst++;
|
||||
cword_val = (cword_val >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save last source bytes as literals
|
||||
while (src <= last_byte)
|
||||
{
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, 4);
|
||||
cword_ptr = dst;
|
||||
dst += 4;
|
||||
cword_val = 1U << 31;
|
||||
}
|
||||
|
||||
if (src < last_byte - 2 && src > source_c + 3)
|
||||
{
|
||||
hashtable[hash_func(fast_read(src, 4))][1] = src;
|
||||
*(unsigned int*)&hashtable[hash_func(fast_read(src, 4))][0] = fast_read(src, 4);
|
||||
}
|
||||
*dst = *src;
|
||||
src++;
|
||||
dst++;
|
||||
|
||||
cword_val = (cword_val >> 1);
|
||||
}
|
||||
|
||||
while((cword_val & 1) != 1)
|
||||
cword_val = (cword_val >> 1);
|
||||
|
||||
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, 4);
|
||||
|
||||
// min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument
|
||||
if (dst - destination_c < 9)
|
||||
return 9;
|
||||
else
|
||||
return (unsigned int)(dst - destination_c);
|
||||
}
|
||||
|
||||
size_t qlz_decompress_core(const unsigned char *source, void *destination, size_t size, size_t source_size, unsigned char *first_valid, const unsigned char *hashtable[])
|
||||
{
|
||||
const unsigned char *source_c = (const unsigned char*)source;
|
||||
unsigned char *destination_c = (unsigned char*)destination;
|
||||
const unsigned char *src = source_c;
|
||||
unsigned char *dst = destination_c;
|
||||
const unsigned char* last_byte_successor = destination_c + size;
|
||||
unsigned int cword_val = 1;
|
||||
const unsigned int bitlut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
|
||||
const unsigned char *guaranteed_uncompressed = last_byte_successor - 4;
|
||||
unsigned char *last_hashed = destination_c + 3;
|
||||
|
||||
first_valid = first_valid;
|
||||
last_hashed = last_hashed;
|
||||
hashtable = hashtable;
|
||||
|
||||
// prevent spurious memory read on a source with size < 4
|
||||
if (dst >= guaranteed_uncompressed)
|
||||
{
|
||||
src += 4;
|
||||
while(dst < last_byte_successor)
|
||||
{
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
|
||||
return (unsigned int)(dst - destination_c);
|
||||
}
|
||||
|
||||
|
||||
for(;;)
|
||||
{
|
||||
unsigned int fetch;
|
||||
|
||||
if (cword_val == 1)
|
||||
{
|
||||
// fetch control word
|
||||
cword_val = fast_read_safe(src, 4, source_c + source_size) | (1U << 31);
|
||||
src += 4;
|
||||
}
|
||||
|
||||
fetch = fast_read_safe(src, 4, source_c + source_size);
|
||||
|
||||
// check if we must decode lz match
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
unsigned int matchlen;
|
||||
|
||||
#if(COMPRESSION_LEVEL == 0)
|
||||
unsigned int hash;
|
||||
const unsigned char *offset2;
|
||||
|
||||
cword_val = cword_val >> 1;
|
||||
|
||||
if((fetch & 0xf) != 15)
|
||||
{
|
||||
hash = (fetch >> 4) & 0xfff;
|
||||
offset2 = hashtable[hash];
|
||||
|
||||
if((fetch & 0xf) != 0)
|
||||
{
|
||||
matchlen = (fetch & 0xf);
|
||||
src += 2;
|
||||
}
|
||||
else if((fetch & 0x00ff0000) != 0)
|
||||
{
|
||||
matchlen = *(src + 2);
|
||||
src += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchlen = fast_read(src + 3, 4);
|
||||
src += 7;
|
||||
}
|
||||
memcpy_up(dst, offset2, matchlen);
|
||||
while(last_hashed < dst)
|
||||
{
|
||||
last_hashed++;
|
||||
hashtable[hash_func(fast_read(last_hashed, 4))] = last_hashed;
|
||||
}
|
||||
dst += matchlen;
|
||||
last_hashed = dst - 1;
|
||||
}
|
||||
|
||||
#else
|
||||
unsigned int offset;
|
||||
cword_val = cword_val >> 1;
|
||||
|
||||
if ((fetch & 3) == 0)
|
||||
{
|
||||
offset = (fetch & 0xff) >> 2;
|
||||
#ifdef memory_safe
|
||||
if (3 > (unsigned int)(guaranteed_uncompressed - dst) || offset > (unsigned int)(dst - first_valid))
|
||||
return 0;
|
||||
#endif
|
||||
memcpy_up(dst, dst - offset, 3);
|
||||
dst += 3;
|
||||
src++;
|
||||
}
|
||||
else if ((fetch & 2) == 0)
|
||||
{
|
||||
offset = (fetch & 0xffff) >> 2;
|
||||
#ifdef memory_safe
|
||||
if (3 > (unsigned int)(guaranteed_uncompressed - dst) || offset > (unsigned int)(dst - first_valid))
|
||||
return 0;
|
||||
#endif
|
||||
memcpy_up(dst, dst - offset, 3);
|
||||
dst += 3;
|
||||
src += 2;
|
||||
}
|
||||
else if ((fetch & 1) == 0)
|
||||
{
|
||||
offset = (fetch & 0xffff) >> 6;
|
||||
matchlen = ((fetch >> 2) & 15) + 3;
|
||||
#ifdef memory_safe
|
||||
if (matchlen > (unsigned int)(guaranteed_uncompressed - dst) || offset > (unsigned int)(dst - first_valid))
|
||||
return 0;
|
||||
#endif
|
||||
memcpy_up(dst, dst - offset, matchlen);
|
||||
src += 2;
|
||||
dst += matchlen;
|
||||
}
|
||||
else if ((fetch & 4) == 0)
|
||||
{
|
||||
offset = (fetch & 0xffffff) >> 8;
|
||||
matchlen = ((fetch >> 3) & 31) + 3;
|
||||
#ifdef memory_safe
|
||||
if (matchlen > (unsigned int)(guaranteed_uncompressed - dst) || offset > (unsigned int)(dst - first_valid))
|
||||
return 0;
|
||||
#endif
|
||||
memcpy_up(dst, dst - offset, matchlen);
|
||||
src += 3;
|
||||
dst += matchlen;
|
||||
}
|
||||
else if ((fetch & 8) == 0)
|
||||
{
|
||||
offset = (fetch >> 15);
|
||||
if (offset != 0)
|
||||
{
|
||||
matchlen = ((fetch >> 4) & 2047) + 3;
|
||||
src += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchlen = fast_read_safe(src + 4, 4, source_c + source_size);
|
||||
offset = fast_read_safe(src + 8, 4, source_c + source_size);
|
||||
src += 12;
|
||||
}
|
||||
#ifdef memory_safe
|
||||
if (matchlen > (unsigned int)(guaranteed_uncompressed - dst) || offset > (unsigned int)(dst - first_valid))
|
||||
return 0;
|
||||
#endif
|
||||
memcpy_up(dst, dst - offset, matchlen);
|
||||
dst += matchlen;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
// decode rle sequence
|
||||
unsigned char rle_char;
|
||||
rle_char = (unsigned char)(fetch >> 16);
|
||||
matchlen = ((fetch >> 4) & 0xfff);
|
||||
|
||||
if(matchlen != 0)
|
||||
src += 3;
|
||||
else
|
||||
{
|
||||
matchlen = fast_read_safe(src + 3, 4, source_c + source_size);
|
||||
src += 7;
|
||||
}
|
||||
|
||||
#ifdef memory_safe
|
||||
if(matchlen > (unsigned int)(guaranteed_uncompressed - dst))
|
||||
return 0;
|
||||
#endif
|
||||
memset(dst, rle_char, matchlen);
|
||||
|
||||
#if(COMPRESSION_LEVEL == 0)
|
||||
while(last_hashed < dst - 1)
|
||||
{
|
||||
last_hashed++;
|
||||
hashtable[hash_func(fast_read(last_hashed, 4))] = last_hashed;
|
||||
}
|
||||
last_hashed = dst - 1 + matchlen;
|
||||
#endif
|
||||
dst += matchlen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// decode literal
|
||||
#ifdef memory_safe
|
||||
if (4 > destination_c + size - dst || src > source_c + source_size + 4)
|
||||
return 0;
|
||||
#endif
|
||||
memcpy_up(dst, src, 4);
|
||||
|
||||
dst += bitlut[cword_val & 0xf];
|
||||
src += bitlut[cword_val & 0xf];
|
||||
cword_val = cword_val >> (bitlut[cword_val & 0xf]);
|
||||
|
||||
#if(COMPRESSION_LEVEL == 0)
|
||||
while(last_hashed < dst - 3)
|
||||
{
|
||||
last_hashed++;
|
||||
hashtable[hash_func(fast_read(last_hashed, 4))] = last_hashed;
|
||||
}
|
||||
#endif
|
||||
if (dst >= guaranteed_uncompressed)
|
||||
{
|
||||
// decode last literals and exit
|
||||
while(dst < last_byte_successor)
|
||||
{
|
||||
if (cword_val == 1)
|
||||
{
|
||||
src += 4;
|
||||
cword_val = 1U << 31;
|
||||
}
|
||||
if (1 > destination_c + size - dst)
|
||||
return 0;
|
||||
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
cword_val = cword_val >> 1;
|
||||
}
|
||||
|
||||
#if(COMPRESSION_LEVEL == 0)
|
||||
while(last_hashed < last_byte_successor - 4)
|
||||
{
|
||||
last_hashed++;
|
||||
hashtable[hash_func(fast_read(last_hashed, 4))] = last_hashed;
|
||||
}
|
||||
#endif
|
||||
if((src - 1) - source_c > 8) // 8 bytes comp. size excessive len is ok
|
||||
return 0;
|
||||
else if(dst - destination_c - size == 0)
|
||||
return size;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t qlz_size_decompressed(const char *source)
|
||||
{
|
||||
unsigned int n, r;
|
||||
n = (((*source) & 2) == 2) ? 4 : 1;
|
||||
r = fast_read(source + 1 + n, n);
|
||||
r = r & (0xffffffff >> ((4 - n)*8));
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t qlz_size_compressed(const char *source)
|
||||
{
|
||||
unsigned int n, r;
|
||||
n = (((*source) & 2) == 2) ? 4 : 1;
|
||||
r = fast_read(source + 1, n);
|
||||
r = r & (0xffffffff >> ((4 - n)*8));
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t qlz_compress(const void *source, char *destination, size_t size, char *scratch)
|
||||
{
|
||||
// 1-8 bytes for aligning (not 0-7!); 8 bytes for buffersize (padds on 32 bit cpu); HASH_SIZE hash table; STREAMING_MODE_ROUNDED bytes streambuffer; optional HASH_ENTRIES byte hash counter
|
||||
unsigned char *buffer_aligned = (unsigned char *)scratch + 8 - (((size_t)scratch) % 8);
|
||||
const unsigned char *(*hashtable)[AND + 1] = (const unsigned char *(*)[AND + 1])(buffer_aligned + 8);
|
||||
size_t *buffersize = (size_t *)buffer_aligned;
|
||||
unsigned char *streambuffer = buffer_aligned + 8 + HASH_SIZE;
|
||||
unsigned int r;
|
||||
unsigned int compressed, base;
|
||||
unsigned char *hash_counter = streambuffer + STREAMING_MODE_ROUNDED;
|
||||
|
||||
if(size == 0 || size > 0xffffffff)
|
||||
return 0;
|
||||
|
||||
#if (COMPRESSION_LEVEL == 0 && STREAMING_MODE_ROUNDED == 0)
|
||||
memset((void *)hashtable, 0, HASH_SIZE);
|
||||
#endif
|
||||
|
||||
if(size < 216)
|
||||
base = 3;
|
||||
else
|
||||
base = 9;
|
||||
|
||||
// if not STREAMING_MODE, then STREAMING_MODE_ROUNDED == 0 and first case (streaming buffer full) is executed unconditionally, functioning as block comp.
|
||||
if (*buffersize + size - 1 >= STREAMING_MODE_ROUNDED)
|
||||
{
|
||||
#if (COMPRESSION_LEVEL == 0 && STREAMING_MODE_ROUNDED != 0)
|
||||
memset((void *)hashtable, 0, HASH_SIZE);
|
||||
#endif
|
||||
|
||||
r = base + qlz_compress_core(source, (unsigned char*)destination + base, (unsigned int)size, hashtable, (const unsigned char*)source, hash_counter);
|
||||
#if (COMPRESSION_LEVEL == 0 && STREAMING_MODE_ROUNDED != 0)
|
||||
memset((void *)hashtable, 0, HASH_SIZE);
|
||||
#endif
|
||||
|
||||
if(r == base)
|
||||
{
|
||||
memcpy(destination + base, source, size);
|
||||
r = (unsigned int)size + base;
|
||||
compressed = 0;
|
||||
}
|
||||
else
|
||||
compressed = 1;
|
||||
*buffersize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(streambuffer + *buffersize, source, size);
|
||||
r = base + qlz_compress_core(streambuffer + *buffersize, (unsigned char*)destination + base, (unsigned int)size, hashtable, streambuffer, hash_counter);
|
||||
|
||||
if(r == base)
|
||||
{
|
||||
memcpy(destination + base, streambuffer + *buffersize, size);
|
||||
r = (unsigned int)size + base;
|
||||
compressed = 0;
|
||||
|
||||
memset((void*)hashtable, 0, HASH_SIZE);
|
||||
}
|
||||
else
|
||||
compressed = 1;
|
||||
*buffersize += size;
|
||||
}
|
||||
|
||||
if(base == 3)
|
||||
{
|
||||
*destination = (unsigned char)(0 | compressed);
|
||||
*(destination + 1) = (unsigned char)r;
|
||||
*(destination + 2) = (unsigned char)size;
|
||||
}
|
||||
else
|
||||
{
|
||||
*destination = (unsigned char)(2 | compressed);
|
||||
fast_write(r, destination + 1, 4);
|
||||
fast_write((unsigned int)size, destination + 5, 4);
|
||||
}
|
||||
|
||||
#if (COMPRESSION_LEVEL == 0)
|
||||
*destination = (*destination) | 4;
|
||||
#endif
|
||||
|
||||
return (size_t)r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t qlz_decompress(const char *source, void *destination, char *scratch)
|
||||
{
|
||||
// 1-8 bytes for aligning (not 0-7!); 8 bytes for buffersize (padds on 32bit cpu); STREAMING_MODE_ROUNDED streambuffer; HASH_SIZE hash table
|
||||
unsigned char *buffer_aligned = (unsigned char *)scratch + 8 - (((size_t)scratch) % 8);
|
||||
size_t *buffersize = (size_t *)buffer_aligned;
|
||||
unsigned int headerlen = 2*((((*source) & 2) == 2) ? 4 : 1) + 1; // get header len
|
||||
|
||||
unsigned char *streambuffer = buffer_aligned + 8;
|
||||
const unsigned char **hashtable = (const unsigned char **)(streambuffer + STREAMING_MODE_ROUNDED);
|
||||
|
||||
size_t dsiz = qlz_size_decompressed((char *)source);
|
||||
size_t csiz = qlz_size_compressed((char *)source);
|
||||
if (*buffersize + qlz_size_decompressed((char *)source) - 1 >= STREAMING_MODE_ROUNDED)
|
||||
{
|
||||
if((*source & 1) == 1)
|
||||
qlz_decompress_core((const unsigned char *)source + headerlen, destination, dsiz, csiz, (unsigned char*)destination, hashtable);
|
||||
else
|
||||
memcpy(destination, source + headerlen, dsiz);
|
||||
*buffersize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((*source & 1) == 1)
|
||||
qlz_decompress_core((const unsigned char *)source + headerlen, streambuffer + *buffersize, dsiz, csiz, streambuffer, hashtable);
|
||||
else
|
||||
memcpy(streambuffer + *buffersize, source + headerlen, dsiz);
|
||||
memcpy(destination, streambuffer + *buffersize, dsiz);
|
||||
*buffersize += dsiz;
|
||||
}
|
||||
return dsiz;
|
||||
}
|
82
mednafen/compress/quicklz.h
Normal file
82
mednafen/compress/quicklz.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef QLZ_HEADER
|
||||
#define QLZ_HEADER
|
||||
|
||||
// Version 1.31 final
|
||||
#define QLZ_VERSION_MAJOR 1
|
||||
#define QLZ_VERSION_MINOR 3
|
||||
#define QLZ_VERSION_REVISION 1
|
||||
|
||||
// Set following flags according to the manual
|
||||
#define COMPRESSION_LEVEL 0
|
||||
//#define STREAMING_MODE 2000000
|
||||
#define test_rle
|
||||
#define speedup_incompressible
|
||||
//#define memory_safe
|
||||
|
||||
// Public functions of QuickLZ
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
size_t qlz_decompress(const char *source, void *destination, char *scratch);
|
||||
size_t qlz_compress(const void *source, char *destination, size_t size, char *scratch);
|
||||
size_t qlz_size_decompressed(const char *source);
|
||||
size_t qlz_size_compressed(const char *source);
|
||||
int qlz_get_setting(int setting);
|
||||
|
||||
#if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64))
|
||||
#define X86X64
|
||||
#endif
|
||||
|
||||
// Compute SCRATCH_COMPRESS, SCRATCH_DECOMPRESS and constants used internally
|
||||
#if COMPRESSION_LEVEL == 0 && defined(memory_safe)
|
||||
#error memory_safe flag cannot be used with COMPRESSION_LEVEL 0
|
||||
#endif
|
||||
|
||||
#define HASH_ENTRIES 4096
|
||||
|
||||
#if (COMPRESSION_LEVEL == 0 || COMPRESSION_LEVEL == 1 || COMPRESSION_LEVEL == 2)
|
||||
#define AND 1
|
||||
#elif (COMPRESSION_LEVEL == 3)
|
||||
#define AND 0x7
|
||||
#else
|
||||
#error COMPRESSION_LEVEL must be 0, 1, 2 or 3
|
||||
#endif
|
||||
|
||||
#define HASH_SIZE (AND + 1)*HASH_ENTRIES*sizeof(unsigned char *)
|
||||
|
||||
#ifdef STREAMING_MODE
|
||||
#define STREAMING_MODE_VALUE STREAMING_MODE
|
||||
#else
|
||||
#define STREAMING_MODE_VALUE 0
|
||||
#endif
|
||||
|
||||
#define STREAMING_MODE_ROUNDED ((STREAMING_MODE_VALUE >> 3) << 3)
|
||||
|
||||
#if (COMPRESSION_LEVEL > 1)
|
||||
#define SCRATCH_COMPRESS HASH_SIZE + STREAMING_MODE_VALUE + 16 + HASH_ENTRIES
|
||||
#else
|
||||
#define SCRATCH_COMPRESS HASH_SIZE + STREAMING_MODE_VALUE + 16
|
||||
#endif
|
||||
|
||||
#if (COMPRESSION_LEVEL == 0)
|
||||
#define SCRATCH_DECOMPRESS HASH_ENTRIES*sizeof(unsigned char *) + 16 + STREAMING_MODE_VALUE
|
||||
#else
|
||||
#define SCRATCH_DECOMPRESS 16 + STREAMING_MODE_VALUE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
1561
mednafen/compress/unzip.c
Normal file
1561
mednafen/compress/unzip.c
Normal file
File diff suppressed because it is too large
Load Diff
357
mednafen/compress/unzip.h
Normal file
357
mednafen/compress/unzip.h
Normal file
@ -0,0 +1,357 @@
|
||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
|
||||
WinZip, InfoZip tools and compatible.
|
||||
|
||||
Multi volume ZipFile (span) are not supported.
|
||||
Encryption compatible with pkzip 2.04g only supported
|
||||
Old compressions used by old PKZip 1.x are not supported
|
||||
|
||||
|
||||
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
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
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"
|
||||
#ifndef OF
|
||||
#define OF(a) a
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#include "ioapi.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 XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
|
||||
"zlib/zlib113.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 unzOpen2 OF((const char *path,
|
||||
zlib_filefunc_def* pzlib_filefunc_def));
|
||||
/*
|
||||
Open a Zip file, like unzOpen, but provide a set of file low level API
|
||||
for read/write the zip file (see ioapi.h)
|
||||
*/
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
/* ****************************************** */
|
||||
/* Ryan supplied functions */
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_pos_s
|
||||
{
|
||||
uLong pos_in_zip_directory; /* offset in zip file directory */
|
||||
uLong num_of_file; /* # of file */
|
||||
} unz_file_pos;
|
||||
|
||||
extern int ZEXPORT unzGetFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
extern int ZEXPORT unzGoToFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
/* ****************************************** */
|
||||
|
||||
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 unzOpenCurrentFilePassword OF((unzFile file,
|
||||
const char* password));
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
password is a crypting password
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw,
|
||||
const char* password));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* Get the current file offset */
|
||||
extern uLong ZEXPORT unzGetOffset (unzFile file);
|
||||
|
||||
/* Set the current file offset */
|
||||
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _unz_H */
|
13
mednafen/cputest/Makefile.am.inc
Normal file
13
mednafen/cputest/Makefile.am.inc
Normal file
@ -0,0 +1,13 @@
|
||||
mednafen_SOURCES += cputest/cputest.c
|
||||
|
||||
if ARCH_X86
|
||||
mednafen_SOURCES += cputest/x86_cpu.c
|
||||
endif
|
||||
|
||||
if ARCH_POWERPC
|
||||
mednafen_SOURCES += cputest/ppc_cpu.c
|
||||
endif
|
||||
|
||||
#if ARCH_ARM
|
||||
#mednafen_SOURCES += cputest/arm_cpu.c
|
||||
#endif
|
3
mednafen/cputest/README
Normal file
3
mednafen/cputest/README
Normal file
@ -0,0 +1,3 @@
|
||||
modified slightly for usage in Mednafen
|
||||
|
||||
ARM stuff not compiled in, for now.
|
29
mednafen/cputest/arm_cpu.c
Normal file
29
mednafen/cputest/arm_cpu.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "cputest.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
int ff_get_cpu_flags_arm(void)
|
||||
{
|
||||
|
||||
return 0;
|
||||
// return HAVE_IWMMXT * CPUTEST_FLAG_IWMMXT;
|
||||
}
|
86
mednafen/cputest/cputest.c
Normal file
86
mednafen/cputest/cputest.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "cputest.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
static int flags, checked = 0;
|
||||
|
||||
|
||||
void cputest_force_flags(int arg)
|
||||
{
|
||||
flags = arg;
|
||||
checked = 1;
|
||||
}
|
||||
|
||||
int cputest_get_flags(void)
|
||||
{
|
||||
if (checked)
|
||||
return flags;
|
||||
|
||||
// if (ARCH_ARM) flags = ff_get_cpu_flags_arm();
|
||||
#if ARCH_POWERPC
|
||||
flags = ff_get_cpu_flags_ppc();
|
||||
#endif
|
||||
|
||||
#if ARCH_X86
|
||||
flags = ff_get_cpu_flags_x86();
|
||||
#endif
|
||||
|
||||
checked = 1;
|
||||
return flags;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//#ifdef TEST
|
||||
|
||||
#undef printf
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
printf("cpu_flags = 0x%08X\n", cpu_flags);
|
||||
printf("cpu_flags = %s%s%s%s%s%s%s%s%s%s%s%s%s\n",
|
||||
#if ARCH_ARM
|
||||
cpu_flags & CPUTEST_FLAG_IWMMXT ? "IWMMXT " : "",
|
||||
#elif ARCH_POWERPC
|
||||
cpu_flags & CPUTEST_FLAG_ALTIVEC ? "ALTIVEC " : "",
|
||||
#elif ARCH_X86
|
||||
cpu_flags & CPUTEST_FLAG_MMX ? "MMX " : "",
|
||||
cpu_flags & CPUTEST_FLAG_MMX2 ? "MMX2 " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSE ? "SSE " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSE2 ? "SSE2 " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSE2SLOW ? "SSE2(slow) " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSE3 ? "SSE3 " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSE3SLOW ? "SSE3(slow) " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSSE3 ? "SSSE3 " : "",
|
||||
cpu_flags & CPUTEST_FLAG_ATOM ? "Atom " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSE4 ? "SSE4.1 " : "",
|
||||
cpu_flags & CPUTEST_FLAG_SSE42 ? "SSE4.2 " : "",
|
||||
cpu_flags & CPUTEST_FLAG_AVX ? "AVX " : "",
|
||||
cpu_flags & CPUTEST_FLAG_3DNOW ? "3DNow " : "",
|
||||
cpu_flags & CPUTEST_FLAG_3DNOWEXT ? "3DNowExt " : "");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
70
mednafen/cputest/cputest.h
Normal file
70
mednafen/cputest/cputest.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef AVUTIL_CPU_H
|
||||
#define AVUTIL_CPU_H
|
||||
|
||||
#define CPUTEST_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */
|
||||
|
||||
/* lower 16 bits - CPU features */
|
||||
#define CPUTEST_FLAG_MMX 0x0001 ///< standard MMX
|
||||
#define CPUTEST_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext
|
||||
#define CPUTEST_FLAG_3DNOW 0x0004 ///< AMD 3DNOW
|
||||
#define CPUTEST_FLAG_SSE 0x0008 ///< SSE functions
|
||||
#define CPUTEST_FLAG_SSE2 0x0010 ///< PIV SSE2 functions
|
||||
#define CPUTEST_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster
|
||||
#define CPUTEST_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt
|
||||
#define CPUTEST_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions
|
||||
#define CPUTEST_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster
|
||||
#define CPUTEST_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions
|
||||
#define CPUTEST_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower
|
||||
#define CPUTEST_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions
|
||||
#define CPUTEST_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions
|
||||
#define CPUTEST_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used
|
||||
//#define CPUTEST_FLAG_IWMMXT 0x0100 ///< XScale IWMMXT
|
||||
#define CPUTEST_FLAG_ALTIVEC 0x0001 ///< standard
|
||||
|
||||
/**
|
||||
* Return the flags which specify extensions supported by the CPU.
|
||||
*/
|
||||
int cputest_get_flags(void);
|
||||
|
||||
|
||||
/**
|
||||
* Disables cpu detection and forces the specified flags.
|
||||
*/
|
||||
void cputest_force_flags(int flags);
|
||||
|
||||
|
||||
/* The following CPU-specific functions shall not be called directly. */
|
||||
int ff_get_cpu_flags_arm(void);
|
||||
int ff_get_cpu_flags_ppc(void);
|
||||
int ff_get_cpu_flags_x86(void);
|
||||
|
||||
#endif /* AVUTIL_CPU_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} //extern "C"
|
||||
#endif
|
||||
|
87
mednafen/cputest/ppc_cpu.c
Normal file
87
mednafen/cputest/ppc_cpu.c
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <machine/cpu.h>
|
||||
#elif defined(__AMIGAOS4__)
|
||||
#include <exec/exec.h>
|
||||
#include <interfaces/exec.h>
|
||||
#include <proto/exec.h>
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#include "cputest.h"
|
||||
|
||||
/**
|
||||
* This function MAY rely on signal() or fork() in order to make sure AltiVec
|
||||
* is present.
|
||||
*/
|
||||
int ff_get_cpu_flags_ppc(void)
|
||||
{
|
||||
//#if HAVE_ALTIVEC
|
||||
#if ARCH_POWERPC_ALTIVEC
|
||||
#ifdef __AMIGAOS4__
|
||||
ULONG result = 0;
|
||||
extern struct ExecIFace *IExec;
|
||||
|
||||
IExec->GetCPUInfoTags(GCIT_VectorUnit, &result, TAG_DONE);
|
||||
if (result == VECTORTYPE_ALTIVEC)
|
||||
return CPUTEST_FLAG_ALTIVEC;
|
||||
return 0;
|
||||
#elif defined(__APPLE__) || defined(__OpenBSD__)
|
||||
#ifdef __OpenBSD__
|
||||
int sels[2] = {CTL_MACHDEP, CPU_ALTIVEC};
|
||||
#else
|
||||
int sels[2] = {CTL_HW, HW_VECTORUNIT};
|
||||
#endif
|
||||
int has_vu = 0;
|
||||
size_t len = sizeof(has_vu);
|
||||
int err;
|
||||
|
||||
err = sysctl(sels, 2, &has_vu, &len, NULL, 0);
|
||||
|
||||
if (err == 0)
|
||||
return has_vu ? CPUTEST_FLAG_ALTIVEC : 0;
|
||||
return 0;
|
||||
#elif CONFIG_RUNTIME_CPUDETECT
|
||||
int proc_ver;
|
||||
// Support of mfspr PVR emulation added in Linux 2.6.17.
|
||||
__asm__ volatile("mfspr %0, 287" : "=r" (proc_ver));
|
||||
proc_ver >>= 16;
|
||||
if (proc_ver & 0x8000 ||
|
||||
proc_ver == 0x000c ||
|
||||
proc_ver == 0x0039 || proc_ver == 0x003c ||
|
||||
proc_ver == 0x0044 || proc_ver == 0x0045 ||
|
||||
proc_ver == 0x0070)
|
||||
return CPUTEST_FLAG_ALTIVEC;
|
||||
return 0;
|
||||
#else
|
||||
// Since we were compiled for AltiVec, just assume we have it
|
||||
// until someone comes up with a proper way (not involving signal hacks).
|
||||
return CPUTEST_FLAG_ALTIVEC;
|
||||
#endif /* __AMIGAOS4__ */
|
||||
#endif /* HAVE_ALTIVEC */
|
||||
return 0;
|
||||
}
|
159
mednafen/cputest/x86_cpu.c
Normal file
159
mednafen/cputest/x86_cpu.c
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* CPU detection code, extracted from mmx.h
|
||||
* (c)1997-99 by H. Dietz and R. Fisher
|
||||
* Converted to C and improved by Fabrice Bellard.
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "x86_cpu.h"
|
||||
#include "cputest.h"
|
||||
|
||||
/* ebx saving is necessary for PIC. gcc seems unable to see it alone */
|
||||
#define cpuid(index,eax,ebx,ecx,edx)\
|
||||
__asm__ volatile\
|
||||
("mov %%"REG_b", %%"REG_S"\n\t"\
|
||||
"cpuid\n\t"\
|
||||
"xchg %%"REG_b", %%"REG_S\
|
||||
: "=a" (eax), "=S" (ebx),\
|
||||
"=c" (ecx), "=d" (edx)\
|
||||
: "0" (index));
|
||||
|
||||
#define xgetbv(index,eax,edx) \
|
||||
__asm__ (".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c" (index))
|
||||
|
||||
/* Function to test if multimedia instructions are supported... */
|
||||
int ff_get_cpu_flags_x86(void)
|
||||
{
|
||||
int rval = 0;
|
||||
int eax, ebx, ecx, edx;
|
||||
int max_std_level, max_ext_level, std_caps=0, ext_caps=0;
|
||||
int family=0, model=0;
|
||||
union { int i[3]; char c[12]; } vendor;
|
||||
|
||||
#if ARCH_X86_32
|
||||
x86_reg a, c;
|
||||
__asm__ volatile (
|
||||
/* See if CPUID instruction is supported ... */
|
||||
/* ... Get copies of EFLAGS into eax and ecx */
|
||||
"pushfl\n\t"
|
||||
"pop %0\n\t"
|
||||
"mov %0, %1\n\t"
|
||||
|
||||
/* ... Toggle the ID bit in one copy and store */
|
||||
/* to the EFLAGS reg */
|
||||
"xor $0x200000, %0\n\t"
|
||||
"push %0\n\t"
|
||||
"popfl\n\t"
|
||||
|
||||
/* ... Get the (hopefully modified) EFLAGS */
|
||||
"pushfl\n\t"
|
||||
"pop %0\n\t"
|
||||
: "=a" (a), "=c" (c)
|
||||
:
|
||||
: "cc"
|
||||
);
|
||||
|
||||
if (a == c)
|
||||
return 0; /* CPUID not supported */
|
||||
#endif
|
||||
|
||||
cpuid(0, max_std_level, vendor.i[0], vendor.i[2], vendor.i[1]);
|
||||
|
||||
if(max_std_level >= 1){
|
||||
cpuid(1, eax, ebx, ecx, std_caps);
|
||||
family = ((eax>>8)&0xf) + ((eax>>20)&0xff);
|
||||
model = ((eax>>4)&0xf) + ((eax>>12)&0xf0);
|
||||
if (std_caps & (1<<23))
|
||||
rval |= CPUTEST_FLAG_MMX;
|
||||
if (std_caps & (1<<25))
|
||||
rval |= CPUTEST_FLAG_MMX2
|
||||
//#if HAVE_SSE
|
||||
| CPUTEST_FLAG_SSE;
|
||||
if (std_caps & (1<<26))
|
||||
rval |= CPUTEST_FLAG_SSE2;
|
||||
if (ecx & 1)
|
||||
rval |= CPUTEST_FLAG_SSE3;
|
||||
if (ecx & 0x00000200 )
|
||||
rval |= CPUTEST_FLAG_SSSE3;
|
||||
if (ecx & 0x00080000 )
|
||||
rval |= CPUTEST_FLAG_SSE4;
|
||||
if (ecx & 0x00100000 )
|
||||
rval |= CPUTEST_FLAG_SSE42;
|
||||
//#if HAVE_AVX
|
||||
/* Check OXSAVE and AVX bits */
|
||||
if ((ecx & 0x18000000) == 0x18000000) {
|
||||
/* Check for OS support */
|
||||
xgetbv(0, eax, edx);
|
||||
if ((eax & 0x6) == 0x6)
|
||||
rval |= CPUTEST_FLAG_AVX;
|
||||
}
|
||||
//#endif
|
||||
//#endif
|
||||
;
|
||||
}
|
||||
|
||||
cpuid(0x80000000, max_ext_level, ebx, ecx, edx);
|
||||
|
||||
if(max_ext_level >= 0x80000001){
|
||||
cpuid(0x80000001, eax, ebx, ecx, ext_caps);
|
||||
if (ext_caps & (1<<31))
|
||||
rval |= CPUTEST_FLAG_3DNOW;
|
||||
if (ext_caps & (1<<30))
|
||||
rval |= CPUTEST_FLAG_3DNOWEXT;
|
||||
if (ext_caps & (1<<23))
|
||||
rval |= CPUTEST_FLAG_MMX;
|
||||
if (ext_caps & (1<<22))
|
||||
rval |= CPUTEST_FLAG_MMX2;
|
||||
|
||||
/* Allow for selectively disabling SSE2 functions on AMD processors
|
||||
with SSE2 support but not SSE4a. This includes Athlon64, some
|
||||
Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster
|
||||
than SSE2 often enough to utilize this special-case flag.
|
||||
CPUTEST_FLAG_SSE2 and CPUTEST_FLAG_SSE2SLOW are both set in this case
|
||||
so that SSE2 is used unless explicitly disabled by checking
|
||||
CPUTEST_FLAG_SSE2SLOW. */
|
||||
if (!strncmp(vendor.c, "AuthenticAMD", 12) &&
|
||||
rval & CPUTEST_FLAG_SSE2 && !(ecx & 0x00000040)) {
|
||||
rval |= CPUTEST_FLAG_SSE2SLOW;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(vendor.c, "GenuineIntel", 12)) {
|
||||
if (family == 6 && (model == 9 || model == 13 || model == 14)) {
|
||||
/* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and 6/14 (core1 "yonah")
|
||||
* theoretically support sse2, but it's usually slower than mmx,
|
||||
* so let's just pretend they don't. CPUTEST_FLAG_SSE2 is disabled and
|
||||
* CPUTEST_FLAG_SSE2SLOW is enabled so that SSE2 is not used unless
|
||||
* explicitly enabled by checking CPUTEST_FLAG_SSE2SLOW. The same
|
||||
* situation applies for CPUTEST_FLAG_SSE3 and CPUTEST_FLAG_SSE3SLOW. */
|
||||
if (rval & CPUTEST_FLAG_SSE2) rval ^= CPUTEST_FLAG_SSE2SLOW|CPUTEST_FLAG_SSE2;
|
||||
if (rval & CPUTEST_FLAG_SSE3) rval ^= CPUTEST_FLAG_SSE3SLOW|CPUTEST_FLAG_SSE3;
|
||||
}
|
||||
/* The Atom processor has SSSE3 support, which is useful in many cases,
|
||||
* but sometimes the SSSE3 version is slower than the SSE2 equivalent
|
||||
* on the Atom, but is generally faster on other processors supporting
|
||||
* SSSE3. This flag allows for selectively disabling certain SSSE3
|
||||
* functions on the Atom. */
|
||||
if (family == 6 && model == 28)
|
||||
rval |= CPUTEST_FLAG_ATOM;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
101
mednafen/cputest/x86_cpu.h
Normal file
101
mednafen/cputest/x86_cpu.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_X86_CPU_H
|
||||
#define AVUTIL_X86_CPU_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if ARCH_X86_64
|
||||
# define OPSIZE "q"
|
||||
# define REG_a "rax"
|
||||
# define REG_b "rbx"
|
||||
# define REG_c "rcx"
|
||||
# define REG_d "rdx"
|
||||
# define REG_D "rdi"
|
||||
# define REG_S "rsi"
|
||||
# define PTR_SIZE "8"
|
||||
typedef int64_t x86_reg;
|
||||
|
||||
# define REG_SP "rsp"
|
||||
# define REG_BP "rbp"
|
||||
# define REGBP rbp
|
||||
# define REGa rax
|
||||
# define REGb rbx
|
||||
# define REGc rcx
|
||||
# define REGd rdx
|
||||
# define REGSP rsp
|
||||
|
||||
#elif ARCH_X86_32
|
||||
|
||||
# define OPSIZE "l"
|
||||
# define REG_a "eax"
|
||||
# define REG_b "ebx"
|
||||
# define REG_c "ecx"
|
||||
# define REG_d "edx"
|
||||
# define REG_D "edi"
|
||||
# define REG_S "esi"
|
||||
# define PTR_SIZE "4"
|
||||
typedef int32_t x86_reg;
|
||||
|
||||
# define REG_SP "esp"
|
||||
# define REG_BP "ebp"
|
||||
# define REGBP ebp
|
||||
# define REGa eax
|
||||
# define REGb ebx
|
||||
# define REGc ecx
|
||||
# define REGd edx
|
||||
# define REGSP esp
|
||||
#else
|
||||
typedef int x86_reg;
|
||||
#endif
|
||||
|
||||
#define HAVE_7REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE && HAVE_EBP_AVAILABLE))
|
||||
#define HAVE_6REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE || HAVE_EBP_AVAILABLE))
|
||||
|
||||
#if ARCH_X86_64 && defined(PIC)
|
||||
# define BROKEN_RELOCATIONS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If gcc is not set to support sse (-msse) it will not accept xmm registers
|
||||
* in the clobber list for inline asm. XMM_CLOBBERS takes a list of xmm
|
||||
* registers to be marked as clobbered and evaluates to nothing if they are
|
||||
* not supported, or to the list itself if they are supported. Since a clobber
|
||||
* list may not be empty, XMM_CLOBBERS_ONLY should be used if the xmm
|
||||
* registers are the only in the clobber list.
|
||||
* For example a list with "eax" and "xmm0" as clobbers should become:
|
||||
* : XMM_CLOBBERS("xmm0",) "eax"
|
||||
* and a list with only "xmm0" should become:
|
||||
* XMM_CLOBBERS_ONLY("xmm0")
|
||||
*/
|
||||
#if HAVE_XMM_CLOBBERS
|
||||
# define XMM_CLOBBERS(...) __VA_ARGS__
|
||||
# define XMM_CLOBBERS_ONLY(...) : __VA_ARGS__
|
||||
#else
|
||||
# define XMM_CLOBBERS(...)
|
||||
# define XMM_CLOBBERS_ONLY(...)
|
||||
#endif
|
||||
|
||||
#endif /* AVUTIL_X86_CPU_H */
|
15
mednafen/driver.h
Normal file
15
mednafen/driver.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _MDFN_DRIVERH
|
||||
#define _MDFN_DRIVERH
|
||||
|
||||
#include "mednafen-types.h"
|
||||
#include <stdio.h> // REMOVE ME eventually
|
||||
#include "git.h"
|
||||
#include "settings-driver.h"
|
||||
#include "mednafen-driver.h"
|
||||
#include "netplay-driver.h"
|
||||
#include "state-driver.h"
|
||||
#include "movie-driver.h"
|
||||
#include "mempatcher-driver.h"
|
||||
#include "video-driver.h"
|
||||
|
||||
#endif
|
245
mednafen/endian.cpp
Normal file
245
mednafen/endian.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "mednafen.h"
|
||||
#include "mednafen-endian.h"
|
||||
|
||||
void Endian_A16_Swap(void *src, uint32 nelements)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 tmp = nsrc[i * 2];
|
||||
|
||||
nsrc[i * 2] = nsrc[i * 2 + 1];
|
||||
nsrc[i * 2 + 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_A32_Swap(void *src, uint32 nelements)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 tmp1 = nsrc[i * 4];
|
||||
uint8 tmp2 = nsrc[i * 4 + 1];
|
||||
|
||||
nsrc[i * 4] = nsrc[i * 4 + 3];
|
||||
nsrc[i * 4 + 1] = nsrc[i * 4 + 2];
|
||||
|
||||
nsrc[i * 4 + 2] = tmp2;
|
||||
nsrc[i * 4 + 3] = tmp1;
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_A64_Swap(void *src, uint32 nelements)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 *base = &nsrc[i * 8];
|
||||
|
||||
for(int z = 0; z < 4; z++)
|
||||
{
|
||||
uint8 tmp = base[z];
|
||||
|
||||
base[z] = base[7 - z];
|
||||
base[7 - z] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_A16_NE_to_LE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Endian_A16_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A32_NE_to_LE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Endian_A32_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A64_NE_to_LE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Endian_A64_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Endian_A16_LE_to_NE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 tmp = nsrc[i * 2];
|
||||
|
||||
nsrc[i * 2] = nsrc[i * 2 + 1];
|
||||
nsrc[i * 2 + 1] = tmp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A16_BE_to_NE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 tmp = nsrc[i * 2];
|
||||
|
||||
nsrc[i * 2] = nsrc[i * 2 + 1];
|
||||
nsrc[i * 2 + 1] = tmp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Endian_A32_LE_to_NE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 tmp1 = nsrc[i * 4];
|
||||
uint8 tmp2 = nsrc[i * 4 + 1];
|
||||
|
||||
nsrc[i * 4] = nsrc[i * 4 + 3];
|
||||
nsrc[i * 4 + 1] = nsrc[i * 4 + 2];
|
||||
|
||||
nsrc[i * 4 + 2] = tmp2;
|
||||
nsrc[i * 4 + 3] = tmp1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A64_LE_to_NE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 *base = &nsrc[i * 8];
|
||||
|
||||
for(int z = 0; z < 4; z++)
|
||||
{
|
||||
uint8 tmp = base[z];
|
||||
|
||||
base[z] = base[7 - z];
|
||||
base[7 - z] = tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FlipByteOrder(uint8 *src, uint32 count)
|
||||
{
|
||||
uint8 *start=src;
|
||||
uint8 *end=src+count-1;
|
||||
|
||||
if((count&1) || !count) return; /* This shouldn't happen. */
|
||||
|
||||
count >>= 1;
|
||||
|
||||
while(count--)
|
||||
{
|
||||
uint8 tmp;
|
||||
|
||||
tmp=*end;
|
||||
*end=*start;
|
||||
*start=tmp;
|
||||
end--;
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_V_LE_to_NE(void *src, uint32 bytesize)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
FlipByteOrder((uint8 *)src, bytesize);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_V_NE_to_LE(void *src, uint32 bytesize)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
FlipByteOrder((uint8 *)src, bytesize);
|
||||
#endif
|
||||
}
|
||||
|
||||
int write16le(uint16 b, FILE *fp)
|
||||
{
|
||||
uint8 s[2];
|
||||
s[0]=b;
|
||||
s[1]=b>>8;
|
||||
return((fwrite(s,1,2,fp)<2)?0:2);
|
||||
}
|
||||
|
||||
int write32le(uint32 b, FILE *fp)
|
||||
{
|
||||
uint8 s[4];
|
||||
s[0]=b;
|
||||
s[1]=b>>8;
|
||||
s[2]=b>>16;
|
||||
s[3]=b>>24;
|
||||
return((fwrite(s,1,4,fp)<4)?0:4);
|
||||
}
|
||||
|
||||
int read32le(uint32 *Bufo, FILE *fp)
|
||||
{
|
||||
uint32 buf;
|
||||
if(fread(&buf,1,4,fp)<4)
|
||||
return 0;
|
||||
#ifdef LSB_FIRST
|
||||
*(uint32*)Bufo=buf;
|
||||
#else
|
||||
*(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read16le(char *d, FILE *fp)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
return((fread(d,1,2,fp)<2)?0:2);
|
||||
#else
|
||||
int ret;
|
||||
ret=fread(d+1,1,1,fp);
|
||||
ret+=fread(d,1,1,fp);
|
||||
return ret<2?0:2;
|
||||
#endif
|
||||
}
|
||||
|
127
mednafen/error.cpp
Normal file
127
mednafen/error.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "mednafen.h"
|
||||
#include "error.h"
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <trio/trio.h>
|
||||
|
||||
MDFN_Error::MDFN_Error() throw()
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
MDFN_Error::MDFN_Error(int errno_code_new, const char *format, ...) throw()
|
||||
{
|
||||
errno_code = errno_code_new;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
error_message = trio_vaprintf(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
MDFN_Error::~MDFN_Error() throw()
|
||||
{
|
||||
if(error_message)
|
||||
{
|
||||
free(error_message);
|
||||
error_message = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
MDFN_Error::MDFN_Error(const MDFN_Error &ze_error) throw()
|
||||
{
|
||||
if(ze_error.error_message)
|
||||
error_message = strdup(ze_error.error_message);
|
||||
else
|
||||
error_message = NULL;
|
||||
|
||||
errno_code = ze_error.errno_code;
|
||||
}
|
||||
|
||||
MDFN_Error& MDFN_Error::operator=(const MDFN_Error &ze_error) throw()
|
||||
{
|
||||
char *new_error_message = ze_error.error_message ? strdup(ze_error.error_message) : NULL;
|
||||
int new_errno_code = ze_error.errno_code;
|
||||
|
||||
if(error_message)
|
||||
free(error_message);
|
||||
|
||||
error_message = new_error_message;
|
||||
errno_code = new_errno_code;
|
||||
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
const char * MDFN_Error::what(void) const throw()
|
||||
{
|
||||
if(!error_message)
|
||||
return("Error allocating memory for the error message!");
|
||||
|
||||
return(error_message);
|
||||
}
|
||||
|
||||
int MDFN_Error::GetErrno(void) throw()
|
||||
{
|
||||
return(errno_code);
|
||||
}
|
||||
|
||||
static const char *srr_wrap(int ret, const char *local_strerror)
|
||||
{
|
||||
if(ret == -1)
|
||||
return("ERROR IN strerror_r()!!!");
|
||||
|
||||
return(local_strerror);
|
||||
}
|
||||
|
||||
static const char *srr_wrap(const char *ret, const char *local_strerror)
|
||||
{
|
||||
if(ret == NULL)
|
||||
return("ERROR IN strerror_r()!!!");
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void ErrnoHolder::SetErrno(int the_errno)
|
||||
{
|
||||
local_errno = the_errno;
|
||||
|
||||
if(the_errno == 0)
|
||||
local_strerror[0] = 0;
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_STRERROR_R
|
||||
const char *retv;
|
||||
|
||||
retv = srr_wrap(strerror_r(the_errno, local_strerror, 256), local_strerror);
|
||||
|
||||
if(retv != local_strerror)
|
||||
strncpy(local_strerror, retv, 255);
|
||||
|
||||
#else // No strerror_r :(
|
||||
|
||||
strncpy(local_strerror, strerror(the_errno), 255);
|
||||
|
||||
#endif
|
||||
|
||||
local_strerror[255] = 0;
|
||||
}
|
||||
}
|
||||
|
72
mednafen/error.h
Normal file
72
mednafen/error.h
Normal file
@ -0,0 +1,72 @@
|
||||
#ifndef __MDFN_ERROR_H
|
||||
#define __MDFN_ERROR_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <exception>
|
||||
|
||||
#ifdef __cplusplus
|
||||
class MDFN_Error : public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
MDFN_Error() throw();
|
||||
|
||||
MDFN_Error(int errno_code_new, const char *format, ...) throw();
|
||||
|
||||
~MDFN_Error() throw();
|
||||
|
||||
MDFN_Error(const MDFN_Error &ze_error) throw();
|
||||
MDFN_Error & operator=(const MDFN_Error &ze_error) throw();
|
||||
|
||||
virtual const char *what(void) const throw();
|
||||
int GetErrno(void) throw();
|
||||
|
||||
private:
|
||||
|
||||
int errno_code;
|
||||
char *error_message;
|
||||
};
|
||||
|
||||
class ErrnoHolder
|
||||
{
|
||||
public:
|
||||
|
||||
ErrnoHolder()
|
||||
{
|
||||
//SetErrno(0);
|
||||
local_errno = 0;
|
||||
local_strerror[0] = 0;
|
||||
}
|
||||
|
||||
ErrnoHolder(int the_errno)
|
||||
{
|
||||
SetErrno(the_errno);
|
||||
}
|
||||
|
||||
inline int Errno(void)
|
||||
{
|
||||
return(local_errno);
|
||||
}
|
||||
|
||||
const char *StrError(void)
|
||||
{
|
||||
return(local_strerror);
|
||||
}
|
||||
|
||||
void operator=(int the_errno)
|
||||
{
|
||||
SetErrno(the_errno);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void SetErrno(int the_errno);
|
||||
|
||||
int local_errno;
|
||||
char local_strerror[256];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
796
mednafen/file.cpp
Normal file
796
mednafen/file.cpp
Normal file
@ -0,0 +1,796 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "mednafen.h"
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <trio/trio.h>
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <zlib.h>
|
||||
#include "compress/unzip.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "general.h"
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define strcasecmp strcmp
|
||||
#endif
|
||||
|
||||
static const int64 MaxROMImageSize = (int64)1 << 26; // 2 ^ 26 = 64MiB
|
||||
|
||||
enum
|
||||
{
|
||||
MDFN_FILETYPE_PLAIN = 0,
|
||||
MDFN_FILETYPE_GZIP = 1,
|
||||
MDFN_FILETYPE_ZIP = 2,
|
||||
};
|
||||
|
||||
static const char *unzErrorString(int error_code)
|
||||
{
|
||||
if(error_code == UNZ_OK)
|
||||
return("ZIP OK");
|
||||
else if(error_code == UNZ_END_OF_LIST_OF_FILE)
|
||||
return("ZIP End of file list");
|
||||
else if(error_code == UNZ_EOF)
|
||||
return("ZIP EOF");
|
||||
else if(error_code == UNZ_PARAMERROR)
|
||||
return("ZIP Parameter error");
|
||||
else if(error_code == UNZ_BADZIPFILE)
|
||||
return("ZIP file bad");
|
||||
else if(error_code == UNZ_INTERNALERROR)
|
||||
return("ZIP Internal error");
|
||||
else if(error_code == UNZ_CRCERROR)
|
||||
return("ZIP CRC error");
|
||||
else if(error_code == UNZ_ERRNO)
|
||||
return(strerror(errno));
|
||||
else
|
||||
return("ZIP Unknown");
|
||||
}
|
||||
|
||||
bool MDFNFILE::ApplyIPS(FILE *ips)
|
||||
{
|
||||
uint8 header[5];
|
||||
uint32 count = 0;
|
||||
|
||||
//MDFN_printf(_("Applying IPS file \"%s\"...\n"), path);
|
||||
|
||||
MDFN_indent(1);
|
||||
if(::fread(header, 1, 5, ips) != 5)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
MDFN_PrintError(_("Error reading IPS file header: %s"), ene.StrError());
|
||||
MDFN_indent(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(memcmp(header, "PATCH", 5))
|
||||
{
|
||||
MDFN_PrintError(_("IPS file header is invalid."));
|
||||
MDFN_indent(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
// If the file is mmap()'d, move it to malloc()'d RAM
|
||||
if(is_mmap)
|
||||
{
|
||||
void *tmp_ptr = MDFN_malloc(f_size, _("file read buffer"));
|
||||
if(!tmp_ptr)
|
||||
{
|
||||
//Close();
|
||||
//fclose(ipsfile);
|
||||
return(0);
|
||||
}
|
||||
memcpy(tmp_ptr, f_data, f_size);
|
||||
|
||||
munmap(f_data, f_size);
|
||||
|
||||
is_mmap = FALSE;
|
||||
f_data = (uint8 *)tmp_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
while(::fread(header, 1, 3, ips) == 3)
|
||||
{
|
||||
uint32 offset = (header[0] << 16) | (header[1] << 8) | header[2];
|
||||
uint8 patch_size_raw[2];
|
||||
uint32 patch_size;
|
||||
bool rle = false;
|
||||
|
||||
if(!memcmp(header, "EOF", 3))
|
||||
{
|
||||
MDFN_printf(_("IPS EOF: Did %d patches\n\n"), count);
|
||||
MDFN_indent(-1);
|
||||
return(1);
|
||||
}
|
||||
|
||||
if(::fread(patch_size_raw, 1, 2, ips) != 2)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
MDFN_PrintError(_("Error reading IPS patch length: %s"), ene.StrError());
|
||||
return(0);
|
||||
}
|
||||
|
||||
patch_size = MDFN_de16msb(patch_size_raw);
|
||||
|
||||
if(!patch_size) /* RLE */
|
||||
{
|
||||
if(::fread(patch_size_raw, 1, 2, ips) != 2)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
MDFN_PrintError(_("Error reading IPS RLE patch length: %s"), ene.StrError());
|
||||
return(0);
|
||||
}
|
||||
|
||||
patch_size = MDFN_de16msb(patch_size_raw);
|
||||
|
||||
// Is this right?
|
||||
if(!patch_size)
|
||||
patch_size = 65536;
|
||||
|
||||
rle = true;
|
||||
//MDFN_printf(" Offset: %8d Size: %5d RLE\n",offset, patch_size);
|
||||
}
|
||||
|
||||
if((offset + patch_size) > f_size)
|
||||
{
|
||||
uint8 *tmp;
|
||||
|
||||
//printf("%d\n", offset + patch_size, f_size);
|
||||
|
||||
if((offset + patch_size) > MaxROMImageSize)
|
||||
{
|
||||
MDFN_PrintError(_("ROM image will be too large after IPS patch; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(!(tmp = (uint8 *)MDFN_realloc(f_data, offset + patch_size, _("file read buffer"))))
|
||||
return(0);
|
||||
|
||||
// Zero newly-allocated memory
|
||||
memset(tmp + f_size, 0, (offset + patch_size) - f_size);
|
||||
|
||||
f_size = offset + patch_size;
|
||||
f_data = tmp;
|
||||
}
|
||||
|
||||
|
||||
if(rle)
|
||||
{
|
||||
const int b = ::fgetc(ips);
|
||||
uint8 *start = f_data + offset;
|
||||
|
||||
if(EOF == b)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
MDFN_PrintError(_("Error reading IPS RLE patch byte: %s"), ene.StrError());
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
while(patch_size--)
|
||||
{
|
||||
*start=b;
|
||||
start++;
|
||||
}
|
||||
|
||||
}
|
||||
else /* Normal patch */
|
||||
{
|
||||
//MDFN_printf(" Offset: %8d Size: %5d\n", offset, patch_size);
|
||||
if(::fread(f_data + offset, 1, patch_size, ips) != patch_size)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
MDFN_PrintError(_("Error reading IPS patch: %s"), ene.StrError());
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
//MDFN_printf(_("Warning: IPS ended without an EOF chunk.\n"));
|
||||
//MDFN_printf(_("IPS EOF: Did %d patches\n\n"), count);
|
||||
MDFN_indent(-1);
|
||||
|
||||
MDFN_PrintError(_("Error reading IPS patch header: %s"), ene.StrError());
|
||||
return(0);
|
||||
|
||||
//return(1);
|
||||
}
|
||||
|
||||
// This function should ALWAYS close the system file "descriptor"(gzip library, zip library, or FILE *) it's given,
|
||||
// even if it errors out.
|
||||
bool MDFNFILE::MakeMemWrapAndClose(void *tz, int type)
|
||||
{
|
||||
bool ret = FALSE;
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
is_mmap = FALSE;
|
||||
#endif
|
||||
location = 0;
|
||||
|
||||
if(type == MDFN_FILETYPE_PLAIN)
|
||||
{
|
||||
::fseek((FILE *)tz, 0, SEEK_END);
|
||||
f_size = ::ftell((FILE *)tz);
|
||||
::fseek((FILE *)tz, 0, SEEK_SET);
|
||||
|
||||
if(size > MaxROMImageSize)
|
||||
{
|
||||
MDFN_PrintError(_("ROM image is too large; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize);
|
||||
goto doret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
if((void *)-1 != (f_data = (uint8 *)mmap(NULL, size, PROT_READ, MAP_SHARED, fileno((FILE *)tz), 0)))
|
||||
{
|
||||
//puts("mmap'ed");
|
||||
is_mmap = TRUE;
|
||||
#ifdef HAVE_MADVISE
|
||||
if(0 == madvise(f_data, size, MADV_SEQUENTIAL | MADV_WILLNEED))
|
||||
{
|
||||
//puts("madvised");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
if(!(f_data = (uint8*)MDFN_malloc(size, _("file read buffer"))))
|
||||
{
|
||||
goto doret;
|
||||
}
|
||||
if((int64)::fread(f_data, 1, size, (FILE *)tz) != size)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
MDFN_PrintError(_("Error reading file: %s"), ene.StrError());
|
||||
|
||||
free(f_data);
|
||||
goto doret;
|
||||
}
|
||||
#ifdef HAVE_MMAP
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(type == MDFN_FILETYPE_GZIP)
|
||||
{
|
||||
uint32_t cur_size = 0;
|
||||
uint32_t cur_alloced = 65536;
|
||||
int howmany;
|
||||
|
||||
if(!(f_data = (uint8*)MDFN_malloc(cur_alloced, _("file read buffer"))))
|
||||
{
|
||||
goto doret;
|
||||
}
|
||||
|
||||
while((howmany = gzread((gzFile)tz, f_data + cur_size, cur_alloced - cur_size)) > 0)
|
||||
{
|
||||
cur_size += howmany;
|
||||
cur_alloced <<= 1;
|
||||
|
||||
if(cur_size > MaxROMImageSize)
|
||||
{
|
||||
MDFN_PrintError(_("ROM image is too large; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize);
|
||||
goto doret;
|
||||
}
|
||||
|
||||
if(!(f_data = (uint8 *)MDFN_realloc(f_data, cur_alloced, _("file read buffer"))))
|
||||
{
|
||||
goto doret;
|
||||
}
|
||||
}
|
||||
|
||||
if(!(f_data = (uint8 *)MDFN_realloc(f_data, cur_size, _("file read buffer"))))
|
||||
{
|
||||
goto doret;
|
||||
}
|
||||
|
||||
f_size = cur_size;
|
||||
|
||||
{
|
||||
int gzerrnum = 0;
|
||||
const char *gzerrstring;
|
||||
if((gzerrstring = gzerror((gzFile)tz, &gzerrnum)) && gzerrnum != Z_OK && gzerrnum != Z_STREAM_END)
|
||||
{
|
||||
if(gzerrnum != Z_ERRNO)
|
||||
{
|
||||
MDFN_PrintError(_("Error reading file: zlib error: %s"), gzerrstring);
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
MDFN_PrintError(_("Error reading file: %s"), ene.StrError());
|
||||
}
|
||||
goto doret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type == MDFN_FILETYPE_ZIP)
|
||||
{
|
||||
unz_file_info ufo;
|
||||
unzGetCurrentFileInfo((unzFile)tz, &ufo, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
f_size = ufo.uncompressed_size;
|
||||
|
||||
if(size > MaxROMImageSize)
|
||||
{
|
||||
MDFN_PrintError(_("ROM image is too large; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize);
|
||||
goto doret;
|
||||
}
|
||||
|
||||
if(!(f_data=(uint8 *)MDFN_malloc(ufo.uncompressed_size, _("file read buffer"))))
|
||||
{
|
||||
goto doret;
|
||||
}
|
||||
|
||||
unzReadCurrentFile((unzFile)tz, f_data, ufo.uncompressed_size);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
doret:
|
||||
if(type == MDFN_FILETYPE_PLAIN)
|
||||
{
|
||||
fclose((FILE *)tz);
|
||||
}
|
||||
else if(type == MDFN_FILETYPE_GZIP)
|
||||
{
|
||||
gzclose((gzFile)tz);
|
||||
}
|
||||
else if(type == MDFN_FILETYPE_ZIP)
|
||||
{
|
||||
unzCloseCurrentFile((unzFile)tz);
|
||||
unzClose((unzFile)tz);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
MDFNFILE::MDFNFILE() : size(f_size), data((const uint8* const &)f_data), ext((const char * const &)f_ext)
|
||||
{
|
||||
f_data = NULL;
|
||||
f_size = 0;
|
||||
f_ext = NULL;
|
||||
|
||||
location = 0;
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
is_mmap = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
MDFNFILE::MDFNFILE(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose) : size(f_size), data((const uint8* const &)f_data), ext((const char * const &)f_ext)
|
||||
{
|
||||
if(!Open(path, known_ext, purpose, false))
|
||||
{
|
||||
throw(MDFN_Error(0, "TODO ERROR"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MDFNFILE::~MDFNFILE()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
bool MDFNFILE::Open(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose, const bool suppress_notfound_pe)
|
||||
{
|
||||
unzFile tz;
|
||||
|
||||
local_errno = 0;
|
||||
error_code = MDFNFILE_EC_OTHER; // Set to 0 at the end if the function succeeds.
|
||||
|
||||
//f_data = (uint8 *)0xDEADBEEF;
|
||||
|
||||
// Try opening it as a zip file first
|
||||
if((tz = unzOpen(path)))
|
||||
{
|
||||
char tempu[1024];
|
||||
int errcode;
|
||||
|
||||
if((errcode = unzGoToFirstFile(tz)) != UNZ_OK)
|
||||
{
|
||||
MDFN_PrintError(_("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode));
|
||||
unzClose(tz);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if(known_ext)
|
||||
{
|
||||
bool FileFound = FALSE;
|
||||
while(!FileFound)
|
||||
{
|
||||
size_t tempu_strlen;
|
||||
const FileExtensionSpecStruct *ext_search = known_ext;
|
||||
|
||||
if((errcode = unzGetCurrentFileInfo(tz, 0, tempu, 1024, 0, 0, 0, 0)) != UNZ_OK)
|
||||
{
|
||||
MDFN_PrintError(_("Could not get file information in ZIP archive: %s"), unzErrorString(errcode));
|
||||
unzClose(tz);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
tempu[1023] = 0;
|
||||
tempu_strlen = strlen(tempu);
|
||||
|
||||
while(ext_search->extension && !FileFound)
|
||||
{
|
||||
size_t ttmeow = strlen(ext_search->extension);
|
||||
if(tempu_strlen >= ttmeow)
|
||||
{
|
||||
if(!strcasecmp(tempu + tempu_strlen - ttmeow, ext_search->extension))
|
||||
FileFound = TRUE;
|
||||
}
|
||||
ext_search++;
|
||||
}
|
||||
|
||||
if(FileFound)
|
||||
break;
|
||||
|
||||
if((errcode = unzGoToNextFile(tz)) != UNZ_OK)
|
||||
{
|
||||
if(errcode != UNZ_END_OF_LIST_OF_FILE)
|
||||
{
|
||||
MDFN_PrintError(_("Error seeking to next file in ZIP archive: %s"), unzErrorString(errcode));
|
||||
unzClose(tz);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if((errcode = unzGoToFirstFile(tz)) != UNZ_OK)
|
||||
{
|
||||
MDFN_PrintError(_("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode));
|
||||
unzClose(tz);
|
||||
return(NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} // end to while(!FileFound)
|
||||
} // end to if(ext)
|
||||
|
||||
if((errcode = unzOpenCurrentFile(tz)) != UNZ_OK)
|
||||
{
|
||||
MDFN_PrintError(_("Could not open file in ZIP archive: %s"), unzErrorString(errcode));
|
||||
unzClose(tz);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if(!MakeMemWrapAndClose(tz, MDFN_FILETYPE_ZIP))
|
||||
return(0);
|
||||
|
||||
char *ld = strrchr(tempu, '.');
|
||||
|
||||
f_ext = strdup(ld ? ld + 1 : "");
|
||||
}
|
||||
else // If it's not a zip file, handle it as...another type of file!
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if(!(fp = fopen(path, "rb")))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
local_errno = ene.Errno();
|
||||
|
||||
if(ene.Errno() == ENOENT)
|
||||
{
|
||||
local_errno = ene.Errno();
|
||||
error_code = MDFNFILE_EC_NOTFOUND;
|
||||
}
|
||||
|
||||
if(ene.Errno() != ENOENT || !suppress_notfound_pe)
|
||||
MDFN_PrintError(_("Error opening \"%s\": %s"), path, ene.StrError());
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint32 gzmagic;
|
||||
|
||||
gzmagic = ::fgetc(fp);
|
||||
gzmagic |= ::fgetc(fp) << 8;
|
||||
gzmagic |= ::fgetc(fp) << 16;
|
||||
|
||||
if(gzmagic != 0x088b1f) /* Not gzip... */
|
||||
{
|
||||
::fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if(!MakeMemWrapAndClose(fp, MDFN_FILETYPE_PLAIN))
|
||||
return(0);
|
||||
|
||||
const char *ld = strrchr(path, '.');
|
||||
f_ext = strdup(ld ? ld + 1 : "");
|
||||
}
|
||||
else /* Probably gzip */
|
||||
{
|
||||
gzFile gzp;
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// Clear errno so we can see if the error occurred within zlib or the C lib
|
||||
errno = 0;
|
||||
if(!(gzp = gzopen(path, "rb")))
|
||||
{
|
||||
if(errno != 0)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
local_errno = ene.Errno();
|
||||
|
||||
if(ene.Errno() == ENOENT)
|
||||
{
|
||||
local_errno = ene.Errno();
|
||||
error_code = MDFNFILE_EC_NOTFOUND;
|
||||
}
|
||||
|
||||
if(ene.Errno() != ENOENT || !suppress_notfound_pe)
|
||||
MDFN_PrintError(_("Error opening \"%s\": %s"), path, ene.StrError());
|
||||
}
|
||||
else
|
||||
MDFN_PrintError(_("Error opening \"%s\": %s"), path, _("zlib error"));
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(!MakeMemWrapAndClose(gzp, MDFN_FILETYPE_GZIP))
|
||||
return(0);
|
||||
|
||||
char *tmp_path = strdup(path);
|
||||
char *ld = strrchr(tmp_path, '.');
|
||||
|
||||
if(ld && ld > tmp_path)
|
||||
{
|
||||
char *last_ld = ld;
|
||||
*ld = 0;
|
||||
ld = strrchr(tmp_path, '.');
|
||||
if(!ld) { *last_ld = '.'; ld = last_ld; }
|
||||
}
|
||||
f_ext = strdup(ld ? ld + 1 : "");
|
||||
free(tmp_path);
|
||||
} // End gzip handling
|
||||
} // End normal and gzip file handling else to zip
|
||||
|
||||
// FIXME: Handle extension fixing for cases where loaded filename is like "moo.moo/lalala"
|
||||
|
||||
error_code = 0;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
bool MDFNFILE::Close(void)
|
||||
{
|
||||
if(f_ext)
|
||||
{
|
||||
free(f_ext);
|
||||
f_ext = NULL;
|
||||
}
|
||||
|
||||
if(f_data)
|
||||
{
|
||||
#if HAVE_MMAP
|
||||
if(is_mmap)
|
||||
munmap(f_data, size);
|
||||
else
|
||||
#endif
|
||||
free(f_data);
|
||||
f_data = NULL;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
uint64 MDFNFILE::fread(void *ptr, size_t element_size, size_t nmemb)
|
||||
{
|
||||
uint32 total = element_size * nmemb;
|
||||
|
||||
if(location >= f_size)
|
||||
return 0;
|
||||
|
||||
if((location + total) > f_size)
|
||||
{
|
||||
int64 ak = f_size - location;
|
||||
|
||||
memcpy((uint8*)ptr, f_data + location, ak);
|
||||
|
||||
location = f_size;
|
||||
|
||||
return(ak / element_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((uint8*)ptr, f_data + location, total);
|
||||
|
||||
location += total;
|
||||
|
||||
return nmemb;
|
||||
}
|
||||
}
|
||||
|
||||
int MDFNFILE::fseek(int64 offset, int whence)
|
||||
{
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:if(offset >= f_size)
|
||||
return(-1);
|
||||
location = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:if((offset + location) > f_size)
|
||||
return(-1);
|
||||
|
||||
location += offset;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MDFNFILE::read16le(uint16 *val)
|
||||
{
|
||||
if((location + 2) > size)
|
||||
return 0;
|
||||
|
||||
*val = MDFN_de16lsb(data + location);
|
||||
|
||||
location += 2;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
int MDFNFILE::read32le(uint32 *val)
|
||||
{
|
||||
if((location + 4) > size)
|
||||
return 0;
|
||||
|
||||
*val = MDFN_de32lsb(data + location);
|
||||
|
||||
location += 4;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
char *MDFNFILE::fgets(char *s, int buffer_size)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
if(!buffer_size)
|
||||
return(NULL);
|
||||
|
||||
if(location >= buffer_size)
|
||||
return(NULL);
|
||||
|
||||
while(pos < (buffer_size - 1) && location < buffer_size)
|
||||
{
|
||||
int v = data[location];
|
||||
s[pos] = v;
|
||||
location++;
|
||||
pos++;
|
||||
if(v == '\n') break;
|
||||
}
|
||||
|
||||
if(buffer_size)
|
||||
s[pos] = 0;
|
||||
|
||||
return(s);
|
||||
}
|
||||
|
||||
static INLINE bool MDFN_DumpToFileReal(const char *filename, int compress, const std::vector<PtrLengthPair> &pearpairs)
|
||||
{
|
||||
if(MDFN_GetSettingB("filesys.disablesavegz"))
|
||||
compress = 0;
|
||||
|
||||
if(compress)
|
||||
{
|
||||
char mode[64];
|
||||
gzFile gp;
|
||||
|
||||
trio_snprintf(mode, 64, "wb%d", compress);
|
||||
|
||||
gp = gzopen(filename, mode);
|
||||
|
||||
if(!gp)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
MDFN_PrintError(_("Error opening \"%s\": %s"), filename, ene.StrError());
|
||||
return(0);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < pearpairs.size(); i++)
|
||||
{
|
||||
const void *data = pearpairs[i].GetData();
|
||||
const int64 length = pearpairs[i].GetLength();
|
||||
|
||||
if(gzwrite(gp, data, length) != length)
|
||||
{
|
||||
int errnum;
|
||||
|
||||
MDFN_PrintError(_("Error writing to \"%s\": %s"), filename, gzerror(gp, &errnum));
|
||||
gzclose(gp);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(gzclose(gp) != Z_OK) // FIXME: Huhm, how should we handle this?
|
||||
{
|
||||
MDFN_PrintError(_("Error closing \"%s\""), filename);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
if(!fp)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
MDFN_PrintError(_("Error opening \"%s\": %s"), filename, ene.StrError());
|
||||
return(0);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < pearpairs.size(); i++)
|
||||
{
|
||||
const void *data = pearpairs[i].GetData();
|
||||
const uint64 length = pearpairs[i].GetLength();
|
||||
|
||||
if(fwrite(data, 1, length, fp) != length)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
MDFN_PrintError(_("Error writing to \"%s\": %s"), filename, ene.StrError());
|
||||
fclose(fp);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(fclose(fp) == EOF)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
MDFN_PrintError(_("Error closing \"%s\": %s"), filename, ene.StrError());
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
bool MDFN_DumpToFile(const char *filename, int compress, const std::vector<PtrLengthPair> &pearpairs)
|
||||
{
|
||||
return(MDFN_DumpToFileReal(filename, compress, pearpairs));
|
||||
}
|
||||
|
||||
bool MDFN_DumpToFile(const char *filename, int compress, const void *data, uint64 length)
|
||||
{
|
||||
std::vector<PtrLengthPair> tmp_pairs;
|
||||
tmp_pairs.push_back(PtrLengthPair(data, length));
|
||||
return(MDFN_DumpToFileReal(filename, compress, tmp_pairs));
|
||||
}
|
156
mednafen/file.h
Normal file
156
mednafen/file.h
Normal file
@ -0,0 +1,156 @@
|
||||
#ifndef MDFN_FILE_H
|
||||
#define MDFN_FILE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#define MDFNFILE_EC_NOTFOUND 1
|
||||
#define MDFNFILE_EC_OTHER 2
|
||||
|
||||
class MDFNFILE
|
||||
{
|
||||
public:
|
||||
|
||||
MDFNFILE();
|
||||
// WIP constructors:
|
||||
MDFNFILE(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose = NULL);
|
||||
|
||||
~MDFNFILE();
|
||||
|
||||
bool Open(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose = NULL, const bool suppress_notfound_pe = FALSE);
|
||||
INLINE bool Open(const std::string &path, const FileExtensionSpecStruct *known_ext, const char *purpose = NULL, const bool suppress_notfound_pe = FALSE)
|
||||
{
|
||||
return(Open(path.c_str(), known_ext, purpose, suppress_notfound_pe));
|
||||
}
|
||||
|
||||
bool ApplyIPS(FILE *);
|
||||
bool Close(void);
|
||||
|
||||
const int64 &size;
|
||||
const uint8 * const &data;
|
||||
const char * const &ext;
|
||||
|
||||
// Currently, only valid with Open()
|
||||
inline int GetErrorCode(int *get_errno = NULL)
|
||||
{
|
||||
if(get_errno)
|
||||
*get_errno = local_errno;
|
||||
|
||||
return(error_code);
|
||||
}
|
||||
|
||||
inline int64 Size(void)
|
||||
{
|
||||
return(f_size);
|
||||
}
|
||||
|
||||
inline const uint8 *Data(void)
|
||||
{
|
||||
return(f_data);
|
||||
}
|
||||
|
||||
uint64 fread(void *ptr, size_t size, size_t nmemb);
|
||||
int fseek(int64 offset, int whence);
|
||||
|
||||
inline uint64 ftell(void)
|
||||
{
|
||||
return(location);
|
||||
}
|
||||
|
||||
inline void rewind(void)
|
||||
{
|
||||
location = 0;
|
||||
}
|
||||
|
||||
int read32le(uint32 *Bufo);
|
||||
int read16le(uint16 *Bufo);
|
||||
|
||||
inline int fgetc(void)
|
||||
{
|
||||
if(location < f_size)
|
||||
return f_data[location++];
|
||||
|
||||
return EOF;
|
||||
}
|
||||
|
||||
inline int fisarchive(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
char *fgets(char *s, int size);
|
||||
|
||||
private:
|
||||
|
||||
uint8 *f_data;
|
||||
int64 f_size;
|
||||
char *f_ext;
|
||||
|
||||
int error_code;
|
||||
int local_errno;
|
||||
|
||||
int64 location;
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
bool is_mmap;
|
||||
#endif
|
||||
|
||||
bool MakeMemWrapAndClose(void *tz, int type);
|
||||
};
|
||||
|
||||
#if 0
|
||||
MDFNFILE *MDFN_fopen(const char *path, const char *ipsfn, const char *mode, const FileExtensionSpecStruct *known_ext);
|
||||
int MDFN_fclose(MDFNFILE*);
|
||||
uint64 MDFN_fread(void *ptr, size_t size, size_t nmemb, MDFNFILE*);
|
||||
uint64 MDFN_fwrite(void *ptr, size_t size, size_t nmemb, MDFNFILE*);
|
||||
int MDFN_fseek(MDFNFILE*, int64 offset, int whence);
|
||||
uint64 MDFN_ftell(MDFNFILE*);
|
||||
void MDFN_rewind(MDFNFILE*);
|
||||
int MDFN_read32le(uint32 *Bufo, MDFNFILE*);
|
||||
int MDFN_read16le(uint16 *Bufo, MDFNFILE*);
|
||||
int MDFN_fgetc(MDFNFILE*);
|
||||
uint64 MDFN_fgetsize(MDFNFILE*);
|
||||
int MDFN_fisarchive(MDFNFILE*);
|
||||
char *MDFN_fgets(char *s, int size, MDFNFILE *);
|
||||
#endif
|
||||
|
||||
class PtrLengthPair
|
||||
{
|
||||
public:
|
||||
|
||||
inline PtrLengthPair(const void *new_data, const uint64 new_length)
|
||||
{
|
||||
data = new_data;
|
||||
length = new_length;
|
||||
}
|
||||
|
||||
~PtrLengthPair()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
INLINE const void *GetData(void) const
|
||||
{
|
||||
return(data);
|
||||
}
|
||||
|
||||
INLINE uint64 GetLength(void) const
|
||||
{
|
||||
return(length);
|
||||
}
|
||||
|
||||
private:
|
||||
const void *data;
|
||||
uint64 length;
|
||||
};
|
||||
|
||||
#include <vector>
|
||||
|
||||
// These functions should be used for data like save states and non-volatile backup memory.
|
||||
// Until(if, even) we add LoadFromFile functions, for reading the files these functions generate, just use gzopen(), gzread(), etc.
|
||||
// "compress" is set to the zlib compression level. 0 disables compression entirely, and dumps the file without a gzip header or footer.
|
||||
// (Note: There is a setting that will force compress to 0 in the internal DumpToFile logic, for hackers who don't want to ungzip save files.)
|
||||
|
||||
bool MDFN_DumpToFile(const char *filename, int compress, const void *data, const uint64 length);
|
||||
bool MDFN_DumpToFile(const char *filename, int compress, const std::vector<PtrLengthPair> &pearpairs);
|
||||
|
||||
#endif
|
588
mednafen/general.cpp
Normal file
588
mednafen/general.cpp
Normal file
@ -0,0 +1,588 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "mednafen.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <trio/trio.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "state.h"
|
||||
#include "movie.h"
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static string BaseDirectory;
|
||||
static string FileBase;
|
||||
static string FileExt; /* Includes the . character, as in ".nes" */
|
||||
static string FileBaseDirectory;
|
||||
|
||||
void MDFNI_SetBaseDirectory(const char *dir)
|
||||
{
|
||||
BaseDirectory = string(dir);
|
||||
}
|
||||
|
||||
// Really dumb, maybe we should use boost?
|
||||
static bool IsAbsolutePath(const char *path)
|
||||
{
|
||||
#if PSS_STYLE==4
|
||||
if(path[0] == ':')
|
||||
#elif PSS_STYLE==1
|
||||
if(path[0] == '/')
|
||||
#else
|
||||
if(path[0] == '\\'
|
||||
#if PSS_STYLE!=3
|
||||
|| path[0] == '/'
|
||||
#endif
|
||||
)
|
||||
#endif
|
||||
{
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// FIXME if we add DOS support(HAHAHAHA).
|
||||
#if defined(WIN32)
|
||||
if((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'))
|
||||
if(path[1] == ':')
|
||||
{
|
||||
return(TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
static bool IsAbsolutePath(const std::string &path)
|
||||
{
|
||||
return(IsAbsolutePath(path.c_str()));
|
||||
}
|
||||
|
||||
bool MDFN_IsFIROPSafe(const std::string &path)
|
||||
{
|
||||
// We could make this more OS-specific, but it shouldn't hurt to try to weed out usage of characters that are path
|
||||
// separators in one OS but not in another, and we'd also run more of a risk of missing a special path separator case
|
||||
// in some OS.
|
||||
|
||||
if(!MDFN_GetSettingB("filesys.untrusted_fip_check"))
|
||||
return(true);
|
||||
|
||||
if(path.find('\0') != string::npos)
|
||||
return(false);
|
||||
|
||||
if(path.find(':') != string::npos)
|
||||
return(false);
|
||||
|
||||
if(path.find('\\') != string::npos)
|
||||
return(false);
|
||||
|
||||
if(path.find('/') != string::npos)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void MDFN_GetFilePathComponents(const std::string &file_path, std::string *dir_path_out, std::string *file_base_out, std::string *file_ext_out)
|
||||
{
|
||||
size_t final_ds; // in file_path
|
||||
string file_name;
|
||||
size_t fn_final_dot; // in local var file_name
|
||||
// Temporary output:
|
||||
string dir_path, file_base, file_ext;
|
||||
|
||||
#if PSS_STYLE==4
|
||||
final_ds = file_path.find_last_of(':');
|
||||
#elif PSS_STYLE==1
|
||||
final_ds = file_path.find_last_of('/');
|
||||
#else
|
||||
final_ds = file_path.find_last_of('\\');
|
||||
|
||||
#if PSS_STYLE!=3
|
||||
{
|
||||
size_t alt_final_ds = file_path.find_last_of('/');
|
||||
|
||||
if(final_ds == string::npos || (alt_final_ds != string::npos && alt_final_ds > final_ds))
|
||||
final_ds = alt_final_ds;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(final_ds == string::npos)
|
||||
{
|
||||
dir_path = string(".");
|
||||
file_name = file_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir_path = file_path.substr(0, final_ds);
|
||||
file_name = file_path.substr(final_ds + 1);
|
||||
}
|
||||
|
||||
fn_final_dot = file_name.find_last_of('.');
|
||||
|
||||
if(fn_final_dot != string::npos)
|
||||
{
|
||||
file_base = file_name.substr(0, fn_final_dot);
|
||||
file_ext = file_name.substr(fn_final_dot);
|
||||
}
|
||||
else
|
||||
{
|
||||
file_base = file_name;
|
||||
file_ext = string("");
|
||||
}
|
||||
|
||||
if(dir_path_out)
|
||||
*dir_path_out = dir_path;
|
||||
|
||||
if(file_base_out)
|
||||
*file_base_out = file_base;
|
||||
|
||||
if(file_ext_out)
|
||||
*file_ext_out = file_ext;
|
||||
}
|
||||
|
||||
std::string MDFN_EvalFIP(const std::string &dir_path, const std::string &rel_path, bool skip_safety_check)
|
||||
{
|
||||
if(!skip_safety_check && !MDFN_IsFIROPSafe(rel_path))
|
||||
throw MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting.\n"), rel_path.c_str());
|
||||
|
||||
if(IsAbsolutePath(rel_path.c_str()))
|
||||
return(rel_path);
|
||||
else
|
||||
{
|
||||
return(dir_path + std::string(PSS) + rel_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef std::map<char, std::string> FSMap;
|
||||
|
||||
static std::string EvalPathFS(const std::string &fstring, /*const (won't work because entry created if char doesn't exist) */ FSMap &fmap)
|
||||
{
|
||||
std::string ret = "";
|
||||
const char *str = fstring.c_str();
|
||||
bool in_spec = false;
|
||||
|
||||
while(*str)
|
||||
{
|
||||
int c = *str;
|
||||
|
||||
if(!in_spec && c == '%')
|
||||
in_spec = true;
|
||||
else if(in_spec == true)
|
||||
{
|
||||
if(c == '%')
|
||||
ret = ret + std::string("%");
|
||||
else
|
||||
ret = ret + fmap[(char)c];
|
||||
in_spec = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
char ct[2];
|
||||
ct[0] = c;
|
||||
ct[1] = 0;
|
||||
ret += std::string(ct);
|
||||
}
|
||||
|
||||
str++;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void CreateMissingDirs(const char *path)
|
||||
{
|
||||
const char *s = path;
|
||||
bool first_psep = true;
|
||||
char last_char = 0;
|
||||
const char char_test1 = '/', char_test2 = '/';
|
||||
|
||||
|
||||
while(*s)
|
||||
{
|
||||
if(*s == char_test1 || *s == char_test2)
|
||||
{
|
||||
if(last_char != *s) //char_test1 && last_char != char_test2)
|
||||
{
|
||||
if(!first_psep)
|
||||
{
|
||||
char tmpbuf[(s - path) + 1];
|
||||
tmpbuf[s - path] = 0;
|
||||
strncpy(tmpbuf, path, s - path);
|
||||
|
||||
puts(tmpbuf);
|
||||
//MDFN_mkdir(tmpbuf, S_IRWXU);
|
||||
}
|
||||
}
|
||||
|
||||
first_psep = false;
|
||||
}
|
||||
last_char = *s;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
|
||||
{
|
||||
char tmp_path[4096];
|
||||
char numtmp[64];
|
||||
struct stat tmpstat;
|
||||
string eff_dir;
|
||||
FSMap fmap;
|
||||
|
||||
fmap['b'] = BaseDirectory;
|
||||
fmap['z'] = std::string(PSS);
|
||||
|
||||
if(MDFNGameInfo)
|
||||
{
|
||||
fmap['d'] = FileBaseDirectory;
|
||||
fmap['f'] = FileBase;
|
||||
fmap['F'] = FileBase; // If game is a CD, and the CD is recognized as being part of a multi-CD set, then this
|
||||
// will be replaced with MDFNGameInfo->shortname
|
||||
|
||||
fmap['m'] = md5_context::asciistr(MDFNGameInfo->MD5, 0); // MD5 hash of the currently loaded game ONLY.
|
||||
|
||||
fmap['M'] = ""; // One with this empty, if file not found, then fill with MD5 hash of the currently loaded game,
|
||||
// or the MD5 gameset hash for certain CD games, followed by a period and go with that result.
|
||||
// Note: The MD5-less result is skipped if the CD is part of a recognized multi-CD set.
|
||||
fmap['e'] = FileExt;
|
||||
fmap['s'] = MDFNGameInfo->shortname;
|
||||
|
||||
fmap['p'] = "";
|
||||
|
||||
|
||||
fmap['x'] = ""; // Default extension(without period)
|
||||
fmap['X'] = ""; // A merging of x and p
|
||||
|
||||
if(MDFNGameInfo->GameSetMD5Valid)
|
||||
{
|
||||
fmap['M'] = md5_context::asciistr(MDFNGameInfo->GameSetMD5, 0) + std::string(".");
|
||||
fmap['F'] = MDFNGameInfo->shortname;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//printf("%s\n", EvalPathFS(std::string("%f.%m.sav"), fmap).c_str());
|
||||
|
||||
switch(type)
|
||||
{
|
||||
default: tmp_path[0] = 0;
|
||||
break;
|
||||
|
||||
case MDFNMKF_MOVIE:
|
||||
case MDFNMKF_STATE:
|
||||
case MDFNMKF_SAV:
|
||||
{
|
||||
std::string dir, fstring, fpath;
|
||||
|
||||
if(type == MDFNMKF_MOVIE)
|
||||
{
|
||||
dir = MDFN_GetSettingS("filesys.path_movie");
|
||||
fstring = MDFN_GetSettingS("filesys.fname_movie");
|
||||
fmap['x'] = "mcm";
|
||||
}
|
||||
else if(type == MDFNMKF_STATE)
|
||||
{
|
||||
dir = MDFN_GetSettingS("filesys.path_state");
|
||||
fstring = MDFN_GetSettingS("filesys.fname_state");
|
||||
fmap['x'] = "mcs";
|
||||
}
|
||||
else if(type == MDFNMKF_SAV)
|
||||
{
|
||||
dir = MDFN_GetSettingS("filesys.path_sav");
|
||||
fstring = MDFN_GetSettingS("filesys.fname_sav");
|
||||
fmap['x'] = std::string(cd1);
|
||||
}
|
||||
|
||||
fmap['X'] = fmap['x'];
|
||||
|
||||
if(type != MDFNMKF_SAV)
|
||||
{
|
||||
snprintf(numtmp, sizeof(numtmp), "%d", id1);
|
||||
fmap['p'] = std::string(numtmp);
|
||||
}
|
||||
|
||||
if(fmap['X'].size() > 1 && fmap['p'].size())
|
||||
fmap['X'] = fmap['X'].erase(fmap['X'].size() - 1) + fmap['p'];
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
fpath = EvalPathFS(fstring, fmap);
|
||||
|
||||
if(!IsAbsolutePath(fpath))
|
||||
{
|
||||
if(!IsAbsolutePath(dir))
|
||||
dir = BaseDirectory + std::string(PSS) + dir;
|
||||
|
||||
fpath = dir + std::string(PSS) + fpath;
|
||||
}
|
||||
|
||||
if(stat(fpath.c_str(), &tmpstat) == -1)
|
||||
fmap['M'] = md5_context::asciistr(MDFNGameInfo->MD5, 0) + std::string(".");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return(fpath);
|
||||
}
|
||||
|
||||
case MDFNMKF_SNAP_DAT:
|
||||
case MDFNMKF_SNAP:
|
||||
{
|
||||
std::string dir = MDFN_GetSettingS("filesys.path_snap");
|
||||
std::string fstring = MDFN_GetSettingS("filesys.fname_snap");
|
||||
std::string fpath;
|
||||
|
||||
snprintf(numtmp, sizeof(numtmp), "%04d", id1);
|
||||
|
||||
fmap['p'] = std::string(numtmp);
|
||||
|
||||
if(cd1)
|
||||
fmap['x'] = std::string(cd1);
|
||||
|
||||
if(type == MDFNMKF_SNAP_DAT)
|
||||
{
|
||||
fmap['p'] = std::string("counter");
|
||||
fmap['x'] = std::string("txt");
|
||||
}
|
||||
fpath = EvalPathFS(fstring, fmap);
|
||||
if(!IsAbsolutePath(fpath))
|
||||
{
|
||||
if(!IsAbsolutePath(dir))
|
||||
dir = BaseDirectory + std::string(PSS) + dir;
|
||||
|
||||
fpath = dir + std::string(PSS) + fpath;
|
||||
}
|
||||
return(fpath);
|
||||
}
|
||||
break;
|
||||
|
||||
case MDFNMKF_CHEAT_TMP:
|
||||
case MDFNMKF_CHEAT:
|
||||
{
|
||||
std::string overpath = MDFN_GetSettingS("filesys.path_cheat");
|
||||
|
||||
if(IsAbsolutePath(overpath))
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.%scht",overpath.c_str(), MDFNGameInfo->shortname, (type == MDFNMKF_CHEAT_TMP) ? "tmp" : "");
|
||||
else
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s"PSS"%s.%scht", BaseDirectory.c_str(), overpath.c_str(), MDFNGameInfo->shortname, (type == MDFNMKF_CHEAT_TMP) ? "tmp" : "");
|
||||
}
|
||||
break;
|
||||
|
||||
case MDFNMKF_AUX: if(IsAbsolutePath(cd1))
|
||||
trio_snprintf(tmp_path, 4096, "%s", (char *)cd1);
|
||||
else
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s", FileBaseDirectory.c_str(), (char *)cd1);
|
||||
break;
|
||||
|
||||
case MDFNMKF_IPS: trio_snprintf(tmp_path, 4096, "%s"PSS"%s%s.ips", FileBaseDirectory.c_str(), FileBase.c_str(), FileExt.c_str());
|
||||
break;
|
||||
|
||||
case MDFNMKF_FIRMWARE:
|
||||
{
|
||||
std::string overpath = MDFN_GetSettingS("filesys.path_firmware");
|
||||
|
||||
if(IsAbsolutePath(cd1))
|
||||
{
|
||||
trio_snprintf(tmp_path, 4096, "%s", cd1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IsAbsolutePath(overpath))
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s",overpath.c_str(), cd1);
|
||||
else
|
||||
{
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s"PSS"%s", BaseDirectory.c_str(), overpath.c_str(), cd1);
|
||||
|
||||
// For backwards-compatibility with < 0.9.0
|
||||
if(stat(tmp_path,&tmpstat) == -1)
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s", BaseDirectory.c_str(), cd1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MDFNMKF_PALETTE:
|
||||
{
|
||||
std::string overpath = MDFN_GetSettingS("filesys.path_palette");
|
||||
|
||||
if(IsAbsolutePath(overpath))
|
||||
eff_dir = overpath;
|
||||
else
|
||||
eff_dir = std::string(BaseDirectory) + std::string(PSS) + overpath;
|
||||
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.pal", eff_dir.c_str(), FileBase.c_str());
|
||||
|
||||
if(stat(tmp_path,&tmpstat) == -1 && errno == ENOENT)
|
||||
{
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.%s.pal", eff_dir.c_str(), FileBase.c_str(), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
|
||||
|
||||
if(stat(tmp_path, &tmpstat) == -1 && errno == ENOENT)
|
||||
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.pal", eff_dir.c_str(), cd1 ? cd1 : MDFNGameInfo->shortname);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return(tmp_path);
|
||||
}
|
||||
|
||||
const char * GetFNComponent(const char *str)
|
||||
{
|
||||
const char *tp1;
|
||||
|
||||
#if PSS_STYLE==4
|
||||
tp1=((char *)strrchr(str,':'));
|
||||
#elif PSS_STYLE==1
|
||||
tp1=((char *)strrchr(str,'/'));
|
||||
#else
|
||||
tp1=((char *)strrchr(str,'\\'));
|
||||
#if PSS_STYLE!=3
|
||||
{
|
||||
const char *tp3;
|
||||
tp3=((char *)strrchr(str,'/'));
|
||||
if(tp1<tp3) tp1=tp3;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(tp1)
|
||||
return(tp1+1);
|
||||
else
|
||||
return(str);
|
||||
}
|
||||
|
||||
void GetFileBase(const char *f)
|
||||
{
|
||||
const char *tp1,*tp3;
|
||||
|
||||
#if PSS_STYLE==4
|
||||
tp1=((char *)strrchr(f,':'));
|
||||
#elif PSS_STYLE==1
|
||||
tp1=((char *)strrchr(f,'/'));
|
||||
#else
|
||||
tp1=((char *)strrchr(f,'\\'));
|
||||
#if PSS_STYLE!=3
|
||||
tp3=((char *)strrchr(f,'/'));
|
||||
if(tp1<tp3) tp1=tp3;
|
||||
#endif
|
||||
#endif
|
||||
if(!tp1)
|
||||
{
|
||||
tp1=f;
|
||||
FileBaseDirectory = ".";
|
||||
}
|
||||
else
|
||||
{
|
||||
char tmpfn[tp1 - f + 1];
|
||||
|
||||
memcpy(tmpfn,f,tp1-f);
|
||||
tmpfn[tp1-f]=0;
|
||||
FileBaseDirectory = string(tmpfn);
|
||||
|
||||
tp1++;
|
||||
}
|
||||
|
||||
if(((tp3=strrchr(f,'.'))!=NULL) && (tp3>tp1))
|
||||
{
|
||||
char tmpbase[tp3 - tp1 + 1];
|
||||
|
||||
memcpy(tmpbase,tp1,tp3-tp1);
|
||||
tmpbase[tp3-tp1]=0;
|
||||
FileBase = string(tmpbase);
|
||||
FileExt = string(tp3);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileBase = string(tp1);
|
||||
FileExt = "";
|
||||
}
|
||||
}
|
||||
|
||||
char *MDFN_RemoveControlChars(char *str)
|
||||
{
|
||||
char *orig = str;
|
||||
if(str)
|
||||
while(*str)
|
||||
{
|
||||
if(*str < 0x20) *str = 0x20;
|
||||
str++;
|
||||
}
|
||||
return(orig);
|
||||
}
|
||||
|
||||
// Remove whitespace from beginning of string
|
||||
void MDFN_ltrim(char *string)
|
||||
{
|
||||
int32 di, si;
|
||||
bool InWhitespace = TRUE;
|
||||
|
||||
di = si = 0;
|
||||
|
||||
while(string[si])
|
||||
{
|
||||
if(InWhitespace && (string[si] == ' ' || string[si] == '\r' || string[si] == '\n' || string[si] == '\t' || string[si] == 0x0b))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
InWhitespace = FALSE;
|
||||
string[di] = string[si];
|
||||
di++;
|
||||
}
|
||||
si++;
|
||||
}
|
||||
string[di] = 0;
|
||||
}
|
||||
|
||||
// Remove whitespace from end of string
|
||||
void MDFN_rtrim(char *string)
|
||||
{
|
||||
int32 len = strlen(string);
|
||||
|
||||
if(len)
|
||||
{
|
||||
for(int32 x = len - 1; x >= 0; x--)
|
||||
{
|
||||
if(string[x] == ' ' || string[x] == '\r' || string[x] == '\n' || string[x] == '\t' || string[x] == 0x0b)
|
||||
string[x] = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MDFN_trim(char *string)
|
||||
{
|
||||
MDFN_rtrim(string);
|
||||
MDFN_ltrim(string);
|
||||
}
|
41
mednafen/general.h
Normal file
41
mednafen/general.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef _GENERAL_H
|
||||
#define _GENERAL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
extern uint32 MDFN_RoundUpPow2(uint32);
|
||||
|
||||
void GetFileBase(const char *f);
|
||||
|
||||
// File-inclusion for-read-only path, for PSF and CUE/TOC sheet usage.
|
||||
bool MDFN_IsFIROPSafe(const std::string &path);
|
||||
|
||||
std::string MDFN_MakeFName(int type, int id1, const char *cd1);
|
||||
char *MDFN_RemoveControlChars(char *str);
|
||||
|
||||
void MDFN_ltrim(char *string);
|
||||
void MDFN_rtrim(char *string);
|
||||
void MDFN_trim(char *string);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MDFNMKF_STATE = 0,
|
||||
MDFNMKF_SNAP,
|
||||
MDFNMKF_SAV,
|
||||
MDFNMKF_CHEAT,
|
||||
MDFNMKF_PALETTE,
|
||||
MDFNMKF_IPS,
|
||||
MDFNMKF_MOVIE,
|
||||
MDFNMKF_AUX,
|
||||
MDFNMKF_SNAP_DAT,
|
||||
MDFNMKF_CHEAT_TMP,
|
||||
MDFNMKF_FIRMWARE
|
||||
} MakeFName_Type;
|
||||
|
||||
std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1);
|
||||
|
||||
const char * GetFNComponent(const char *str);
|
||||
|
||||
void MDFN_GetFilePathComponents(const std::string &file_path, std::string *dir_path_out, std::string *file_base_out = NULL, std::string *file_ext_out = NULL);
|
||||
std::string MDFN_EvalFIP(const std::string &dir_path, const std::string &rel_path, bool skip_safety_check = false);
|
||||
#endif
|
79
mednafen/gettext.h
Normal file
79
mednafen/gettext.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* Convenience header for conditional use of GNU <libintl.h>.
|
||||
Copyright (C) 1995-1998, 2000-2002, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published
|
||||
by the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
USA. */
|
||||
|
||||
#ifndef _LIBGETTEXT_H
|
||||
#define _LIBGETTEXT_H 1
|
||||
|
||||
/* NLS can be disabled through the configure --disable-nls option. */
|
||||
#if ENABLE_NLS
|
||||
|
||||
/* Get declarations of GNU message catalog functions. */
|
||||
# include <libintl.h>
|
||||
|
||||
#else
|
||||
|
||||
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
|
||||
chokes if dcgettext is defined as a macro. So include it now, to make
|
||||
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
|
||||
as well because people using "gettext.h" will not include <libintl.h>,
|
||||
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
|
||||
is OK. */
|
||||
#if defined(__sun)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
|
||||
<libintl.h>, which chokes if dcgettext is defined as a macro. So include
|
||||
it now, to make later inclusions of <libintl.h> a NOP. */
|
||||
#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
|
||||
# include <cstdlib>
|
||||
# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
|
||||
# include <libintl.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Disabled NLS.
|
||||
The casts to 'const char *' serve the purpose of producing warnings
|
||||
for invalid uses of the value returned from these functions.
|
||||
On pre-ANSI systems without 'const', the config.h file is supposed to
|
||||
contain "#define const". */
|
||||
# define gettext(Msgid) ((const char *) (Msgid))
|
||||
# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
|
||||
# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
|
||||
# define dngettext(Domainname, Msgid1, Msgid2, N) \
|
||||
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
|
||||
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
|
||||
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
|
||||
# define textdomain(Domainname) ((const char *) (Domainname))
|
||||
# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
|
||||
# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
|
||||
|
||||
#endif
|
||||
|
||||
/* A pseudo function call that serves as a marker for the automated
|
||||
extraction of messages, but does not call gettext(). The run-time
|
||||
translation is done at a different place in the code.
|
||||
The argument, String, should be a literal string. Concatenated strings
|
||||
and other string expressions won't work.
|
||||
The macro's expansion is not parenthesized, so that it is suitable as
|
||||
initializer for static 'char[]' or 'const char[]' variables. */
|
||||
#define gettext_noop(String) String
|
||||
|
||||
#endif /* _LIBGETTEXT_H */
|
365
mednafen/git-virtb.h
Normal file
365
mednafen/git-virtb.h
Normal file
@ -0,0 +1,365 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
This file includes parts(thus is modified from) of SDL_keysym.h, whose file header is shown below:
|
||||
|
||||
Everything from VIRTB_KB_UNKNOWN to VIRTB_KB_UNDO should map to SDLK_UNKNOWN to SDLK_KB_UNDO, so the driver
|
||||
side can use the raw VIRTB_KB_* values for SDLK_* if less than VIRTB_KB_LAST if using SDL 1.2(if not SDL 1.3),
|
||||
but probably really should have a translation table.
|
||||
*/
|
||||
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2006 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
#ifndef __MDFN_GIT_VIRTB_H
|
||||
#define __MDFN_GIT_VIRTB_H
|
||||
|
||||
/* What we really want is a mapping of every raw key on the keyboard.
|
||||
To support international keyboards, we use the range 0xA1 - 0xFF
|
||||
as international virtual keycodes. We'll follow in the footsteps of X11...
|
||||
The names of the keys
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
VIRTB_UNKNOWN = 0,
|
||||
|
||||
/* The keyboard syms have been cleverly chosen to map to ASCII */
|
||||
VIRTB_KB_UNKNOWN = 0,
|
||||
VIRTB_KB_FIRST = 0,
|
||||
VIRTB_KB_BACKSPACE = 8,
|
||||
VIRTB_KB_TAB = 9,
|
||||
VIRTB_KB_CLEAR = 12,
|
||||
VIRTB_KB_RETURN = 13,
|
||||
VIRTB_KB_PAUSE = 19,
|
||||
VIRTB_KB_ESCAPE = 27,
|
||||
VIRTB_KB_SPACE = 32,
|
||||
VIRTB_KB_EXCLAIM = 33,
|
||||
VIRTB_KB_QUOTEDBL = 34,
|
||||
VIRTB_KB_HASH = 35,
|
||||
VIRTB_KB_DOLLAR = 36,
|
||||
VIRTB_KB_AMPERSAND = 38,
|
||||
VIRTB_KB_QUOTE = 39,
|
||||
VIRTB_KB_LEFTPAREN = 40,
|
||||
VIRTB_KB_RIGHTPAREN = 41,
|
||||
VIRTB_KB_ASTERISK = 42,
|
||||
VIRTB_KB_PLUS = 43,
|
||||
VIRTB_KB_COMMA = 44,
|
||||
VIRTB_KB_MINUS = 45,
|
||||
VIRTB_KB_PERIOD = 46,
|
||||
VIRTB_KB_SLASH = 47,
|
||||
VIRTB_KB_0 = 48,
|
||||
VIRTB_KB_1 = 49,
|
||||
VIRTB_KB_2 = 50,
|
||||
VIRTB_KB_3 = 51,
|
||||
VIRTB_KB_4 = 52,
|
||||
VIRTB_KB_5 = 53,
|
||||
VIRTB_KB_6 = 54,
|
||||
VIRTB_KB_7 = 55,
|
||||
VIRTB_KB_8 = 56,
|
||||
VIRTB_KB_9 = 57,
|
||||
VIRTB_KB_COLON = 58,
|
||||
VIRTB_KB_SEMICOLON = 59,
|
||||
VIRTB_KB_LESS = 60,
|
||||
VIRTB_KB_EQUALS = 61,
|
||||
VIRTB_KB_GREATER = 62,
|
||||
VIRTB_KB_QUESTION = 63,
|
||||
VIRTB_KB_AT = 64,
|
||||
/*
|
||||
Skip uppercase letters
|
||||
*/
|
||||
VIRTB_KB_LEFTBRACKET = 91,
|
||||
VIRTB_KB_BACKSLASH = 92,
|
||||
VIRTB_KB_RIGHTBRACKET = 93,
|
||||
VIRTB_KB_CARET = 94,
|
||||
VIRTB_KB_UNDERSCORE = 95,
|
||||
VIRTB_KB_BACKQUOTE = 96,
|
||||
VIRTB_KB_a = 97,
|
||||
VIRTB_KB_b = 98,
|
||||
VIRTB_KB_c = 99,
|
||||
VIRTB_KB_d = 100,
|
||||
VIRTB_KB_e = 101,
|
||||
VIRTB_KB_f = 102,
|
||||
VIRTB_KB_g = 103,
|
||||
VIRTB_KB_h = 104,
|
||||
VIRTB_KB_i = 105,
|
||||
VIRTB_KB_j = 106,
|
||||
VIRTB_KB_k = 107,
|
||||
VIRTB_KB_l = 108,
|
||||
VIRTB_KB_m = 109,
|
||||
VIRTB_KB_n = 110,
|
||||
VIRTB_KB_o = 111,
|
||||
VIRTB_KB_p = 112,
|
||||
VIRTB_KB_q = 113,
|
||||
VIRTB_KB_r = 114,
|
||||
VIRTB_KB_s = 115,
|
||||
VIRTB_KB_t = 116,
|
||||
VIRTB_KB_u = 117,
|
||||
VIRTB_KB_v = 118,
|
||||
VIRTB_KB_w = 119,
|
||||
VIRTB_KB_x = 120,
|
||||
VIRTB_KB_y = 121,
|
||||
VIRTB_KB_z = 122,
|
||||
VIRTB_KB_DELETE = 127,
|
||||
/* End of ASCII mapped keysyms */
|
||||
|
||||
/* International keyboard syms */
|
||||
VIRTB_KB_WORLD_0 = 160, /* 0xA0 */
|
||||
VIRTB_KB_WORLD_1 = 161,
|
||||
VIRTB_KB_WORLD_2 = 162,
|
||||
VIRTB_KB_WORLD_3 = 163,
|
||||
VIRTB_KB_WORLD_4 = 164,
|
||||
VIRTB_KB_WORLD_5 = 165,
|
||||
VIRTB_KB_WORLD_6 = 166,
|
||||
VIRTB_KB_WORLD_7 = 167,
|
||||
VIRTB_KB_WORLD_8 = 168,
|
||||
VIRTB_KB_WORLD_9 = 169,
|
||||
VIRTB_KB_WORLD_10 = 170,
|
||||
VIRTB_KB_WORLD_11 = 171,
|
||||
VIRTB_KB_WORLD_12 = 172,
|
||||
VIRTB_KB_WORLD_13 = 173,
|
||||
VIRTB_KB_WORLD_14 = 174,
|
||||
VIRTB_KB_WORLD_15 = 175,
|
||||
VIRTB_KB_WORLD_16 = 176,
|
||||
VIRTB_KB_WORLD_17 = 177,
|
||||
VIRTB_KB_WORLD_18 = 178,
|
||||
VIRTB_KB_WORLD_19 = 179,
|
||||
VIRTB_KB_WORLD_20 = 180,
|
||||
VIRTB_KB_WORLD_21 = 181,
|
||||
VIRTB_KB_WORLD_22 = 182,
|
||||
VIRTB_KB_WORLD_23 = 183,
|
||||
VIRTB_KB_WORLD_24 = 184,
|
||||
VIRTB_KB_WORLD_25 = 185,
|
||||
VIRTB_KB_WORLD_26 = 186,
|
||||
VIRTB_KB_WORLD_27 = 187,
|
||||
VIRTB_KB_WORLD_28 = 188,
|
||||
VIRTB_KB_WORLD_29 = 189,
|
||||
VIRTB_KB_WORLD_30 = 190,
|
||||
VIRTB_KB_WORLD_31 = 191,
|
||||
VIRTB_KB_WORLD_32 = 192,
|
||||
VIRTB_KB_WORLD_33 = 193,
|
||||
VIRTB_KB_WORLD_34 = 194,
|
||||
VIRTB_KB_WORLD_35 = 195,
|
||||
VIRTB_KB_WORLD_36 = 196,
|
||||
VIRTB_KB_WORLD_37 = 197,
|
||||
VIRTB_KB_WORLD_38 = 198,
|
||||
VIRTB_KB_WORLD_39 = 199,
|
||||
VIRTB_KB_WORLD_40 = 200,
|
||||
VIRTB_KB_WORLD_41 = 201,
|
||||
VIRTB_KB_WORLD_42 = 202,
|
||||
VIRTB_KB_WORLD_43 = 203,
|
||||
VIRTB_KB_WORLD_44 = 204,
|
||||
VIRTB_KB_WORLD_45 = 205,
|
||||
VIRTB_KB_WORLD_46 = 206,
|
||||
VIRTB_KB_WORLD_47 = 207,
|
||||
VIRTB_KB_WORLD_48 = 208,
|
||||
VIRTB_KB_WORLD_49 = 209,
|
||||
VIRTB_KB_WORLD_50 = 210,
|
||||
VIRTB_KB_WORLD_51 = 211,
|
||||
VIRTB_KB_WORLD_52 = 212,
|
||||
VIRTB_KB_WORLD_53 = 213,
|
||||
VIRTB_KB_WORLD_54 = 214,
|
||||
VIRTB_KB_WORLD_55 = 215,
|
||||
VIRTB_KB_WORLD_56 = 216,
|
||||
VIRTB_KB_WORLD_57 = 217,
|
||||
VIRTB_KB_WORLD_58 = 218,
|
||||
VIRTB_KB_WORLD_59 = 219,
|
||||
VIRTB_KB_WORLD_60 = 220,
|
||||
VIRTB_KB_WORLD_61 = 221,
|
||||
VIRTB_KB_WORLD_62 = 222,
|
||||
VIRTB_KB_WORLD_63 = 223,
|
||||
VIRTB_KB_WORLD_64 = 224,
|
||||
VIRTB_KB_WORLD_65 = 225,
|
||||
VIRTB_KB_WORLD_66 = 226,
|
||||
VIRTB_KB_WORLD_67 = 227,
|
||||
VIRTB_KB_WORLD_68 = 228,
|
||||
VIRTB_KB_WORLD_69 = 229,
|
||||
VIRTB_KB_WORLD_70 = 230,
|
||||
VIRTB_KB_WORLD_71 = 231,
|
||||
VIRTB_KB_WORLD_72 = 232,
|
||||
VIRTB_KB_WORLD_73 = 233,
|
||||
VIRTB_KB_WORLD_74 = 234,
|
||||
VIRTB_KB_WORLD_75 = 235,
|
||||
VIRTB_KB_WORLD_76 = 236,
|
||||
VIRTB_KB_WORLD_77 = 237,
|
||||
VIRTB_KB_WORLD_78 = 238,
|
||||
VIRTB_KB_WORLD_79 = 239,
|
||||
VIRTB_KB_WORLD_80 = 240,
|
||||
VIRTB_KB_WORLD_81 = 241,
|
||||
VIRTB_KB_WORLD_82 = 242,
|
||||
VIRTB_KB_WORLD_83 = 243,
|
||||
VIRTB_KB_WORLD_84 = 244,
|
||||
VIRTB_KB_WORLD_85 = 245,
|
||||
VIRTB_KB_WORLD_86 = 246,
|
||||
VIRTB_KB_WORLD_87 = 247,
|
||||
VIRTB_KB_WORLD_88 = 248,
|
||||
VIRTB_KB_WORLD_89 = 249,
|
||||
VIRTB_KB_WORLD_90 = 250,
|
||||
VIRTB_KB_WORLD_91 = 251,
|
||||
VIRTB_KB_WORLD_92 = 252,
|
||||
VIRTB_KB_WORLD_93 = 253,
|
||||
VIRTB_KB_WORLD_94 = 254,
|
||||
VIRTB_KB_WORLD_95 = 255, /* 0xFF */
|
||||
|
||||
/* Numeric keypad */
|
||||
VIRTB_KB_KP0 = 256,
|
||||
VIRTB_KB_KP1 = 257,
|
||||
VIRTB_KB_KP2 = 258,
|
||||
VIRTB_KB_KP3 = 259,
|
||||
VIRTB_KB_KP4 = 260,
|
||||
VIRTB_KB_KP5 = 261,
|
||||
VIRTB_KB_KP6 = 262,
|
||||
VIRTB_KB_KP7 = 263,
|
||||
VIRTB_KB_KP8 = 264,
|
||||
VIRTB_KB_KP9 = 265,
|
||||
VIRTB_KB_KP_PERIOD = 266,
|
||||
VIRTB_KB_KP_DIVIDE = 267,
|
||||
VIRTB_KB_KP_MULTIPLY = 268,
|
||||
VIRTB_KB_KP_MINUS = 269,
|
||||
VIRTB_KB_KP_PLUS = 270,
|
||||
VIRTB_KB_KP_ENTER = 271,
|
||||
VIRTB_KB_KP_EQUALS = 272,
|
||||
|
||||
/* Arrows + Home/End pad */
|
||||
VIRTB_KB_UP = 273,
|
||||
VIRTB_KB_DOWN = 274,
|
||||
VIRTB_KB_RIGHT = 275,
|
||||
VIRTB_KB_LEFT = 276,
|
||||
VIRTB_KB_INSERT = 277,
|
||||
VIRTB_KB_HOME = 278,
|
||||
VIRTB_KB_END = 279,
|
||||
VIRTB_KB_PAGEUP = 280,
|
||||
VIRTB_KB_PAGEDOWN = 281,
|
||||
|
||||
/* Function keys */
|
||||
VIRTB_KB_F1 = 282,
|
||||
VIRTB_KB_F2 = 283,
|
||||
VIRTB_KB_F3 = 284,
|
||||
VIRTB_KB_F4 = 285,
|
||||
VIRTB_KB_F5 = 286,
|
||||
VIRTB_KB_F6 = 287,
|
||||
VIRTB_KB_F7 = 288,
|
||||
VIRTB_KB_F8 = 289,
|
||||
VIRTB_KB_F9 = 290,
|
||||
VIRTB_KB_F10 = 291,
|
||||
VIRTB_KB_F11 = 292,
|
||||
VIRTB_KB_F12 = 293,
|
||||
VIRTB_KB_F13 = 294,
|
||||
VIRTB_KB_F14 = 295,
|
||||
VIRTB_KB_F15 = 296,
|
||||
|
||||
/* Key state modifier keys */
|
||||
VIRTB_KB_NUMLOCK = 300,
|
||||
VIRTB_KB_CAPSLOCK = 301,
|
||||
VIRTB_KB_SCROLLOCK = 302,
|
||||
VIRTB_KB_RSHIFT = 303,
|
||||
VIRTB_KB_LSHIFT = 304,
|
||||
VIRTB_KB_RCTRL = 305,
|
||||
VIRTB_KB_LCTRL = 306,
|
||||
VIRTB_KB_RALT = 307,
|
||||
VIRTB_KB_LALT = 308,
|
||||
VIRTB_KB_RMETA = 309,
|
||||
VIRTB_KB_LMETA = 310,
|
||||
VIRTB_KB_LSUPER = 311, /* Left "Windows" key */
|
||||
VIRTB_KB_RSUPER = 312, /* Right "Windows" key */
|
||||
VIRTB_KB_MODE = 313, /* "Alt Gr" key */
|
||||
VIRTB_KB_COMPOSE = 314, /* Multi-key compose key */
|
||||
|
||||
/* Miscellaneous function keys */
|
||||
VIRTB_KB_HELP = 315,
|
||||
VIRTB_KB_PRINT = 316,
|
||||
VIRTB_KB_SYSREQ = 317,
|
||||
VIRTB_KB_BREAK = 318,
|
||||
VIRTB_KB_MENU = 319,
|
||||
VIRTB_KB_POWER = 320, /* Power Macintosh power key */
|
||||
VIRTB_KB_EURO = 321, /* Some european keyboards */
|
||||
VIRTB_KB_UNDO = 322, /* Atari keyboard has Undo */
|
||||
|
||||
/* Add any other keys here */
|
||||
|
||||
VIRTB_KB_LAST,
|
||||
|
||||
/* Mednafen-specific virtual buttons */
|
||||
|
||||
// D-pad 0
|
||||
VIRTB_DP0_U = 0x1000,
|
||||
VIRTB_DP0_D,
|
||||
VIRTB_DP0_L,
|
||||
VIRTB_DP0_R,
|
||||
|
||||
// D-pad 1
|
||||
VIRTB_DP1_U = 0x1100,
|
||||
VIRTB_DP1_D,
|
||||
VIRTB_DP1_L,
|
||||
VIRTB_DP1_R,
|
||||
|
||||
// Single row of buttons. Don't use if VIRTB_TOP_* or VIRTB_BOTTOM_* virtual buttons are also used with the device.
|
||||
// This is for simple devices with one row of action buttons.
|
||||
VIRTB_0 = 0x2000,
|
||||
VIRTB_1,
|
||||
VIRTB_2,
|
||||
VIRTB_3,
|
||||
|
||||
// Top row of buttons, left to right.
|
||||
VIRTB_TOP_0 = 0x2100,
|
||||
VIRTB_TOP_1,
|
||||
VIRTB_TOP_2,
|
||||
VIRTB_TOP_3,
|
||||
|
||||
// Bottom row of buttons.
|
||||
VIRTB_BOT_0 = 0x2200,
|
||||
VIRTB_BOT_1,
|
||||
VIRTB_BOT_2,
|
||||
VIRTB_BOT_3,
|
||||
|
||||
VIRTB_SELECT = 0x2800,
|
||||
VIRTB_START,
|
||||
|
||||
// Diamond-shaped button arrangement
|
||||
VIRTB_DMD_L = VIRTB_BOT_0, /*0x3000*/ // Treated equivalent to VIRTB_BOT_0 for now.
|
||||
VIRTB_DMD_R = VIRTB_TOP_1, // Treated equivalent to VIRTB_TOP_1, for now.
|
||||
VIRTB_DMD_U = VIRTB_TOP_0, // Treated equivalent to VIRTB_TOP_0, for now.
|
||||
VIRTB_DMD_D = VIRTB_BOT_1, // Treated equivalent to VIRTB_BOT_1, for now.
|
||||
|
||||
// Shoulder buttons
|
||||
|
||||
VIRTB_SHLDR_L = 0x3100,
|
||||
VIRTB_SHLDR_R,
|
||||
|
||||
VIRTB_LAST
|
||||
} InputDeviceInputVB;
|
||||
|
||||
#endif
|
383
mednafen/git.h
Normal file
383
mednafen/git.h
Normal file
@ -0,0 +1,383 @@
|
||||
#ifndef _GIT_H
|
||||
#define _GIT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "video.h"
|
||||
#include "sound.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *extension; // Example ".nes"
|
||||
const char *description; // Example "iNES Format ROM Image"
|
||||
} FileExtensionSpecStruct;
|
||||
|
||||
#include "file.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MDFN_ROTATE0 = 0,
|
||||
MDFN_ROTATE90,
|
||||
MDFN_ROTATE180,
|
||||
MDFN_ROTATE270
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VIDSYS_NONE, // Can be used internally in system emulation code, but it is an error condition to let it continue to be
|
||||
// after the Load() or LoadCD() function returns!
|
||||
VIDSYS_PAL,
|
||||
VIDSYS_PAL_M, // Same timing as NTSC, but uses PAL-style colour encoding
|
||||
VIDSYS_NTSC,
|
||||
VIDSYS_SECAM
|
||||
} VideoSystems;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GMT_CART, // Self-explanatory!
|
||||
GMT_ARCADE, // VS Unisystem, PC-10...
|
||||
GMT_DISK, // Famicom Disk System, mostly
|
||||
GMT_CDROM, // PC Engine CD, PC-FX
|
||||
GMT_PLAYER // Music player(NSF, HES, GSF)
|
||||
} GameMediumTypes;
|
||||
|
||||
#include "state.h"
|
||||
#include "settings-common.h"
|
||||
|
||||
#ifdef WANT_DEBUGGER
|
||||
// #ifdef WANT_DEBUGGER
|
||||
// typedef struct DebuggerInfoStruct;
|
||||
// #else
|
||||
#include "debug.h"
|
||||
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IDIT_BUTTON, // 1-bit
|
||||
IDIT_BUTTON_CAN_RAPID, // 1-bit
|
||||
IDIT_BUTTON_BYTE, // 8-bits, Button as a byte instead of a bit.
|
||||
IDIT_X_AXIS, // 32-bits
|
||||
IDIT_Y_AXIS, // 32-bits
|
||||
IDIT_X_AXIS_REL, // 32-bits, signed
|
||||
IDIT_Y_AXIS_REL, // 32-bits, signed
|
||||
IDIT_BYTE_SPECIAL,
|
||||
IDIT_BUTTON_ANALOG, // 32-bits, 0 - 32767
|
||||
} InputDeviceInputType;
|
||||
|
||||
#include "git-virtb.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *SettingName; // No spaces, shouldbe all a-z0-9 and _. Definitely no ~!
|
||||
const char *Name;
|
||||
/*const InputDeviceInputVB VirtButton;*/
|
||||
const int ConfigOrder; // Configuration order during in-game config process, -1 for no config.
|
||||
const InputDeviceInputType Type;
|
||||
const char *ExcludeName; // SettingName of a button that can't be pressed at the same time as this button
|
||||
// due to physical limitations.
|
||||
|
||||
const char *RotateName[3]; // 90, 180, 270
|
||||
//const char *Rotate180Name;
|
||||
//const char *Rotate270Name;
|
||||
} InputDeviceInputInfoStruct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *ShortName;
|
||||
const char *FullName;
|
||||
|
||||
//struct InputPortInfoStruct *PortExpanderDeviceInfo;
|
||||
const void *PortExpanderDeviceInfo;
|
||||
int NumInputs; // Usually just the number of buttons....OR if PortExpanderDeviceInfo is non-NULL, it's the number of input
|
||||
// ports this port expander device provides.
|
||||
const InputDeviceInputInfoStruct *IDII;
|
||||
} InputDeviceInfoStruct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const int pid_offset;
|
||||
const char *ShortName;
|
||||
const char *FullName;
|
||||
int NumTypes; // Number of unique input devices available for this input port
|
||||
InputDeviceInfoStruct *DeviceInfo;
|
||||
const char *DefaultDevice; // Default device for this port.
|
||||
} InputPortInfoStruct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int InputPorts;
|
||||
const InputPortInfoStruct *Types;
|
||||
} InputInfoStruct;
|
||||
|
||||
|
||||
// Miscellaneous system/simple commands(power, reset, dip switch toggles, coin insert, etc.)
|
||||
// (for DoSimpleCommand() )
|
||||
enum
|
||||
{
|
||||
MDFN_MSC_RESET = 0x01,
|
||||
MDFN_MSC_POWER = 0x02,
|
||||
|
||||
MDFN_MSC_INSERT_COIN = 0x07,
|
||||
|
||||
// If we ever support arcade systems, we'll abstract DIP switches differently...maybe.
|
||||
MDFN_MSC_TOGGLE_DIP0 = 0x10,
|
||||
MDFN_MSC_TOGGLE_DIP1,
|
||||
MDFN_MSC_TOGGLE_DIP2,
|
||||
MDFN_MSC_TOGGLE_DIP3,
|
||||
MDFN_MSC_TOGGLE_DIP4,
|
||||
MDFN_MSC_TOGGLE_DIP5,
|
||||
MDFN_MSC_TOGGLE_DIP6,
|
||||
MDFN_MSC_TOGGLE_DIP7,
|
||||
MDFN_MSC_TOGGLE_DIP8,
|
||||
MDFN_MSC_TOGGLE_DIP9,
|
||||
MDFN_MSC_TOGGLE_DIP10,
|
||||
MDFN_MSC_TOGGLE_DIP11,
|
||||
MDFN_MSC_TOGGLE_DIP12,
|
||||
MDFN_MSC_TOGGLE_DIP13,
|
||||
MDFN_MSC_TOGGLE_DIP14,
|
||||
MDFN_MSC_TOGGLE_DIP15,
|
||||
|
||||
|
||||
// n of DISKn translates to is emulation module specific.
|
||||
MDFN_MSC_INSERT_DISK0 = 0x20,
|
||||
MDFN_MSC_INSERT_DISK1,
|
||||
MDFN_MSC_INSERT_DISK2,
|
||||
MDFN_MSC_INSERT_DISK3,
|
||||
MDFN_MSC_INSERT_DISK4,
|
||||
MDFN_MSC_INSERT_DISK5,
|
||||
MDFN_MSC_INSERT_DISK6,
|
||||
MDFN_MSC_INSERT_DISK7,
|
||||
MDFN_MSC_INSERT_DISK8,
|
||||
MDFN_MSC_INSERT_DISK9,
|
||||
MDFN_MSC_INSERT_DISK10,
|
||||
MDFN_MSC_INSERT_DISK11,
|
||||
MDFN_MSC_INSERT_DISK12,
|
||||
MDFN_MSC_INSERT_DISK13,
|
||||
MDFN_MSC_INSERT_DISK14,
|
||||
MDFN_MSC_INSERT_DISK15,
|
||||
|
||||
MDFN_MSC_INSERT_DISK = 0x30,
|
||||
MDFN_MSC_EJECT_DISK = 0x31,
|
||||
|
||||
// This command should select the next disk or disk side in the set and use MDFN_DispMessage() to show which disk is selected.
|
||||
// (If it's only allowed while a disk is ejected, or not, is emulation module specific.
|
||||
MDFN_MSC_SELECT_DISK = 0x32,
|
||||
|
||||
MDFN_MSC__LAST = 0x3F // WARNING: Increasing(or having the enum'd value of a command greater than this :b) this will necessitate a change to the netplay protocol.
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Pitch(32-bit) must be equal to width and >= the pitch specified in the MDFNGI struct for the emulated system.
|
||||
// Height must be >= to the fb_height specified in the MDFNGI struct for the emulated system.
|
||||
// The framebuffer pointed to by surface->pixels is written to by the system emulation code.
|
||||
MDFN_Surface *surface;
|
||||
|
||||
// Will be set to TRUE if the video pixel format has changed since the last call to Emulate(), FALSE otherwise.
|
||||
// Will be set to TRUE on the first call to the Emulate() function/method
|
||||
bool VideoFormatChanged;
|
||||
|
||||
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
|
||||
// of the image. If the emulated system sets the elements of LineWidths, then the horizontal offset(x) and width(w) of this structure
|
||||
// are ignored while drawing the image.
|
||||
MDFN_Rect DisplayRect;
|
||||
|
||||
// Pointer to an array of MDFN_Rect, number of elements = fb_height, set by the driver code. Individual MDFN_Rect structs written
|
||||
// to by system emulation code. If the emulated system doesn't support multiple screen widths per frame, or if you handle
|
||||
// such a situation by outputting at a constant width-per-frame that is the least-common-multiple of the screen widths, then
|
||||
// you can ignore this. If you do wish to use this, you must set all elements every frame.
|
||||
MDFN_Rect *LineWidths;
|
||||
|
||||
// TODO
|
||||
bool *IsFMV;
|
||||
|
||||
// Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
|
||||
// only every other line in surface (with the start line defined by InterlacedField) has valid data
|
||||
// (it's up to internal Mednafen code to deinterlace it).
|
||||
bool InterlaceOn;
|
||||
bool InterlaceField;
|
||||
|
||||
// Skip rendering this frame if true. Set by the driver code.
|
||||
int skip;
|
||||
|
||||
//
|
||||
// If sound is disabled, the driver code must set SoundRate to false, SoundBuf to NULL, SoundBufMaxSize to 0.
|
||||
|
||||
// Will be set to TRUE if the sound format(only rate for now, at least) has changed since the last call to Emulate(), FALSE otherwise.
|
||||
// Will be set to TRUE on the first call to the Emulate() function/method
|
||||
bool SoundFormatChanged;
|
||||
|
||||
// Sound rate. Set by driver side.
|
||||
double SoundRate;
|
||||
|
||||
// Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
|
||||
// Guaranteed to be at least 500ms in length, but emulation code really shouldn't exceed 40ms or so. Additionally, if emulation code
|
||||
// generates >= 100ms,
|
||||
// DEPRECATED: Emulation code may set this pointer to a sound buffer internal to the emulation module.
|
||||
int16 *SoundBuf;
|
||||
|
||||
// Maximum size of the sound buffer, in frames. Set by the driver code.
|
||||
int32 SoundBufMaxSize;
|
||||
|
||||
// Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
|
||||
int32 SoundBufSize;
|
||||
int32 SoundBufSizeALMS; // SoundBufSize value at last MidSync(), 0
|
||||
// if mid sync isn't implemented for the emulation module in use.
|
||||
|
||||
// Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
|
||||
// Set by emulation code.
|
||||
int64 MasterCycles;
|
||||
int64 MasterCyclesALMS; // MasterCycles value at last MidSync(), 0
|
||||
// if mid sync isn't implemented for the emulation module in use.
|
||||
|
||||
// Current sound volume(0.000...<=volume<=1.000...). If, after calling Emulate(), it is still != 1, Mednafen will handle it internally.
|
||||
// Emulation modules can handle volume themselves if they like, for speed reasons. If they do, afterwards, they should set its value to 1.
|
||||
double SoundVolume;
|
||||
|
||||
// Current sound speed multiplier. Set by the driver code. If, after calling Emulate(), it is still != 1, Mednafen will handle it internally
|
||||
// by resampling the audio. This means that emulation modules can handle(and set the value to 1 after handling it) it if they want to get the most
|
||||
// performance possible. HOWEVER, emulation modules must make sure the value is in a range(with minimum and maximum) that their code can handle
|
||||
// before they try to handle it.
|
||||
double soundmultiplier;
|
||||
|
||||
// True if we want to rewind one frame. Set by the driver code.
|
||||
bool NeedRewind;
|
||||
|
||||
// Sound reversal during state rewinding is normally done in mednafen.cpp, but
|
||||
// individual system emulation code can also do it if this is set, and clear it after it's done.
|
||||
// (Also, the driver code shouldn't touch this variable)
|
||||
bool NeedSoundReverse;
|
||||
|
||||
} EmulateSpecStruct;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MODPRIO_INTERNAL_EXTRA_LOW = 0, // For "cdplay" module, mostly.
|
||||
|
||||
MODPRIO_INTERNAL_LOW = 10,
|
||||
MODPRIO_EXTERNAL_LOW = 20,
|
||||
MODPRIO_INTERNAL_HIGH = 30,
|
||||
MODPRIO_EXTERNAL_HIGH = 40
|
||||
} ModPrio;
|
||||
|
||||
class CDIF;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Private functions to Mednafen. Do not call directly
|
||||
from the driver code, or else bad things shall happen. Maybe. Probably not, but don't
|
||||
do it(yet)!
|
||||
*/
|
||||
// Short system name, lowercase a-z, 0-9, and _ are the only allowable characters!
|
||||
const char *shortname;
|
||||
|
||||
// Full system name. Preferably English letters, but can be UTF8
|
||||
const char *fullname;
|
||||
|
||||
// Pointer to an array of FileExtensionSpecStruct, with the last entry being { NULL, NULL } to terminate the list.
|
||||
// This list is used to make best-guess choices, when calling the TestMagic*() functions would be unreasonable, such
|
||||
// as when scanning a ZIP archive for a file to load. The list may also be used in the future for GUI file open windows.
|
||||
const FileExtensionSpecStruct *FileExtensions;
|
||||
|
||||
ModPrio ModulePriority;
|
||||
|
||||
#ifdef WANT_DEBUGGER
|
||||
DebuggerInfoStruct *Debugger;
|
||||
#else
|
||||
void *Debugger;
|
||||
#endif
|
||||
InputInfoStruct *InputInfo;
|
||||
|
||||
// Returns 1 on successful load, 0 on fatal error(deprecated: -1 on unrecognized format)
|
||||
int (*Load)(const char *name, MDFNFILE *fp);
|
||||
|
||||
// Return TRUE if the file is a recognized type, FALSE if not.
|
||||
bool (*TestMagic)(const char *name, MDFNFILE *fp);
|
||||
|
||||
//
|
||||
// (*CDInterfaces).size() is guaranteed to be >= 1.
|
||||
int (*LoadCD)(std::vector<CDIF *> *CDInterfaces);
|
||||
bool (*TestMagicCD)(std::vector<CDIF *> *CDInterfaces);
|
||||
|
||||
void (*CloseGame)(void);
|
||||
|
||||
void (*SetLayerEnableMask)(uint64 mask); // Video
|
||||
const char *LayerNames;
|
||||
|
||||
void (*SetChanEnableMask)(uint64 mask); // Audio(TODO, placeholder)
|
||||
const char *ChanNames;
|
||||
|
||||
void (*InstallReadPatch)(uint32 address);
|
||||
void (*RemoveReadPatches)(void);
|
||||
uint8 (*MemRead)(uint32 addr);
|
||||
|
||||
// Main save state routine, called by the save state code in state.cpp.
|
||||
// When saving, load is set to 0. When loading, load is set to the version field of the save state being loaded.
|
||||
// data_only is true when the save state data is temporary, such as being saved into memory for state rewinding.
|
||||
int (*StateAction)(StateMem *sm, int load, int data_only);
|
||||
|
||||
void (*Emulate)(EmulateSpecStruct *espec);
|
||||
void (*SetInput)(int port, const char *type, void *ptr);
|
||||
|
||||
void (*DoSimpleCommand)(int cmd);
|
||||
|
||||
const MDFNSetting *Settings;
|
||||
|
||||
// Time base for EmulateSpecStruct::MasterCycles
|
||||
#define MDFN_MASTERCLOCK_FIXED(n) ((n) * (1LL << 32))
|
||||
int64 MasterClock;
|
||||
|
||||
uint32 fps; // frames per second * 65536 * 256, truncated
|
||||
|
||||
// multires is a hint that, if set, indicates that the system has fairly programmable video modes(particularly, the ability
|
||||
// to display multiple horizontal resolutions, such as the PCE, PC-FX, or Genesis). In practice, it will cause the driver
|
||||
// code to set the linear interpolation on by default.
|
||||
//
|
||||
// lcm_width and lcm_height are the least common multiples of all possible
|
||||
// resolutions in the frame buffer as specified by DisplayRect/LineWidths(Ex for PCE: widths of 256, 341.333333, 512,
|
||||
// lcm = 1024)
|
||||
//
|
||||
// nominal_width and nominal_height specify the resolution that Mednafen should display
|
||||
// the framebuffer image in at 1x scaling, scaled from the dimensions of DisplayRect, and optionally the LineWidths array
|
||||
// passed through espec to the Emulate() function.
|
||||
//
|
||||
bool multires;
|
||||
|
||||
int lcm_width;
|
||||
int lcm_height;
|
||||
|
||||
void *dummy_separator; //
|
||||
|
||||
int nominal_width;
|
||||
int nominal_height;
|
||||
|
||||
int fb_width; // Width of the framebuffer(not necessarily width of the image). MDFN_Surface width should be >= this.
|
||||
int fb_height; // Height of the framebuffer passed to the Emulate() function(not necessarily height of the image)
|
||||
|
||||
int soundchan; // Number of output sound channels.
|
||||
|
||||
|
||||
int rotated;
|
||||
|
||||
uint8 *name; /* Game name, UTF8 encoding */
|
||||
uint8 MD5[16];
|
||||
uint8 GameSetMD5[16]; /* A unique ID for the game set this CD belongs to, only used in PC-FX emulation. */
|
||||
bool GameSetMD5Valid; /* True if GameSetMD5 is valid. */
|
||||
|
||||
|
||||
int soundrate; /* For Ogg Vorbis expansion sound wacky support. 0 for default. */
|
||||
|
||||
VideoSystems VideoSystem;
|
||||
GameMediumTypes GameType;
|
||||
|
||||
//int DiskLogicalCount; // A single double-sided disk would be 2 here.
|
||||
//const char *DiskNames; // Null-terminated.
|
||||
|
||||
const char *cspecial; /* Special cart expansion: DIP switches, barcode reader, etc. */
|
||||
|
||||
std::vector<const char *>DesiredInput; // Desired input device for the input ports, NULL for don't care
|
||||
|
||||
double mouse_sensitivity;
|
||||
} MDFNGI;
|
||||
#endif
|
243
mednafen/include/Fir_Resampler.h
Normal file
243
mednafen/include/Fir_Resampler.h
Normal file
@ -0,0 +1,243 @@
|
||||
// Finite impulse response (FIR) resampler with adjustable FIR size
|
||||
|
||||
// Game_Music_Emu 0.5.2
|
||||
#ifndef FIR_RESAMPLER_H
|
||||
#define FIR_RESAMPLER_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
#include <string.h>
|
||||
|
||||
class Fir_Resampler_ {
|
||||
public:
|
||||
|
||||
// Use Fir_Resampler<width> (below)
|
||||
|
||||
// Set input/output resampling ratio and optionally low-pass rolloff and gain.
|
||||
// Returns actual ratio used (rounded to internal precision).
|
||||
double time_ratio( double factor, double rolloff = 0.999, double gain = 1.0 );
|
||||
|
||||
// Current input/output ratio
|
||||
double ratio() const { return ratio_; }
|
||||
|
||||
// Input
|
||||
|
||||
typedef short sample_t;
|
||||
|
||||
// Resize and clear input buffer
|
||||
blargg_err_t buffer_size( int );
|
||||
|
||||
// Clear input buffer. At least two output samples will be available after
|
||||
// two input samples are written.
|
||||
void clear();
|
||||
|
||||
// Number of input samples that can be written
|
||||
int max_write() const { return buf.end() - write_pos; }
|
||||
|
||||
// Pointer to place to write input samples
|
||||
sample_t* buffer() { return write_pos; }
|
||||
|
||||
// Notify resampler that 'count' input samples have been written
|
||||
void write( long count );
|
||||
|
||||
// Number of input samples in buffer
|
||||
int written() const { return write_pos - &buf [write_offset]; }
|
||||
|
||||
// Skip 'count' input samples. Returns number of samples actually skipped.
|
||||
int skip_input( long count );
|
||||
|
||||
// Output
|
||||
|
||||
// Number of extra input samples needed until 'count' output samples are available
|
||||
int input_needed( blargg_long count ) const;
|
||||
|
||||
// Number of output samples available
|
||||
int avail() const { return avail_( write_pos - &buf [width_ * stereo] ); }
|
||||
|
||||
public:
|
||||
~Fir_Resampler_();
|
||||
protected:
|
||||
enum { stereo = 2 };
|
||||
enum { max_res = 32 };
|
||||
blargg_vector<sample_t> buf;
|
||||
sample_t* write_pos;
|
||||
int res;
|
||||
int imp_phase;
|
||||
int const width_;
|
||||
int const write_offset;
|
||||
blargg_ulong skip_bits;
|
||||
int step;
|
||||
int input_per_cycle;
|
||||
double ratio_;
|
||||
sample_t* impulses;
|
||||
|
||||
Fir_Resampler_( int width, sample_t* );
|
||||
int avail_( blargg_long input_count ) const;
|
||||
};
|
||||
|
||||
// Width is number of points in FIR. Must be even and 4 or more. More points give
|
||||
// better quality and rolloff effectiveness, and take longer to calculate.
|
||||
template<int width>
|
||||
class Fir_Resampler : public Fir_Resampler_ {
|
||||
BOOST_STATIC_ASSERT( width >= 4 && width % 2 == 0 );
|
||||
short impulses [max_res] [width];
|
||||
public:
|
||||
Fir_Resampler() : Fir_Resampler_( width, impulses [0] ) { }
|
||||
|
||||
// Read at most 'count' samples. Returns number of samples actually read.
|
||||
typedef short sample_t;
|
||||
int read( sample_t* out, blargg_long count );
|
||||
|
||||
int read_mono_hack( sample_t* out, blargg_long count );
|
||||
};
|
||||
|
||||
// End of public interface
|
||||
|
||||
inline void Fir_Resampler_::write( long count )
|
||||
{
|
||||
write_pos += count;
|
||||
assert( write_pos <= buf.end() );
|
||||
}
|
||||
|
||||
template<int width>
|
||||
int Fir_Resampler<width>::read( sample_t* out_begin, blargg_long count )
|
||||
{
|
||||
sample_t* out = out_begin;
|
||||
const sample_t* in = buf.begin();
|
||||
sample_t* end_pos = write_pos;
|
||||
blargg_ulong skip = skip_bits >> imp_phase;
|
||||
sample_t const* imp = impulses [imp_phase];
|
||||
int remain = res - imp_phase;
|
||||
int const local_step = this->step;
|
||||
|
||||
count >>= 1;
|
||||
|
||||
if ( end_pos - in >= width * stereo )
|
||||
{
|
||||
end_pos -= width * stereo;
|
||||
do
|
||||
{
|
||||
count--;
|
||||
|
||||
// accumulate in extended precision
|
||||
blargg_long l = 0;
|
||||
blargg_long r = 0;
|
||||
|
||||
const sample_t* i = in;
|
||||
if ( count < 0 )
|
||||
break;
|
||||
|
||||
for ( int n = width / 2; n; --n )
|
||||
{
|
||||
int pt0 = imp [0];
|
||||
l += pt0 * i [0];
|
||||
r += pt0 * i [1];
|
||||
int pt1 = imp [1];
|
||||
imp += 2;
|
||||
l += pt1 * i [2];
|
||||
r += pt1 * i [3];
|
||||
i += 4;
|
||||
}
|
||||
|
||||
remain--;
|
||||
|
||||
l >>= 15;
|
||||
r >>= 15;
|
||||
|
||||
in += (skip * stereo) & stereo;
|
||||
skip >>= 1;
|
||||
in += local_step;
|
||||
|
||||
if ( !remain )
|
||||
{
|
||||
imp = impulses [0];
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
|
||||
out [0] = (sample_t) l;
|
||||
out [1] = (sample_t) r;
|
||||
out += 2;
|
||||
}
|
||||
while ( in <= end_pos );
|
||||
}
|
||||
|
||||
imp_phase = res - remain;
|
||||
|
||||
int left = write_pos - in;
|
||||
write_pos = &buf [left];
|
||||
memmove( buf.begin(), in, left * sizeof *in );
|
||||
|
||||
return out - out_begin;
|
||||
}
|
||||
#include <stdio.h>
|
||||
template<int width>
|
||||
int Fir_Resampler<width>::read_mono_hack( sample_t* out_begin, blargg_long count )
|
||||
{
|
||||
sample_t* out = out_begin;
|
||||
const sample_t* in = buf.begin();
|
||||
sample_t* end_pos = write_pos;
|
||||
blargg_ulong skip = skip_bits >> imp_phase;
|
||||
sample_t const* imp = impulses [imp_phase];
|
||||
int remain = res - imp_phase;
|
||||
int const local_step = this->step;
|
||||
|
||||
count >>= 1;
|
||||
|
||||
if ( end_pos - in >= width * stereo )
|
||||
{
|
||||
end_pos -= width * stereo;
|
||||
do
|
||||
{
|
||||
count--;
|
||||
|
||||
// accumulate in extended precision
|
||||
blargg_long l = 0;
|
||||
|
||||
const sample_t* i = in;
|
||||
if ( count < 0 )
|
||||
break;
|
||||
|
||||
for ( int n = width / 2; n; --n )
|
||||
{
|
||||
int pt0 = imp [0];
|
||||
l += pt0 * i [0];
|
||||
|
||||
int pt1 = imp [1];
|
||||
imp += 2;
|
||||
l += pt1 * i [2];
|
||||
|
||||
i += 4;
|
||||
}
|
||||
|
||||
remain--;
|
||||
|
||||
l >>= 15;
|
||||
|
||||
in += (skip * stereo) & stereo;
|
||||
skip >>= 1;
|
||||
in += local_step;
|
||||
|
||||
if ( !remain )
|
||||
{
|
||||
imp = impulses [0];
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
|
||||
*out = (sample_t) l;
|
||||
out ++;
|
||||
}
|
||||
while ( in <= end_pos );
|
||||
}
|
||||
|
||||
imp_phase = res - remain;
|
||||
|
||||
int left = write_pos - in;
|
||||
write_pos = &buf [left];
|
||||
memmove( buf.begin(), in, left * sizeof *in );
|
||||
|
||||
return out - out_begin;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
175
mednafen/include/blargg_common.h
Normal file
175
mednafen/include/blargg_common.h
Normal file
@ -0,0 +1,175 @@
|
||||
// Sets up common environment for Shay Green's libraries.
|
||||
// To change configuration options, modify blargg_config.h, not this file.
|
||||
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#undef BLARGG_COMMON_H
|
||||
// allow blargg_config.h to #include blargg_common.h
|
||||
#include "blargg_config.h"
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
|
||||
#ifndef STATIC_CAST
|
||||
#define STATIC_CAST(T,expr) ((T) (expr))
|
||||
#endif
|
||||
|
||||
// blargg_err_t (0 on success, otherwise error string)
|
||||
#ifndef blargg_err_t
|
||||
typedef const char* blargg_err_t;
|
||||
#endif
|
||||
|
||||
// blargg_vector - very lightweight vector of POD types (no constructor/destructor)
|
||||
template<class T>
|
||||
class blargg_vector {
|
||||
T* begin_;
|
||||
size_t size_;
|
||||
public:
|
||||
blargg_vector() : begin_( 0 ), size_( 0 ) { }
|
||||
~blargg_vector() { free( begin_ ); }
|
||||
size_t size() const { return size_; }
|
||||
T* begin() const { return begin_; }
|
||||
T* end() const { return begin_ + size_; }
|
||||
blargg_err_t resize( size_t n )
|
||||
{
|
||||
void* p = realloc( begin_, n * sizeof (T) );
|
||||
if ( !p && n )
|
||||
return "Out of memory";
|
||||
begin_ = (T*) p;
|
||||
size_ = n;
|
||||
return 0;
|
||||
}
|
||||
void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); }
|
||||
T& operator [] ( size_t n ) const
|
||||
{
|
||||
assert( n <= size_ ); // <= to allow past-the-end value
|
||||
return begin_ [n];
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef BLARGG_DISABLE_NOTHROW
|
||||
#if __cplusplus < 199711
|
||||
#define BLARGG_THROWS( spec )
|
||||
#else
|
||||
#define BLARGG_THROWS( spec ) throw spec
|
||||
#endif
|
||||
#define BLARGG_DISABLE_NOTHROW \
|
||||
void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\
|
||||
void operator delete ( void* p ) { free( p ); }
|
||||
#define BLARGG_NEW new
|
||||
#else
|
||||
#include <new>
|
||||
#define BLARGG_NEW new (std::nothrow)
|
||||
#endif
|
||||
|
||||
#define BLARGG_4CHAR( a, b, c, d ) \
|
||||
((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
|
||||
|
||||
// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
|
||||
#ifndef BOOST_STATIC_ASSERT
|
||||
#ifdef _MSC_VER
|
||||
// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
|
||||
#define BOOST_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
|
||||
#else
|
||||
// Some other compilers fail when declaring same function multiple times in class,
|
||||
// so differentiate them by line
|
||||
#define BOOST_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
|
||||
// compiler is assumed to support bool. If undefined, availability is determined.
|
||||
#ifndef BLARGG_COMPILER_HAS_BOOL
|
||||
#if defined (__MWERKS__)
|
||||
#if !__option(bool)
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#elif defined (_MSC_VER)
|
||||
#if _MSC_VER < 1100
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#elif defined (__GNUC__)
|
||||
// supports bool
|
||||
#elif __cplusplus < 199711
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#endif
|
||||
#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
|
||||
// If you get errors here, modify your blargg_config.h file
|
||||
typedef int bool;
|
||||
const bool true = 1;
|
||||
const bool false = 0;
|
||||
#endif
|
||||
|
||||
// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
|
||||
#include <limits.h>
|
||||
|
||||
#if INT_MAX >= 0x7FFFFFFF
|
||||
typedef int blargg_long;
|
||||
#else
|
||||
typedef long blargg_long;
|
||||
#endif
|
||||
|
||||
#if UINT_MAX >= 0xFFFFFFFF
|
||||
typedef unsigned blargg_ulong;
|
||||
#else
|
||||
typedef unsigned long blargg_ulong;
|
||||
#endif
|
||||
|
||||
// BOOST::int8_t etc.
|
||||
|
||||
// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
|
||||
#if defined (HAVE_STDINT_H)
|
||||
#include <stdint.h>
|
||||
#define BOOST
|
||||
|
||||
// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
|
||||
#elif defined (HAVE_INTTYPES_H)
|
||||
#include <inttypes.h>
|
||||
#define BOOST
|
||||
|
||||
#else
|
||||
struct BOOST
|
||||
{
|
||||
#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
#else
|
||||
// No suitable 8-bit type available
|
||||
typedef struct see_blargg_common_h int8_t;
|
||||
typedef struct see_blargg_common_h uint8_t;
|
||||
#endif
|
||||
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
#else
|
||||
// No suitable 16-bit type available
|
||||
typedef struct see_blargg_common_h int16_t;
|
||||
typedef struct see_blargg_common_h uint16_t;
|
||||
#endif
|
||||
|
||||
#if ULONG_MAX == 0xFFFFFFFF
|
||||
typedef long int32_t;
|
||||
typedef unsigned long uint32_t;
|
||||
#elif UINT_MAX == 0xFFFFFFFF
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
// No suitable 32-bit type available
|
||||
typedef struct see_blargg_common_h int32_t;
|
||||
typedef struct see_blargg_common_h uint32_t;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
30
mednafen/include/blargg_config.h
Normal file
30
mednafen/include/blargg_config.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Library configuration. Modify this file as necessary.
|
||||
|
||||
#ifndef BLARGG_CONFIG_H
|
||||
#define BLARGG_CONFIG_H
|
||||
|
||||
// Uncomment to use zlib for transparent decompression of gzipped files
|
||||
//#define HAVE_ZLIB_H
|
||||
|
||||
// Uncomment to support only the listed game music types. See gme_type_list.cpp
|
||||
// for a list of all types.
|
||||
//#define GME_TYPE_LIST gme_nsf_type, gme_gbs_type
|
||||
|
||||
// Uncomment to enable platform-specific optimizations
|
||||
//#define BLARGG_NONPORTABLE 1
|
||||
|
||||
// Uncomment to use faster, lower quality sound synthesis
|
||||
//#define BLIP_BUFFER_FAST 1
|
||||
|
||||
// Uncomment if automatic byte-order determination doesn't work
|
||||
//#define BLARGG_BIG_ENDIAN 1
|
||||
|
||||
// Uncomment if you get errors in the bool section of blargg_common.h
|
||||
//#define BLARGG_COMPILER_HAS_BOOL 1
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#endif
|
158
mednafen/include/blargg_endian.h
Normal file
158
mednafen/include/blargg_endian.h
Normal file
@ -0,0 +1,158 @@
|
||||
// CPU Byte Order Utilities
|
||||
|
||||
// Game_Music_Emu 0.5.2
|
||||
#ifndef BLARGG_ENDIAN
|
||||
#define BLARGG_ENDIAN
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
|
||||
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
|
||||
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
|
||||
#define BLARGG_CPU_X86 1
|
||||
#define BLARGG_CPU_CISC 1
|
||||
#endif
|
||||
|
||||
#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc)
|
||||
#define BLARGG_CPU_POWERPC 1
|
||||
#endif
|
||||
|
||||
// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
|
||||
// one may be #defined to 1. Only needed if something actually depends on byte order.
|
||||
#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
|
||||
#ifdef __GLIBC__
|
||||
// GCC handles this for us
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#endif
|
||||
#else
|
||||
|
||||
#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
|
||||
(defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
|
||||
defined (__mips__) || defined (__sparc__) || BLARGG_CPU_POWERPC || \
|
||||
(defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#else
|
||||
// No endian specified; assume little-endian, since it's most common
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
|
||||
#undef BLARGG_LITTLE_ENDIAN
|
||||
#undef BLARGG_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
inline void blargg_verify_byte_order()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
#if BLARGG_BIG_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i == 0 );
|
||||
#elif BLARGG_LITTLE_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i != 0 );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
inline unsigned get_le16( void const* p ) {
|
||||
return ((unsigned char const*) p) [1] * 0x100u +
|
||||
((unsigned char const*) p) [0];
|
||||
}
|
||||
inline unsigned get_be16( void const* p ) {
|
||||
return ((unsigned char const*) p) [0] * 0x100u +
|
||||
((unsigned char const*) p) [1];
|
||||
}
|
||||
inline blargg_ulong get_le32( void const* p ) {
|
||||
return ((unsigned char const*) p) [3] * 0x01000000u +
|
||||
((unsigned char const*) p) [2] * 0x00010000u +
|
||||
((unsigned char const*) p) [1] * 0x00000100u +
|
||||
((unsigned char const*) p) [0];
|
||||
}
|
||||
inline blargg_ulong get_be32( void const* p ) {
|
||||
return ((unsigned char const*) p) [0] * 0x01000000u +
|
||||
((unsigned char const*) p) [1] * 0x00010000u +
|
||||
((unsigned char const*) p) [2] * 0x00000100u +
|
||||
((unsigned char const*) p) [3];
|
||||
}
|
||||
inline void set_le16( void* p, unsigned n ) {
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
}
|
||||
inline void set_be16( void* p, unsigned n ) {
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [1] = (unsigned char) n;
|
||||
}
|
||||
inline void set_le32( void* p, blargg_ulong n ) {
|
||||
((unsigned char*) p) [3] = (unsigned char) (n >> 24);
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
}
|
||||
inline void set_be32( void* p, blargg_ulong n ) {
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 24);
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [3] = (unsigned char) n;
|
||||
}
|
||||
|
||||
#if BLARGG_NONPORTABLE
|
||||
// Optimized implementation if byte order is known
|
||||
#if BLARGG_LITTLE_ENDIAN
|
||||
#define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
|
||||
#define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
|
||||
#define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
#elif BLARGG_BIG_ENDIAN
|
||||
#define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
|
||||
#define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
|
||||
#define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
#endif
|
||||
|
||||
#if BLARGG_CPU_POWERPC && defined (__MWERKS__)
|
||||
// PowerPC has special byte-reversed instructions
|
||||
// to do: assumes that PowerPC is running in big-endian mode
|
||||
// to do: implement for other compilers which don't support these macros
|
||||
#define GET_LE16( addr ) (__lhbrx( (addr), 0 ))
|
||||
#define GET_LE32( addr ) (__lwbrx( (addr), 0 ))
|
||||
#define SET_LE16( addr, data ) (__sthbrx( (data), (addr), 0 ))
|
||||
#define SET_LE32( addr, data ) (__stwbrx( (data), (addr), 0 ))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GET_LE16
|
||||
#define GET_LE16( addr ) get_le16( addr )
|
||||
#define GET_LE32( addr ) get_le32( addr )
|
||||
#define SET_LE16( addr, data ) set_le16( addr, data )
|
||||
#define SET_LE32( addr, data ) set_le32( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_BE16
|
||||
#define GET_BE16( addr ) get_be16( addr )
|
||||
#define GET_BE32( addr ) get_be32( addr )
|
||||
#define SET_BE16( addr, data ) set_be16( addr, data )
|
||||
#define SET_BE32( addr, data ) set_be32( addr, data )
|
||||
#endif
|
||||
|
||||
// auto-selecting versions
|
||||
|
||||
inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
|
||||
inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
|
||||
inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
|
||||
inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
|
||||
inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
|
||||
inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
|
||||
inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
|
||||
inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
|
||||
|
||||
#endif
|
78
mednafen/include/blargg_source.h
Normal file
78
mednafen/include/blargg_source.h
Normal file
@ -0,0 +1,78 @@
|
||||
// Included at the beginning of library source files, after all other #include lines
|
||||
#ifndef BLARGG_SOURCE_H
|
||||
#define BLARGG_SOURCE_H
|
||||
|
||||
// If debugging is enabled, abort program if expr is false. Meant for checking
|
||||
// internal state and consistency. A failed assertion indicates a bug in the module.
|
||||
// void assert( bool expr );
|
||||
#include <assert.h>
|
||||
|
||||
// If debugging is enabled and expr is false, abort program. Meant for checking
|
||||
// caller-supplied parameters and operations that are outside the control of the
|
||||
// module. A failed requirement indicates a bug outside the module.
|
||||
// void require( bool expr );
|
||||
#undef require
|
||||
#define require( expr ) assert( expr )
|
||||
|
||||
// Like printf() except output goes to debug log file. Might be defined to do
|
||||
// nothing (not even evaluate its arguments).
|
||||
// void dprintf( const char* format, ... );
|
||||
inline void blargg_dprintf_( const char*, ... ) { }
|
||||
#undef dprintf
|
||||
#define dprintf (1) ? (void) 0 : blargg_dprintf_
|
||||
|
||||
// If enabled, evaluate expr and if false, make debug log entry with source file
|
||||
// and line. Meant for finding situations that should be examined further, but that
|
||||
// don't indicate a problem. In all cases, execution continues normally.
|
||||
#undef check
|
||||
#define check( expr ) ((void) 0)
|
||||
|
||||
// If expr yields error string, return it from current function, otherwise continue.
|
||||
#undef RETURN_ERR
|
||||
#define RETURN_ERR( expr ) do { \
|
||||
blargg_err_t blargg_return_err_ = (expr); \
|
||||
if ( blargg_return_err_ ) return blargg_return_err_; \
|
||||
} while ( 0 )
|
||||
|
||||
// If ptr is 0, return out of memory error string.
|
||||
#undef CHECK_ALLOC
|
||||
#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
|
||||
|
||||
// Avoid any macros which evaluate their arguments multiple times
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
// using const references generates crappy code, and I am currenly only using these
|
||||
// for built-in types, so they take arguments by value
|
||||
|
||||
template<class T>
|
||||
inline T min( T x, T y )
|
||||
{
|
||||
if ( x < y )
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T max( T x, T y )
|
||||
{
|
||||
if ( x < y )
|
||||
return y;
|
||||
return x;
|
||||
}
|
||||
|
||||
// TODO: good idea? bad idea?
|
||||
#undef byte
|
||||
#define byte byte_
|
||||
typedef unsigned char byte;
|
||||
|
||||
// deprecated
|
||||
#define BLARGG_CHECK_ALLOC CHECK_ALLOC
|
||||
#define BLARGG_RETURN_ERR RETURN_ERR
|
||||
|
||||
// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check
|
||||
#ifdef BLARGG_SOURCE_BEGIN
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#endif
|
||||
|
||||
#endif
|
498
mednafen/include/blip/Blip_Buffer.h
Normal file
498
mednafen/include/blip/Blip_Buffer.h
Normal file
@ -0,0 +1,498 @@
|
||||
// Band-limited sound synthesis buffer
|
||||
// Various changes and hacks for use in Mednafen.
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define blip_inline inline __attribute__((always_inline))
|
||||
#else
|
||||
#define blip_inline inline
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Blip_Buffer 0.4.1
|
||||
#ifndef BLIP_BUFFER_H
|
||||
#define BLIP_BUFFER_H
|
||||
|
||||
// Internal
|
||||
typedef int32_t blip_long;
|
||||
typedef uint32_t blip_ulong;
|
||||
typedef int64_t blip_s64;
|
||||
typedef uint64_t blip_u64;
|
||||
|
||||
// Time unit at source clock rate
|
||||
typedef blip_long blip_time_t;
|
||||
|
||||
// Output samples are 16-bit signed, with a range of -32768 to 32767
|
||||
typedef short blip_sample_t;
|
||||
enum { blip_sample_max = 32767 };
|
||||
|
||||
class Blip_Buffer {
|
||||
public:
|
||||
typedef const char* blargg_err_t;
|
||||
|
||||
// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
|
||||
// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
|
||||
// isn't enough memory, returns error without affecting current buffer setup.
|
||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
|
||||
|
||||
// Set number of source time units per second
|
||||
void clock_rate( long );
|
||||
|
||||
// End current time frame of specified duration and make its samples available
|
||||
// (along with any still-unread samples) for reading with read_samples(). Begins
|
||||
// a new time frame at the end of the current frame.
|
||||
void end_frame( blip_time_t time );
|
||||
|
||||
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
|
||||
// the buffer. Returns number of samples actually read and removed. If stereo is
|
||||
// true, increments 'dest' one extra time after writing each sample, to allow
|
||||
// easy interleving of two channels into a stereo output buffer.
|
||||
long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
|
||||
|
||||
// Additional optional features
|
||||
|
||||
// Current output sample rate
|
||||
long sample_rate() const;
|
||||
|
||||
// Length of buffer, in milliseconds
|
||||
int length() const;
|
||||
|
||||
// Number of source time units per second
|
||||
long clock_rate() const;
|
||||
|
||||
// Set frequency high-pass filter frequency, where higher values reduce bass more
|
||||
void bass_freq( int frequency );
|
||||
|
||||
// Number of samples delay from synthesis to samples read out
|
||||
int output_latency() const;
|
||||
|
||||
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
|
||||
// false, just clears out any samples waiting rather than the entire buffer.
|
||||
void clear( int entire_buffer = 1 );
|
||||
|
||||
// Number of samples available for reading with read_samples()
|
||||
long samples_avail() const;
|
||||
|
||||
// Remove 'count' samples from those waiting to be read
|
||||
void remove_samples( long count );
|
||||
|
||||
// Experimental features
|
||||
|
||||
// Count number of clocks needed until 'count' samples will be available.
|
||||
// If buffer can't even hold 'count' samples, returns number of clocks until
|
||||
// buffer becomes full.
|
||||
blip_time_t count_clocks( long count ) const;
|
||||
|
||||
// Number of raw samples that can be mixed within frame of specified duration.
|
||||
long count_samples( blip_time_t duration ) const;
|
||||
|
||||
// Mix 'count' samples from 'buf' into buffer.
|
||||
void mix_samples( blip_sample_t const* buf, long count );
|
||||
|
||||
// not documented yet
|
||||
void set_modified() { modified_ = 1; }
|
||||
int clear_modified() { int b = modified_; modified_ = 0; return b; }
|
||||
typedef blip_u64 blip_resampled_time_t;
|
||||
void remove_silence( long count );
|
||||
blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
|
||||
blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
|
||||
blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
|
||||
public:
|
||||
Blip_Buffer();
|
||||
~Blip_Buffer();
|
||||
|
||||
// Deprecated
|
||||
typedef blip_resampled_time_t resampled_time_t;
|
||||
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
|
||||
blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
|
||||
private:
|
||||
// noncopyable
|
||||
Blip_Buffer( const Blip_Buffer& );
|
||||
Blip_Buffer& operator = ( const Blip_Buffer& );
|
||||
public:
|
||||
typedef blip_time_t buf_t_;
|
||||
blip_u64 factor_;
|
||||
blip_resampled_time_t offset_;
|
||||
buf_t_* buffer_;
|
||||
blip_long buffer_size_;
|
||||
blip_long reader_accum_;
|
||||
int bass_shift_;
|
||||
private:
|
||||
long sample_rate_;
|
||||
long clock_rate_;
|
||||
int bass_freq_;
|
||||
int length_;
|
||||
int modified_;
|
||||
friend class Blip_Reader;
|
||||
};
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define BLIP_BUFFER_ACCURACY 32
|
||||
#define BLIP_PHASE_BITS 8
|
||||
|
||||
// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
|
||||
// but reduce maximum buffer size.
|
||||
//#ifndef BLIP_BUFFER_ACCURACY
|
||||
// #define BLIP_BUFFER_ACCURACY 16
|
||||
//#endif
|
||||
|
||||
// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
|
||||
// noticeable broadband noise when synthesizing high frequency square waves.
|
||||
// Affects size of Blip_Synth objects since they store the waveform directly.
|
||||
//#ifndef BLIP_PHASE_BITS
|
||||
// #if BLIP_BUFFER_FAST
|
||||
// #define BLIP_PHASE_BITS 8
|
||||
// #else
|
||||
// #define BLIP_PHASE_BITS 6
|
||||
// #endif
|
||||
//#endif
|
||||
|
||||
// Internal
|
||||
typedef blip_u64 blip_resampled_time_t;
|
||||
int const blip_widest_impulse_ = 16;
|
||||
int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
|
||||
int const blip_res = 1 << BLIP_PHASE_BITS;
|
||||
class blip_eq_t;
|
||||
|
||||
class Blip_Synth_Fast_ {
|
||||
public:
|
||||
Blip_Buffer* buf;
|
||||
int last_amp;
|
||||
int delta_factor;
|
||||
|
||||
void volume_unit( double );
|
||||
Blip_Synth_Fast_();
|
||||
void treble_eq( blip_eq_t const& ) { }
|
||||
};
|
||||
|
||||
class Blip_Synth_ {
|
||||
public:
|
||||
Blip_Buffer* buf;
|
||||
int last_amp;
|
||||
int delta_factor;
|
||||
|
||||
void volume_unit( double );
|
||||
Blip_Synth_( short* impulses, int width );
|
||||
void treble_eq( blip_eq_t const& );
|
||||
private:
|
||||
double volume_unit_;
|
||||
short* const impulses;
|
||||
int const width;
|
||||
blip_long kernel_unit;
|
||||
int impulses_size() const { return blip_res / 2 * width + 1; }
|
||||
void adjust_impulse();
|
||||
};
|
||||
|
||||
// Quality level. Start with blip_good_quality.
|
||||
const int blip_med_quality = 8;
|
||||
const int blip_good_quality = 12;
|
||||
const int blip_high_quality = 16;
|
||||
|
||||
// Range specifies the greatest expected change in amplitude. Calculate it
|
||||
// by finding the difference between the maximum and minimum expected
|
||||
// amplitudes (max - min).
|
||||
template<int quality,int range>
|
||||
class Blip_Synth {
|
||||
public:
|
||||
// Set overall volume of waveform
|
||||
void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
|
||||
|
||||
// Configure low-pass filter (see blip_buffer.txt)
|
||||
void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
|
||||
|
||||
// Get/set Blip_Buffer used for output
|
||||
Blip_Buffer* output() const { return impl.buf; }
|
||||
void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
|
||||
|
||||
// Update amplitude of waveform at given time. Using this requires a separate
|
||||
// Blip_Synth for each waveform.
|
||||
void update( blip_time_t time, int amplitude );
|
||||
|
||||
// Low-level interface
|
||||
|
||||
// Add an amplitude transition of specified delta, optionally into specified buffer
|
||||
// rather than the one set with output(). Delta can be positive or negative.
|
||||
// The actual change in amplitude is delta * (volume / range)
|
||||
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
|
||||
void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
|
||||
|
||||
// Works directly in terms of fractional output samples. Contact author for more info.
|
||||
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
|
||||
|
||||
// Same as offset(), except code is inlined for higher performance
|
||||
void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
|
||||
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
|
||||
}
|
||||
void offset_inline( blip_time_t t, int delta ) const {
|
||||
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
|
||||
}
|
||||
|
||||
private:
|
||||
#if BLIP_BUFFER_FAST
|
||||
Blip_Synth_Fast_ impl;
|
||||
#else
|
||||
Blip_Synth_ impl;
|
||||
typedef short imp_t;
|
||||
imp_t impulses [blip_res * (quality / 2) + 1];
|
||||
public:
|
||||
Blip_Synth() : impl( impulses, quality ) { }
|
||||
#endif
|
||||
};
|
||||
|
||||
// Low-pass equalization parameters
|
||||
class blip_eq_t {
|
||||
public:
|
||||
// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
|
||||
// treble, small positive values (0 to 5.0) increase treble.
|
||||
blip_eq_t( double treble_db = 0 );
|
||||
|
||||
// See blip_buffer.txt
|
||||
blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
|
||||
|
||||
private:
|
||||
double treble;
|
||||
long rolloff_freq;
|
||||
long sample_rate;
|
||||
long cutoff_freq;
|
||||
void generate( float* out, int count ) const;
|
||||
friend class Blip_Synth_;
|
||||
};
|
||||
|
||||
int const blip_sample_bits = 30;
|
||||
|
||||
// Dummy Blip_Buffer to direct sound output to, for easy muting without
|
||||
// having to stop sound code.
|
||||
class Silent_Blip_Buffer : public Blip_Buffer {
|
||||
buf_t_ buf [blip_buffer_extra_ + 1];
|
||||
public:
|
||||
// The following cannot be used (an assertion will fail if attempted):
|
||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
|
||||
blip_time_t count_clocks( long count ) const;
|
||||
void mix_samples( blip_sample_t const* buf, long count );
|
||||
|
||||
Silent_Blip_Buffer();
|
||||
};
|
||||
|
||||
#if defined (__GNUC__) || _MSC_VER >= 1100
|
||||
#define BLIP_RESTRICT __restrict
|
||||
#else
|
||||
#define BLIP_RESTRICT
|
||||
#endif
|
||||
|
||||
// Optimized reading from Blip_Buffer, for use in custom sample output
|
||||
|
||||
// Begin reading from buffer. Name should be unique to the current block.
|
||||
#define BLIP_READER_BEGIN( name, blip_buffer ) \
|
||||
const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
|
||||
blip_long name##_reader_accum = (blip_buffer).reader_accum_
|
||||
|
||||
// Get value to pass to BLIP_READER_NEXT()
|
||||
#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
|
||||
|
||||
// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
|
||||
// code at the cost of having no bass control
|
||||
int const blip_reader_default_bass = 9;
|
||||
|
||||
// Current sample
|
||||
#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
|
||||
|
||||
// Current raw sample in full internal resolution
|
||||
#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
|
||||
|
||||
// Advance to next sample
|
||||
#define BLIP_READER_NEXT( name, bass ) \
|
||||
(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
|
||||
|
||||
// End reading samples from buffer. The number of samples read must now be removed
|
||||
// using Blip_Buffer::remove_samples().
|
||||
#define BLIP_READER_END( name, blip_buffer ) \
|
||||
(void) ((blip_buffer).reader_accum_ = name##_reader_accum)
|
||||
|
||||
|
||||
// Compatibility with older version
|
||||
const long blip_unscaled = 65535;
|
||||
const int blip_low_quality = blip_med_quality;
|
||||
const int blip_best_quality = blip_high_quality;
|
||||
|
||||
// Deprecated; use BLIP_READER macros as follows:
|
||||
// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
|
||||
// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
|
||||
// r.read() -> BLIP_READER_READ( r )
|
||||
// r.read_raw() -> BLIP_READER_READ_RAW( r )
|
||||
// r.next( bass ) -> BLIP_READER_NEXT( r, bass )
|
||||
// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )
|
||||
// r.end( buf ) -> BLIP_READER_END( r, buf )
|
||||
class Blip_Reader {
|
||||
public:
|
||||
int begin( Blip_Buffer& );
|
||||
blip_long read() const { return accum >> (blip_sample_bits - 16); }
|
||||
blip_long read_raw() const { return accum; }
|
||||
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
|
||||
void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }
|
||||
|
||||
private:
|
||||
const Blip_Buffer::buf_t_* buf;
|
||||
blip_long accum;
|
||||
};
|
||||
|
||||
// End of public interface
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
template<int quality,int range>
|
||||
blip_inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
|
||||
int delta, Blip_Buffer* blip_buf ) const
|
||||
{
|
||||
// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
|
||||
// need for a longer buffer as set by set_sample_rate().
|
||||
assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
|
||||
delta *= impl.delta_factor;
|
||||
blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
|
||||
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
|
||||
|
||||
#if BLIP_BUFFER_FAST
|
||||
blip_long left = buf [0] + delta;
|
||||
|
||||
// Kind of crappy, but doing shift after multiply results in overflow.
|
||||
// Alternate way of delaying multiply by delta_factor results in worse
|
||||
// sub-sample resolution.
|
||||
blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
|
||||
left -= right;
|
||||
right += buf [1];
|
||||
|
||||
buf [0] = left;
|
||||
buf [1] = right;
|
||||
#else
|
||||
|
||||
int const fwd = (blip_widest_impulse_ - quality) / 2;
|
||||
int const rev = fwd + quality - 2;
|
||||
int const mid = quality / 2 - 1;
|
||||
|
||||
imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
|
||||
|
||||
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
|
||||
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
|
||||
|
||||
// straight forward implementation resulted in better code on GCC for x86
|
||||
|
||||
#define ADD_IMP( out, in ) \
|
||||
buf [out] += (blip_long) imp [blip_res * (in)] * delta
|
||||
|
||||
#define BLIP_FWD( i ) {\
|
||||
ADD_IMP( fwd + i, i );\
|
||||
ADD_IMP( fwd + 1 + i, i + 1 );\
|
||||
}
|
||||
#define BLIP_REV( r ) {\
|
||||
ADD_IMP( rev - r, r + 1 );\
|
||||
ADD_IMP( rev + 1 - r, r );\
|
||||
}
|
||||
|
||||
BLIP_FWD( 0 )
|
||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
||||
{
|
||||
ADD_IMP( fwd + mid - 1, mid - 1 );
|
||||
ADD_IMP( fwd + mid , mid );
|
||||
imp = impulses + phase;
|
||||
}
|
||||
if ( quality > 12 ) BLIP_REV( 6 )
|
||||
if ( quality > 8 ) BLIP_REV( 4 )
|
||||
BLIP_REV( 2 )
|
||||
|
||||
ADD_IMP( rev , 1 );
|
||||
ADD_IMP( rev + 1, 0 );
|
||||
|
||||
#else
|
||||
|
||||
// for RISC processors, help compiler by reading ahead of writes
|
||||
|
||||
#define BLIP_FWD( i ) {\
|
||||
blip_long t0 = i0 * delta + buf [fwd + i];\
|
||||
blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
|
||||
i0 = imp [blip_res * (i + 2)];\
|
||||
buf [fwd + i] = t0;\
|
||||
buf [fwd + 1 + i] = t1;\
|
||||
}
|
||||
#define BLIP_REV( r ) {\
|
||||
blip_long t0 = i0 * delta + buf [rev - r];\
|
||||
blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
|
||||
i0 = imp [blip_res * (r - 1)];\
|
||||
buf [rev - r] = t0;\
|
||||
buf [rev + 1 - r] = t1;\
|
||||
}
|
||||
|
||||
blip_long i0 = *imp;
|
||||
BLIP_FWD( 0 )
|
||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
||||
{
|
||||
blip_long t0 = i0 * delta + buf [fwd + mid - 1];
|
||||
blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];
|
||||
imp = impulses + phase;
|
||||
i0 = imp [blip_res * mid];
|
||||
buf [fwd + mid - 1] = t0;
|
||||
buf [fwd + mid ] = t1;
|
||||
}
|
||||
if ( quality > 12 ) BLIP_REV( 6 )
|
||||
if ( quality > 8 ) BLIP_REV( 4 )
|
||||
BLIP_REV( 2 )
|
||||
|
||||
blip_long t0 = i0 * delta + buf [rev ];
|
||||
blip_long t1 = *imp * delta + buf [rev + 1];
|
||||
buf [rev ] = t0;
|
||||
buf [rev + 1] = t1;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef BLIP_FWD
|
||||
#undef BLIP_REV
|
||||
|
||||
template<int quality,int range>
|
||||
#if BLIP_BUFFER_FAST
|
||||
blip_inline
|
||||
#endif
|
||||
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
|
||||
{
|
||||
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
|
||||
}
|
||||
|
||||
template<int quality,int range>
|
||||
#if BLIP_BUFFER_FAST
|
||||
blip_inline
|
||||
#endif
|
||||
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
|
||||
{
|
||||
int delta = amp - impl.last_amp;
|
||||
impl.last_amp = amp;
|
||||
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
|
||||
}
|
||||
|
||||
blip_inline blip_eq_t::blip_eq_t( double t ) :
|
||||
treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
|
||||
blip_inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
|
||||
treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
|
||||
|
||||
blip_inline int Blip_Buffer::length() const { return length_; }
|
||||
blip_inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
|
||||
blip_inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
|
||||
blip_inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
|
||||
blip_inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
|
||||
blip_inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
|
||||
|
||||
blip_inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
|
||||
{
|
||||
buf = blip_buf.buffer_;
|
||||
accum = blip_buf.reader_accum_;
|
||||
return blip_buf.bass_shift_;
|
||||
}
|
||||
|
||||
int const blip_max_length = 0;
|
||||
int const blip_default_length = 250;
|
||||
|
||||
#endif
|
71
mednafen/include/blip/Stereo_Buffer.h
Normal file
71
mednafen/include/blip/Stereo_Buffer.h
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
// Simple stereo Blip_Buffer for sound emulators whose oscillators output
|
||||
// either on the left only, center, or right only.
|
||||
|
||||
// Blip_Buffer 0.3.0. Copyright (C) 2003-2004 Shay Green. GNU GPL license.
|
||||
|
||||
#ifndef STEREO_BUFFER_H
|
||||
#define STEREO_BUFFER_H
|
||||
|
||||
#include "Blip_Buffer.h"
|
||||
|
||||
class Stereo_Buffer {
|
||||
public:
|
||||
Stereo_Buffer();
|
||||
~Stereo_Buffer();
|
||||
|
||||
// Same as in Blip_Buffer (see Blip_Buffer.h)
|
||||
bool set_sample_rate( long, int msec = 0 );
|
||||
void clock_rate( long );
|
||||
void bass_freq( int );
|
||||
void clear();
|
||||
|
||||
// Buffers to output synthesis to
|
||||
Blip_Buffer* left();
|
||||
Blip_Buffer* center();
|
||||
Blip_Buffer* right();
|
||||
|
||||
// Same as in Blip_Buffer. For more efficient operation, pass false
|
||||
// for was_stereo if the left and right buffers had nothing added
|
||||
// to them for this frame.
|
||||
void end_frame( blip_time_t, bool was_stereo = true );
|
||||
|
||||
// Output is stereo with channels interleved, left before right. Counts
|
||||
// are in samples, *not* pairs.
|
||||
long samples_avail() const;
|
||||
long read_samples( blip_sample_t*, long );
|
||||
|
||||
private:
|
||||
// noncopyable
|
||||
Stereo_Buffer( const Stereo_Buffer& );
|
||||
Stereo_Buffer& operator = ( const Stereo_Buffer& );
|
||||
|
||||
enum { buf_count = 3 };
|
||||
Blip_Buffer bufs [buf_count];
|
||||
bool stereo_added;
|
||||
bool was_stereo;
|
||||
|
||||
void mix_stereo( blip_sample_t*, long );
|
||||
void mix_mono( blip_sample_t*, long );
|
||||
void mix_stereo( float*, long );
|
||||
void mix_mono( float*, long );
|
||||
};
|
||||
|
||||
inline Blip_Buffer* Stereo_Buffer::left() {
|
||||
return &bufs [1];
|
||||
}
|
||||
|
||||
inline Blip_Buffer* Stereo_Buffer::center() {
|
||||
return &bufs [0];
|
||||
}
|
||||
|
||||
inline Blip_Buffer* Stereo_Buffer::right() {
|
||||
return &bufs [2];
|
||||
}
|
||||
|
||||
inline long Stereo_Buffer::samples_avail() const {
|
||||
return bufs [0].samples_avail();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
676
mednafen/include/config.h.in
Normal file
676
mednafen/include/config.h.in
Normal file
@ -0,0 +1,676 @@
|
||||
/* include/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define if we are compiling for PPC architectures. */
|
||||
#undef ARCH_POWERPC
|
||||
|
||||
/* Define if we are compiling with AltiVec usage. */
|
||||
#undef ARCH_POWERPC_ALTIVEC
|
||||
|
||||
/* Define if we are compiling for 32-bit or 64-bit x86 architectures. */
|
||||
#undef ARCH_X86
|
||||
|
||||
/* Define if we are compiling for 32-bit x86 architectures. */
|
||||
#undef ARCH_X86_32
|
||||
|
||||
/* Define if we are compiling for 64-bit x86 architectures. */
|
||||
#undef ARCH_X86_64
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define if we are compiling with ALSA support. */
|
||||
#undef HAVE_ALSA
|
||||
|
||||
/* Define if altivec.h is present and usable. */
|
||||
#undef HAVE_ALTIVEC_H
|
||||
|
||||
/* Define if we should include from OpenGL instead of GL */
|
||||
#undef HAVE_APPLE_OPENGL_FRAMEWORK
|
||||
|
||||
/* Define to 1 if you have the `argz_count' function. */
|
||||
#undef HAVE_ARGZ_COUNT
|
||||
|
||||
/* Define to 1 if you have the <argz.h> header file. */
|
||||
#undef HAVE_ARGZ_H
|
||||
|
||||
/* Define to 1 if you have the `argz_next' function. */
|
||||
#undef HAVE_ARGZ_NEXT
|
||||
|
||||
/* Define to 1 if you have the `argz_stringify' function. */
|
||||
#undef HAVE_ARGZ_STRINGIFY
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* Define to 1 if the compiler understands __builtin_expect. */
|
||||
#undef HAVE_BUILTIN_EXPECT
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
|
||||
CoreFoundation framework. */
|
||||
#undef HAVE_CFLOCALECOPYCURRENT
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
|
||||
the CoreFoundation framework. */
|
||||
#undef HAVE_CFPREFERENCESCOPYAPPVALUE
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
|
||||
/* Define if the GNU dcgettext() function is already present or preinstalled.
|
||||
*/
|
||||
#undef HAVE_DCGETTEXT
|
||||
|
||||
/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_FEOF_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
|
||||
you don't. */
|
||||
#undef HAVE_DECL_FGETS_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_GETC_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL__SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL__SNWPRINTF
|
||||
|
||||
/* Define if we are compiling with DirectSound support. */
|
||||
#undef HAVE_DIRECTSOUND
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `fcntl' function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `fopen64' function. */
|
||||
#undef HAVE_FOPEN64
|
||||
|
||||
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
|
||||
#undef HAVE_FSEEKO
|
||||
|
||||
/* Define to 1 if you have the `fseeko64' function. */
|
||||
#undef HAVE_FSEEKO64
|
||||
|
||||
/* Define to 1 if you have the `fstat64' function. */
|
||||
#undef HAVE_FSTAT64
|
||||
|
||||
/* Define to 1 if you have the `ftello' function. */
|
||||
#undef HAVE_FTELLO
|
||||
|
||||
/* Define to 1 if you have the `ftello64' function. */
|
||||
#undef HAVE_FTELLO64
|
||||
|
||||
/* Define to 1 if you have the `fwprintf' function. */
|
||||
#undef HAVE_FWPRINTF
|
||||
|
||||
/* Define to 1 if you have the `getcwd' function. */
|
||||
#undef HAVE_GETCWD
|
||||
|
||||
/* Define to 1 if you have the `getegid' function. */
|
||||
#undef HAVE_GETEGID
|
||||
|
||||
/* Define to 1 if you have the `getenv' function. */
|
||||
#undef HAVE_GETENV
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#undef HAVE_GETEUID
|
||||
|
||||
/* Define to 1 if you have the `getgid' function. */
|
||||
#undef HAVE_GETGID
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
/* Define to 1 if you have the `getpwuid' function. */
|
||||
#undef HAVE_GETPWUID
|
||||
|
||||
/* Define if the GNU gettext() function is already present or preinstalled. */
|
||||
#undef HAVE_GETTEXT
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the `getuid' function. */
|
||||
#undef HAVE_GETUID
|
||||
|
||||
/* Define if you have the iconv() function and it works. */
|
||||
#undef HAVE_ICONV
|
||||
|
||||
/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#undef HAVE_INTMAX_T
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
|
||||
declares uintmax_t. */
|
||||
#undef HAVE_INTTYPES_H_WITH_UINTMAX
|
||||
|
||||
/* Define if we are compiling with JACK support. */
|
||||
#undef HAVE_JACK
|
||||
|
||||
/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
|
||||
#undef HAVE_LANGINFO_CODESET
|
||||
|
||||
/* Define if your <locale.h> file defines LC_MESSAGES. */
|
||||
#undef HAVE_LC_MESSAGES
|
||||
|
||||
/* Define to 1 if you have the `asound' library (-lasound). */
|
||||
#undef HAVE_LIBASOUND
|
||||
|
||||
/* Define if we are compiling with libcdio support. */
|
||||
#undef HAVE_LIBCDIO
|
||||
|
||||
/* Define if we are compiling with libsndfile support. */
|
||||
#undef HAVE_LIBSNDFILE
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#undef HAVE_LIBZ
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if the system has the type `long long int'. */
|
||||
#undef HAVE_LONG_LONG_INT
|
||||
|
||||
/* Define to 1 if you have the `madvise' function. */
|
||||
#undef HAVE_MADVISE
|
||||
|
||||
/* Define to 1 if you have the `mbrtowc' function. */
|
||||
#undef HAVE_MBRTOWC
|
||||
|
||||
/* Define to 1 if you have the `memcmp' function. */
|
||||
#undef HAVE_MEMCMP
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#undef HAVE_MEMCPY
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
#undef HAVE_MEMPCPY
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the `mkdir' function. */
|
||||
#undef HAVE_MKDIR
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#undef HAVE_MMAP
|
||||
|
||||
/* Define to 1 if you have the `munmap' function. */
|
||||
#undef HAVE_MUNMAP
|
||||
|
||||
/* Define to 1 if you have the `newlocale' function. */
|
||||
#undef HAVE_NEWLOCALE
|
||||
|
||||
/* Define if we are compiling with OSS support. */
|
||||
#undef HAVE_OSSDSP
|
||||
|
||||
/* Define if your printf() function supports format strings with positions. */
|
||||
#undef HAVE_POSIX_PRINTF
|
||||
|
||||
/* Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE. */
|
||||
#undef HAVE_PTHREAD_MUTEX_RECURSIVE
|
||||
|
||||
/* Define if the POSIX multithreading library has read/write locks. */
|
||||
#undef HAVE_PTHREAD_RWLOCK
|
||||
|
||||
/* Define to 1 if you have the `putenv' function. */
|
||||
#undef HAVE_PUTENV
|
||||
|
||||
/* Define if we are compiling with SDL sound support. */
|
||||
#undef HAVE_SDL
|
||||
|
||||
/* Define if we are compiling with SDL_net support. */
|
||||
#undef HAVE_SDL_NET
|
||||
|
||||
/* Define to 1 if you have the `setenv' function. */
|
||||
#undef HAVE_SETENV
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define to 1 if you have the `signal' function. */
|
||||
#undef HAVE_SIGNAL
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
|
||||
uintmax_t. */
|
||||
#undef HAVE_STDINT_H_WITH_UINTMAX
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `stpcpy' function. */
|
||||
#undef HAVE_STPCPY
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the `strerror_r' function. */
|
||||
#undef HAVE_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strnlen' function. */
|
||||
#undef HAVE_STRNLEN
|
||||
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#undef HAVE_STRTOUL
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the `tsearch' function. */
|
||||
#undef HAVE_TSEARCH
|
||||
|
||||
/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#undef HAVE_UINTMAX_T
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if the system has the type `unsigned long long int'. */
|
||||
#undef HAVE_UNSIGNED_LONG_LONG_INT
|
||||
|
||||
/* Define to 1 if you have the `uselocale' function. */
|
||||
#undef HAVE_USELOCALE
|
||||
|
||||
/* Define to 1 if you have the `usleep' function. */
|
||||
#undef HAVE_USLEEP
|
||||
|
||||
/* Define to 1 or 0, depending whether the compiler supports simple visibility
|
||||
declarations. */
|
||||
#undef HAVE_VISIBILITY
|
||||
|
||||
/* Define if you have the 'wchar_t' type. */
|
||||
#undef HAVE_WCHAR_T
|
||||
|
||||
/* Define to 1 if you have the `wcrtomb' function. */
|
||||
#undef HAVE_WCRTOMB
|
||||
|
||||
/* Define to 1 if you have the `wcslen' function. */
|
||||
#undef HAVE_WCSLEN
|
||||
|
||||
/* Define to 1 if you have the `wcsnlen' function. */
|
||||
#undef HAVE_WCSNLEN
|
||||
|
||||
/* Define if you have the 'wint_t' type. */
|
||||
#undef HAVE_WINT_T
|
||||
|
||||
/* Define to 1 if O_NOATIME works. */
|
||||
#undef HAVE_WORKING_O_NOATIME
|
||||
|
||||
/* Define to 1 if O_NOFOLLOW works. */
|
||||
#undef HAVE_WORKING_O_NOFOLLOW
|
||||
|
||||
/* Define to 1 if you have the `_mkdir' function. */
|
||||
#undef HAVE__MKDIR
|
||||
|
||||
/* Define to 1 if you have the `__fsetlocking' function. */
|
||||
#undef HAVE___FSETLOCKING
|
||||
|
||||
/* Define as const if the declaration of iconv() needs const. */
|
||||
#undef ICONV_CONST
|
||||
|
||||
/* Define if integer division by zero raises signal SIGFPE. */
|
||||
#undef INTDIV0_RAISES_SIGFPE
|
||||
|
||||
/* Define on little-endian platforms. */
|
||||
#undef LSB_FIRST
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Mednafen version definition. */
|
||||
#undef MEDNAFEN_VERSION
|
||||
|
||||
/* Mednafen version numeric. */
|
||||
#undef MEDNAFEN_VERSION_NUMERIC
|
||||
|
||||
/* Define if config.h is present */
|
||||
#undef MINILZO_HAVE_CONFIG_H
|
||||
|
||||
/* Define if mkdir takes only one argument. */
|
||||
#undef MKDIR_TAKES_ONE_ARG
|
||||
|
||||
/* Define to use fixed-point MPC decoder. */
|
||||
#undef MPC_FIXED_POINT
|
||||
|
||||
/* Define on big-endian platforms. */
|
||||
#undef MSB_FIRST
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#undef NO_MINUS_C_MINUS_O
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define if <inttypes.h> exists and defines unusable PRI* macros. */
|
||||
#undef PRI_MACROS_BROKEN
|
||||
|
||||
/* Defines the filesystem path-separator type. */
|
||||
#undef PSS_STYLE
|
||||
|
||||
/* Define if the pthread_in_use() detection is hard. */
|
||||
#undef PTHREAD_IN_USE_DETECTION_HARD
|
||||
|
||||
/* The size of `double', as computed by sizeof. */
|
||||
#undef SIZEOF_DOUBLE
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#undef SIZEOF_INT
|
||||
|
||||
/* The size of `long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
/* The size of `long long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG_LONG
|
||||
|
||||
/* The size of `off_t', as computed by sizeof. */
|
||||
#undef SIZEOF_OFF_T
|
||||
|
||||
/* The size of `ptrdiff_t', as computed by sizeof. */
|
||||
#undef SIZEOF_PTRDIFF_T
|
||||
|
||||
/* The size of `short', as computed by sizeof. */
|
||||
#undef SIZEOF_SHORT
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#undef SIZEOF_SIZE_T
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#undef SIZEOF_VOID_P
|
||||
|
||||
/* The size of `__int64', as computed by sizeof. */
|
||||
#undef SIZEOF___INT64
|
||||
|
||||
/* Define as the maximum value of type 'size_t', if the system doesn't define
|
||||
it. */
|
||||
#ifndef SIZE_MAX
|
||||
# undef SIZE_MAX
|
||||
#endif
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define if the POSIX multithreading library can be used. */
|
||||
#undef USE_POSIX_THREADS
|
||||
|
||||
/* Define if references to the POSIX multithreading library should be made
|
||||
weak. */
|
||||
#undef USE_POSIX_THREADS_WEAK
|
||||
|
||||
/* Define if the GNU Pth multithreading library can be used. */
|
||||
#undef USE_PTH_THREADS
|
||||
|
||||
/* Define if references to the GNU Pth multithreading library should be made
|
||||
weak. */
|
||||
#undef USE_PTH_THREADS_WEAK
|
||||
|
||||
/* Define if the old Solaris multithreading library can be used. */
|
||||
#undef USE_SOLARIS_THREADS
|
||||
|
||||
/* Define if references to the old Solaris multithreading library should be
|
||||
made weak. */
|
||||
#undef USE_SOLARIS_THREADS_WEAK
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Define if the Win32 multithreading API can be used. */
|
||||
#undef USE_WIN32_THREADS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define if we are compiling with debugger. */
|
||||
#undef WANT_DEBUGGER
|
||||
|
||||
/* Define if we are compiling with GBA emulation. */
|
||||
#undef WANT_GBA_EMU
|
||||
|
||||
/* Define if we are compiling with GB emulation. */
|
||||
#undef WANT_GB_EMU
|
||||
|
||||
/* Define if we are compiling with internal CJK fonts. */
|
||||
#undef WANT_INTERNAL_CJK
|
||||
|
||||
/* Define if we are compiling with Lynx emulation. */
|
||||
#undef WANT_LYNX_EMU
|
||||
|
||||
/* Define if we are compiling with Sega Genesis/MegaDrive emulation. */
|
||||
#undef WANT_MD_EMU
|
||||
|
||||
/* Define if we are compiling with NES emulation. */
|
||||
#undef WANT_NES_EMU
|
||||
|
||||
/* Define if we are compiling with NGP emulation. */
|
||||
#undef WANT_NGP_EMU
|
||||
|
||||
/* Define if we are compiling with PCE emulation. */
|
||||
#undef WANT_PCE_EMU
|
||||
|
||||
/* Define if we are compiling with separate fast PCE emulation. */
|
||||
#undef WANT_PCE_FAST_EMU
|
||||
|
||||
/* Define if we are compiling with PC-FX emulation. */
|
||||
#undef WANT_PCFX_EMU
|
||||
|
||||
/* Define if we are compiling with PlayStation emulation. */
|
||||
#undef WANT_PSX_EMU
|
||||
|
||||
/* Define if we are compiling with SMS+GG emulation. */
|
||||
#undef WANT_SMS_EMU
|
||||
|
||||
/* Define if we are compiling with SNES emulation. */
|
||||
#undef WANT_SNES_EMU
|
||||
|
||||
/* Define if we are compiling with Virtual Boy emulation. */
|
||||
#undef WANT_VB_EMU
|
||||
|
||||
/* Define if we are compiling with WonderSwan emulation. */
|
||||
#undef WANT_WSWAN_EMU
|
||||
|
||||
/* Define if we are compiling for Win32. */
|
||||
#undef WIN32
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
|
||||
#undef _LARGEFILE_SOURCE
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define as the type of the result of subtracting two pointers, if the system
|
||||
doesn't define it. */
|
||||
#undef ptrdiff_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to unsigned long or unsigned long long if <stdint.h> and
|
||||
<inttypes.h> don't define. */
|
||||
#undef uintmax_t
|
||||
|
||||
|
||||
#define __libc_lock_t gl_lock_t
|
||||
#define __libc_lock_define gl_lock_define
|
||||
#define __libc_lock_define_initialized gl_lock_define_initialized
|
||||
#define __libc_lock_init gl_lock_init
|
||||
#define __libc_lock_lock gl_lock_lock
|
||||
#define __libc_lock_unlock gl_lock_unlock
|
||||
#define __libc_lock_recursive_t gl_recursive_lock_t
|
||||
#define __libc_lock_define_recursive gl_recursive_lock_define
|
||||
#define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized
|
||||
#define __libc_lock_init_recursive gl_recursive_lock_init
|
||||
#define __libc_lock_lock_recursive gl_recursive_lock_lock
|
||||
#define __libc_lock_unlock_recursive gl_recursive_lock_unlock
|
||||
#define glthread_in_use libintl_thread_in_use
|
||||
#define glthread_lock_init_func libintl_lock_init_func
|
||||
#define glthread_lock_lock_func libintl_lock_lock_func
|
||||
#define glthread_lock_unlock_func libintl_lock_unlock_func
|
||||
#define glthread_lock_destroy_func libintl_lock_destroy_func
|
||||
#define glthread_rwlock_init_multithreaded libintl_rwlock_init_multithreaded
|
||||
#define glthread_rwlock_init_func libintl_rwlock_init_func
|
||||
#define glthread_rwlock_rdlock_multithreaded libintl_rwlock_rdlock_multithreaded
|
||||
#define glthread_rwlock_rdlock_func libintl_rwlock_rdlock_func
|
||||
#define glthread_rwlock_wrlock_multithreaded libintl_rwlock_wrlock_multithreaded
|
||||
#define glthread_rwlock_wrlock_func libintl_rwlock_wrlock_func
|
||||
#define glthread_rwlock_unlock_multithreaded libintl_rwlock_unlock_multithreaded
|
||||
#define glthread_rwlock_unlock_func libintl_rwlock_unlock_func
|
||||
#define glthread_rwlock_destroy_multithreaded libintl_rwlock_destroy_multithreaded
|
||||
#define glthread_rwlock_destroy_func libintl_rwlock_destroy_func
|
||||
#define glthread_recursive_lock_init_multithreaded libintl_recursive_lock_init_multithreaded
|
||||
#define glthread_recursive_lock_init_func libintl_recursive_lock_init_func
|
||||
#define glthread_recursive_lock_lock_multithreaded libintl_recursive_lock_lock_multithreaded
|
||||
#define glthread_recursive_lock_lock_func libintl_recursive_lock_lock_func
|
||||
#define glthread_recursive_lock_unlock_multithreaded libintl_recursive_lock_unlock_multithreaded
|
||||
#define glthread_recursive_lock_unlock_func libintl_recursive_lock_unlock_func
|
||||
#define glthread_recursive_lock_destroy_multithreaded libintl_recursive_lock_destroy_multithreaded
|
||||
#define glthread_recursive_lock_destroy_func libintl_recursive_lock_destroy_func
|
||||
#define glthread_once_func libintl_once_func
|
||||
#define glthread_once_singlethreaded libintl_once_singlethreaded
|
||||
#define glthread_once_multithreaded libintl_once_multithreaded
|
||||
|
679
mednafen/include/config.h.in~
Normal file
679
mednafen/include/config.h.in~
Normal file
@ -0,0 +1,679 @@
|
||||
/* include/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define if we are compiling for PPC architectures. */
|
||||
#undef ARCH_POWERPC
|
||||
|
||||
/* Define if we are compiling with AltiVec usage. */
|
||||
#undef ARCH_POWERPC_ALTIVEC
|
||||
|
||||
/* Define if we are compiling for 32-bit or 64-bit x86 architectures. */
|
||||
#undef ARCH_X86
|
||||
|
||||
/* Define if we are compiling for 32-bit x86 architectures. */
|
||||
#undef ARCH_X86_32
|
||||
|
||||
/* Define if we are compiling for 64-bit x86 architectures. */
|
||||
#undef ARCH_X86_64
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define if we are compiling with ALSA support. */
|
||||
#undef HAVE_ALSA
|
||||
|
||||
/* Define if altivec.h is present and usable. */
|
||||
#undef HAVE_ALTIVEC_H
|
||||
|
||||
/* Define if we should include from OpenGL instead of GL */
|
||||
#undef HAVE_APPLE_OPENGL_FRAMEWORK
|
||||
|
||||
/* Define to 1 if you have the `argz_count' function. */
|
||||
#undef HAVE_ARGZ_COUNT
|
||||
|
||||
/* Define to 1 if you have the <argz.h> header file. */
|
||||
#undef HAVE_ARGZ_H
|
||||
|
||||
/* Define to 1 if you have the `argz_next' function. */
|
||||
#undef HAVE_ARGZ_NEXT
|
||||
|
||||
/* Define to 1 if you have the `argz_stringify' function. */
|
||||
#undef HAVE_ARGZ_STRINGIFY
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* Define to 1 if the compiler understands __builtin_expect. */
|
||||
#undef HAVE_BUILTIN_EXPECT
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
|
||||
CoreFoundation framework. */
|
||||
#undef HAVE_CFLOCALECOPYCURRENT
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
|
||||
the CoreFoundation framework. */
|
||||
#undef HAVE_CFPREFERENCESCOPYAPPVALUE
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
|
||||
/* Define if the GNU dcgettext() function is already present or preinstalled.
|
||||
*/
|
||||
#undef HAVE_DCGETTEXT
|
||||
|
||||
/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_FEOF_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
|
||||
you don't. */
|
||||
#undef HAVE_DECL_FGETS_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_GETC_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL__SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL__SNWPRINTF
|
||||
|
||||
/* Define if we are compiling with DirectSound support. */
|
||||
#undef HAVE_DIRECTSOUND
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `fcntl' function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `fopen64' function. */
|
||||
#undef HAVE_FOPEN64
|
||||
|
||||
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
|
||||
#undef HAVE_FSEEKO
|
||||
|
||||
/* Define to 1 if you have the `fseeko64' function. */
|
||||
#undef HAVE_FSEEKO64
|
||||
|
||||
/* Define to 1 if you have the `fstat64' function. */
|
||||
#undef HAVE_FSTAT64
|
||||
|
||||
/* Define to 1 if you have the `ftello' function. */
|
||||
#undef HAVE_FTELLO
|
||||
|
||||
/* Define to 1 if you have the `ftello64' function. */
|
||||
#undef HAVE_FTELLO64
|
||||
|
||||
/* Define to 1 if you have the `fwprintf' function. */
|
||||
#undef HAVE_FWPRINTF
|
||||
|
||||
/* Define to 1 if you have the `getcwd' function. */
|
||||
#undef HAVE_GETCWD
|
||||
|
||||
/* Define to 1 if you have the `getegid' function. */
|
||||
#undef HAVE_GETEGID
|
||||
|
||||
/* Define to 1 if you have the `getenv' function. */
|
||||
#undef HAVE_GETENV
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#undef HAVE_GETEUID
|
||||
|
||||
/* Define to 1 if you have the `getgid' function. */
|
||||
#undef HAVE_GETGID
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
/* Define to 1 if you have the `getpwuid' function. */
|
||||
#undef HAVE_GETPWUID
|
||||
|
||||
/* Define if the GNU gettext() function is already present or preinstalled. */
|
||||
#undef HAVE_GETTEXT
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the `getuid' function. */
|
||||
#undef HAVE_GETUID
|
||||
|
||||
/* Define if you have the iconv() function and it works. */
|
||||
#undef HAVE_ICONV
|
||||
|
||||
/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#undef HAVE_INTMAX_T
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
|
||||
declares uintmax_t. */
|
||||
#undef HAVE_INTTYPES_H_WITH_UINTMAX
|
||||
|
||||
/* Define if we are compiling with JACK support. */
|
||||
#undef HAVE_JACK
|
||||
|
||||
/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
|
||||
#undef HAVE_LANGINFO_CODESET
|
||||
|
||||
/* Define if your <locale.h> file defines LC_MESSAGES. */
|
||||
#undef HAVE_LC_MESSAGES
|
||||
|
||||
/* Define to 1 if you have the `asound' library (-lasound). */
|
||||
#undef HAVE_LIBASOUND
|
||||
|
||||
/* Define if we are compiling with libcdio support. */
|
||||
#undef HAVE_LIBCDIO
|
||||
|
||||
/* Define if we are compiling with libsndfile support. */
|
||||
#undef HAVE_LIBSNDFILE
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#undef HAVE_LIBZ
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if the system has the type `long long int'. */
|
||||
#undef HAVE_LONG_LONG_INT
|
||||
|
||||
/* Define to 1 if you have the `madvise' function. */
|
||||
#undef HAVE_MADVISE
|
||||
|
||||
/* Define to 1 if you have the `mbrtowc' function. */
|
||||
#undef HAVE_MBRTOWC
|
||||
|
||||
/* Define to 1 if you have the `memcmp' function. */
|
||||
#undef HAVE_MEMCMP
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#undef HAVE_MEMCPY
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
#undef HAVE_MEMPCPY
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the `mkdir' function. */
|
||||
#undef HAVE_MKDIR
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#undef HAVE_MMAP
|
||||
|
||||
/* Define to 1 if you have the `munmap' function. */
|
||||
#undef HAVE_MUNMAP
|
||||
|
||||
/* Define to 1 if you have the `newlocale' function. */
|
||||
#undef HAVE_NEWLOCALE
|
||||
|
||||
/* Define if we are compiling with OSS support. */
|
||||
#undef HAVE_OSSDSP
|
||||
|
||||
/* Define if your printf() function supports format strings with positions. */
|
||||
#undef HAVE_POSIX_PRINTF
|
||||
|
||||
/* Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE. */
|
||||
#undef HAVE_PTHREAD_MUTEX_RECURSIVE
|
||||
|
||||
/* Define if the POSIX multithreading library has read/write locks. */
|
||||
#undef HAVE_PTHREAD_RWLOCK
|
||||
|
||||
/* Define to 1 if you have the `putenv' function. */
|
||||
#undef HAVE_PUTENV
|
||||
|
||||
/* Define if we are compiling with SDL sound support. */
|
||||
#undef HAVE_SDL
|
||||
|
||||
/* Define if we are compiling with SDL_net support. */
|
||||
#undef HAVE_SDL_NET
|
||||
|
||||
/* Define to 1 if you have the `setenv' function. */
|
||||
#undef HAVE_SETENV
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define to 1 if you have the `signal' function. */
|
||||
#undef HAVE_SIGNAL
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
|
||||
uintmax_t. */
|
||||
#undef HAVE_STDINT_H_WITH_UINTMAX
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `stpcpy' function. */
|
||||
#undef HAVE_STPCPY
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the `strerror_r' function. */
|
||||
#undef HAVE_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strnlen' function. */
|
||||
#undef HAVE_STRNLEN
|
||||
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#undef HAVE_STRTOUL
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the `tsearch' function. */
|
||||
#undef HAVE_TSEARCH
|
||||
|
||||
/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#undef HAVE_UINTMAX_T
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if the system has the type `unsigned long long int'. */
|
||||
#undef HAVE_UNSIGNED_LONG_LONG_INT
|
||||
|
||||
/* Define to 1 if you have the `uselocale' function. */
|
||||
#undef HAVE_USELOCALE
|
||||
|
||||
/* Define to 1 if you have the `usleep' function. */
|
||||
#undef HAVE_USLEEP
|
||||
|
||||
/* Define to 1 or 0, depending whether the compiler supports simple visibility
|
||||
declarations. */
|
||||
#undef HAVE_VISIBILITY
|
||||
|
||||
/* Define if you have the 'wchar_t' type. */
|
||||
#undef HAVE_WCHAR_T
|
||||
|
||||
/* Define to 1 if you have the `wcrtomb' function. */
|
||||
#undef HAVE_WCRTOMB
|
||||
|
||||
/* Define to 1 if you have the `wcslen' function. */
|
||||
#undef HAVE_WCSLEN
|
||||
|
||||
/* Define to 1 if you have the `wcsnlen' function. */
|
||||
#undef HAVE_WCSNLEN
|
||||
|
||||
/* Define if you have the 'wint_t' type. */
|
||||
#undef HAVE_WINT_T
|
||||
|
||||
/* Define to 1 if O_NOATIME works. */
|
||||
#undef HAVE_WORKING_O_NOATIME
|
||||
|
||||
/* Define to 1 if O_NOFOLLOW works. */
|
||||
#undef HAVE_WORKING_O_NOFOLLOW
|
||||
|
||||
/* Define to 1 if you have the `_mkdir' function. */
|
||||
#undef HAVE__MKDIR
|
||||
|
||||
/* Define to 1 if you have the `__fsetlocking' function. */
|
||||
#undef HAVE___FSETLOCKING
|
||||
|
||||
/* Define as const if the declaration of iconv() needs const. */
|
||||
#undef ICONV_CONST
|
||||
|
||||
/* Define if integer division by zero raises signal SIGFPE. */
|
||||
#undef INTDIV0_RAISES_SIGFPE
|
||||
|
||||
/* Define on little-endian platforms. */
|
||||
#undef LSB_FIRST
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Mednafen version definition. */
|
||||
#undef MEDNAFEN_VERSION
|
||||
|
||||
/* Mednafen version numeric. */
|
||||
#undef MEDNAFEN_VERSION_NUMERIC
|
||||
|
||||
/* Define if config.h is present */
|
||||
#undef MINILZO_HAVE_CONFIG_H
|
||||
|
||||
/* Define if mkdir takes only one argument. */
|
||||
#undef MKDIR_TAKES_ONE_ARG
|
||||
|
||||
/* Define to use fixed-point MPC decoder. */
|
||||
#undef MPC_FIXED_POINT
|
||||
|
||||
/* Define on little-endian platforms. */
|
||||
#undef MPC_LITTLE_ENDIAN
|
||||
|
||||
/* Define on big-endian platforms. */
|
||||
#undef MSB_FIRST
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#undef NO_MINUS_C_MINUS_O
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define if <inttypes.h> exists and defines unusable PRI* macros. */
|
||||
#undef PRI_MACROS_BROKEN
|
||||
|
||||
/* Defines the filesystem path-separator type. */
|
||||
#undef PSS_STYLE
|
||||
|
||||
/* Define if the pthread_in_use() detection is hard. */
|
||||
#undef PTHREAD_IN_USE_DETECTION_HARD
|
||||
|
||||
/* The size of `double', as computed by sizeof. */
|
||||
#undef SIZEOF_DOUBLE
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#undef SIZEOF_INT
|
||||
|
||||
/* The size of `long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
/* The size of `long long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG_LONG
|
||||
|
||||
/* The size of `off_t', as computed by sizeof. */
|
||||
#undef SIZEOF_OFF_T
|
||||
|
||||
/* The size of `ptrdiff_t', as computed by sizeof. */
|
||||
#undef SIZEOF_PTRDIFF_T
|
||||
|
||||
/* The size of `short', as computed by sizeof. */
|
||||
#undef SIZEOF_SHORT
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#undef SIZEOF_SIZE_T
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#undef SIZEOF_VOID_P
|
||||
|
||||
/* The size of `__int64', as computed by sizeof. */
|
||||
#undef SIZEOF___INT64
|
||||
|
||||
/* Define as the maximum value of type 'size_t', if the system doesn't define
|
||||
it. */
|
||||
#ifndef SIZE_MAX
|
||||
# undef SIZE_MAX
|
||||
#endif
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define if the POSIX multithreading library can be used. */
|
||||
#undef USE_POSIX_THREADS
|
||||
|
||||
/* Define if references to the POSIX multithreading library should be made
|
||||
weak. */
|
||||
#undef USE_POSIX_THREADS_WEAK
|
||||
|
||||
/* Define if the GNU Pth multithreading library can be used. */
|
||||
#undef USE_PTH_THREADS
|
||||
|
||||
/* Define if references to the GNU Pth multithreading library should be made
|
||||
weak. */
|
||||
#undef USE_PTH_THREADS_WEAK
|
||||
|
||||
/* Define if the old Solaris multithreading library can be used. */
|
||||
#undef USE_SOLARIS_THREADS
|
||||
|
||||
/* Define if references to the old Solaris multithreading library should be
|
||||
made weak. */
|
||||
#undef USE_SOLARIS_THREADS_WEAK
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Define if the Win32 multithreading API can be used. */
|
||||
#undef USE_WIN32_THREADS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define if we are compiling with debugger. */
|
||||
#undef WANT_DEBUGGER
|
||||
|
||||
/* Define if we are compiling with GBA emulation. */
|
||||
#undef WANT_GBA_EMU
|
||||
|
||||
/* Define if we are compiling with GB emulation. */
|
||||
#undef WANT_GB_EMU
|
||||
|
||||
/* Define if we are compiling with internal CJK fonts. */
|
||||
#undef WANT_INTERNAL_CJK
|
||||
|
||||
/* Define if we are compiling with Lynx emulation. */
|
||||
#undef WANT_LYNX_EMU
|
||||
|
||||
/* Define if we are compiling with Sega Genesis/MegaDrive emulation. */
|
||||
#undef WANT_MD_EMU
|
||||
|
||||
/* Define if we are compiling with NES emulation. */
|
||||
#undef WANT_NES_EMU
|
||||
|
||||
/* Define if we are compiling with NGP emulation. */
|
||||
#undef WANT_NGP_EMU
|
||||
|
||||
/* Define if we are compiling with PCE emulation. */
|
||||
#undef WANT_PCE_EMU
|
||||
|
||||
/* Define if we are compiling with separate fast PCE emulation. */
|
||||
#undef WANT_PCE_FAST_EMU
|
||||
|
||||
/* Define if we are compiling with PC-FX emulation. */
|
||||
#undef WANT_PCFX_EMU
|
||||
|
||||
/* Define if we are compiling with PlayStation emulation. */
|
||||
#undef WANT_PSX_EMU
|
||||
|
||||
/* Define if we are compiling with SMS+GG emulation. */
|
||||
#undef WANT_SMS_EMU
|
||||
|
||||
/* Define if we are compiling with SNES emulation. */
|
||||
#undef WANT_SNES_EMU
|
||||
|
||||
/* Define if we are compiling with Virtual Boy emulation. */
|
||||
#undef WANT_VB_EMU
|
||||
|
||||
/* Define if we are compiling with WonderSwan emulation. */
|
||||
#undef WANT_WSWAN_EMU
|
||||
|
||||
/* Define if we are compiling for Win32. */
|
||||
#undef WIN32
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
|
||||
#undef _LARGEFILE_SOURCE
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define as the type of the result of subtracting two pointers, if the system
|
||||
doesn't define it. */
|
||||
#undef ptrdiff_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to unsigned long or unsigned long long if <stdint.h> and
|
||||
<inttypes.h> don't define. */
|
||||
#undef uintmax_t
|
||||
|
||||
|
||||
#define __libc_lock_t gl_lock_t
|
||||
#define __libc_lock_define gl_lock_define
|
||||
#define __libc_lock_define_initialized gl_lock_define_initialized
|
||||
#define __libc_lock_init gl_lock_init
|
||||
#define __libc_lock_lock gl_lock_lock
|
||||
#define __libc_lock_unlock gl_lock_unlock
|
||||
#define __libc_lock_recursive_t gl_recursive_lock_t
|
||||
#define __libc_lock_define_recursive gl_recursive_lock_define
|
||||
#define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized
|
||||
#define __libc_lock_init_recursive gl_recursive_lock_init
|
||||
#define __libc_lock_lock_recursive gl_recursive_lock_lock
|
||||
#define __libc_lock_unlock_recursive gl_recursive_lock_unlock
|
||||
#define glthread_in_use libintl_thread_in_use
|
||||
#define glthread_lock_init_func libintl_lock_init_func
|
||||
#define glthread_lock_lock_func libintl_lock_lock_func
|
||||
#define glthread_lock_unlock_func libintl_lock_unlock_func
|
||||
#define glthread_lock_destroy_func libintl_lock_destroy_func
|
||||
#define glthread_rwlock_init_multithreaded libintl_rwlock_init_multithreaded
|
||||
#define glthread_rwlock_init_func libintl_rwlock_init_func
|
||||
#define glthread_rwlock_rdlock_multithreaded libintl_rwlock_rdlock_multithreaded
|
||||
#define glthread_rwlock_rdlock_func libintl_rwlock_rdlock_func
|
||||
#define glthread_rwlock_wrlock_multithreaded libintl_rwlock_wrlock_multithreaded
|
||||
#define glthread_rwlock_wrlock_func libintl_rwlock_wrlock_func
|
||||
#define glthread_rwlock_unlock_multithreaded libintl_rwlock_unlock_multithreaded
|
||||
#define glthread_rwlock_unlock_func libintl_rwlock_unlock_func
|
||||
#define glthread_rwlock_destroy_multithreaded libintl_rwlock_destroy_multithreaded
|
||||
#define glthread_rwlock_destroy_func libintl_rwlock_destroy_func
|
||||
#define glthread_recursive_lock_init_multithreaded libintl_recursive_lock_init_multithreaded
|
||||
#define glthread_recursive_lock_init_func libintl_recursive_lock_init_func
|
||||
#define glthread_recursive_lock_lock_multithreaded libintl_recursive_lock_lock_multithreaded
|
||||
#define glthread_recursive_lock_lock_func libintl_recursive_lock_lock_func
|
||||
#define glthread_recursive_lock_unlock_multithreaded libintl_recursive_lock_unlock_multithreaded
|
||||
#define glthread_recursive_lock_unlock_func libintl_recursive_lock_unlock_func
|
||||
#define glthread_recursive_lock_destroy_multithreaded libintl_recursive_lock_destroy_multithreaded
|
||||
#define glthread_recursive_lock_destroy_func libintl_recursive_lock_destroy_func
|
||||
#define glthread_once_func libintl_once_func
|
||||
#define glthread_once_singlethreaded libintl_once_singlethreaded
|
||||
#define glthread_once_multithreaded libintl_once_multithreaded
|
||||
|
1
mednafen/include/desa68
Symbolic link
1
mednafen/include/desa68
Symbolic link
@ -0,0 +1 @@
|
||||
../src/desa68/
|
1
mednafen/include/trio/CHANGES
Symbolic link
1
mednafen/include/trio/CHANGES
Symbolic link
@ -0,0 +1 @@
|
||||
../../src/trio/CHANGES
|
235
mednafen/include/trio/trio.h
Normal file
235
mednafen/include/trio/trio.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* $Id: trio.h,v 1.19 2009/09/13 10:12:22 breese Exp $
|
||||
*
|
||||
* Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
|
||||
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
|
||||
*
|
||||
*************************************************************************
|
||||
*
|
||||
* http://ctrio.sourceforge.net/
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef TRIO_TRIO_H
|
||||
#define TRIO_TRIO_H
|
||||
|
||||
#if !defined(WITHOUT_TRIO)
|
||||
|
||||
/*
|
||||
* Use autoconf defines if present. Packages using trio must define
|
||||
* HAVE_CONFIG_H as a compiler option themselves.
|
||||
*/
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "triop.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Error codes.
|
||||
*
|
||||
* Remember to add a textual description to trio_strerror.
|
||||
*/
|
||||
enum {
|
||||
TRIO_EOF = 1,
|
||||
TRIO_EINVAL = 2,
|
||||
TRIO_ETOOMANY = 3,
|
||||
TRIO_EDBLREF = 4,
|
||||
TRIO_EGAP = 5,
|
||||
TRIO_ENOMEM = 6,
|
||||
TRIO_ERANGE = 7,
|
||||
TRIO_ERRNO = 8,
|
||||
TRIO_ECUSTOM = 9
|
||||
};
|
||||
|
||||
/* Error macros */
|
||||
#define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF)
|
||||
#define TRIO_ERROR_POSITION(x) ((-(x)) >> 8)
|
||||
#define TRIO_ERROR_NAME(x) trio_strerror(x)
|
||||
|
||||
typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int));
|
||||
typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t));
|
||||
|
||||
TRIO_CONST char *trio_strerror TRIO_PROTO((int));
|
||||
|
||||
/*************************************************************************
|
||||
* Print Functions
|
||||
*/
|
||||
|
||||
int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...));
|
||||
int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
|
||||
int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
|
||||
int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
|
||||
int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
|
||||
int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
|
||||
int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
|
||||
TRIO_CONST char *format, ...));
|
||||
int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
|
||||
TRIO_CONST char *format, va_list args));
|
||||
int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
|
||||
TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...));
|
||||
int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args));
|
||||
int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
|
||||
int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
|
||||
va_list args));
|
||||
int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
|
||||
void **args));
|
||||
|
||||
int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
|
||||
int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
|
||||
va_list args));
|
||||
|
||||
#if defined(TRIO_DEPRECATED)
|
||||
char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...));
|
||||
char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
|
||||
#endif
|
||||
|
||||
int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...));
|
||||
int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args));
|
||||
int trio_asprintfv TRIO_PROTO((char **result, TRIO_CONST char *format, trio_pointer_t * args));
|
||||
|
||||
/*************************************************************************
|
||||
* Scan Functions
|
||||
*/
|
||||
int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...));
|
||||
int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args));
|
||||
int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
|
||||
int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
|
||||
int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
|
||||
int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
|
||||
int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
|
||||
TRIO_CONST char *format, ...));
|
||||
int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
|
||||
TRIO_CONST char *format, va_list args));
|
||||
int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
|
||||
TRIO_CONST char *format, void **args));
|
||||
|
||||
int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...));
|
||||
int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args));
|
||||
int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args));
|
||||
|
||||
/*************************************************************************
|
||||
* Locale Functions
|
||||
*/
|
||||
void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint));
|
||||
void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator));
|
||||
void trio_locale_set_grouping TRIO_PROTO((char *grouping));
|
||||
|
||||
/*************************************************************************
|
||||
* Renaming
|
||||
*/
|
||||
#ifdef TRIO_REPLACE_STDIO
|
||||
/* Replace the <stdio.h> functions */
|
||||
#ifndef HAVE_PRINTF
|
||||
# undef printf
|
||||
# define printf trio_printf
|
||||
#endif
|
||||
#ifndef HAVE_VPRINTF
|
||||
# undef vprintf
|
||||
# define vprintf trio_vprintf
|
||||
#endif
|
||||
#ifndef HAVE_FPRINTF
|
||||
# undef fprintf
|
||||
# define fprintf trio_fprintf
|
||||
#endif
|
||||
#ifndef HAVE_VFPRINTF
|
||||
# undef vfprintf
|
||||
# define vfprintf trio_vfprintf
|
||||
#endif
|
||||
#ifndef HAVE_SPRINTF
|
||||
# undef sprintf
|
||||
# define sprintf trio_sprintf
|
||||
#endif
|
||||
#ifndef HAVE_VSPRINTF
|
||||
# undef vsprintf
|
||||
# define vsprintf trio_vsprintf
|
||||
#endif
|
||||
#ifndef HAVE_SNPRINTF
|
||||
# undef snprintf
|
||||
# define snprintf trio_snprintf
|
||||
#endif
|
||||
#ifndef HAVE_VSNPRINTF
|
||||
# undef vsnprintf
|
||||
# define vsnprintf trio_vsnprintf
|
||||
#endif
|
||||
#ifndef HAVE_SCANF
|
||||
# undef scanf
|
||||
# define scanf trio_scanf
|
||||
#endif
|
||||
#ifndef HAVE_VSCANF
|
||||
# undef vscanf
|
||||
# define vscanf trio_vscanf
|
||||
#endif
|
||||
#ifndef HAVE_FSCANF
|
||||
# undef fscanf
|
||||
# define fscanf trio_fscanf
|
||||
#endif
|
||||
#ifndef HAVE_VFSCANF
|
||||
# undef vfscanf
|
||||
# define vfscanf trio_vfscanf
|
||||
#endif
|
||||
#ifndef HAVE_SSCANF
|
||||
# undef sscanf
|
||||
# define sscanf trio_sscanf
|
||||
#endif
|
||||
#ifndef HAVE_VSSCANF
|
||||
# undef vsscanf
|
||||
# define vsscanf trio_vsscanf
|
||||
#endif
|
||||
/* These aren't stdio functions, but we make them look similar */
|
||||
#undef dprintf
|
||||
#define dprintf trio_dprintf
|
||||
#undef vdprintf
|
||||
#define vdprintf trio_vdprintf
|
||||
#undef aprintf
|
||||
#define aprintf trio_aprintf
|
||||
#undef vaprintf
|
||||
#define vaprintf trio_vaprintf
|
||||
#undef asprintf
|
||||
#define asprintf trio_asprintf
|
||||
#undef vasprintf
|
||||
#define vasprintf trio_vasprintf
|
||||
#undef dscanf
|
||||
#define dscanf trio_dscanf
|
||||
#undef vdscanf
|
||||
#define vdscanf trio_vdscanf
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* WITHOUT_TRIO */
|
||||
|
||||
#endif /* TRIO_TRIO_H */
|
335
mednafen/include/trio/triodef.h
Normal file
335
mednafen/include/trio/triodef.h
Normal file
@ -0,0 +1,335 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* $Id: triodef.h,v 1.35 2009/09/20 11:37:14 breese Exp $
|
||||
*
|
||||
* Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
|
||||
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef TRIO_TRIODEF_H
|
||||
#define TRIO_TRIODEF_H
|
||||
|
||||
/*************************************************************************
|
||||
* Compiler support detection
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define TRIO_COMPILER_GCC
|
||||
#endif
|
||||
|
||||
#if defined(__SUNPRO_CC)
|
||||
# define TRIO_COMPILER_SUNPRO __SUNPRO_CC
|
||||
#else
|
||||
# if defined(__SUNPRO_C)
|
||||
# define TRIO_COMPILER_SUNPRO __SUNPRO_C
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__)
|
||||
# define TRIO_COMPILER_XLC
|
||||
#else
|
||||
# if defined(_AIX) && !defined(__GNUC__)
|
||||
# define TRIO_COMPILER_XLC /* Workaround for old xlc */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__DECC) || defined(__DECCXX)
|
||||
# define TRIO_COMPILER_DECC
|
||||
#else
|
||||
# if defined(__osf__) && defined(__LANGUAGE_C__) && !defined(__GNUC__)
|
||||
# define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__HP_aCC) || defined(__HP_cc)
|
||||
# define TRIO_COMPILER_HP
|
||||
#endif
|
||||
|
||||
#if defined(sgi) || defined(__sgi)
|
||||
# define TRIO_COMPILER_MIPSPRO
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define TRIO_COMPILER_MSVC
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
# define TRIO_COMPILER_BCB
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Platform support detection
|
||||
*/
|
||||
|
||||
#if defined(VMS) || defined(__VMS)
|
||||
# define TRIO_PLATFORM_VMS
|
||||
#endif
|
||||
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_COMPILER_XLC) || defined(_AIX)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_COMPILER_DECC) || defined(__osf___)
|
||||
# if !defined(TRIO_PLATFORM_VMS)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(__Lynx__)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
# define TRIO_PLATFORM_LYNX
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(__QNX__)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
# define TRIO_PLATFORM_QNX
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(AMIGA) && defined(TRIO_COMPILER_GCC)
|
||||
# define TRIO_PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32)
|
||||
# define TRIO_PLATFORM_WIN32
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
# define TRIO_PLATFORM_WINCE
|
||||
#endif
|
||||
|
||||
#if defined(mpeix) || defined(__mpexl)
|
||||
# define TRIO_PLATFORM_MPEIX
|
||||
#endif
|
||||
|
||||
#if defined(_AIX)
|
||||
# define TRIO_PLATFORM_AIX
|
||||
#endif
|
||||
|
||||
#if defined(__hpux)
|
||||
# define TRIO_PLATFORM_HPUX
|
||||
#endif
|
||||
|
||||
#if defined(sun) || defined(__sun__)
|
||||
# if defined(__SVR4) || defined(__svr4__)
|
||||
# define TRIO_PLATFORM_SOLARIS
|
||||
# else
|
||||
# define TRIO_PLATFORM_SUNOS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Standards support detection
|
||||
*/
|
||||
|
||||
#if defined(__STDC__) \
|
||||
|| defined(_MSC_EXTENSIONS) \
|
||||
|| defined(TRIO_COMPILER_BCB)
|
||||
# define PREDEF_STANDARD_C89
|
||||
#endif
|
||||
#if defined(__STDC_VERSION__)
|
||||
# define PREDEF_STANDARD_C90
|
||||
#endif
|
||||
#if (__STDC_VERSION__ - 0 >= 199409L)
|
||||
# define PREDEF_STANDARD_C94
|
||||
#endif
|
||||
#if (__STDC_VERSION__ - 0 >= 199901L)
|
||||
# define PREDEF_STANDARD_C99
|
||||
#endif
|
||||
#if defined(TRIO_COMPILER_SUNPRO) && (TRIO_COMPILER_SUNPRO >= 0x420)
|
||||
# if !defined(PREDEF_STANDARD_C94)
|
||||
# define PREDEF_STANDARD_C94
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define PREDEF_STANDARD_CXX
|
||||
#endif
|
||||
#if __cplusplus - 0 >= 199711L
|
||||
# define PREDEF_STANDARD_CXX89
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_PLATFORM_UNIX)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(_POSIX_VERSION)
|
||||
# define PREDEF_STANDARD_POSIX _POSIX_VERSION
|
||||
# if (_POSIX_VERSION >= 199506L)
|
||||
# define PREDEF_STANDARD_POSIX_1996
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (_XOPEN_VERSION - 0 >= 3) || defined(_XOPEN_XPG3)
|
||||
# define PREDEF_STANDARD_XPG3
|
||||
#endif
|
||||
#if (_XOPEN_VERSION - 0 >= 4) || defined(_XOPEN_XPG4)
|
||||
# define PREDEF_STANDARD_XPG4
|
||||
#endif
|
||||
#if (_XOPEN_VERSION - 0 > 4) \
|
||||
|| (defined(_XOPEN_UNIX) && (_XOPEN_VERSION - 0 == 4))
|
||||
# define PREDEF_STANDARD_UNIX95
|
||||
#endif
|
||||
#if (_XOPEN_VERSION - 0 >= 500)
|
||||
# define PREDEF_STANDARD_UNIX98
|
||||
#endif
|
||||
#if (_XOPEN_VERSION - 0 >= 600)
|
||||
# define PREDEF_STANDARD_UNIX03
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Generic defines
|
||||
*/
|
||||
|
||||
#if !defined(TRIO_PUBLIC)
|
||||
# define TRIO_PUBLIC
|
||||
#endif
|
||||
#if !defined(TRIO_PRIVATE)
|
||||
# define TRIO_PRIVATE static
|
||||
#endif
|
||||
|
||||
#if !(defined(PREDEF_STANDARD_C89) || defined(PREDEF_STANDARD_CXX))
|
||||
# define TRIO_COMPILER_ANCIENT
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_COMPILER_ANCIENT)
|
||||
# define TRIO_CONST
|
||||
# define TRIO_VOLATILE
|
||||
# define TRIO_SIGNED
|
||||
typedef double trio_long_double_t;
|
||||
typedef char * trio_pointer_t;
|
||||
# define TRIO_SUFFIX_LONG(x) x
|
||||
# define TRIO_PROTO(x) ()
|
||||
# define TRIO_NOARGS
|
||||
# define TRIO_ARGS1(list,a1) list a1;
|
||||
# define TRIO_ARGS2(list,a1,a2) list a1; a2;
|
||||
# define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3;
|
||||
# define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4;
|
||||
# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5;
|
||||
# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6;
|
||||
# define TRIO_ARGS7(list,a1,a2,a3,a4,a5,a6,a7) list a1; a2; a3; a4; a5; a6; a7;
|
||||
# define TRIO_VARGS2(list,a1,a2) list a1; a2
|
||||
# define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3
|
||||
# define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4
|
||||
# define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5
|
||||
# define TRIO_VA_DECL va_dcl
|
||||
# define TRIO_VA_START(x,y) va_start(x)
|
||||
# define TRIO_VA_END(x) va_end(x)
|
||||
#else /* ANSI C */
|
||||
# define TRIO_CONST const
|
||||
# define TRIO_VOLATILE volatile
|
||||
# define TRIO_SIGNED signed
|
||||
typedef long double trio_long_double_t;
|
||||
typedef void * trio_pointer_t;
|
||||
# define TRIO_SUFFIX_LONG(x) x ## L
|
||||
# define TRIO_PROTO(x) x
|
||||
# define TRIO_NOARGS void
|
||||
# define TRIO_ARGS1(list,a1) (a1)
|
||||
# define TRIO_ARGS2(list,a1,a2) (a1,a2)
|
||||
# define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3)
|
||||
# define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4)
|
||||
# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5)
|
||||
# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6)
|
||||
# define TRIO_ARGS7(list,a1,a2,a3,a4,a5,a6,a7) (a1,a2,a3,a4,a5,a6,a7)
|
||||
# define TRIO_VARGS2 TRIO_ARGS2
|
||||
# define TRIO_VARGS3 TRIO_ARGS3
|
||||
# define TRIO_VARGS4 TRIO_ARGS4
|
||||
# define TRIO_VARGS5 TRIO_ARGS5
|
||||
# define TRIO_VA_DECL ...
|
||||
# define TRIO_VA_START(x,y) va_start(x,y)
|
||||
# define TRIO_VA_END(x) va_end(x)
|
||||
#endif
|
||||
|
||||
#if defined(PREDEF_STANDARD_C99) || defined(PREDEF_STANDARD_CXX)
|
||||
# define TRIO_INLINE inline
|
||||
#else
|
||||
# if defined(TRIO_COMPILER_GCC)
|
||||
# define TRIO_INLINE __inline__
|
||||
# endif
|
||||
# if defined(TRIO_COMPILER_MSVC)
|
||||
# define TRIO_INLINE _inline
|
||||
# endif
|
||||
# if defined(TRIO_COMPILER_BCB)
|
||||
# define TRIO_INLINE __inline
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(TRIO_INLINE)
|
||||
# define TRIO_INLINE
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Workarounds
|
||||
*/
|
||||
|
||||
#if defined(TRIO_PLATFORM_VMS)
|
||||
/*
|
||||
* Computations done with constants at compile time can trigger these
|
||||
* even when compiling with IEEE enabled.
|
||||
*/
|
||||
# pragma message disable (UNDERFLOW, FLOATOVERFL)
|
||||
|
||||
# if (__CRTL_VER < 80210001)
|
||||
/*
|
||||
* Although the compiler supports C99 language constructs, the C
|
||||
* run-time library does not contain all C99 functions.
|
||||
*/
|
||||
# if defined(PREDEF_STANDARD_C99)
|
||||
# undef PREDEF_STANDARD_C99
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Not all preprocessors supports the LL token.
|
||||
*/
|
||||
#if defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB)
|
||||
#else
|
||||
# define TRIO_COMPILER_SUPPORTS_LL
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
/*
|
||||
* Cygwin defines the macros for hosted C99, but does not support certain
|
||||
* long double math functions.
|
||||
*/
|
||||
# include <cygwin/version.h>
|
||||
# define TRIO_CYGWIN_VERSION_API CYGWIN_VERSION_API_MAJOR * 1000 + \
|
||||
CYGWIN_VERSION_API_MINOR
|
||||
/*
|
||||
* Please change the version number below when the Cygwin API supports
|
||||
* long double math functions (powl, fmodl, etc.)
|
||||
*/
|
||||
# if TRIO_CYGWIN_VERSION_API < 99999999
|
||||
# define TRIO_NO_FLOORL 1
|
||||
# define TRIO_NO_CEILL 1
|
||||
# define TRIO_NO_POWL 1
|
||||
# define TRIO_NO_FMODL 1
|
||||
# define TRIO_NO_LOG10L 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* TRIO_TRIODEF_H */
|
183
mednafen/include/trio/trionan.h
Normal file
183
mednafen/include/trio/trionan.h
Normal file
@ -0,0 +1,183 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* $Id: trionan.h,v 1.9 2005/03/27 18:52:45 breese Exp $
|
||||
*
|
||||
* Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
|
||||
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef TRIO_TRIONAN_H
|
||||
#define TRIO_TRIONAN_H
|
||||
|
||||
#include "triodef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_PUBLIC_NAN)
|
||||
# if !defined(TRIO_PUBLIC)
|
||||
# define TRIO_PUBLIC
|
||||
# endif
|
||||
# define TRIO_PUBLIC_NAN TRIO_PUBLIC
|
||||
#endif
|
||||
|
||||
enum {
|
||||
TRIO_FP_INFINITE,
|
||||
TRIO_FP_NAN,
|
||||
TRIO_FP_NORMAL,
|
||||
TRIO_FP_SUBNORMAL,
|
||||
TRIO_FP_ZERO
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
#if defined(TRIO_EMBED_NAN)
|
||||
|
||||
/*
|
||||
* The application that trionan is embedded in must define which functions
|
||||
* it uses.
|
||||
*
|
||||
* The following resolves internal dependencies.
|
||||
*/
|
||||
|
||||
# if defined(TRIO_FUNC_ISNAN) \
|
||||
|| defined(TRIO_FUNC_ISINF)
|
||||
# if !defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT)
|
||||
# define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_NAN)
|
||||
# if !defined(TRIO_FUNC_PINF)
|
||||
# define TRIO_FUNC_PINF
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_NINF)
|
||||
# if !defined(TRIO_FUNC_PINF)
|
||||
# define TRIO_FUNC_PINF
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* When trionan is not embedded all all functions are defined.
|
||||
*/
|
||||
|
||||
# define TRIO_FUNC_NAN
|
||||
# define TRIO_FUNC_PINF
|
||||
# define TRIO_FUNC_NINF
|
||||
# define TRIO_FUNC_NZERO
|
||||
# define TRIO_FUNC_ISNAN
|
||||
# define TRIO_FUNC_ISINF
|
||||
# define TRIO_FUNC_ISFINITE
|
||||
# define TRIO_FUNC_SIGNBIT
|
||||
# define TRIO_FUNC_FPCLASSIFY
|
||||
# define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT
|
||||
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return NaN (Not-a-Number).
|
||||
*/
|
||||
#if defined(TRIO_FUNC_NAN)
|
||||
TRIO_PUBLIC_NAN double
|
||||
trio_nan
|
||||
TRIO_PROTO((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return positive infinity.
|
||||
*/
|
||||
#if defined(TRIO_FUNC_PINF)
|
||||
TRIO_PUBLIC_NAN double
|
||||
trio_pinf
|
||||
TRIO_PROTO((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return negative infinity.
|
||||
*/
|
||||
#if defined(TRIO_FUNC_NINF)
|
||||
TRIO_PUBLIC_NAN double
|
||||
trio_ninf
|
||||
TRIO_PROTO((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return negative zero.
|
||||
*/
|
||||
#if defined(TRIO_FUNC_NZERO)
|
||||
TRIO_PUBLIC_NAN double
|
||||
trio_nzero
|
||||
TRIO_PROTO((TRIO_NOARGS));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If number is a NaN return non-zero, otherwise return zero.
|
||||
*/
|
||||
#if defined(TRIO_FUNC_ISNAN)
|
||||
TRIO_PUBLIC_NAN int
|
||||
trio_isnan
|
||||
TRIO_PROTO((double number));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If number is positive infinity return 1, if number is negative
|
||||
* infinity return -1, otherwise return 0.
|
||||
*/
|
||||
#if defined(TRIO_FUNC_ISINF)
|
||||
TRIO_PUBLIC_NAN int
|
||||
trio_isinf
|
||||
TRIO_PROTO((double number));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If number is finite return non-zero, otherwise return zero.
|
||||
*/
|
||||
#if defined(TRIO_FUNC_ISFINITE)
|
||||
TRIO_PUBLIC_NAN int
|
||||
trio_isfinite
|
||||
TRIO_PROTO((double number));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_SIGNBIT)
|
||||
TRIO_PUBLIC_NAN int
|
||||
trio_signbit
|
||||
TRIO_PROTO((double number));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_FPCLASSIFY)
|
||||
TRIO_PUBLIC_NAN int
|
||||
trio_fpclassify
|
||||
TRIO_PROTO((double number));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT)
|
||||
TRIO_PUBLIC_NAN int
|
||||
trio_fpclassify_and_signbit
|
||||
TRIO_PROTO((double number, int *is_negative));
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TRIO_TRIONAN_H */
|
473
mednafen/include/trio/triop.h
Normal file
473
mednafen/include/trio/triop.h
Normal file
@ -0,0 +1,473 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* $Id: triop.h,v 1.18 2009/07/05 10:14:07 breese Exp $
|
||||
*
|
||||
* Copyright (C) 2000 Bjorn Reese and Daniel Stenberg.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
|
||||
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
|
||||
*
|
||||
************************************************************************
|
||||
*
|
||||
* Private functions, types, etc. used for callback functions.
|
||||
*
|
||||
* The ref pointer is an opaque type and should remain as such.
|
||||
* Private data must only be accessible through the getter and
|
||||
* setter functions.
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef TRIO_TRIOP_H
|
||||
#define TRIO_TRIOP_H
|
||||
|
||||
#include "triodef.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#if defined(TRIO_COMPILER_ANCIENT)
|
||||
# include <varargs.h>
|
||||
#else
|
||||
# include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Supported standards
|
||||
*/
|
||||
|
||||
/*
|
||||
* TRIO_C99 (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable C99 format specifier extensions, or
|
||||
* define to 1 to enable them. The format specifiers that are
|
||||
* disabled by this switch are labelled with [C99] in the format
|
||||
* specifier documentation.
|
||||
*/
|
||||
#if !defined(TRIO_C99)
|
||||
# define TRIO_C99 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_BSD (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable BSD format specifier extensions, or
|
||||
* define to 1 to enable them. The format specifiers that are
|
||||
* disabled by this switch are labelled with [BSD] in the format
|
||||
* specifier documentation.
|
||||
*/
|
||||
#if !defined(TRIO_BSD)
|
||||
# define TRIO_BSD 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_GNU (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable GNU format specifier extensions, or
|
||||
* define to 1 to enable them. The format specifiers that are
|
||||
* disabled by this switch are labelled with [GNU] in the format
|
||||
* specifier documentation.
|
||||
*/
|
||||
#if !defined(TRIO_GNU)
|
||||
# define TRIO_GNU 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_MISC (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable miscellaneous format specifier
|
||||
* extensions, or define to 1 to enable them. The format specifiers
|
||||
* that are disabled by this switch are labelled with [MISC] in the
|
||||
* format specifier documentation.
|
||||
*/
|
||||
#if !defined(TRIO_MISC)
|
||||
# define TRIO_MISC 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_UNIX98 (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable UNIX98 format specifier extensions,
|
||||
* or define to 1 to enable them. The format specifiers that are
|
||||
* disabled by this switch are labelled with [UNIX98] in the format
|
||||
* specifier documentation.
|
||||
*/
|
||||
#if !defined(TRIO_UNIX98)
|
||||
# define TRIO_UNIX98 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_MICROSOFT (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable Microsoft Visual C format specifier
|
||||
* extensions, or define to 1 to enable them. The format specifiers
|
||||
* that are disabled by this switch are labelled with [MSVC] in the
|
||||
* format specifier documentation.
|
||||
*/
|
||||
#if !defined(TRIO_MICROSOFT)
|
||||
# define TRIO_MICROSOFT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_EXTENSION (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable Trio-specific extensions, or define
|
||||
* to 1 to enable them. This has two effects: it controls whether
|
||||
* or not the Trio user-defined formating mechanism
|
||||
* (trio_register() etc) is supported, and it enables or disables
|
||||
* Trio's own format specifier extensions. The format specifiers
|
||||
* that are disabled by this switch are labelled with [TRIO] in
|
||||
* the format specifier documentation.
|
||||
*/
|
||||
#if !defined(TRIO_EXTENSION)
|
||||
# define TRIO_EXTENSION 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_DEPRECATED (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable deprecated functionality, or define
|
||||
* to 1 to enable them.
|
||||
*/
|
||||
#if !defined(TRIO_DEPRECATED)
|
||||
# define TRIO_DEPRECATED 1
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Features
|
||||
*/
|
||||
|
||||
#if defined(TRIO_SNPRINTF_ONLY)
|
||||
# define TRIO_FEATURE_SCANF 0
|
||||
# define TRIO_FEATURE_FILE 0
|
||||
# define TRIO_FEATURE_STDIO 0
|
||||
# define TRIO_FEATURE_FD 0
|
||||
# define TRIO_FEATURE_DYNAMICSTRING 0
|
||||
# define TRIO_FEATURE_CLOSURE 0
|
||||
# define TRIO_FEATURE_STRERR 0
|
||||
# define TRIO_FEATURE_LOCALE 0
|
||||
# define TRIO_EMBED_NAN 1
|
||||
# define TRIO_EMBED_STRING 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_SCANF (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable all the scanf() variants, or define to 1
|
||||
* to enable them.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_SCANF)
|
||||
# define TRIO_FEATURE_SCANF 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_FILE (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable compilation of the trio_fprintf() and
|
||||
* trio_fscanf() family of functions, or define to 1 to enable them.
|
||||
*
|
||||
* This may be useful on an embedded platform with no filesystem.
|
||||
* Note that trio_printf() uses fwrite to write to stdout, so if you
|
||||
* do not have an implementation of fwrite() at all then you must also
|
||||
* define TRIO_FEATURE_STDIO to 0.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_FILE)
|
||||
# define TRIO_FEATURE_FILE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_STDIO (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable compilation of the trio_printf() and
|
||||
* trio_scanf() family of functions, or define to 1 to enable them.
|
||||
*
|
||||
* This may be useful on an embedded platform with no standard I/O.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_STDIO)
|
||||
# define TRIO_FEATURE_STDIO 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_FD (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable compilation of the trio_dprintf() and
|
||||
* trio_dscanf() family of functions, or define to 1 to enable them.
|
||||
*
|
||||
* This may be useful on an embedded platform with no filesystem, or on
|
||||
* a platform that supports file I/O using FILE* but not using raw file
|
||||
* descriptors.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_FD)
|
||||
# define TRIO_FEATURE_FD 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_DYNAMICSTRING (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable compilation of the trio_aprintf()
|
||||
* family of functions, or define to 1 to enable them.
|
||||
*
|
||||
* If you define both this and TRIO_MINIMAL to 0, then Trio will never
|
||||
* call malloc or free.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_DYNAMICSTRING)
|
||||
# define TRIO_FEATURE_DYNAMICSTRING 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_CLOSURE (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable compilation of the trio_cprintf() and
|
||||
* trio_cscanf() family of functions, or define to 1 to enable them.
|
||||
*
|
||||
* These functions are rarely needed. This saves a (small) amount of code.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_CLOSURE)
|
||||
# define TRIO_FEATURE_CLOSURE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_ERRORCODE (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to return -1 from the print and scan function on
|
||||
* error, or define to 1 to return a negative number with debugging
|
||||
* information as part of the return code.
|
||||
*
|
||||
* If enabled, the return code will be a negative number, which encodes
|
||||
* an error code and an error location. These can be decoded with the
|
||||
* TRIO_ERROR_CODE and TRIO_ERROR_POSITION macros.
|
||||
*/
|
||||
#if defined(TRIO_ERRORS)
|
||||
# define TRIO_FEATURE_ERRORCODE TRIO_ERRORS
|
||||
#endif
|
||||
#if !defined(TRIO_FEATURE_ERRORCODE)
|
||||
# define TRIO_FEATURE_ERRORCODE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_STRERR (=0 or =1)
|
||||
*
|
||||
* Define this to 0 if you do not use trio_strerror(), or define to 1 if
|
||||
* you do use it.
|
||||
*
|
||||
* This saves a (small) amount of code.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_STRERR)
|
||||
# define TRIO_FEATURE_STRERR 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_FLOAT (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable all floating-point support, or define
|
||||
* to 1 to enable it.
|
||||
*
|
||||
* This is useful in restricted embedded platforms that do not support
|
||||
* floating-point. Obviously you cannot use floating-point format
|
||||
* specifiers if you define this.
|
||||
*
|
||||
* Do not compile trionan.c if you disable this.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_FLOAT)
|
||||
# define TRIO_FEATURE_FLOAT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_FEATURE_LOCALE (=0 or =1)
|
||||
*
|
||||
* Define this to 0 to disable customized locale support, or define
|
||||
* to 1 to enable it.
|
||||
*
|
||||
* This saves a (small) amount of code.
|
||||
*/
|
||||
#if !defined(TRIO_FEATURE_LOCALE)
|
||||
# define TRIO_FEATURE_LOCALE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TRIO_MINIMAL
|
||||
*
|
||||
* Define this to disable building the public trionan.h and triostr.h.
|
||||
* If you define this, then you must not compile trionan.c and triostr.c
|
||||
* separately.
|
||||
*/
|
||||
#if defined(TRIO_MINIMAL)
|
||||
# if !defined(TRIO_EMBED_NAN)
|
||||
# define TRIO_EMBED_NAN
|
||||
# endif
|
||||
# if !defined(TRIO_EMBED_STRING)
|
||||
# define TRIO_EMBED_STRING
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Does not work yet. Do not enable */
|
||||
#ifndef TRIO_FEATURE_WIDECHAR
|
||||
# define TRIO_FEATURE_WIDECHAR 0
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Mapping standards to internal features
|
||||
*/
|
||||
|
||||
#if !defined(TRIO_FEATURE_HEXFLOAT)
|
||||
# define TRIO_FEATURE_HEXFLOAT (TRIO_C99 && TRIO_FEATURE_FLOAT)
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_LONGDOUBLE)
|
||||
# define TRIO_FEATURE_LONGDOUBLE TRIO_FEATURE_FLOAT
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_ERRNO)
|
||||
# define TRIO_FEATURE_ERRNO TRIO_GNU
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_QUAD)
|
||||
# define TRIO_FEATURE_QUAD (TRIO_BSD || TRIO_GNU)
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_SIZE_T)
|
||||
# define TRIO_FEATURE_SIZE_T TRIO_C99
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_SIZE_T_UPPER)
|
||||
# define TRIO_FEATURE_SIZE_T_UPPER TRIO_GNU
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_PTRDIFF_T)
|
||||
# define TRIO_FEATURE_PTRDIFF_T TRIO_C99
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_INTMAX_T)
|
||||
# define TRIO_FEATURE_INTMAX_T TRIO_C99
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_FIXED_SIZE)
|
||||
# define TRIO_FEATURE_FIXED_SIZE TRIO_MICROSOFT
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_POSITIONAL)
|
||||
# define TRIO_FEATURE_POSITIONAL TRIO_UNIX98
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_USER_DEFINED)
|
||||
# define TRIO_FEATURE_USER_DEFINED TRIO_EXTENSION
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_BINARY)
|
||||
# define TRIO_FEATURE_BINARY TRIO_EXTENSION
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_QUOTE)
|
||||
# define TRIO_FEATURE_QUOTE TRIO_EXTENSION
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_STICKY)
|
||||
# define TRIO_FEATURE_STICKY TRIO_EXTENSION
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_VARSIZE)
|
||||
# define TRIO_FEATURE_VARSIZE TRIO_EXTENSION
|
||||
#endif
|
||||
|
||||
#if !defined(TRIO_FEATURE_ROUNDING)
|
||||
# define TRIO_FEATURE_ROUNDING TRIO_EXTENSION
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Memory handling
|
||||
*/
|
||||
#ifndef TRIO_MALLOC
|
||||
# define TRIO_MALLOC(n) malloc(n)
|
||||
#endif
|
||||
#ifndef TRIO_REALLOC
|
||||
# define TRIO_REALLOC(x,n) realloc((x),(n))
|
||||
#endif
|
||||
#ifndef TRIO_FREE
|
||||
# define TRIO_FREE(x) free(x)
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* User-defined specifiers
|
||||
*/
|
||||
|
||||
typedef int (*trio_callback_t) TRIO_PROTO((trio_pointer_t));
|
||||
|
||||
trio_pointer_t trio_register TRIO_PROTO((trio_callback_t callback, const char *name));
|
||||
void trio_unregister TRIO_PROTO((trio_pointer_t handle));
|
||||
|
||||
TRIO_CONST char *trio_get_format TRIO_PROTO((trio_pointer_t ref));
|
||||
/* Mednafen modification to fix a gcc warning */
|
||||
/*TRIO_CONST*/ trio_pointer_t trio_get_argument TRIO_PROTO((trio_pointer_t ref));
|
||||
|
||||
/* Modifiers */
|
||||
int trio_get_width TRIO_PROTO((trio_pointer_t ref));
|
||||
void trio_set_width TRIO_PROTO((trio_pointer_t ref, int width));
|
||||
int trio_get_precision TRIO_PROTO((trio_pointer_t ref));
|
||||
void trio_set_precision TRIO_PROTO((trio_pointer_t ref, int precision));
|
||||
int trio_get_base TRIO_PROTO((trio_pointer_t ref));
|
||||
void trio_set_base TRIO_PROTO((trio_pointer_t ref, int base));
|
||||
int trio_get_padding TRIO_PROTO((trio_pointer_t ref));
|
||||
void trio_set_padding TRIO_PROTO((trio_pointer_t ref, int is_padding));
|
||||
int trio_get_short TRIO_PROTO((trio_pointer_t ref)); /* h */
|
||||
void trio_set_shortshort TRIO_PROTO((trio_pointer_t ref, int is_shortshort));
|
||||
int trio_get_shortshort TRIO_PROTO((trio_pointer_t ref)); /* hh */
|
||||
void trio_set_short TRIO_PROTO((trio_pointer_t ref, int is_short));
|
||||
int trio_get_long TRIO_PROTO((trio_pointer_t ref)); /* l */
|
||||
void trio_set_long TRIO_PROTO((trio_pointer_t ref, int is_long));
|
||||
int trio_get_longlong TRIO_PROTO((trio_pointer_t ref)); /* ll */
|
||||
void trio_set_longlong TRIO_PROTO((trio_pointer_t ref, int is_longlong));
|
||||
int trio_get_longdouble TRIO_PROTO((trio_pointer_t ref)); /* L */
|
||||
void trio_set_longdouble TRIO_PROTO((trio_pointer_t ref, int is_longdouble));
|
||||
int trio_get_alternative TRIO_PROTO((trio_pointer_t ref)); /* # */
|
||||
void trio_set_alternative TRIO_PROTO((trio_pointer_t ref, int is_alternative));
|
||||
int trio_get_alignment TRIO_PROTO((trio_pointer_t ref)); /* - */
|
||||
void trio_set_alignment TRIO_PROTO((trio_pointer_t ref, int is_leftaligned));
|
||||
int trio_get_spacing TRIO_PROTO((trio_pointer_t ref)); /* (space) */
|
||||
void trio_set_spacing TRIO_PROTO((trio_pointer_t ref, int is_space));
|
||||
int trio_get_sign TRIO_PROTO((trio_pointer_t ref)); /* + */
|
||||
void trio_set_sign TRIO_PROTO((trio_pointer_t ref, int is_showsign));
|
||||
#if TRIO_FEATURE_QUOTE
|
||||
int trio_get_quote TRIO_PROTO((trio_pointer_t ref)); /* ' */
|
||||
void trio_set_quote TRIO_PROTO((trio_pointer_t ref, int is_quote));
|
||||
#endif
|
||||
int trio_get_upper TRIO_PROTO((trio_pointer_t ref));
|
||||
void trio_set_upper TRIO_PROTO((trio_pointer_t ref, int is_upper));
|
||||
#if TRIO_FEATURE_INTMAX_T
|
||||
int trio_get_largest TRIO_PROTO((trio_pointer_t ref)); /* j */
|
||||
void trio_set_largest TRIO_PROTO((trio_pointer_t ref, int is_largest));
|
||||
#endif
|
||||
#if TRIO_FEATURE_PTRDIFF_T
|
||||
int trio_get_ptrdiff TRIO_PROTO((trio_pointer_t ref)); /* t */
|
||||
void trio_set_ptrdiff TRIO_PROTO((trio_pointer_t ref, int is_ptrdiff));
|
||||
#endif
|
||||
#if TRIO_FEATURE_SIZE_T
|
||||
int trio_get_size TRIO_PROTO((trio_pointer_t ref)); /* z / Z */
|
||||
void trio_set_size TRIO_PROTO((trio_pointer_t ref, int is_size));
|
||||
#endif
|
||||
|
||||
/* Printing */
|
||||
int trio_print_ref TRIO_PROTO((trio_pointer_t ref, const char *format, ...));
|
||||
int trio_vprint_ref TRIO_PROTO((trio_pointer_t ref, const char *format, va_list args));
|
||||
int trio_printv_ref TRIO_PROTO((trio_pointer_t ref, const char *format, trio_pointer_t *args));
|
||||
|
||||
void trio_print_int TRIO_PROTO((trio_pointer_t ref, int number));
|
||||
void trio_print_uint TRIO_PROTO((trio_pointer_t ref, unsigned int number));
|
||||
/* void trio_print_long TRIO_PROTO((trio_pointer_t ref, long number)); */
|
||||
/* void trio_print_ulong TRIO_PROTO((trio_pointer_t ref, unsigned long number)); */
|
||||
void trio_print_double TRIO_PROTO((trio_pointer_t ref, double number));
|
||||
void trio_print_string TRIO_PROTO((trio_pointer_t ref, TRIO_CONST char *string));
|
||||
void trio_print_pointer TRIO_PROTO((trio_pointer_t ref, trio_pointer_t pointer));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* TRIO_TRIOP_H */
|
681
mednafen/include/trio/triostr.h
Normal file
681
mednafen/include/trio/triostr.h
Normal file
@ -0,0 +1,681 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* $Id: triostr.h,v 1.18 2010/01/26 13:02:02 breese Exp $
|
||||
*
|
||||
* Copyright (C) 2001 Bjorn Reese and Daniel Stenberg.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
|
||||
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef TRIO_TRIOSTR_H
|
||||
#define TRIO_TRIOSTR_H
|
||||
|
||||
/*
|
||||
* Documentation is located in triostr.c
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "triodef.h"
|
||||
#include "triop.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
TRIO_HASH_NONE = 0,
|
||||
TRIO_HASH_PLAIN,
|
||||
TRIO_HASH_TWOSIGNED
|
||||
};
|
||||
|
||||
#if !defined(TRIO_PUBLIC_STRING)
|
||||
# if !defined(TRIO_PUBLIC)
|
||||
# define TRIO_PUBLIC
|
||||
# endif
|
||||
# define TRIO_PUBLIC_STRING TRIO_PUBLIC
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
#if defined(TRIO_EMBED_STRING)
|
||||
|
||||
/*
|
||||
* The application that triostr is embedded in must define which functions
|
||||
* it uses.
|
||||
*
|
||||
* The following resolves internal dependencies.
|
||||
*/
|
||||
|
||||
# if defined(TRIO_FUNC_XSTRING_SET)
|
||||
# if !defined(TRIO_FUNC_DUPLICATE)
|
||||
# define TRIO_FUNC_DUPLICATE
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_DUPLICATE) \
|
||||
|| defined(TRIO_FUNC_DUPLICATE_MAX) \
|
||||
|| defined(TRIO_FUNC_STRING_DUPLICATE) \
|
||||
|| defined(TRIO_FUNC_XSTRING_DUPLICATE)
|
||||
# if !defined(TRIO_FUNC_CREATE)
|
||||
# define TRIO_FUNC_CREATE
|
||||
# endif
|
||||
# if !defined(TRIO_FUNC_COPY_MAX)
|
||||
# define TRIO_FUNC_COPY_MAX
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_STRING_CREATE)
|
||||
# if !defined(TRIO_FUNC_STRING_DESTROY)
|
||||
# define TRIO_FUNC_STRING_DESTROY
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_STRING_DESTROY) \
|
||||
|| defined(TRIO_FUNC_XSTRING_SET)
|
||||
# if !defined(TRIO_FUNC_DESTROY)
|
||||
# define TRIO_FUNC_DESTROY
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_EQUAL_LOCALE) \
|
||||
|| defined(TRIO_FUNC_STRING_EQUAL) \
|
||||
|| defined(TRIO_FUNC_XSTRING_EQUAL)
|
||||
# if !defined(TRIO_FUNC_EQUAL)
|
||||
# define TRIO_FUNC_EQUAL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_EQUAL_CASE) \
|
||||
|| defined(TRIO_FUNC_STRING_EQUAL_CASE) \
|
||||
|| defined(TRIO_FUNC_XSTRING_EQUAL_CASE)
|
||||
# if !defined(TRIO_FUNC_EQUAL_CASE)
|
||||
# define TRIO_FUNC_EQUAL_CASE
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_SUBSTRING_MAX) \
|
||||
|| defined(TRIO_FUNC_STRING_EQUAL_MAX) \
|
||||
|| defined(TRIO_FUNC_XSTRING_EQUAL_MAX)
|
||||
# if !defined(TRIO_FUNC_EQUAL_MAX)
|
||||
# define TRIO_FUNC_EQUAL_MAX
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_TO_DOUBLE) \
|
||||
|| defined(TRIO_FUNC_TO_FLOAT)
|
||||
# if !defined(TRIO_FUNC_TO_LONG_DOUBLE)
|
||||
# define TRIO_FUNC_TO_LONG_DOUBLE
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_STRING_TERMINATE)
|
||||
# if !defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
|
||||
# define TRIO_FUNC_XSTRING_APPEND_CHAR
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
|
||||
# if !defined(TRIO_FUNC_STRING_SIZE)
|
||||
# define TRIO_FUNC_STRING_SIZE
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* When triostr is not embedded all functions are defined.
|
||||
*/
|
||||
|
||||
# define TRIO_FUNC_APPEND
|
||||
# define TRIO_FUNC_APPEND_MAX
|
||||
# define TRIO_FUNC_CONTAINS
|
||||
# define TRIO_FUNC_COPY
|
||||
# define TRIO_FUNC_COPY_MAX
|
||||
# define TRIO_FUNC_CREATE
|
||||
# define TRIO_FUNC_DESTROY
|
||||
# define TRIO_FUNC_DUPLICATE
|
||||
# define TRIO_FUNC_DUPLICATE_MAX
|
||||
# define TRIO_FUNC_EQUAL
|
||||
# define TRIO_FUNC_EQUAL_CASE
|
||||
# define TRIO_FUNC_EQUAL_CASE_MAX
|
||||
# define TRIO_FUNC_EQUAL_LOCALE
|
||||
# define TRIO_FUNC_EQUAL_MAX
|
||||
# define TRIO_FUNC_ERROR
|
||||
# if !defined(TRIO_PLATFORM_WINCE)
|
||||
# define TRIO_FUNC_FORMAT_DATE_MAX
|
||||
# endif
|
||||
# define TRIO_FUNC_HASH
|
||||
# define TRIO_FUNC_INDEX
|
||||
# define TRIO_FUNC_INDEX_LAST
|
||||
# define TRIO_FUNC_LENGTH
|
||||
# define TRIO_FUNC_LENGTH_MAX
|
||||
# define TRIO_FUNC_LOWER
|
||||
# define TRIO_FUNC_MATCH
|
||||
# define TRIO_FUNC_MATCH_CASE
|
||||
# define TRIO_FUNC_SPAN_FUNCTION
|
||||
# define TRIO_FUNC_SUBSTRING
|
||||
# define TRIO_FUNC_SUBSTRING_MAX
|
||||
# define TRIO_FUNC_TO_DOUBLE
|
||||
# define TRIO_FUNC_TO_FLOAT
|
||||
# define TRIO_FUNC_TO_LONG
|
||||
# define TRIO_FUNC_TO_LONG_DOUBLE
|
||||
# define TRIO_FUNC_TO_LOWER
|
||||
# define TRIO_FUNC_TO_UNSIGNED_LONG
|
||||
# define TRIO_FUNC_TO_UPPER
|
||||
# define TRIO_FUNC_TOKENIZE
|
||||
# define TRIO_FUNC_UPPER
|
||||
|
||||
# define TRIO_FUNC_STRING_APPEND
|
||||
# define TRIO_FUNC_STRING_CONTAINS
|
||||
# define TRIO_FUNC_STRING_COPY
|
||||
# define TRIO_FUNC_STRING_CREATE
|
||||
# define TRIO_FUNC_STRING_DESTROY
|
||||
# define TRIO_FUNC_STRING_DUPLICATE
|
||||
# define TRIO_FUNC_STRING_EQUAL
|
||||
# define TRIO_FUNC_STRING_EQUAL_CASE
|
||||
# define TRIO_FUNC_STRING_EQUAL_CASE_MAX
|
||||
# define TRIO_FUNC_STRING_EQUAL_MAX
|
||||
# define TRIO_FUNC_STRING_EXTRACT
|
||||
# if !defined(TRIO_PLATFORM_WINCE)
|
||||
# define TRIO_FUNC_STRING_FORMAT_DATE_MAX
|
||||
# endif
|
||||
# define TRIO_FUNC_STRING_GET
|
||||
# define TRIO_FUNC_STRING_INDEX
|
||||
# define TRIO_FUNC_STRING_INDEX_LAST
|
||||
# define TRIO_FUNC_STRING_LENGTH
|
||||
# define TRIO_FUNC_STRING_LOWER
|
||||
# define TRIO_FUNC_STRING_MATCH
|
||||
# define TRIO_FUNC_STRING_MATCH_CASE
|
||||
# define TRIO_FUNC_STRING_SIZE
|
||||
# define TRIO_FUNC_STRING_SUBSTRING
|
||||
# define TRIO_FUNC_STRING_TERMINATE
|
||||
# define TRIO_FUNC_STRING_UPPER
|
||||
|
||||
# define TRIO_FUNC_XSTRING_APPEND
|
||||
# define TRIO_FUNC_XSTRING_APPEND_CHAR
|
||||
# define TRIO_FUNC_XSTRING_APPEND_MAX
|
||||
# define TRIO_FUNC_XSTRING_CONTAINS
|
||||
# define TRIO_FUNC_XSTRING_COPY
|
||||
# define TRIO_FUNC_XSTRING_DUPLICATE
|
||||
# define TRIO_FUNC_XSTRING_EQUAL
|
||||
# define TRIO_FUNC_XSTRING_EQUAL_CASE
|
||||
# define TRIO_FUNC_XSTRING_EQUAL_CASE_MAX
|
||||
# define TRIO_FUNC_XSTRING_EQUAL_MAX
|
||||
# define TRIO_FUNC_XSTRING_MATCH
|
||||
# define TRIO_FUNC_XSTRING_MATCH_CASE
|
||||
# define TRIO_FUNC_XSTRING_SET
|
||||
# define TRIO_FUNC_XSTRING_SUBSTRING
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* String functions
|
||||
*/
|
||||
|
||||
#if defined(TRIO_FUNC_APPEND)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_append
|
||||
TRIO_PROTO((char *target, TRIO_CONST char *source));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_APPEND_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_append_max
|
||||
TRIO_PROTO((char *target, size_t max, TRIO_CONST char *source));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_CONTAINS)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_contains
|
||||
TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *substring));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_COPY)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_copy
|
||||
TRIO_PROTO((char *target, TRIO_CONST char *source));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_COPY_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_copy_max
|
||||
TRIO_PROTO((char *target, size_t max, TRIO_CONST char *source));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_CREATE)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_create
|
||||
TRIO_PROTO((size_t size));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_DESTROY)
|
||||
TRIO_PUBLIC_STRING void
|
||||
trio_destroy
|
||||
TRIO_PROTO((char *string));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_DUPLICATE)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_duplicate
|
||||
TRIO_PROTO((TRIO_CONST char *source));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_DUPLICATE_MAX)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_duplicate_max
|
||||
TRIO_PROTO((TRIO_CONST char *source, size_t max));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_EQUAL)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_equal
|
||||
TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_EQUAL_CASE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_equal_case
|
||||
TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_EQUAL_CASE_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_equal_case_max
|
||||
TRIO_PROTO((TRIO_CONST char *first, size_t max, TRIO_CONST char *second));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_EQUAL_LOCALE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_equal_locale
|
||||
TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_EQUAL_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_equal_max
|
||||
TRIO_PROTO((TRIO_CONST char *first, size_t max, TRIO_CONST char *second));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_ERROR)
|
||||
TRIO_PUBLIC_STRING TRIO_CONST char *
|
||||
trio_error
|
||||
TRIO_PROTO((int));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_FORMAT_DATE_MAX)
|
||||
TRIO_PUBLIC_STRING size_t
|
||||
trio_format_date_max
|
||||
TRIO_PROTO((char *target, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_HASH)
|
||||
TRIO_PUBLIC_STRING unsigned long
|
||||
trio_hash
|
||||
TRIO_PROTO((TRIO_CONST char *string, int type));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_INDEX)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_index
|
||||
TRIO_PROTO((TRIO_CONST char *string, int character));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_INDEX_LAST)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_index_last
|
||||
TRIO_PROTO((TRIO_CONST char *string, int character));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_LENGTH)
|
||||
TRIO_PUBLIC_STRING size_t
|
||||
trio_length
|
||||
TRIO_PROTO((TRIO_CONST char *string));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_LENGTH_MAX)
|
||||
TRIO_PUBLIC_STRING size_t
|
||||
trio_length_max
|
||||
TRIO_PROTO((TRIO_CONST char *string, size_t max));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_LOWER)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_lower
|
||||
TRIO_PROTO((char *target));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_MATCH)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_match
|
||||
TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *pattern));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_MATCH_CASE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_match_case
|
||||
TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *pattern));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_SPAN_FUNCTION)
|
||||
TRIO_PUBLIC_STRING size_t
|
||||
trio_span_function
|
||||
TRIO_PROTO((char *target, TRIO_CONST char *source, int (*Function) TRIO_PROTO((int))));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_SUBSTRING)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_substring
|
||||
TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *substring));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_SUBSTRING_MAX)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_substring_max
|
||||
TRIO_PROTO((TRIO_CONST char *string, size_t max, TRIO_CONST char *substring));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TO_DOUBLE)
|
||||
TRIO_PUBLIC_STRING double
|
||||
trio_to_double
|
||||
TRIO_PROTO((TRIO_CONST char *source, char **endp));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TO_FLOAT)
|
||||
TRIO_PUBLIC_STRING float
|
||||
trio_to_float
|
||||
TRIO_PROTO((TRIO_CONST char *source, char **endp));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TO_LONG)
|
||||
TRIO_PUBLIC_STRING long
|
||||
trio_to_long
|
||||
TRIO_PROTO((TRIO_CONST char *source, char **endp, int base));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TO_LOWER)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_to_lower
|
||||
TRIO_PROTO((int source));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TO_LONG_DOUBLE)
|
||||
TRIO_PUBLIC_STRING trio_long_double_t
|
||||
trio_to_long_double
|
||||
TRIO_PROTO((TRIO_CONST char *source, char **endp));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TO_UNSIGNED_LONG)
|
||||
TRIO_PUBLIC_STRING unsigned long
|
||||
trio_to_unsigned_long
|
||||
TRIO_PROTO((TRIO_CONST char *source, char **endp, int base));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TO_UPPER)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_to_upper
|
||||
TRIO_PROTO((int source));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_TOKENIZE)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_tokenize
|
||||
TRIO_PROTO((char *string, TRIO_CONST char *delimiters));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_UPPER)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_upper
|
||||
TRIO_PROTO((char *target));
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Dynamic string functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Opaque type for dynamic strings
|
||||
*/
|
||||
|
||||
typedef struct _trio_string_t trio_string_t;
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_APPEND)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_append
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_CONTAINS)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_contains
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_COPY)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_copy
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_CREATE)
|
||||
TRIO_PUBLIC_STRING trio_string_t *
|
||||
trio_string_create
|
||||
TRIO_PROTO((int initial_size));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_DESTROY)
|
||||
TRIO_PUBLIC_STRING void
|
||||
trio_string_destroy
|
||||
TRIO_PROTO((trio_string_t *self));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_DUPLICATE)
|
||||
TRIO_PUBLIC_STRING trio_string_t *
|
||||
trio_string_duplicate
|
||||
TRIO_PROTO((trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_EQUAL)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_equal
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_EQUAL_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_equal_max
|
||||
TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *second));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_EQUAL_CASE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_equal_case
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_EQUAL_CASE_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_equal_case_max
|
||||
TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_EXTRACT)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_string_extract
|
||||
TRIO_PROTO((trio_string_t *self));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_FORMAT_DATE_MAX)
|
||||
TRIO_PUBLIC_STRING size_t
|
||||
trio_string_format_date_max
|
||||
TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_GET)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_string_get
|
||||
TRIO_PROTO((trio_string_t *self, int offset));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_INDEX)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_string_index
|
||||
TRIO_PROTO((trio_string_t *self, int character));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_INDEX_LAST)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_string_index_last
|
||||
TRIO_PROTO((trio_string_t *self, int character));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_LENGTH)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_length
|
||||
TRIO_PROTO((trio_string_t *self));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_LOWER)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_lower
|
||||
TRIO_PROTO((trio_string_t *self));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_MATCH)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_match
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_MATCH_CASE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_match_case
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_SIZE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_size
|
||||
TRIO_PROTO((trio_string_t *self));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_SUBSTRING)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_string_substring
|
||||
TRIO_PROTO((trio_string_t *self, trio_string_t *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_TERMINATE)
|
||||
TRIO_PUBLIC_STRING void
|
||||
trio_string_terminate
|
||||
TRIO_PROTO((trio_string_t *self));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_STRING_UPPER)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_string_upper
|
||||
TRIO_PROTO((trio_string_t *self));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_APPEND)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_append
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_append_char
|
||||
TRIO_PROTO((trio_string_t *self, char character));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_APPEND_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_append_max
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other, size_t max));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_CONTAINS)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_contains
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_COPY)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_copy
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_DUPLICATE)
|
||||
TRIO_PUBLIC_STRING trio_string_t *
|
||||
trio_xstring_duplicate
|
||||
TRIO_PROTO((TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_EQUAL)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_equal
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_EQUAL_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_equal_max
|
||||
TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_EQUAL_CASE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_equal_case
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_EQUAL_CASE_MAX)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_equal_case_max
|
||||
TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_MATCH)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_match
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_MATCH_CASE)
|
||||
TRIO_PUBLIC_STRING int
|
||||
trio_xstring_match_case
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_SET)
|
||||
TRIO_PUBLIC_STRING void
|
||||
trio_xstring_set
|
||||
TRIO_PROTO((trio_string_t *self, char *buffer));
|
||||
#endif
|
||||
|
||||
#if defined(TRIO_FUNC_XSTRING_SUBSTRING)
|
||||
TRIO_PUBLIC_STRING char *
|
||||
trio_xstring_substring
|
||||
TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TRIO_TRIOSTR_H */
|
103
mednafen/lepacker.h
Normal file
103
mednafen/lepacker.h
Normal file
@ -0,0 +1,103 @@
|
||||
#ifndef __MDFN_LEPACKER_H
|
||||
#define __MDFN_LEPACKER_H
|
||||
|
||||
#include "mednafen.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Little-endian byte packer(and unpacker). */
|
||||
|
||||
namespace MDFN
|
||||
{
|
||||
|
||||
class LEPacker;
|
||||
class LEPackable
|
||||
{
|
||||
public:
|
||||
virtual void pack(LEPacker &lep) = 0;
|
||||
};
|
||||
|
||||
class LEPacker : public std::vector<uint8>
|
||||
{
|
||||
public:
|
||||
|
||||
LEPacker() : read_mode(0), read_pos(0), randomize_read_mode(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void set_read_mode(bool new_read_mode, bool new_randomize_read_mode = false)
|
||||
{
|
||||
read_mode = new_read_mode;
|
||||
randomize_read_mode = new_randomize_read_mode;
|
||||
}
|
||||
|
||||
inline void reset_read_pos(void)
|
||||
{
|
||||
read_pos = 0;
|
||||
}
|
||||
|
||||
void operator^(LEPackable &o)
|
||||
{
|
||||
o.pack(*this);
|
||||
}
|
||||
|
||||
template<typename T> INLINE void operator^(T &val)
|
||||
{
|
||||
size_type csize = size();
|
||||
|
||||
if(read_mode)
|
||||
{
|
||||
if((read_pos + sizeof(T)) > csize)
|
||||
throw(std::out_of_range("LEPacker::operator^"));
|
||||
|
||||
uint8 *ptr = &(*this)[read_pos];
|
||||
val = 0;
|
||||
|
||||
if(randomize_read_mode)
|
||||
{
|
||||
for(unsigned int n = 0; n < sizeof(T); n++)
|
||||
val |= ((T)((rand() >> 4) & 0xFF)) << (n << 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(unsigned int n = 0; n < sizeof(T); n++)
|
||||
val |= ((T)ptr[n]) << (n << 3);
|
||||
}
|
||||
|
||||
read_pos += sizeof(T);
|
||||
}
|
||||
else
|
||||
{
|
||||
resize(csize + sizeof(T));
|
||||
|
||||
uint8 *ptr = &(*this)[csize];
|
||||
|
||||
for(unsigned int n = 0; n < sizeof(T); n++)
|
||||
ptr[n] = val >> (n << 3);
|
||||
}
|
||||
}
|
||||
|
||||
INLINE void operator^(bool &val)
|
||||
{
|
||||
uint8 tmp = val;
|
||||
|
||||
(*this) ^ tmp;
|
||||
|
||||
if(read_mode)
|
||||
val = tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool read_mode;
|
||||
uint64 read_pos;
|
||||
bool randomize_read_mode;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
209
mednafen/masmem.h
Normal file
209
mednafen/masmem.h
Normal file
@ -0,0 +1,209 @@
|
||||
#ifndef __MDFN_PSX_MASMEM_H
|
||||
#define __MDFN_PSX_MASMEM_H
|
||||
|
||||
// TODO, WIP (big-endian stores and loads not fully supported yet)
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
#define MAS_NATIVE_IS_BIGENDIAN 0
|
||||
#else
|
||||
#define MAS_NATIVE_IS_BIGENDIAN 1
|
||||
#endif
|
||||
|
||||
static INLINE uint16 LoadU16_RBO(const uint16 *a)
|
||||
{
|
||||
#ifdef ARCH_POWERPC
|
||||
uint16 tmp;
|
||||
|
||||
__asm__ ("lhbrx %0, %y1" : "=r"(tmp) : "Z"(*a));
|
||||
|
||||
return(tmp);
|
||||
|
||||
#else
|
||||
uint16 tmp = *a;
|
||||
return((tmp << 8) | (tmp >> 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE uint32 LoadU32_RBO(const uint32 *a)
|
||||
{
|
||||
#ifdef ARCH_POWERPC
|
||||
uint32 tmp;
|
||||
|
||||
__asm__ ("lwbrx %0, %y1" : "=r"(tmp) : "Z"(*a));
|
||||
|
||||
return(tmp);
|
||||
#else
|
||||
uint32 tmp = *a;
|
||||
return((tmp << 24) | ((tmp & 0xFF00) << 8) | ((tmp >> 8) & 0xFF00) | (tmp >> 24));
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void StoreU16_RBO(uint16 *a, const uint16 v)
|
||||
{
|
||||
#ifdef ARCH_POWERPC
|
||||
__asm__ ("sthbrx %0, %y1" : : "r"(v), "Z"(*a));
|
||||
#else
|
||||
uint16 tmp = (v << 8) | (v >> 8);
|
||||
*a = tmp;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void StoreU32_RBO(uint32 *a, const uint32 v)
|
||||
{
|
||||
#ifdef ARCH_POWERPC
|
||||
__asm__ ("stwbrx %0, %y1" : : "r"(v), "Z"(*a));
|
||||
#else
|
||||
uint32 tmp = (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24);
|
||||
*a = tmp;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE uint16 LoadU16_LE(const uint16 *a)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
return LoadU16_RBO(a);
|
||||
#else
|
||||
return *a;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE uint32 LoadU32_LE(const uint32 *a)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
return LoadU32_RBO(a);
|
||||
#else
|
||||
return *a;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void StoreU16_LE(uint16 *a, const uint16 v)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
StoreU16_RBO(a, v);
|
||||
#else
|
||||
*a = v;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void StoreU32_LE(uint32 *a, const uint32 v)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
StoreU32_RBO(a, v);
|
||||
#else
|
||||
*a = v;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// address must not be >= size specified by template parameter, and address must be a multiple of the byte-size of the
|
||||
// unit(1,2,4) being read(except for Read/WriteU24, which only needs to be byte-aligned).
|
||||
//
|
||||
// max_unit_type should be uint16 or uint32
|
||||
//
|
||||
// pre_padding and post_padding are specified in units of sizeof(max_unit_type).
|
||||
//
|
||||
template<unsigned size, typename max_unit_type, bool big_endian, unsigned pre_padding_count, unsigned post_padding_count>
|
||||
struct MultiAccessSizeMem
|
||||
{
|
||||
max_unit_type pre_padding[pre_padding_count];
|
||||
|
||||
union
|
||||
{
|
||||
uint8 data8[size];
|
||||
uint16 data16[size / sizeof(uint16)];
|
||||
uint32 data32[size / sizeof(uint32)];
|
||||
};
|
||||
|
||||
max_unit_type post_padding[post_padding_count];
|
||||
|
||||
INLINE uint8 ReadU8(uint32 address)
|
||||
{
|
||||
return data8[address];
|
||||
}
|
||||
|
||||
INLINE uint16 ReadU16(uint32 address)
|
||||
{
|
||||
if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
|
||||
return *(uint16*)(((uint8*)data16) + address);
|
||||
else
|
||||
return LoadU16_RBO((uint16*)(((uint8*)data16) + address));
|
||||
}
|
||||
|
||||
INLINE uint32 ReadU32(uint32 address)
|
||||
{
|
||||
if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
|
||||
return *(uint32*)(((uint8*)data32) + address);
|
||||
else
|
||||
return LoadU32_RBO((uint32*)(((uint8*)data32) + address));
|
||||
}
|
||||
|
||||
INLINE uint32 ReadU24(uint32 address)
|
||||
{
|
||||
uint32 ret;
|
||||
|
||||
if(!big_endian)
|
||||
{
|
||||
ret = ReadU8(address) | (ReadU8(address + 1) << 8) | (ReadU8(address + 2) << 16);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
INLINE void WriteU8(uint32 address, uint8 value)
|
||||
{
|
||||
data8[address] = value;
|
||||
}
|
||||
|
||||
INLINE void WriteU16(uint32 address, uint16 value)
|
||||
{
|
||||
if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
|
||||
*(uint16*)(((uint8*)data16) + address) = value;
|
||||
else
|
||||
StoreU16_RBO((uint16*)(((uint8*)data16) + address), value);
|
||||
}
|
||||
|
||||
INLINE void WriteU32(uint32 address, uint32 value)
|
||||
{
|
||||
if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
|
||||
*(uint32*)(((uint8*)data32) + address) = value;
|
||||
else
|
||||
StoreU32_RBO((uint32*)(((uint8*)data32) + address), value);
|
||||
}
|
||||
|
||||
INLINE void WriteU24(uint32 address, uint32 value)
|
||||
{
|
||||
if(!big_endian)
|
||||
{
|
||||
WriteU8(address + 0, value >> 0);
|
||||
WriteU8(address + 1, value >> 8);
|
||||
WriteU8(address + 2, value >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE T Read(uint32 address)
|
||||
{
|
||||
if(sizeof(T) == 4)
|
||||
return(ReadU32(address));
|
||||
else if(sizeof(T) == 2)
|
||||
return(ReadU16(address));
|
||||
else
|
||||
return(ReadU8(address));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void Write(uint32 address, T value)
|
||||
{
|
||||
if(sizeof(T) == 4)
|
||||
WriteU32(address, value);
|
||||
else if(sizeof(T) == 2)
|
||||
WriteU16(address, value);
|
||||
else
|
||||
WriteU8(address, value);
|
||||
}
|
||||
};
|
||||
|
||||
#undef MAS_NATIVE_IS_BIGENDIAN
|
||||
|
||||
#endif
|
36
mednafen/math_ops.cpp
Normal file
36
mednafen/math_ops.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "mednafen.h"
|
||||
#include "math_ops.h"
|
||||
|
||||
// Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
// Rounds up to the nearest power of 2.
|
||||
uint32 round_up_pow2(uint32 v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
|
||||
v += (v == 0);
|
||||
|
||||
return(v);
|
||||
}
|
||||
|
44
mednafen/math_ops.h
Normal file
44
mednafen/math_ops.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef __MDFN_MATH_OPS_H
|
||||
#define __MDFN_MATH_OPS_H
|
||||
|
||||
uint32 round_up_pow2(uint32 v);
|
||||
|
||||
static INLINE uint32 uilog2(uint32 v)
|
||||
{
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
|
||||
|
||||
static const uint32 MultiplyDeBruijnBitPosition[32] =
|
||||
{
|
||||
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
||||
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
||||
};
|
||||
|
||||
v |= v >> 1; // first round down to one less than a power of 2
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
|
||||
return MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];
|
||||
}
|
||||
|
||||
// Some compilers' optimizers and some platforms might fubar the generated code from these macros,
|
||||
// so some tests are run in...tests.cpp
|
||||
#define sign_8_to_s16(_value) ((int16)(int8)(_value))
|
||||
#define sign_9_to_s16(_value) (((int16)((unsigned int)(_value) << 7)) >> 7)
|
||||
#define sign_10_to_s16(_value) (((int16)((uint32)(_value) << 6)) >> 6)
|
||||
#define sign_11_to_s16(_value) (((int16)((uint32)(_value) << 5)) >> 5)
|
||||
#define sign_12_to_s16(_value) (((int16)((uint32)(_value) << 4)) >> 4)
|
||||
#define sign_13_to_s16(_value) (((int16)((uint32)(_value) << 3)) >> 3)
|
||||
#define sign_14_to_s16(_value) (((int16)((uint32)(_value) << 2)) >> 2)
|
||||
#define sign_15_to_s16(_value) (((int16)((uint32)(_value) << 1)) >> 1)
|
||||
|
||||
// This obviously won't convert higher-than-32 bit numbers to signed 32-bit ;)
|
||||
// Also, this shouldn't be used for 8-bit and 16-bit signed numbers, since you can
|
||||
// convert those faster with typecasts...
|
||||
#define sign_x_to_s32(_bits, _value) (((int32)((uint32)(_value) << (32 - _bits))) >> (32 - _bits))
|
||||
|
||||
|
||||
#define INT16_TO_BCD(A) ((((((A) % 100) / 10) * 16 + ((A) % 10))) | (((((((A) / 100) % 100) / 10) * 16 + (((A) / 100) % 10))) << 8)) // convert INT16 --> BCD
|
||||
|
||||
#endif
|
260
mednafen/md5.cpp
Normal file
260
mednafen/md5.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* RFC 1321 compliant MD5 implementation,
|
||||
* by Christophe Devine <devine@cr0.net>;
|
||||
* this program is licensed under the GPL.
|
||||
*/
|
||||
/* Converted to C++ for use in Mednafen */
|
||||
|
||||
#include "mednafen-types.h"
|
||||
#include <string.h>
|
||||
#include "md5.h"
|
||||
|
||||
#define GET_UINT32(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (uint32) (b)[(i) + 3] << 24 ) \
|
||||
| ( (uint32) (b)[(i) + 2] << 16 ) \
|
||||
| ( (uint32) (b)[(i) + 1] << 8 ) \
|
||||
| ( (uint32) (b)[(i) ] ); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (uint8) ( (n) ); \
|
||||
(b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
|
||||
(b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
|
||||
(b)[(i) + 3] = (uint8) ( (n) >> 24 ); \
|
||||
}
|
||||
|
||||
md5_context::md5_context(void)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
md5_context::~md5_context(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void md5_context::starts(void)
|
||||
{
|
||||
total[0] = 0;
|
||||
total[1] = 0;
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xEFCDAB89;
|
||||
state[2] = 0x98BADCFE;
|
||||
state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void md5_context::process(const uint8 data[64])
|
||||
{
|
||||
uint32 A, B, C, D, X[16];
|
||||
|
||||
GET_UINT32( X[0], data, 0 );
|
||||
GET_UINT32( X[1], data, 4 );
|
||||
GET_UINT32( X[2], data, 8 );
|
||||
GET_UINT32( X[3], data, 12 );
|
||||
GET_UINT32( X[4], data, 16 );
|
||||
GET_UINT32( X[5], data, 20 );
|
||||
GET_UINT32( X[6], data, 24 );
|
||||
GET_UINT32( X[7], data, 28 );
|
||||
GET_UINT32( X[8], data, 32 );
|
||||
GET_UINT32( X[9], data, 36 );
|
||||
GET_UINT32( X[10], data, 40 );
|
||||
GET_UINT32( X[11], data, 44 );
|
||||
GET_UINT32( X[12], data, 48 );
|
||||
GET_UINT32( X[13], data, 52 );
|
||||
GET_UINT32( X[14], data, 56 );
|
||||
GET_UINT32( X[15], data, 60 );
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) \
|
||||
{ \
|
||||
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
|
||||
}
|
||||
|
||||
A = state[0];
|
||||
B = state[1];
|
||||
C = state[2];
|
||||
D = state[3];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P( A, B, C, D, 0, 7, 0xD76AA478 );
|
||||
P( D, A, B, C, 1, 12, 0xE8C7B756 );
|
||||
P( C, D, A, B, 2, 17, 0x242070DB );
|
||||
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
|
||||
P( A, B, C, D, 4, 7, 0xF57C0FAF );
|
||||
P( D, A, B, C, 5, 12, 0x4787C62A );
|
||||
P( C, D, A, B, 6, 17, 0xA8304613 );
|
||||
P( B, C, D, A, 7, 22, 0xFD469501 );
|
||||
P( A, B, C, D, 8, 7, 0x698098D8 );
|
||||
P( D, A, B, C, 9, 12, 0x8B44F7AF );
|
||||
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
|
||||
P( B, C, D, A, 11, 22, 0x895CD7BE );
|
||||
P( A, B, C, D, 12, 7, 0x6B901122 );
|
||||
P( D, A, B, C, 13, 12, 0xFD987193 );
|
||||
P( C, D, A, B, 14, 17, 0xA679438E );
|
||||
P( B, C, D, A, 15, 22, 0x49B40821 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P( A, B, C, D, 1, 5, 0xF61E2562 );
|
||||
P( D, A, B, C, 6, 9, 0xC040B340 );
|
||||
P( C, D, A, B, 11, 14, 0x265E5A51 );
|
||||
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
|
||||
P( A, B, C, D, 5, 5, 0xD62F105D );
|
||||
P( D, A, B, C, 10, 9, 0x02441453 );
|
||||
P( C, D, A, B, 15, 14, 0xD8A1E681 );
|
||||
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
|
||||
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
|
||||
P( D, A, B, C, 14, 9, 0xC33707D6 );
|
||||
P( C, D, A, B, 3, 14, 0xF4D50D87 );
|
||||
P( B, C, D, A, 8, 20, 0x455A14ED );
|
||||
P( A, B, C, D, 13, 5, 0xA9E3E905 );
|
||||
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
|
||||
P( C, D, A, B, 7, 14, 0x676F02D9 );
|
||||
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P( A, B, C, D, 5, 4, 0xFFFA3942 );
|
||||
P( D, A, B, C, 8, 11, 0x8771F681 );
|
||||
P( C, D, A, B, 11, 16, 0x6D9D6122 );
|
||||
P( B, C, D, A, 14, 23, 0xFDE5380C );
|
||||
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
|
||||
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
|
||||
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
|
||||
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
|
||||
P( A, B, C, D, 13, 4, 0x289B7EC6 );
|
||||
P( D, A, B, C, 0, 11, 0xEAA127FA );
|
||||
P( C, D, A, B, 3, 16, 0xD4EF3085 );
|
||||
P( B, C, D, A, 6, 23, 0x04881D05 );
|
||||
P( A, B, C, D, 9, 4, 0xD9D4D039 );
|
||||
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
|
||||
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
|
||||
P( B, C, D, A, 2, 23, 0xC4AC5665 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P( A, B, C, D, 0, 6, 0xF4292244 );
|
||||
P( D, A, B, C, 7, 10, 0x432AFF97 );
|
||||
P( C, D, A, B, 14, 15, 0xAB9423A7 );
|
||||
P( B, C, D, A, 5, 21, 0xFC93A039 );
|
||||
P( A, B, C, D, 12, 6, 0x655B59C3 );
|
||||
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
|
||||
P( C, D, A, B, 10, 15, 0xFFEFF47D );
|
||||
P( B, C, D, A, 1, 21, 0x85845DD1 );
|
||||
P( A, B, C, D, 8, 6, 0x6FA87E4F );
|
||||
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
|
||||
P( C, D, A, B, 6, 15, 0xA3014314 );
|
||||
P( B, C, D, A, 13, 21, 0x4E0811A1 );
|
||||
P( A, B, C, D, 4, 6, 0xF7537E82 );
|
||||
P( D, A, B, C, 11, 10, 0xBD3AF235 );
|
||||
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
|
||||
P( B, C, D, A, 9, 21, 0xEB86D391 );
|
||||
|
||||
#undef F
|
||||
|
||||
state[0] += A;
|
||||
state[1] += B;
|
||||
state[2] += C;
|
||||
state[3] += D;
|
||||
}
|
||||
|
||||
void md5_context::update(const uint8 *input, uint32 length )
|
||||
{
|
||||
uint32 left, fill;
|
||||
|
||||
if( ! length ) return;
|
||||
|
||||
left = ( total[0] >> 3 ) & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
total[0] += length << 3;
|
||||
total[1] += length >> 29;
|
||||
|
||||
total[0] &= 0xFFFFFFFF;
|
||||
total[1] += total[0] < ( length << 3 );
|
||||
|
||||
if( left && length >= fill )
|
||||
{
|
||||
memcpy( (void *) (buffer + left), (void *) input, fill );
|
||||
process(buffer );
|
||||
length -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while( length >= 64 )
|
||||
{
|
||||
process(input );
|
||||
length -= 64;
|
||||
input += 64;
|
||||
}
|
||||
|
||||
if( length )
|
||||
{
|
||||
memcpy( (void *) (buffer + left), (void *) input, length );
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8 md5_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void md5_context::finish(uint8 digest[16] )
|
||||
{
|
||||
uint32 last, padn;
|
||||
uint8 msglen[8];
|
||||
|
||||
PUT_UINT32( total[0], msglen, 0 );
|
||||
PUT_UINT32( total[1], msglen, 4 );
|
||||
|
||||
last = ( total[0] >> 3 ) & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
update( md5_padding, padn );
|
||||
update( msglen, 8 );
|
||||
|
||||
PUT_UINT32( state[0], digest, 0 );
|
||||
PUT_UINT32( state[1], digest, 4 );
|
||||
PUT_UINT32( state[2], digest, 8 );
|
||||
PUT_UINT32( state[3], digest, 12 );
|
||||
}
|
||||
|
||||
|
||||
/* Uses a static buffer, so beware of how it's used. */
|
||||
//static
|
||||
std::string md5_context::asciistr(const uint8 digest[16], bool borked_order)
|
||||
{
|
||||
static char str[33];
|
||||
static char trans[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
||||
int x;
|
||||
|
||||
for(x=0;x<16;x++)
|
||||
{
|
||||
if(borked_order)
|
||||
{
|
||||
str[x*2]=trans[digest[x]&0x0F];
|
||||
str[x*2+1]=trans[digest[x]>>4];
|
||||
}
|
||||
else
|
||||
{
|
||||
str[x*2+1]=trans[digest[x]&0x0F];
|
||||
str[x*2]=trans[digest[x]>>4];
|
||||
}
|
||||
}
|
||||
return(std::string(str));
|
||||
}
|
41
mednafen/md5.h
Normal file
41
mednafen/md5.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef _MD5_H
|
||||
#define _MD5_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class md5_context
|
||||
{
|
||||
public:
|
||||
md5_context(void);
|
||||
~md5_context(void);
|
||||
|
||||
static std::string asciistr(const uint8 digest[16], bool borked_order);
|
||||
std::string asciistr(void);
|
||||
void starts(void);
|
||||
void update(const uint8 *input, uint32 length);
|
||||
inline void update_u32_as_lsb(const uint32 input)
|
||||
{
|
||||
uint8 buf[4];
|
||||
|
||||
buf[0] = input >> 0;
|
||||
buf[1] = input >> 8;
|
||||
buf[2] = input >> 16;
|
||||
buf[3] = input >> 24;
|
||||
|
||||
update(buf, 4);
|
||||
}
|
||||
|
||||
inline void update_string(const char *string)
|
||||
{
|
||||
update((const uint8 *)string, strlen(string));
|
||||
}
|
||||
void finish(uint8 digest[16]);
|
||||
|
||||
private:
|
||||
void process(const uint8 data[64]);
|
||||
uint32 total[2];
|
||||
uint32 state[4];
|
||||
uint8 buffer[64];
|
||||
};
|
||||
|
||||
#endif /* md5.h */
|
160
mednafen/mednafen-driver.h
Normal file
160
mednafen/mednafen-driver.h
Normal file
@ -0,0 +1,160 @@
|
||||
#ifndef __MDFN_MEDNAFEN_DRIVER_H
|
||||
#define __MDFN_MEDNAFEN_DRIVER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "settings-common.h"
|
||||
|
||||
extern std::vector<MDFNGI *>MDFNSystems;
|
||||
|
||||
/* Indent stdout newlines +- "indent" amount */
|
||||
void MDFN_indent(int indent);
|
||||
void MDFN_printf(const char *format, ...) throw() MDFN_FORMATSTR(printf, 1, 2);
|
||||
|
||||
#define MDFNI_printf MDFN_printf
|
||||
|
||||
/* Displays an error. Can block or not. */
|
||||
void MDFND_PrintError(const char *s);
|
||||
void MDFND_Message(const char *s);
|
||||
|
||||
uint32 MDFND_GetTime(void);
|
||||
void MDFND_Sleep(uint32 ms);
|
||||
|
||||
// Synchronize virtual time to actual time using members of espec:
|
||||
//
|
||||
// MasterCycles and MasterCyclesALMS (coupled with MasterClock of MDFNGI)
|
||||
// and/or
|
||||
// SoundBuf, SoundBufSize, and SoundBufSizeALMS
|
||||
//
|
||||
// ...and after synchronization, update the data pointed to by the pointers passed to MDFNI_SetInput().
|
||||
// DO NOT CALL MDFN_* or MDFNI_* functions from within MDFND_MidSync().
|
||||
// Calling MDFN_printf(), MDFN_DispMessage(),and MDFND_PrintError() are ok, though.
|
||||
//
|
||||
// If you do not understand how to implement this function, you can leave it empty at first, but know that doing so
|
||||
// will subtly break at least one PC Engine game(Takeda Shingen), and raise input latency on some other PC Engine games.
|
||||
void MDFND_MidSync(const EmulateSpecStruct *espec);
|
||||
|
||||
/* Being threading support. */
|
||||
// Mostly based off SDL's prototypes and semantics.
|
||||
// Driver code should actually define MDFN_Thread and MDFN_Mutex.
|
||||
|
||||
struct MDFN_Thread;
|
||||
struct MDFN_Mutex;
|
||||
|
||||
MDFN_Thread *MDFND_CreateThread(int (*fn)(void *), void *data);
|
||||
void MDFND_WaitThread(MDFN_Thread *thread, int *status);
|
||||
void MDFND_KillThread(MDFN_Thread *thread);
|
||||
|
||||
MDFN_Mutex *MDFND_CreateMutex(void);
|
||||
void MDFND_DestroyMutex(MDFN_Mutex *mutex);
|
||||
int MDFND_LockMutex(MDFN_Mutex *mutex);
|
||||
int MDFND_UnlockMutex(MDFN_Mutex *mutex);
|
||||
|
||||
/* End threading support. */
|
||||
|
||||
void MDFNI_Reset(void);
|
||||
void MDFNI_Power(void);
|
||||
|
||||
/* Called from the physical CD disc reading code. */
|
||||
bool MDFND_ExitBlockingLoop(void);
|
||||
|
||||
/* path = path of game/file to load. returns NULL on failure. */
|
||||
MDFNGI *MDFNI_LoadGame(const char *force_module, const char *path);
|
||||
|
||||
MDFNGI *MDFNI_LoadCD(const char *sysname, const char *devicename);
|
||||
|
||||
// Call this function as early as possible, even before MDFNI_Initialize()
|
||||
bool MDFNI_InitializeModules(const std::vector<MDFNGI *> &ExternalSystems);
|
||||
|
||||
/* allocates memory. 0 on failure, 1 on success. */
|
||||
/* Also pass it the base directory to load the configuration file. */
|
||||
int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &DriverSettings);
|
||||
|
||||
/* Sets the base directory(save states, snapshots, etc. are saved in directories
|
||||
below this directory. */
|
||||
void MDFNI_SetBaseDirectory(const char *dir);
|
||||
|
||||
/* Call only when a game is loaded. */
|
||||
int MDFNI_NetplayStart(uint32 local_players, uint32 netmerge, const std::string &nickname, const std::string &game_key, const std::string &connect_password);
|
||||
|
||||
/* Emulates a frame. */
|
||||
void MDFNI_Emulate(EmulateSpecStruct *espec);
|
||||
|
||||
/* Closes currently loaded game */
|
||||
void MDFNI_CloseGame(void);
|
||||
|
||||
/* Deallocates all allocated memory. Call after MDFNI_Emulate() returns. */
|
||||
void MDFNI_Kill(void);
|
||||
|
||||
void MDFN_DispMessage(const char *format, ...) throw() MDFN_FORMATSTR(printf, 1, 2);
|
||||
#define MDFNI_DispMessage MDFN_DispMessage
|
||||
|
||||
uint32 MDFNI_CRC32(uint32 crc, uint8 *buf, uint32 len);
|
||||
|
||||
// NES hackish function. Should abstract in the future.
|
||||
int MDFNI_DatachSet(const uint8 *rcode);
|
||||
|
||||
void MDFNI_DoRewind(void);
|
||||
|
||||
void MDFNI_SetLayerEnableMask(uint64 mask);
|
||||
|
||||
void MDFNI_SetInput(int port, const char *type, void *ptr, uint32 dsize);
|
||||
|
||||
//int MDFNI_DiskInsert(int oride);
|
||||
//int MDFNI_DiskEject(void);
|
||||
//int MDFNI_DiskSelect(void);
|
||||
|
||||
// Arcade-support functions
|
||||
// We really need to reexamine how we should abstract this, considering the initial state of the DIP switches,
|
||||
// and moving the DIP switch drawing code to the driver side.
|
||||
void MDFNI_ToggleDIP(int which);
|
||||
void MDFNI_InsertCoin(void);
|
||||
void MDFNI_ToggleDIPView(void);
|
||||
|
||||
// Disk/Disc-based system support functions
|
||||
void MDFNI_DiskSelect(int which);
|
||||
void MDFNI_DiskSelect();
|
||||
void MDFNI_DiskInsert();
|
||||
void MDFNI_DiskEject();
|
||||
|
||||
// New removable media interface(TODO!)
|
||||
//
|
||||
#if 0
|
||||
|
||||
struct MediumInfoStruct
|
||||
{
|
||||
const char *name; // More descriptive name, "Al Gore's Grand Adventure, Disk 1 of 7" ???
|
||||
// (remember, Do utf8->utf32->utf8 for truncation for display)
|
||||
const char *set_member_name; // "Disk 1 of 4, Side A", "Disk 3 of 4, Side B", "Disc 2 of 5" ???? (Disk M of N, where N is related to the number of entries
|
||||
// in the structure???)
|
||||
};
|
||||
|
||||
struct DriveInfoStruct
|
||||
{
|
||||
const char *name;
|
||||
const char *description;
|
||||
const MediumInfoStruct *possible_media;
|
||||
//bool
|
||||
//const char *eject_state_name; // Like "Lid Open", or "Tray Ejected"
|
||||
//const char *insert_state_name; // Like "
|
||||
};
|
||||
|
||||
// Entry point
|
||||
DriveInfoStruct *Drives;
|
||||
|
||||
void MDFNI_SetDriveMedium(unsigned drive_index, unsigned int medium_index, unsigned state_id);
|
||||
#endif
|
||||
|
||||
|
||||
bool MDFNI_StartAVRecord(const char *path, double SoundRate);
|
||||
void MDFNI_StopAVRecord(void);
|
||||
|
||||
bool MDFNI_StartWAVRecord(const char *path, double SoundRate);
|
||||
void MDFNI_StopWAVRecord(void);
|
||||
|
||||
void MDFNI_DumpModulesDef(const char *fn);
|
||||
|
||||
|
||||
#endif
|
207
mednafen/mednafen-endian.h
Normal file
207
mednafen/mednafen-endian.h
Normal file
@ -0,0 +1,207 @@
|
||||
#ifndef __MDFN_ENDIAN_H
|
||||
#define __MDFN_ENDIAN_H
|
||||
|
||||
#ifdef MSB_FIRST
|
||||
#ifdef LSB_FIRST
|
||||
#error Only define one of LSB_FIRST and MSB_FIRST
|
||||
#endif
|
||||
|
||||
#ifndef le32toh
|
||||
#define le32toh(l) ((((l)>>24) & 0xff) | (((l)>>8) & 0xff00) \
|
||||
| (((l)<<8) & 0xff0000) | (((l)<<24) & 0xff000000))
|
||||
#endif
|
||||
#ifndef le16toh
|
||||
#define le16toh(l) ((((l)>>8) & 0xff) | (((l)<<8) & 0xff00))
|
||||
#endif
|
||||
#else
|
||||
#ifndef le32toh
|
||||
#define le32toh(l) (l)
|
||||
#endif
|
||||
#ifndef le16toh
|
||||
#define le16toh(l) (l)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef htole32
|
||||
#define htole32 le32toh
|
||||
#endif
|
||||
|
||||
#ifndef htole16
|
||||
#define htole16 le16toh
|
||||
#endif
|
||||
|
||||
|
||||
int write16le(uint16 b, FILE *fp);
|
||||
int write32le(uint32 b, FILE *fp);
|
||||
int read32le(uint32 *Bufo, FILE *fp);
|
||||
|
||||
void Endian_A16_Swap(void *src, uint32 nelements);
|
||||
void Endian_A32_Swap(void *src, uint32 nelements);
|
||||
void Endian_A64_Swap(void *src, uint32 nelements);
|
||||
|
||||
void Endian_A16_NE_to_LE(void *src, uint32 nelements);
|
||||
void Endian_A32_NE_to_LE(void *src, uint32 nelements);
|
||||
void Endian_A64_NE_to_LE(void *src, uint32 nelements);
|
||||
|
||||
void Endian_A16_LE_to_NE(void *src, uint32 nelements);
|
||||
void Endian_A16_BE_to_NE(void *src, uint32 nelements);
|
||||
void Endian_A32_LE_to_NE(void *src, uint32 nelements);
|
||||
void Endian_A64_LE_to_NE(void *src, uint32 nelements);
|
||||
|
||||
void Endian_V_LE_to_NE(void *src, uint32 bytesize);
|
||||
void Endian_V_NE_to_LE(void *src, uint32 bytesize);
|
||||
|
||||
void FlipByteOrder(uint8 *src, uint32 count);
|
||||
|
||||
// The following functions can encode/decode to unaligned addresses.
|
||||
|
||||
static INLINE void MDFN_en16lsb(uint8 *buf, uint16 morp)
|
||||
{
|
||||
buf[0]=morp;
|
||||
buf[1]=morp>>8;
|
||||
}
|
||||
|
||||
static INLINE void MDFN_en24lsb(uint8 *buf, uint32 morp)
|
||||
{
|
||||
buf[0]=morp;
|
||||
buf[1]=morp>>8;
|
||||
buf[2]=morp>>16;
|
||||
}
|
||||
|
||||
|
||||
static INLINE void MDFN_en32lsb(uint8 *buf, uint32 morp)
|
||||
{
|
||||
buf[0]=morp;
|
||||
buf[1]=morp>>8;
|
||||
buf[2]=morp>>16;
|
||||
buf[3]=morp>>24;
|
||||
}
|
||||
|
||||
static INLINE void MDFN_en64lsb(uint8 *buf, uint64 morp)
|
||||
{
|
||||
buf[0]=morp >> 0;
|
||||
buf[1]=morp >> 8;
|
||||
buf[2]=morp >> 16;
|
||||
buf[3]=morp >> 24;
|
||||
buf[4]=morp >> 32;
|
||||
buf[5]=morp >> 40;
|
||||
buf[6]=morp >> 48;
|
||||
buf[7]=morp >> 56;
|
||||
}
|
||||
|
||||
|
||||
static INLINE void MDFN_en16msb(uint8 *buf, uint16 morp)
|
||||
{
|
||||
buf[0] = morp >> 8;
|
||||
buf[1] = morp;
|
||||
}
|
||||
|
||||
static INLINE void MDFN_en24msb(uint8 *buf, uint32 morp)
|
||||
{
|
||||
buf[0] = morp >> 16;
|
||||
buf[1] = morp >> 8;
|
||||
buf[2] = morp;
|
||||
}
|
||||
|
||||
static INLINE void MDFN_en32msb(uint8 *buf, uint32 morp)
|
||||
{
|
||||
buf[0] = morp >> 24;
|
||||
buf[1] = morp >> 16;
|
||||
buf[2] = morp >> 8;
|
||||
buf[3] = morp;
|
||||
}
|
||||
|
||||
static INLINE void MDFN_en64msb(uint8 *buf, uint64 morp)
|
||||
{
|
||||
buf[0] = morp >> 56;
|
||||
buf[1] = morp >> 48;
|
||||
buf[2] = morp >> 40;
|
||||
buf[3] = morp >> 32;
|
||||
buf[4] = morp >> 24;
|
||||
buf[5] = morp >> 16;
|
||||
buf[6] = morp >> 8;
|
||||
buf[7] = morp >> 0;
|
||||
}
|
||||
|
||||
|
||||
// Overloaded functions, yay.
|
||||
static INLINE void MDFN_enlsb(uint16 * buf, uint16 value)
|
||||
{
|
||||
MDFN_en16lsb((uint8 *)buf, value);
|
||||
}
|
||||
|
||||
static INLINE void MDFN_enlsb(uint32 * buf, uint32 value)
|
||||
{
|
||||
MDFN_en32lsb((uint8 *)buf, value);
|
||||
}
|
||||
|
||||
static INLINE void MDFN_enlsb(uint64 * buf, uint64 value)
|
||||
{
|
||||
MDFN_en64lsb((uint8 *)buf, value);
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint16 MDFN_de16lsb(const uint8 *morp)
|
||||
{
|
||||
return(morp[0] | (morp[1] << 8));
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint32 MDFN_de24lsb(const uint8 *morp)
|
||||
{
|
||||
return(morp[0]|(morp[1]<<8)|(morp[2]<<16));
|
||||
}
|
||||
|
||||
static INLINE uint32 MDFN_de32lsb(const uint8 *morp)
|
||||
{
|
||||
return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24));
|
||||
}
|
||||
|
||||
static INLINE uint64 MDFN_de64lsb(const uint8 *morp)
|
||||
{
|
||||
uint64 ret = 0;
|
||||
|
||||
ret |= (uint64)morp[0];
|
||||
ret |= (uint64)morp[1] << 8;
|
||||
ret |= (uint64)morp[2] << 16;
|
||||
ret |= (uint64)morp[3] << 24;
|
||||
ret |= (uint64)morp[4] << 32;
|
||||
ret |= (uint64)morp[5] << 40;
|
||||
ret |= (uint64)morp[6] << 48;
|
||||
ret |= (uint64)morp[7] << 56;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static INLINE uint16 MDFN_delsb(const uint16 *buf)
|
||||
{
|
||||
return(MDFN_de16lsb((uint8 *)buf));
|
||||
}
|
||||
|
||||
static INLINE uint32 MDFN_delsb(const uint32 *buf)
|
||||
{
|
||||
return(MDFN_de32lsb((uint8 *)buf));
|
||||
}
|
||||
|
||||
static INLINE uint64 MDFN_delsb(const uint64 *buf)
|
||||
{
|
||||
return(MDFN_de64lsb((uint8 *)buf));
|
||||
}
|
||||
|
||||
static INLINE uint16 MDFN_de16msb(const uint8 *morp)
|
||||
{
|
||||
return(morp[1] | (morp[0] << 8));
|
||||
}
|
||||
|
||||
static INLINE uint32 MDFN_de24msb(const uint8 *morp)
|
||||
{
|
||||
return((morp[2]<<0)|(morp[1]<<8)|(morp[0]<<16));
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint32 MDFN_de32msb(const uint8 *morp)
|
||||
{
|
||||
return(morp[3]|(morp[2]<<8)|(morp[1]<<16)|(morp[0]<<24));
|
||||
}
|
||||
|
||||
#endif
|
196
mednafen/mednafen-types.h
Normal file
196
mednafen/mednafen-types.h
Normal file
@ -0,0 +1,196 @@
|
||||
#ifndef __MDFN_TYPES
|
||||
#define __MDFN_TYPES
|
||||
|
||||
// Make sure this file is included BEFORE a few common standard C header files(stdio.h, errno.h, math.h, AND OTHERS, but this is not an exhaustive check, nor
|
||||
// should it be), so that any defines in config.h that change header file behavior will work properly.
|
||||
#if defined(EOF) || defined(EACCES) || defined(F_LOCK) || defined(NULL) || defined(O_APPEND) || defined(M_LOG2E)
|
||||
#error "Wrong include order for mednafen-types.h"
|
||||
#endif
|
||||
|
||||
// Yes, yes, I know: There's a better place for including config.h than here, but I'm tired, and this should work fine. :b
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#if HAVE_MKDIR
|
||||
#if MKDIR_TAKES_ONE_ARG
|
||||
#define MDFN_mkdir(a, b) mkdir(a)
|
||||
#else
|
||||
#define MDFN_mkdir(a, b) mkdir(a, b)
|
||||
#endif
|
||||
#else
|
||||
#if HAVE__MKDIR
|
||||
/* Plain Win32 */
|
||||
#define MDFN_mkdir(a, b) _mkdir(a)
|
||||
#else
|
||||
#error "Don't know how to create a directory on this system."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
|
||||
#if !defined(HAVE_NATIVE64BIT) && SIZEOF_VOID_P >= 8
|
||||
#define HAVE_NATIVE64BIT 1
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Multi-type union array!
|
||||
template<size_t array_byte_size>
|
||||
struct mtuarray
|
||||
{
|
||||
union
|
||||
{
|
||||
uint64 u64[array_byte_size / sizeof(uint64)];
|
||||
int64 s64[array_byte_size / sizeof(uint64)];
|
||||
|
||||
uint8 u8[array_byte_size];
|
||||
int8 s8[array_byte_size];
|
||||
|
||||
uint16 u16[array_byte_size / sizeof(uint16)];
|
||||
int16 s16[array_byte_size / sizeof(int16)];
|
||||
|
||||
uint32 u32[array_byte_size / sizeof(uint32)];
|
||||
int32 s32[array_byte_size / sizeof(int32)];
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define INLINE inline __attribute__((always_inline))
|
||||
#define NO_INLINE __attribute__((noinline))
|
||||
|
||||
#if defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
|
||||
#define MDFN_FASTCALL __attribute__((fastcall))
|
||||
#else
|
||||
#define MDFN_FASTCALL
|
||||
#endif
|
||||
|
||||
#define MDFN_ALIGN(n) __attribute__ ((aligned (n)))
|
||||
#define MDFN_FORMATSTR(a,b,c) __attribute__ ((format (a, b, c)));
|
||||
#define MDFN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#warning "Compiling with MSVC, untested"
|
||||
#define INLINE inline __forceinline
|
||||
#define NO_INLINE __declspec(noinline)
|
||||
|
||||
#define MDFN_FASTCALL __fastcall
|
||||
|
||||
#define MDFN_ALIGN(n) __declspec(align(n))
|
||||
|
||||
#define MDFN_FORMATSTR(a,b,c)
|
||||
|
||||
#define MDFN_WARN_UNUSED_RESULT
|
||||
|
||||
#else
|
||||
#error "Not compiling with GCC nor MSVC"
|
||||
#define INLINE inline
|
||||
#define NO_INLINE
|
||||
|
||||
#define MDFN_FASTCALL
|
||||
|
||||
#define MDFN_ALIGN(n) // hence the #error.
|
||||
|
||||
#define MDFN_FORMATSTR(a,b,c)
|
||||
|
||||
#define MDFN_WARN_UNUSED_RESULT
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
uint8 High;
|
||||
uint8 Low;
|
||||
#else
|
||||
uint8 Low;
|
||||
uint8 High;
|
||||
#endif
|
||||
} Union8;
|
||||
uint16 Val16;
|
||||
};
|
||||
} Uuint16;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Uuint16 High;
|
||||
Uuint16 Low;
|
||||
#else
|
||||
Uuint16 Low;
|
||||
Uuint16 High;
|
||||
#endif
|
||||
} Union16;
|
||||
uint32 Val32;
|
||||
};
|
||||
} Uuint32;
|
||||
|
||||
|
||||
#if PSS_STYLE==2
|
||||
|
||||
#define PSS "\\"
|
||||
#define MDFN_PS '\\'
|
||||
|
||||
#elif PSS_STYLE==1
|
||||
|
||||
#define PSS "/"
|
||||
#define MDFN_PS '/'
|
||||
|
||||
#elif PSS_STYLE==3
|
||||
|
||||
#define PSS "\\"
|
||||
#define MDFN_PS '\\'
|
||||
|
||||
#elif PSS_STYLE==4
|
||||
|
||||
#define PSS ":"
|
||||
#define MDFN_PS ':'
|
||||
|
||||
#endif
|
||||
|
||||
typedef uint32 UTF32; /* at least 32 bits */
|
||||
typedef uint16 UTF16; /* at least 16 bits */
|
||||
typedef uint8 UTF8; /* typically 8 bits */
|
||||
typedef unsigned char Boolean; /* 0 or 1 */
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#undef require
|
||||
#define require( expr ) assert( expr )
|
||||
|
||||
#if !defined(MSB_FIRST) && !defined(LSB_FIRST)
|
||||
#error "Define MSB_FIRST or LSB_FIRST!"
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#endif
|
1661
mednafen/mednafen.cpp
Normal file
1661
mednafen/mednafen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
57
mednafen/mednafen.h
Normal file
57
mednafen/mednafen.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef _MEDNAFEN_H
|
||||
|
||||
#include "mednafen-types.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "gettext.h"
|
||||
|
||||
#define _(String) gettext (String)
|
||||
|
||||
#include "math_ops.h"
|
||||
#include "git.h"
|
||||
|
||||
extern MDFNGI *MDFNGameInfo;
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
void MDFN_PrintError(const char *format, ...) throw() MDFN_FORMATSTR(printf, 1, 2);
|
||||
void MDFN_printf(const char *format, ...) throw() MDFN_FORMATSTR(printf, 1, 2);
|
||||
void MDFN_DispMessage(const char *format, ...) throw() MDFN_FORMATSTR(printf, 1, 2);
|
||||
|
||||
void MDFN_DebugPrintReal(const char *file, const int line, const char *format, ...) MDFN_FORMATSTR(printf, 3, 4);
|
||||
|
||||
#define MDFN_DebugPrint(format, ...) MDFN_DebugPrintReal(__FILE__, __LINE__, format, ## __VA_ARGS__)
|
||||
|
||||
|
||||
class MDFNException
|
||||
{
|
||||
public:
|
||||
|
||||
MDFNException();
|
||||
~MDFNException();
|
||||
|
||||
char TheMessage[1024];
|
||||
|
||||
void AddPre(const char *format, ...);
|
||||
void AddPost(const char *format, ...);
|
||||
};
|
||||
|
||||
|
||||
void MDFN_LoadGameCheats(FILE *override);
|
||||
void MDFN_FlushGameCheats(int nosave);
|
||||
void MDFN_DoSimpleCommand(int cmd);
|
||||
void MDFN_QSimpleCommand(int cmd);
|
||||
|
||||
void MDFN_MidSync(EmulateSpecStruct *espec);
|
||||
|
||||
#include "state.h"
|
||||
int MDFN_RawInputStateAction(StateMem *sm, int load, int data_only);
|
||||
|
||||
#include "mednafen-driver.h"
|
||||
|
||||
#include "mednafen-endian.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define _MEDNAFEN_H
|
||||
#endif
|
71
mednafen/memory.cpp
Normal file
71
mednafen/memory.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "mednafen.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
void *MDFN_calloc_real(uint32 nmemb, uint32 size, const char *purpose, const char *_file, const int _line)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = calloc(nmemb, size);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
MDFN_PrintError(_("Error allocating(calloc) %u bytes for \"%s\" in %s(%d)!"), size, purpose, _file, _line);
|
||||
return(0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *MDFN_malloc_real(uint32 size, const char *purpose, const char *_file, const int _line)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = malloc(size);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
MDFN_PrintError(_("Error allocating(malloc) %u bytes for \"%s\" in %s(%d)!"), size, purpose, _file, _line);
|
||||
return(0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *MDFN_realloc_real(void *ptr, uint32 size, const char *purpose, const char *_file, const int _line)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = realloc(ptr, size);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
MDFN_PrintError(_("Error allocating(realloc) %u bytes for \"%s\" in %s(%d)!"), size, purpose, _file, _line);
|
||||
return(0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MDFN_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
51
mednafen/memory.h
Normal file
51
mednafen/memory.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef _MDFN_MEMORY_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// These functions can be used from driver code or from internal Mednafen code.
|
||||
|
||||
#define MDFN_malloc(size, purpose) MDFN_malloc_real(size, purpose, __FILE__, __LINE__)
|
||||
#define MDFN_calloc(nmemb, size, purpose) MDFN_calloc_real(nmemb, size, purpose, __FILE__, __LINE__)
|
||||
#define MDFN_realloc(ptr, size, purpose) MDFN_realloc_real(ptr, size, purpose, __FILE__, __LINE__)
|
||||
|
||||
void *MDFN_malloc_real(uint32_t size, const char *purpose, const char *_file, const int _line);
|
||||
void *MDFN_calloc_real(uint32_t nmemb, uint32_t size, const char *purpose, const char *_file, const int _line);
|
||||
void *MDFN_realloc_real(void *ptr, uint32_t size, const char *purpose, const char *_file, const int _line);
|
||||
void MDFN_free(void *ptr);
|
||||
|
||||
static inline void MDFN_FastU32MemsetM8(uint32_t *array, uint32_t value_32, unsigned int u32len)
|
||||
{
|
||||
#ifdef ARCH_X86
|
||||
uint32_t dummy_output0, dummy_output1;
|
||||
|
||||
#ifdef __x86_64__
|
||||
asm volatile(
|
||||
"cld\n\t"
|
||||
"rep stosq\n\t"
|
||||
: "=D" (dummy_output0), "=c" (dummy_output1)
|
||||
: "a" (value_32 | ((uint64_t)value_32 << 32)), "D" (array), "c" (u32len >> 1)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
asm volatile(
|
||||
"cld\n\t"
|
||||
"rep stosl\n\t"
|
||||
: "=D" (dummy_output0), "=c" (dummy_output1)
|
||||
: "a" (value_32), "D" (array), "c" (u32len)
|
||||
: "cc", "memory");
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
for(uint32_t *ai = array; ai < array + u32len; ai += 2)
|
||||
{
|
||||
ai[0] = value_32;
|
||||
ai[1] = value_32;
|
||||
}
|
||||
|
||||
#endif
|
||||
//printf("%08x %d\n", (int)(long long)array, u32len);
|
||||
}
|
||||
|
||||
#define _MDFN_MEMORY_H
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user