Initial commit.

This commit is contained in:
Themaister 2012-06-03 17:48:14 +02:00
commit e942ae84aa
314 changed files with 191389 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*.o
*.so
*.dll
*.dylib
/old

131
Makefile Normal file
View 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
View 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
View 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

5
link.T Normal file
View File

@ -0,0 +1,5 @@
{
global: retro_*;
local: *;
};

351
mednafen/FileWrapper.cpp Normal file
View 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
View 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
View 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
View 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
View 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(&sector_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
};

View 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
View 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

View 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)
{
}

View 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

View 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;
}
}
}

View 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

View 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
View 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

View 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

View File

@ -0,0 +1,6 @@
#include "../mednafen.h"
#include "SimpleFIFO.h"

107
mednafen/cdrom/SimpleFIFO.h Normal file
View 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

View 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);
}

View 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
View 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
View 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
View 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
View 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 */

View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

66
mednafen/cdrom/pcecd.h Normal file
View 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

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

101
mednafen/cdrom/scsicd.h Normal file
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

3743
mednafen/compress/minilzo.c Normal file

File diff suppressed because it is too large Load Diff

103
mednafen/compress/minilzo.h Normal file
View 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
View 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;
}

View 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

File diff suppressed because it is too large Load Diff

357
mednafen/compress/unzip.h Normal file
View 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 */

View 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
View File

@ -0,0 +1,3 @@
modified slightly for usage in Mednafen
ARM stuff not compiled in, for now.

View 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;
}

View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View File

@ -0,0 +1 @@
../src/desa68/

View File

@ -0,0 +1 @@
../../src/trio/CHANGES

View 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 */

View 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 */

View 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 */

View 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 */

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

57
mednafen/mednafen.h Normal file
View 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
View 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
View 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