update mednadisc to 0.9.38.4
This commit is contained in:
parent
bea654bced
commit
fada87b3d3
|
@ -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;
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __MDFN_CDAFREADER_MPC_H
|
||||
#define __MDFN_CDAFREADER_MPC_H
|
||||
|
||||
CDAFReader* CDAFR_MPC_Open(Stream* fp);
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __MDFN_CDAFREADER_SF_H
|
||||
#define __MDFN_CDAFREADER_SF_H
|
||||
|
||||
CDAFReader* CDAFR_SF_Open(Stream* fp);
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __MDFN_CDAFREADER_VORBIS_H
|
||||
#define __MDFN_CDAFREADER_VORBIS_H
|
||||
|
||||
CDAFReader* CDAFR_Vorbis_Open(Stream* fp);
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
Loading…
Reference in New Issue