update mednadisc to 0.9.38.4

This commit is contained in:
zeromus 2015-06-23 13:17:51 -05:00
parent bea654bced
commit fada87b3d3
39 changed files with 21769 additions and 7911 deletions

View File

@ -25,7 +25,7 @@ EW_EXPORT void* mednadisc_LoadCD(const char* fname)
{ {
CDAccess* disc = NULL; CDAccess* disc = NULL;
try { try {
disc = cdaccess_open_image(fname,false); disc = CDAccess_Open(fname,false);
} }
catch(MDFN_Error &) { catch(MDFN_Error &) {
return NULL; return NULL;
@ -53,6 +53,9 @@ EW_EXPORT void mednadisc_ReadTOC(MednaDisc* md, JustTOC* justToc, CDUtility::TOC
memcpy(tracks101,toc.tracks,sizeof(toc.tracks)); memcpy(tracks101,toc.tracks,sizeof(toc.tracks));
} }
//NOTE: the subcode will come out interleaved.
//this is almost useless, but it won't always be needed, so we're not deinterleaving it here yet
//we should probably have more granular control than just reading this one sector eventually
EW_EXPORT int32 mednadisc_ReadSector(MednaDisc* md, int lba, void* buf2448) EW_EXPORT int32 mednadisc_ReadSector(MednaDisc* md, int lba, void* buf2448)
{ {
CDAccess* disc = md->disc; CDAccess* disc = md->disc;

View File

@ -1,248 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="psx">
<UniqueIdentifier>{00f73db4-1182-4bf7-b891-66bf860d3742}</UniqueIdentifier>
</Filter>
<Filter Include="emuware">
<UniqueIdentifier>{f69cc8f2-7480-44d6-9a32-9dca789d2bf6}</UniqueIdentifier>
</Filter>
<Filter Include="cdrom">
<UniqueIdentifier>{57a8e6ec-9225-410d-b38f-ba209abae070}</UniqueIdentifier>
</Filter>
<Filter Include="psx\input">
<UniqueIdentifier>{76abb796-5411-4d33-b3e0-f1f3873f138e}</UniqueIdentifier>
</Filter>
<Filter Include="emuware\msvc">
<UniqueIdentifier>{cb700979-4dce-4b10-8521-3ab71a313271}</UniqueIdentifier>
</Filter>
<Filter Include="video">
<UniqueIdentifier>{d1f71901-17a5-441a-8b4f-f7da34a057c1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\psx\cdc.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\psx.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\dis.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\gte.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\spu.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\Stream.cpp" />
<ClCompile Include="..\psx\frontio.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\cpu.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\dma.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\irq.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\mdec.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\sio.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\timer.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\endian.cpp" />
<ClCompile Include="..\psx\input\dualshock.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\gamepad.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\guncon.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\justifier.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\memcard.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\mouse.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\multitap.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\negcon.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\psx\input\dualanalog.cpp">
<Filter>psx\input</Filter>
</ClCompile>
<ClCompile Include="..\octoshock.cpp" />
<ClCompile Include="..\emuware\emuware.cpp">
<Filter>emuware</Filter>
</ClCompile>
<ClCompile Include="..\video\surface.cpp">
<Filter>video</Filter>
</ClCompile>
<ClCompile Include="..\video\Deinterlacer.cpp">
<Filter>video</Filter>
</ClCompile>
<ClCompile Include="..\emuware\EW_state.cpp">
<Filter>emuware</Filter>
</ClCompile>
<ClCompile Include="..\psx\gpu.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\gpu_line.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\gpu_polygon.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\psx\gpu_sprite.cpp">
<Filter>psx</Filter>
</ClCompile>
<ClCompile Include="..\cdrom\CDUtility.cpp">
<Filter>cdrom</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\psx\cdc.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\psx.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\emuware\emuware.h">
<Filter>emuware</Filter>
</ClInclude>
<ClInclude Include="..\psx\dis.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\gte.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\math_ops.h" />
<ClInclude Include="..\git.h" />
<ClInclude Include="..\octoshock.h" />
<ClInclude Include="..\psx\spu.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\endian.h" />
<ClInclude Include="..\Stream.h" />
<ClInclude Include="..\error.h" />
<ClInclude Include="..\psx\frontio.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\cpu.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\dma.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\irq.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\mdec.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\sio.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\timer.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\dualanalog.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\dualshock.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\gamepad.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\guncon.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\justifier.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\memcard.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\mouse.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\multitap.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\psx\input\negcon.h">
<Filter>psx\input</Filter>
</ClInclude>
<ClInclude Include="..\emuware\msvc\inttypes.h">
<Filter>emuware\msvc</Filter>
</ClInclude>
<ClInclude Include="..\emuware\msvc\stdint.h">
<Filter>emuware\msvc</Filter>
</ClInclude>
<ClInclude Include="..\video\surface.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\video\Deinterlacer.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\emuware\EW_state.h">
<Filter>emuware</Filter>
</ClInclude>
<ClInclude Include="..\cdrom\SimpleFIFO.h">
<Filter>cdrom</Filter>
</ClInclude>
<ClInclude Include="..\psx\gpu.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\psx\masmem.h">
<Filter>psx</Filter>
</ClInclude>
<ClInclude Include="..\cdrom\CDUtility.h">
<Filter>cdrom</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\psx\spu_fir_table.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\spu_reverb.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\gpu_command_table.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\gpu_common.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\gpu_line.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\gpu_polygon.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\gpu_sprite.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\cpu_computedgoto.inc">
<Filter>psx</Filter>
</None>
<None Include="..\psx\cpu_bigswitch.inc">
<Filter>psx</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -11,10 +11,10 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\cdrom\audioreader.cpp" />
<ClCompile Include="..\cdrom\CDAccess.cpp" /> <ClCompile Include="..\cdrom\CDAccess.cpp" />
<ClCompile Include="..\cdrom\CDAccess_CCD.cpp" /> <ClCompile Include="..\cdrom\CDAccess_CCD.cpp" />
<ClCompile Include="..\cdrom\CDAccess_Image.cpp" /> <ClCompile Include="..\cdrom\CDAccess_Image.cpp" />
<ClCompile Include="..\cdrom\CDAFReader.cpp" />
<ClCompile Include="..\cdrom\cdromif.cpp" /> <ClCompile Include="..\cdrom\cdromif.cpp" />
<ClCompile Include="..\cdrom\CDUtility.cpp" /> <ClCompile Include="..\cdrom\CDUtility.cpp" />
<ClCompile Include="..\cdrom\crc32.cpp" /> <ClCompile Include="..\cdrom\crc32.cpp" />
@ -30,12 +30,15 @@
<ClCompile Include="..\MemoryStream.cpp" /> <ClCompile Include="..\MemoryStream.cpp" />
<ClCompile Include="..\Stream.cpp" /> <ClCompile Include="..\Stream.cpp" />
<ClCompile Include="..\string\trim.cpp" /> <ClCompile Include="..\string\trim.cpp" />
<ClCompile Include="..\trio\trio.c" />
<ClCompile Include="..\trio\trionan.c" />
<ClCompile Include="..\trio\triostr.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\cdrom\audioreader.h" />
<ClInclude Include="..\cdrom\CDAccess.h" /> <ClInclude Include="..\cdrom\CDAccess.h" />
<ClInclude Include="..\cdrom\CDAccess_CCD.h" /> <ClInclude Include="..\cdrom\CDAccess_CCD.h" />
<ClInclude Include="..\cdrom\CDAccess_Image.h" /> <ClInclude Include="..\cdrom\CDAccess_Image.h" />
<ClInclude Include="..\cdrom\CDAFReader.h" />
<ClInclude Include="..\cdrom\cdromif.h" /> <ClInclude Include="..\cdrom\cdromif.h" />
<ClInclude Include="..\cdrom\CDUtility.h" /> <ClInclude Include="..\cdrom\CDUtility.h" />
<ClInclude Include="..\cdrom\dvdisaster.h" /> <ClInclude Include="..\cdrom\dvdisaster.h" />
@ -51,6 +54,7 @@
<ClInclude Include="..\MemoryStream.h" /> <ClInclude Include="..\MemoryStream.h" />
<ClInclude Include="..\Stream.h" /> <ClInclude Include="..\Stream.h" />
<ClInclude Include="..\string\trim.h" /> <ClInclude Include="..\string\trim.h" />
<ClInclude Include="..\trio\trio.h" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}</ProjectGuid> <ProjectGuid>{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}</ProjectGuid>
@ -81,7 +85,7 @@
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)\..\..\..\output\dll\</OutDir> <OutDir>$(ProjectDir)..\..\..\output\dll\</OutDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
@ -92,7 +96,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>EW_EXPORT;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;OCTOSHOCK_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>TRIO_PUBLIC=;TRIO_PRIVATE=static;EW_EXPORT;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;OCTOSHOCK_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../emuware/msvc;..</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>../emuware/msvc;..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile> <PrecompiledHeaderFile>
</PrecompiledHeaderFile> </PrecompiledHeaderFile>

View File

@ -10,6 +10,9 @@
<Filter Include="string"> <Filter Include="string">
<UniqueIdentifier>{798fa5bd-6381-487a-99d2-35a15a6da439}</UniqueIdentifier> <UniqueIdentifier>{798fa5bd-6381-487a-99d2-35a15a6da439}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="trio">
<UniqueIdentifier>{a43930f5-41a5-4b2b-92ef-bd90f9716127}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\cdrom\CDAccess_Image.cpp"> <ClCompile Include="..\cdrom\CDAccess_Image.cpp">
@ -51,10 +54,19 @@
<Filter>string</Filter> <Filter>string</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\general.cpp" /> <ClCompile Include="..\general.cpp" />
<ClCompile Include="..\cdrom\audioreader.cpp"> <ClCompile Include="..\Mednadisc.cpp" />
<ClCompile Include="..\trio\trio.c">
<Filter>trio</Filter>
</ClCompile>
<ClCompile Include="..\cdrom\CDAFReader.cpp">
<Filter>cdrom</Filter> <Filter>cdrom</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Mednadisc.cpp" /> <ClCompile Include="..\trio\trionan.c">
<Filter>trio</Filter>
</ClCompile>
<ClCompile Include="..\trio\triostr.c">
<Filter>trio</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\cdrom\CDAccess_Image.h"> <ClInclude Include="..\cdrom\CDAccess_Image.h">
@ -96,9 +108,12 @@
<Filter>string</Filter> <Filter>string</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\general.h" /> <ClInclude Include="..\general.h" />
<ClInclude Include="..\cdrom\audioreader.h"> <ClInclude Include="..\Mednadisc.h" />
<ClInclude Include="..\trio\trio.h">
<Filter>trio</Filter>
</ClInclude>
<ClInclude Include="..\cdrom\CDAFReader.h">
<Filter>cdrom</Filter> <Filter>cdrom</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Mednadisc.h" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,83 @@
/* 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
*/
// CDAFR_Open(), and CDAFReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
// to it for as long as the CDAFReader object exists.
// Don't allow exceptions to propagate into the vorbis/musepack/etc. libraries, as it could easily leave the state of the library's decoder "object" in an
// inconsistent state, which would cause all sorts of unfun when we try to destroy it while handling the exception farther up.
#include "emuware/emuware.h"
#include "CDAFReader.h"
#include "CDAFReader_Vorbis.h"
#include "CDAFReader_MPC.h"
#ifdef HAVE_LIBSNDFILE
#include "CDAFReader_SF.h"
#endif
CDAFReader::CDAFReader() : LastReadPos(0)
{
}
CDAFReader::~CDAFReader()
{
}
CDAFReader* CDAFR_Null_Open(Stream* fp)
{
return NULL;
}
CDAFReader *CDAFR_Open(Stream *fp)
{
static CDAFReader* (* const OpenFuncs[])(Stream* fp) =
{
#ifdef HAVE_MPC
CDAFR_MPC_Open,
#endif
#ifdef HAVE_VORBIS
CDAFR_Vorbis_Open, // Must come before CDAFR_SF_Open
#endif
#ifdef HAVE_LIBSNDFILE
CDAFR_SF_Open,
#endif
CDAFR_Null_Open
};
for(int idx=0;idx<ARRAY_SIZE(OpenFuncs);idx++)
{
auto f = OpenFuncs[idx];
try
{
fp->rewind();
return f(fp);
}
catch(int i)
{
}
}
return(NULL);
}

View File

@ -0,0 +1,41 @@
#ifndef __MDFN_CDAFREADER_H
#define __MDFN_CDAFREADER_H
#include "Stream.h"
class CDAFReader
{
public:
CDAFReader();
virtual ~CDAFReader();
virtual uint64 FrameCount(void) = 0;
INLINE uint64 Read(uint64 frame_offset, int16 *buffer, uint64 frames)
{
uint64 ret;
if(LastReadPos != frame_offset)
{
//puts("SEEK");
if(!Seek_(frame_offset))
return(0);
LastReadPos = frame_offset;
}
ret = Read_(buffer, frames);
LastReadPos += ret;
return(ret);
}
private:
virtual uint64 Read_(int16 *buffer, uint64 frames) = 0;
virtual bool Seek_(uint64 frame_offset) = 0;
uint64 LastReadPos;
};
// AR_Open(), and CDAFReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
// to it for as long as the CDAFReader object exists.
CDAFReader *CDAFR_Open(Stream *fp);
#endif

View File

@ -0,0 +1,238 @@
/* 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 "CDAFReader.h"
#include "CDAFReader_MPC.h"
#if 0
#include <mpc/mpcdec.h>
#else
#include <mednafen/mpcdec/mpcdec.h>
#endif
class CDAFReader_MPC final : public CDAFReader
{
public:
CDAFReader_MPC(Stream *fp);
~CDAFReader_MPC();
uint64 Read_(int16 *buffer, uint64 frames) override;
bool Seek_(uint64 frame_offset) override;
uint64 FrameCount(void) override;
private:
mpc_reader reader;
mpc_demux *demux;
mpc_streaminfo si;
MPC_SAMPLE_FORMAT MPCBuffer[MPC_DECODER_BUFFER_LENGTH];
uint32 MPCBufferIn;
uint32 MPCBufferOffs;
Stream *fw;
};
/// Reads size bytes of data into buffer at ptr.
static mpc_int32_t impc_read(mpc_reader *p_reader, void *ptr, mpc_int32_t size)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->read(ptr, size, false);
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// Seeks to byte position offset.
static mpc_bool_t impc_seek(mpc_reader *p_reader, mpc_int32_t offset)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
fw->seek(offset, SEEK_SET);
return(MPC_TRUE);
}
catch(...)
{
return(MPC_FALSE);
}
}
/// Returns the current byte offset in the stream.
static mpc_int32_t impc_tell(mpc_reader *p_reader)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->tell();
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// Returns the total length of the source stream, in bytes.
static mpc_int32_t impc_get_size(mpc_reader *p_reader)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->size();
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// True if the stream is a seekable stream.
static mpc_bool_t impc_canseek(mpc_reader *p_reader)
{
return(MPC_TRUE);
}
CDAFReader_MPC::CDAFReader_MPC(Stream *fp) : fw(fp)
{
demux = NULL;
memset(&si, 0, sizeof(si));
memset(MPCBuffer, 0, sizeof(MPCBuffer));
MPCBufferOffs = 0;
MPCBufferIn = 0;
memset(&reader, 0, sizeof(reader));
reader.read = impc_read;
reader.seek = impc_seek;
reader.tell = impc_tell;
reader.get_size = impc_get_size;
reader.canseek = impc_canseek;
reader.data = (void*)fp;
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(%u); 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(%u Hz); the correct samplerate is 44100 Hz."), si.sample_freq);
}
}
CDAFReader_MPC::~CDAFReader_MPC()
{
if(demux)
{
mpc_demux_exit(demux);
demux = NULL;
}
}
uint64 CDAFReader_MPC::Read_(int16 *buffer, uint64 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 CDAFReader_MPC::Seek_(uint64 frame_offset)
{
MPCBufferOffs = 0;
MPCBufferIn = 0;
if(mpc_demux_seek_sample(demux, frame_offset) < 0)
return(false);
return(true);
}
uint64 CDAFReader_MPC::FrameCount(void)
{
return(mpc_streaminfo_get_length_samples(&si));
}
CDAFReader* CDAFR_MPC_Open(Stream* fp)
{
return new CDAFReader_MPC(fp);
}

View File

@ -0,0 +1,6 @@
#ifndef __MDFN_CDAFREADER_MPC_H
#define __MDFN_CDAFREADER_MPC_H
CDAFReader* CDAFR_MPC_Open(Stream* fp);
#endif

View File

@ -0,0 +1,155 @@
/* 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 "CDAFReader.h"
#include "CDAFReader_SF.h"
#include <sndfile.h>
class CDAFReader_SF final : public CDAFReader
{
public:
CDAFReader_SF(Stream *fp);
~CDAFReader_SF();
uint64 Read_(int16 *buffer, uint64 frames) override;
bool Seek_(uint64 frame_offset) override;
uint64 FrameCount(void) override;
private:
SNDFILE *sf;
SF_INFO sfinfo;
SF_VIRTUAL_IO sfvf;
Stream *fw;
};
static sf_count_t isf_get_filelen(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->size();
}
catch(...)
{
return(-1);
}
}
static sf_count_t isf_seek(sf_count_t offset, int whence, void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
//printf("Seek: offset=%lld, whence=%lld\n", (long long)offset, (long long)whence);
fw->seek(offset, whence);
return fw->tell();
}
catch(...)
{
//printf(" SEEK FAILED\n");
return(-1);
}
}
static sf_count_t isf_read(void *ptr, sf_count_t count, void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
sf_count_t ret = fw->read(ptr, count, false);
//printf("Read: count=%lld, ret=%lld\n", (long long)count, (long long)ret);
return ret;
}
catch(...)
{
//printf(" READ FAILED\n");
return(0);
}
}
static sf_count_t isf_write(const void *ptr, sf_count_t count, void *user_data)
{
return(0);
}
static sf_count_t isf_tell(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
CDAFReader_SF::CDAFReader_SF(Stream *fp) : fw(fp)
{
memset(&sfvf, 0, sizeof(sfvf));
sfvf.get_filelen = isf_get_filelen;
sfvf.seek = isf_seek;
sfvf.read = isf_read;
sfvf.write = isf_write;
sfvf.tell = isf_tell;
memset(&sfinfo, 0, sizeof(sfinfo));
if(!(sf = sf_open_virtual(&sfvf, SFM_READ, &sfinfo, (void*)fp)))
throw(0);
}
CDAFReader_SF::~CDAFReader_SF()
{
sf_close(sf);
}
uint64 CDAFReader_SF::Read_(int16 *buffer, uint64 frames)
{
return(sf_read_short(sf, (short*)buffer, frames * 2) / 2);
}
bool CDAFReader_SF::Seek_(uint64 frame_offset)
{
// FIXME error condition
if((uint64)sf_seek(sf, frame_offset, SEEK_SET) != frame_offset)
return(false);
return(true);
}
uint64 CDAFReader_SF::FrameCount(void)
{
return(sfinfo.frames);
}
CDAFReader* CDAFR_SF_Open(Stream* fp)
{
return new CDAFReader_SF(fp);
}

View File

@ -0,0 +1,6 @@
#ifndef __MDFN_CDAFREADER_SF_H
#define __MDFN_CDAFREADER_SF_H
CDAFReader* CDAFR_SF_Open(Stream* fp);
#endif

View File

@ -0,0 +1,158 @@
/* 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 "CDAFReader.h"
#include "CDAFReader_Vorbis.h"
#if 0
#include <tremor/ivorbisfile.h>
#else
#include <mednafen/tremor/ivorbisfile.h>
#endif
class CDAFReader_Vorbis final : public CDAFReader
{
public:
CDAFReader_Vorbis(Stream *fp);
~CDAFReader_Vorbis();
uint64 Read_(int16 *buffer, uint64 frames) override;
bool Seek_(uint64 frame_offset) override;
uint64 FrameCount(void) override;
private:
OggVorbis_File ovfile;
Stream *fw;
};
static size_t iov_read_func(void *ptr, size_t size, size_t nmemb, void *user_data)
{
Stream *fw = (Stream*)user_data;
if(!size)
return(0);
try
{
return fw->read(ptr, size * nmemb, false) / size;
}
catch(...)
{
return(0);
}
}
static int iov_seek_func(void *user_data, ogg_int64_t offset, int whence)
{
Stream *fw = (Stream*)user_data;
try
{
fw->seek(offset, whence);
return(0);
}
catch(...)
{
return(-1);
}
}
static int iov_close_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
fw->close();
return(0);
}
catch(...)
{
return EOF;
}
}
static long iov_tell_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
CDAFReader_Vorbis::CDAFReader_Vorbis(Stream *fp) : fw(fp)
{
ov_callbacks cb;
memset(&cb, 0, sizeof(cb));
cb.read_func = iov_read_func;
cb.seek_func = iov_seek_func;
cb.close_func = iov_close_func;
cb.tell_func = iov_tell_func;
if(ov_open_callbacks(fp, &ovfile, NULL, 0, cb))
throw(0);
}
CDAFReader_Vorbis::~CDAFReader_Vorbis()
{
ov_clear(&ovfile);
}
uint64 CDAFReader_Vorbis::Read_(int16 *buffer, uint64 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 CDAFReader_Vorbis::Seek_(uint64 frame_offset)
{
ov_pcm_seek(&ovfile, frame_offset);
return(true);
}
uint64 CDAFReader_Vorbis::FrameCount(void)
{
return(ov_pcm_total(&ovfile, -1));
}
CDAFReader* CDAFR_Vorbis_Open(Stream* fp)
{
return new CDAFReader_Vorbis(fp);
}

View File

@ -0,0 +1,7 @@
#ifndef __MDFN_CDAFREADER_VORBIS_H
#define __MDFN_CDAFREADER_VORBIS_H
CDAFReader* CDAFR_Vorbis_Open(Stream* fp);
#endif

View File

@ -1,58 +1,46 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "emuware/emuware.h" #include "emuware/emuware.h"
#include "CDAccess.h" #include "CDAccess.h"
#include "CDAccess_Image.h" #include "CDAccess_Image.h"
#include "CDAccess_CCD.h" #include "CDAccess_CCD.h"
#ifdef HAVE_LIBCDIO using namespace CDUtility;
#include "CDAccess_Physical.h"
#endif CDAccess::CDAccess()
{
using namespace CDUtility;
}
CDAccess::CDAccess()
{ CDAccess::~CDAccess()
{
}
}
CDAccess::~CDAccess()
{ CDAccess* CDAccess_Open(const std::string& path, bool image_memcache)
{
} CDAccess *ret = NULL;
CDAccess *cdaccess_open_image(const std::string& path, bool image_memcache) if(path.size() >= 4 && !strcasecmp(path.c_str() + path.size() - 4, ".ccd"))
{ ret = new CDAccess_CCD(path, image_memcache);
CDAccess *ret = NULL; else
ret = new CDAccess_Image(path, image_memcache);
if(path.size() >= 4 && !strcasecmp(path.c_str() + path.size() - 4, ".ccd"))
ret = new CDAccess_CCD(path, image_memcache); return ret;
else }
ret = new CDAccess_Image(path, image_memcache);
return ret;
}
CDAccess *cdaccess_open_phys(const std::string& devicename)
{
#ifdef HAVE_LIBCDIO
return new CDAccess_Physical(devicename);
#else
throw MDFN_Error(0, ("Physical CD access support not compiled in."));
#endif
}

View File

@ -1,32 +1,33 @@
#ifndef __MDFN_CDROMFILE_H #ifndef __MDFN_CDROMFILE_H
#define __MDFN_CDROMFILE_H #define __MDFN_CDROMFILE_H
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include "CDUtility.h" #include "CDUtility.h"
class CDAccess class CDAccess
{ {
public: public:
CDAccess(); CDAccess();
virtual ~CDAccess(); virtual ~CDAccess();
virtual void Read_Raw_Sector(uint8 *buf, int32 lba) = 0; virtual void Read_Raw_Sector(uint8 *buf, int32 lba) = 0;
virtual void Read_TOC(CDUtility::TOC *toc) = 0; // Returns false if the read wouldn't be "fast"(i.e. reading from a disk),
// or if the read can't be done in a thread-safe re-entrant manner.
virtual bool Is_Physical(void) throw() = 0; //
// Writes 96 bytes into pwbuf, and returns 'true' otherwise.
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 virtual bool Fast_Read_Raw_PW_TSRE(uint8* pwbuf, int32 lba) const noexcept = 0;
private: virtual void Read_TOC(CDUtility::TOC *toc) = 0;
CDAccess(const CDAccess&); // No copy constructor.
CDAccess& operator=(const CDAccess&); // No assignment operator. private:
}; CDAccess(const CDAccess&); // No copy constructor.
CDAccess& operator=(const CDAccess&); // No assignment operator.
CDAccess *cdaccess_open_image(const std::string& path, bool image_memcache); };
CDAccess *cdaccess_open_phys(const std::string& devicename);
CDAccess* CDAccess_Open(const std::string& path, bool image_memcache);
#endif
#endif

View File

@ -1,435 +1,432 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "emuware/emuware.h" //#define CHECK_CCD_GARBAGE_CUBQ_A
#include "../general.h" //#define CHECK_CCD_GARBAGE_CUBQ_B
#include "../string/trim.h" //#define CHECK_CCD_GARBAGE_CUBQ_C
#include "CDAccess_CCD.h" //#define CHECK_CCD_GARBAGE_CUBQ_D
//#include <trio/trio.h>
#include "emuware/emuware.h"
//wrapper to repair gettext stuff #include "../general.h"
#define _(X) X #include "../string/trim.h"
#include "CDAccess_CCD.h"
#include <limits> #include <trio/trio.h>
#include <limits.h>
#include <map> //wrapper to repair gettext stuff
#define _(X) X
using namespace CDUtility;
#include <limits>
static void MDFN_strtoupper(std::string &str) #include <limits.h>
{ #include <map>
const size_t len = str.length();
using namespace CDUtility;
for(size_t x = 0; x < len; x++)
{ static void MDFN_strtoupper(std::string &str)
if(str[x] >= 'a' && str[x] <= 'z') {
{ const size_t len = str.length();
str[x] = str[x] - 'a' + 'A';
} for(size_t x = 0; x < len; x++)
} {
} if(str[x] >= 'a' && str[x] <= 'z')
{
typedef std::map<std::string, std::string> CCD_Section; str[x] = str[x] - 'a' + 'A';
}
template<typename T> }
static T CCD_ReadInt(CCD_Section &s, const std::string &propname, const bool have_defval = false, const int defval = 0) }
{
CCD_Section::iterator zit = s.find(propname); typedef std::map<std::string, std::string> CCD_Section;
if(zit == s.end()) template<typename T>
{ static T CCD_ReadInt(CCD_Section &s, const std::string &propname, const bool have_defval = false, const int defval = 0)
if(have_defval) {
return defval; CCD_Section::iterator zit = s.find(propname);
else
throw MDFN_Error(0, _("Missing property: %s"), propname.c_str()); if(zit == s.end())
} {
if(have_defval)
const std::string &v = zit->second; return defval;
int scan_base = 10; else
size_t scan_offset = 0; throw MDFN_Error(0, _("Missing property: %s"), propname.c_str());
long ret = 0; }
if(v.length() >= 3 && v[0] == '0' && v[1] == 'x') const std::string &v = zit->second;
{ int scan_base = 10;
scan_base = 16; size_t scan_offset = 0;
scan_offset = 2; long ret = 0;
}
if(v.length() >= 3 && v[0] == '0' && v[1] == 'x')
const char *vp = v.c_str() + scan_offset; {
char *ep = NULL; scan_base = 16;
scan_offset = 2;
if(std::numeric_limits<T>::is_signed) }
ret = strtol(vp, &ep, scan_base);
else const char *vp = v.c_str() + scan_offset;
ret = strtoul(vp, &ep, scan_base); char *ep = NULL;
if(!vp[0] || ep[0]) if(std::numeric_limits<T>::is_signed)
{ ret = strtol(vp, &ep, scan_base);
throw MDFN_Error(0, _("Property %s: Malformed integer: %s"), propname.c_str(), v.c_str()); else
} ret = strtoul(vp, &ep, scan_base);
//if(ret < minv || ret > maxv) if(!vp[0] || ep[0])
//{ {
// throw MDFN_Error(0, _("Property %s: Integer %ld out of range(accepted: %d through %d)."), propname.c_str(), ret, minv, maxv); throw MDFN_Error(0, _("Property %s: Malformed integer: %s"), propname.c_str(), v.c_str());
//} }
return ret; //if(ret < minv || ret > maxv)
} //{
// throw MDFN_Error(0, _("Property %s: Integer %ld out of range(accepted: %d through %d)."), propname.c_str(), ret, minv, maxv);
//}
CDAccess_CCD::CDAccess_CCD(const std::string& path, bool image_memcache) : img_stream(NULL), sub_stream(NULL), img_numsectors(0)
{ return ret;
try }
{
Load(path, image_memcache);
} CDAccess_CCD::CDAccess_CCD(const std::string& path, bool image_memcache) : img_numsectors(0)
catch(...) {
{ Load(path, image_memcache);
Cleanup(); }
throw;
} void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
} {
FileStream cf(path, FileStream::MODE_READ);
void CDAccess_CCD::Load(const std::string& path, bool image_memcache) std::map<std::string, CCD_Section> Sections;
{ std::string linebuf;
FileStream cf(path, FileStream::MODE_READ); std::string cur_section_name;
std::map<std::string, CCD_Section> Sections; std::string dir_path, file_base, file_ext;
std::string linebuf; char img_extsd[4] = { 'i', 'm', 'g', 0 };
std::string cur_section_name; char sub_extsd[4] = { 's', 'u', 'b', 0 };
std::string dir_path, file_base, file_ext;
char img_extsd[4] = { 'i', 'm', 'g', 0 }; MDFN_GetFilePathComponents(path, &dir_path, &file_base, &file_ext);
char sub_extsd[4] = { 's', 'u', 'b', 0 };
if(file_ext.length() == 4 && file_ext[0] == '.')
MDFN_GetFilePathComponents(path, &dir_path, &file_base, &file_ext); {
signed char extupt[3] = { -1, -1, -1 };
if(file_ext.length() == 4 && file_ext[0] == '.')
{ for(int i = 1; i < 4; i++)
signed char extupt[3] = { -1, -1, -1 }; {
if(file_ext[i] >= 'A' && file_ext[i] <= 'Z')
for(int i = 1; i < 4; i++) extupt[i - 1] = 'A' - 'a';
{ else if(file_ext[i] >= 'a' && file_ext[i] <= 'z')
if(file_ext[i] >= 'A' && file_ext[i] <= 'Z') extupt[i - 1] = 0;
extupt[i - 1] = 'A' - 'a'; }
else if(file_ext[i] >= 'a' && file_ext[i] <= 'z')
extupt[i - 1] = 0; signed char av = -1;
} for(int i = 0; i < 3; i++)
{
signed char av = -1; if(extupt[i] != -1)
for(int i = 0; i < 3; i++) av = extupt[i];
{ else
if(extupt[i] != -1) extupt[i] = av;
av = extupt[i]; }
else
extupt[i] = av; if(av == -1)
} av = 0;
if(av == -1) for(int i = 0; i < 3; i++)
av = 0; {
if(extupt[i] == -1)
for(int i = 0; i < 3; i++) extupt[i] = av;
{ }
if(extupt[i] == -1)
extupt[i] = av; for(int i = 0; i < 3; i++)
} {
img_extsd[i] += extupt[i];
for(int i = 0; i < 3; i++) sub_extsd[i] += extupt[i];
{ }
img_extsd[i] += extupt[i]; }
sub_extsd[i] += extupt[i];
} //printf("%s %d %d %d\n", file_ext.c_str(), extupt[0], extupt[1], extupt[2]);
}
linebuf.reserve(256);
//printf("%s %d %d %d\n", file_ext.c_str(), extupt[0], extupt[1], extupt[2]);
while(cf.get_line(linebuf) >= 0)
linebuf.reserve(256); {
MDFN_trim(linebuf);
while(cf.get_line(linebuf) >= 0)
{ if(linebuf.length() == 0) // Skip blank lines.
MDFN_trim(linebuf); continue;
if(linebuf.length() == 0) // Skip blank lines. if(linebuf[0] == '[')
continue; {
if(linebuf.length() < 3 || linebuf[linebuf.length() - 1] != ']')
if(linebuf[0] == '[') throw MDFN_Error(0, _("Malformed section specifier: %s"), linebuf.c_str());
{
if(linebuf.length() < 3 || linebuf[linebuf.length() - 1] != ']') cur_section_name = linebuf.substr(1, linebuf.length() - 2);
throw MDFN_Error(0, _("Malformed section specifier: %s"), linebuf.c_str()); MDFN_strtoupper(cur_section_name);
}
cur_section_name = linebuf.substr(1, linebuf.length() - 2); else
MDFN_strtoupper(cur_section_name); {
} const size_t feqpos = linebuf.find('=');
else const size_t leqpos = linebuf.rfind('=');
{ std::string k, v;
const size_t feqpos = linebuf.find('=');
const size_t leqpos = linebuf.rfind('='); if(feqpos == std::string::npos || feqpos != leqpos)
std::string k, v; throw MDFN_Error(0, _("Malformed value pair specifier: %s"), linebuf.c_str());
if(feqpos == std::string::npos || feqpos != leqpos) k = linebuf.substr(0, feqpos);
throw MDFN_Error(0, _("Malformed value pair specifier: %s"), linebuf.c_str()); v = linebuf.substr(feqpos + 1);
k = linebuf.substr(0, feqpos); MDFN_trim(k);
v = linebuf.substr(feqpos + 1); MDFN_trim(v);
MDFN_trim(k); MDFN_strtoupper(k);
MDFN_trim(v);
Sections[cur_section_name][k] = v;
MDFN_strtoupper(k); }
}
Sections[cur_section_name][k] = v;
} {
} CCD_Section& ds = Sections["DISC"];
unsigned toc_entries = CCD_ReadInt<unsigned>(ds, "TOCENTRIES");
{ unsigned num_sessions = CCD_ReadInt<unsigned>(ds, "SESSIONS");
CCD_Section& ds = Sections["DISC"]; bool data_tracks_scrambled = CCD_ReadInt<unsigned>(ds, "DATATRACKSSCRAMBLED");
unsigned toc_entries = CCD_ReadInt<unsigned>(ds, "TOCENTRIES");
unsigned num_sessions = CCD_ReadInt<unsigned>(ds, "SESSIONS"); if(num_sessions != 1)
bool data_tracks_scrambled = CCD_ReadInt<unsigned>(ds, "DATATRACKSSCRAMBLED"); throw MDFN_Error(0, _("Unsupported number of sessions: %u"), num_sessions);
if(num_sessions != 1) if(data_tracks_scrambled)
throw MDFN_Error(0, _("Unsupported number of sessions: %u"), num_sessions); throw MDFN_Error(0, _("Scrambled CCD data tracks currently not supported."));
if(data_tracks_scrambled) //printf("MOO: %d\n", toc_entries);
throw MDFN_Error(0, _("Scrambled CCD data tracks currently not supported."));
for(unsigned te = 0; te < toc_entries; te++)
//printf("MOO: %d\n", toc_entries); {
char tmpbuf[64];
for(unsigned te = 0; te < toc_entries; te++) trio_snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te);
{ CCD_Section& ts = Sections[std::string(tmpbuf)];
char tmpbuf[64]; unsigned session = CCD_ReadInt<unsigned>(ts, "SESSION");
snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te); uint8 point = CCD_ReadInt<uint8>(ts, "POINT");
CCD_Section& ts = Sections[std::string(tmpbuf)]; uint8 adr = CCD_ReadInt<uint8>(ts, "ADR");
unsigned session = CCD_ReadInt<unsigned>(ts, "SESSION"); uint8 control = CCD_ReadInt<uint8>(ts, "CONTROL");
uint8 point = CCD_ReadInt<uint8>(ts, "POINT"); uint8 pmin = CCD_ReadInt<uint8>(ts, "PMIN");
uint8 adr = CCD_ReadInt<uint8>(ts, "ADR"); uint8 psec = CCD_ReadInt<uint8>(ts, "PSEC");
uint8 control = CCD_ReadInt<uint8>(ts, "CONTROL"); //uint8 pframe = CCD_ReadInt<uint8>(ts, "PFRAME");
uint8 pmin = CCD_ReadInt<uint8>(ts, "PMIN"); signed plba = CCD_ReadInt<signed>(ts, "PLBA");
uint8 psec = CCD_ReadInt<uint8>(ts, "PSEC");
//uint8 pframe = CCD_ReadInt<uint8>(ts, "PFRAME"); if(session != 1)
signed plba = CCD_ReadInt<signed>(ts, "PLBA"); throw MDFN_Error(0, "Unsupported TOC entry Session value: %u", session);
if(session != 1) // Reference: ECMA-394, page 5-14
throw MDFN_Error(0, "Unsupported TOC entry Session value: %u", session); if(point >= 1 && point <= 99)
{
// Reference: ECMA-394, page 5-14 tocd.tracks[point].adr = adr;
if(point >= 1 && point <= 99) tocd.tracks[point].control = control;
{ tocd.tracks[point].lba = plba;
tocd.tracks[point].adr = adr; tocd.tracks[point].valid = true;
tocd.tracks[point].control = control; }
tocd.tracks[point].lba = plba; else switch(point)
} {
else default:
switch(point) throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point);
{ break;
default:
throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point); case 0xA0:
break; tocd.first_track = pmin;
tocd.disc_type = psec;
case 0xA0: break;
tocd.first_track = pmin;
tocd.disc_type = psec; case 0xA1:
break; tocd.last_track = pmin;
break;
case 0xA1:
tocd.last_track = pmin; case 0xA2:
break; tocd.tracks[100].adr = adr;
tocd.tracks[100].control = control;
case 0xA2: tocd.tracks[100].lba = plba;
tocd.tracks[100].adr = adr; tocd.tracks[100].valid = true;
tocd.tracks[100].control = control; break;
tocd.tracks[100].lba = plba; }
break; }
}
break; //
} // Open image stream.
} {
} std::string image_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(img_extsd), true);
// Convenience leadout track duplication. if(image_memcache)
if(tocd.last_track < 99) {
tocd.tracks[tocd.last_track + 1] = tocd.tracks[100]; img_stream.reset(new MemoryStream(new FileStream(image_path, FileStream::MODE_READ)));
}
// else
// Open image stream. {
{ img_stream.reset(new FileStream(image_path, FileStream::MODE_READ));
std::string image_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(img_extsd), true); }
if(image_memcache) uint64 ss = img_stream->size();
{
img_stream = new MemoryStream(new FileStream(image_path, FileStream::MODE_READ)); if(ss % 2352)
} throw MDFN_Error(0, _("CCD image size is not evenly divisible by 2352."));
else
{ if(ss > 0x7FFFFFFF)
img_stream = new FileStream(image_path, FileStream::MODE_READ); throw MDFN_Error(0, _("CCD image is too large."));
}
img_numsectors = ss / 2352;
int64 ss = img_stream->size(); }
if(ss % 2352) //
throw MDFN_Error(0, _("CCD image size is not evenly divisible by 2352.")); // Open subchannel stream
{
img_numsectors = ss / 2352; std::string sub_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(sub_extsd), true);
} FileStream sub_stream(sub_path, FileStream::MODE_READ);
// if(sub_stream.size() != (uint64)img_numsectors * 96)
// Open subchannel stream throw MDFN_Error(0, _("CCD SUB file size mismatch."));
{
std::string sub_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(sub_extsd), true); sub_data.reset(new uint8[(uint64)img_numsectors * 96]);
sub_stream.read(sub_data.get(), (uint64)img_numsectors * 96);
if(image_memcache) }
sub_stream = new MemoryStream(new FileStream(sub_path, FileStream::MODE_READ));
else CheckSubQSanity();
sub_stream = new FileStream(sub_path, FileStream::MODE_READ); }
if(sub_stream->size() != (uint64)img_numsectors * 96) //
throw MDFN_Error(0, _("CCD SUB file size mismatch.")); // Checks for Q subchannel mode 1(current time) data that has a correct checksum, but the data is nonsensical or corrupted nonetheless; this is the
} // case for some bad rips floating around on the Internet. Allowing these bad rips to be used will cause all sorts of problems during emulation, so we
// error out here if a bad rip is detected.
CheckSubQSanity(); //
} // This check is not as aggressive or exhaustive as it could be, and will not detect all potential Q subchannel rip errors; as such, it should definitely NOT be
// used in an effort to "repair" a broken rip.
// //
// Checks for Q subchannel mode 1(current time) data that has a correct checksum, but the data is nonsensical or corrupted nonetheless; this is the void CDAccess_CCD::CheckSubQSanity(void)
// case for some bad rips floating around on the Internet. Allowing these bad rips to be used will cause all sorts of problems during emulation, so we {
// error out here if a bad rip is detected. size_t checksum_pass_counter = 0;
// int prev_lba = INT_MAX;
// This check is not as aggressive or exhaustive as it could be, and will not detect all potential Q subchannel rip errors; as such, it should definitely NOT be uint8 prev_track = 0;
// used in an effort to "repair" a broken rip.
// for(size_t s = 0; s < img_numsectors; s++)
void CDAccess_CCD::CheckSubQSanity(void) {
{ union
size_t checksum_pass_counter = 0; {
int prev_lba = INT_MAX; uint8 full[96];
uint8 prev_track = 0; struct
{
for(size_t s = 0; s < img_numsectors; s++) uint8 pbuf[12];
{ uint8 qbuf[12];
union };
{ } buf;
uint8 full[96];
struct memcpy(buf.full, &sub_data[s * 96], 96);
{
uint8 pbuf[12]; if(subq_check_checksum(buf.qbuf))
uint8 qbuf[12]; {
}; uint8 adr = buf.qbuf[0] & 0xF;
} buf;
if(adr == 0x01)
sub_stream->seek(s * 96, SEEK_SET); {
sub_stream->read(buf.full, 96); uint8 track_bcd = buf.qbuf[1];
uint8 index_bcd = buf.qbuf[2];
if(subq_check_checksum(buf.qbuf)) uint8 rm_bcd = buf.qbuf[3];
{ uint8 rs_bcd = buf.qbuf[4];
uint8 adr = buf.qbuf[0] & 0xF; uint8 rf_bcd = buf.qbuf[5];
uint8 am_bcd = buf.qbuf[7];
if(adr == 0x01) uint8 as_bcd = buf.qbuf[8];
{ uint8 af_bcd = buf.qbuf[9];
uint8 track_bcd = buf.qbuf[1];
uint8 index_bcd = buf.qbuf[2]; //printf("%2x %2x %2x\n", am_bcd, as_bcd, af_bcd);
uint8 rm_bcd = buf.qbuf[3];
uint8 rs_bcd = buf.qbuf[4]; if(!BCD_is_valid(track_bcd) || !BCD_is_valid(index_bcd) || !BCD_is_valid(rm_bcd) || !BCD_is_valid(rs_bcd) || !BCD_is_valid(rf_bcd) ||
uint8 rf_bcd = buf.qbuf[5]; !BCD_is_valid(am_bcd) || !BCD_is_valid(as_bcd) || !BCD_is_valid(af_bcd) ||
uint8 am_bcd = buf.qbuf[7]; rs_bcd > 0x59 || rf_bcd > 0x74 || as_bcd > 0x59 || af_bcd > 0x74)
uint8 as_bcd = buf.qbuf[8]; {
uint8 af_bcd = buf.qbuf[9]; #ifdef CHECK_CCD_GARBAGE_SUBQ_A
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad BCD/out of range): %02x:%02x:%02x %02x:%02x:%02x"), rm_bcd, rs_bcd, rf_bcd, am_bcd, as_bcd, af_bcd);
//printf("%2x %2x %2x\n", am_bcd, as_bcd, af_bcd); #endif
}
if(!BCD_is_valid(track_bcd) || !BCD_is_valid(index_bcd) || !BCD_is_valid(rm_bcd) || !BCD_is_valid(rs_bcd) || !BCD_is_valid(rf_bcd) || else
!BCD_is_valid(am_bcd) || !BCD_is_valid(as_bcd) || !BCD_is_valid(af_bcd) || {
rs_bcd > 0x59 || rf_bcd > 0x74 || as_bcd > 0x59 || af_bcd > 0x74) int lba = ((BCD_to_U8(am_bcd) * 60 + BCD_to_U8(as_bcd)) * 75 + BCD_to_U8(af_bcd)) - 150;
{ uint8 track = BCD_to_U8(track_bcd);
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad BCD/out of range): %02x:%02x:%02x %02x:%02x:%02x"), rm_bcd, rs_bcd, rf_bcd, am_bcd, as_bcd, af_bcd);
} #ifdef CHECK_CCD_GARBAGE_SUBQ_B
else if(prev_lba != INT_MAX && abs(lba - prev_lba) > 100)
{ throw MDFN_Error(0, _("Garbage subchannel Q data detected(excessively large jump in AMSF)"));
int lba = ((BCD_to_U8(am_bcd) * 60 + BCD_to_U8(as_bcd)) * 75 + BCD_to_U8(af_bcd)) - 150; #endif
uint8 track = BCD_to_U8(track_bcd);
#ifdef CHECK_CCD_GARBAGE_SUBQ_C
if(prev_lba != INT_MAX && abs(lba - prev_lba) > 100) if(abs(lba - (int)s) > 100) //zero 19-jun-2015 a bit of a sneaky signed/unsigned fixup here
throw MDFN_Error(0, _("Garbage subchannel Q data detected(excessively large jump in AMSF)")); throw MDFN_Error(0, _("Garbage subchannel Q data detected(AMSF value is out of tolerance)"));
#endif
if(abs(lba - (int)s) > 100)
throw MDFN_Error(0, _("Garbage subchannel Q data detected(AMSF value is out of tolerance)")); prev_lba = lba;
prev_lba = lba; #ifdef CHECK_CCD_GARBAGE_SUBQ_D
if(track < prev_track)
if(track < prev_track) throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad track number)"));
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad track number)")); #endif
//else if(prev_track && track - pre //else if(prev_track && track - pre
prev_track = track; prev_track = track;
} }
checksum_pass_counter++; checksum_pass_counter++;
} }
} }
} }
//printf("%u/%u\n", checksum_pass_counter, img_numsectors); //printf("%u/%u\n", checksum_pass_counter, img_numsectors);
} }
void CDAccess_CCD::Cleanup(void) CDAccess_CCD::~CDAccess_CCD()
{ {
if(img_stream)
{ }
delete img_stream;
img_stream = NULL; void CDAccess_CCD::Read_Raw_Sector(uint8 *buf, int32 lba)
} {
if(lba < 0)
if(sub_stream) {
{ synth_udapp_sector_lba(0xFF, tocd, lba, 0, buf);
delete sub_stream; return;
sub_stream = NULL; }
}
} if((size_t)lba >= img_numsectors)
{
CDAccess_CCD::~CDAccess_CCD() synth_leadout_sector_lba(0xFF, tocd, lba, buf);
{ return;
Cleanup(); }
}
img_stream->seek(lba * 2352, SEEK_SET);
void CDAccess_CCD::Read_Raw_Sector(uint8 *buf, int32 lba) img_stream->read(buf, 2352);
{
if(lba < 0 || (size_t)lba >= img_numsectors) subpw_interleave(&sub_data[lba * 96], buf + 2352);
throw(MDFN_Error(0, _("LBA out of range."))); }
uint8 sub_buf[96]; bool CDAccess_CCD::Fast_Read_Raw_PW_TSRE(uint8* pwbuf, int32 lba) const noexcept
{
img_stream->seek(lba * 2352, SEEK_SET); if(lba < 0)
img_stream->read(buf, 2352); {
subpw_synth_udapp_lba(tocd, lba, 0, pwbuf);
sub_stream->seek(lba * 96, SEEK_SET); return true;
sub_stream->read(sub_buf, 96); }
subpw_interleave(sub_buf, buf + 2352); if((size_t)lba >= img_numsectors)
} {
subpw_synth_leadout_lba(tocd, lba, pwbuf);
return true;
void CDAccess_CCD::Read_TOC(CDUtility::TOC *toc) }
{
*toc = tocd; subpw_interleave(&sub_data[lba * 96], pwbuf);
}
return true;
bool CDAccess_CCD::Is_Physical(void) throw() }
{
return false; void CDAccess_CCD::Read_TOC(CDUtility::TOC *toc)
} {
*toc = tocd;
void CDAccess_CCD::Eject(bool eject_status) }
{
}

View File

@ -1,50 +1,48 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "../FileStream.h" #include "../FileStream.h"
#include "../MemoryStream.h" #include "../MemoryStream.h"
#include "CDAccess.h" #include "CDAccess.h"
#include <memory>
#include <vector>
class CDAccess_CCD : public CDAccess
class CDAccess_CCD : public CDAccess {
{ public:
public:
CDAccess_CCD(const std::string& path, bool image_memcache);
CDAccess_CCD(const std::string& path, bool image_memcache); virtual ~CDAccess_CCD();
virtual ~CDAccess_CCD();
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
virtual bool Fast_Read_Raw_PW_TSRE(uint8* pwbuf, int32 lba) const noexcept;
virtual void Read_TOC(CDUtility::TOC *toc);
virtual void Read_TOC(CDUtility::TOC *toc);
virtual bool Is_Physical(void) throw();
private:
virtual void Eject(bool eject_status);
void Load(const std::string& path, bool image_memcache);
private: void Cleanup(void);
void Load(const std::string& path, bool image_memcache); void CheckSubQSanity(void);
void Cleanup(void);
std::unique_ptr<Stream> img_stream;
void CheckSubQSanity(void); std::unique_ptr<uint8[]> sub_data;
Stream* img_stream; size_t img_numsectors;
Stream* sub_stream; CDUtility::TOC tocd;
size_t img_numsectors; };
CDUtility::TOC tocd;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,102 +1,103 @@
#ifndef __MDFN_CDACCESS_IMAGE_H #ifndef __MDFN_CDACCESS_IMAGE_H
#define __MDFN_CDACCESS_IMAGE_H #define __MDFN_CDACCESS_IMAGE_H
#include <map> #include <map>
#include <array> #include <array>
class Stream; class Stream;
class AudioReader; class CDAFReader;
struct CDRFILE_TRACK_INFO struct CDRFILE_TRACK_INFO
{ {
int32 LBA; int32 LBA;
uint32 DIFormat; uint32 DIFormat;
uint8 subq_control; uint8 subq_control;
int32 pregap; int32 pregap;
int32 pregap_dv; int32 pregap_dv;
int32 postgap; int32 postgap;
int32 index[2]; int32 index[2];
int32 sectors; // Not including pregap sectors! int32 sectors; // Not including pregap sectors!
Stream *fp; Stream *fp;
bool FirstFileInstance; bool FirstFileInstance;
bool RawAudioMSBFirst; bool RawAudioMSBFirst;
long FileOffset; long FileOffset;
unsigned int SubchannelMode; unsigned int SubchannelMode;
uint32 LastSamplePos; uint32 LastSamplePos;
AudioReader *AReader; CDAFReader *AReader;
}; };
#if 0 #if 0
struct Medium_Chunk struct Medium_Chunk
{ {
int64 Offset; // Offset in [..TODO..] int64 Offset; // Offset in [..TODO..]
uint32 DIFormat; uint32 DIFormat;
FILE *fp; FILE *fp;
bool FirstFileInstance; bool FirstFileInstance;
bool RawAudioMSBFirst; bool RawAudioMSBFirst;
unsigned int SubchannelMode; unsigned int SubchannelMode;
uint32 LastSamplePos; uint32 LastSamplePos;
AudioReader *AReader; AudioReader *AReader;
}; };
struct CD_Chunk struct CD_Chunk
{ {
int32 LBA; int32 LBA;
int32 Track; int32 Track;
int32 Index; int32 Index;
bool DataType; bool DataType;
Medium_Chunk Medium; Medium_Chunk Medium;
}; };
static std::vector<CD_Chunk> Chunks; static std::vector<CD_Chunk> Chunks;
#endif #endif
class CDAccess_Image : public CDAccess class CDAccess_Image : public CDAccess
{ {
public: public:
CDAccess_Image(const std::string& path, bool image_memcache); CDAccess_Image(const std::string& path, bool image_memcache);
virtual ~CDAccess_Image(); virtual ~CDAccess_Image();
virtual void Read_Raw_Sector(uint8 *buf, int32 lba); virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
virtual void Read_TOC(CDUtility::TOC *toc); virtual bool Fast_Read_Raw_PW_TSRE(uint8* pwbuf, int32 lba) const noexcept;
virtual bool Is_Physical(void) throw(); virtual void Read_TOC(CDUtility::TOC *toc);
virtual void Eject(bool eject_status); private:
private:
int32 NumTracks;
int32 NumTracks; int32 FirstTrack;
int32 FirstTrack; int32 LastTrack;
int32 LastTrack; int32 total_sectors;
int32 total_sectors; uint8 disc_type;
uint8 disc_type; CDRFILE_TRACK_INFO Tracks[100]; // Track #0(HMM?) through 99
CDRFILE_TRACK_INFO Tracks[100]; // Track #0(HMM?) through 99 CDUtility::TOC toc;
std::map<uint32, std::array<uint8, 12>> SubQReplaceMap; std::map<uint32, std::array<uint8, 12>> SubQReplaceMap;
std::string base_dir; std::string base_dir;
void ImageOpen(const std::string& path, bool image_memcache); void ImageOpen(const std::string& path, bool image_memcache);
void LoadSBI(const std::string& sbi_path); void LoadSBI(const std::string& sbi_path);
void Cleanup(void); void GenerateTOC(void);
void Cleanup(void);
// MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf.
void MakeSubPQ(int32 lba, uint8 *SubPWBuf); // MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf.
int32 MakeSubPQ(int32 lba, uint8 *SubPWBuf) const;
void ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const std::string &filename, const char *binoffset, const char *msfoffset, const char *length, bool image_memcache, std::map<std::string, Stream*> &toc_streamcache);
uint32 GetSectorCount(CDRFILE_TRACK_INFO *track); void ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const std::string &filename, const char *binoffset, const char *msfoffset, const char *length, bool image_memcache, std::map<std::string, Stream*> &toc_streamcache);
}; uint32 GetSectorCount(CDRFILE_TRACK_INFO *track);
};
#endif
#endif

View File

@ -1,324 +1,435 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de> * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "emuware/emuware.h" #include "emuware/emuware.h"
#include "CDUtility.h" #include "CDUtility.h"
#include "dvdisaster.h" #include "dvdisaster.h"
#include "lec.h" #include "lec.h"
// Kill_LEC_Correct(); #include <assert.h>
// Kill_LEC_Correct();
namespace CDUtility
{ namespace CDUtility
{
// lookup table for crc calculation
static uint16 subq_crctab[256] = // 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, 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
}; 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static uint8 scramble_table[2352 - 12];
static uint8 scramble_table[2352 - 12];
static bool CDUtility_Inited = false;
static bool CDUtility_Inited = false;
static void InitScrambleTable(void)
{ static void InitScrambleTable(void)
unsigned cv = 1; {
unsigned cv = 1;
for(unsigned i = 12; i < 2352; i++)
{ for(unsigned i = 12; i < 2352; i++)
unsigned char z = 0; {
unsigned char z = 0;
for(int b = 0; b < 8; b++)
{ for(int b = 0; b < 8; b++)
z |= (cv & 1) << b; {
z |= (cv & 1) << b;
int feedback = ((cv >> 1) & 1) ^ (cv & 1);
cv = (cv >> 1) | (feedback << 14); int feedback = ((cv >> 1) & 1) ^ (cv & 1);
} cv = (cv >> 1) | (feedback << 14);
}
scramble_table[i - 12] = z;
} scramble_table[i - 12] = z;
}
//for(int i = 0; i < 2352 - 12; i++)
// printf("0x%02x, ", scramble_table[i]); //for(int i = 0; i < 2352 - 12; i++)
} // printf("0x%02x, ", scramble_table[i]);
}
void CDUtility_Init(void)
{ void CDUtility_Init(void)
if(!CDUtility_Inited) {
{ if(!CDUtility_Inited)
Init_LEC_Correct(); {
Init_LEC_Correct();
InitScrambleTable();
InitScrambleTable();
CDUtility_Inited = true;
} CDUtility_Inited = true;
} }
}
void encode_mode0_sector(uint32 aba, uint8 *sector_data)
{ void encode_mode0_sector(uint32 aba, uint8 *sector_data)
CDUtility_Init(); {
CDUtility_Init();
lec_encode_mode0_sector(aba, sector_data);
} lec_encode_mode0_sector(aba, sector_data);
}
void encode_mode1_sector(uint32 aba, uint8 *sector_data)
{ void encode_mode1_sector(uint32 aba, uint8 *sector_data)
CDUtility_Init(); {
CDUtility_Init();
lec_encode_mode1_sector(aba, sector_data);
} lec_encode_mode1_sector(aba, sector_data);
}
void encode_mode2_sector(uint32 aba, uint8 *sector_data)
{ void encode_mode2_sector(uint32 aba, uint8 *sector_data)
CDUtility_Init(); {
CDUtility_Init();
lec_encode_mode2_sector(aba, sector_data);
} lec_encode_mode2_sector(aba, sector_data);
}
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
{ void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
CDUtility_Init(); {
CDUtility_Init();
lec_encode_mode2_form1_sector(aba, sector_data);
} lec_encode_mode2_form1_sector(aba, sector_data);
}
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
{ void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
CDUtility_Init(); {
CDUtility_Init();
lec_encode_mode2_form2_sector(aba, sector_data);
} lec_encode_mode2_form2_sector(aba, sector_data);
}
bool edc_check(const uint8 *sector_data, bool xa)
{ bool edc_check(const uint8 *sector_data, bool xa)
CDUtility_Init(); {
CDUtility_Init();
return(CheckEDC(sector_data, xa));
} return(CheckEDC(sector_data, xa));
}
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
{ bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
CDUtility_Init(); {
CDUtility_Init();
return(ValidateRawSector(sector_data, xa));
} return(ValidateRawSector(sector_data, xa));
}
bool subq_check_checksum(const uint8 *SubQBuf)
{ bool subq_check_checksum(const uint8 *SubQBuf)
uint16 crc = 0; {
uint16 stored_crc = 0; uint16 crc = 0;
uint16 stored_crc = 0;
stored_crc = SubQBuf[0xA] << 8;
stored_crc |= SubQBuf[0xB]; 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); for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
crc = ~crc;
crc = ~crc;
return(crc == stored_crc);
} return(crc == stored_crc);
}
void subq_generate_checksum(uint8 *buf)
{ void subq_generate_checksum(uint8 *buf)
uint16 crc = 0; {
uint16 crc = 0;
for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8); for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
// Checksum
buf[0xa] = ~(crc >> 8); // Checksum
buf[0xb] = ~(crc); buf[0xa] = ~(crc >> 8);
} buf[0xb] = ~(crc);
}
void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
{ void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
memset(qbuf, 0, 0xC); {
memset(qbuf, 0, 0xC);
for(int i = 0; i < 96; i++)
{ for(int i = 0; i < 96; i++)
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7)); {
} qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
} }
}
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf) // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
{ void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
assert(in_buf != out_buf); {
assert(in_buf != out_buf);
memset(out_buf, 0, 96);
memset(out_buf, 0, 96);
for(unsigned ch = 0; ch < 8; ch++)
{ for(unsigned ch = 0; ch < 8; ch++)
for(unsigned i = 0; i < 96; i++) {
{ for(unsigned i = 0; i < 96; i++)
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7)); {
} out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
} }
}
}
}
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf) // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
{ void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
assert(in_buf != out_buf); {
assert(in_buf != out_buf);
for(unsigned d = 0; d < 12; d++)
{ for(unsigned d = 0; d < 12; d++)
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++) {
{ for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
uint8 rawb = 0; {
uint8 rawb = 0;
for(unsigned ch = 0; ch < 8; ch++)
{ for(unsigned ch = 0; ch < 8; ch++)
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch); {
} rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
out_buf[(d << 3) + bitpoodle] = rawb; }
} out_buf[(d << 3) + bitpoodle] = rawb;
} }
} }
}
// NOTES ON LEADOUT AREA SYNTHESIS
// // NOTES ON LEADOUT AREA SYNTHESIS
// I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry //
// and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement // I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
// data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code). // and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
// // data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf) //
{ void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
uint8 buf[0xC]; {
uint32 lba_relative; uint8 buf[0xC];
uint32 ma, sa, fa; uint32 lba_relative;
uint32 m, s, f; uint32 ma, sa, fa;
uint32 m, s, f;
lba_relative = lba - toc.tracks[100].lba;
lba_relative = lba - toc.tracks[100].lba;
f = (lba_relative % 75);
s = ((lba_relative / 75) % 60); f = (lba_relative % 75);
m = (lba_relative / 75 / 60); s = ((lba_relative / 75) % 60);
m = (lba_relative / 75 / 60);
fa = (lba + 150) % 75;
sa = ((lba + 150) / 75) % 60; fa = (lba + 150) % 75;
ma = ((lba + 150) / 75 / 60); sa = ((lba + 150) / 75) % 60;
ma = ((lba + 150) / 75 / 60);
uint8 adr = 0x1; // Q channel data encodes position
uint8 control = (toc.tracks[toc.last_track].control & 0x4) | toc.tracks[100].control; uint8 adr = 0x1; // Q channel data encodes position
uint8 control = toc.tracks[100].control;
memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4); if(toc.tracks[toc.last_track].valid)
buf[1] = 0xAA; control |= toc.tracks[toc.last_track].control & 0x4;
buf[2] = 0x01; else if(toc.disc_type == DISC_TYPE_CD_I)
control |= 0x4;
// Track relative MSF address
buf[3] = U8_to_BCD(m); memset(buf, 0, 0xC);
buf[4] = U8_to_BCD(s); buf[0] = (adr << 0) | (control << 4);
buf[5] = U8_to_BCD(f); buf[1] = 0xAA;
buf[2] = 0x01;
buf[6] = 0; // Zerroooo
// Track relative MSF address
// Absolute MSF address buf[3] = U8_to_BCD(m);
buf[7] = U8_to_BCD(ma); buf[4] = U8_to_BCD(s);
buf[8] = U8_to_BCD(sa); buf[5] = U8_to_BCD(f);
buf[9] = U8_to_BCD(fa);
buf[6] = 0; // Zerroooo
subq_generate_checksum(buf);
// Absolute MSF address
for(int i = 0; i < 96; i++) buf[7] = U8_to_BCD(ma);
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80; buf[8] = U8_to_BCD(sa);
} buf[9] = U8_to_BCD(fa);
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf) subq_generate_checksum(buf);
{
memset(out_buf, 0, 2352 + 96); for(int i = 0; i < 96; i++)
subpw_synth_leadout_lba(toc, lba, out_buf + 2352); SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
}
if((toc.tracks[toc.last_track].control | toc.tracks[100].control) & 0x4)
{ void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
switch(mode) {
{ memset(out_buf, 0, 2352 + 96);
default: subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break; if(out_buf[2352 + 1] & 0x40)
{
case 0x01: if(mode == 0xFF)
encode_mode1_sector(LBA_to_ABA(lba), out_buf); {
break; if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I)
mode = 0x02;
case 0x02: else
out_buf[18] = 0x20; mode = 0x01;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf); }
break;
} switch(mode)
} {
} default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
#if 0 break;
bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
{ case 0x01:
assert(subq_check_checksum(subq_input)); encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break;
subq_generate_checksum(subq_output); case 0x02:
} out_buf[12 + 6] = 0x20;
#endif out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
void scrambleize_data_sector(uint8 *sector_data) break;
{ }
for(unsigned i = 12; i < 2352; i++) }
sector_data[i] ^= scramble_table[i - 12]; }
}
// ISO/IEC 10149:1995 (E): 20.2
} //
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf)
{
uint8 buf[0xC];
uint32 lba_relative;
uint32 ma, sa, fa;
uint32 m, s, f;
if(lba < -150 || lba >= 0)
printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba);
{
int32 lba_tmp = lba + lba_subq_relative_offs;
if(lba_tmp < 0)
lba_relative = 0 - 1 - lba_tmp;
else
lba_relative = lba_tmp - 0;
}
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;
if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1)
control = 0x4;
else if(toc.tracks[toc.first_track].valid)
control = toc.tracks[toc.first_track].control;
else
control = 0x0;
memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4);
buf[1] = U8_to_BCD(toc.first_track);
buf[2] = U8_to_BCD(0x00);
// 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) | 0x80;
}
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf)
{
memset(out_buf, 0, 2352 + 96);
subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, out_buf + 2352);
if(out_buf[2352 + 1] & 0x40)
{
if(mode == 0xFF)
{
if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I)
mode = 0x02;
else
mode = 0x01;
}
switch(mode)
{
default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break;
case 0x01:
encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break;
case 0x02:
out_buf[12 + 6] = 0x20;
out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break;
}
}
}
#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
void scrambleize_data_sector(uint8 *sector_data)
{
for(unsigned i = 12; i < 2352; i++)
sector_data[i] ^= scramble_table[i - 12];
}
}

View File

@ -1,225 +1,234 @@
#ifndef __MDFN_CDROM_CDUTILITY_H #ifndef __MDFN_CDROM_CDUTILITY_H
#define __MDFN_CDROM_CDUTILITY_H #define __MDFN_CDROM_CDUTILITY_H
namespace CDUtility namespace CDUtility
{ {
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions. // 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 // 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 // the initialization function to be called is called, for potential
// usage in constructors of statically-declared objects. // usage in constructors of statically-declared objects.
void CDUtility_Init(void); void CDUtility_Init(void);
// Quick definitions here: // Quick definitions here:
// //
// ABA - Absolute block address, synonymous to absolute MSF // ABA - Absolute block address, synonymous to absolute MSF
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a // 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 - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
// lba = aba - 150 // lba = aba - 150
enum enum
{ {
ADR_NOQINFO = 0x00, ADR_NOQINFO = 0x00,
ADR_CURPOS = 0x01, ADR_CURPOS = 0x01,
ADR_MCN = 0x02, ADR_MCN = 0x02,
ADR_ISRC = 0x03 ADR_ISRC = 0x03
}; };
struct TOC_Track struct TOC_Track
{ {
uint8 adr; uint8 adr;
uint8 control; uint8 control;
uint32 lba; uint32 lba;
}; bool valid; // valid/present; oh CD-i...
};
// SubQ control field flags.
enum // SubQ control field flags.
{ enum
SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis. {
SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted. SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
SUBQ_CTRLF_DATA = 0x04, // Data track. SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA. SUBQ_CTRLF_DATA = 0x04, // Data track.
}; SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
};
enum
{ enum
DISC_TYPE_CDDA_OR_M1 = 0x00, {
DISC_TYPE_CD_I = 0x10, DISC_TYPE_CDDA_OR_M1 = 0x00,
DISC_TYPE_CD_XA = 0x20 DISC_TYPE_CD_I = 0x10,
}; DISC_TYPE_CD_XA = 0x20
};
struct TOC
{ struct TOC
INLINE TOC() {
{ INLINE TOC()
Clear(); {
} Clear();
}
INLINE void Clear(void)
{ INLINE void Clear(void)
first_track = last_track = 0; {
disc_type = 0; first_track = last_track = 0;
disc_type = 0;
memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
} memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
}
INLINE int FindTrackByLBA(uint32 LBA)
{ INLINE int FindTrackByLBA(uint32 LBA) const
for(int32 track = first_track; track <= (last_track + 1); track++) {
{ int32 lvt = 0;
if(track == (last_track + 1))
{ for(int32 track = 1; track <= 100; track++)
if(LBA < tracks[100].lba) {
return(track - 1); if(!tracks[track].valid)
} continue;
else
{ if(LBA < tracks[track].lba)
if(LBA < tracks[track].lba) break;
return(track - 1);
} lvt = track;
} }
return(0);
} return(lvt);
}
uint8 first_track;
uint8 last_track; uint8 first_track;
uint8 disc_type; uint8 last_track;
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track. uint8 disc_type;
// Also, for convenience, tracks[last_track + 1] will always refer TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated). };
};
//
// // Address conversion functions.
// Address conversion functions. //
// static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
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);
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)
static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a) {
{ *m_a = aba / 75 / 60;
*m_a = aba / 75 / 60; *s_a = (aba - *m_a * 75 * 60) / 75;
*s_a = (aba - *m_a * 75 * 60) / 75; *f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75); }
}
static INLINE int32 ABA_to_LBA(uint32 aba)
static INLINE int32 ABA_to_LBA(uint32 aba) {
{ return(aba - 150);
return(aba - 150); }
}
static INLINE uint32 LBA_to_ABA(int32 lba)
static INLINE uint32 LBA_to_ABA(int32 lba) {
{ return(lba + 150);
return(lba + 150); }
}
static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
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)));
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)
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);
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a); }
}
//
// // BCD conversion functions
// BCD conversion functions //
// static INLINE bool BCD_is_valid(uint8 bcd_number)
static INLINE bool BCD_is_valid(uint8 bcd_number) {
{ if((bcd_number & 0xF0) >= 0xA0)
if((bcd_number & 0xF0) >= 0xA0) return(false);
return(false);
if((bcd_number & 0x0F) >= 0x0A)
if((bcd_number & 0x0F) >= 0x0A) return(false);
return(false);
return(true);
return(true); }
}
static INLINE uint8 BCD_to_U8(uint8 bcd_number)
static INLINE uint8 BCD_to_U8(uint8 bcd_number) {
{ return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) ); }
}
static INLINE uint8 U8_to_BCD(uint8 num)
static INLINE uint8 U8_to_BCD(uint8 num) {
{ return( ((num / 10) << 4) + (num % 10) );
return( ((num / 10) << 4) + (num % 10) ); }
}
// should always perform the conversion, even if the bcd number is invalid.
// 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)
static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number) {
{ *out_number = BCD_to_U8(bcd_number);
*out_number = BCD_to_U8(bcd_number);
if(!BCD_is_valid(bcd_number))
if(!BCD_is_valid(bcd_number)) return(false);
return(false);
return(true);
return(true); }
}
//
// // Sector data encoding functions(to full 2352 bytes raw sector).
// Sector data encoding functions(to full 2352 bytes raw sector). //
// // sector_data must be able to contain at least 2352 bytes.
// sector_data must be able to contain at least 2352 bytes. void encode_mode0_sector(uint32 aba, uint8 *sector_data);
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_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_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_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
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16
// User data area pre-pause(MSF 00:00:00 through 00:01:74), lba -150 through -1
// out_buf must be able to contain 2352+96 bytes. // out_buf must be able to contain 2352+96 bytes.
// "mode" is only used if(toc.tracks[100].control & 0x4) // "mode" is not used if the area is to be encoded as audio.
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf); // pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf);
// void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf);
// User data error detection and correction
// // out_buf must be able to contain 2352+96 bytes.
// "mode" is not used if the area is to be encoded as audio.
// Check EDC of a mode 1 or mode 2 form 1 sector. // pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.
// Returns "true" if checksum is ok(matches). void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
// Returns "false" if checksum mismatch. void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf);
// 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. // User data error detection and correction
// 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. // Check EDC of a mode 1 or mode 2 form 1 sector.
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa); // Returns "true" if checksum is ok(matches).
// Returns "false" if checksum mismatch.
// // sector_data should contain 2352 bytes of raw sector data.
// Subchannel(Q in particular) functions 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 false on checksum mismatch, true on match. // Returns "true" if errors weren't detected, or they were corrected succesfully.
bool subq_check_checksum(const uint8 *subq_buf); // Returns "false" if errors couldn't be corrected.
// sector_data should contain 2352 bytes of raw sector data.
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);
// in subq_buf.
void subq_generate_checksum(uint8 *subq_buf); //
// Subchannel(Q in particular) functions
// 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);
// Returns false on checksum mismatch, true on match.
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data. bool subq_check_checksum(const uint8 *subq_buf);
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_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
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data. // in subq_buf.
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf); void subq_generate_checksum(uint8 *subq_buf);
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output. // Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
// Only valid for ADR_CURPOS. void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);
// subq_input must pass subq_check_checksum().
// TODO // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
//void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output); void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);
// (De)Scrambles data sector. // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void scrambleize_data_sector(uint8 *sector_data); void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);
}
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
#endif // 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);
// (De)Scrambles data sector.
void scrambleize_data_sector(uint8 *sector_data);
}
#endif

View File

@ -1,7 +1,11 @@
mednafen_SOURCES += cdrom/audioreader.cpp cdrom/cdromif.cpp cdrom/scsicd.cpp mednafen_SOURCES += cdrom/cdromif.cpp cdrom/scsicd.cpp
mednafen_SOURCES += cdrom/CDUtility.cpp cdrom/crc32.cpp cdrom/galois.cpp cdrom/l-ec.cpp cdrom/recover-raw.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 cdrom/CDAccess_CCD.cpp mednafen_SOURCES += cdrom/lec.cpp cdrom/CDAccess.cpp cdrom/CDAccess_Image.cpp cdrom/CDAccess_CCD.cpp
if HAVE_LIBCDIO mednafen_SOURCES += cdrom/CDAFReader.cpp
mednafen_SOURCES += cdrom/CDAccess_Physical.cpp mednafen_SOURCES += cdrom/CDAFReader_Vorbis.cpp
endif mednafen_SOURCES += cdrom/CDAFReader_MPC.cpp
if HAVE_LIBSNDFILE
mednafen_SOURCES += cdrom/CDAFReader_SF.cpp
endif

View File

@ -1,617 +0,0 @@
/* 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
*/
// AR_Open(), and AudioReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
// to it for as long as the AudioReader object exists.
// Don't allow exceptions to propagate into the vorbis/musepack/etc. libraries, as it could easily leave the state of the library's decoder "object" in an
// inconsistent state, which would cause all sorts of unfun when we try to destroy it while handling the exception farther up.
#include "emuware/emuware.h"
#include "audioreader.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_AUDIOREADER
#include "../tremor/ivorbisfile.h"
#include "../mpcdec/mpcdec.h"
#endif
#ifdef HAVE_LIBSNDFILE
#include <sndfile.h>
#endif
#ifdef HAVE_OPUSFILE
#include "audioreader_opus.h"
#endif
#include <string.h>
#include <errno.h>
#include <time.h>
#include "../general.h"
#include "../endian.h"
AudioReader::AudioReader() : LastReadPos(0)
{
}
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);
}
/*
**
**
**
**
**
**
**
**
**
*/
#ifdef HAVE_AUDIOREADER
class OggVorbisReader : public AudioReader
{
public:
OggVorbisReader(Stream *fp);
~OggVorbisReader();
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
OggVorbis_File ovfile;
Stream *fw;
};
static size_t iov_read_func(void *ptr, size_t size, size_t nmemb, void *user_data)
{
Stream *fw = (Stream*)user_data;
if(!size)
return(0);
try
{
return fw->read(ptr, size * nmemb, false) / size;
}
catch(...)
{
return(0);
}
}
static int iov_seek_func(void *user_data, ogg_int64_t offset, int whence)
{
Stream *fw = (Stream*)user_data;
try
{
fw->seek(offset, whence);
return(0);
}
catch(...)
{
return(-1);
}
}
static int iov_close_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
fw->close();
return(0);
}
catch(...)
{
return EOF;
}
}
static long iov_tell_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
OggVorbisReader::OggVorbisReader(Stream *fp) : fw(fp)
{
ov_callbacks cb;
memset(&cb, 0, sizeof(cb));
cb.read_func = iov_read_func;
cb.seek_func = iov_seek_func;
cb.close_func = iov_close_func;
cb.tell_func = iov_tell_func;
fp->seek(0, SEEK_SET);
if(ov_open_callbacks(fp, &ovfile, NULL, 0, cb))
throw(0);
}
OggVorbisReader::~OggVorbisReader()
{
ov_clear(&ovfile);
}
int64 OggVorbisReader::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 OggVorbisReader::Seek_(int64 frame_offset)
{
ov_pcm_seek(&ovfile, frame_offset);
return(true);
}
int64 OggVorbisReader::FrameCount(void)
{
return(ov_pcm_total(&ovfile, -1));
}
class MPCReader : public AudioReader
{
public:
MPCReader(Stream *fp);
~MPCReader();
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
mpc_reader reader;
mpc_demux *demux;
mpc_streaminfo si;
MPC_SAMPLE_FORMAT MPCBuffer[MPC_DECODER_BUFFER_LENGTH];
uint32 MPCBufferIn;
uint32 MPCBufferOffs;
Stream *fw;
};
/// Reads size bytes of data into buffer at ptr.
static mpc_int32_t impc_read(mpc_reader *p_reader, void *ptr, mpc_int32_t size)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->read(ptr, size, false);
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// Seeks to byte position offset.
static mpc_bool_t impc_seek(mpc_reader *p_reader, mpc_int32_t offset)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
fw->seek(offset, SEEK_SET);
return(MPC_TRUE);
}
catch(...)
{
return(MPC_FALSE);
}
}
/// Returns the current byte offset in the stream.
static mpc_int32_t impc_tell(mpc_reader *p_reader)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->tell();
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// Returns the total length of the source stream, in bytes.
static mpc_int32_t impc_get_size(mpc_reader *p_reader)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->size();
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// True if the stream is a seekable stream.
static mpc_bool_t impc_canseek(mpc_reader *p_reader)
{
return(MPC_TRUE);
}
MPCReader::MPCReader(Stream *fp) : fw(fp)
{
fp->seek(0, SEEK_SET);
demux = NULL;
memset(&si, 0, sizeof(si));
memset(MPCBuffer, 0, sizeof(MPCBuffer));
MPCBufferOffs = 0;
MPCBufferIn = 0;
memset(&reader, 0, sizeof(reader));
reader.read = impc_read;
reader.seek = impc_seek;
reader.tell = impc_tell;
reader.get_size = impc_get_size;
reader.canseek = impc_canseek;
reader.data = (void*)fp;
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(%u); 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(%u Hz); the correct samplerate is 44100 Hz."), si.sample_freq);
}
}
MPCReader::~MPCReader()
{
if(demux)
{
mpc_demux_exit(demux);
demux = NULL;
}
}
int64 MPCReader::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 MPCReader::Seek_(int64 frame_offset)
{
MPCBufferOffs = 0;
MPCBufferIn = 0;
if(mpc_demux_seek_sample(demux, frame_offset) < 0)
return(false);
return(true);
}
int64 MPCReader::FrameCount(void)
{
return(mpc_streaminfo_get_length_samples(&si));
}
#endif //HAVE_AUDIOREADER
/*
**
**
**
**
**
**
**
**
**
*/
#ifdef HAVE_LIBSNDFILE
class SFReader : public AudioReader
{
public:
SFReader(Stream *fp);
~SFReader();
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
SNDFILE *sf;
SF_INFO sfinfo;
SF_VIRTUAL_IO sfvf;
Stream *fw;
};
static sf_count_t isf_get_filelen(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->size();
}
catch(...)
{
return(-1);
}
}
static sf_count_t isf_seek(sf_count_t offset, int whence, void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
//printf("Seek: offset=%lld, whence=%lld\n", (long long)offset, (long long)whence);
fw->seek(offset, whence);
return fw->tell();
}
catch(...)
{
//printf(" SEEK FAILED\n");
return(-1);
}
}
static sf_count_t isf_read(void *ptr, sf_count_t count, void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
sf_count_t ret = fw->read(ptr, count, false);
//printf("Read: count=%lld, ret=%lld\n", (long long)count, (long long)ret);
return ret;
}
catch(...)
{
//printf(" READ FAILED\n");
return(0);
}
}
static sf_count_t isf_write(const void *ptr, sf_count_t count, void *user_data)
{
return(0);
}
static sf_count_t isf_tell(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
SFReader::SFReader(Stream *fp) : fw(fp)
{
fp->seek(0, SEEK_SET);
memset(&sfvf, 0, sizeof(sfvf));
sfvf.get_filelen = isf_get_filelen;
sfvf.seek = isf_seek;
sfvf.read = isf_read;
sfvf.write = isf_write;
sfvf.tell = isf_tell;
memset(&sfinfo, 0, sizeof(sfinfo));
if(!(sf = sf_open_virtual(&sfvf, SFM_READ, &sfinfo, (void*)fp)))
throw(0);
}
SFReader::~SFReader()
{
sf_close(sf);
}
int64 SFReader::Read_(int16 *buffer, int64 frames)
{
return(sf_read_short(sf, (short*)buffer, frames * 2) / 2);
}
bool SFReader::Seek_(int64 frame_offset)
{
// FIXME error condition
if(sf_seek(sf, frame_offset, SEEK_SET) != frame_offset)
return(false);
return(true);
}
int64 SFReader::FrameCount(void)
{
return(sfinfo.frames);
}
#endif
AudioReader *AR_Open(Stream *fp)
{
#ifdef HAVE_AUDIOREADER
try
{
return new MPCReader(fp);
}
catch(int i)
{
}
#endif
#ifdef HAVE_OPUSFILE
try
{
return new OpusReader(fp);
}
catch(int i)
{
}
#endif
#ifdef HAVE_AUDIOREADER
try
{
return new OggVorbisReader(fp);
}
catch(int i)
{
}
#endif
#ifdef HAVE_LIBSNDFILE
try
{
return new SFReader(fp);
}
catch(int i)
{
}
#endif
return(NULL);
}

View File

@ -1,43 +0,0 @@
#ifndef __MDFN_AUDIOREADER_H
#define __MDFN_AUDIOREADER_H
#include "../Stream.h"
class AudioReader
{
public:
AudioReader();
virtual ~AudioReader();
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:
virtual int64 Read_(int16 *buffer, int64 frames);
virtual bool Seek_(int64 frame_offset);
int64 LastReadPos;
};
// AR_Open(), and AudioReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
// to it for as long as the AudioReader object exists.
AudioReader *AR_Open(Stream *fp);
#endif

View File

@ -1,185 +0,0 @@
/* 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 "audioreader_opus.h"
// OPUS SUPPORT NOT DONE YET!!!
/*
(int64)op_pcm_total() * 44100 / 48000
resampling vs seek, filter delay, etc. to consider
*/
static size_t iop_read_func(void *ptr, size_t size, size_t nmemb, void *user_data)
{
Stream *fw = (Stream*)user_data;
if(!size)
return(0);
try
{
return fw->read(ptr, size * nmemb, false) / size;
}
catch(...)
{
return(0);
}
}
static int iop_seek_func(void *user_data, opus_int64 offset, int whence)
{
Stream *fw = (Stream*)user_data;
try
{
fw->seek(offset, whence);
return(0);
}
catch(...)
{
return(-1);
}
}
static int iop_close_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
fw->close();
return(0);
}
catch(...)
{
return EOF;
}
}
static opus_int64 iop_tell_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
/* Error strings copied from libopusfile header file comments. */
static const char *op_errstring(int error)
{
static const struct
{
int code;
const char *str;
} error_table[] =
{
{ OP_EREAD, gettext_noop("OP_EREAD: An underlying read, seek, or tell operation failed when it should have succeeded.") },
{ OP_EFAULT, gettext_noop("OP_EFAULT: A NULL pointer was passed where one was unexpected, or an internal memory allocation failed, or an internal library error was encountered.") },
{ OP_EIMPL, gettext_noop("OP_EIMPL: The stream used a feature that is not implemented, such as an unsupported channel family.") },
{ OP_EINVAL, gettext_noop("OP_EINVAL: One or more parameters to a function were invalid.") },
{ OP_ENOTFORMAT, gettext_noop("OP_ENOTFORMAT: A purported Ogg Opus stream did not begin with an Ogg page, or a purported header packet did not start with one of the required strings, \"OpusHead\" or \"OpusTags\".") },
{ OP_EBADHEADER, gettext_noop("OP_EBADHEADER: A required header packet was not properly formatted, contained illegal values, or was missing altogether.") },
{ OP_EVERSION, gettext_noop("OP_EVERSION: The ID header contained an unrecognized version number.") },
{ OP_EBADPACKET, gettext_noop("OP_EBADPACKET: An audio packet failed to decode properly.") },
{ OP_EBADLINK, gettext_noop("OP_EBADLINK: We failed to find data we had seen before, or the bitstream structure was sufficiently malformed that seeking to the target destination was impossible.") },
{ OP_ENOSEEK, gettext_noop("OP_ENOSEEK: An operation that requires seeking was requested on an unseekable stream.") },
{ OP_EBADTIMESTAMP, gettext_noop("OP_EBADTIMESTAMP: The first or last granule position of a link failed basic validity checks.") },
};
for(unsigned i = 0; i < sizeof(error_table) / sizeof(error_table[0]); i++)
{
if(error_table[i].code == error)
{
return _(error_table[i].str);
}
}
return _("Unknown");
}
OggOpusReader::OggOpusReader(Stream *fp) : fw(fp)
{
OpusFileCallbacks cb;
int error = 0;
memset(&cb, 0, sizeof(cb));
cb.read_func = iop_read_func;
cb.seek_func = iop_seek_func;
cb.close_func = iop_close_func;
cb.tell_func = iop_tell_func;
fp->seek(0, SEEK_SET);
if(!(opfile = op_open_callbacks((void*)fp, &cb, NULL, 0, &error)))
{
switch(error)
{
default:
throw MDFN_Error(0, _("opusfile: error code: %d(%s)", error, op_errstring(error)));
break;
case OP_ENOTFORMAT:
throw(0);
break;
}
}
}
OggOpusReader::~OggOpusReader()
{
op_free(opfile);
}
int64 OggOpusReader::Read_(int16 *buffer, int64 frames)
{
int16 *tr_buffer = buffer;
int64 tr_count = frames * 2;
while(tr_count > 0)
{
int64 didread = op_read(opfile, tr_buffer, tr_count, NULL);
if(didread == 0)
break;
tr_buffer += didread * 2;
tr_count -= didread * 2;
}
return(frames - (tr_count / 2));
}
bool OggOpusReader::Seek_(int64 frame_offset)
{
op_pcm_seek(opfile, frame_offset);
return(true);
}
int64 OggOpusReader::FrameCount(void)
{
return(op_pcm_total(pvfile, -1));
}

View File

@ -1,21 +0,0 @@
#ifndef __MDFN_AUDIOREADER_OPUS_H
#define __MDFN_AUDIOREADER_OPUS_H
#include <opus/opusfile.h>
class OggOpusReader : public AudioReader
{
public:
OggOpusReader(Stream *fp);
~OggOpusReader();
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
OggOpus_File *opfile;
Stream *fw;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +1,66 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef __MDFN_CDROM_CDROMIF_H #ifndef __MDFN_CDROM_CDROMIF_H
#define __MDFN_CDROM_CDROMIF_H #define __MDFN_CDROM_CDROMIF_H
#include "CDUtility.h" #include "CDUtility.h"
#include "stream.h" #include "stream.h"
#include <queue> #include <queue>
typedef CDUtility::TOC CD_TOC; typedef CDUtility::TOC CD_TOC;
class CDIF class CDIF
{ {
public: public:
CDIF(); CDIF();
virtual ~CDIF(); virtual ~CDIF();
inline void ReadTOC(CDUtility::TOC *read_target) static const int32 LBA_Read_Minimum = -150;
{ static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1
*read_target = disc_toc;
} inline void ReadTOC(CDUtility::TOC *read_target)
{
virtual void HintReadSector(uint32 lba) = 0; *read_target = disc_toc;
virtual bool ReadRawSector(uint8 *buf, uint32 lba) = 0; }
// Call for mode 1 or mode 2 form 1 only. virtual void HintReadSector(int32 lba) = 0;
bool ValidateRawSector(uint8 *buf); virtual bool ReadRawSector(uint8 *buf, int32 lba) = 0; // Reads 2352+96 bytes of data into buf.
virtual bool ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread) = 0; // Reads 96 bytes(of raw subchannel PW data) into pwbuf.
// Utility/Wrapped functions
// Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned) // Call for mode 1 or mode 2 form 1 only.
// Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error bool ValidateRawSector(uint8 *buf);
int ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors);
// Utility/Wrapped functions
// Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status). // Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
// Returns false on failure(usually drive error of some kind; not completely fatal, can try again). // Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
virtual bool Eject(bool eject_status) = 0; int ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message = false);
inline bool IsPhysical(void) { return(is_phys_cache); } // For Mode 1, or Mode 2 Form 1.
// No reference counting or whatever is done, so if you destroy the CDIF object before you destroy the returned Stream, things will go BOOM.
// For Mode 1, or Mode 2 Form 1. Stream *MakeStream(int32 lba, uint32 sector_count);
// No reference counting or whatever is done, so if you destroy the CDIF object before you destroy the returned Stream, things will go BOOM.
Stream *MakeStream(uint32 lba, uint32 sector_count); protected:
bool UnrecoverableError;
protected: CDUtility::TOC disc_toc;
bool UnrecoverableError; };
bool is_phys_cache;
CDUtility::TOC disc_toc; CDIF *CDIF_Open(const std::string& path, bool image_memcache);
int DiscEjected; // 0 = inserted, 1 = ejected, -1 = DRAGONS ATE THE DISC. NOM NOM NOM.
}; #endif
CDIF *CDIF_Open(const std::string& path, const bool is_device, bool image_memcache);
#endif

View File

@ -1,203 +1,203 @@
/* dvdisaster: Additional error correction for optical media. /* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2007 Carsten Gnoerlich. * Copyright (C) 2004-2007 Carsten Gnoerlich.
* Project home page: http://www.dvdisaster.com * Project home page: http://www.dvdisaster.com
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org. * or direct your browser at http://www.gnu.org.
*/ */
#include "dvdisaster.h" #include "dvdisaster.h"
static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */ static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
static ReedSolomonTables *rt = NULL; static ReedSolomonTables *rt = NULL;
bool Init_LEC_Correct(void) bool Init_LEC_Correct(void)
{ {
gt = CreateGaloisTables(0x11d); gt = CreateGaloisTables(0x11d);
rt = CreateReedSolomonTables(gt, 0, 1, 10); rt = CreateReedSolomonTables(gt, 0, 1, 10);
return(1); return(1);
} }
void Kill_LEC_Correct(void) void Kill_LEC_Correct(void)
{ {
FreeGaloisTables(gt); FreeGaloisTables(gt);
FreeReedSolomonTables(rt); FreeReedSolomonTables(rt);
} }
/*** /***
*** CD level CRC calculation *** CD level CRC calculation
***/ ***/
/* /*
* Test raw sector against its 32bit CRC. * Test raw sector against its 32bit CRC.
* Returns TRUE if frame is good. * Returns TRUE if frame is good.
*/ */
int CheckEDC(const unsigned char *cd_frame, bool xa_mode) int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
{ {
unsigned int expected_crc, real_crc; unsigned int expected_crc, real_crc;
unsigned int crc_base = xa_mode ? 2072 : 2064; unsigned int crc_base = xa_mode ? 2072 : 2064;
expected_crc = cd_frame[crc_base + 0] << 0; expected_crc = cd_frame[crc_base + 0] << 0;
expected_crc |= cd_frame[crc_base + 1] << 8; expected_crc |= cd_frame[crc_base + 1] << 8;
expected_crc |= cd_frame[crc_base + 2] << 16; expected_crc |= cd_frame[crc_base + 2] << 16;
expected_crc |= cd_frame[crc_base + 3] << 24; expected_crc |= cd_frame[crc_base + 3] << 24;
if(xa_mode) if(xa_mode)
real_crc = EDCCrc32(cd_frame+16, 2056); real_crc = EDCCrc32(cd_frame+16, 2056);
else else
real_crc = EDCCrc32(cd_frame, 2064); real_crc = EDCCrc32(cd_frame, 2064);
if(expected_crc == real_crc) if(expected_crc == real_crc)
return(1); return(1);
else else
{ {
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc); //printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
return(0); return(0);
} }
} }
/*** /***
*** A very simple L-EC error correction. *** A very simple L-EC error correction.
*** ***
* Perform just one pass over the Q and P vectors to see if everything * 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 * 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. * same stuff the drive is supposed to do in the final L-EC stage.
*/ */
static int simple_lec(unsigned char *frame) static int simple_lec(unsigned char *frame)
{ {
unsigned char byte_state[2352]; unsigned char byte_state[2352];
unsigned char p_vector[P_VECTOR_SIZE]; unsigned char p_vector[P_VECTOR_SIZE];
unsigned char q_vector[Q_VECTOR_SIZE]; unsigned char q_vector[Q_VECTOR_SIZE];
unsigned char p_state[P_VECTOR_SIZE]; unsigned char p_state[P_VECTOR_SIZE];
int erasures[Q_VECTOR_SIZE], erasure_count; int erasures[Q_VECTOR_SIZE], erasure_count;
int ignore[2]; int ignore[2];
int p_failures, q_failures; int p_failures, q_failures;
int p_corrected, q_corrected; int p_corrected, q_corrected;
int p,q; int p,q;
/* Setup */ /* Setup */
memset(byte_state, 0, 2352); memset(byte_state, 0, 2352);
p_failures = q_failures = 0; p_failures = q_failures = 0;
p_corrected = q_corrected = 0; p_corrected = q_corrected = 0;
/* Perform Q-Parity error correction */ /* Perform Q-Parity error correction */
for(q=0; q<N_Q_VECTORS; q++) for(q=0; q<N_Q_VECTORS; q++)
{ int err; { int err;
/* We have no erasure information for Q vectors */ /* We have no erasure information for Q vectors */
GetQVector(frame, q_vector, q); GetQVector(frame, q_vector, q);
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0); err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
/* See what we've got */ /* See what we've got */
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */ if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
{ q_failures++; { q_failures++;
FillQVector(byte_state, 1, q); FillQVector(byte_state, 1, q);
} }
else /* Correctable */ else /* Correctable */
{ if(err == 1 || err == 2) /* Store back corrected vector */ { if(err == 1 || err == 2) /* Store back corrected vector */
{ SetQVector(frame, q_vector, q); { SetQVector(frame, q_vector, q);
q_corrected++; q_corrected++;
} }
} }
} }
/* Perform P-Parity error correction */ /* Perform P-Parity error correction */
for(p=0; p<N_P_VECTORS; p++) for(p=0; p<N_P_VECTORS; p++)
{ int err,i; { int err,i;
/* Try error correction without erasure information */ /* Try error correction without erasure information */
GetPVector(frame, p_vector, p); GetPVector(frame, p_vector, p);
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0); err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
/* If unsuccessful, try again using erasures. /* If unsuccessful, try again using erasures.
Erasure information is uncertain, so try this last. */ Erasure information is uncertain, so try this last. */
if(err < 0 || err > 2) if(err < 0 || err > 2)
{ GetPVector(byte_state, p_state, p); { GetPVector(byte_state, p_state, p);
erasure_count = 0; erasure_count = 0;
for(i=0; i<P_VECTOR_SIZE; i++) for(i=0; i<P_VECTOR_SIZE; i++)
if(p_state[i]) if(p_state[i])
erasures[erasure_count++] = i; erasures[erasure_count++] = i;
if(erasure_count > 0 && erasure_count <= 2) if(erasure_count > 0 && erasure_count <= 2)
{ GetPVector(frame, p_vector, p); { GetPVector(frame, p_vector, p);
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count); err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
} }
} }
/* See what we've got */ /* See what we've got */
if(err < 0) /* Uncorrectable. */ if(err < 0) /* Uncorrectable. */
{ p_failures++; { p_failures++;
} }
else /* Correctable. */ else /* Correctable. */
{ if(err == 1 || err == 2) /* Store back corrected vector */ { if(err == 1 || err == 2) /* Store back corrected vector */
{ SetPVector(frame, p_vector, p); { SetPVector(frame, p_vector, p);
p_corrected++; p_corrected++;
} }
} }
} }
/* Sum up */ /* Sum up */
if(q_failures || p_failures || q_corrected || p_corrected) if(q_failures || p_failures || q_corrected || p_corrected)
{ {
return 1; return 1;
} }
return 0; return 0;
} }
/*** /***
*** Validate CD raw sector *** Validate CD raw sector
***/ ***/
int ValidateRawSector(unsigned char *frame, bool xaMode) int ValidateRawSector(unsigned char *frame, bool xaMode)
{ {
int lec_did_sth = FALSE_0; int lec_did_sth = FALSE_0;
/* Do simple L-EC. /* Do simple L-EC.
It seems that drives stop their internal L-EC as soon as the 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. 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 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. */ L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
if(!CheckEDC(frame, xaMode)) if(!CheckEDC(frame, xaMode))
{ {
lec_did_sth = simple_lec(frame); lec_did_sth = simple_lec(frame);
} }
/* Test internal sector checksum again */ /* Test internal sector checksum again */
if(!CheckEDC(frame, xaMode)) if(!CheckEDC(frame, xaMode))
{ {
/* EDC failure in RAW sector */ /* EDC failure in RAW sector */
return FALSE_0; return FALSE_0;
} }
return TRUE_1; return TRUE_1;
} }

View File

@ -1,259 +1,259 @@
/******************************************************** /********************************************************
* * * *
* PC Engine CD Command 0xD8 - SAPSP * * PC Engine CD Command 0xD8 - SAPSP *
* * * *
********************************************************/ ********************************************************/
static void DoNEC_PCE_SAPSP(const uint8 *cdb) static void DoNEC_PCE_SAPSP(const uint8 *cdb)
{ {
uint32 new_read_sec_start; 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]); //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) switch (cdb[9] & 0xc0)
{ {
default: SCSIDBG("Unknown SAPSP 9: %02x\n", cdb[9]); default: //SCSIDBG("Unknown SAPSP 9: %02x\n", cdb[9]);
case 0x00: case 0x00:
new_read_sec_start = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; new_read_sec_start = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
break; break;
case 0x40: case 0x40:
new_read_sec_start = AMSF_to_LBA(BCD_to_U8(cdb[2]), BCD_to_U8(cdb[3]), BCD_to_U8(cdb[4])); new_read_sec_start = AMSF_to_LBA(BCD_to_U8(cdb[2]), BCD_to_U8(cdb[3]), BCD_to_U8(cdb[4]));
break; break;
case 0x80: case 0x80:
{ {
int track = BCD_to_U8(cdb[2]); int track = BCD_to_U8(cdb[2]);
if(!track) if(!track)
track = 1; track = 1;
else if(track >= toc.last_track + 1) else if(track >= toc.last_track + 1)
track = 100; track = 100;
new_read_sec_start = toc.tracks[track].lba; new_read_sec_start = toc.tracks[track].lba;
} }
break; break;
} }
//printf("%lld\n", (long long)(monotonic_timestamp - pce_lastsapsp_timestamp) * 1000 / System_Clock); //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) 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; pce_lastsapsp_timestamp = monotonic_timestamp;
SendStatusAndMessage(STATUS_GOOD, 0x00); SendStatusAndMessage(STATUS_GOOD, 0x00);
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE); CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
return; return;
} }
pce_lastsapsp_timestamp = monotonic_timestamp; pce_lastsapsp_timestamp = monotonic_timestamp;
read_sec = read_sec_start = new_read_sec_start; read_sec = read_sec_start = new_read_sec_start;
read_sec_end = toc.tracks[100].lba; read_sec_end = toc.tracks[100].lba;
cdda.CDDAReadPos = 588; cdda.CDDAReadPos = 588;
cdda.CDDAStatus = CDDASTATUS_PAUSED; cdda.CDDAStatus = CDDASTATUS_PAUSED;
cdda.PlayMode = PLAYMODE_SILENT; cdda.PlayMode = PLAYMODE_SILENT;
if(cdb[1]) if(cdb[1])
{ {
cdda.PlayMode = PLAYMODE_NORMAL; cdda.PlayMode = PLAYMODE_NORMAL;
cdda.CDDAStatus = CDDASTATUS_PLAYING; cdda.CDDAStatus = CDDASTATUS_PLAYING;
} }
if(read_sec < toc.tracks[100].lba) if(read_sec < toc.tracks[100].lba)
Cur_CDIF->HintReadSector(read_sec); Cur_CDIF->HintReadSector(read_sec);
SendStatusAndMessage(STATUS_GOOD, 0x00); SendStatusAndMessage(STATUS_GOOD, 0x00);
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE); CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
} }
/******************************************************** /********************************************************
* * * *
* PC Engine CD Command 0xD9 - SAPEP * * PC Engine CD Command 0xD9 - SAPEP *
* * * *
********************************************************/ ********************************************************/
static void DoNEC_PCE_SAPEP(const uint8 *cdb) static void DoNEC_PCE_SAPEP(const uint8 *cdb)
{ {
uint32 new_read_sec_end; 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]); //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) switch (cdb[9] & 0xc0)
{ {
default: SCSIDBG("Unknown SAPEP 9: %02x\n", cdb[9]); default: //SCSIDBG("Unknown SAPEP 9: %02x\n", cdb[9]);
case 0x00: case 0x00:
new_read_sec_end = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; new_read_sec_end = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
break; break;
case 0x40: 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 = BCD_to_U8(cdb[4]) + 75 * (BCD_to_U8(cdb[3]) + 60 * BCD_to_U8(cdb[2]));
new_read_sec_end -= 150; new_read_sec_end -= 150;
break; break;
case 0x80: case 0x80:
{ {
int track = BCD_to_U8(cdb[2]); int track = BCD_to_U8(cdb[2]);
if(!track) if(!track)
track = 1; track = 1;
else if(track >= toc.last_track + 1) else if(track >= toc.last_track + 1)
track = 100; track = 100;
new_read_sec_end = toc.tracks[track].lba; new_read_sec_end = toc.tracks[track].lba;
} }
break; break;
} }
read_sec_end = new_read_sec_end; read_sec_end = new_read_sec_end;
switch(cdb[1]) // PCE CD(TODO: Confirm these, and check the mode mask): switch(cdb[1]) // PCE CD(TODO: Confirm these, and check the mode mask):
{ {
default: default:
case 0x03: cdda.PlayMode = PLAYMODE_NORMAL; case 0x03: cdda.PlayMode = PLAYMODE_NORMAL;
cdda.CDDAStatus = CDDASTATUS_PLAYING; cdda.CDDAStatus = CDDASTATUS_PLAYING;
break; break;
case 0x02: cdda.PlayMode = PLAYMODE_INTERRUPT; case 0x02: cdda.PlayMode = PLAYMODE_INTERRUPT;
cdda.CDDAStatus = CDDASTATUS_PLAYING; cdda.CDDAStatus = CDDASTATUS_PLAYING;
break; break;
case 0x01: cdda.PlayMode = PLAYMODE_LOOP; case 0x01: cdda.PlayMode = PLAYMODE_LOOP;
cdda.CDDAStatus = CDDASTATUS_PLAYING; cdda.CDDAStatus = CDDASTATUS_PLAYING;
break; break;
case 0x00: cdda.PlayMode = PLAYMODE_SILENT; case 0x00: cdda.PlayMode = PLAYMODE_SILENT;
cdda.CDDAStatus = CDDASTATUS_STOPPED; cdda.CDDAStatus = CDDASTATUS_STOPPED;
break; break;
} }
SendStatusAndMessage(STATUS_GOOD, 0x00); SendStatusAndMessage(STATUS_GOOD, 0x00);
} }
/******************************************************** /********************************************************
* * * *
* PC Engine CD Command 0xDA - Pause * * PC Engine CD Command 0xDA - Pause *
* * * *
********************************************************/ ********************************************************/
static void DoNEC_PCE_PAUSE(const uint8 *cdb) 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? 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; cdda.CDDAStatus = CDDASTATUS_PAUSED;
SendStatusAndMessage(STATUS_GOOD, 0x00); SendStatusAndMessage(STATUS_GOOD, 0x00);
} }
else // Definitely give an error if it tries to pause when no track is playing! else // Definitely give an error if it tries to pause when no track is playing!
{ {
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_AUDIO_NOT_PLAYING); CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_AUDIO_NOT_PLAYING);
} }
} }
/******************************************************** /********************************************************
* * * *
* PC Engine CD Command 0xDD - Read Subchannel Q * * PC Engine CD Command 0xDD - Read Subchannel Q *
* * * *
********************************************************/ ********************************************************/
static void DoNEC_PCE_READSUBQ(const uint8 *cdb) static void DoNEC_PCE_READSUBQ(const uint8 *cdb)
{ {
uint8 *SubQBuf = cd.SubQBuf[QMode_Time]; uint8 *SubQBuf = cd.SubQBuf[QMode_Time];
uint8 data_in[8192]; uint8 data_in[8192];
memset(data_in, 0x00, 10); memset(data_in, 0x00, 10);
data_in[2] = SubQBuf[1]; // Track data_in[2] = SubQBuf[1]; // Track
data_in[3] = SubQBuf[2]; // Index data_in[3] = SubQBuf[2]; // Index
data_in[4] = SubQBuf[3]; // M(rel) data_in[4] = SubQBuf[3]; // M(rel)
data_in[5] = SubQBuf[4]; // S(rel) data_in[5] = SubQBuf[4]; // S(rel)
data_in[6] = SubQBuf[5]; // F(rel) data_in[6] = SubQBuf[5]; // F(rel)
data_in[7] = SubQBuf[7]; // M(abs) data_in[7] = SubQBuf[7]; // M(abs)
data_in[8] = SubQBuf[8]; // S(abs) data_in[8] = SubQBuf[8]; // S(abs)
data_in[9] = SubQBuf[9]; // F(abs) data_in[9] = SubQBuf[9]; // F(abs)
if(cdda.CDDAStatus == CDDASTATUS_PAUSED) if(cdda.CDDAStatus == CDDASTATUS_PAUSED)
data_in[0] = 2; // Pause 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? 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 data_in[0] = 0; // Playing
else else
data_in[0] = 3; // Stopped data_in[0] = 3; // Stopped
DoSimpleDataIn(data_in, 10); DoSimpleDataIn(data_in, 10);
} }
/******************************************************** /********************************************************
* * * *
* PC Engine CD Command 0xDE - Get Directory Info * * PC Engine CD Command 0xDE - Get Directory Info *
* * * *
********************************************************/ ********************************************************/
static void DoNEC_PCE_GETDIRINFO(const uint8 *cdb) static void DoNEC_PCE_GETDIRINFO(const uint8 *cdb)
{ {
// Problems: // Problems:
// Returned data lengths on real PCE are not confirmed. // Returned data lengths on real PCE are not confirmed.
// Mode 0x03 behavior not tested on real PCE // Mode 0x03 behavior not tested on real PCE
uint8 data_in[2048]; uint8 data_in[2048];
uint32 data_in_size = 0; uint32 data_in_size = 0;
memset(data_in, 0, sizeof(data_in)); memset(data_in, 0, sizeof(data_in));
switch(cdb[1]) switch(cdb[1])
{ {
default: MDFN_DispMessage("Unknown GETDIRINFO Mode: %02x", cdb[1]); default: //MDFN_DispMessage("Unknown GETDIRINFO Mode: %02x", cdb[1]);
printf("Unknown GETDIRINFO Mode: %02x", cdb[1]); //printf("Unknown GETDIRINFO Mode: %02x", cdb[1]);
case 0x0: case 0x0:
data_in[0] = U8_to_BCD(toc.first_track); data_in[0] = U8_to_BCD(toc.first_track);
data_in[1] = U8_to_BCD(toc.last_track); data_in[1] = U8_to_BCD(toc.last_track);
data_in_size = 2; data_in_size = 2;
break; break;
case 0x1: case 0x1:
{ {
uint8 m, s, f; uint8 m, s, f;
LBA_to_AMSF(toc.tracks[100].lba, &m, &s, &f); LBA_to_AMSF(toc.tracks[100].lba, &m, &s, &f);
data_in[0] = U8_to_BCD(m); data_in[0] = U8_to_BCD(m);
data_in[1] = U8_to_BCD(s); data_in[1] = U8_to_BCD(s);
data_in[2] = U8_to_BCD(f); data_in[2] = U8_to_BCD(f);
data_in_size = 3; data_in_size = 3;
} }
break; break;
case 0x2: case 0x2:
{ {
uint8 m, s, f; uint8 m, s, f;
int track = BCD_to_U8(cdb[2]); int track = BCD_to_U8(cdb[2]);
if(!track) if(!track)
track = 1; track = 1;
else if(cdb[2] == 0xAA) else if(cdb[2] == 0xAA)
{ {
track = 100; track = 100;
} }
else if(track > 99) else if(track > 99)
{ {
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_INVALID_PARAMETER); CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_INVALID_PARAMETER);
return; return;
} }
LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f); LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
data_in[0] = U8_to_BCD(m); data_in[0] = U8_to_BCD(m);
data_in[1] = U8_to_BCD(s); data_in[1] = U8_to_BCD(s);
data_in[2] = U8_to_BCD(f); data_in[2] = U8_to_BCD(f);
data_in[3] = toc.tracks[track].control; data_in[3] = toc.tracks[track].control;
data_in_size = 4; data_in_size = 4;
} }
break; break;
} }
DoSimpleDataIn(data_in, data_in_size); DoSimpleDataIn(data_in, data_in_size);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,99 +1,99 @@
#ifndef __PCFX_SCSICD_H #ifndef __PCFX_SCSICD_H
#define __PCFX_SCSICD_H #define __PCFX_SCSICD_H
typedef int32 scsicd_timestamp_t; typedef int32 scsicd_timestamp_t;
typedef struct typedef struct
{ {
// Data bus(FIXME: we should have a variable for the target and the initiator, and OR them together to be truly accurate). // Data bus(FIXME: we should have a variable for the target and the initiator, and OR them together to be truly accurate).
uint8 DB; uint8 DB;
uint32 signals; uint32 signals;
// Signals under our(the "target") control. // Signals under our(the "target") control.
//bool BSY, MSG, CD, REQ, IO; //bool BSY, MSG, CD, REQ, IO;
// Signals under the control of the initiator(not us!) // Signals under the control of the initiator(not us!)
//bool kingACK, kingRST, kingSEL, kingATN; //bool kingACK, kingRST, kingSEL, kingATN;
} scsicd_bus_t; } 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. 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. // Signals under our(the "target") control.
#define SCSICD_IO_mask 0x001 #define SCSICD_IO_mask 0x001
#define SCSICD_CD_mask 0x002 #define SCSICD_CD_mask 0x002
#define SCSICD_MSG_mask 0x004 #define SCSICD_MSG_mask 0x004
#define SCSICD_REQ_mask 0x008 #define SCSICD_REQ_mask 0x008
#define SCSICD_BSY_mask 0x010 #define SCSICD_BSY_mask 0x010
// Signals under the control of the initiator(not us!) // Signals under the control of the initiator(not us!)
#define SCSICD_kingRST_mask 0x020 #define SCSICD_kingRST_mask 0x020
#define SCSICD_kingACK_mask 0x040 #define SCSICD_kingACK_mask 0x040
#define SCSICD_kingATN_mask 0x080 #define SCSICD_kingATN_mask 0x080
#define SCSICD_kingSEL_mask 0x100 #define SCSICD_kingSEL_mask 0x100
#define BSY_signal ((const bool)(cd_bus.signals & SCSICD_BSY_mask)) #define BSY_signal ((const bool)(cd_bus.signals & SCSICD_BSY_mask))
#define ACK_signal ((const bool)(cd_bus.signals & SCSICD_kingACK_mask)) #define ACK_signal ((const bool)(cd_bus.signals & SCSICD_kingACK_mask))
#define RST_signal ((const bool)(cd_bus.signals & SCSICD_kingRST_mask)) #define RST_signal ((const bool)(cd_bus.signals & SCSICD_kingRST_mask))
#define MSG_signal ((const bool)(cd_bus.signals & SCSICD_MSG_mask)) #define MSG_signal ((const bool)(cd_bus.signals & SCSICD_MSG_mask))
#define SEL_signal ((const bool)(cd_bus.signals & SCSICD_kingSEL_mask)) #define SEL_signal ((const bool)(cd_bus.signals & SCSICD_kingSEL_mask))
#define REQ_signal ((const bool)(cd_bus.signals & SCSICD_REQ_mask)) #define REQ_signal ((const bool)(cd_bus.signals & SCSICD_REQ_mask))
#define IO_signal ((const bool)(cd_bus.signals & SCSICD_IO_mask)) #define IO_signal ((const bool)(cd_bus.signals & SCSICD_IO_mask))
#define CD_signal ((const bool)(cd_bus.signals & SCSICD_CD_mask)) #define CD_signal ((const bool)(cd_bus.signals & SCSICD_CD_mask))
#define ATN_signal ((const bool)(cd_bus.signals & SCSICD_kingATN_mask)) #define ATN_signal ((const bool)(cd_bus.signals & SCSICD_kingATN_mask))
#define DB_signal ((const uint8)cd_bus.DB) #define DB_signal ((const uint8)cd_bus.DB)
#define SCSICD_GetDB() DB_signal #define SCSICD_GetDB() DB_signal
#define SCSICD_GetBSY() BSY_signal #define SCSICD_GetBSY() BSY_signal
#define SCSICD_GetIO() IO_signal #define SCSICD_GetIO() IO_signal
#define SCSICD_GetCD() CD_signal #define SCSICD_GetCD() CD_signal
#define SCSICD_GetMSG() MSG_signal #define SCSICD_GetMSG() MSG_signal
#define SCSICD_GetREQ() REQ_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)? // 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_GetACK() ACK_signal
#define SCSICD_GetRST() RST_signal #define SCSICD_GetRST() RST_signal
#define SCSICD_GetSEL() SEL_signal #define SCSICD_GetSEL() SEL_signal
#define SCSICD_GetATN() ATN_signal #define SCSICD_GetATN() ATN_signal
void SCSICD_Power(scsicd_timestamp_t system_timestamp); void SCSICD_Power(scsicd_timestamp_t system_timestamp);
void SCSICD_SetDB(uint8 data); void SCSICD_SetDB(uint8 data);
// These SCSICD_Set* functions are kind of misnomers, at least in comparison to the SCSICD_Get* functions... // 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. // They will set/clear the bits corresponding to the KING's side of the bus.
void SCSICD_SetACK(bool set); void SCSICD_SetACK(bool set);
void SCSICD_SetSEL(bool set); void SCSICD_SetSEL(bool set);
void SCSICD_SetRST(bool set); void SCSICD_SetRST(bool set);
void SCSICD_SetATN(bool set); void SCSICD_SetATN(bool set);
uint32 SCSICD_Run(scsicd_timestamp_t); uint32 SCSICD_Run(scsicd_timestamp_t);
void SCSICD_ResetTS(uint32 ts_base); void SCSICD_ResetTS(uint32 ts_base);
enum enum
{ {
SCSICD_PCE = 1, SCSICD_PCE = 1,
SCSICD_PCFX SCSICD_PCFX
}; };
enum enum
{ {
SCSICD_IRQ_DATA_TRANSFER_DONE = 1, SCSICD_IRQ_DATA_TRANSFER_DONE = 1,
SCSICD_IRQ_DATA_TRANSFER_READY, SCSICD_IRQ_DATA_TRANSFER_READY,
SCSICD_IRQ_MAGICAL_REQ, SCSICD_IRQ_MAGICAL_REQ,
}; };
void SCSICD_GetCDDAValues(int16 &left, int16 &right); void SCSICD_GetCDDAValues(int16 &left, int16 &right);
void SCSICD_SetLog(void (*logfunc)(const char *, const char *, ...)); void SCSICD_SetLog(void (*logfunc)(const char *, const char *, ...));
void SCSICD_Init(int type, int CDDATimeDiv, int32* left_hrbuf, int32* right_hrbuf, uint32 TransferRate, uint32 SystemClock, void (*IRQFunc)(int), void (*SSCFunc)(uint8, int)); void SCSICD_Init(int type, int CDDATimeDiv, int32* left_hrbuf, int32* right_hrbuf, uint32 TransferRate, uint32 SystemClock, void (*IRQFunc)(int), void (*SSCFunc)(uint8, int));
void SCSICD_Close(void); void SCSICD_Close(void);
void SCSICD_SetTransferRate(uint32 TransferRate); void SCSICD_SetTransferRate(uint32 TransferRate);
void SCSICD_SetCDDAVolume(double left, double right); void SCSICD_SetCDDAVolume(double left, double right);
void SCSICD_StateAction(StateMem *sm, const unsigned load, const bool data_only, const char *sname); void SCSICD_StateAction(StateMem *sm, const unsigned load, const bool data_only, const char *sname);
void SCSICD_SetDisc(bool tray_open, CDIF *cdif, bool no_emu_side_effects = false); void SCSICD_SetDisc(bool tray_open, CDIF *cdif, bool no_emu_side_effects = false);
#endif #endif

7907
psx/mednadisc/trio/trio.c Normal file

File diff suppressed because it is too large Load Diff

270
psx/mednadisc/trio/trio.h Normal file
View File

@ -0,0 +1,270 @@
/*************************************************************************
*
* $Id$
*
* 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)
/* Argument function types */
enum {
TRIO_TYPE_POINTER = 1,
TRIO_TYPE_CHAR = 2,
TRIO_TYPE_SHORT = 3,
TRIO_TYPE_INT = 4,
TRIO_TYPE_LONG = 5,
TRIO_TYPE_ULONGLONG = 6,
TRIO_TYPE_UINTMAX = 7,
TRIO_TYPE_PTRDIFF = 8,
TRIO_TYPE_SIZE = 9,
TRIO_TYPE_PCHAR = 10,
TRIO_TYPE_PWCHAR = 11,
TRIO_TYPE_FLOAT = 12,
TRIO_TYPE_DOUBLE = 13,
TRIO_TYPE_LONGDOUBLE = 14
};
typedef trio_pointer_t (*trio_argfunc_t) TRIO_PROTO((trio_pointer_t, int, int));
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
*/
#if defined(TRIO_COMPILER_GCC) && !TRIO_EXTENSION
# define TRIO_PROTO_PRINTF(x,a) TRIO_PROTO(x) __attribute__ ((format (gnu_printf, a, a+1)))
# define TRIO_PROTO_SCANF(x,a) TRIO_PROTO(x) __attribute__ ((format (gnu_scanf, a, a+1)))
#else
# define TRIO_PROTO_PRINTF(x,a) TRIO_PROTO(x)
# define TRIO_PROTO_SCANF(x,a) TRIO_PROTO(x)
#endif
int trio_printf TRIO_PROTO_PRINTF((TRIO_CONST char *format, ...), 1);
int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
int trio_printfv TRIO_PROTO((TRIO_CONST char *format, trio_pointer_t *args));
int trio_fprintf TRIO_PROTO_PRINTF((FILE *file, TRIO_CONST char *format, ...), 2);
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, trio_pointer_t *args));
int trio_dprintf TRIO_PROTO_PRINTF((int fd, TRIO_CONST char *format, ...), 2);
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, trio_pointer_t *args));
int trio_cprintf TRIO_PROTO_PRINTF((trio_outstream_t stream, trio_pointer_t closure,
TRIO_CONST char *format, ...),
3);
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, trio_pointer_t *args));
int trio_cprintff TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
TRIO_CONST char *format,
trio_argfunc_t func, trio_pointer_t context));
int trio_sprintf TRIO_PROTO_PRINTF((char *buffer, TRIO_CONST char *format, ...), 2);
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, trio_pointer_t *args));
int trio_snprintf TRIO_PROTO_PRINTF((char *buffer, size_t max, TRIO_CONST char *format, ...), 3);
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,
trio_pointer_t *args));
int trio_snprintfcat TRIO_PROTO_PRINTF((char *buffer, size_t max, TRIO_CONST char *format, ...), 3);
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_PRINTF((TRIO_CONST char *format, ...), 1);
char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
#endif
int trio_asprintf TRIO_PROTO_PRINTF((char **ret, TRIO_CONST char *format, ...), 2);
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_SCANF((TRIO_CONST char *format, ...), 1);
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_SCANF((FILE *file, TRIO_CONST char *format, ...), 2);
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_SCANF((int fd, TRIO_CONST char *format, ...), 2);
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_SCANF((trio_instream_t stream, trio_pointer_t closure,
TRIO_CONST char *format, ...),
3);
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_cscanff TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
TRIO_CONST char *format,
trio_argfunc_t func, trio_pointer_t context));
int trio_sscanf TRIO_PROTO_SCANF((TRIO_CONST char *buffer, TRIO_CONST char *format, ...), 2);
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,375 @@
/*************************************************************************
*
* $Id$
*
* 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
#if defined(__powerpc) || defined(__powerpc__) || defined(_ARCH_PPC)
# define TRIO_CPU_POWERPC
#endif
#if defined(__sparc) || defined(__sparc__)
# define TRIO_CPU_SPARC
#endif
#if defined(__s390x__) || defined(__zarch__) || defined(__SYSC_ZARCH__)
# define TRIO_CPU_SYSTEMZ
#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 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L)
# define PREDEF_STANDARD_C94
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 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 defined(__cplusplus) && (__cplusplus >= 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)
/* Based on http://gcc.gnu.org/wiki/Visibility */
# if defined(TRIO_PLATFORM_WIN32) || defined (__CYGWIN__)
# if defined(BUILDING_DLL)
# if defined(TRIO_COMPILER_GCC)
# define TRIO_PUBLIC __attribute__ ((dllexport))
# else
# define TRIO_PUBLIC __declspec(dllexport)
# endif
# else
# if defined(TRIO_COMPILER_GCC)
# define TRIO_PUBLIC __attribute__ ((dllimport))
# else
# define TRIO_PUBLIC __declspec(dllimport)
# endif
# endif
# else
# if defined(TRIO_COMPILER_GCC) && __GNUC__ >= 4
# define TRIO_PUBLIC __attribute__ ((visibility ("default")))
# define TRIO_PRIVATE __attribute__ ((visibility ("hidden")))
# else
# define TRIO_PUBLIC
# endif
# endif
#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_ARGS8(list,a1,a2,a3,a4,a5,a6,a7,a8) list a1; a2; a3; a4; a5; a6; a7; a8;
# 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_ARGS8(list,a1,a2,a3,a4,a5,a6,a7,a8) (a1,a2,a3,a4,a5,a6,a7,a8)
# 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
# if defined(TRIO_CPU_POWERPC) || defined(TRIO_CPU_SPARC) || defined(TRIO_CPU_SYSTEMZ)
# define TRIO_DOUBLE_DOUBLE
# endif
#endif /* TRIO_TRIODEF_H */

1318
psx/mednadisc/trio/trionan.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/*************************************************************************
*
* $Id$
*
* 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 */

496
psx/mednadisc/trio/triop.h Normal file
View File

@ -0,0 +1,496 @@
/*************************************************************************
*
* $Id$
*
* 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_ARGFUNC 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_ARGFUNC (=0 or =1)
*
* Define this to 0 to disable compilation of trio_cprintff() and
* trio_cscanff() functions and related code (might have a tiny
* performance gain), or define to 1 to enable them.
*
* This functionality is needed only if you have to fetch the arguments using
* a pull model instead of passing them all at once (for example if you plan
* to plug the library into a script interpreter or validate the types).
*
* Only the closure family of functions are available with this interface,
* because if you need this, you usually provide custom input/output
* handling too (and so this forces TRIO_FEATURE_CLOSURE to enabled).
*/
#if !defined(TRIO_FEATURE_ARGFUNC)
# define TRIO_FEATURE_ARGFUNC 1
#endif
#if TRIO_FEATURE_ARGFUNC
# undef 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));
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 */

2385
psx/mednadisc/trio/triostr.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,681 @@
/*************************************************************************
*
* $Id$
*
* 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 */