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;
try {
disc = cdaccess_open_image(fname,false);
disc = CDAccess_Open(fname,false);
}
catch(MDFN_Error &) {
return NULL;
@ -53,6 +53,9 @@ EW_EXPORT void mednadisc_ReadTOC(MednaDisc* md, JustTOC* justToc, CDUtility::TOC
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)
{
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>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\cdrom\audioreader.cpp" />
<ClCompile Include="..\cdrom\CDAccess.cpp" />
<ClCompile Include="..\cdrom\CDAccess_CCD.cpp" />
<ClCompile Include="..\cdrom\CDAccess_Image.cpp" />
<ClCompile Include="..\cdrom\CDAFReader.cpp" />
<ClCompile Include="..\cdrom\cdromif.cpp" />
<ClCompile Include="..\cdrom\CDUtility.cpp" />
<ClCompile Include="..\cdrom\crc32.cpp" />
@ -30,12 +30,15 @@
<ClCompile Include="..\MemoryStream.cpp" />
<ClCompile Include="..\Stream.cpp" />
<ClCompile Include="..\string\trim.cpp" />
<ClCompile Include="..\trio\trio.c" />
<ClCompile Include="..\trio\trionan.c" />
<ClCompile Include="..\trio\triostr.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\cdrom\audioreader.h" />
<ClInclude Include="..\cdrom\CDAccess.h" />
<ClInclude Include="..\cdrom\CDAccess_CCD.h" />
<ClInclude Include="..\cdrom\CDAccess_Image.h" />
<ClInclude Include="..\cdrom\CDAFReader.h" />
<ClInclude Include="..\cdrom\cdromif.h" />
<ClInclude Include="..\cdrom\CDUtility.h" />
<ClInclude Include="..\cdrom\dvdisaster.h" />
@ -51,6 +54,7 @@
<ClInclude Include="..\MemoryStream.h" />
<ClInclude Include="..\Stream.h" />
<ClInclude Include="..\string\trim.h" />
<ClInclude Include="..\trio\trio.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}</ProjectGuid>
@ -81,7 +85,7 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)\..\..\..\output\dll\</OutDir>
<OutDir>$(ProjectDir)..\..\..\output\dll\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
@ -92,7 +96,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<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>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>

View File

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

@ -20,10 +20,6 @@
#include "CDAccess_Image.h"
#include "CDAccess_CCD.h"
#ifdef HAVE_LIBCDIO
#include "CDAccess_Physical.h"
#endif
using namespace CDUtility;
CDAccess::CDAccess()
@ -36,7 +32,7 @@ CDAccess::~CDAccess()
}
CDAccess *cdaccess_open_image(const std::string& path, bool image_memcache)
CDAccess* CDAccess_Open(const std::string& path, bool image_memcache)
{
CDAccess *ret = NULL;
@ -48,11 +44,3 @@ CDAccess *cdaccess_open_image(const std::string& path, bool 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

@ -15,18 +15,19 @@ class CDAccess
virtual void Read_Raw_Sector(uint8 *buf, int32 lba) = 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.
//
// Writes 96 bytes into pwbuf, and returns 'true' otherwise.
virtual bool Fast_Read_Raw_PW_TSRE(uint8* pwbuf, int32 lba) const noexcept = 0;
virtual void Read_TOC(CDUtility::TOC *toc) = 0;
virtual bool Is_Physical(void) throw() = 0;
virtual void Eject(bool eject_status) = 0; // Eject a disc if it's physical, otherwise NOP. Returns true on success(or NOP), false on error
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

View File

@ -15,11 +15,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#define CHECK_CCD_GARBAGE_CUBQ_A
//#define CHECK_CCD_GARBAGE_CUBQ_B
//#define CHECK_CCD_GARBAGE_CUBQ_C
//#define CHECK_CCD_GARBAGE_CUBQ_D
#include "emuware/emuware.h"
#include "../general.h"
#include "../string/trim.h"
#include "CDAccess_CCD.h"
//#include <trio/trio.h>
#include <trio/trio.h>
//wrapper to repair gettext stuff
#define _(X) X
@ -91,17 +96,9 @@ static T CCD_ReadInt(CCD_Section &s, const std::string &propname, const bool hav
}
CDAccess_CCD::CDAccess_CCD(const std::string& path, bool image_memcache) : img_stream(NULL), sub_stream(NULL), img_numsectors(0)
CDAccess_CCD::CDAccess_CCD(const std::string& path, bool image_memcache) : img_numsectors(0)
{
try
{
Load(path, image_memcache);
}
catch(...)
{
Cleanup();
throw;
}
Load(path, image_memcache);
}
void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
@ -210,7 +207,7 @@ void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
for(unsigned te = 0; te < toc_entries; te++)
{
char tmpbuf[64];
snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te);
trio_snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te);
CCD_Section& ts = Sections[std::string(tmpbuf)];
unsigned session = CCD_ReadInt<unsigned>(ts, "SESSION");
uint8 point = CCD_ReadInt<uint8>(ts, "POINT");
@ -225,14 +222,14 @@ void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
throw MDFN_Error(0, "Unsupported TOC entry Session value: %u", session);
// Reference: ECMA-394, page 5-14
if(point >= 1 && point <= 99)
{
tocd.tracks[point].adr = adr;
if(point >= 1 && point <= 99)
{
tocd.tracks[point].adr = adr;
tocd.tracks[point].control = control;
tocd.tracks[point].lba = plba;
}
else
switch(point)
tocd.tracks[point].valid = true;
}
else switch(point)
{
default:
throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point);
@ -251,18 +248,12 @@ void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
tocd.tracks[100].adr = adr;
tocd.tracks[100].control = control;
tocd.tracks[100].lba = plba;
break;
tocd.tracks[100].valid = true;
break;
}
}
}
// Convenience leadout track duplication.
if(tocd.last_track < 99)
tocd.tracks[tocd.last_track + 1] = tocd.tracks[100];
//
// Open image stream.
{
@ -270,18 +261,21 @@ void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
if(image_memcache)
{
img_stream = new MemoryStream(new FileStream(image_path, FileStream::MODE_READ));
img_stream.reset(new MemoryStream(new FileStream(image_path, FileStream::MODE_READ)));
}
else
{
img_stream = new FileStream(image_path, FileStream::MODE_READ);
img_stream.reset(new FileStream(image_path, FileStream::MODE_READ));
}
int64 ss = img_stream->size();
uint64 ss = img_stream->size();
if(ss % 2352)
throw MDFN_Error(0, _("CCD image size is not evenly divisible by 2352."));
if(ss > 0x7FFFFFFF)
throw MDFN_Error(0, _("CCD image is too large."));
img_numsectors = ss / 2352;
}
@ -289,14 +283,13 @@ void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
// Open subchannel stream
{
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(image_memcache)
sub_stream = new MemoryStream(new FileStream(sub_path, FileStream::MODE_READ));
else
sub_stream = new FileStream(sub_path, FileStream::MODE_READ);
if(sub_stream->size() != (uint64)img_numsectors * 96)
if(sub_stream.size() != (uint64)img_numsectors * 96)
throw MDFN_Error(0, _("CCD SUB file size mismatch."));
sub_data.reset(new uint8[(uint64)img_numsectors * 96]);
sub_stream.read(sub_data.get(), (uint64)img_numsectors * 96);
}
CheckSubQSanity();
@ -328,8 +321,7 @@ void CDAccess_CCD::CheckSubQSanity(void)
};
} buf;
sub_stream->seek(s * 96, SEEK_SET);
sub_stream->read(buf.full, 96);
memcpy(buf.full, &sub_data[s * 96], 96);
if(subq_check_checksum(buf.qbuf))
{
@ -352,23 +344,31 @@ void CDAccess_CCD::CheckSubQSanity(void)
!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)
{
#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);
#endif
}
else
{
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);
#ifdef CHECK_CCD_GARBAGE_SUBQ_B
if(prev_lba != INT_MAX && abs(lba - prev_lba) > 100)
throw MDFN_Error(0, _("Garbage subchannel Q data detected(excessively large jump in AMSF)"));
#endif
if(abs(lba - (int)s) > 100)
#ifdef CHECK_CCD_GARBAGE_SUBQ_C
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(AMSF value is out of tolerance)"));
#endif
prev_lba = lba;
#ifdef CHECK_CCD_GARBAGE_SUBQ_D
if(track < prev_track)
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad track number)"));
#endif
//else if(prev_track && track - pre
prev_track = track;
@ -381,55 +381,52 @@ void CDAccess_CCD::CheckSubQSanity(void)
//printf("%u/%u\n", checksum_pass_counter, img_numsectors);
}
void CDAccess_CCD::Cleanup(void)
{
if(img_stream)
{
delete img_stream;
img_stream = NULL;
}
if(sub_stream)
{
delete sub_stream;
sub_stream = NULL;
}
}
CDAccess_CCD::~CDAccess_CCD()
{
Cleanup();
}
void CDAccess_CCD::Read_Raw_Sector(uint8 *buf, int32 lba)
{
if(lba < 0 || (size_t)lba >= img_numsectors)
throw(MDFN_Error(0, _("LBA out of range.")));
if(lba < 0)
{
synth_udapp_sector_lba(0xFF, tocd, lba, 0, buf);
return;
}
uint8 sub_buf[96];
if((size_t)lba >= img_numsectors)
{
synth_leadout_sector_lba(0xFF, tocd, lba, buf);
return;
}
img_stream->seek(lba * 2352, SEEK_SET);
img_stream->read(buf, 2352);
sub_stream->seek(lba * 96, SEEK_SET);
sub_stream->read(sub_buf, 96);
subpw_interleave(sub_buf, buf + 2352);
subpw_interleave(&sub_data[lba * 96], buf + 2352);
}
bool CDAccess_CCD::Fast_Read_Raw_PW_TSRE(uint8* pwbuf, int32 lba) const noexcept
{
if(lba < 0)
{
subpw_synth_udapp_lba(tocd, lba, 0, pwbuf);
return true;
}
if((size_t)lba >= img_numsectors)
{
subpw_synth_leadout_lba(tocd, lba, pwbuf);
return true;
}
subpw_interleave(&sub_data[lba * 96], pwbuf);
return true;
}
void CDAccess_CCD::Read_TOC(CDUtility::TOC *toc)
{
*toc = tocd;
}
bool CDAccess_CCD::Is_Physical(void) throw()
{
return false;
}
void CDAccess_CCD::Eject(bool eject_status)
{
}

View File

@ -18,8 +18,7 @@
#include "../FileStream.h"
#include "../MemoryStream.h"
#include "CDAccess.h"
#include <vector>
#include <memory>
class CDAccess_CCD : public CDAccess
{
@ -30,12 +29,10 @@ class CDAccess_CCD : public CDAccess
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 bool Is_Physical(void) throw();
virtual void Eject(bool eject_status);
private:
void Load(const std::string& path, bool image_memcache);
@ -43,8 +40,9 @@ class CDAccess_CCD : public CDAccess
void CheckSubQSanity(void);
Stream* img_stream;
Stream* sub_stream;
std::unique_ptr<Stream> img_stream;
std::unique_ptr<uint8[]> sub_data;
size_t img_numsectors;
CDUtility::TOC tocd;
};

View File

@ -26,8 +26,6 @@
A PREGAP statement in the first track definition in a CUE sheet may not work properly(depends on what is proper);
it will be added onto the implicit default 00:02:00 of pregap.
Trying to read sectors at an LBA of less than 0 is not supported. TODO: support it(at least up to -150).
*/
#include "emuware/emuware.h"
@ -40,6 +38,7 @@
#include <string.h>
#include <errno.h>
#include <time.h>
#include <trio/trio.h>
#include <memory>
#include "general.h"
@ -51,7 +50,7 @@
#include "CDAccess.h"
#include "CDAccess_Image.h"
#include "audioreader.h"
#include "CDAFReader.h"
#include <map>
@ -74,10 +73,11 @@ enum
DI_FORMAT_MODE2_FORM1 = 0x04,
DI_FORMAT_MODE2_FORM2 = 0x05,
DI_FORMAT_MODE2_RAW = 0x06,
DI_FORMAT_CDI_RAW = 0x07,
_DI_FORMAT_COUNT
};
static const int32 DI_Size_Table[7] =
static const int32 DI_Size_Table[8] =
{
2352, // Audio
2048, // MODE1
@ -85,10 +85,11 @@ static const int32 DI_Size_Table[7] =
2336, // MODE2
2048, // MODE2 Form 1
2324, // Mode 2 Form 2
2352
2352, // MODE2 RAW
2352, // CD-I RAW
};
static const char *DI_CDRDAO_Strings[7] =
static const char *DI_CDRDAO_Strings[8] =
{
"AUDIO",
"MODE1",
@ -96,20 +97,20 @@ static const char *DI_CDRDAO_Strings[7] =
"MODE2",
"MODE2_FORM1",
"MODE2_FORM2",
"MODE2_RAW"
"MODE2_RAW",
"CDI_RAW"
};
static const char *DI_CUE_Strings[7] =
static const char *DI_CUE_Strings[8] =
{
"AUDIO",
"MODE1/2048",
"MODE1/2352",
// FIXME: These are just guesses:
"MODE2/2336",
"MODE2/2048",
"MODE2/2324",
"MODE2/2352"
"MODE2/2336", // FIXME: A guess
"MODE2/2048", // FIXME: A guess
"MODE2/2324", // FIXME: A guess
"MODE2/2352", // FIXME: A guess
"CDI/2352",
};
// Should return an offset to the start of the next argument(past any whitespace), or if there isn't a next argument,
@ -235,7 +236,7 @@ void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int t
if(filename.length() >= 4 && !strcasecmp(filename.c_str() + filename.length() - 4, ".wav"))
{
track->AReader = AR_Open(track->fp);
track->AReader = CDAFR_Open(track->fp);
if(!track->AReader)
throw MDFN_Error(0, "TODO ERROR");
@ -246,12 +247,12 @@ void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int t
if(track->SubchannelMode)
sector_mult += 96;
if(binoffset && sscanf(binoffset, "%ld", &tmp_long) == 1)
if(binoffset && trio_sscanf(binoffset, "%ld", &tmp_long) == 1)
{
offset += tmp_long;
}
if(msfoffset && sscanf(msfoffset, "%d:%d:%d", &m, &s, &f) == 3)
if(msfoffset && trio_sscanf(msfoffset, "%d:%d:%d", &m, &s, &f) == 3)
{
offset += ((m * 60 + s) * 75 + f) * sector_mult;
}
@ -264,7 +265,7 @@ void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int t
{
tmp_long = sectors;
if(sscanf(length, "%d:%d:%d", &m, &s, &f) == 3)
if(trio_sscanf(length, "%d:%d:%d", &m, &s, &f) == 3)
tmp_long = (m * 60 + s) * 75 + f;
else if(track->DIFormat == DI_FORMAT_AUDIO)
{
@ -390,6 +391,14 @@ void CDAccess_Image::LoadSBI(const std::string& sbi_path)
}
}
static void StringToMSF(const char* str, unsigned* m, unsigned* s, unsigned* f)
{
if(trio_sscanf(str, "%u:%u:%u", m, s, f) != 3)
throw MDFN_Error(0, _("M:S:F time \"%s\" is malformed."), str);
if(*m > 99 || *s > 59 || *f > 74)
throw MDFN_Error(0, _("M:S:F time \"%s\" contains component(s) out of range."), str);
}
void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
{
@ -397,7 +406,7 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
static const unsigned max_args = 4;
std::string linebuf;
std::string cmdbuf, args[max_args];
bool IsTOC = false;
bool IsTOC = FALSE_0;
int32 active_track = -1;
int32 AutoTrackInc = 1; // For TOC
CDRFILE_TRACK_INFO TmpTrack;
@ -509,7 +518,7 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
}
if(TmpTrack.DIFormat == DI_FORMAT_AUDIO)
TmpTrack.RawAudioMSBFirst = true; // Silly cdrdao...
TmpTrack.RawAudioMSBFirst = TRUE_1; // Silly cdrdao...
if(!strcasecmp(args[1].c_str(), "RW"))
{
@ -577,8 +586,11 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
{
throw(MDFN_Error(0, _("Command %s is outside of a TRACK definition!\n"), cmdbuf.c_str()));
}
int m,s,f;
sscanf(args[0].c_str(), "%d:%d:%d", &m, &s, &f);
unsigned int m,s,f;
StringToMSF(args[0].c_str(), &m, &s, &f);
TmpTrack.pregap = (m * 60 + s) * 75 + f;
} // end to PREGAP
else if(cmdbuf == "START")
@ -587,8 +599,11 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
{
throw(MDFN_Error(0, _("Command %s is outside of a TRACK definition!\n"), cmdbuf.c_str()));
}
int m,s,f;
sscanf(args[0].c_str(), "%d:%d:%d", &m, &s, &f);
unsigned int m,s,f;
StringToMSF(args[0].c_str(), &m, &s, &f);
TmpTrack.pregap = (m * 60 + s) * 75 + f;
}
else if(cmdbuf == "TWO_CHANNEL_AUDIO")
@ -666,7 +681,7 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
else if(!strcasecmp(args[1].c_str(), "OGG") || !strcasecmp(args[1].c_str(), "VORBIS") || !strcasecmp(args[1].c_str(), "WAVE") || !strcasecmp(args[1].c_str(), "WAV") || !strcasecmp(args[1].c_str(), "PCM")
|| !strcasecmp(args[1].c_str(), "MPC") || !strcasecmp(args[1].c_str(), "MP+"))
{
TmpTrack.AReader = AR_Open(TmpTrack.fp);
TmpTrack.AReader = CDAFR_Open(TmpTrack.fp);
if(!TmpTrack.AReader)
{
throw(MDFN_Error(0, _("Unsupported audio track file format: %s\n"), args[0].c_str()));
@ -691,6 +706,11 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
}
active_track = atoi(args[0].c_str());
if(active_track < 1 || active_track > 99)
{
throw(MDFN_Error(0, _("Invalid track number: %d\n"), active_track));
}
if(active_track < FirstTrack)
FirstTrack = active_track;
if(active_track > LastTrack)
@ -710,11 +730,6 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
{
throw(MDFN_Error(0, _("Invalid track format: %s\n"), args[1].c_str()));
}
if(active_track < 0 || active_track > 99)
{
throw(MDFN_Error(0, _("Invalid track number: %d\n"), active_track));
}
}
else if(cmdbuf == "INDEX")
{
@ -722,10 +737,7 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
{
unsigned int m,s,f;
if(sscanf(args[1].c_str(), "%u:%u:%u", &m, &s, &f) != 3)
{
throw MDFN_Error(0, _("Malformed m:s:f time in \"%s\" directive: %s"), cmdbuf.c_str(), args[0].c_str());
}
StringToMSF(args[1].c_str(), &m, &s, &f);
if(!strcasecmp(args[0].c_str(), "01") || !strcasecmp(args[0].c_str(), "1"))
TmpTrack.index[1] = (m * 60 + s) * 75 + f;
@ -739,10 +751,7 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
{
unsigned int m,s,f;
if(sscanf(args[0].c_str(), "%u:%u:%u", &m, &s, &f) != 3)
{
throw MDFN_Error(0, _("Malformed m:s:f time in \"%s\" directive: %s"), cmdbuf.c_str(), args[0].c_str());
}
StringToMSF(args[0].c_str(), &m, &s, &f);
TmpTrack.pregap = (m * 60 + s) * 75 + f;
}
@ -753,10 +762,7 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
{
unsigned int m,s,f;
if(sscanf(args[0].c_str(), "%u:%u:%u", &m, &s, &f) != 3)
{
throw MDFN_Error(0, _("Malformed m:s:f time in \"%s\" directive: %s"), cmdbuf.c_str(), args[0].c_str());
}
StringToMSF(args[0].c_str(), &m, &s, &f);
TmpTrack.postgap = (m * 60 + s) * 75 + f;
}
@ -820,8 +826,14 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
int32 LastIndex = 0;
long FileOffset = 0;
RunningLBA -= 150;
Tracks[FirstTrack].pregap += 150;
for(int x = FirstTrack; x < (FirstTrack + NumTracks); x++)
{
if(!Tracks[x].fp && !Tracks[x].AReader)
throw MDFN_Error(0, _("Missing track %u."), x);
if(Tracks[x].DIFormat == DI_FORMAT_AUDIO)
Tracks[x].subq_control &= ~SUBQ_CTRLF_DATA;
else
@ -829,16 +841,23 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
if(!IsTOC) // TOC-format disc_type calculation is handled differently.
{
switch(Tracks[x].DIFormat)
if(disc_type != DISC_TYPE_CD_I)
{
default: break;
switch(Tracks[x].DIFormat)
{
default: break;
case DI_FORMAT_MODE2:
case DI_FORMAT_MODE2_FORM1:
case DI_FORMAT_MODE2_FORM2:
case DI_FORMAT_MODE2_RAW:
case DI_FORMAT_MODE2:
case DI_FORMAT_MODE2_FORM1:
case DI_FORMAT_MODE2_FORM2:
case DI_FORMAT_MODE2_RAW:
disc_type = DISC_TYPE_CD_XA;
break;
case DI_FORMAT_CDI_RAW:
disc_type = DISC_TYPE_CD_I;
break;
}
}
}
@ -917,6 +936,8 @@ void CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
LoadSBI(MDFN_EvalFIP(base_dir, file_base + std::string(".") + std::string(sbi_ext), true).c_str());
}
GenerateTOC();
}
void CDAccess_Image::Cleanup(void)
@ -964,64 +985,122 @@ CDAccess_Image::~CDAccess_Image()
void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
{
bool TrackFound = FALSE_0;
uint8 SimuQ[0xC];
int32 track;
CDRFILE_TRACK_INFO *ct;
//
// Leadout synthesis
//
if(lba >= total_sectors)
{
uint8 data_synth_mode = (disc_type == DISC_TYPE_CD_XA ? 0x02 : 0x01);
switch(Tracks[LastTrack].DIFormat)
{
case DI_FORMAT_AUDIO:
break;
case DI_FORMAT_MODE1_RAW:
case DI_FORMAT_MODE1:
data_synth_mode = 0x01;
break;
case DI_FORMAT_MODE2_RAW:
case DI_FORMAT_MODE2_FORM1:
case DI_FORMAT_MODE2_FORM2:
case DI_FORMAT_MODE2:
case DI_FORMAT_CDI_RAW:
data_synth_mode = 0x02;
break;
}
synth_leadout_sector_lba(data_synth_mode, toc, lba, buf);
return;
}
//
//
//
memset(buf + 2352, 0, 96);
MakeSubPQ(lba, buf + 2352);
track = MakeSubPQ(lba, buf + 2352);
subq_deinterleave(buf + 2352, SimuQ);
for(int32 track = FirstTrack; track < (FirstTrack + NumTracks); track++)
ct = &Tracks[track];
//
// Handle pregap and postgap reading
//
if(lba < (ct->LBA - ct->pregap_dv) || lba >= (ct->LBA + ct->sectors))
{
CDRFILE_TRACK_INFO *ct = &Tracks[track];
int32 pg_offset = lba - ct->LBA;
CDRFILE_TRACK_INFO* et = ct;
if(lba >= (ct->LBA - ct->pregap_dv - ct->pregap) && lba < (ct->LBA + ct->sectors + ct->postgap))
if(pg_offset < -150)
{
TrackFound = TRUE_1;
if((Tracks[track].subq_control & SUBQ_CTRLF_DATA) && (FirstTrack < track) && !(Tracks[track - 1].subq_control & SUBQ_CTRLF_DATA))
et = &Tracks[track - 1];
}
// Handle pregap and postgap reading
if(lba < (ct->LBA - ct->pregap_dv) || lba >= (ct->LBA + ct->sectors))
memset(buf, 0, 2352);
switch(et->DIFormat)
{
case DI_FORMAT_AUDIO:
break;
case DI_FORMAT_MODE1_RAW:
case DI_FORMAT_MODE1:
encode_mode1_sector(lba + 150, buf);
break;
case DI_FORMAT_MODE2_RAW:
case DI_FORMAT_MODE2_FORM1:
case DI_FORMAT_MODE2_FORM2:
case DI_FORMAT_MODE2:
case DI_FORMAT_CDI_RAW:
buf[12 + 6] = 0x20;
buf[12 + 10] = 0x20;
encode_mode2_form2_sector(lba + 150, buf);
// TODO: Zero out optional(?) checksum bytes?
break;
}
//printf("Pre/post-gap read, LBA=%d(LBA-track_start_LBA=%d)\n", lba, lba - ct->LBA);
}
else
{
if(ct->AReader)
{
int16 AudioBuf[588 * 2];
uint64 frames_read = ct->AReader->Read((ct->FileOffset / 4) + (lba - ct->LBA) * 588, AudioBuf, 588);
ct->LastSamplePos += frames_read;
if(frames_read > 588) // This shouldn't happen.
{
//printf("Pre/post-gap read, LBA=%d(LBA-track_start_LBA=%d)\n", lba, lba - ct->LBA);
memset(buf, 0, 2352); // Null sector data, per spec
printf("Error: frames_read out of range: %llu\n", (unsigned long long)frames_read);
frames_read = 0;
}
else
if(frames_read < 588)
memset((uint8 *)AudioBuf + frames_read * 2 * sizeof(int16), 0, (588 - frames_read) * 2 * sizeof(int16));
for(int i = 0; i < 588 * 2; i++)
MDFN_en16lsb<false>(buf + i * 2, AudioBuf[i]);
}
else // Binary, woo.
{
long SeekPos = ct->FileOffset;
long LBARelPos = lba - ct->LBA;
SeekPos += LBARelPos * DI_Size_Table[ct->DIFormat];
if(ct->SubchannelMode)
SeekPos += 96 * (lba - ct->LBA);
ct->fp->seek(SeekPos, SEEK_SET);
switch(ct->DIFormat)
{
if(ct->AReader)
{
int16 AudioBuf[588 * 2];
int frames_read = ct->AReader->Read((ct->FileOffset / 4) + (lba - ct->LBA) * 588, AudioBuf, 588);
ct->LastSamplePos += frames_read;
if(frames_read < 0 || frames_read > 588) // This shouldn't happen.
{
printf("Error: frames_read out of range: %d\n", frames_read);
frames_read = 0;
}
if(frames_read < 588)
memset((uint8 *)AudioBuf + frames_read * 2 * sizeof(int16), 0, (588 - frames_read) * 2 * sizeof(int16));
for(int i = 0; i < 588 * 2; i++)
MDFN_en16lsb<false>(buf + i * 2, AudioBuf[i]);
}
else // Binary, woo.
{
long SeekPos = ct->FileOffset;
long LBARelPos = lba - ct->LBA;
SeekPos += LBARelPos * DI_Size_Table[ct->DIFormat];
if(ct->SubchannelMode)
SeekPos += 96 * (lba - ct->LBA);
ct->fp->seek(SeekPos, SEEK_SET);
switch(ct->DIFormat)
{
case DI_FORMAT_AUDIO:
ct->fp->read(buf, 2352);
@ -1036,6 +1115,7 @@ void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
case DI_FORMAT_MODE1_RAW:
case DI_FORMAT_MODE2_RAW:
case DI_FORMAT_CDI_RAW:
ct->fp->read(buf, 2352);
break;
@ -1057,55 +1137,47 @@ void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
//encode_mode2_form2_sector(lba + 150, buf);
break;
}
}
if(ct->SubchannelMode)
ct->fp->read(buf + 2352, 96);
}
} // end if audible part of audio track read.
break;
} // End if LBA is in range
} // end track search loop
if(!TrackFound)
{
throw(MDFN_Error(0, _("Could not find track for sector %u!"), lba));
}
#if 0
if(qbuf[0] & 0x40)
{
uint8 dummy_buf[2352 + 96];
bool any_mismatch = FALSE;
memcpy(dummy_buf + 16, buf + 16, 2048);
memset(dummy_buf + 2352, 0, 96);
MakeSubPQ(lba, dummy_buf + 2352);
encode_mode1_sector(lba + 150, dummy_buf);
for(int i = 0; i < 2352 + 96; i++)
{
if(dummy_buf[i] != buf[i])
{
printf("Mismatch at %d, %d: %02x:%02x; ", lba, i, dummy_buf[i], buf[i]);
any_mismatch = TRUE;
if(ct->SubchannelMode)
ct->fp->read(buf + 2352, 96);
}
}
if(any_mismatch)
puts("\n");
}
#endif
} // end if audible part of audio track read.
}
//subq_deinterleave(buf + 2352, qbuf);
//printf("%02x\n", qbuf[0]);
//printf("%02x\n", buf[12 + 3]);
bool CDAccess_Image::Fast_Read_Raw_PW_TSRE(uint8* pwbuf, int32 lba) const noexcept
{
int32 track;
if(lba >= total_sectors)
{
subpw_synth_leadout_lba(toc, lba, pwbuf);
return(true);
}
memset(pwbuf, 0, 96);
try
{
track = MakeSubPQ(lba, pwbuf);
}
catch(...)
{
return(false);
}
//
// If TOC+BIN has embedded subchannel data, we can't fast-read(synthesize) it...
//
if(Tracks[track].SubchannelMode && lba >= (Tracks[track].LBA - Tracks[track].pregap_dv) && (lba < Tracks[track].LBA + Tracks[track].sectors))
return(false);
return(true);
}
//
// Note: this function makes use of the current contents(as in |=) in SubPWBuf.
//
void CDAccess_Image::MakeSubPQ(int32 lba, uint8 *SubPWBuf)
int32 CDAccess_Image::MakeSubPQ(int32 lba, uint8 *SubPWBuf) const
{
uint8 buf[0xC];
int32 track;
@ -1124,15 +1196,13 @@ void CDAccess_Image::MakeSubPQ(int32 lba, uint8 *SubPWBuf)
}
}
//printf("%d %d\n", Tracks[1].LBA, Tracks[1].sectors);
if(!track_found)
{
printf("MakeSubPQ error for sector %u!", lba);
track = FirstTrack;
}
throw(MDFN_Error(0, _("Could not find track for sector %u!"), lba));
lba_relative = abs((int32)lba - Tracks[track].LBA);
if(lba < Tracks[track].LBA)
lba_relative = Tracks[track].LBA - 1 - lba;
else
lba_relative = lba - Tracks[track].LBA;
f = (lba_relative % 75);
s = ((lba_relative / 75) % 60);
@ -1209,39 +1279,41 @@ void CDAccess_Image::MakeSubPQ(int32 lba, uint8 *SubPWBuf)
for(int i = 0; i < 96; i++)
SubPWBuf[i] |= (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | pause_or;
return track;
}
void CDAccess_Image::Read_TOC(TOC *toc)
void CDAccess_Image::Read_TOC(TOC *rtoc)
{
toc->Clear();
*rtoc = toc;
}
toc->first_track = FirstTrack;
toc->last_track = FirstTrack + NumTracks - 1;
toc->disc_type = disc_type;
void CDAccess_Image::GenerateTOC(void)
{
toc.Clear();
for(int i = toc->first_track; i <= toc->last_track; i++)
toc.first_track = FirstTrack;
toc.last_track = FirstTrack + NumTracks - 1;
toc.disc_type = disc_type;
for(int i = FirstTrack; i < FirstTrack + NumTracks; i++)
{
toc->tracks[i].lba = Tracks[i].LBA;
toc->tracks[i].adr = ADR_CURPOS;
toc->tracks[i].control = Tracks[i].subq_control;
if(Tracks[i].DIFormat == DI_FORMAT_CDI_RAW)
{
toc.first_track = std::min<int>(99, i + 1);
toc.last_track = std::max<int>(toc.first_track, toc.last_track);
}
toc.tracks[i].lba = Tracks[i].LBA;
toc.tracks[i].adr = ADR_CURPOS;
toc.tracks[i].control = Tracks[i].subq_control;
toc.tracks[i].valid = true;
}
toc->tracks[100].lba = total_sectors;
toc->tracks[100].adr = ADR_CURPOS;
toc->tracks[100].control = toc->tracks[toc->last_track].control & 0x4;
// Convenience leadout track duplication.
if(toc->last_track < 99)
toc->tracks[toc->last_track + 1] = toc->tracks[100];
toc.tracks[100].lba = total_sectors;
toc.tracks[100].adr = ADR_CURPOS;
toc.tracks[100].control = Tracks[FirstTrack + NumTracks - 1].subq_control & 0x4;
toc.tracks[100].valid = true;
}
bool CDAccess_Image::Is_Physical(void) throw()
{
return(false);
}
void CDAccess_Image::Eject(bool eject_status)
{
}

View File

@ -5,7 +5,7 @@
#include <array>
class Stream;
class AudioReader;
class CDAFReader;
struct CDRFILE_TRACK_INFO
{
@ -30,7 +30,7 @@ struct CDRFILE_TRACK_INFO
uint32 LastSamplePos;
AudioReader *AReader;
CDAFReader *AReader;
};
#if 0
struct Medium_Chunk
@ -69,11 +69,10 @@ class CDAccess_Image : public CDAccess
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 bool Is_Physical(void) throw();
virtual void Eject(bool eject_status);
private:
int32 NumTracks;
@ -82,6 +81,7 @@ class CDAccess_Image : public CDAccess
int32 total_sectors;
uint8 disc_type;
CDRFILE_TRACK_INFO Tracks[100]; // Track #0(HMM?) through 99
CDUtility::TOC toc;
std::map<uint32, std::array<uint8, 12>> SubQReplaceMap;
@ -89,10 +89,11 @@ class CDAccess_Image : public CDAccess
void ImageOpen(const std::string& path, bool image_memcache);
void LoadSBI(const std::string& sbi_path);
void GenerateTOC(void);
void Cleanup(void);
// MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf.
void MakeSubPQ(int32 lba, uint8 *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);

View File

@ -25,6 +25,7 @@
#include "dvdisaster.h"
#include "lec.h"
#include <assert.h>
// Kill_LEC_Correct();
@ -255,7 +256,12 @@ void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
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 control = toc.tracks[100].control;
if(toc.tracks[toc.last_track].valid)
control |= toc.tracks[toc.last_track].control & 0x4;
else if(toc.disc_type == DISC_TYPE_CD_I)
control |= 0x4;
memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4);
@ -280,13 +286,21 @@ void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
}
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
{
memset(out_buf, 0, 2352 + 96);
subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
if((toc.tracks[toc.last_track].control | toc.tracks[100].control) & 0x4)
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:
@ -298,7 +312,104 @@ void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba,
break;
case 0x02:
out_buf[18] = 0x20;
out_buf[12 + 6] = 0x20;
out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break;
}
}
}
// 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;
}

View File

@ -32,6 +32,7 @@ namespace CDUtility
uint8 adr;
uint8 control;
uint32 lba;
bool valid; // valid/present; oh CD-i...
};
// SubQ control field flags.
@ -65,30 +66,28 @@ namespace CDUtility
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;
for(int32 track = 1; track <= 100; track++)
{
if(track == (last_track + 1))
{
if(LBA < tracks[100].lba)
return(track - 1);
}
else
{
if(LBA < tracks[track].lba)
return(track - 1);
}
if(!tracks[track].valid)
continue;
if(LBA < tracks[track].lba)
break;
lvt = track;
}
return(0);
return(lvt);
}
uint8 first_track;
uint8 last_track;
uint8 disc_type;
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
// Also, for convenience, tracks[last_track + 1] will always refer
// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).
};
//
@ -172,9 +171,19 @@ namespace CDUtility
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.
// "mode" is only used if(toc.tracks[100].control & 0x4)
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
// "mode" is not used if the area is to be encoded as audio.
// 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);
// out_buf must be able to contain 2352+96 bytes.
// "mode" is not used if the area is to be encoded as audio.
// pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.
void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf);
//
// User data error detection and correction

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/lec.cpp cdrom/CDAccess.cpp cdrom/CDAccess_Image.cpp cdrom/CDAccess_CCD.cpp
if HAVE_LIBCDIO
mednafen_SOURCES += cdrom/CDAccess_Physical.cpp
mednafen_SOURCES += cdrom/CDAFReader.cpp
mednafen_SOURCES += cdrom/CDAFReader_Vorbis.cpp
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

View File

@ -17,10 +17,8 @@
#include <string.h>
#include <sys/types.h>
#include <algorithm>
#include <trio/trio.h>
#include "emuware/emuware.h"
#include "cdromif.h"
#include "CDAccess.h"
#include "general.h"
@ -28,6 +26,7 @@
//undo gettext stuff
#define _(X) X
#include <algorithm>
using namespace CDUtility;
@ -46,8 +45,6 @@ enum
CDIF_MSG_READ_SECTOR, /* Emu -> read
args[0] = lba
*/
CDIF_MSG_EJECT, // Emu -> read, args[0]; 0=insert, 1=eject
};
class CDIF_Message
@ -65,16 +62,81 @@ class CDIF_Message
std::string str_message;
};
#ifdef WANT_QUEUE
class CDIF_Queue
{
public:
CDIF_Queue();
~CDIF_Queue();
bool Read(CDIF_Message *message, bool blocking = TRUE);
void Write(const CDIF_Message &message);
private:
std::queue<CDIF_Message> ze_queue;
MDFN_Mutex *ze_mutex;
MDFN_Cond *ze_cond;
};
#endif
typedef struct
{
bool valid;
bool error;
uint32 lba;
int32 lba;
uint8 data[2352 + 96];
} CDIF_Sector_Buffer;
#ifdef WANT_QUEUE
// TODO: prohibit copy constructor
class CDIF_MT : public CDIF
{
public:
CDIF_MT(CDAccess *cda);
virtual ~CDIF_MT();
virtual void HintReadSector(int32 lba);
virtual bool ReadRawSector(uint8 *buf, int32 lba);
virtual bool ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread);
// FIXME: Semi-private:
int ReadThreadStart(void);
private:
CDAccess *disc_cdaccess;
MDFN_Thread *CDReadThread;
// Queue for messages to the read thread.
CDIF_Queue ReadThreadQueue;
// Queue for messages to the emu thread.
CDIF_Queue EmuThreadQueue;
enum { SBSize = 256 };
CDIF_Sector_Buffer SectorBuffers[SBSize];
uint32 SBWritePos;
MDFN_Mutex *SBMutex;
MDFN_Cond *SBCond;
//
// Read-thread-only:
//
int32 ra_lba;
int32 ra_count;
int32 last_read_lba;
};
#endif //WANT_QUEUE
// TODO: prohibit copy constructor
class CDIF_ST : public CDIF
@ -84,15 +146,15 @@ class CDIF_ST : public CDIF
CDIF_ST(CDAccess *cda);
virtual ~CDIF_ST();
virtual void HintReadSector(uint32 lba);
virtual bool ReadRawSector(uint8 *buf, uint32 lba);
virtual bool Eject(bool eject_status);
virtual void HintReadSector(int32 lba);
virtual bool ReadRawSector(uint8 *buf, int32 lba);
virtual bool ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread);
private:
CDAccess *disc_cdaccess;
};
CDIF::CDIF() : UnrecoverableError(false), is_phys_cache(false), DiscEjected(false)
CDIF::CDIF() : UnrecoverableError(false)
{
}
@ -130,6 +192,301 @@ CDIF_Message::~CDIF_Message()
}
#ifdef WANT_QUEUE
CDIF_Queue::CDIF_Queue()
{
ze_mutex = MDFND_CreateMutex();
ze_cond = MDFND_CreateCond();
}
CDIF_Queue::~CDIF_Queue()
{
MDFND_DestroyMutex(ze_mutex);
MDFND_DestroyCond(ze_cond);
}
// Returns FALSE if message not read, TRUE if it was read. Will always return TRUE if "blocking" is set.
// Will throw MDFN_Error if the read message code is CDIF_MSG_FATAL_ERROR
bool CDIF_Queue::Read(CDIF_Message *message, bool blocking)
{
bool ret = true;
//
//
//
MDFND_LockMutex(ze_mutex);
if(blocking)
{
while(ze_queue.size() == 0) // while, not just if.
{
MDFND_WaitCond(ze_cond, ze_mutex);
}
}
if(ze_queue.size() == 0)
ret = false;
else
{
*message = ze_queue.front();
ze_queue.pop();
}
MDFND_UnlockMutex(ze_mutex);
//
//
//
if(ret && message->message == CDIF_MSG_FATAL_ERROR)
throw MDFN_Error(0, "%s", message->str_message.c_str());
return(ret);
}
void CDIF_Queue::Write(const CDIF_Message &message)
{
MDFND_LockMutex(ze_mutex);
try
{
ze_queue.push(message);
}
catch(...)
{
fprintf(stderr, "\n\nCDIF_Message queue push failed!!! (We now return you to your regularly unscheduled lockup)\n\n");
}
MDFND_SignalCond(ze_cond); // Signal while the mutex is held to prevent icky race conditions.
MDFND_UnlockMutex(ze_mutex);
}
struct RTS_Args
{
CDIF_MT *cdif_ptr;
};
static int ReadThreadStart_C(void *v_arg)
{
RTS_Args *args = (RTS_Args *)v_arg;
return args->cdif_ptr->ReadThreadStart();
}
int CDIF_MT::ReadThreadStart()
{
bool Running = TRUE;
SBWritePos = 0;
ra_lba = 0;
ra_count = 0;
last_read_lba = LBA_Read_Maximum + 1;
try
{
disc_cdaccess->Read_TOC(&disc_toc);
if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
{
throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
}
SBWritePos = 0;
ra_lba = 0;
ra_count = 0;
last_read_lba = LBA_Read_Maximum + 1;
memset(SectorBuffers, 0, SBSize * sizeof(CDIF_Sector_Buffer));
}
catch(std::exception &e)
{
EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what())));
return(0);
}
EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE));
while(Running)
{
CDIF_Message msg;
// Only do a blocking-wait for a message if we don't have any sectors to read-ahead.
// MDFN_DispMessage("%d %d %d\n", last_read_lba, ra_lba, ra_count);
if(ReadThreadQueue.Read(&msg, ra_count ? FALSE : TRUE))
{
switch(msg.message)
{
case CDIF_MSG_DIEDIEDIE:
Running = FALSE;
break;
case CDIF_MSG_READ_SECTOR:
{
static const int max_ra = 16;
static const int initial_ra = 1;
static const int speedmult_ra = 2;
int32 new_lba = msg.args[0];
assert((unsigned int)max_ra < (SBSize / 4));
if(new_lba == (last_read_lba + 1))
{
int how_far_ahead = ra_lba - new_lba;
if(how_far_ahead <= max_ra)
ra_count = std::min(speedmult_ra, 1 + max_ra - how_far_ahead);
else
ra_count++;
}
else if(new_lba != last_read_lba)
{
ra_lba = new_lba;
ra_count = initial_ra;
}
last_read_lba = new_lba;
}
break;
}
}
//
// Don't read beyond what the disc (image) readers can handle sanely.
//
if(ra_count && ra_lba == LBA_Read_Maximum)
{
ra_count = 0;
//printf("Ephemeral scarabs: %d!\n", ra_lba);
}
if(ra_count)
{
uint8 tmpbuf[2352 + 96];
bool error_condition = false;
try
{
disc_cdaccess->Read_Raw_Sector(tmpbuf, ra_lba);
}
catch(std::exception &e)
{
MDFN_PrintError(_("Sector %u read error: %s"), ra_lba, e.what());
memset(tmpbuf, 0, sizeof(tmpbuf));
error_condition = true;
}
//
//
MDFND_LockMutex(SBMutex);
SectorBuffers[SBWritePos].lba = ra_lba;
memcpy(SectorBuffers[SBWritePos].data, tmpbuf, 2352 + 96);
SectorBuffers[SBWritePos].valid = TRUE;
SectorBuffers[SBWritePos].error = error_condition;
SBWritePos = (SBWritePos + 1) % SBSize;
MDFND_SignalCond(SBCond);
MDFND_UnlockMutex(SBMutex);
//
//
ra_lba++;
ra_count--;
}
}
return(1);
}
CDIF_MT::CDIF_MT(CDAccess *cda) : disc_cdaccess(cda), CDReadThread(NULL), SBMutex(NULL), SBCond(NULL)
{
try
{
CDIF_Message msg;
RTS_Args s;
if(!(SBMutex = MDFND_CreateMutex()))
throw MDFN_Error(0, _("Error creating CD read thread mutex."));
if(!(SBCond = MDFND_CreateCond()))
throw MDFN_Error(0, _("Error creating CD read thread condition variable."));
UnrecoverableError = false;
s.cdif_ptr = this;
if(!(CDReadThread = MDFND_CreateThread(ReadThreadStart_C, &s)))
throw MDFN_Error(0, _("Error creating CD read thread."));
EmuThreadQueue.Read(&msg);
}
catch(...)
{
if(CDReadThread)
{
MDFND_WaitThread(CDReadThread, NULL);
CDReadThread = NULL;
}
if(SBMutex)
{
MDFND_DestroyMutex(SBMutex);
SBMutex = NULL;
}
if(SBCond)
{
MDFND_DestroyCond(SBCond);
SBCond = NULL;
}
if(disc_cdaccess)
{
delete disc_cdaccess;
disc_cdaccess = NULL;
}
throw;
}
}
CDIF_MT::~CDIF_MT()
{
bool thread_deaded_failed = false;
try
{
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_DIEDIEDIE));
}
catch(std::exception &e)
{
MDFND_PrintError(e.what());
thread_deaded_failed = true;
}
if(!thread_deaded_failed)
MDFND_WaitThread(CDReadThread, NULL);
if(SBMutex)
{
MDFND_DestroyMutex(SBMutex);
SBMutex = NULL;
}
if(SBCond)
{
MDFND_DestroyCond(SBCond);
SBCond = NULL;
}
if(disc_cdaccess)
{
delete disc_cdaccess;
disc_cdaccess = NULL;
}
}
#endif //WANT_QUEUE
bool CDIF::ValidateRawSector(uint8 *buf)
{
@ -143,14 +500,114 @@ bool CDIF::ValidateRawSector(uint8 *buf)
return(true);
}
int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
#ifdef WANT_QUEUE
bool CDIF_MT::ReadRawSector(uint8 *buf, int32 lba)
{
bool found = FALSE;
bool error_condition = false;
if(UnrecoverableError)
{
memset(buf, 0, 2352 + 96);
return(false);
}
if(lba < LBA_Read_Minimum || lba > LBA_Read_Maximum)
{
printf("Attempt to read sector out of bounds; LBA=%d\n", lba);
memset(buf, 0, 2352 + 96);
return(false);
}
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
//
//
//
MDFND_LockMutex(SBMutex);
do
{
for(int i = 0; i < SBSize; i++)
{
if(SectorBuffers[i].valid && SectorBuffers[i].lba == lba)
{
error_condition = SectorBuffers[i].error;
memcpy(buf, SectorBuffers[i].data, 2352 + 96);
found = TRUE;
}
}
if(!found)
{
//int32 swt = MDFND_GetTime();
MDFND_WaitCond(SBCond, SBMutex);
//printf("SB Waited: %d\n", MDFND_GetTime() - swt);
}
} while(!found);
MDFND_UnlockMutex(SBMutex);
//
//
//
return(!error_condition);
}
bool CDIF_MT::ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread)
{
if(UnrecoverableError)
{
memset(pwbuf, 0, 96);
return(false);
}
if(lba < LBA_Read_Minimum || lba > LBA_Read_Maximum)
{
printf("Attempt to read sector out of bounds; LBA=%d\n", lba);
memset(pwbuf, 0, 96);
return(false);
}
if(disc_cdaccess->Fast_Read_Raw_PW_TSRE(pwbuf, lba))
{
if(hint_fullread)
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
return(true);
}
else
{
uint8 tmpbuf[2352 + 96];
bool ret;
ret = ReadRawSector(tmpbuf, lba);
memcpy(pwbuf, tmpbuf + 2352, 96);
return ret;
}
}
void CDIF_MT::HintReadSector(int32 lba)
{
if(UnrecoverableError)
return;
ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
}
#endif //WANT_QUEUE
int CDIF::ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message)
{
int ret = 0;
if(UnrecoverableError)
return(false);
while(nSectors--)
while(sector_count--)
{
uint8 tmpbuf[2352 + 96];
@ -162,7 +619,11 @@ int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
if(!ValidateRawSector(tmpbuf))
{
printf(_("Uncorrectable data at sector %d"), lba);
if(!suppress_uncorrectable_message)
{
printf(_("Uncorrectable data at sector %d"), lba);
}
return(false);
}
@ -173,11 +634,11 @@ int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
if(mode == 1)
{
memcpy(pBuf, &tmpbuf[12 + 4], 2048);
memcpy(buf, &tmpbuf[12 + 4], 2048);
}
else if(mode == 2)
{
memcpy(pBuf, &tmpbuf[12 + 4 + 8], 2048);
memcpy(buf, &tmpbuf[12 + 4 + 8], 2048);
}
else
{
@ -185,7 +646,7 @@ int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
return(false);
}
pBuf += 2048;
buf += 2048;
lba++;
}
@ -202,9 +663,7 @@ CDIF_ST::CDIF_ST(CDAccess *cda) : disc_cdaccess(cda)
{
//puts("***WARNING USING SINGLE-THREADED CD READER***");
is_phys_cache = disc_cdaccess->Is_Physical();
UnrecoverableError = false;
DiscEjected = false;
disc_cdaccess->Read_TOC(&disc_toc);
@ -223,12 +682,12 @@ CDIF_ST::~CDIF_ST()
}
}
void CDIF_ST::HintReadSector(uint32 lba)
void CDIF_ST::HintReadSector(int32 lba)
{
// TODO: disc_cdaccess seek hint? (probably not, would require asynchronousitycamel)
}
bool CDIF_ST::ReadRawSector(uint8 *buf, uint32 lba)
bool CDIF_ST::ReadRawSector(uint8 *buf, int32 lba)
{
if(UnrecoverableError)
{
@ -236,6 +695,13 @@ bool CDIF_ST::ReadRawSector(uint8 *buf, uint32 lba)
return(false);
}
if(lba < LBA_Read_Minimum || lba > LBA_Read_Maximum)
{
printf("Attempt to read sector out of bounds; LBA=%d\n", lba);
memset(buf, 0, 2352 + 96);
return(false);
}
try
{
disc_cdaccess->Read_Raw_Sector(buf, lba);
@ -250,42 +716,35 @@ bool CDIF_ST::ReadRawSector(uint8 *buf, uint32 lba)
return(true);
}
bool CDIF_ST::Eject(bool eject_status)
bool CDIF_ST::ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread)
{
if(UnrecoverableError)
return(false);
try
{
if(eject_status != DiscEjected)
{
disc_cdaccess->Eject(eject_status);
// Set after ->Eject(), since it might throw an exception.
DiscEjected = -1; // For if TOC reading fails or there's something horribly wrong with the disc.
if(!eject_status) // Re-read the TOC
{
disc_cdaccess->Read_TOC(&disc_toc);
if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
{
throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
}
}
DiscEjected = eject_status;
}
}
catch(std::exception &e)
{
printf("%s", e.what());
memset(pwbuf, 0, 96);
return(false);
}
return(true);
if(lba < LBA_Read_Minimum || lba > LBA_Read_Maximum)
{
printf("Attempt to read sector out of bounds; LBA=%d\n", lba);
memset(pwbuf, 0, 96);
return(false);
}
if(disc_cdaccess->Fast_Read_Raw_PW_TSRE(pwbuf, lba))
return(true);
else
{
uint8 tmpbuf[2352 + 96];
bool ret;
ret = ReadRawSector(tmpbuf, lba);
memcpy(pwbuf, tmpbuf + 2352, 96);
return ret;
}
}
class CDIF_Stream_Thing : public Stream
{
public:
@ -420,15 +879,20 @@ void CDIF_Stream_Thing::close(void)
}
Stream *CDIF::MakeStream(uint32 lba, uint32 sector_count)
Stream *CDIF::MakeStream(int32 lba, uint32 sector_count)
{
return new CDIF_Stream_Thing(this, lba, sector_count);
}
CDIF *CDIF_Open(const std::string& path, const bool is_device, bool image_memcache)
CDIF *CDIF_Open(const std::string& path, bool image_memcache)
{
CDAccess *cda = cdaccess_open_image(path, image_memcache);
CDAccess *cda = CDAccess_Open(path, image_memcache);
return new CDIF_ST(cda);
#ifdef WANT_QUEUE
if(!image_memcache)
return new CDIF_MT(cda);
else
#endif
return new CDIF_ST(cda);
}

View File

@ -32,13 +32,17 @@ class CDIF
CDIF();
virtual ~CDIF();
static const int32 LBA_Read_Minimum = -150;
static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1
inline void ReadTOC(CDUtility::TOC *read_target)
{
*read_target = disc_toc;
}
virtual void HintReadSector(uint32 lba) = 0;
virtual bool ReadRawSector(uint8 *buf, uint32 lba) = 0;
virtual void HintReadSector(int32 lba) = 0;
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.
// Call for mode 1 or mode 2 form 1 only.
bool ValidateRawSector(uint8 *buf);
@ -46,25 +50,17 @@ class CDIF
// Utility/Wrapped functions
// Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
// Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
int ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors);
// Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
// Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
virtual bool Eject(bool eject_status) = 0;
inline bool IsPhysical(void) { return(is_phys_cache); }
int ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message = false);
// 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.
Stream *MakeStream(uint32 lba, uint32 sector_count);
Stream *MakeStream(int32 lba, uint32 sector_count);
protected:
bool UnrecoverableError;
bool is_phys_cache;
CDUtility::TOC disc_toc;
int DiscEjected; // 0 = inserted, 1 = ejected, -1 = DRAGONS ATE THE DISC. NOM NOM NOM.
};
CDIF *CDIF_Open(const std::string& path, const bool is_device, bool image_memcache);
CDIF *CDIF_Open(const std::string& path, bool image_memcache);
#endif

View File

@ -10,7 +10,7 @@ static void DoNEC_PCE_SAPSP(const uint8 *cdb)
//printf("Set audio start: %02x %02x %02x %02x %02x %02x %02x\n", cdb[9], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6]);
switch (cdb[9] & 0xc0)
{
default: SCSIDBG("Unknown SAPSP 9: %02x\n", cdb[9]);
default: //SCSIDBG("Unknown SAPSP 9: %02x\n", cdb[9]);
case 0x00:
new_read_sec_start = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
break;
@ -81,7 +81,7 @@ static void DoNEC_PCE_SAPEP(const uint8 *cdb)
switch (cdb[9] & 0xc0)
{
default: SCSIDBG("Unknown SAPEP 9: %02x\n", cdb[9]);
default: //SCSIDBG("Unknown SAPEP 9: %02x\n", cdb[9]);
case 0x00:
new_read_sec_end = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
@ -203,8 +203,8 @@ static void DoNEC_PCE_GETDIRINFO(const uint8 *cdb)
switch(cdb[1])
{
default: MDFN_DispMessage("Unknown GETDIRINFO Mode: %02x", cdb[1]);
printf("Unknown GETDIRINFO Mode: %02x", cdb[1]);
default: //MDFN_DispMessage("Unknown GETDIRINFO Mode: %02x", cdb[1]);
//printf("Unknown GETDIRINFO Mode: %02x", cdb[1]);
case 0x0:
data_in[0] = U8_to_BCD(toc.first_track);
data_in[1] = U8_to_BCD(toc.last_track);

View File

@ -28,7 +28,7 @@
#include <emmintrin.h>
#endif
#define SCSIDBG(format, ...) { printf("[SCSICD] " format "\n", ## __VA_ARGS__); }
//#define SCSIDBG(format, ...) { printf("[SCSICD] " format "\n", ## __VA_ARGS__); }
//#define SCSIDBG(format, ...) { }
using namespace CDUtility;
@ -325,7 +325,7 @@ static void GenSubQFromSubPW(void)
if(!subq_check_checksum(SubQBuf))
{
SCSIDBG("SubQ checksum error!");
//SCSIDBG("SubQ checksum error!");
}
else
{
@ -456,7 +456,7 @@ static void SendStatusAndMessage(uint8 status, uint8 message)
// This should never ever happen, but that doesn't mean it won't. ;)
if(din->CanRead())
{
printf("[SCSICD] BUG: %d bytes still in SCSI CD FIFO\n", din->CanRead());
//printf("[SCSICD] BUG: %d bytes still in SCSI CD FIFO\n", din->CanRead());
din->Flush();
}
@ -516,7 +516,7 @@ void SCSICD_SetDisc(bool new_tray_open, CDIF *cdif, bool no_emu_side_effects)
static void CommandCCError(int key, int asc = 0, int ascq = 0)
{
printf("[SCSICD] CC Error: %02x %02x %02x\n", key, asc, ascq);
//printf("[SCSICD] CC Error: %02x %02x %02x\n", key, asc, ascq);
cd.key_pending = key;
cd.asc_pending = asc;
@ -788,10 +788,10 @@ static void FinishMODESELECT6(const uint8 *data, const uint8 data_len)
uint8 mode_data_length, medium_type, device_specific, block_descriptor_length;
uint32 offset = 0;
printf("[SCSICD] Mode Select (6) Data: Length=0x%02x, ", data_len);
for(uint32 i = 0; i < data_len; i++)
printf("0x%02x ", data[i]);
printf("\n");
//printf("[SCSICD] Mode Select (6) Data: Length=0x%02x, ", data_len);
//for(uint32 i = 0; i < data_len; i++)
// printf("0x%02x ", data[i]);
//printf("\n");
if(data_len < 4)
{
@ -905,7 +905,7 @@ static void DoMODESENSE6(const uint8 *cdb)
uint8 PageMatchOR = 0x00;
bool AnyPageMatch = false;
SCSIDBG("Mode sense 6: %02x %d %d %d", PageCode, PC, DBD, AllocSize);
//SCSIDBG("Mode sense 6: %02x %d %d %d", PageCode, PC, DBD, AllocSize);
if(!AllocSize)
{
@ -1004,18 +1004,18 @@ static void DoMODESENSE6(const uint8 *cdb)
static void DoSTARTSTOPUNIT6(const uint8 *cdb)
{
bool Immed = cdb[1] & 0x01;
bool LoEj = cdb[4] & 0x02;
bool Start = cdb[4] & 0x01;
//bool Immed = cdb[1] & 0x01;
//bool LoEj = cdb[4] & 0x02;
//bool Start = cdb[4] & 0x01;
SCSIDBG("Do start stop unit 6: %d %d %d\n", Immed, LoEj, Start);
//SCSIDBG("Do start stop unit 6: %d %d %d\n", Immed, LoEj, Start);
SendStatusAndMessage(STATUS_GOOD, 0x00);
}
static void DoREZEROUNIT(const uint8 *cdb)
{
SCSIDBG("Rezero Unit: %02x\n", cdb[5]);
//SCSIDBG("Rezero Unit: %02x\n", cdb[5]);
SendStatusAndMessage(STATUS_GOOD, 0x00);
}
@ -1953,7 +1953,7 @@ static void DoREAD6(const uint8 *cdb)
// TODO: confirm real PCE does this(PC-FX does at least).
if(!sc)
{
SCSIDBG("READ(6) with count == 0.\n");
//SCSIDBG("READ(6) with count == 0.\n");
sc = 256;
}
@ -2260,7 +2260,7 @@ static void DoNEC_SCAN(const uint8 *cdb)
switch (cdb[9] & 0xc0)
{
default:
SCSIDBG("Unknown NECSCAN format");
//SCSIDBG("Unknown NECSCAN format");
break;
case 0x00:
@ -2894,7 +2894,7 @@ uint32 SCSICD_Run(scsicd_timestamp_t system_timestamp)
{
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_INVALID_COMMAND);
SCSIDBG("Bad Command: %02x\n", cd.command_buffer[0]);
//SCSIDBG("Bad Command: %02x\n", cd.command_buffer[0]);
if(SCSILog)
SCSILog("SCSI", "Bad Command: %02x", cd.command_buffer[0]);
@ -2905,7 +2905,7 @@ uint32 SCSICD_Run(scsicd_timestamp_t system_timestamp)
{
if(cmd_info_ptr->flags & SCF_UNTESTED)
{
SCSIDBG("Untested SCSI command: %02x, %s", cd.command_buffer[0], cmd_info_ptr->pretty_name);
//SCSIDBG("Untested SCSI command: %02x, %s", cd.command_buffer[0], cmd_info_ptr->pretty_name);
}
if(TrayOpen && (cmd_info_ptr->flags & SCF_REQUIRES_MEDIUM))
@ -2983,7 +2983,7 @@ uint32 SCSICD_Run(scsicd_timestamp_t system_timestamp)
//if(cd_bus.DB == 0x6) // ABORT message!
if(1)
{
printf("[SCSICD] Abort Received(DB=0x%02x)\n", cd_bus.DB);
//printf("[SCSICD] Abort Received(DB=0x%02x)\n", cd_bus.DB);
din->Flush();
cd.data_out_pos = cd.data_out_want = 0;
@ -2991,8 +2991,8 @@ uint32 SCSICD_Run(scsicd_timestamp_t system_timestamp)
cdda.CDDAStatus = CDDASTATUS_STOPPED;
ChangePhase(PHASE_BUS_FREE);
}
else
printf("[SCSICD] Message to target: 0x%02x\n", cd_bus.DB);
//else
// printf("[SCSICD] Message to target: 0x%02x\n", cd_bus.DB);
}
break;

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