Remove Octoshock's unmanaged source and the binary
This commit is contained in:
parent
64a13ed003
commit
5403e86f1e
Binary file not shown.
|
@ -1,349 +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 "emuware/emuware.h"
|
||||
#include "FileStream.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
//#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//work around gettext
|
||||
#define _(X) X
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <sys/stat.h>
|
||||
#include <io.h>
|
||||
// These are not defined in MSVC version of stat.h
|
||||
#define S_IWUSR S_IWRITE
|
||||
#define S_IRUSR S_IREAD
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
// Some really bad preprocessor abuse follows to handle platforms that don't have fseeko and ftello...and of course
|
||||
// for largefile support on Windows:
|
||||
|
||||
#ifndef HAVE_FSEEKO
|
||||
#define fseeko fseek
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FTELLO
|
||||
#define ftello ftell
|
||||
#endif
|
||||
|
||||
#define STRUCT_STAT struct stat
|
||||
|
||||
#if SIZEOF_OFF_T == 4
|
||||
|
||||
#ifdef HAVE_FOPEN64
|
||||
#define fopen fopen64
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FTELLO64
|
||||
#undef ftello
|
||||
#define ftello ftello64
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSEEKO64
|
||||
#undef fseeko
|
||||
#define fseeko fseeko64
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSTAT64
|
||||
#define fstat fstat64
|
||||
#define stat stat64
|
||||
#undef STRUCT_STAT
|
||||
#define STRUCT_STAT struct stat64
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FTRUNCATE64
|
||||
#define ftruncate ftruncate64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
FileStream::FileStream(const std::string& path, const int mode) : OpenedMode(mode), mapping(NULL), mapping_size(0)
|
||||
{
|
||||
path_save = path;
|
||||
|
||||
if(mode == MODE_READ)
|
||||
fp = fopen(path.c_str(), "rb");
|
||||
else if(mode == MODE_WRITE)
|
||||
fp = fopen(path.c_str(), "wb");
|
||||
else if(mode == MODE_WRITE_SAFE || mode == MODE_WRITE_INPLACE) // SO ANNOYING
|
||||
{
|
||||
int open_flags = O_WRONLY | O_CREAT;
|
||||
|
||||
if(mode == MODE_WRITE_SAFE)
|
||||
open_flags |= O_EXCL;
|
||||
|
||||
#ifdef O_BINARY
|
||||
open_flags |= O_BINARY;
|
||||
#elif defined(_O_BINARY)
|
||||
open_flags |= _O_BINARY;
|
||||
#endif
|
||||
|
||||
#if defined(S_IRGRP) && defined(S_IROTH)
|
||||
int tmpfd = open(path.c_str(), open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
#else
|
||||
int tmpfd = open(path.c_str(), open_flags, S_IRUSR | S_IWUSR);
|
||||
#endif
|
||||
if(tmpfd == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
fp = fdopen(tmpfd, "wb");
|
||||
}
|
||||
else
|
||||
abort();
|
||||
|
||||
if(!fp)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
FileStream::~FileStream()
|
||||
{
|
||||
try
|
||||
{
|
||||
close();
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
printf(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
uint64 FileStream::attributes(void)
|
||||
{
|
||||
uint64 ret = ATTRIBUTE_SEEKABLE;
|
||||
|
||||
switch(OpenedMode)
|
||||
{
|
||||
case MODE_READ:
|
||||
ret |= ATTRIBUTE_READABLE;
|
||||
break;
|
||||
|
||||
case MODE_WRITE_INPLACE:
|
||||
case MODE_WRITE_SAFE:
|
||||
case MODE_WRITE:
|
||||
ret |= ATTRIBUTE_WRITEABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8 *FileStream::map(void) noexcept
|
||||
{
|
||||
if(!mapping)
|
||||
{
|
||||
#ifdef HAVE_MMAP
|
||||
uint64 length = size();
|
||||
int prot = 0;
|
||||
int flags = 0;
|
||||
void* tptr;
|
||||
|
||||
if(OpenedMode == MODE_READ)
|
||||
{
|
||||
prot |= PROT_READ; // | PROT_EXEC;
|
||||
flags |= MAP_PRIVATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
prot |= PROT_WRITE;
|
||||
prot |= MAP_SHARED;
|
||||
}
|
||||
|
||||
if(length > SIZE_MAX)
|
||||
return(NULL);
|
||||
|
||||
tptr = mmap(NULL, length, prot, flags, fileno(fp), 0);
|
||||
if(tptr != (void*)-1)
|
||||
{
|
||||
mapping = tptr;
|
||||
mapping_size = length;
|
||||
|
||||
#ifdef HAVE_MADVISE
|
||||
// Should probably make this controllable via flag or somesuch.
|
||||
madvise(mapping, mapping_size, MADV_SEQUENTIAL | MADV_WILLNEED);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return((uint8*)mapping);
|
||||
}
|
||||
|
||||
uint64 FileStream::map_size(void) noexcept
|
||||
{
|
||||
return mapping_size;
|
||||
}
|
||||
|
||||
void FileStream::unmap(void) noexcept
|
||||
{
|
||||
if(mapping)
|
||||
{
|
||||
#ifdef HAVE_MMAP
|
||||
munmap(mapping, mapping_size);
|
||||
#endif
|
||||
mapping = NULL;
|
||||
mapping_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64 FileStream::read(void *data, uint64 count, bool error_on_eos)
|
||||
{
|
||||
uint64 read_count;
|
||||
|
||||
clearerr(fp);
|
||||
|
||||
read_count = fread(data, 1, count, fp);
|
||||
|
||||
if(read_count != count)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
if(ferror(fp))
|
||||
throw(MDFN_Error(ene.Errno(), _("Error reading from opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
|
||||
if(error_on_eos)
|
||||
throw(MDFN_Error(0, _("Error reading from opened file \"%s\": %s"), path_save.c_str(), _("Unexpected EOF")));
|
||||
}
|
||||
|
||||
return(read_count);
|
||||
}
|
||||
|
||||
void FileStream::write(const void *data, uint64 count)
|
||||
{
|
||||
if(fwrite(data, 1, count, fp) != count)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error writing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
void FileStream::truncate(uint64 length)
|
||||
{
|
||||
//not needed by mednadisc
|
||||
//if(fflush(fp) == EOF || ftruncate(fileno(fp), length) != 0)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error truncating opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
void FileStream::seek(int64 offset, int whence)
|
||||
{
|
||||
if(fseeko(fp, offset, whence) == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error seeking in opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
void FileStream::flush(void)
|
||||
{
|
||||
if(fflush(fp) == EOF)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error flushing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
uint64 FileStream::tell(void)
|
||||
{
|
||||
auto offset = ftello(fp);
|
||||
|
||||
if(offset == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error getting position in opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
|
||||
return (std::make_unsigned<decltype(offset)>::type)offset;
|
||||
}
|
||||
|
||||
uint64 FileStream::size(void)
|
||||
{
|
||||
STRUCT_STAT buf;
|
||||
|
||||
if((OpenedMode != MODE_READ && fflush(fp) == EOF) || fstat(fileno(fp), &buf) == -1)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error getting the size of opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
|
||||
return (std::make_unsigned<decltype(buf.st_size)>::type)buf.st_size;
|
||||
}
|
||||
|
||||
void FileStream::close(void)
|
||||
{
|
||||
if(fp)
|
||||
{
|
||||
FILE *tmp = fp;
|
||||
|
||||
unmap();
|
||||
fp = NULL;
|
||||
|
||||
if(fclose(tmp) == EOF)
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error closing opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FileStream::get_line(std::string &str)
|
||||
{
|
||||
int c;
|
||||
|
||||
str.clear();
|
||||
|
||||
while((c = get_char()) >= 0)
|
||||
{
|
||||
if(c == '\r' || c == '\n' || c == 0)
|
||||
return(c);
|
||||
|
||||
str.push_back(c);
|
||||
}
|
||||
|
||||
return(str.length() ? 256 : -1);
|
||||
}
|
||||
|
|
@ -1,89 +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
|
||||
*/
|
||||
|
||||
#ifndef __MDFN_FILESTREAM_H
|
||||
#define __MDFN_FILESTREAM_H
|
||||
|
||||
#include "Stream.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
class FileStream : public Stream
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
MODE_READ = 0,
|
||||
MODE_WRITE,
|
||||
MODE_WRITE_SAFE, // Will throw an exception instead of overwriting an existing file.
|
||||
MODE_WRITE_INPLACE, // Like MODE_WRITE, but won't truncate the file if it already exists.
|
||||
};
|
||||
|
||||
FileStream(const std::string& path, const int mode);
|
||||
virtual ~FileStream() override;
|
||||
|
||||
virtual uint64 attributes(void) override;
|
||||
|
||||
virtual uint8 *map(void) noexcept override;
|
||||
virtual uint64 map_size(void) noexcept override;
|
||||
virtual void unmap(void) noexcept override;
|
||||
|
||||
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) override;
|
||||
virtual void write(const void *data, uint64 count) override;
|
||||
virtual void truncate(uint64 length) override;
|
||||
virtual void seek(int64 offset, int whence) override;
|
||||
virtual uint64 tell(void) override;
|
||||
virtual uint64 size(void) override;
|
||||
virtual void flush(void) override;
|
||||
virtual void close(void) override;
|
||||
|
||||
virtual int get_line(std::string &str) override;
|
||||
|
||||
INLINE int get_char(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
errno = 0;
|
||||
ret = fgetc(fp);
|
||||
|
||||
if(MDFN_UNLIKELY(errno != 0))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
throw(MDFN_Error(ene.Errno(), ("Error reading from opened file \"%s\": %s"), path_save.c_str(), ene.StrError()));
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
private:
|
||||
FileStream & operator=(const FileStream &); // Assignment operator
|
||||
FileStream(const FileStream &); // Copy constructor
|
||||
//FileStream(FileStream &); // Copy constructor
|
||||
|
||||
FILE *fp;
|
||||
std::string path_save;
|
||||
const int OpenedMode;
|
||||
|
||||
void* mapping;
|
||||
uint64 mapping_size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,81 +0,0 @@
|
|||
#include "emuware/emuware.h"
|
||||
|
||||
#include "Mednadisc.h"
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#include "cdrom/CDAccess.h"
|
||||
#include "cdrom/CDUtility.h"
|
||||
#include "cdrom/cdromif.h"
|
||||
#include "cdrom/CDAccess_Image.h"
|
||||
|
||||
|
||||
class MednaDisc
|
||||
{
|
||||
public:
|
||||
~MednaDisc()
|
||||
{
|
||||
delete disc;
|
||||
}
|
||||
CDAccess* disc;
|
||||
CDUtility::TOC toc;
|
||||
};
|
||||
|
||||
EW_EXPORT void* mednadisc_LoadCD(const char* fname)
|
||||
{
|
||||
CDAccess* disc = NULL;
|
||||
try {
|
||||
disc = CDAccess_Open(fname,false);
|
||||
}
|
||||
catch(MDFN_Error &) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MednaDisc* md = new MednaDisc();
|
||||
md->disc = disc;
|
||||
disc->Read_TOC(&md->toc);
|
||||
return md;
|
||||
}
|
||||
|
||||
struct JustTOC
|
||||
{
|
||||
uint8 first_track;
|
||||
uint8 last_track;
|
||||
uint8 disc_type;
|
||||
};
|
||||
|
||||
EW_EXPORT void mednadisc_ReadTOC(MednaDisc* md, JustTOC* justToc, CDUtility::TOC_Track *tracks101)
|
||||
{
|
||||
CDUtility::TOC &toc = md->toc;
|
||||
justToc->first_track = toc.first_track;
|
||||
justToc->last_track = toc.last_track;
|
||||
justToc->disc_type = toc.disc_type;
|
||||
memcpy(tracks101,toc.tracks,sizeof(toc.tracks));
|
||||
}
|
||||
|
||||
//NOTE: the subcode will come out interleaved.
|
||||
//Don't try changing this unless youre REALLY bored. It's convoluted.
|
||||
//If you do, make sure you have three states: must_interleave, must_deinterleaved and dontcare
|
||||
EW_EXPORT int32 mednadisc_ReadSector(MednaDisc* md, int lba, void* buf2448)
|
||||
{
|
||||
CDAccess* disc = md->disc;
|
||||
CDUtility::TOC &toc = md->toc;
|
||||
try
|
||||
{
|
||||
//EDIT: this is handled now by the individual readers
|
||||
//if it's at the lead-out track or beyond, synthesize it as a lead-out sector
|
||||
//if(lba >= (int32)toc.tracks[100].lba)
|
||||
// synth_leadout_sector_lba(0x02, toc, lba, (uint8*)buf2448);
|
||||
//else
|
||||
disc->Read_Raw_Sector((uint8*)buf2448,lba);
|
||||
}
|
||||
catch(MDFN_Error &) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
EW_EXPORT void mednadisc_CloseCD(MednaDisc* md)
|
||||
{
|
||||
delete md;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "emuware/emuware.h"
|
||||
|
||||
class MednaDisc;
|
||||
|
||||
EW_EXPORT void* mednadisc_LoadCD(const char* fname);
|
||||
EW_EXPORT int32 mednadisc_ReadSector(MednaDisc* disc, int lba, void* buf2448);
|
||||
EW_EXPORT void mednadisc_CloseCD(MednaDisc* disc);
|
|
@ -1,330 +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 <stdlib.h>
|
||||
#include "MemoryStream.h"
|
||||
#include "math_ops.h"
|
||||
#include "error.h"
|
||||
|
||||
//work around gettext
|
||||
#define _(X) X
|
||||
|
||||
/*
|
||||
TODO: Copy and assignment constructor fixes.
|
||||
|
||||
Proper negative position behavior?
|
||||
*/
|
||||
|
||||
MemoryStream::MemoryStream() : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
|
||||
{
|
||||
data_buffer_size = 0;
|
||||
data_buffer_alloced = 64;
|
||||
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(uint64 alloc_hint, int alloc_hint_is_size) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
|
||||
{
|
||||
if(alloc_hint_is_size != 0)
|
||||
{
|
||||
data_buffer_size = alloc_hint;
|
||||
data_buffer_alloced = alloc_hint;
|
||||
|
||||
if(alloc_hint > SIZE_MAX)
|
||||
throw MDFN_Error(ErrnoHolder(ENOMEM));
|
||||
}
|
||||
else
|
||||
{
|
||||
data_buffer_size = 0;
|
||||
data_buffer_alloced = (alloc_hint > SIZE_MAX) ? SIZE_MAX : alloc_hint;
|
||||
}
|
||||
|
||||
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
|
||||
if(alloc_hint_is_size > 0)
|
||||
memset(data_buffer, 0, data_buffer_size);
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(Stream *stream, uint64 size_limit) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if((position = stream->tell()) != 0)
|
||||
stream->seek(0, SEEK_SET);
|
||||
|
||||
void* tp;
|
||||
data_buffer_size = data_buffer_alloced = stream->alloc_and_read(&tp, size_limit);
|
||||
data_buffer = (uint8*)tp;
|
||||
stream->close();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
if(data_buffer)
|
||||
{
|
||||
free(data_buffer);
|
||||
data_buffer = NULL;
|
||||
}
|
||||
|
||||
delete stream;
|
||||
throw;
|
||||
}
|
||||
delete stream;
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(const MemoryStream &zs)
|
||||
{
|
||||
data_buffer_size = zs.data_buffer_size;
|
||||
data_buffer_alloced = zs.data_buffer_alloced;
|
||||
if(!(data_buffer = (uint8*)malloc(data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
|
||||
memcpy(data_buffer, zs.data_buffer, data_buffer_size);
|
||||
|
||||
position = zs.position;
|
||||
}
|
||||
|
||||
#if 0
|
||||
MemoryStream & MemoryStream::operator=(const MemoryStream &zs)
|
||||
{
|
||||
if(this != &zs)
|
||||
{
|
||||
if(data_buffer)
|
||||
{
|
||||
free(data_buffer);
|
||||
data_buffer = NULL;
|
||||
}
|
||||
|
||||
data_buffer_size = zs.data_buffer_size;
|
||||
data_buffer_alloced = zs.data_buffer_alloced;
|
||||
|
||||
if(!(data_buffer = (uint8*)malloc(data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
|
||||
memcpy(data_buffer, zs.data_buffer, data_buffer_size);
|
||||
|
||||
position = zs.position;
|
||||
}
|
||||
return(*this);
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryStream::~MemoryStream()
|
||||
{
|
||||
if(data_buffer)
|
||||
{
|
||||
free(data_buffer);
|
||||
data_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint64 MemoryStream::attributes(void)
|
||||
{
|
||||
return (ATTRIBUTE_READABLE | ATTRIBUTE_WRITEABLE | ATTRIBUTE_SEEKABLE);
|
||||
}
|
||||
|
||||
|
||||
uint8 *MemoryStream::map(void) noexcept
|
||||
{
|
||||
return data_buffer;
|
||||
}
|
||||
|
||||
uint64 MemoryStream::map_size(void) noexcept
|
||||
{
|
||||
return data_buffer_size;
|
||||
}
|
||||
|
||||
void MemoryStream::unmap(void) noexcept
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
INLINE void MemoryStream::grow_if_necessary(uint64 new_required_size, uint64 hole_end)
|
||||
{
|
||||
if(new_required_size > data_buffer_size)
|
||||
{
|
||||
const uint64 old_data_buffer_size = data_buffer_size;
|
||||
|
||||
if(new_required_size > data_buffer_alloced)
|
||||
{
|
||||
uint64 new_required_alloced = round_up_pow2(new_required_size);
|
||||
uint8 *new_data_buffer;
|
||||
|
||||
// first condition will happen at new_required_size > (1ULL << 63) due to round_up_pow2() "wrapping".
|
||||
// second condition can occur when running on a 32-bit system.
|
||||
if(new_required_alloced < new_required_size || new_required_alloced > SIZE_MAX)
|
||||
new_required_alloced = SIZE_MAX;
|
||||
|
||||
// If constrained alloc size isn't enough, throw an out-of-memory/address-space type error.
|
||||
if(new_required_alloced < new_required_size)
|
||||
throw MDFN_Error(ErrnoHolder(ENOMEM));
|
||||
|
||||
if(!(new_data_buffer = (uint8*)realloc(data_buffer, new_required_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
|
||||
//
|
||||
// Assign all in one go after the realloc() so we don't leave our object in an inconsistent state if the realloc() fails.
|
||||
//
|
||||
data_buffer = new_data_buffer;
|
||||
data_buffer_size = new_required_size;
|
||||
data_buffer_alloced = new_required_alloced;
|
||||
}
|
||||
else
|
||||
data_buffer_size = new_required_size;
|
||||
|
||||
if(hole_end > old_data_buffer_size)
|
||||
memset(data_buffer + old_data_buffer_size, 0, hole_end - old_data_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryStream::shrink_to_fit(void) noexcept
|
||||
{
|
||||
if(data_buffer_alloced > data_buffer_size)
|
||||
{
|
||||
uint8 *new_data_buffer;
|
||||
|
||||
new_data_buffer = (uint8*)realloc(data_buffer, data_buffer_size);
|
||||
|
||||
if(new_data_buffer != NULL)
|
||||
{
|
||||
data_buffer = new_data_buffer;
|
||||
data_buffer_alloced = data_buffer_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64 MemoryStream::read(void *data, uint64 count, bool error_on_eos)
|
||||
{
|
||||
//printf("%llu %llu %llu\n", position, count, data_buffer_size);
|
||||
|
||||
if(count > data_buffer_size)
|
||||
{
|
||||
if(error_on_eos)
|
||||
throw MDFN_Error(0, _("Unexpected EOF"));
|
||||
|
||||
count = data_buffer_size;
|
||||
}
|
||||
|
||||
if(position > (data_buffer_size - count))
|
||||
{
|
||||
if(error_on_eos)
|
||||
throw MDFN_Error(0, _("Unexpected EOF"));
|
||||
|
||||
if(data_buffer_size > position)
|
||||
count = data_buffer_size - position;
|
||||
else
|
||||
count = 0;
|
||||
}
|
||||
|
||||
memmove(data, &data_buffer[position], count);
|
||||
position += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void MemoryStream::write(const void *data, uint64 count)
|
||||
{
|
||||
uint64 nrs = position + count;
|
||||
|
||||
if(nrs < position)
|
||||
throw MDFN_Error(ErrnoHolder(EFBIG));
|
||||
|
||||
grow_if_necessary(nrs, position);
|
||||
|
||||
memmove(&data_buffer[position], data, count);
|
||||
position += count;
|
||||
}
|
||||
|
||||
//
|
||||
// Don't add code to reduce the amount of memory allocated(when possible) without providing a
|
||||
// per-stream setting to disable that behavior.
|
||||
//
|
||||
void MemoryStream::truncate(uint64 length)
|
||||
{
|
||||
grow_if_necessary(length, length);
|
||||
|
||||
data_buffer_size = length;
|
||||
}
|
||||
|
||||
void MemoryStream::seek(int64 offset, int whence)
|
||||
{
|
||||
uint64 new_position;
|
||||
|
||||
switch(whence)
|
||||
{
|
||||
default:
|
||||
throw MDFN_Error(ErrnoHolder(EINVAL));
|
||||
break;
|
||||
|
||||
case SEEK_SET:
|
||||
new_position = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
new_position = position + offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
new_position = data_buffer_size + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if(new_position < 0)
|
||||
throw MDFN_Error(ErrnoHolder(EINVAL));
|
||||
|
||||
position = new_position;
|
||||
}
|
||||
|
||||
uint64 MemoryStream::tell(void)
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
uint64 MemoryStream::size(void)
|
||||
{
|
||||
return data_buffer_size;
|
||||
}
|
||||
|
||||
void MemoryStream::flush(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MemoryStream::close(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
int MemoryStream::get_line(std::string &str)
|
||||
{
|
||||
str.clear(); // or str.resize(0)??
|
||||
|
||||
while((uint64)position < data_buffer_size)
|
||||
{
|
||||
uint8 c = data_buffer[position++];
|
||||
|
||||
if(c == '\r' || c == '\n' || c == 0)
|
||||
return(c);
|
||||
|
||||
str.push_back(c); // Should be faster than str.append(1, c)
|
||||
}
|
||||
|
||||
return(str.length() ? 256 : -1);
|
||||
}
|
||||
|
|
@ -1,77 +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
|
||||
*/
|
||||
|
||||
/*
|
||||
Notes:
|
||||
For performance reasons(like in the state rewinding code), we should try to make sure map()
|
||||
returns a pointer that is aligned to at least what malloc()/realloc() provides.
|
||||
(And maybe forcefully align it to at least 16 bytes in the future)
|
||||
*/
|
||||
|
||||
#ifndef __MDFN_MEMORYSTREAM_H
|
||||
#define __MDFN_MEMORYSTREAM_H
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
class MemoryStream : public Stream
|
||||
{
|
||||
public:
|
||||
|
||||
MemoryStream();
|
||||
MemoryStream(uint64 alloc_hint, int alloc_hint_is_size = false); // Pass -1 instead of 1 for alloc_hint_is_size to skip initialization of the memory.
|
||||
MemoryStream(Stream *stream, uint64 size_limit = ~(uint64)0);
|
||||
// Will create a MemoryStream equivalent of the contents of "stream", and then "delete stream".
|
||||
// Will only work if stream->tell() == 0, or if "stream" is seekable.
|
||||
// stream will be deleted even if this constructor throws.
|
||||
//
|
||||
// Will throw an exception if the initial size() of the MemoryStream would be greater than size_limit(useful for when passing
|
||||
// in GZFileStream streams).
|
||||
|
||||
MemoryStream(const MemoryStream &zs);
|
||||
MemoryStream & operator=(const MemoryStream &zs);
|
||||
|
||||
virtual ~MemoryStream() override;
|
||||
|
||||
virtual uint64 attributes(void) override;
|
||||
|
||||
virtual uint8 *map(void) noexcept override;
|
||||
virtual uint64 map_size(void) noexcept override;
|
||||
virtual void unmap(void) noexcept override;
|
||||
|
||||
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) override;
|
||||
virtual void write(const void *data, uint64 count) override;
|
||||
virtual void truncate(uint64 length) override;
|
||||
virtual void seek(int64 offset, int whence) override;
|
||||
virtual uint64 tell(void) override;
|
||||
virtual uint64 size(void) override;
|
||||
virtual void flush(void) override;
|
||||
virtual void close(void) override;
|
||||
|
||||
virtual int get_line(std::string &str) override;
|
||||
|
||||
void shrink_to_fit(void) noexcept; // Minimizes alloced memory.
|
||||
|
||||
private:
|
||||
uint8 *data_buffer;
|
||||
uint64 data_buffer_size;
|
||||
uint64 data_buffer_alloced;
|
||||
|
||||
uint64 position;
|
||||
|
||||
void grow_if_necessary(uint64 new_required_size, uint64 hole_end);
|
||||
};
|
||||
#endif
|
|
@ -1,219 +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 <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "emuware/emuware.h"
|
||||
#include "Stream.h"
|
||||
#include "error.h"
|
||||
|
||||
//work around gettext stuff
|
||||
#define _(X) X
|
||||
|
||||
|
||||
Stream::Stream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Stream::~Stream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint64 Stream::read_discard(uint64 count)
|
||||
{
|
||||
uint8 buf[1024];
|
||||
uint64 tmp;
|
||||
uint64 ret = 0;
|
||||
|
||||
do
|
||||
{
|
||||
tmp = read(buf, std::min<uint64>(count, sizeof(buf)), false);
|
||||
count -= tmp;
|
||||
ret += tmp;
|
||||
} while(tmp == sizeof(buf));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64 Stream::alloc_and_read(void** data_out, uint64 size_limit)
|
||||
{
|
||||
uint8 *data_buffer = NULL;
|
||||
uint64 data_buffer_size = 0;
|
||||
uint64 data_buffer_alloced = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if(attributes() & ATTRIBUTE_SLOW_SIZE)
|
||||
{
|
||||
uint64 rti;
|
||||
|
||||
data_buffer_size = 0;
|
||||
data_buffer_alloced = 65536;
|
||||
|
||||
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
|
||||
while((rti = read(data_buffer + data_buffer_size, data_buffer_alloced - data_buffer_size, false)) > 0)
|
||||
{
|
||||
uint8* new_data_buffer;
|
||||
|
||||
data_buffer_size += rti;
|
||||
|
||||
if(data_buffer_size == data_buffer_alloced)
|
||||
{
|
||||
data_buffer_alloced <<= 1;
|
||||
|
||||
if(data_buffer_alloced > size_limit) // So we can test against our size limit without going far far over it in temporary memory allocations.
|
||||
data_buffer_alloced = size_limit + 1;
|
||||
|
||||
if(data_buffer_size > size_limit)
|
||||
throw MDFN_Error(0, _("Size limit of %llu bytes would be exceeded."), (unsigned long long)size_limit);
|
||||
|
||||
if(!(new_data_buffer = (uint8 *)realloc(data_buffer, data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
data_buffer = new_data_buffer;
|
||||
}
|
||||
else // EOS
|
||||
break;
|
||||
}
|
||||
|
||||
if(data_buffer_alloced > data_buffer_size)
|
||||
{
|
||||
uint8 *new_data_buffer;
|
||||
|
||||
new_data_buffer = (uint8*)realloc(data_buffer, data_buffer_size);
|
||||
|
||||
if(new_data_buffer != NULL)
|
||||
{
|
||||
data_buffer = new_data_buffer;
|
||||
data_buffer_alloced = data_buffer_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data_buffer_size = size();
|
||||
data_buffer_alloced = data_buffer_size;
|
||||
|
||||
if(data_buffer_size > size_limit)
|
||||
throw MDFN_Error(0, _("Size limit of %llu bytes would be exceeded."), (unsigned long long)size_limit);
|
||||
|
||||
if(data_buffer_alloced > SIZE_MAX)
|
||||
throw MDFN_Error(ErrnoHolder(ENOMEM));
|
||||
|
||||
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
|
||||
read(data_buffer, data_buffer_size);
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
if(data_buffer)
|
||||
{
|
||||
free(data_buffer);
|
||||
data_buffer = NULL;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
*data_out = data_buffer;
|
||||
return data_buffer_size;
|
||||
}
|
||||
|
||||
uint8* Stream::map(void) noexcept
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
uint64 Stream::map_size(void) noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Stream::unmap(void) noexcept
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Stream::put_line(const std::string& str)
|
||||
{
|
||||
char l = '\n';
|
||||
|
||||
write(&str[0], str.size());
|
||||
write(&l, sizeof(l));
|
||||
}
|
||||
|
||||
|
||||
void Stream::print_format(const char *format, ...)
|
||||
{
|
||||
char *str = NULL;
|
||||
int rc;
|
||||
|
||||
va_list ap;
|
||||
|
||||
int size = 128;
|
||||
for(;;) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
str = (char*)malloc(size);
|
||||
size *= 2;
|
||||
int ret = vsprintf(str, format, ap);
|
||||
va_end(ap);
|
||||
if(ret>=0)
|
||||
break;
|
||||
free(str);
|
||||
}
|
||||
|
||||
if(rc < 0)
|
||||
throw MDFN_Error(0, "Error in trio_vasprintf()");
|
||||
else
|
||||
{
|
||||
try // Bleck
|
||||
{
|
||||
write(str, rc);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free(str);
|
||||
throw;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
|
||||
int Stream::get_line(std::string &str)
|
||||
{
|
||||
uint8 c;
|
||||
|
||||
str.clear(); // or str.resize(0)??
|
||||
|
||||
while(read(&c, sizeof(c), false) > 0)
|
||||
{
|
||||
if(c == '\r' || c == '\n' || c == 0)
|
||||
return(c);
|
||||
|
||||
str.push_back(c);
|
||||
}
|
||||
|
||||
return(str.length() ? 256 : -1);
|
||||
}
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
#ifndef __MDFN_STREAM_H
|
||||
#define __MDFN_STREAM_H
|
||||
|
||||
// TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument.
|
||||
|
||||
#include "emuware/emuware.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h> // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT.
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
|
||||
Stream();
|
||||
virtual ~Stream();
|
||||
|
||||
enum
|
||||
{
|
||||
ATTRIBUTE_READABLE = 1U << 0,
|
||||
ATTRIBUTE_WRITEABLE = 1U << 1,
|
||||
ATTRIBUTE_SEEKABLE = 1U << 2,
|
||||
ATTRIBUTE_SLOW_SEEK = 1U << 3,
|
||||
ATTRIBUTE_SLOW_SIZE = 1U << 4
|
||||
};
|
||||
virtual uint64 attributes(void) = 0;
|
||||
|
||||
virtual uint8 *map(void) noexcept;
|
||||
// Map the entirety of the stream data into the address space of the process, if possible, and return a pointer.
|
||||
// (the returned pointer must be cached, and returned on any subsequent calls to map() without an unmap()
|
||||
// in-between, to facilitate a sort of "feature-testing", to determine if an alternative like "MemoryStream"
|
||||
// should be used).
|
||||
//
|
||||
// If the mapping fails for whatever reason, return NULL rather than throwing an exception.
|
||||
//
|
||||
// For code using this functionality, ensure usage of map_size() instead of size(), unless you're only using a specific derived
|
||||
// class like MemoryStream() where the value returned by size() won't change unexpectedly due to outside factors.
|
||||
|
||||
virtual uint64 map_size(void) noexcept;
|
||||
// The size of the memory mapping area, point to which returned by map().
|
||||
//
|
||||
// Returns 0 on supported, or if no mapping currently exists.
|
||||
|
||||
virtual void unmap(void) noexcept;
|
||||
// Unmap the stream data from the address space. (Possibly invalidating the pointer returned from map()).
|
||||
// (must automatically be called, if necessary, from the destructor).
|
||||
//
|
||||
// If the data can't be "unmapped" as such because it was never mmap()'d or similar in the first place(such as with MemoryStream),
|
||||
// then this will be a nop.
|
||||
|
||||
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;
|
||||
virtual void write(const void *data, uint64 count) = 0;
|
||||
|
||||
virtual void truncate(uint64 length) = 0; // Should have ftruncate()-like semantics; but avoid using it to extend files.
|
||||
|
||||
virtual void seek(int64 offset, int whence = SEEK_SET) = 0;
|
||||
inline void rewind(void)
|
||||
{
|
||||
seek(0, SEEK_SET);
|
||||
}
|
||||
virtual uint64 tell(void) = 0;
|
||||
virtual uint64 size(void) = 0; // May implicitly call flush() if the stream is writeable.
|
||||
virtual void flush(void) = 0;
|
||||
virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream.
|
||||
// Necessary since this operation can fail(running out of disk space, for instance),
|
||||
// and throw an exception in the destructor would be a Bad Idea(TM).
|
||||
//
|
||||
// Manually calling this function isn't strictly necessary, but recommended when the
|
||||
// stream is writeable; it will be called automatically from the destructor, with any
|
||||
// exceptions thrown caught and logged.
|
||||
|
||||
//
|
||||
// Utility functions(TODO):
|
||||
//
|
||||
INLINE uint8 get_u8(void)
|
||||
{
|
||||
uint8 ret;
|
||||
|
||||
read(&ret, sizeof(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
INLINE void put_u8(uint8 c)
|
||||
{
|
||||
write(&c, sizeof(c));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_NE(void)
|
||||
{
|
||||
T ret;
|
||||
|
||||
read(&ret, sizeof(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_RE(void)
|
||||
{
|
||||
uint8 tmp[sizeof(T)];
|
||||
union
|
||||
{
|
||||
T ret;
|
||||
uint8 ret_u8[sizeof(T)];
|
||||
};
|
||||
|
||||
read(tmp, sizeof(tmp));
|
||||
|
||||
for(unsigned i = 0; i < sizeof(T); i++)
|
||||
ret_u8[i] = tmp[sizeof(T) - 1 - i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_NE(T c)
|
||||
{
|
||||
write(&c, sizeof(c));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_RE(T c)
|
||||
{
|
||||
uint8 tmp[sizeof(T)];
|
||||
|
||||
for(unsigned i = 0; i < sizeof(T); i++)
|
||||
tmp[i] = ((uint8 *)&c)[sizeof(T) - 1 - i];
|
||||
|
||||
write(tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_LE(void)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
return get_NE<T>();
|
||||
#else
|
||||
return get_RE<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_LE(T c)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
return put_NE<T>(c);
|
||||
#else
|
||||
return put_RE<T>(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_BE(void)
|
||||
{
|
||||
#ifndef LSB_FIRST
|
||||
return get_NE<T>();
|
||||
#else
|
||||
return get_RE<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_BE(T c)
|
||||
{
|
||||
#ifndef LSB_FIRST
|
||||
return put_NE<T>(c);
|
||||
#else
|
||||
return put_RE<T>(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
INLINE void put_string(const char* str)
|
||||
{
|
||||
write(str, strlen(str));
|
||||
}
|
||||
|
||||
// Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or 256 on EOF and
|
||||
// data has been read into "str", and -1 on EOF when no data has been read into "str".
|
||||
// The line-end char won't be added to "str".
|
||||
// It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n).
|
||||
// ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part
|
||||
// of it would be up to the STL implementation).
|
||||
// Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream)
|
||||
virtual int get_line(std::string &str);
|
||||
|
||||
virtual void put_line(const std::string& str);
|
||||
|
||||
virtual void print_format(const char *format, ...) MDFN_FORMATSTR(gnu_printf, 2, 3);
|
||||
|
||||
#if 0
|
||||
int scanf(const char *format, ...) MDFN_FORMATSTR(gnu_scanf, 2, 3);
|
||||
void put_string(const char *str);
|
||||
void put_string(const std::string &str);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Read until end-of-stream(or count), discarding any read data, and returns the amount of data "read".
|
||||
// (Useful for detecting and printing warnings about extra garbage data without needing to call size(),
|
||||
// which can be problematic for some types of Streams).
|
||||
uint64 read_discard(uint64 count = ~(uint64)0);
|
||||
|
||||
//
|
||||
// Reads stream starting at the current stream position(as returned by tell()), into memory allocated with malloc() and realloc(), and
|
||||
// sets *data_out to a pointer to the memory(which the caller will need to free() at some point).
|
||||
//
|
||||
// *data_out is only an output.
|
||||
//
|
||||
// If size_limit is/will be exceeded, an exception will be thrown, and *data_out will not be written to.
|
||||
//
|
||||
// Will return the amount of data read(and the size of the alloced memory).
|
||||
//
|
||||
uint64 alloc_and_read(void** data_out, uint64 size_limit = ~(uint64)0);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,608 +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 "../mednafen.h"
|
||||
#include "audioreader.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../tremor/ivorbisfile.h"
|
||||
#include "../mpcdec/mpcdec.h"
|
||||
|
||||
#ifdef HAVE_LIBSNDFILE
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#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)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new MPCReader(fp);
|
||||
}
|
||||
catch(int i)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPUSFILE
|
||||
try
|
||||
{
|
||||
return new OpusReader(fp);
|
||||
}
|
||||
catch(int i)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
return new OggVorbisReader(fp);
|
||||
}
|
||||
catch(int i)
|
||||
{
|
||||
}
|
||||
|
||||
#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,24 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mednadisc", "mednadisc.vcxproj", "{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Release|Win32.Build.0 = Release|Win32
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,138 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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" />
|
||||
<ClCompile Include="..\cdrom\galois.cpp" />
|
||||
<ClCompile Include="..\cdrom\l-ec.cpp" />
|
||||
<ClCompile Include="..\cdrom\lec.cpp" />
|
||||
<ClCompile Include="..\cdrom\recover-raw.cpp" />
|
||||
<ClCompile Include="..\endian.cpp" />
|
||||
<ClCompile Include="..\error.cpp" />
|
||||
<ClCompile Include="..\FileStream.cpp" />
|
||||
<ClCompile Include="..\general.cpp" />
|
||||
<ClCompile Include="..\Mednadisc.cpp" />
|
||||
<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\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" />
|
||||
<ClInclude Include="..\cdrom\galois-inlines.h" />
|
||||
<ClInclude Include="..\cdrom\lec.h" />
|
||||
<ClInclude Include="..\cdrom\SimpleFIFO.h" />
|
||||
<ClInclude Include="..\emuware\emuware.h" />
|
||||
<ClInclude Include="..\endian.h" />
|
||||
<ClInclude Include="..\error.h" />
|
||||
<ClInclude Include="..\FileStream.h" />
|
||||
<ClInclude Include="..\general.h" />
|
||||
<ClInclude Include="..\Mednadisc.h" />
|
||||
<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>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>mednadisc</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(ProjectDir)..\..\..\output\dll\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(ProjectDir)\..\..\..\output\dll\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<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>
|
||||
<PrecompiledHeaderOutputFile>
|
||||
</PrecompiledHeaderOutputFile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;TRIO_PUBLIC=;TRIO_PRIVATE=static;EW_EXPORT;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>
|
||||
</PrecompiledHeaderOutputFile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<AdditionalIncludeDirectories>../emuware/msvc;..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,119 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="cdrom">
|
||||
<UniqueIdentifier>{a3ffd332-9644-473f-b3b6-d31b08be5256}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="emuware">
|
||||
<UniqueIdentifier>{99e57b88-966c-4695-8f5c-1db6345b1b26}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<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">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\cdromif.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\CDUtility.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\crc32.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\galois.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\lec.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\l-ec.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\recover-raw.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\CDAccess.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\CDAccess_CCD.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Stream.cpp" />
|
||||
<ClCompile Include="..\error.cpp" />
|
||||
<ClCompile Include="..\FileStream.cpp" />
|
||||
<ClCompile Include="..\endian.cpp" />
|
||||
<ClCompile Include="..\MemoryStream.cpp" />
|
||||
<ClCompile Include="..\string\trim.cpp">
|
||||
<Filter>string</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\general.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="..\trio\trionan.c">
|
||||
<Filter>trio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\trio\triostr.c">
|
||||
<Filter>trio</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\cdrom\CDAccess_Image.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\cdromif.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\CDUtility.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\dvdisaster.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\galois-inlines.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\lec.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\SimpleFIFO.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\CDAccess.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\CDAccess_CCD.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\emuware\emuware.h">
|
||||
<Filter>emuware</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\error.h" />
|
||||
<ClInclude Include="..\Stream.h" />
|
||||
<ClInclude Include="..\FileStream.h" />
|
||||
<ClInclude Include="..\endian.h" />
|
||||
<ClInclude Include="..\MemoryStream.h" />
|
||||
<ClInclude Include="..\string\trim.h">
|
||||
<Filter>string</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\general.h" />
|
||||
<ClInclude Include="..\Mednadisc.h" />
|
||||
<ClInclude Include="..\trio\trio.h">
|
||||
<Filter>trio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\CDAFReader.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,83 +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
|
||||
*/
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#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
|
|
@ -1,238 +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/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);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __MDFN_CDAFREADER_MPC_H
|
||||
#define __MDFN_CDAFREADER_MPC_H
|
||||
|
||||
CDAFReader* CDAFR_MPC_Open(Stream* fp);
|
||||
|
||||
#endif
|
|
@ -1,155 +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/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);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __MDFN_CDAFREADER_SF_H
|
||||
#define __MDFN_CDAFREADER_SF_H
|
||||
|
||||
CDAFReader* CDAFR_SF_Open(Stream* fp);
|
||||
|
||||
#endif
|
|
@ -1,158 +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/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);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef __MDFN_CDAFREADER_VORBIS_H
|
||||
#define __MDFN_CDAFREADER_VORBIS_H
|
||||
|
||||
CDAFReader* CDAFR_Vorbis_Open(Stream* fp);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,46 +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 "emuware/emuware.h"
|
||||
#include "CDAccess.h"
|
||||
#include "CDAccess_Image.h"
|
||||
#include "CDAccess_CCD.h"
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
CDAccess::CDAccess()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDAccess::~CDAccess()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDAccess* CDAccess_Open(const std::string& path, bool image_memcache)
|
||||
{
|
||||
CDAccess *ret = NULL;
|
||||
|
||||
if(path.size() >= 4 && !strcasecmp(path.c_str() + path.size() - 4, ".ccd"))
|
||||
ret = new CDAccess_CCD(path, image_memcache);
|
||||
else
|
||||
ret = new CDAccess_Image(path, image_memcache);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#ifndef __MDFN_CDROMFILE_H
|
||||
#define __MDFN_CDROMFILE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "CDUtility.h"
|
||||
|
||||
class CDAccess
|
||||
{
|
||||
public:
|
||||
|
||||
CDAccess();
|
||||
virtual ~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;
|
||||
|
||||
private:
|
||||
CDAccess(const CDAccess&); // No copy constructor.
|
||||
CDAccess& operator=(const CDAccess&); // No assignment operator.
|
||||
};
|
||||
|
||||
CDAccess* CDAccess_Open(const std::string& path, bool image_memcache);
|
||||
|
||||
#endif
|
|
@ -1,432 +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
|
||||
*/
|
||||
|
||||
//#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>
|
||||
|
||||
//wrapper to repair gettext stuff
|
||||
#define _(X) X
|
||||
|
||||
#include <limits>
|
||||
#include <limits.h>
|
||||
#include <map>
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
static void MDFN_strtoupper(std::string &str)
|
||||
{
|
||||
const size_t len = str.length();
|
||||
|
||||
for(size_t x = 0; x < len; x++)
|
||||
{
|
||||
if(str[x] >= 'a' && str[x] <= 'z')
|
||||
{
|
||||
str[x] = str[x] - 'a' + 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::map<std::string, std::string> CCD_Section;
|
||||
|
||||
template<typename T>
|
||||
static T CCD_ReadInt(CCD_Section &s, const std::string &propname, const bool have_defval = false, const int defval = 0)
|
||||
{
|
||||
CCD_Section::iterator zit = s.find(propname);
|
||||
|
||||
if(zit == s.end())
|
||||
{
|
||||
if(have_defval)
|
||||
return defval;
|
||||
else
|
||||
throw MDFN_Error(0, _("Missing property: %s"), propname.c_str());
|
||||
}
|
||||
|
||||
const std::string &v = zit->second;
|
||||
int scan_base = 10;
|
||||
size_t scan_offset = 0;
|
||||
long ret = 0;
|
||||
|
||||
if(v.length() >= 3 && v[0] == '0' && v[1] == 'x')
|
||||
{
|
||||
scan_base = 16;
|
||||
scan_offset = 2;
|
||||
}
|
||||
|
||||
const char *vp = v.c_str() + scan_offset;
|
||||
char *ep = NULL;
|
||||
|
||||
if(std::numeric_limits<T>::is_signed)
|
||||
ret = strtol(vp, &ep, scan_base);
|
||||
else
|
||||
ret = strtoul(vp, &ep, scan_base);
|
||||
|
||||
if(!vp[0] || ep[0])
|
||||
{
|
||||
throw MDFN_Error(0, _("Property %s: Malformed integer: %s"), propname.c_str(), v.c_str());
|
||||
}
|
||||
|
||||
//if(ret < minv || ret > maxv)
|
||||
//{
|
||||
// throw MDFN_Error(0, _("Property %s: Integer %ld out of range(accepted: %d through %d)."), propname.c_str(), ret, minv, maxv);
|
||||
//}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
CDAccess_CCD::CDAccess_CCD(const std::string& path, bool image_memcache) : img_numsectors(0)
|
||||
{
|
||||
Load(path, image_memcache);
|
||||
}
|
||||
|
||||
void CDAccess_CCD::Load(const std::string& path, bool image_memcache)
|
||||
{
|
||||
FileStream cf(path, FileStream::MODE_READ);
|
||||
std::map<std::string, CCD_Section> Sections;
|
||||
std::string linebuf;
|
||||
std::string cur_section_name;
|
||||
std::string dir_path, file_base, file_ext;
|
||||
char img_extsd[4] = { 'i', 'm', 'g', 0 };
|
||||
char sub_extsd[4] = { 's', 'u', 'b', 0 };
|
||||
|
||||
MDFN_GetFilePathComponents(path, &dir_path, &file_base, &file_ext);
|
||||
|
||||
if(file_ext.length() == 4 && file_ext[0] == '.')
|
||||
{
|
||||
signed char extupt[3] = { -1, -1, -1 };
|
||||
|
||||
for(int i = 1; i < 4; i++)
|
||||
{
|
||||
if(file_ext[i] >= 'A' && file_ext[i] <= 'Z')
|
||||
extupt[i - 1] = 'A' - 'a';
|
||||
else if(file_ext[i] >= 'a' && file_ext[i] <= 'z')
|
||||
extupt[i - 1] = 0;
|
||||
}
|
||||
|
||||
signed char av = -1;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(extupt[i] != -1)
|
||||
av = extupt[i];
|
||||
else
|
||||
extupt[i] = av;
|
||||
}
|
||||
|
||||
if(av == -1)
|
||||
av = 0;
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(extupt[i] == -1)
|
||||
extupt[i] = av;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
img_extsd[i] += extupt[i];
|
||||
sub_extsd[i] += extupt[i];
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%s %d %d %d\n", file_ext.c_str(), extupt[0], extupt[1], extupt[2]);
|
||||
|
||||
linebuf.reserve(256);
|
||||
|
||||
while(cf.get_line(linebuf) >= 0)
|
||||
{
|
||||
MDFN_trim(linebuf);
|
||||
|
||||
if(linebuf.length() == 0) // Skip blank lines.
|
||||
continue;
|
||||
|
||||
if(linebuf[0] == '[')
|
||||
{
|
||||
if(linebuf.length() < 3 || linebuf[linebuf.length() - 1] != ']')
|
||||
throw MDFN_Error(0, _("Malformed section specifier: %s"), linebuf.c_str());
|
||||
|
||||
cur_section_name = linebuf.substr(1, linebuf.length() - 2);
|
||||
MDFN_strtoupper(cur_section_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t feqpos = linebuf.find('=');
|
||||
const size_t leqpos = linebuf.rfind('=');
|
||||
std::string k, v;
|
||||
|
||||
if(feqpos == std::string::npos || feqpos != leqpos)
|
||||
throw MDFN_Error(0, _("Malformed value pair specifier: %s"), linebuf.c_str());
|
||||
|
||||
k = linebuf.substr(0, feqpos);
|
||||
v = linebuf.substr(feqpos + 1);
|
||||
|
||||
MDFN_trim(k);
|
||||
MDFN_trim(v);
|
||||
|
||||
MDFN_strtoupper(k);
|
||||
|
||||
Sections[cur_section_name][k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
CCD_Section& ds = Sections["DISC"];
|
||||
unsigned toc_entries = CCD_ReadInt<unsigned>(ds, "TOCENTRIES");
|
||||
unsigned num_sessions = CCD_ReadInt<unsigned>(ds, "SESSIONS");
|
||||
bool data_tracks_scrambled = CCD_ReadInt<unsigned>(ds, "DATATRACKSSCRAMBLED");
|
||||
|
||||
if(num_sessions != 1)
|
||||
throw MDFN_Error(0, _("Unsupported number of sessions: %u"), num_sessions);
|
||||
|
||||
if(data_tracks_scrambled)
|
||||
throw MDFN_Error(0, _("Scrambled CCD data tracks currently not supported."));
|
||||
|
||||
//printf("MOO: %d\n", toc_entries);
|
||||
|
||||
for(unsigned te = 0; te < toc_entries; te++)
|
||||
{
|
||||
char tmpbuf[64];
|
||||
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");
|
||||
uint8 adr = CCD_ReadInt<uint8>(ts, "ADR");
|
||||
uint8 control = CCD_ReadInt<uint8>(ts, "CONTROL");
|
||||
uint8 pmin = CCD_ReadInt<uint8>(ts, "PMIN");
|
||||
uint8 psec = CCD_ReadInt<uint8>(ts, "PSEC");
|
||||
//uint8 pframe = CCD_ReadInt<uint8>(ts, "PFRAME");
|
||||
signed plba = CCD_ReadInt<signed>(ts, "PLBA");
|
||||
|
||||
if(session != 1)
|
||||
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;
|
||||
tocd.tracks[point].control = control;
|
||||
tocd.tracks[point].lba = plba;
|
||||
tocd.tracks[point].valid = true;
|
||||
}
|
||||
else switch(point)
|
||||
{
|
||||
default:
|
||||
throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point);
|
||||
break;
|
||||
|
||||
case 0xA0:
|
||||
tocd.first_track = pmin;
|
||||
tocd.disc_type = psec;
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
tocd.last_track = pmin;
|
||||
break;
|
||||
|
||||
case 0xA2:
|
||||
tocd.tracks[100].adr = adr;
|
||||
tocd.tracks[100].control = control;
|
||||
tocd.tracks[100].lba = plba;
|
||||
tocd.tracks[100].valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Open image stream.
|
||||
{
|
||||
std::string image_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(img_extsd), true);
|
||||
|
||||
if(image_memcache)
|
||||
{
|
||||
img_stream.reset(new MemoryStream(new FileStream(image_path, FileStream::MODE_READ)));
|
||||
}
|
||||
else
|
||||
{
|
||||
img_stream.reset(new FileStream(image_path, FileStream::MODE_READ));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// 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(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();
|
||||
}
|
||||
|
||||
//
|
||||
// Checks for Q subchannel mode 1(current time) data that has a correct checksum, but the data is nonsensical or corrupted nonetheless; this is the
|
||||
// case for some bad rips floating around on the Internet. Allowing these bad rips to be used will cause all sorts of problems during emulation, so we
|
||||
// error out here if a bad rip is detected.
|
||||
//
|
||||
// This check is not as aggressive or exhaustive as it could be, and will not detect all potential Q subchannel rip errors; as such, it should definitely NOT be
|
||||
// used in an effort to "repair" a broken rip.
|
||||
//
|
||||
void CDAccess_CCD::CheckSubQSanity(void)
|
||||
{
|
||||
size_t checksum_pass_counter = 0;
|
||||
int prev_lba = INT_MAX;
|
||||
uint8 prev_track = 0;
|
||||
|
||||
for(size_t s = 0; s < img_numsectors; s++)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint8 full[96];
|
||||
struct
|
||||
{
|
||||
uint8 pbuf[12];
|
||||
uint8 qbuf[12];
|
||||
};
|
||||
} buf;
|
||||
|
||||
memcpy(buf.full, &sub_data[s * 96], 96);
|
||||
|
||||
if(subq_check_checksum(buf.qbuf))
|
||||
{
|
||||
uint8 adr = buf.qbuf[0] & 0xF;
|
||||
|
||||
if(adr == 0x01)
|
||||
{
|
||||
uint8 track_bcd = buf.qbuf[1];
|
||||
uint8 index_bcd = buf.qbuf[2];
|
||||
uint8 rm_bcd = buf.qbuf[3];
|
||||
uint8 rs_bcd = buf.qbuf[4];
|
||||
uint8 rf_bcd = buf.qbuf[5];
|
||||
uint8 am_bcd = buf.qbuf[7];
|
||||
uint8 as_bcd = buf.qbuf[8];
|
||||
uint8 af_bcd = buf.qbuf[9];
|
||||
|
||||
//printf("%2x %2x %2x\n", am_bcd, as_bcd, af_bcd);
|
||||
|
||||
if(!BCD_is_valid(track_bcd) || !BCD_is_valid(index_bcd) || !BCD_is_valid(rm_bcd) || !BCD_is_valid(rs_bcd) || !BCD_is_valid(rf_bcd) ||
|
||||
!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
|
||||
|
||||
#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;
|
||||
}
|
||||
checksum_pass_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%u/%u\n", checksum_pass_counter, img_numsectors);
|
||||
}
|
||||
|
||||
CDAccess_CCD::~CDAccess_CCD()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CDAccess_CCD::Read_Raw_Sector(uint8 *buf, int32 lba)
|
||||
{
|
||||
if(lba < 0)
|
||||
{
|
||||
synth_udapp_sector_lba(0xFF, tocd, lba, 0, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,48 +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 "../FileStream.h"
|
||||
#include "../MemoryStream.h"
|
||||
#include "CDAccess.h"
|
||||
#include <memory>
|
||||
|
||||
class CDAccess_CCD : public CDAccess
|
||||
{
|
||||
public:
|
||||
|
||||
CDAccess_CCD(const std::string& path, bool image_memcache);
|
||||
virtual ~CDAccess_CCD();
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
void Load(const std::string& path, bool image_memcache);
|
||||
void Cleanup(void);
|
||||
|
||||
void CheckSubQSanity(void);
|
||||
|
||||
std::unique_ptr<Stream> img_stream;
|
||||
std::unique_ptr<uint8[]> sub_data;
|
||||
|
||||
size_t img_numsectors;
|
||||
CDUtility::TOC tocd;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -1,103 +0,0 @@
|
|||
#ifndef __MDFN_CDACCESS_IMAGE_H
|
||||
#define __MDFN_CDACCESS_IMAGE_H
|
||||
|
||||
#include <map>
|
||||
#include <array>
|
||||
|
||||
class Stream;
|
||||
class CDAFReader;
|
||||
|
||||
struct CDRFILE_TRACK_INFO
|
||||
{
|
||||
int32 LBA;
|
||||
|
||||
uint32 DIFormat;
|
||||
uint8 subq_control;
|
||||
|
||||
int32 pregap;
|
||||
int32 pregap_dv;
|
||||
|
||||
int32 postgap;
|
||||
|
||||
int32 index[2];
|
||||
|
||||
int32 sectors; // Not including pregap sectors!
|
||||
Stream *fp;
|
||||
bool FirstFileInstance;
|
||||
bool RawAudioMSBFirst;
|
||||
long FileOffset;
|
||||
unsigned int SubchannelMode;
|
||||
|
||||
uint32 LastSamplePos;
|
||||
|
||||
CDAFReader *AReader;
|
||||
};
|
||||
#if 0
|
||||
struct Medium_Chunk
|
||||
{
|
||||
int64 Offset; // Offset in [..TODO..]
|
||||
uint32 DIFormat;
|
||||
|
||||
FILE *fp;
|
||||
bool FirstFileInstance;
|
||||
bool RawAudioMSBFirst;
|
||||
unsigned int SubchannelMode;
|
||||
|
||||
uint32 LastSamplePos;
|
||||
AudioReader *AReader;
|
||||
};
|
||||
|
||||
struct CD_Chunk
|
||||
{
|
||||
int32 LBA;
|
||||
int32 Track;
|
||||
int32 Index;
|
||||
bool DataType;
|
||||
|
||||
Medium_Chunk Medium;
|
||||
};
|
||||
|
||||
static std::vector<CD_Chunk> Chunks;
|
||||
#endif
|
||||
|
||||
class CDAccess_Image : public CDAccess
|
||||
{
|
||||
public:
|
||||
|
||||
CDAccess_Image(const std::string& path, bool image_memcache);
|
||||
virtual ~CDAccess_Image();
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
int32 NumTracks;
|
||||
int32 FirstTrack;
|
||||
int32 LastTrack;
|
||||
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;
|
||||
|
||||
std::string base_dir;
|
||||
|
||||
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.
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,456 +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
|
||||
*/
|
||||
|
||||
#define EXTERNAL_LIBCDIO_CONFIG_H 1
|
||||
|
||||
#include "../mednafen.h"
|
||||
#include "../general.h"
|
||||
|
||||
#include "CDAccess.h"
|
||||
#include "CDAccess_Physical.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/mmc.h>
|
||||
#include <cdio/logging.h>
|
||||
|
||||
#if LIBCDIO_VERSION_NUM >= 83
|
||||
#include <cdio/mmc_cmds.h>
|
||||
#endif
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
static bool Logging = false;
|
||||
static std::string LogMessage;
|
||||
static void LogHandler(cdio_log_level_t level, const char message[])
|
||||
{
|
||||
if(!Logging)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if(LogMessage.size() > 0)
|
||||
LogMessage.append(" - ");
|
||||
|
||||
LogMessage.append(message);
|
||||
}
|
||||
catch(...) // Don't throw exceptions through libcdio's code.
|
||||
{
|
||||
LogMessage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void StartLogging(void)
|
||||
{
|
||||
Logging = true;
|
||||
LogMessage.clear();
|
||||
}
|
||||
|
||||
static INLINE void ClearLogging(void)
|
||||
{
|
||||
LogMessage.clear();
|
||||
}
|
||||
|
||||
static INLINE std::string StopLogging(void)
|
||||
{
|
||||
std::string ret = LogMessage;
|
||||
|
||||
Logging = false;
|
||||
LogMessage.clear();
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void CDAccess_Physical::DetermineFeatures(void)
|
||||
{
|
||||
uint8 buf[256];
|
||||
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
|
||||
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE_10);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
cdb.field[2] = 0x2A;
|
||||
|
||||
cdb.field[7] = sizeof(buf) >> 8;
|
||||
cdb.field[8] = sizeof(buf) & 0xFF;
|
||||
|
||||
StartLogging();
|
||||
if(mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
sizeof(buf),
|
||||
buf))
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC [MODE SENSE 10] command failed: %s"), StopLogging().c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8 *pd = &buf[8];
|
||||
|
||||
StopLogging();
|
||||
|
||||
if(pd[0] != 0x2A || pd[1] < 0x14)
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC [MODE SENSE 10] command returned bogus data for mode page 0x2A.")));
|
||||
}
|
||||
|
||||
if(!(pd[4] & 0x10))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Drive does not support reading Mode 2 Form 1 sectors.")));
|
||||
}
|
||||
|
||||
if(!(pd[4] & 0x20))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Drive does not support reading Mode 2 Form 2 sectors.")));
|
||||
}
|
||||
|
||||
if(!(pd[5] & 0x01))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Reading CD-DA sectors via \"READ CD\" is not supported.")));
|
||||
}
|
||||
|
||||
if(!(pd[5] & 0x02))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Read CD-DA sectors via \"READ CD\" are not positionally-accurate.")));
|
||||
}
|
||||
|
||||
if(!(pd[5] & 0x04))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Reading raw subchannel data via \"READ CD\" is not supported.")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDAccess_Physical::PreventAllowMediumRemoval(bool prevent)
|
||||
{
|
||||
#if 0
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
uint8 buf[8];
|
||||
|
||||
cdb.field[0] = 0x1E;
|
||||
cdb.field[1] = 0x00;
|
||||
cdb.field[2] = 0x00;
|
||||
cdb.field[3] = 0x00;
|
||||
cdb.field[4] = 0x00; //prevent;
|
||||
cdb.field[5] = 0x00;
|
||||
|
||||
printf("%d\n", mmc_run_cmd_len (p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb, 6,
|
||||
SCSI_MMC_DATA_READ, 0, buf));
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// To be used in the future for constructing semi-raw TOC data.
|
||||
#if 0
|
||||
static uint8 cond_hex_to_bcd(uint8 val)
|
||||
{
|
||||
if( ((val & 0xF) > 0x9) || ((val & 0xF0) > 0x90) )
|
||||
return val;
|
||||
|
||||
return U8_to_BCD(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CDAccess_Physical::ReadPhysDiscInfo(unsigned retry)
|
||||
{
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
std::vector<uint8> toc_buffer;
|
||||
int64 start_time = time(NULL);
|
||||
int cdio_rc;
|
||||
|
||||
toc_buffer.resize(0x3FFF); // (2**(8 * 2 - 1 - 1)) - 1, in case the drive has buggy firmware which chops upper bits off or overflows with values near
|
||||
// the max of a 16-bit signed value
|
||||
|
||||
cdb.field[0] = 0x43; // Read TOC
|
||||
cdb.field[1] = 0x00;
|
||||
cdb.field[2] = 0x02; // Format 0010b
|
||||
cdb.field[3] = 0x00;
|
||||
cdb.field[4] = 0x00;
|
||||
cdb.field[5] = 0x00;
|
||||
cdb.field[6] = 0x01; // First session number
|
||||
cdb.field[7] = toc_buffer.size() >> 8;
|
||||
cdb.field[8] = toc_buffer.size() & 0xFF;
|
||||
cdb.field[9] = 0x00;
|
||||
|
||||
StartLogging();
|
||||
while((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
toc_buffer.size(),
|
||||
&toc_buffer[0])))
|
||||
{
|
||||
if(!retry || time(NULL) >= (start_time + retry))
|
||||
{
|
||||
throw(MDFN_Error(0, _("Error reading disc TOC: %s"), StopLogging().c_str()));
|
||||
}
|
||||
else
|
||||
ClearLogging();
|
||||
}
|
||||
StopLogging();
|
||||
|
||||
PhysTOC.Clear();
|
||||
|
||||
{
|
||||
int32 len_counter = MDFN_de16msb(&toc_buffer[0]) - 2;
|
||||
uint8 *tbi = &toc_buffer[4];
|
||||
|
||||
if(len_counter < 0 || (len_counter % 11) != 0)
|
||||
throw MDFN_Error(0, _("READ TOC command response data is of an invalid length."));
|
||||
|
||||
while(len_counter)
|
||||
{
|
||||
// Ref: MMC-3 draft revision 10g, page 221
|
||||
uint8 sess MDFN_NOWARN_UNUSED = tbi[0];
|
||||
uint8 adr_ctrl = tbi[1];
|
||||
uint8 tno MDFN_NOWARN_UNUSED = tbi[2];
|
||||
uint8 point = tbi[3];
|
||||
uint8 min MDFN_NOWARN_UNUSED = tbi[4];
|
||||
uint8 sec MDFN_NOWARN_UNUSED = tbi[5];
|
||||
uint8 frame MDFN_NOWARN_UNUSED = tbi[6];
|
||||
uint8 hour_phour MDFN_NOWARN_UNUSED = tbi[7];
|
||||
uint8 pmin = tbi[8];
|
||||
uint8 psec = tbi[9];
|
||||
uint8 pframe = tbi[10];
|
||||
|
||||
if((adr_ctrl >> 4) == 1)
|
||||
{
|
||||
switch(((adr_ctrl >> 4) << 8) | point)
|
||||
{
|
||||
case 0x101 ... 0x163:
|
||||
PhysTOC.tracks[point].adr = adr_ctrl >> 4;
|
||||
PhysTOC.tracks[point].control = adr_ctrl & 0xF;
|
||||
PhysTOC.tracks[point].lba = AMSF_to_LBA(pmin, psec, pframe);
|
||||
break;
|
||||
|
||||
case 0x1A0:
|
||||
PhysTOC.first_track = pmin;
|
||||
PhysTOC.disc_type = psec;
|
||||
break;
|
||||
|
||||
case 0x1A1:
|
||||
PhysTOC.last_track = pmin;
|
||||
break;
|
||||
|
||||
case 0x1A2:
|
||||
PhysTOC.tracks[100].adr = adr_ctrl >> 4;
|
||||
PhysTOC.tracks[100].control = adr_ctrl & 0xF;
|
||||
PhysTOC.tracks[100].lba = AMSF_to_LBA(pmin, psec, pframe);
|
||||
break;
|
||||
|
||||
default:
|
||||
//MDFN_printf("%02x %02x\n", adr_ctrl >> 4, point);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tbi += 11;
|
||||
len_counter -= 11;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(PhysTOC.first_track < 1 || PhysTOC.first_track > 99)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid first track: %d\n"), PhysTOC.first_track));
|
||||
}
|
||||
|
||||
if(PhysTOC.last_track > 99 || PhysTOC.last_track < PhysTOC.first_track)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Invalid last track: %d\n"), PhysTOC.last_track));
|
||||
}
|
||||
|
||||
// Convenience leadout track duplication.
|
||||
if(PhysTOC.last_track < 99)
|
||||
PhysTOC.tracks[PhysTOC.last_track + 1] = PhysTOC.tracks[100];
|
||||
}
|
||||
|
||||
void CDAccess_Physical::Read_TOC(TOC *toc)
|
||||
{
|
||||
*toc = PhysTOC;
|
||||
}
|
||||
|
||||
void CDAccess_Physical::Read_Raw_Sector(uint8 *buf, int32 lba)
|
||||
{
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
int cdio_rc;
|
||||
|
||||
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
|
||||
CDIO_MMC_SET_READ_TYPE (cdb.field, CDIO_MMC_READ_TYPE_ANY);
|
||||
CDIO_MMC_SET_READ_LBA (cdb.field, lba);
|
||||
CDIO_MMC_SET_READ_LENGTH24(cdb.field, 1);
|
||||
|
||||
StartLogging();
|
||||
if(SkipSectorRead[(lba >> 3) & 0xFFFF] & (1 << (lba & 7)))
|
||||
{
|
||||
printf("Read(skipped): %d\n", lba);
|
||||
memset(buf, 0, 2352);
|
||||
|
||||
cdb.field[9] = 0x00;
|
||||
cdb.field[10] = 0x01;
|
||||
|
||||
if((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
96,
|
||||
buf + 2352)))
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC Read Error: %s"), StopLogging().c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cdb.field[9] = 0xF8;
|
||||
cdb.field[10] = 0x01;
|
||||
|
||||
if((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
2352 + 96,
|
||||
buf)))
|
||||
{
|
||||
throw(MDFN_Error(0, _("MMC Read Error: %s"), StopLogging().c_str()));
|
||||
}
|
||||
}
|
||||
StopLogging();
|
||||
}
|
||||
|
||||
CDAccess_Physical::CDAccess_Physical(const std::string& path)
|
||||
{
|
||||
char **devices = NULL;
|
||||
char **parseit = NULL;
|
||||
|
||||
p_cdio = NULL;
|
||||
|
||||
cdio_init();
|
||||
cdio_log_set_handler(LogHandler);
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
try
|
||||
{
|
||||
devices = cdio_get_devices(DRIVER_DEVICE);
|
||||
parseit = devices;
|
||||
if(parseit)
|
||||
{
|
||||
MDFN_printf(_("Connected physical devices:\n"));
|
||||
MDFN_indent(1);
|
||||
while(*parseit)
|
||||
{
|
||||
MDFN_printf("%s\n", *parseit);
|
||||
parseit++;
|
||||
}
|
||||
MDFN_indent(-1);
|
||||
}
|
||||
|
||||
if(!parseit || parseit == devices)
|
||||
{
|
||||
throw(MDFN_Error(0, _("No CDROM drives detected(or no disc present).")));
|
||||
}
|
||||
|
||||
if(devices)
|
||||
{
|
||||
cdio_free_device_list(devices);
|
||||
devices = NULL;
|
||||
}
|
||||
|
||||
StartLogging();
|
||||
p_cdio = cdio_open_cd(path.c_str());
|
||||
if(!p_cdio)
|
||||
{
|
||||
throw(MDFN_Error(0, _("Error opening physical CD: %s"), StopLogging().c_str()));
|
||||
}
|
||||
StopLogging();
|
||||
|
||||
//PreventAllowMediumRemoval(true);
|
||||
ReadPhysDiscInfo(0);
|
||||
|
||||
//
|
||||
// Determine how we can read this CD.
|
||||
//
|
||||
DetermineFeatures();
|
||||
|
||||
memset(SkipSectorRead, 0, sizeof(SkipSectorRead));
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
if(devices)
|
||||
cdio_free_device_list(devices);
|
||||
|
||||
if(p_cdio)
|
||||
cdio_destroy((CdIo *)p_cdio);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
CDAccess_Physical::~CDAccess_Physical()
|
||||
{
|
||||
cdio_destroy((CdIo *)p_cdio);
|
||||
}
|
||||
|
||||
bool CDAccess_Physical::Is_Physical(void) throw()
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
void CDAccess_Physical::Eject(bool eject_status)
|
||||
{
|
||||
int cdio_rc;
|
||||
|
||||
StartLogging();
|
||||
#if LIBCDIO_VERSION_NUM >= 83
|
||||
if((cdio_rc = mmc_start_stop_unit((CdIo *)p_cdio, eject_status, false, 0, 0)) != 0)
|
||||
{
|
||||
if(cdio_rc != DRIVER_OP_UNSUPPORTED) // Don't error out if it's just an unsupported operation.
|
||||
throw(MDFN_Error(0, _("Error ejecting medium: %s"), StopLogging().c_str()));
|
||||
}
|
||||
#else
|
||||
if((cdio_rc = mmc_start_stop_media((CdIo *)p_cdio, eject_status, false, 0)) != 0)
|
||||
{
|
||||
if(cdio_rc != DRIVER_OP_UNSUPPORTED) // Don't error out if it's just an unsupported operation.
|
||||
throw(MDFN_Error(0, _("Error ejecting medium: %s"), StopLogging().c_str()));
|
||||
}
|
||||
#endif
|
||||
StopLogging();
|
||||
|
||||
if(!eject_status)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReadPhysDiscInfo(10);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
#if LIBCDIO_VERSION_NUM >= 83
|
||||
mmc_start_stop_unit((CdIo *)p_cdio, true, false, 0, 0); // Eject disc, if possible.
|
||||
#else
|
||||
mmc_start_stop_media((CdIo *)p_cdio, true, false, 0); // Eject disc, if possible.
|
||||
#endif
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#ifndef __MDFN_CDACCESS_PHYSICAL_H
|
||||
#define __MDFN_CDACCESS_PHYSICAL_H
|
||||
|
||||
//
|
||||
// This class's methods are NOT re-entrant!
|
||||
//
|
||||
|
||||
// Don't include <cdio.h> here, else it will pollute with its #define's.
|
||||
|
||||
class CDAccess_Physical : public CDAccess
|
||||
{
|
||||
public:
|
||||
|
||||
CDAccess_Physical(const std::string& path);
|
||||
virtual ~CDAccess_Physical();
|
||||
|
||||
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
|
||||
|
||||
virtual void Read_TOC(CDUtility::TOC *toc);
|
||||
|
||||
virtual bool Is_Physical(void) throw();
|
||||
|
||||
virtual void Eject(bool eject_status);
|
||||
private:
|
||||
|
||||
void *p_cdio;
|
||||
|
||||
void DetermineFeatures(void);
|
||||
void ReadPhysDiscInfo(unsigned retry);
|
||||
|
||||
void PreventAllowMediumRemoval(bool prevent);
|
||||
|
||||
CDUtility::TOC PhysTOC;
|
||||
|
||||
// TODO: 1-bit per sector on the physical CD. If set, don't read that sector.
|
||||
uint8 SkipSectorRead[65536];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,435 +0,0 @@
|
|||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "emuware/emuware.h"
|
||||
#include "CDUtility.h"
|
||||
#include "dvdisaster.h"
|
||||
#include "lec.h"
|
||||
|
||||
#include <assert.h>
|
||||
// Kill_LEC_Correct();
|
||||
|
||||
|
||||
namespace CDUtility
|
||||
{
|
||||
|
||||
// lookup table for crc calculation
|
||||
static uint16 subq_crctab[256] =
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
|
||||
|
||||
static uint8 scramble_table[2352 - 12];
|
||||
|
||||
static bool CDUtility_Inited = false;
|
||||
|
||||
static void InitScrambleTable(void)
|
||||
{
|
||||
unsigned cv = 1;
|
||||
|
||||
for(unsigned i = 12; i < 2352; i++)
|
||||
{
|
||||
unsigned char z = 0;
|
||||
|
||||
for(int b = 0; b < 8; b++)
|
||||
{
|
||||
z |= (cv & 1) << b;
|
||||
|
||||
int feedback = ((cv >> 1) & 1) ^ (cv & 1);
|
||||
cv = (cv >> 1) | (feedback << 14);
|
||||
}
|
||||
|
||||
scramble_table[i - 12] = z;
|
||||
}
|
||||
|
||||
//for(int i = 0; i < 2352 - 12; i++)
|
||||
// printf("0x%02x, ", scramble_table[i]);
|
||||
}
|
||||
|
||||
void CDUtility_Init(void)
|
||||
{
|
||||
if(!CDUtility_Inited)
|
||||
{
|
||||
Init_LEC_Correct();
|
||||
|
||||
InitScrambleTable();
|
||||
|
||||
CDUtility_Inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_mode0_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode0_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode1_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode1_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_form1_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_form2_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
bool edc_check(const uint8 *sector_data, bool xa)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
return(CheckEDC(sector_data, xa));
|
||||
}
|
||||
|
||||
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
return(ValidateRawSector(sector_data, xa));
|
||||
}
|
||||
|
||||
|
||||
bool subq_check_checksum(const uint8 *SubQBuf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
uint16 stored_crc = 0;
|
||||
|
||||
stored_crc = SubQBuf[0xA] << 8;
|
||||
stored_crc |= SubQBuf[0xB];
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
|
||||
|
||||
crc = ~crc;
|
||||
|
||||
return(crc == stored_crc);
|
||||
}
|
||||
|
||||
void subq_generate_checksum(uint8 *buf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
|
||||
|
||||
// Checksum
|
||||
buf[0xa] = ~(crc >> 8);
|
||||
buf[0xb] = ~(crc);
|
||||
}
|
||||
|
||||
void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
|
||||
{
|
||||
memset(qbuf, 0, 0xC);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
{
|
||||
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
|
||||
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
|
||||
{
|
||||
assert(in_buf != out_buf);
|
||||
|
||||
memset(out_buf, 0, 96);
|
||||
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
{
|
||||
for(unsigned i = 0; i < 96; i++)
|
||||
{
|
||||
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
|
||||
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
|
||||
{
|
||||
assert(in_buf != out_buf);
|
||||
|
||||
for(unsigned d = 0; d < 12; d++)
|
||||
{
|
||||
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
|
||||
{
|
||||
uint8 rawb = 0;
|
||||
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
{
|
||||
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
|
||||
}
|
||||
out_buf[(d << 3) + bitpoodle] = rawb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTES ON LEADOUT AREA SYNTHESIS
|
||||
//
|
||||
// I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
|
||||
// and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
|
||||
// data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).
|
||||
//
|
||||
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
|
||||
{
|
||||
uint8 buf[0xC];
|
||||
uint32 lba_relative;
|
||||
uint32 ma, sa, fa;
|
||||
uint32 m, s, f;
|
||||
|
||||
lba_relative = lba - toc.tracks[100].lba;
|
||||
|
||||
f = (lba_relative % 75);
|
||||
s = ((lba_relative / 75) % 60);
|
||||
m = (lba_relative / 75 / 60);
|
||||
|
||||
fa = (lba + 150) % 75;
|
||||
sa = ((lba + 150) / 75) % 60;
|
||||
ma = ((lba + 150) / 75 / 60);
|
||||
|
||||
uint8 adr = 0x1; // Q channel data encodes position
|
||||
uint8 control = 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);
|
||||
buf[1] = 0xAA;
|
||||
buf[2] = 0x01;
|
||||
|
||||
// Track relative MSF address
|
||||
buf[3] = U8_to_BCD(m);
|
||||
buf[4] = U8_to_BCD(s);
|
||||
buf[5] = U8_to_BCD(f);
|
||||
|
||||
buf[6] = 0; // Zerroooo
|
||||
|
||||
// Absolute MSF address
|
||||
buf[7] = U8_to_BCD(ma);
|
||||
buf[8] = U8_to_BCD(sa);
|
||||
buf[9] = U8_to_BCD(fa);
|
||||
|
||||
subq_generate_checksum(buf);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
|
||||
}
|
||||
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ISO/IEC 10149:1995 (E): 20.2
|
||||
//
|
||||
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf)
|
||||
{
|
||||
uint8 buf[0xC];
|
||||
uint32 lba_relative;
|
||||
uint32 ma, sa, fa;
|
||||
uint32 m, s, f;
|
||||
|
||||
if(lba < -150 || lba >= 0)
|
||||
printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba);
|
||||
|
||||
{
|
||||
int32 lba_tmp = lba + lba_subq_relative_offs;
|
||||
|
||||
if(lba_tmp < 0)
|
||||
lba_relative = 0 - 1 - lba_tmp;
|
||||
else
|
||||
lba_relative = lba_tmp - 0;
|
||||
}
|
||||
|
||||
f = (lba_relative % 75);
|
||||
s = ((lba_relative / 75) % 60);
|
||||
m = (lba_relative / 75 / 60);
|
||||
|
||||
fa = (lba + 150) % 75;
|
||||
sa = ((lba + 150) / 75) % 60;
|
||||
ma = ((lba + 150) / 75 / 60);
|
||||
|
||||
uint8 adr = 0x1; // Q channel data encodes position
|
||||
uint8 control;
|
||||
|
||||
if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1)
|
||||
control = 0x4;
|
||||
else if(toc.tracks[toc.first_track].valid)
|
||||
control = toc.tracks[toc.first_track].control;
|
||||
else
|
||||
control = 0x0;
|
||||
|
||||
memset(buf, 0, 0xC);
|
||||
buf[0] = (adr << 0) | (control << 4);
|
||||
buf[1] = U8_to_BCD(toc.first_track);
|
||||
buf[2] = U8_to_BCD(0x00);
|
||||
|
||||
// Track relative MSF address
|
||||
buf[3] = U8_to_BCD(m);
|
||||
buf[4] = U8_to_BCD(s);
|
||||
buf[5] = U8_to_BCD(f);
|
||||
|
||||
buf[6] = 0; // Zerroooo
|
||||
|
||||
// Absolute MSF address
|
||||
buf[7] = U8_to_BCD(ma);
|
||||
buf[8] = U8_to_BCD(sa);
|
||||
buf[9] = U8_to_BCD(fa);
|
||||
|
||||
subq_generate_checksum(buf);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
|
||||
}
|
||||
|
||||
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf)
|
||||
{
|
||||
memset(out_buf, 0, 2352 + 96);
|
||||
subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, out_buf + 2352);
|
||||
|
||||
if(out_buf[2352 + 1] & 0x40)
|
||||
{
|
||||
if(mode == 0xFF)
|
||||
{
|
||||
if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I)
|
||||
mode = 0x02;
|
||||
else
|
||||
mode = 0x01;
|
||||
}
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
encode_mode1_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
out_buf[12 + 6] = 0x20;
|
||||
out_buf[12 + 10] = 0x20;
|
||||
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
|
||||
{
|
||||
assert(subq_check_checksum(subq_input));
|
||||
|
||||
|
||||
subq_generate_checksum(subq_output);
|
||||
}
|
||||
#endif
|
||||
|
||||
void scrambleize_data_sector(uint8 *sector_data)
|
||||
{
|
||||
for(unsigned i = 12; i < 2352; i++)
|
||||
sector_data[i] ^= scramble_table[i - 12];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
#ifndef __MDFN_CDROM_CDUTILITY_H
|
||||
#define __MDFN_CDROM_CDUTILITY_H
|
||||
|
||||
namespace CDUtility
|
||||
{
|
||||
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
|
||||
// It will also be called automatically if needed for the first time a function in this namespace that requires
|
||||
// the initialization function to be called is called, for potential
|
||||
// usage in constructors of statically-declared objects.
|
||||
void CDUtility_Init(void);
|
||||
|
||||
// Quick definitions here:
|
||||
//
|
||||
// ABA - Absolute block address, synonymous to absolute MSF
|
||||
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a
|
||||
//
|
||||
// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
|
||||
// lba = aba - 150
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
ADR_NOQINFO = 0x00,
|
||||
ADR_CURPOS = 0x01,
|
||||
ADR_MCN = 0x02,
|
||||
ADR_ISRC = 0x03
|
||||
};
|
||||
|
||||
|
||||
struct TOC_Track
|
||||
{
|
||||
uint8 adr;
|
||||
uint8 control;
|
||||
uint32 lba;
|
||||
bool valid; // valid/present; oh CD-i...
|
||||
};
|
||||
|
||||
// SubQ control field flags.
|
||||
enum
|
||||
{
|
||||
SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
|
||||
SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
|
||||
SUBQ_CTRLF_DATA = 0x04, // Data track.
|
||||
SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DISC_TYPE_CDDA_OR_M1 = 0x00,
|
||||
DISC_TYPE_CD_I = 0x10,
|
||||
DISC_TYPE_CD_XA = 0x20
|
||||
};
|
||||
|
||||
struct TOC
|
||||
{
|
||||
INLINE TOC()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
INLINE void Clear(void)
|
||||
{
|
||||
first_track = last_track = 0;
|
||||
disc_type = 0;
|
||||
|
||||
memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
|
||||
}
|
||||
|
||||
INLINE int FindTrackByLBA(uint32 LBA) const
|
||||
{
|
||||
int32 lvt = 0;
|
||||
|
||||
for(int32 track = 1; track <= 100; track++)
|
||||
{
|
||||
if(!tracks[track].valid)
|
||||
continue;
|
||||
|
||||
if(LBA < tracks[track].lba)
|
||||
break;
|
||||
|
||||
lvt = track;
|
||||
}
|
||||
|
||||
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.
|
||||
};
|
||||
|
||||
//
|
||||
// Address conversion functions.
|
||||
//
|
||||
static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
|
||||
{
|
||||
return(f_a + 75 * s_a + 75 * 60 * m_a);
|
||||
}
|
||||
|
||||
static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
*m_a = aba / 75 / 60;
|
||||
*s_a = (aba - *m_a * 75 * 60) / 75;
|
||||
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
|
||||
}
|
||||
|
||||
static INLINE int32 ABA_to_LBA(uint32 aba)
|
||||
{
|
||||
return(aba - 150);
|
||||
}
|
||||
|
||||
static INLINE uint32 LBA_to_ABA(int32 lba)
|
||||
{
|
||||
return(lba + 150);
|
||||
}
|
||||
|
||||
static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
|
||||
{
|
||||
return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
|
||||
}
|
||||
|
||||
static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
|
||||
}
|
||||
|
||||
//
|
||||
// BCD conversion functions
|
||||
//
|
||||
static INLINE bool BCD_is_valid(uint8 bcd_number)
|
||||
{
|
||||
if((bcd_number & 0xF0) >= 0xA0)
|
||||
return(false);
|
||||
|
||||
if((bcd_number & 0x0F) >= 0x0A)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
static INLINE uint8 BCD_to_U8(uint8 bcd_number)
|
||||
{
|
||||
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
|
||||
}
|
||||
|
||||
static INLINE uint8 U8_to_BCD(uint8 num)
|
||||
{
|
||||
return( ((num / 10) << 4) + (num % 10) );
|
||||
}
|
||||
|
||||
// should always perform the conversion, even if the bcd number is invalid.
|
||||
static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number)
|
||||
{
|
||||
*out_number = BCD_to_U8(bcd_number);
|
||||
|
||||
if(!BCD_is_valid(bcd_number))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
//
|
||||
// Sector data encoding functions(to full 2352 bytes raw sector).
|
||||
//
|
||||
// sector_data must be able to contain at least 2352 bytes.
|
||||
void encode_mode0_sector(uint32 aba, uint8 *sector_data);
|
||||
void encode_mode1_sector(uint32 aba, uint8 *sector_data); // 2048 bytes of user data at offset 16
|
||||
void encode_mode2_sector(uint32 aba, uint8 *sector_data); // 2336 bytes of user data at offset 16
|
||||
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data); // 2048+8 bytes of user data at offset 16
|
||||
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16
|
||||
|
||||
|
||||
// User data 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 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
|
||||
//
|
||||
|
||||
// Check EDC of a mode 1 or mode 2 form 1 sector.
|
||||
// Returns "true" if checksum is ok(matches).
|
||||
// Returns "false" if checksum mismatch.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_check(const uint8 *sector_data, bool xa);
|
||||
|
||||
// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
|
||||
// Returns "true" if errors weren't detected, or they were corrected succesfully.
|
||||
// Returns "false" if errors couldn't be corrected.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);
|
||||
|
||||
//
|
||||
// Subchannel(Q in particular) functions
|
||||
//
|
||||
|
||||
// Returns false on checksum mismatch, true on match.
|
||||
bool subq_check_checksum(const uint8 *subq_buf);
|
||||
|
||||
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
|
||||
// in subq_buf.
|
||||
void subq_generate_checksum(uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
|
||||
void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
|
||||
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
|
||||
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
|
||||
// Only valid for ADR_CURPOS.
|
||||
// subq_input must pass subq_check_checksum().
|
||||
// TODO
|
||||
//void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output);
|
||||
|
||||
// (De)Scrambles data sector.
|
||||
void scrambleize_data_sector(uint8 *sector_data);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,11 +0,0 @@
|
|||
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
|
||||
|
||||
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,140 +0,0 @@
|
|||
#ifndef __MDFN_SIMPLEFIFO_H
|
||||
#define __MDFN_SIMPLEFIFO_H
|
||||
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../math_ops.h"
|
||||
|
||||
template<typename T>
|
||||
class SimpleFIFO
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
SimpleFIFO(uint32 the_size) // Size should be a power of 2!
|
||||
{
|
||||
data.resize(round_up_pow2(the_size));
|
||||
size = the_size;
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
INLINE ~SimpleFIFO()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
INLINE void SaveStatePostLoad(void)
|
||||
{
|
||||
read_pos %= data.size();
|
||||
write_pos %= data.size();
|
||||
in_count %= (data.size() + 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
INLINE int StateAction(StateMem *sm, int load, int data_only, const char* sname)
|
||||
{
|
||||
SFORMAT StateRegs[] =
|
||||
{
|
||||
std::vector<T> data;
|
||||
uint32 size;
|
||||
|
||||
SFVAR(read_pos),
|
||||
SFVAR(write_pos),
|
||||
SFVAR(in_count),
|
||||
SFEND;
|
||||
}
|
||||
int ret = MDFNSS_StateAction(sm, load, data_only, sname);
|
||||
|
||||
if(load)
|
||||
{
|
||||
read_pos %= data.size();
|
||||
write_pos %= data.size();
|
||||
in_count %= (data.size() + 1);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
INLINE uint32 CanRead(void)
|
||||
{
|
||||
return(in_count);
|
||||
}
|
||||
|
||||
INLINE uint32 CanWrite(void)
|
||||
{
|
||||
return(size - in_count);
|
||||
}
|
||||
|
||||
INLINE T ReadUnit(bool peek = false)
|
||||
{
|
||||
T ret;
|
||||
|
||||
assert(in_count > 0);
|
||||
|
||||
ret = data[read_pos];
|
||||
|
||||
if(!peek)
|
||||
{
|
||||
read_pos = (read_pos + 1) & (data.size() - 1);
|
||||
in_count--;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
INLINE uint8 ReadByte(bool peek = false)
|
||||
{
|
||||
assert(sizeof(T) == 1);
|
||||
|
||||
return(ReadUnit(peek));
|
||||
}
|
||||
|
||||
INLINE void Write(const T *happy_data, uint32 happy_count)
|
||||
{
|
||||
assert(CanWrite() >= happy_count);
|
||||
|
||||
while(happy_count)
|
||||
{
|
||||
data[write_pos] = *happy_data;
|
||||
|
||||
write_pos = (write_pos + 1) & (data.size() - 1);
|
||||
in_count++;
|
||||
happy_data++;
|
||||
happy_count--;
|
||||
}
|
||||
}
|
||||
|
||||
INLINE void WriteUnit(const T& wr_data)
|
||||
{
|
||||
Write(&wr_data, 1);
|
||||
}
|
||||
|
||||
INLINE void WriteByte(const T& wr_data)
|
||||
{
|
||||
assert(sizeof(T) == 1);
|
||||
Write(&wr_data, 1);
|
||||
}
|
||||
|
||||
|
||||
INLINE void Flush(void)
|
||||
{
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
//private:
|
||||
std::vector<T> data;
|
||||
uint32 size;
|
||||
uint32 read_pos; // Read position
|
||||
uint32 write_pos; // Write position
|
||||
uint32 in_count; // Number of units in the FIFO
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,898 +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 <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <trio/trio.h>
|
||||
#include "emuware/emuware.h"
|
||||
#include "cdromif.h"
|
||||
#include "CDAccess.h"
|
||||
#include "general.h"
|
||||
#include "error.h"
|
||||
|
||||
//undo gettext stuff
|
||||
#define _(X) X
|
||||
#include <algorithm>
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
enum
|
||||
{
|
||||
// Status/Error messages
|
||||
CDIF_MSG_DONE = 0, // Read -> emu. args: No args.
|
||||
CDIF_MSG_INFO, // Read -> emu. args: str_message
|
||||
CDIF_MSG_FATAL_ERROR, // Read -> emu. args: *TODO ARGS*
|
||||
|
||||
//
|
||||
// Command messages.
|
||||
//
|
||||
CDIF_MSG_DIEDIEDIE, // Emu -> read
|
||||
|
||||
CDIF_MSG_READ_SECTOR, /* Emu -> read
|
||||
args[0] = lba
|
||||
*/
|
||||
};
|
||||
|
||||
class CDIF_Message
|
||||
{
|
||||
public:
|
||||
|
||||
CDIF_Message();
|
||||
CDIF_Message(unsigned int message_, uint32 arg0 = 0, uint32 arg1 = 0, uint32 arg2 = 0, uint32 arg3 = 0);
|
||||
CDIF_Message(unsigned int message_, const std::string &str);
|
||||
~CDIF_Message();
|
||||
|
||||
unsigned int message;
|
||||
uint32 args[4];
|
||||
void *parg;
|
||||
std::string str_message;
|
||||
};
|
||||
|
||||
#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;
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
||||
CDIF_ST(CDAccess *cda);
|
||||
virtual ~CDIF_ST();
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDIF::~CDIF()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
CDIF_Message::CDIF_Message()
|
||||
{
|
||||
message = 0;
|
||||
|
||||
memset(args, 0, sizeof(args));
|
||||
}
|
||||
|
||||
CDIF_Message::CDIF_Message(unsigned int message_, uint32 arg0, uint32 arg1, uint32 arg2, uint32 arg3)
|
||||
{
|
||||
message = message_;
|
||||
args[0] = arg0;
|
||||
args[1] = arg1;
|
||||
args[2] = arg2;
|
||||
args[3] = arg3;
|
||||
}
|
||||
|
||||
CDIF_Message::CDIF_Message(unsigned int message_, const std::string &str)
|
||||
{
|
||||
message = message_;
|
||||
str_message = str;
|
||||
}
|
||||
|
||||
CDIF_Message::~CDIF_Message()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
int mode = buf[12 + 3];
|
||||
|
||||
if(mode != 0x1 && mode != 0x2)
|
||||
return(false);
|
||||
|
||||
if(!edc_lec_check_and_correct(buf, mode == 2))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#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(sector_count--)
|
||||
{
|
||||
uint8 tmpbuf[2352 + 96];
|
||||
|
||||
if(!ReadRawSector(tmpbuf, lba))
|
||||
{
|
||||
puts("CDIF Raw Read error");
|
||||
return(FALSE_0);
|
||||
}
|
||||
|
||||
if(!ValidateRawSector(tmpbuf))
|
||||
{
|
||||
if(!suppress_uncorrectable_message)
|
||||
{
|
||||
printf(_("Uncorrectable data at sector %d"), lba);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
const int mode = tmpbuf[12 + 3];
|
||||
|
||||
if(!ret)
|
||||
ret = mode;
|
||||
|
||||
if(mode == 1)
|
||||
{
|
||||
memcpy(buf, &tmpbuf[12 + 4], 2048);
|
||||
}
|
||||
else if(mode == 2)
|
||||
{
|
||||
memcpy(buf, &tmpbuf[12 + 4 + 8], 2048);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
|
||||
return(false);
|
||||
}
|
||||
|
||||
buf += 2048;
|
||||
lba++;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Single-threaded implementation follows.
|
||||
//
|
||||
//
|
||||
|
||||
CDIF_ST::CDIF_ST(CDAccess *cda) : disc_cdaccess(cda)
|
||||
{
|
||||
//puts("***WARNING USING SINGLE-THREADED CD READER***");
|
||||
|
||||
UnrecoverableError = false;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
CDIF_ST::~CDIF_ST()
|
||||
{
|
||||
if(disc_cdaccess)
|
||||
{
|
||||
delete disc_cdaccess;
|
||||
disc_cdaccess = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CDIF_ST::HintReadSector(int32 lba)
|
||||
{
|
||||
// TODO: disc_cdaccess seek hint? (probably not, would require asynchronousitycamel)
|
||||
}
|
||||
|
||||
bool CDIF_ST::ReadRawSector(uint8 *buf, int32 lba)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
disc_cdaccess->Read_Raw_Sector(buf, lba);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
printf(_("Sector %u read error: %s"), lba, e.what());
|
||||
memset(buf, 0, 2352 + 96);
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool CDIF_ST::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))
|
||||
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:
|
||||
|
||||
CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg);
|
||||
~CDIF_Stream_Thing();
|
||||
|
||||
virtual uint64 attributes(void) override;
|
||||
|
||||
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) override;
|
||||
virtual void write(const void *data, uint64 count) override;
|
||||
virtual void truncate(uint64 length) override;
|
||||
|
||||
virtual void seek(int64 offset, int whence) override;
|
||||
virtual uint64 tell(void) override;
|
||||
virtual uint64 size(void) override;
|
||||
virtual void flush(void) override;
|
||||
virtual void close(void) override;
|
||||
|
||||
private:
|
||||
CDIF *cdintf;
|
||||
const uint32 start_lba;
|
||||
const uint32 sector_count;
|
||||
int64 position;
|
||||
};
|
||||
|
||||
CDIF_Stream_Thing::CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) : cdintf(cdintf_arg), start_lba(start_lba_arg), sector_count(sector_count_arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDIF_Stream_Thing::~CDIF_Stream_Thing()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint64 CDIF_Stream_Thing::attributes(void)
|
||||
{
|
||||
return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE);
|
||||
}
|
||||
|
||||
uint64 CDIF_Stream_Thing::read(void *data, uint64 count, bool error_on_eos)
|
||||
{
|
||||
if(count > (((uint64)sector_count * 2048) - position))
|
||||
{
|
||||
if(error_on_eos)
|
||||
{
|
||||
throw MDFN_Error(0, "EOF");
|
||||
}
|
||||
|
||||
count = ((uint64)sector_count * 2048) - position;
|
||||
}
|
||||
|
||||
if(!count)
|
||||
return(0);
|
||||
|
||||
for(uint64 rp = position; rp < (position + count); rp = (rp &~ 2047) + 2048)
|
||||
{
|
||||
uint8 buf[2048];
|
||||
|
||||
if(!cdintf->ReadSector(buf, start_lba + (rp / 2048), 1))
|
||||
{
|
||||
throw MDFN_Error(ErrnoHolder(EIO));
|
||||
}
|
||||
|
||||
//::printf("Meow: %08llx -- %08llx\n", count, (rp - position) + std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
|
||||
memcpy((uint8*)data + (rp - position), buf + (rp & 2047), std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
|
||||
}
|
||||
|
||||
position += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void CDIF_Stream_Thing::write(const void *data, uint64 count)
|
||||
{
|
||||
throw MDFN_Error(ErrnoHolder(EBADF));
|
||||
}
|
||||
|
||||
void CDIF_Stream_Thing::truncate(uint64 length)
|
||||
{
|
||||
throw MDFN_Error(ErrnoHolder(EBADF));
|
||||
}
|
||||
|
||||
void CDIF_Stream_Thing::seek(int64 offset, int whence)
|
||||
{
|
||||
int64 new_position;
|
||||
|
||||
switch(whence)
|
||||
{
|
||||
default:
|
||||
throw MDFN_Error(ErrnoHolder(EINVAL));
|
||||
break;
|
||||
|
||||
case SEEK_SET:
|
||||
new_position = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
new_position = position + offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
new_position = ((int64)sector_count * 2048) + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if(new_position < 0 || new_position > ((int64)sector_count * 2048))
|
||||
throw MDFN_Error(ErrnoHolder(EINVAL));
|
||||
|
||||
position = new_position;
|
||||
}
|
||||
|
||||
uint64 CDIF_Stream_Thing::tell(void)
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
uint64 CDIF_Stream_Thing::size(void)
|
||||
{
|
||||
return(sector_count * 2048);
|
||||
}
|
||||
|
||||
void CDIF_Stream_Thing::flush(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CDIF_Stream_Thing::close(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
Stream *CDIF::MakeStream(int32 lba, uint32 sector_count)
|
||||
{
|
||||
return new CDIF_Stream_Thing(this, lba, sector_count);
|
||||
}
|
||||
|
||||
|
||||
CDIF *CDIF_Open(const std::string& path, bool image_memcache)
|
||||
{
|
||||
CDAccess *cda = CDAccess_Open(path, image_memcache);
|
||||
|
||||
#ifdef WANT_QUEUE
|
||||
if(!image_memcache)
|
||||
return new CDIF_MT(cda);
|
||||
else
|
||||
#endif
|
||||
return new CDIF_ST(cda);
|
||||
}
|
|
@ -1,66 +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
|
||||
*/
|
||||
|
||||
#ifndef __MDFN_CDROM_CDROMIF_H
|
||||
#define __MDFN_CDROM_CDROMIF_H
|
||||
|
||||
#include "CDUtility.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
typedef CDUtility::TOC CD_TOC;
|
||||
|
||||
class CDIF
|
||||
{
|
||||
public:
|
||||
|
||||
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(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);
|
||||
|
||||
// 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* 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(int32 lba, uint32 sector_count);
|
||||
|
||||
protected:
|
||||
bool UnrecoverableError;
|
||||
CDUtility::TOC disc_toc;
|
||||
};
|
||||
|
||||
CDIF *CDIF_Open(const std::string& path, bool image_memcache);
|
||||
|
||||
#endif
|
|
@ -1,130 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* CRC32 code based upon public domain code by Ross Williams (see notes below)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
/***
|
||||
*** EDC checksum used in CDROM sectors
|
||||
***/
|
||||
|
||||
/*****************************************************************/
|
||||
/* */
|
||||
/* CRC LOOKUP TABLE */
|
||||
/* ================ */
|
||||
/* The following CRC lookup table was generated automagically */
|
||||
/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
|
||||
/* Program V1.0 using the following model parameters: */
|
||||
/* */
|
||||
/* Width : 4 bytes. */
|
||||
/* Poly : 0x8001801BL */
|
||||
/* Reverse : TRUE. */
|
||||
/* */
|
||||
/* For more information on the Rocksoft^tm Model CRC Algorithm, */
|
||||
/* see the document titled "A Painless Guide to CRC Error */
|
||||
/* Detection Algorithms" by Ross Williams */
|
||||
/* (ross@guest.adelaide.edu.au.). This document is likely to be */
|
||||
/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
unsigned long edctable[256] =
|
||||
{
|
||||
0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
|
||||
0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
|
||||
0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
|
||||
0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
|
||||
0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
|
||||
0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
|
||||
0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
|
||||
0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
|
||||
0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
|
||||
0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
|
||||
0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
|
||||
0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
|
||||
0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
|
||||
0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
|
||||
0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
|
||||
0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
|
||||
0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
|
||||
0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
|
||||
0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
|
||||
0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
|
||||
0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
|
||||
0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
|
||||
0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
|
||||
0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
|
||||
0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
|
||||
0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
|
||||
0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
|
||||
0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
|
||||
0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
|
||||
0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
|
||||
0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
|
||||
0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
|
||||
0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
|
||||
0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
|
||||
0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
|
||||
0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
|
||||
0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
|
||||
0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
|
||||
0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
|
||||
0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
|
||||
0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
|
||||
0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
|
||||
0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
|
||||
0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
|
||||
0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
|
||||
0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
|
||||
0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
|
||||
0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
|
||||
0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
|
||||
0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
|
||||
0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
|
||||
0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
|
||||
0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
|
||||
0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
|
||||
0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
|
||||
0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
|
||||
0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
|
||||
0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
|
||||
0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
|
||||
0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
|
||||
0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
|
||||
0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
|
||||
0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
|
||||
0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
|
||||
};
|
||||
|
||||
/*
|
||||
* CDROM EDC calculation
|
||||
*/
|
||||
|
||||
uint32 EDCCrc32(const unsigned char *data, int len)
|
||||
{
|
||||
uint32 crc = 0;
|
||||
|
||||
while(len--)
|
||||
crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return crc;
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef DVDISASTER_H
|
||||
#define DVDISASTER_H
|
||||
|
||||
/* "Dare to be gorgeous and unique.
|
||||
* But don't ever be cryptic or otherwise unfathomable.
|
||||
* Make it unforgettably great."
|
||||
*
|
||||
* From "A Final Note on Style",
|
||||
* Amiga Intuition Reference Manual, 1986, p. 231
|
||||
*/
|
||||
|
||||
/***
|
||||
*** I'm too lazy to mess with #include dependencies.
|
||||
*** Everything #includeable is rolled up herein...
|
||||
*/
|
||||
|
||||
//#include "../types.h"
|
||||
#include "emuware/emuware.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
//#include <unistd.h>
|
||||
|
||||
/***
|
||||
*** dvdisaster.c
|
||||
***/
|
||||
|
||||
void PrepareDeadSector(void);
|
||||
|
||||
void CreateEcc(void);
|
||||
void FixEcc(void);
|
||||
void Verify(void);
|
||||
|
||||
uint32 EDCCrc32(const unsigned char*, int);
|
||||
|
||||
/***
|
||||
*** galois.c
|
||||
***
|
||||
* This is currently the hardcoded GF(2**8).
|
||||
* int32 gives abundant space for the GF.
|
||||
* Squeezing it down to uint8 won't probably gain much,
|
||||
* so we implement this defensively here.
|
||||
*
|
||||
* Note that some performance critical stuff needs to
|
||||
* be #included from galois-inlines.h
|
||||
*/
|
||||
|
||||
/* Galois field parameters for 8bit symbol Reed-Solomon code */
|
||||
|
||||
#define GF_SYMBOLSIZE 8
|
||||
#define GF_FIELDSIZE (1<<GF_SYMBOLSIZE)
|
||||
#define GF_FIELDMAX (GF_FIELDSIZE-1)
|
||||
#define GF_ALPHA0 GF_FIELDMAX
|
||||
|
||||
/* Lookup tables for Galois field arithmetic */
|
||||
|
||||
typedef struct _GaloisTables
|
||||
{ int32 gfGenerator; /* GF generator polynomial */
|
||||
int32 *indexOf; /* log */
|
||||
int32 *alphaTo; /* inverse log */
|
||||
int32 *encAlphaTo; /* inverse log optimized for encoder */
|
||||
} GaloisTables;
|
||||
|
||||
/* Lookup and working tables for the ReedSolomon codecs */
|
||||
|
||||
typedef struct _ReedSolomonTables
|
||||
{ GaloisTables *gfTables;/* from above */
|
||||
int32 *gpoly; /* RS code generator polynomial */
|
||||
int32 fcr; /* first consecutive root of RS generator polynomial */
|
||||
int32 primElem; /* primitive field element */
|
||||
int32 nroots; /* degree of RS generator polynomial */
|
||||
int32 ndata; /* data bytes per ecc block */
|
||||
} ReedSolomonTables;
|
||||
|
||||
GaloisTables* CreateGaloisTables(int32);
|
||||
void FreeGaloisTables(GaloisTables*);
|
||||
|
||||
ReedSolomonTables *CreateReedSolomonTables(GaloisTables*, int32, int32, int);
|
||||
void FreeReedSolomonTables(ReedSolomonTables*);
|
||||
|
||||
/***
|
||||
*** l-ec.c
|
||||
***/
|
||||
|
||||
#define N_P_VECTORS 86 /* 43 16bit p vectors */
|
||||
#define P_VECTOR_SIZE 26 /* using RS(26,24) ECC */
|
||||
|
||||
#define N_Q_VECTORS 52 /* 26 16bit q vectors */
|
||||
#define Q_VECTOR_SIZE 45 /* using RS(45,43) ECC */
|
||||
|
||||
#define P_PADDING 229 /* padding values for */
|
||||
#define Q_PADDING 210 /* shortened RS code */
|
||||
|
||||
int PToByteIndex(int, int);
|
||||
int QToByteIndex(int, int);
|
||||
void ByteIndexToP(int, int*, int*);
|
||||
void ByteIndexToQ(int, int*, int*);
|
||||
|
||||
void GetPVector(unsigned char*, unsigned char*, int);
|
||||
void SetPVector(unsigned char*, unsigned char*, int);
|
||||
void FillPVector(unsigned char*, unsigned char, int);
|
||||
void AndPVector(unsigned char*, unsigned char, int);
|
||||
void OrPVector(unsigned char*, unsigned char, int);
|
||||
|
||||
void GetQVector(unsigned char*, unsigned char*, int);
|
||||
void SetQVector(unsigned char*, unsigned char*, int);
|
||||
void FillQVector(unsigned char*, unsigned char, int);
|
||||
void AndQVector(unsigned char*, unsigned char, int);
|
||||
void OrQVector(unsigned char*, unsigned char, int);
|
||||
|
||||
int DecodePQ(ReedSolomonTables*, unsigned char*, int, int*, int);
|
||||
|
||||
int CountC2Errors(unsigned char*);
|
||||
|
||||
/***
|
||||
*** misc.c
|
||||
***/
|
||||
|
||||
char* sgettext(char*);
|
||||
char* sgettext_utf8(char*);
|
||||
|
||||
int64 uchar_to_int64(unsigned char*);
|
||||
void int64_to_uchar(unsigned char*, int64);
|
||||
|
||||
void CalcSectors(int64, int64*, int*);
|
||||
|
||||
/***
|
||||
*** recover-raw.c
|
||||
***/
|
||||
|
||||
#define CD_RAW_SECTOR_SIZE 2352
|
||||
#define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
|
||||
|
||||
int CheckEDC(const unsigned char*, bool);
|
||||
int CheckMSF(unsigned char*, int);
|
||||
|
||||
|
||||
int ValidateRawSector(unsigned char *frame, bool xaMode);
|
||||
bool Init_LEC_Correct(void);
|
||||
void Kill_LEC_Correct(void);
|
||||
|
||||
|
||||
#endif /* DVDISASTER_H */
|
|
@ -1,40 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
/*
|
||||
* The following routine is performance critical.
|
||||
*/
|
||||
|
||||
static inline int mod_fieldmax(int x)
|
||||
{
|
||||
while (x >= GF_FIELDMAX)
|
||||
{
|
||||
x -= GF_FIELDMAX;
|
||||
x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
#include "galois-inlines.h"
|
||||
|
||||
/***
|
||||
*** Galois field arithmetic.
|
||||
***
|
||||
* Calculations are done over the extension field GF(2**n).
|
||||
* Be careful not to overgeneralize these arithmetics;
|
||||
* they only work for the case of GF(p**n) with p being prime.
|
||||
*/
|
||||
|
||||
/* Initialize the Galois field tables */
|
||||
|
||||
|
||||
GaloisTables* CreateGaloisTables(int32 gf_generator)
|
||||
{
|
||||
GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
|
||||
int32 b,log;
|
||||
|
||||
/* Allocate the tables.
|
||||
The encoder uses a special version of alpha_to which has the mod_fieldmax()
|
||||
folded into the table. */
|
||||
|
||||
gt->gfGenerator = gf_generator;
|
||||
|
||||
gt->indexOf = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->alphaTo = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->encAlphaTo = (int32 *)calloc(2*GF_FIELDSIZE, sizeof(int32));
|
||||
|
||||
/* create the log/ilog values */
|
||||
|
||||
for(b=1, log=0; log<GF_FIELDMAX; log++)
|
||||
{ gt->indexOf[b] = log;
|
||||
gt->alphaTo[log] = b;
|
||||
b = b << 1;
|
||||
if(b & GF_FIELDSIZE)
|
||||
b = b ^ gf_generator;
|
||||
}
|
||||
|
||||
if(b!=1)
|
||||
{
|
||||
printf("Failed to create the Galois field log tables!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* we're even closed using infinity (makes things easier) */
|
||||
|
||||
gt->indexOf[0] = GF_ALPHA0; /* log(0) = inf */
|
||||
gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */
|
||||
|
||||
for(b=0; b<2*GF_FIELDSIZE; b++)
|
||||
gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
|
||||
|
||||
return gt;
|
||||
}
|
||||
|
||||
void FreeGaloisTables(GaloisTables *gt)
|
||||
{
|
||||
if(gt->indexOf) free(gt->indexOf);
|
||||
if(gt->alphaTo) free(gt->alphaTo);
|
||||
if(gt->encAlphaTo) free(gt->encAlphaTo);
|
||||
|
||||
free(gt);
|
||||
}
|
||||
|
||||
/***
|
||||
*** Create the the Reed-Solomon generator polynomial
|
||||
*** and some auxiliary data structures.
|
||||
*/
|
||||
|
||||
ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
|
||||
int32 first_consecutive_root,
|
||||
int32 prim_elem,
|
||||
int nroots_in)
|
||||
{ ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));
|
||||
int32 i,j,root;
|
||||
|
||||
rt->gfTables = gt;
|
||||
rt->fcr = first_consecutive_root;
|
||||
rt->primElem = prim_elem;
|
||||
rt->nroots = nroots_in;
|
||||
rt->ndata = GF_FIELDMAX - rt->nroots;
|
||||
|
||||
rt->gpoly = (int32 *)calloc((rt->nroots+1), sizeof(int32));
|
||||
|
||||
/* Create the RS code generator polynomial */
|
||||
|
||||
rt->gpoly[0] = 1;
|
||||
|
||||
for(i=0, root=first_consecutive_root*prim_elem; i<rt->nroots; i++, root+=prim_elem)
|
||||
{ rt->gpoly[i+1] = 1;
|
||||
|
||||
/* Multiply gpoly by alpha**(root+x) */
|
||||
|
||||
for(j=i; j>0; j--)
|
||||
{
|
||||
if(rt->gpoly[j] != 0)
|
||||
rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
|
||||
else
|
||||
rt->gpoly[j] = rt->gpoly[j-1];
|
||||
}
|
||||
|
||||
rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
|
||||
}
|
||||
|
||||
/* Store the polynomials index for faster encoding */
|
||||
|
||||
for(i=0; i<=rt->nroots; i++)
|
||||
rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
|
||||
|
||||
#if 0
|
||||
/* for the precalculated unrolled loops only */
|
||||
|
||||
for(i=gt->nroots-1; i>0; i--)
|
||||
PrintCLI(
|
||||
" par_idx[((++spk)&%d)] ^= enc_alpha_to[feedback + %3d];\n",
|
||||
nroots-1,gt->gpoly[i]);
|
||||
|
||||
PrintCLI(" par_idx[sp] = enc_alpha_to[feedback + %3d];\n",
|
||||
gt->gpoly[0]);
|
||||
#endif
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
void FreeReedSolomonTables(ReedSolomonTables *rt)
|
||||
{
|
||||
if(rt->gpoly) free(rt->gpoly);
|
||||
|
||||
free(rt);
|
||||
}
|
|
@ -1,478 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
#include "galois-inlines.h"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/***
|
||||
*** Mapping between cd frame and parity vectors
|
||||
***/
|
||||
|
||||
/*
|
||||
* Mapping of frame bytes to P/Q Vectors
|
||||
*/
|
||||
|
||||
int PToByteIndex(int p, int i)
|
||||
{ return 12 + p + i*86;
|
||||
}
|
||||
|
||||
void ByteIndexToP(int b, int *p, int *i)
|
||||
{ *p = (b-12)%86;
|
||||
*i = (b-12)/86;
|
||||
}
|
||||
|
||||
int QToByteIndex(int q, int i)
|
||||
{ int offset = 12 + (q & 1);
|
||||
|
||||
if(i == 43) return 2248+q;
|
||||
if(i == 44) return 2300+q;
|
||||
|
||||
q&=~1;
|
||||
return offset + (q*43 + i*88) % 2236;
|
||||
}
|
||||
|
||||
void ByteIndexToQ(int b, int *q, int *i)
|
||||
{ int x,y,offset;
|
||||
|
||||
if(b >= 2300)
|
||||
{ *i = 44;
|
||||
*q = (b-2300);
|
||||
return;
|
||||
}
|
||||
|
||||
if(b >= 2248)
|
||||
{ *i = 43;
|
||||
*q = (b-2248);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = b&1;
|
||||
b = (b-12)/2;
|
||||
x = b/43;
|
||||
y = (b-(x*43))%26;
|
||||
*i = b-(x*43);
|
||||
*q = 2*((x+26-y)%26)+offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are 86 vectors of P-parity, yielding a RS(26,24) code.
|
||||
*/
|
||||
|
||||
void GetPVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
data[i] = frame[w_idx];
|
||||
}
|
||||
|
||||
void SetPVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] = data[i];
|
||||
}
|
||||
|
||||
void FillPVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] = data;
|
||||
}
|
||||
|
||||
void OrPVector(unsigned char *frame, unsigned char value, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] |= value;
|
||||
}
|
||||
|
||||
void AndPVector(unsigned char *frame, unsigned char value, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] &= value;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are 52 vectors of Q-parity, yielding a RS(45,43) code.
|
||||
*/
|
||||
|
||||
void GetQVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
data[i] = frame[(w_idx % 2236) + offset];
|
||||
|
||||
data[43] = frame[2248 + n];
|
||||
data[44] = frame[2300 + n];
|
||||
}
|
||||
|
||||
void SetQVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] = data[i];
|
||||
|
||||
frame[2248 + n] = data[43];
|
||||
frame[2300 + n] = data[44];
|
||||
}
|
||||
|
||||
void FillQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] = data;
|
||||
|
||||
frame[2248 + n] = data;
|
||||
frame[2300 + n] = data;
|
||||
}
|
||||
|
||||
void OrQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] |= data;
|
||||
|
||||
frame[2248 + n] |= data;
|
||||
frame[2300 + n] |= data;
|
||||
}
|
||||
|
||||
void AndQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] &= data;
|
||||
|
||||
frame[2248 + n] &= data;
|
||||
frame[2300 + n] &= data;
|
||||
}
|
||||
|
||||
/***
|
||||
*** C2 error counting
|
||||
***/
|
||||
|
||||
int CountC2Errors(unsigned char *frame)
|
||||
{ int i,count = 0;
|
||||
frame += 2352;
|
||||
|
||||
for(i=0; i<294; i++, frame++)
|
||||
{ if(*frame & 0x01) count++;
|
||||
if(*frame & 0x02) count++;
|
||||
if(*frame & 0x04) count++;
|
||||
if(*frame & 0x08) count++;
|
||||
if(*frame & 0x10) count++;
|
||||
if(*frame & 0x20) count++;
|
||||
if(*frame & 0x40) count++;
|
||||
if(*frame & 0x80) count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/***
|
||||
*** L-EC error correction for CD raw data sectors
|
||||
***/
|
||||
|
||||
/*
|
||||
* These could be used from ReedSolomonTables,
|
||||
* but hardcoding them is faster.
|
||||
*/
|
||||
|
||||
#define NROOTS 2
|
||||
#define LEC_FIRST_ROOT 0 //GF_ALPHA0
|
||||
#define LEC_PRIM_ELEM 1
|
||||
#define LEC_PRIMTH_ROOT 1
|
||||
|
||||
/*
|
||||
* Calculate the error syndrome
|
||||
*/
|
||||
|
||||
int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
int *erasure_list, int erasure_count)
|
||||
{ GaloisTables *gt = rt->gfTables;
|
||||
int syndrome[NROOTS];
|
||||
int lambda[NROOTS+1];
|
||||
int omega[NROOTS+1];
|
||||
int b[NROOTS+1];
|
||||
int reg[NROOTS+1];
|
||||
int root[NROOTS];
|
||||
int loc[NROOTS];
|
||||
int syn_error;
|
||||
int deg_lambda,lambda_roots;
|
||||
int deg_omega;
|
||||
int shortened_size = GF_FIELDMAX - padding;
|
||||
int corrected = 0;
|
||||
int i,j,k;
|
||||
int r,el;
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
|
||||
syn_error = 0;
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ syn_error |= syndrome[i];
|
||||
syndrome[i] = gt->indexOf[syndrome[i]];
|
||||
}
|
||||
|
||||
/*** If the syndrome is zero, everything is fine. */
|
||||
|
||||
if(!syn_error)
|
||||
return 0;
|
||||
|
||||
/*** Initialize lambda to be the erasure locator polynomial */
|
||||
|
||||
lambda[0] = 1;
|
||||
lambda[1] = lambda[2] = 0;
|
||||
|
||||
erasure_list[0] += padding;
|
||||
erasure_list[1] += padding;
|
||||
|
||||
if(erasure_count > 2) /* sanity check */
|
||||
erasure_count = 0;
|
||||
|
||||
if(erasure_count > 0)
|
||||
{ lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
|
||||
|
||||
for(i=1; i<erasure_count; i++)
|
||||
{ int u = mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[i]));
|
||||
|
||||
for(j=i+1; j>0; j--)
|
||||
{ int tmp = gt->indexOf[lambda[j-1]];
|
||||
|
||||
if(tmp != GF_ALPHA0)
|
||||
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
b[i] = gt->indexOf[lambda[i]];
|
||||
|
||||
/*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
|
||||
|
||||
r = erasure_count; /* r is the step number */
|
||||
el = erasure_count;
|
||||
|
||||
/* Compute discrepancy at the r-th step in poly-form */
|
||||
|
||||
while(++r <= NROOTS)
|
||||
{ int discr_r = 0;
|
||||
|
||||
for(i=0; i<r; i++)
|
||||
if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
|
||||
discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
|
||||
|
||||
discr_r = gt->indexOf[discr_r];
|
||||
|
||||
if(discr_r == GF_ALPHA0)
|
||||
{ /* B(x) = x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
else
|
||||
{ int t[NROOTS+1];
|
||||
|
||||
/* T(x) = lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(b[i] != GF_ALPHA0)
|
||||
t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
|
||||
else t[i+1] = lambda[i+1];
|
||||
}
|
||||
|
||||
if(2*el <= r+erasure_count-1)
|
||||
{ el = r + erasure_count - el;
|
||||
|
||||
/* B(x) <-- inv(discr_r) * lambda(x) */
|
||||
for(i=0; i<=NROOTS; i++)
|
||||
b[i] = (lambda[i] == 0) ? GF_ALPHA0
|
||||
: mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
|
||||
}
|
||||
else
|
||||
{ /* 2 lines below: B(x) <-- x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
|
||||
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/*** Convert lambda to index form and compute deg(lambda(x)) */
|
||||
|
||||
deg_lambda = 0;
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
{ lambda[i] = gt->indexOf[lambda[i]];
|
||||
if(lambda[i] != GF_ALPHA0)
|
||||
deg_lambda = i;
|
||||
}
|
||||
|
||||
/*** Find roots of the error+erasure locator polynomial by Chien search */
|
||||
|
||||
memcpy(reg+1, lambda+1, NROOTS*sizeof(reg[0]));
|
||||
lambda_roots = 0; /* Number of roots of lambda(x) */
|
||||
|
||||
for(i=1, k=LEC_PRIMTH_ROOT-1; i<=GF_FIELDMAX; i++, k=mod_fieldmax(k+LEC_PRIMTH_ROOT))
|
||||
{ int q=1; /* lambda[0] is always 0 */
|
||||
|
||||
for(j=deg_lambda; j>0; j--)
|
||||
{ if(reg[j] != GF_ALPHA0)
|
||||
{ reg[j] = mod_fieldmax(reg[j] + j);
|
||||
q ^= gt->alphaTo[reg[j]];
|
||||
}
|
||||
}
|
||||
|
||||
if(q != 0) continue; /* Not a root */
|
||||
|
||||
/* store root in index-form and the error location number */
|
||||
|
||||
root[lambda_roots] = i;
|
||||
loc[lambda_roots] = k;
|
||||
|
||||
/* If we've already found max possible roots, abort the search to save time */
|
||||
|
||||
if(++lambda_roots == deg_lambda) break;
|
||||
}
|
||||
|
||||
/* deg(lambda) unequal to number of roots => uncorrectable error detected
|
||||
This is not reliable for very small numbers of roots, e.g. nroots = 2 */
|
||||
|
||||
if(deg_lambda != lambda_roots)
|
||||
{ return -1;
|
||||
}
|
||||
|
||||
/* Compute err+eras evaluator poly omega(x) = syn(x)*lambda(x)
|
||||
(modulo x**nroots). in index form. Also find deg(omega). */
|
||||
|
||||
deg_omega = deg_lambda-1;
|
||||
|
||||
for(i=0; i<=deg_omega; i++)
|
||||
{ int tmp = 0;
|
||||
|
||||
for(j=i; j>=0; j--)
|
||||
{ if((syndrome[i - j] != GF_ALPHA0) && (lambda[j] != GF_ALPHA0))
|
||||
tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
|
||||
}
|
||||
|
||||
omega[i] = gt->indexOf[tmp];
|
||||
}
|
||||
|
||||
/* Compute error values in poly-form.
|
||||
num1 = omega(inv(X(l))),
|
||||
num2 = inv(X(l))**(FIRST_ROOT-1) and
|
||||
den = lambda_pr(inv(X(l))) all in poly-form. */
|
||||
|
||||
for(j=lambda_roots-1; j>=0; j--)
|
||||
{ int num1 = 0;
|
||||
int num2;
|
||||
int den;
|
||||
int location = loc[j];
|
||||
|
||||
for(i=deg_omega; i>=0; i--)
|
||||
{ if(omega[i] != GF_ALPHA0)
|
||||
num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
|
||||
}
|
||||
|
||||
num2 = gt->alphaTo[mod_fieldmax(root[j] * (LEC_FIRST_ROOT - 1) + GF_FIELDMAX)];
|
||||
den = 0;
|
||||
|
||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
||||
|
||||
for(i=MIN(deg_lambda, NROOTS-1) & ~1; i>=0; i-=2)
|
||||
{ if(lambda[i+1] != GF_ALPHA0)
|
||||
den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
|
||||
}
|
||||
|
||||
/* Apply error to data */
|
||||
|
||||
if(num1 != 0 && location >= padding)
|
||||
{
|
||||
corrected++;
|
||||
data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
|
||||
+ GF_FIELDMAX - gt->indexOf[den])];
|
||||
|
||||
/* If no erasures were given, at most one error was corrected.
|
||||
Return its position in erasure_list[0]. */
|
||||
|
||||
if(!erasure_count)
|
||||
erasure_list[0] = location-padding;
|
||||
}
|
||||
#if 1
|
||||
else return -3;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
}
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
#if 1
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i])
|
||||
return -2;
|
||||
#endif
|
||||
|
||||
return corrected;
|
||||
}
|
||||
|
||||
|
|
@ -1,691 +0,0 @@
|
|||
/* cdrdao - write audio CD-Rs in disc-at-once mode
|
||||
*
|
||||
* Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lec.h"
|
||||
|
||||
#define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */
|
||||
|
||||
#define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */
|
||||
|
||||
#define LEC_HEADER_OFFSET 12
|
||||
#define LEC_DATA_OFFSET 16
|
||||
#define LEC_MODE1_DATA_LEN 2048
|
||||
#define LEC_MODE1_EDC_OFFSET 2064
|
||||
#define LEC_MODE1_INTERMEDIATE_OFFSET 2068
|
||||
#define LEC_MODE1_P_PARITY_OFFSET 2076
|
||||
#define LEC_MODE1_Q_PARITY_OFFSET 2248
|
||||
#define LEC_MODE2_FORM1_DATA_LEN (2048+8)
|
||||
#define LEC_MODE2_FORM1_EDC_OFFSET 2072
|
||||
#define LEC_MODE2_FORM2_DATA_LEN (2324+8)
|
||||
#define LEC_MODE2_FORM2_EDC_OFFSET 2348
|
||||
|
||||
|
||||
typedef u_int8_t gf8_t;
|
||||
|
||||
static u_int8_t GF8_LOG[256];
|
||||
static gf8_t GF8_ILOG[256];
|
||||
|
||||
static const class Gf8_Q_Coeffs_Results_01 {
|
||||
private:
|
||||
u_int16_t table[43][256];
|
||||
public:
|
||||
Gf8_Q_Coeffs_Results_01();
|
||||
~Gf8_Q_Coeffs_Results_01() {}
|
||||
const u_int16_t *operator[] (int i) const { return &table[i][0]; }
|
||||
operator const u_int16_t *() const { return &table[0][0]; }
|
||||
} CF8_Q_COEFFS_RESULTS_01;
|
||||
|
||||
static const class CrcTable {
|
||||
private:
|
||||
u_int32_t table[256];
|
||||
public:
|
||||
CrcTable();
|
||||
~CrcTable() {}
|
||||
u_int32_t operator[](int i) const { return table[i]; }
|
||||
operator const u_int32_t *() const { return table; }
|
||||
} CRCTABLE;
|
||||
|
||||
static const class ScrambleTable {
|
||||
private:
|
||||
u_int8_t table[2340];
|
||||
public:
|
||||
ScrambleTable();
|
||||
~ScrambleTable() {}
|
||||
u_int8_t operator[](int i) const { return table[i]; }
|
||||
operator const u_int8_t *() const { return table; }
|
||||
} SCRAMBLE_TABLE;
|
||||
|
||||
/* Creates the logarithm and inverse logarithm table that is required
|
||||
* for performing multiplication in the GF(8) domain.
|
||||
*/
|
||||
static void gf8_create_log_tables()
|
||||
{
|
||||
u_int8_t log;
|
||||
u_int16_t b;
|
||||
|
||||
for (b = 0; b <= 255; b++) {
|
||||
GF8_LOG[b] = 0;
|
||||
GF8_ILOG[b] = 0;
|
||||
}
|
||||
|
||||
b = 1;
|
||||
|
||||
for (log = 0; log < 255; log++) {
|
||||
GF8_LOG[(u_int8_t)b] = log;
|
||||
GF8_ILOG[log] = (u_int8_t)b;
|
||||
|
||||
b <<= 1;
|
||||
|
||||
if ((b & 0x100) != 0)
|
||||
b ^= GF8_PRIM_POLY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Addition in the GF(8) domain: just the XOR of the values.
|
||||
*/
|
||||
#define gf8_add(a, b) (a) ^ (b)
|
||||
|
||||
|
||||
/* Multiplication in the GF(8) domain: add the logarithms (modulo 255)
|
||||
* and return the inverse logarithm. Not used!
|
||||
*/
|
||||
#if 0
|
||||
static gf8_t gf8_mult(gf8_t a, gf8_t b)
|
||||
{
|
||||
int16_t sum;
|
||||
|
||||
if (a == 0 || b == 0)
|
||||
return 0;
|
||||
|
||||
sum = GF8_LOG[a] + GF8_LOG[b];
|
||||
|
||||
if (sum >= 255)
|
||||
sum -= 255;
|
||||
|
||||
return GF8_ILOG[sum];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Division in the GF(8) domain: Like multiplication but logarithms a
|
||||
* subtracted.
|
||||
*/
|
||||
static gf8_t gf8_div(gf8_t a, gf8_t b)
|
||||
{
|
||||
int16_t sum;
|
||||
|
||||
assert(b != 0);
|
||||
|
||||
if (a == 0)
|
||||
return 0;
|
||||
|
||||
sum = GF8_LOG[a] - GF8_LOG[b];
|
||||
|
||||
if (sum < 0)
|
||||
sum += 255;
|
||||
|
||||
return GF8_ILOG[sum];
|
||||
}
|
||||
|
||||
Gf8_Q_Coeffs_Results_01::Gf8_Q_Coeffs_Results_01()
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t c;
|
||||
gf8_t GF8_COEFFS_HELP[2][45];
|
||||
u_int8_t GF8_Q_COEFFS[2][45];
|
||||
|
||||
|
||||
gf8_create_log_tables();
|
||||
|
||||
/* build matrix H:
|
||||
* 1 1 ... 1 1
|
||||
* a^44 a^43 ... a^1 a^0
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_COEFFS_HELP[0][j] = 1; /* e0 */
|
||||
GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */
|
||||
}
|
||||
|
||||
|
||||
/* resolve equation system for parity byte 0 and 1 */
|
||||
|
||||
/* e1' = e1 + e0 */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j],
|
||||
GF8_COEFFS_HELP[0][j]);
|
||||
}
|
||||
|
||||
/* e1'' = e1' / (a^1 + 1) */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]);
|
||||
}
|
||||
|
||||
/* e0' = e0 + e1 / a^1 */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j],
|
||||
gf8_div(GF8_COEFFS_HELP[1][j],
|
||||
GF8_ILOG[1]));
|
||||
}
|
||||
|
||||
/* e0'' = e0' / (1 + 1 / a^1) */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the products of 0..255 with all of the Q coefficients in
|
||||
* advance. When building the scalar product between the data vectors
|
||||
* and the P/Q vectors the individual products can be looked up in
|
||||
* this table
|
||||
*
|
||||
* The P parity coefficients are just a subset of the Q coefficients so
|
||||
* that we do not need to create a separate table for them.
|
||||
*/
|
||||
|
||||
for (j = 0; j < 43; j++) {
|
||||
|
||||
table[j][0] = 0;
|
||||
|
||||
for (i = 1; i < 256; i++) {
|
||||
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]];
|
||||
if (c >= 255) c -= 255;
|
||||
table[j][i] = GF8_ILOG[c];
|
||||
|
||||
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]];
|
||||
if (c >= 255) c -= 255;
|
||||
table[j][i] |= GF8_ILOG[c]<<8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'.
|
||||
*/
|
||||
static u_int32_t mirror_bits(u_int32_t d, int bits)
|
||||
{
|
||||
int i;
|
||||
u_int32_t r = 0;
|
||||
|
||||
for (i = 0; i < bits; i++) {
|
||||
r <<= 1;
|
||||
|
||||
if ((d & 0x1) != 0)
|
||||
r |= 0x1;
|
||||
|
||||
d >>= 1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide
|
||||
* and reversed (i.e. the bit stream is divided by the EDC_POLY with the
|
||||
* LSB first order).
|
||||
*/
|
||||
CrcTable::CrcTable ()
|
||||
{
|
||||
u_int32_t i, j;
|
||||
u_int32_t r;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
r = mirror_bits(i, 8);
|
||||
|
||||
r <<= 24;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if ((r & 0x80000000) != 0) {
|
||||
r <<= 1;
|
||||
r ^= EDC_POLY;
|
||||
}
|
||||
else {
|
||||
r <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
r = mirror_bits(r, 32);
|
||||
|
||||
table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates the CRC of given data with given lengths based on the
|
||||
* table lookup algorithm.
|
||||
*/
|
||||
static u_int32_t calc_edc(u_int8_t *data, int len)
|
||||
{
|
||||
u_int32_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
crc = CRCTABLE[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Build the scramble table as defined in the yellow book. The bytes
|
||||
12 to 2351 of a sector will be XORed with the data of this table.
|
||||
*/
|
||||
ScrambleTable::ScrambleTable()
|
||||
{
|
||||
u_int16_t i, j;
|
||||
u_int16_t reg = 1;
|
||||
u_int8_t d;
|
||||
|
||||
for (i = 0; i < 2340; i++) {
|
||||
d = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
d >>= 1;
|
||||
|
||||
if ((reg & 0x1) != 0)
|
||||
d |= 0x80;
|
||||
|
||||
if ((reg & 0x1) != ((reg >> 1) & 0x1)) {
|
||||
reg >>= 1;
|
||||
reg |= 0x4000; /* 15-bit register */
|
||||
}
|
||||
else {
|
||||
reg >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
table[i] = d;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calc EDC for a MODE 1 sector
|
||||
*/
|
||||
static void calc_mode1_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16);
|
||||
|
||||
sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Calc EDC for a XA form 1 sector
|
||||
*/
|
||||
static void calc_mode2_form1_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
|
||||
LEC_MODE2_FORM1_DATA_LEN);
|
||||
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Calc EDC for a XA form 2 sector
|
||||
*/
|
||||
static void calc_mode2_form2_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
|
||||
LEC_MODE2_FORM2_DATA_LEN);
|
||||
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Writes the sync pattern to the given sector.
|
||||
*/
|
||||
static void set_sync_pattern(u_int8_t *sector)
|
||||
{
|
||||
sector[0] = 0;
|
||||
|
||||
sector[1] = sector[2] = sector[3] = sector[4] = sector[5] =
|
||||
sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff;
|
||||
|
||||
sector[11] = 0;
|
||||
}
|
||||
|
||||
|
||||
static u_int8_t bin2bcd(u_int8_t b)
|
||||
{
|
||||
return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f);
|
||||
}
|
||||
|
||||
/* Builds the sector header.
|
||||
*/
|
||||
static void set_sector_header(u_int8_t mode, u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75));
|
||||
sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60);
|
||||
sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75);
|
||||
sector[LEC_HEADER_OFFSET + 3] = mode;
|
||||
}
|
||||
|
||||
/* Calculate the P parities for the sector.
|
||||
* The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
|
||||
*/
|
||||
static void calc_P_parity(u_int8_t *sector)
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t p01_msb, p01_lsb;
|
||||
u_int8_t *p_lsb_start;
|
||||
u_int8_t *p_lsb;
|
||||
u_int8_t *p0, *p1;
|
||||
u_int8_t d0,d1;
|
||||
|
||||
p_lsb_start = sector + LEC_HEADER_OFFSET;
|
||||
|
||||
p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
|
||||
p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
|
||||
|
||||
for (i = 0; i <= 42; i++) {
|
||||
p_lsb = p_lsb_start;
|
||||
|
||||
p01_lsb = p01_msb = 0;
|
||||
|
||||
for (j = 19; j <= 42; j++) {
|
||||
d0 = *p_lsb;
|
||||
d1 = *(p_lsb+1);
|
||||
|
||||
p01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
|
||||
p01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
|
||||
|
||||
p_lsb += 2 * 43;
|
||||
}
|
||||
|
||||
*p0 = p01_lsb;
|
||||
*(p0 + 1) = p01_msb;
|
||||
|
||||
*p1 = p01_lsb>>8;
|
||||
*(p1 + 1) = p01_msb>>8;
|
||||
|
||||
p0 += 2;
|
||||
p1 += 2;
|
||||
|
||||
p_lsb_start += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the Q parities for the sector.
|
||||
* The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
|
||||
*/
|
||||
static void calc_Q_parity(u_int8_t *sector)
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t q01_lsb, q01_msb;
|
||||
u_int8_t *q_lsb_start;
|
||||
u_int8_t *q_lsb;
|
||||
u_int8_t *q0, *q1, *q_start;
|
||||
u_int8_t d0,d1;
|
||||
|
||||
q_lsb_start = sector + LEC_HEADER_OFFSET;
|
||||
|
||||
q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
||||
q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
||||
q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
|
||||
|
||||
for (i = 0; i <= 25; i++) {
|
||||
q_lsb = q_lsb_start;
|
||||
|
||||
q01_lsb = q01_msb = 0;
|
||||
|
||||
for (j = 0; j <= 42; j++) {
|
||||
d0 = *q_lsb;
|
||||
d1 = *(q_lsb+1);
|
||||
|
||||
q01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
|
||||
q01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
|
||||
|
||||
q_lsb += 2 * 44;
|
||||
|
||||
if (q_lsb >= q_start) {
|
||||
q_lsb -= 2 * 1118;
|
||||
}
|
||||
}
|
||||
|
||||
*q0 = q01_lsb;
|
||||
*(q0 + 1) = q01_msb;
|
||||
|
||||
*q1 = q01_lsb>>8;
|
||||
*(q1 + 1) = q01_msb>>8;
|
||||
|
||||
q0 += 2;
|
||||
q1 += 2;
|
||||
|
||||
q_lsb_start += 2 * 43;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encodes a MODE 0 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide
|
||||
*/
|
||||
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
u_int16_t i;
|
||||
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(0, adr, sector);
|
||||
|
||||
sector += 16;
|
||||
|
||||
for (i = 0; i < 2336; i++)
|
||||
*sector++ = 0;
|
||||
}
|
||||
|
||||
/* Encodes a MODE 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(1, adr, sector);
|
||||
|
||||
calc_mode1_edc(sector);
|
||||
|
||||
/* clear the intermediate field */
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0;
|
||||
|
||||
calc_P_parity(sector);
|
||||
calc_Q_parity(sector);
|
||||
}
|
||||
|
||||
/* Encodes a MODE 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Encodes a XA form 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
|
||||
calc_mode2_form1_edc(sector);
|
||||
|
||||
/* P/Q partiy must not contain the sector header so clear it */
|
||||
sector[LEC_HEADER_OFFSET] =
|
||||
sector[LEC_HEADER_OFFSET + 1] =
|
||||
sector[LEC_HEADER_OFFSET + 2] =
|
||||
sector[LEC_HEADER_OFFSET + 3] = 0;
|
||||
|
||||
calc_P_parity(sector);
|
||||
calc_Q_parity(sector);
|
||||
|
||||
/* finally add the sector header */
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Encodes a XA form 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
|
||||
calc_mode2_form2_edc(sector);
|
||||
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Scrambles and byte swaps an encoded sector.
|
||||
* 'sector' must be 2352 byte wide.
|
||||
*/
|
||||
void lec_scramble(u_int8_t *sector)
|
||||
{
|
||||
u_int16_t i;
|
||||
const u_int8_t *stable = SCRAMBLE_TABLE;
|
||||
u_int8_t *p = sector;
|
||||
u_int8_t tmp;
|
||||
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
/* just swap bytes of sector sync */
|
||||
tmp = *p;
|
||||
*p = *(p + 1);
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
for (;i < (2352 / 2); i++) {
|
||||
/* scramble and swap bytes */
|
||||
tmp = *p ^ *stable++;
|
||||
*p = *(p + 1) ^ *stable++;
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *infile;
|
||||
char *outfile;
|
||||
int fd_in, fd_out;
|
||||
u_int8_t buffer1[2352];
|
||||
u_int8_t buffer2[2352];
|
||||
u_int32_t lba;
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < 2048; i++)
|
||||
buffer1[i + 16] = 234;
|
||||
|
||||
lba = 150;
|
||||
|
||||
for (i = 0; i < 100000; i++) {
|
||||
lec_encode_mode1_sector(lba, buffer1);
|
||||
lec_scramble(buffer2);
|
||||
lba++;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (argc != 3)
|
||||
return 1;
|
||||
|
||||
infile = argv[1];
|
||||
outfile = argv[2];
|
||||
|
||||
|
||||
if ((fd_in = open(infile, O_RDONLY)) < 0) {
|
||||
perror("Cannot open input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd_out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
|
||||
perror("Cannot open output file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lba = 150;
|
||||
|
||||
do {
|
||||
if (read(fd_in, buffer1, 2352) != 2352)
|
||||
break;
|
||||
|
||||
switch (*(buffer1 + 12 + 3)) {
|
||||
case 1:
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048);
|
||||
|
||||
lec_encode_mode1_sector(lba, buffer2);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ((*(buffer1 + 12 + 4 + 2) & 0x20) != 0) {
|
||||
/* form 2 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2324 + 8);
|
||||
lec_encode_mode2_form2_sector(lba, buffer2);
|
||||
}
|
||||
else {
|
||||
/* form 1 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048 + 8);
|
||||
lec_encode_mode2_form1_sector(lba, buffer2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(buffer1, buffer2, 2352) != 0) {
|
||||
printf("Verify error at lba %ld\n", lba);
|
||||
}
|
||||
|
||||
lec_scramble(buffer2);
|
||||
write(fd_out, buffer2, 2352);
|
||||
|
||||
lba++;
|
||||
} while (1);
|
||||
|
||||
close(fd_in);
|
||||
close(fd_out);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,77 +0,0 @@
|
|||
/* cdrdao - write audio CD-Rs in disc-at-once mode
|
||||
*
|
||||
* Copyright (C) 1998-2002 Andreas Mueller <mueller@daneb.ping.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LEC_H__
|
||||
#define __LEC_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef uint32_t u_int32_t;
|
||||
typedef uint16_t u_int16_t;
|
||||
typedef uint8_t u_int8_t;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/* Encodes a MODE 0 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide
|
||||
*/
|
||||
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a MODE 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a MODE 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a XA form 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a XA form 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Scrambles and byte swaps an encoded sector.
|
||||
* 'sector' must be 2352 byte wide.
|
||||
*/
|
||||
void lec_scramble(u_int8_t *sector);
|
||||
|
||||
#endif
|
|
@ -1,203 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
|
||||
static ReedSolomonTables *rt = NULL;
|
||||
|
||||
bool Init_LEC_Correct(void)
|
||||
{
|
||||
gt = CreateGaloisTables(0x11d);
|
||||
rt = CreateReedSolomonTables(gt, 0, 1, 10);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void Kill_LEC_Correct(void)
|
||||
{
|
||||
FreeGaloisTables(gt);
|
||||
FreeReedSolomonTables(rt);
|
||||
}
|
||||
|
||||
/***
|
||||
*** CD level CRC calculation
|
||||
***/
|
||||
|
||||
/*
|
||||
* Test raw sector against its 32bit CRC.
|
||||
* Returns TRUE if frame is good.
|
||||
*/
|
||||
|
||||
int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
|
||||
{
|
||||
unsigned int expected_crc, real_crc;
|
||||
unsigned int crc_base = xa_mode ? 2072 : 2064;
|
||||
|
||||
expected_crc = cd_frame[crc_base + 0] << 0;
|
||||
expected_crc |= cd_frame[crc_base + 1] << 8;
|
||||
expected_crc |= cd_frame[crc_base + 2] << 16;
|
||||
expected_crc |= cd_frame[crc_base + 3] << 24;
|
||||
|
||||
if(xa_mode)
|
||||
real_crc = EDCCrc32(cd_frame+16, 2056);
|
||||
else
|
||||
real_crc = EDCCrc32(cd_frame, 2064);
|
||||
|
||||
if(expected_crc == real_crc)
|
||||
return(1);
|
||||
else
|
||||
{
|
||||
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
*** A very simple L-EC error correction.
|
||||
***
|
||||
* Perform just one pass over the Q and P vectors to see if everything
|
||||
* is okay respectively correct minor errors. This is pretty much the
|
||||
* same stuff the drive is supposed to do in the final L-EC stage.
|
||||
*/
|
||||
|
||||
static int simple_lec(unsigned char *frame)
|
||||
{
|
||||
unsigned char byte_state[2352];
|
||||
unsigned char p_vector[P_VECTOR_SIZE];
|
||||
unsigned char q_vector[Q_VECTOR_SIZE];
|
||||
unsigned char p_state[P_VECTOR_SIZE];
|
||||
int erasures[Q_VECTOR_SIZE], erasure_count;
|
||||
int ignore[2];
|
||||
int p_failures, q_failures;
|
||||
int p_corrected, q_corrected;
|
||||
int p,q;
|
||||
|
||||
/* Setup */
|
||||
|
||||
memset(byte_state, 0, 2352);
|
||||
|
||||
p_failures = q_failures = 0;
|
||||
p_corrected = q_corrected = 0;
|
||||
|
||||
/* Perform Q-Parity error correction */
|
||||
|
||||
for(q=0; q<N_Q_VECTORS; q++)
|
||||
{ int err;
|
||||
|
||||
/* We have no erasure information for Q vectors */
|
||||
|
||||
GetQVector(frame, q_vector, q);
|
||||
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
|
||||
|
||||
/* See what we've got */
|
||||
|
||||
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
|
||||
{ q_failures++;
|
||||
FillQVector(byte_state, 1, q);
|
||||
}
|
||||
else /* Correctable */
|
||||
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{ SetQVector(frame, q_vector, q);
|
||||
q_corrected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform P-Parity error correction */
|
||||
|
||||
for(p=0; p<N_P_VECTORS; p++)
|
||||
{ int err,i;
|
||||
|
||||
/* Try error correction without erasure information */
|
||||
|
||||
GetPVector(frame, p_vector, p);
|
||||
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
|
||||
|
||||
/* If unsuccessful, try again using erasures.
|
||||
Erasure information is uncertain, so try this last. */
|
||||
|
||||
if(err < 0 || err > 2)
|
||||
{ GetPVector(byte_state, p_state, p);
|
||||
erasure_count = 0;
|
||||
|
||||
for(i=0; i<P_VECTOR_SIZE; i++)
|
||||
if(p_state[i])
|
||||
erasures[erasure_count++] = i;
|
||||
|
||||
if(erasure_count > 0 && erasure_count <= 2)
|
||||
{ GetPVector(frame, p_vector, p);
|
||||
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
|
||||
}
|
||||
}
|
||||
|
||||
/* See what we've got */
|
||||
|
||||
if(err < 0) /* Uncorrectable. */
|
||||
{ p_failures++;
|
||||
}
|
||||
else /* Correctable. */
|
||||
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{ SetPVector(frame, p_vector, p);
|
||||
p_corrected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sum up */
|
||||
|
||||
if(q_failures || p_failures || q_corrected || p_corrected)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***
|
||||
*** Validate CD raw sector
|
||||
***/
|
||||
|
||||
int ValidateRawSector(unsigned char *frame, bool xaMode)
|
||||
{
|
||||
int lec_did_sth = FALSE_0;
|
||||
|
||||
/* Do simple L-EC.
|
||||
It seems that drives stop their internal L-EC as soon as the
|
||||
EDC is okay, so we may see uncorrected errors in the parity bytes.
|
||||
Since we are also interested in the user data only and doing the
|
||||
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
|
||||
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
{
|
||||
lec_did_sth = simple_lec(frame);
|
||||
}
|
||||
/* Test internal sector checksum again */
|
||||
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
{
|
||||
/* EDC failure in RAW sector */
|
||||
return FALSE_0;
|
||||
}
|
||||
|
||||
return TRUE_1;
|
||||
}
|
||||
|
|
@ -1,259 +0,0 @@
|
|||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xD8 - SAPSP *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_SAPSP(const uint8 *cdb)
|
||||
{
|
||||
uint32 new_read_sec_start;
|
||||
|
||||
//printf("Set audio start: %02x %02x %02x %02x %02x %02x %02x\n", cdb[9], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6]);
|
||||
switch (cdb[9] & 0xc0)
|
||||
{
|
||||
default: //SCSIDBG("Unknown SAPSP 9: %02x\n", cdb[9]);
|
||||
case 0x00:
|
||||
new_read_sec_start = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
new_read_sec_start = AMSF_to_LBA(BCD_to_U8(cdb[2]), BCD_to_U8(cdb[3]), BCD_to_U8(cdb[4]));
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
int track = BCD_to_U8(cdb[2]);
|
||||
|
||||
if(!track)
|
||||
track = 1;
|
||||
else if(track >= toc.last_track + 1)
|
||||
track = 100;
|
||||
new_read_sec_start = toc.tracks[track].lba;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("%lld\n", (long long)(monotonic_timestamp - pce_lastsapsp_timestamp) * 1000 / System_Clock);
|
||||
if(cdda.CDDAStatus == CDDASTATUS_PLAYING && new_read_sec_start == read_sec_start && ((int64)(monotonic_timestamp - pce_lastsapsp_timestamp) * 1000 / System_Clock) < 190)
|
||||
{
|
||||
pce_lastsapsp_timestamp = monotonic_timestamp;
|
||||
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
pce_lastsapsp_timestamp = monotonic_timestamp;
|
||||
|
||||
read_sec = read_sec_start = new_read_sec_start;
|
||||
read_sec_end = toc.tracks[100].lba;
|
||||
|
||||
|
||||
cdda.CDDAReadPos = 588;
|
||||
|
||||
cdda.CDDAStatus = CDDASTATUS_PAUSED;
|
||||
cdda.PlayMode = PLAYMODE_SILENT;
|
||||
|
||||
if(cdb[1])
|
||||
{
|
||||
cdda.PlayMode = PLAYMODE_NORMAL;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
}
|
||||
|
||||
if(read_sec < toc.tracks[100].lba)
|
||||
Cur_CDIF->HintReadSector(read_sec);
|
||||
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xD9 - SAPEP *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_SAPEP(const uint8 *cdb)
|
||||
{
|
||||
uint32 new_read_sec_end;
|
||||
|
||||
//printf("Set audio end: %02x %02x %02x %02x %02x %02x %02x\n", cdb[9], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6]);
|
||||
|
||||
switch (cdb[9] & 0xc0)
|
||||
{
|
||||
default: //SCSIDBG("Unknown SAPEP 9: %02x\n", cdb[9]);
|
||||
|
||||
case 0x00:
|
||||
new_read_sec_end = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
new_read_sec_end = BCD_to_U8(cdb[4]) + 75 * (BCD_to_U8(cdb[3]) + 60 * BCD_to_U8(cdb[2]));
|
||||
new_read_sec_end -= 150;
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
int track = BCD_to_U8(cdb[2]);
|
||||
|
||||
if(!track)
|
||||
track = 1;
|
||||
else if(track >= toc.last_track + 1)
|
||||
track = 100;
|
||||
new_read_sec_end = toc.tracks[track].lba;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
read_sec_end = new_read_sec_end;
|
||||
|
||||
switch(cdb[1]) // PCE CD(TODO: Confirm these, and check the mode mask):
|
||||
{
|
||||
default:
|
||||
case 0x03: cdda.PlayMode = PLAYMODE_NORMAL;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
break;
|
||||
|
||||
case 0x02: cdda.PlayMode = PLAYMODE_INTERRUPT;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
break;
|
||||
|
||||
case 0x01: cdda.PlayMode = PLAYMODE_LOOP;
|
||||
cdda.CDDAStatus = CDDASTATUS_PLAYING;
|
||||
break;
|
||||
|
||||
case 0x00: cdda.PlayMode = PLAYMODE_SILENT;
|
||||
cdda.CDDAStatus = CDDASTATUS_STOPPED;
|
||||
break;
|
||||
}
|
||||
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xDA - Pause *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_PAUSE(const uint8 *cdb)
|
||||
{
|
||||
if(cdda.CDDAStatus != CDDASTATUS_STOPPED) // Hmm, should we give an error if it tries to pause and it's already paused?
|
||||
{
|
||||
cdda.CDDAStatus = CDDASTATUS_PAUSED;
|
||||
SendStatusAndMessage(STATUS_GOOD, 0x00);
|
||||
}
|
||||
else // Definitely give an error if it tries to pause when no track is playing!
|
||||
{
|
||||
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_AUDIO_NOT_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xDD - Read Subchannel Q *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_READSUBQ(const uint8 *cdb)
|
||||
{
|
||||
uint8 *SubQBuf = cd.SubQBuf[QMode_Time];
|
||||
uint8 data_in[8192];
|
||||
|
||||
memset(data_in, 0x00, 10);
|
||||
|
||||
data_in[2] = SubQBuf[1]; // Track
|
||||
data_in[3] = SubQBuf[2]; // Index
|
||||
data_in[4] = SubQBuf[3]; // M(rel)
|
||||
data_in[5] = SubQBuf[4]; // S(rel)
|
||||
data_in[6] = SubQBuf[5]; // F(rel)
|
||||
data_in[7] = SubQBuf[7]; // M(abs)
|
||||
data_in[8] = SubQBuf[8]; // S(abs)
|
||||
data_in[9] = SubQBuf[9]; // F(abs)
|
||||
|
||||
if(cdda.CDDAStatus == CDDASTATUS_PAUSED)
|
||||
data_in[0] = 2; // Pause
|
||||
else if(cdda.CDDAStatus == CDDASTATUS_PLAYING || cdda.CDDAStatus == CDDASTATUS_SCANNING) // FIXME: Is this the correct status code for scanning playback?
|
||||
data_in[0] = 0; // Playing
|
||||
else
|
||||
data_in[0] = 3; // Stopped
|
||||
|
||||
DoSimpleDataIn(data_in, 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* PC Engine CD Command 0xDE - Get Directory Info *
|
||||
* *
|
||||
********************************************************/
|
||||
static void DoNEC_PCE_GETDIRINFO(const uint8 *cdb)
|
||||
{
|
||||
// Problems:
|
||||
// Returned data lengths on real PCE are not confirmed.
|
||||
// Mode 0x03 behavior not tested on real PCE
|
||||
|
||||
uint8 data_in[2048];
|
||||
uint32 data_in_size = 0;
|
||||
|
||||
memset(data_in, 0, sizeof(data_in));
|
||||
|
||||
switch(cdb[1])
|
||||
{
|
||||
default: //MDFN_DispMessage("Unknown GETDIRINFO Mode: %02x", cdb[1]);
|
||||
//printf("Unknown GETDIRINFO Mode: %02x", cdb[1]);
|
||||
case 0x0:
|
||||
data_in[0] = U8_to_BCD(toc.first_track);
|
||||
data_in[1] = U8_to_BCD(toc.last_track);
|
||||
|
||||
data_in_size = 2;
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
{
|
||||
uint8 m, s, f;
|
||||
|
||||
LBA_to_AMSF(toc.tracks[100].lba, &m, &s, &f);
|
||||
|
||||
data_in[0] = U8_to_BCD(m);
|
||||
data_in[1] = U8_to_BCD(s);
|
||||
data_in[2] = U8_to_BCD(f);
|
||||
|
||||
data_in_size = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
{
|
||||
uint8 m, s, f;
|
||||
int track = BCD_to_U8(cdb[2]);
|
||||
|
||||
if(!track)
|
||||
track = 1;
|
||||
else if(cdb[2] == 0xAA)
|
||||
{
|
||||
track = 100;
|
||||
}
|
||||
else if(track > 99)
|
||||
{
|
||||
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
|
||||
|
||||
data_in[0] = U8_to_BCD(m);
|
||||
data_in[1] = U8_to_BCD(s);
|
||||
data_in[2] = U8_to_BCD(f);
|
||||
data_in[3] = toc.tracks[track].control;
|
||||
data_in_size = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DoSimpleDataIn(data_in, data_in_size);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,99 +0,0 @@
|
|||
#ifndef __PCFX_SCSICD_H
|
||||
#define __PCFX_SCSICD_H
|
||||
|
||||
typedef int32 scsicd_timestamp_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Data bus(FIXME: we should have a variable for the target and the initiator, and OR them together to be truly accurate).
|
||||
uint8 DB;
|
||||
|
||||
uint32 signals;
|
||||
|
||||
// Signals under our(the "target") control.
|
||||
//bool BSY, MSG, CD, REQ, IO;
|
||||
|
||||
// Signals under the control of the initiator(not us!)
|
||||
//bool kingACK, kingRST, kingSEL, kingATN;
|
||||
} scsicd_bus_t;
|
||||
|
||||
extern scsicd_bus_t cd_bus; // Don't access this structure directly by name outside of scsicd.c, but use the macros below.
|
||||
|
||||
// Signals under our(the "target") control.
|
||||
#define SCSICD_IO_mask 0x001
|
||||
#define SCSICD_CD_mask 0x002
|
||||
#define SCSICD_MSG_mask 0x004
|
||||
#define SCSICD_REQ_mask 0x008
|
||||
#define SCSICD_BSY_mask 0x010
|
||||
|
||||
// Signals under the control of the initiator(not us!)
|
||||
#define SCSICD_kingRST_mask 0x020
|
||||
#define SCSICD_kingACK_mask 0x040
|
||||
#define SCSICD_kingATN_mask 0x080
|
||||
#define SCSICD_kingSEL_mask 0x100
|
||||
|
||||
#define BSY_signal ((const bool)(cd_bus.signals & SCSICD_BSY_mask))
|
||||
#define ACK_signal ((const bool)(cd_bus.signals & SCSICD_kingACK_mask))
|
||||
#define RST_signal ((const bool)(cd_bus.signals & SCSICD_kingRST_mask))
|
||||
#define MSG_signal ((const bool)(cd_bus.signals & SCSICD_MSG_mask))
|
||||
#define SEL_signal ((const bool)(cd_bus.signals & SCSICD_kingSEL_mask))
|
||||
#define REQ_signal ((const bool)(cd_bus.signals & SCSICD_REQ_mask))
|
||||
#define IO_signal ((const bool)(cd_bus.signals & SCSICD_IO_mask))
|
||||
#define CD_signal ((const bool)(cd_bus.signals & SCSICD_CD_mask))
|
||||
#define ATN_signal ((const bool)(cd_bus.signals & SCSICD_kingATN_mask))
|
||||
|
||||
#define DB_signal ((const uint8)cd_bus.DB)
|
||||
|
||||
#define SCSICD_GetDB() DB_signal
|
||||
#define SCSICD_GetBSY() BSY_signal
|
||||
#define SCSICD_GetIO() IO_signal
|
||||
#define SCSICD_GetCD() CD_signal
|
||||
#define SCSICD_GetMSG() MSG_signal
|
||||
#define SCSICD_GetREQ() REQ_signal
|
||||
|
||||
// Should we phase out getting these initiator-driven signals like this(the initiator really should keep track of them itself)?
|
||||
#define SCSICD_GetACK() ACK_signal
|
||||
#define SCSICD_GetRST() RST_signal
|
||||
#define SCSICD_GetSEL() SEL_signal
|
||||
#define SCSICD_GetATN() ATN_signal
|
||||
|
||||
void SCSICD_Power(scsicd_timestamp_t system_timestamp);
|
||||
void SCSICD_SetDB(uint8 data);
|
||||
|
||||
// These SCSICD_Set* functions are kind of misnomers, at least in comparison to the SCSICD_Get* functions...
|
||||
// They will set/clear the bits corresponding to the KING's side of the bus.
|
||||
void SCSICD_SetACK(bool set);
|
||||
void SCSICD_SetSEL(bool set);
|
||||
void SCSICD_SetRST(bool set);
|
||||
void SCSICD_SetATN(bool set);
|
||||
|
||||
uint32 SCSICD_Run(scsicd_timestamp_t);
|
||||
void SCSICD_ResetTS(uint32 ts_base);
|
||||
|
||||
enum
|
||||
{
|
||||
SCSICD_PCE = 1,
|
||||
SCSICD_PCFX
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCSICD_IRQ_DATA_TRANSFER_DONE = 1,
|
||||
SCSICD_IRQ_DATA_TRANSFER_READY,
|
||||
SCSICD_IRQ_MAGICAL_REQ,
|
||||
};
|
||||
|
||||
void SCSICD_GetCDDAValues(int16 &left, int16 &right);
|
||||
|
||||
void SCSICD_SetLog(void (*logfunc)(const char *, const char *, ...));
|
||||
|
||||
void SCSICD_Init(int type, int CDDATimeDiv, int32* left_hrbuf, int32* right_hrbuf, uint32 TransferRate, uint32 SystemClock, void (*IRQFunc)(int), void (*SSCFunc)(uint8, int));
|
||||
void SCSICD_Close(void);
|
||||
|
||||
void SCSICD_SetTransferRate(uint32 TransferRate);
|
||||
void SCSICD_SetCDDAVolume(double left, double right);
|
||||
void SCSICD_StateAction(StateMem *sm, const unsigned load, const bool data_only, const char *sname);
|
||||
|
||||
void SCSICD_SetDisc(bool tray_open, CDIF *cdif, bool no_emu_side_effects = false);
|
||||
|
||||
#endif
|
|
@ -1,69 +0,0 @@
|
|||
// WARNING: Check resampling algorithm in scsicd.cpp for overflows if any value in here is negative.
|
||||
|
||||
/* -1 */ { 1777, 12211, 27812, 27640, 11965, 1703, 9, 0 }, // 83117 83119.332059(diff = 2.332059)
|
||||
/* 0 */ { 1702, 11965, 27640, 27811, 12211, 1777, 11, 0 }, // 83117 83121.547903(diff = 4.547903)
|
||||
/* 1 */ { 1630, 11720, 27463, 27977, 12459, 1854, 14, 0 }, // 83117 83123.444392(diff = 6.444392)
|
||||
/* 2 */ { 1560, 11478, 27282, 28139, 12708, 1933, 17, 0 }, // 83117 83125.036510(diff = 8.036510)
|
||||
/* 3 */ { 1492, 11238, 27098, 28296, 12959, 2014, 20, 0 }, // 83117 83126.338722(diff = 9.338722)
|
||||
/* 4 */ { 1427, 11000, 26909, 28448, 13212, 2098, 23, 0 }, // 83117 83127.364983(diff = 10.364983)
|
||||
/* 5 */ { 1363, 10764, 26716, 28595, 13467, 2185, 27, 0 }, // 83117 83128.128743(diff = 11.128743)
|
||||
/* 6 */ { 1302, 10530, 26519, 28738, 13723, 2274, 31, 0 }, // 83117 83128.642956(diff = 11.642956)
|
||||
/* 7 */ { 1242, 10299, 26319, 28876, 13981, 2365, 35, 0 }, // 83117 83128.920096(diff = 11.920096)
|
||||
/* 8 */ { 1185, 10071, 26115, 29009, 14239, 2459, 39, 0 }, // 83117 83128.972128(diff = 11.972128)
|
||||
/* 9 */ { 1129, 9844, 25907, 29137, 14499, 2556, 45, 0 }, // 83117 83128.810568(diff = 11.810568)
|
||||
/* 10 */ { 1076, 9620, 25695, 29260, 14761, 2655, 50, 0 }, // 83117 83128.446456(diff = 11.446456)
|
||||
/* 11 */ { 1024, 9399, 25481, 29377, 15023, 2757, 56, 0 }, // 83117 83127.890369(diff = 10.890369)
|
||||
/* 12 */ { 975, 9180, 25263, 29489, 15287, 2861, 62, 0 }, // 83117 83127.152431(diff = 10.152431)
|
||||
/* 13 */ { 927, 8964, 25041, 29596, 15552, 2968, 69, 0 }, // 83117 83126.242312(diff = 9.242312)
|
||||
/* 14 */ { 880, 8750, 24817, 29698, 15818, 3078, 76, 0 }, // 83117 83125.169251(diff = 8.169251)
|
||||
/* 15 */ { 836, 8539, 24590, 29794, 16083, 3191, 84, 0 }, // 83117 83123.942037(diff = 6.942037)
|
||||
/* 16 */ { 793, 8331, 24359, 29884, 16350, 3307, 93, 0 }, // 83117 83122.569034(diff = 5.569034)
|
||||
/* 17 */ { 752, 8125, 24126, 29969, 16618, 3425, 102, 0 }, // 83117 83121.058175(diff = 4.058175)
|
||||
/* 18 */ { 712, 7923, 23890, 30049, 16886, 3546, 111, 0 }, // 83117 83119.416975(diff = 2.416975)
|
||||
/* 19 */ { 674, 7723, 23651, 30123, 17154, 3670, 122, 0 }, // 83117 83117.652622(diff = 0.652622)
|
||||
/* 20 */ { 638, 7526, 23410, 30191, 17422, 3797, 133, 0 }, // 83117 83115.771622(diff = 1.228378)
|
||||
/* 21 */ { 603, 7331, 23167, 30254, 17691, 3927, 144, 0 }, // 83117 83113.780335(diff = 3.219665)
|
||||
/* 22 */ { 569, 7140, 22922, 30310, 17960, 4059, 157, 0 }, // 83117 83111.684630(diff = 5.315370)
|
||||
/* 23 */ { 537, 6951, 22674, 30361, 18229, 4195, 170, 0 }, // 83117 83109.489972(diff = 7.510028)
|
||||
/* 24 */ { 506, 6766, 22424, 30407, 18497, 4334, 183, 0 }, // 83117 83107.201429(diff = 9.798571)
|
||||
/* 25 */ { 477, 6583, 22172, 30446, 18766, 4475, 198, 0 }, // 83117 83104.823668(diff = 12.176332)
|
||||
/* 26 */ { 449, 6403, 21919, 30479, 19034, 4619, 214, 0 }, // 83117 83102.360963(diff = 14.639037)
|
||||
/* 27 */ { 422, 6226, 21664, 30507, 19301, 4767, 230, 0 }, // 83117 83099.817193(diff = 17.182807)
|
||||
/* 28 */ { 396, 6053, 21407, 30529, 19568, 4917, 247, 0 }, // 83117 83097.195820(diff = 19.804180)
|
||||
/* 29 */ { 372, 5882, 21148, 30545, 19834, 5071, 265, 0 }, // 83117 83094.499993(diff = 22.500007)
|
||||
/* 30 */ { 348, 5714, 20888, 30555, 20100, 5227, 285, 0 }, // 83117 83091.732389(diff = 25.267611)
|
||||
/* 31 */ { 326, 5549, 20627, 30559, 20365, 5386, 305, 0 }, // 83117 83088.895321(diff = 28.104679)
|
||||
/* 32 */ { 305, 5386, 20365, 30559, 20627, 5549, 326, 0 }, // 83117 83088.895321(diff = 28.104679)
|
||||
/* 33 */ { 285, 5227, 20100, 30555, 20888, 5714, 348, 0 }, // 83117 83091.732389(diff = 25.267611)
|
||||
/* 34 */ { 265, 5071, 19834, 30545, 21148, 5882, 372, 0 }, // 83117 83094.499993(diff = 22.500007)
|
||||
/* 35 */ { 247, 4917, 19568, 30529, 21407, 6053, 396, 0 }, // 83117 83097.195820(diff = 19.804180)
|
||||
/* 36 */ { 230, 4767, 19301, 30507, 21664, 6226, 422, 0 }, // 83117 83099.817193(diff = 17.182807)
|
||||
/* 37 */ { 214, 4619, 19034, 30479, 21919, 6403, 449, 0 }, // 83117 83102.360963(diff = 14.639037)
|
||||
/* 38 */ { 198, 4475, 18766, 30446, 22172, 6583, 477, 0 }, // 83117 83104.823668(diff = 12.176332)
|
||||
/* 39 */ { 183, 4334, 18497, 30407, 22424, 6766, 506, 0 }, // 83117 83107.201429(diff = 9.798571)
|
||||
/* 40 */ { 170, 4195, 18229, 30361, 22674, 6951, 537, 0 }, // 83117 83109.489972(diff = 7.510028)
|
||||
/* 41 */ { 157, 4059, 17960, 30310, 22922, 7140, 569, 0 }, // 83117 83111.684630(diff = 5.315370)
|
||||
/* 42 */ { 144, 3927, 17691, 30254, 23167, 7331, 603, 0 }, // 83117 83113.780335(diff = 3.219665)
|
||||
/* 43 */ { 133, 3797, 17422, 30191, 23410, 7526, 638, 0 }, // 83117 83115.771622(diff = 1.228378)
|
||||
/* 44 */ { 122, 3670, 17154, 30123, 23651, 7723, 674, 0 }, // 83117 83117.652622(diff = 0.652622)
|
||||
/* 45 */ { 111, 3546, 16886, 30049, 23890, 7923, 712, 0 }, // 83117 83119.416975(diff = 2.416975)
|
||||
/* 46 */ { 102, 3425, 16618, 29969, 24126, 8125, 752, 0 }, // 83117 83121.058175(diff = 4.058175)
|
||||
/* 47 */ { 93, 3307, 16350, 29884, 24359, 8331, 793, 0 }, // 83117 83122.569034(diff = 5.569034)
|
||||
/* 48 */ { 84, 3191, 16083, 29794, 24590, 8539, 836, 0 }, // 83117 83123.942037(diff = 6.942037)
|
||||
/* 49 */ { 76, 3078, 15818, 29698, 24817, 8750, 880, 0 }, // 83117 83125.169251(diff = 8.169251)
|
||||
/* 50 */ { 69, 2968, 15552, 29596, 25041, 8964, 927, 0 }, // 83117 83126.242312(diff = 9.242312)
|
||||
/* 51 */ { 62, 2861, 15287, 29489, 25263, 9180, 975, 0 }, // 83117 83127.152431(diff = 10.152431)
|
||||
/* 52 */ { 56, 2757, 15023, 29377, 25481, 9399, 1024, 0 }, // 83117 83127.890369(diff = 10.890369)
|
||||
/* 53 */ { 50, 2655, 14761, 29260, 25695, 9620, 1076, 0 }, // 83117 83128.446456(diff = 11.446456)
|
||||
/* 54 */ { 45, 2556, 14499, 29137, 25907, 9844, 1129, 0 }, // 83117 83128.810568(diff = 11.810568)
|
||||
/* 55 */ { 39, 2459, 14239, 29009, 26115, 10071, 1185, 0 }, // 83117 83128.972128(diff = 11.972128)
|
||||
/* 56 */ { 35, 2365, 13981, 28876, 26319, 10299, 1242, 0 }, // 83117 83128.920096(diff = 11.920096)
|
||||
/* 57 */ { 31, 2274, 13723, 28738, 26519, 10530, 1302, 0 }, // 83117 83128.642956(diff = 11.642956)
|
||||
/* 58 */ { 27, 2185, 13467, 28595, 26716, 10764, 1363, 0 }, // 83117 83128.128743(diff = 11.128743)
|
||||
/* 59 */ { 23, 2098, 13212, 28448, 26909, 11000, 1427, 0 }, // 83117 83127.364983(diff = 10.364983)
|
||||
/* 60 */ { 20, 2014, 12959, 28296, 27098, 11238, 1492, 0 }, // 83117 83126.338722(diff = 9.338722)
|
||||
/* 61 */ { 17, 1933, 12708, 28139, 27282, 11478, 1560, 0 }, // 83117 83125.036510(diff = 8.036510)
|
||||
/* 62 */ { 14, 1854, 12459, 27977, 27463, 11720, 1630, 0 }, // 83117 83123.444392(diff = 6.444392)
|
||||
/* 63 */ { 11, 1777, 12211, 27811, 27640, 11965, 1702, 0 }, // 83117 83121.547903(diff = 4.547903)
|
||||
/* 64 */ { 9, 1703, 11965, 27640, 27812, 12211, 1777, 0 }, // 83117 83119.332059(diff = 2.332059)
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
#include "EW_state.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace EW {
|
||||
|
||||
NewStateDummy::NewStateDummy()
|
||||
:length(0)
|
||||
{
|
||||
}
|
||||
void NewStateDummy::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
length += size;
|
||||
}
|
||||
void NewStateDummy::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
NewStateExternalBuffer::NewStateExternalBuffer(char *buffer, long maxlength)
|
||||
:buffer(buffer), length(0), maxlength(maxlength)
|
||||
{
|
||||
}
|
||||
|
||||
void NewStateExternalBuffer::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
if (maxlength - length >= (long)size)
|
||||
{
|
||||
std::memcpy(buffer + length, ptr, size);
|
||||
}
|
||||
length += size;
|
||||
}
|
||||
|
||||
void NewStateExternalBuffer::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
char *dst = static_cast<char *>(ptr);
|
||||
if (maxlength - length >= (long)size)
|
||||
{
|
||||
std::memcpy(dst, buffer + length, size);
|
||||
}
|
||||
length += size;
|
||||
}
|
||||
|
||||
NewStateExternalFunctions::NewStateExternalFunctions(const FPtrs *ff)
|
||||
:Save_(ff->Save_),
|
||||
Load_(ff->Load_),
|
||||
EnterSection_(ff->EnterSection_),
|
||||
ExitSection_(ff->ExitSection_)
|
||||
{
|
||||
}
|
||||
|
||||
void NewStateExternalFunctions::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
Save_(ptr, size, name);
|
||||
}
|
||||
void NewStateExternalFunctions::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
Load_(ptr, size, name);
|
||||
}
|
||||
|
||||
void NewStateExternalFunctions::EnterSection(const char *name, ...)
|
||||
{
|
||||
//analysis: multiple passes to generate string not ideal, but there arent many sections.. so it should be OK. improvement would be special vararg overload
|
||||
va_list ap;
|
||||
va_start(ap,name);
|
||||
char easybuf[32];
|
||||
int size = vsnprintf(easybuf,0,name,ap);
|
||||
char *ptr = easybuf;
|
||||
if(size>31)
|
||||
ptr = (char*)malloc(size+1);
|
||||
vsprintf(ptr,name,ap);
|
||||
EnterSection_(ptr);
|
||||
if(ptr != easybuf)
|
||||
free(ptr);
|
||||
va_end(ap);
|
||||
}
|
||||
void NewStateExternalFunctions::ExitSection(const char *name, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap,name);
|
||||
char easybuf[32];
|
||||
int size = vsnprintf(easybuf,0,name,ap);
|
||||
char *ptr = easybuf;
|
||||
if(size>31)
|
||||
ptr = (char*)malloc(size+1);
|
||||
vsprintf(ptr,name,ap);
|
||||
ExitSection_(ptr);
|
||||
if(ptr != easybuf)
|
||||
free(ptr);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
#ifndef NEWSTATE_H
|
||||
#define NEWSTATE_H
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
namespace EW
|
||||
{
|
||||
|
||||
class NewState
|
||||
{
|
||||
public:
|
||||
virtual void Save(const void *ptr, size_t size, const char *name) = 0;
|
||||
virtual void Load(void *ptr, size_t size, const char *name) = 0;
|
||||
virtual void EnterSection(const char *name, ...) { }
|
||||
virtual void ExitSection(const char *name, ...) { }
|
||||
};
|
||||
|
||||
class NewStateDummy : public NewState
|
||||
{
|
||||
private:
|
||||
long length;
|
||||
public:
|
||||
NewStateDummy();
|
||||
long GetLength() { return length; }
|
||||
void Rewind() { length = 0; }
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
};
|
||||
|
||||
class NewStateExternalBuffer : public NewState
|
||||
{
|
||||
private:
|
||||
char *const buffer;
|
||||
long length;
|
||||
const long maxlength;
|
||||
public:
|
||||
NewStateExternalBuffer(char *buffer, long maxlength);
|
||||
long GetLength() { return length; }
|
||||
void Rewind() { length = 0; }
|
||||
bool Overflow() { return length > maxlength; }
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
};
|
||||
|
||||
struct FPtrs
|
||||
{
|
||||
void (*Save_)(const void *ptr, size_t size, const char *name);
|
||||
void (*Load_)(void *ptr, size_t size, const char *name);
|
||||
void (*EnterSection_)(const char *name);
|
||||
void (*ExitSection_)(const char *name);
|
||||
};
|
||||
|
||||
class NewStateExternalFunctions : public NewState
|
||||
{
|
||||
private:
|
||||
void (*Save_)(const void *ptr, size_t size, const char *name);
|
||||
void (*Load_)(void *ptr, size_t size, const char *name);
|
||||
void (*EnterSection_)(const char *name);
|
||||
void (*ExitSection_)(const char *name);
|
||||
public:
|
||||
NewStateExternalFunctions(const FPtrs *ff);
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
virtual void EnterSection(const char *name, ...);
|
||||
virtual void ExitSection(const char *name, ...);
|
||||
};
|
||||
|
||||
// defines and explicitly instantiates
|
||||
#define SYNCFUNC(x)\
|
||||
template void x::SyncState<false>(EW::NewState *ns);\
|
||||
template void x::SyncState<true>(EW::NewState *ns);\
|
||||
template<bool isReader>void x::SyncState(EW::NewState *ns)
|
||||
|
||||
// N = normal variable
|
||||
// P = pointer to fixed size data
|
||||
// S = "sub object"
|
||||
// T = "ptr to sub object"
|
||||
// R = pointer, store its offset from some other pointer
|
||||
// E = general purpose cased value "enum"
|
||||
|
||||
|
||||
// first line is default value in converted enum; last line is default value in argument x
|
||||
#define EBS(x,d) do { int _ttmp = (d); if (isReader) ns->Load(&_ttmp, sizeof(_ttmp), #x); if (0)
|
||||
#define EVS(x,v,n) else if (!isReader && (x) == (v)) _ttmp = (n); else if (isReader && _ttmp == (n)) (x) = (v)
|
||||
#define EES(x,d) else if (isReader) (x) = (d); if (!isReader) ns->Save(&_ttmp, sizeof(_ttmp), #x); } while (0)
|
||||
|
||||
#define RSS(x,b) do { if (isReader)\
|
||||
{ ptrdiff_t _ttmp; ns->Load(&_ttmp, sizeof(_ttmp), #x); (x) = (_ttmp == (ptrdiff_t)0xdeadbeef ? 0 : (b) + _ttmp); }\
|
||||
else\
|
||||
{ ptrdiff_t _ttmp = (x) == 0 ? 0xdeadbeef : (x) - (b); ns->Save(&_ttmp, sizeof(_ttmp), #x); } } while (0)
|
||||
|
||||
#define PSS(x,s) do { if (isReader) ns->Load((x), (s), #x); else ns->Save((x), (s), #x); } while (0)
|
||||
|
||||
#define NSS(x) do { if (isReader) ns->Load(&(x), sizeof(x), #x); else ns->Save(&(x), sizeof(x), #x); } while (0)
|
||||
|
||||
#define SSS(x) do { ns->EnterSection(#x); (x).SyncState<isReader>(ns); ns->ExitSection(#x); } while (0)
|
||||
|
||||
#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState<isReader>(ns); ns->ExitSection(#x); } while (0)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //NEWSTATE_H
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef __GNUC__
|
||||
#pragma pack(push, 1)
|
||||
#pragma warning(disable : 4103)
|
||||
#endif
|
||||
|
||||
#ifndef __PACKED
|
||||
#ifdef __GNUC__
|
||||
#define __PACKED __attribute__((__packed__))
|
||||
#else
|
||||
#define __PACKED
|
||||
#endif
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
#ifndef __GNUC__
|
||||
#pragma pack(pop)
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
#include "emuware.h"
|
||||
|
||||
//this file intentionally empty
|
|
@ -1,160 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef __int64 s64;
|
||||
typedef __int32 s32;
|
||||
typedef __int16 s16;
|
||||
typedef __int8 s8;
|
||||
typedef unsigned __int64 u64;
|
||||
typedef unsigned __int32 u32;
|
||||
typedef unsigned __int16 u16;
|
||||
typedef unsigned __int8 u8;
|
||||
|
||||
typedef __int64 int64;
|
||||
typedef __int32 int32;
|
||||
typedef __int16 int16;
|
||||
typedef __int8 int8;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef unsigned __int32 uint32;
|
||||
typedef unsigned __int16 uint16;
|
||||
typedef unsigned __int8 uint8;
|
||||
#else
|
||||
typedef __int64_t s64;
|
||||
typedef __int32_t s32;
|
||||
typedef __int16_t s16;
|
||||
typedef __int8_t s8;
|
||||
typedef __uint64_t u64;
|
||||
typedef __uint32_t u32;
|
||||
typedef __uint16_t u16;
|
||||
typedef __uint8_t u8;
|
||||
|
||||
typedef __int64_t int64;
|
||||
typedef __int32_t int32;
|
||||
typedef __int16_t int16;
|
||||
typedef __int8_t int8;
|
||||
typedef __uint64_t uint64;
|
||||
typedef __uint32_t uint32;
|
||||
typedef __uint16_t uint16;
|
||||
typedef __uint8_t uint8;
|
||||
#endif
|
||||
|
||||
#define final
|
||||
#define noexcept
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
//http://stackoverflow.com/questions/355967/how-to-use-msvc-intrinsics-to-get-the-equivalent-of-this-gcc-code
|
||||
//if needed
|
||||
//uint32_t __inline ctz( uint32_t value )
|
||||
//{
|
||||
// DWORD trailing_zero = 0;
|
||||
//
|
||||
// if ( _BitScanForward( &trailing_zero, value ) )
|
||||
// {
|
||||
// return trailing_zero;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // This is undefined, I better choose 32 than 0
|
||||
// return 32;
|
||||
// }
|
||||
//}
|
||||
|
||||
uint32 __inline __builtin_clz( uint32_t value )
|
||||
{
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if ( _BitScanReverse( &leading_zero, value ) )
|
||||
{
|
||||
return 31 - leading_zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Same remarks as above
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//#if MDFN_GCC_VERSION >= MDFN_MAKE_GCCV(4,7,0)
|
||||
// #define MDFN_ASSUME_ALIGNED(p, align) __builtin_assume_aligned((p), (align))
|
||||
//#else
|
||||
// #define MDFN_ASSUME_ALIGNED(p, align) (p)
|
||||
//#endif
|
||||
#define MDFN_ASSUME_ALIGNED(p, align) (p)
|
||||
|
||||
//#define MDFN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
|
||||
#define MDFN_WARN_UNUSED_RESULT
|
||||
|
||||
//#define MDFN_COLD __attribute__((cold))
|
||||
#define MDFN_COLD
|
||||
|
||||
//#define NO_INLINE __attribute__((noinline))
|
||||
#define NO_INLINE
|
||||
|
||||
//#define MDFN_UNLIKELY(n) __builtin_expect((n) != 0, 0)
|
||||
//#define MDFN_LIKELY(n) __builtin_expect((n) != 0, 1)
|
||||
#define MDFN_UNLIKELY(n) (n)
|
||||
#define MDFN_LIKELY(n) (n)
|
||||
|
||||
//#define MDFN_NOWARN_UNUSED __attribute__((unused))
|
||||
#define MDFN_NOWARN_UNUSED
|
||||
|
||||
//#define MDFN_FORMATSTR(a,b,c) __attribute__ ((format (a, b, c)))
|
||||
#define MDFN_FORMATSTR(a,b,c)
|
||||
|
||||
#define INLINE inline
|
||||
|
||||
#ifndef UNALIGNED
|
||||
#define UNALIGNED
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
#define TRUE_1 1
|
||||
#define FALSE_0 0
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
//taken from winnt.h
|
||||
extern "C++" // templates cannot be declared to have 'C' linkage
|
||||
template <typename T, size_t N>
|
||||
char (*BLAHBLAHBLAH( UNALIGNED T (&)[N] ))[N];
|
||||
|
||||
#define ARRAY_SIZE(A) (sizeof(*BLAHBLAHBLAH(A)))
|
||||
#endif
|
||||
|
||||
//------------alignment macros-------------
|
||||
//dont apply these to types without further testing. it only works portably here on declarations of variables
|
||||
//cant we find a pattern other people use more successfully?
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
#define EW_VAR_ALIGN(X) __declspec(align(X))
|
||||
#elif defined(__GNUC__)
|
||||
#define EW_VAR_ALIGN(X) __attribute__ ((aligned (X)))
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
//---------------------------------------------
|
||||
|
||||
#ifdef EW_EXPORT
|
||||
#undef EW_EXPORT
|
||||
#define EW_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define EW_EXPORT extern "C" __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
|
||||
#define SIZEOF_DOUBLE 8
|
||||
|
||||
#define LSB_FIRST
|
||||
|
||||
//no MSVC support, no use anyway??
|
||||
#define override
|
|
@ -1,138 +0,0 @@
|
|||
------------------------------------------------------------------------
|
||||
r26 | 2009-10-02 13:36:47 +0400 | 2 lines
|
||||
|
||||
[Issue 5] Change <stdint.h> to "stdint.h" to let compiler search for it in local directory.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r25 | 2009-09-17 23:46:49 +0400 | 2 lines
|
||||
|
||||
[Issue 4] Fix incorrect int8_t behaviour if compiled with /J flag.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r24 | 2009-05-13 14:53:48 +0400 | 2 lines
|
||||
|
||||
Forgot about #ifdef __cplusplus guard around 'extern "C"', so inclusion to C files has been broken.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r23 | 2009-05-12 01:27:45 +0400 | 3 lines
|
||||
|
||||
[Issue 2] Always wrap <wcharîàž with external "C" {}.
|
||||
It turns out that not only Visual Studio 6 requires this, but also newer versions when compiling for ARM.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r22 | 2009-05-11 22:22:15 +0400 | 3 lines
|
||||
|
||||
[Issue 3] Visual Studio 6 and Embedded Visual C++ 4 doesn't realize that, e.g. char has the same size as __int8 so we give up on __intX for them.
|
||||
his should close Issue 3 in issue tracker.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r21 | 2008-07-17 09:47:22 +0400 | 4 lines
|
||||
|
||||
Get rid of these compiler warnings when compiling for 32-bit:
|
||||
warning C4311: 'type cast' : pointer truncation from 'void *' to 'uintptr_t'
|
||||
warning C4312: 'type cast' : conversion from 'uintptr_t' to 'const void *' of greater size
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r20 | 2007-10-09 16:54:27 +0400 | 2 lines
|
||||
|
||||
Better C99 conformance: macros for format specifiers should only be included in C++ implementations if __STDC_FORMAT_MACROS is defined before <inttypes.h> is included.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r19 | 2007-07-04 02:14:40 +0400 | 3 lines
|
||||
|
||||
Explicitly cast to appropriate type INT8_MIN, INT16_MIN, INT32_MIN and INT64_MIN constants.
|
||||
Due to their unusual definition in Visual Studio headers (-_Ix_MAX-1) they are propagated to int and thus do not have expected type, causing VS6 strict compiler to claim about type inconsistency.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r18 | 2007-06-26 16:53:23 +0400 | 2 lines
|
||||
|
||||
Better handling of (U)INTx_C macros - now they generate constants of exact width.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r17 | 2007-03-29 20:16:14 +0400 | 2 lines
|
||||
|
||||
Fix typo: Miscrosoft -> Microsoft.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r16 | 2007-02-24 17:32:58 +0300 | 4 lines
|
||||
|
||||
Remove <BaseTsd.h> include, as it is not present in Visual Studio 2005 Epxress Edition and required only for INT_PTR and UINT_PTR types.
|
||||
|
||||
'intptr_t' and 'uintptr_t' types now defined explicitly with #ifdef _WIN64.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r15 | 2007-02-11 20:53:05 +0300 | 2 lines
|
||||
|
||||
More correct fix for compilation under VS6.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r14 | 2007-02-11 20:04:32 +0300 | 2 lines
|
||||
|
||||
Bugfix: fix compiling under VS6, when stdint.h enclosed in 'extern "C" {}'.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r13 | 2006-12-13 16:53:11 +0300 | 2 lines
|
||||
|
||||
Make _inline modifier for imaxdiv default option. Use STATIC_IMAXDIV to make it static.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r12 | 2006-12-13 16:42:24 +0300 | 2 lines
|
||||
|
||||
Error message changed: VC6 supported from now.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r11 | 2006-12-13 16:39:33 +0300 | 2 lines
|
||||
|
||||
All (U)INT* types changed to (unsigned) __int*. This should make stdint.h compatible with VC6.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r10 | 2006-12-13 16:20:57 +0300 | 3 lines
|
||||
|
||||
Added INLINE_IMAXDIV define switch.
|
||||
If INLINE_IMAXDIV is defined imaxdiv() have static modifier. If not - it is _inline.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r9 | 2006-12-13 15:53:52 +0300 | 2 lines
|
||||
|
||||
Error message for non-MSC compiler changed.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r8 | 2006-12-13 12:47:48 +0300 | 2 lines
|
||||
|
||||
Added #ifndef for SIZE_MAX (it is defined in limits.h on MSVSC 8).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r7 | 2006-12-13 01:08:02 +0300 | 2 lines
|
||||
|
||||
License chaged to BSD-derivative.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r6 | 2006-12-13 00:53:20 +0300 | 2 lines
|
||||
|
||||
Added <wchar.h> include to avoid warnings when it is included after stdint.h.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r5 | 2006-12-12 00:58:05 +0300 | 2 lines
|
||||
|
||||
BUGFIX: Definitions of INTPTR_MIN, INTPTR_MAX and UINTPTR_MAX for WIN32 and WIN64 was mixed up.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r4 | 2006-12-12 00:51:55 +0300 | 2 lines
|
||||
|
||||
Rise #error if _MSC_VER is not defined. I.e. compiler other then Microsoft Visual C++ is used.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r3 | 2006-12-11 22:54:14 +0300 | 2 lines
|
||||
|
||||
Added <limits.h> include to stdint.h.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r2 | 2006-12-11 21:39:27 +0300 | 2 lines
|
||||
|
||||
Initial check in.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r1 | 2006-12-11 21:30:23 +0300 | 1 line
|
||||
|
||||
Initial directory structure.
|
||||
------------------------------------------------------------------------
|
|
@ -1,305 +0,0 @@
|
|||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// The fscanf macros for signed integers are:
|
||||
#define SCNd8 "d"
|
||||
#define SCNi8 "i"
|
||||
#define SCNdLEAST8 "d"
|
||||
#define SCNiLEAST8 "i"
|
||||
#define SCNdFAST8 "d"
|
||||
#define SCNiFAST8 "i"
|
||||
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNdFAST16 "hd"
|
||||
#define SCNiFAST16 "hi"
|
||||
|
||||
#define SCNd32 "ld"
|
||||
#define SCNi32 "li"
|
||||
#define SCNdLEAST32 "ld"
|
||||
#define SCNiLEAST32 "li"
|
||||
#define SCNdFAST32 "ld"
|
||||
#define SCNiFAST32 "li"
|
||||
|
||||
#define SCNd64 "I64d"
|
||||
#define SCNi64 "I64i"
|
||||
#define SCNdLEAST64 "I64d"
|
||||
#define SCNiLEAST64 "I64i"
|
||||
#define SCNdFAST64 "I64d"
|
||||
#define SCNiFAST64 "I64i"
|
||||
|
||||
#define SCNdMAX "I64d"
|
||||
#define SCNiMAX "I64i"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNdPTR "I64d"
|
||||
# define SCNiPTR "I64i"
|
||||
#else // _WIN64 ][
|
||||
# define SCNdPTR "ld"
|
||||
# define SCNiPTR "li"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// The fscanf macros for unsigned integers are:
|
||||
#define SCNo8 "o"
|
||||
#define SCNu8 "u"
|
||||
#define SCNx8 "x"
|
||||
#define SCNX8 "X"
|
||||
#define SCNoLEAST8 "o"
|
||||
#define SCNuLEAST8 "u"
|
||||
#define SCNxLEAST8 "x"
|
||||
#define SCNXLEAST8 "X"
|
||||
#define SCNoFAST8 "o"
|
||||
#define SCNuFAST8 "u"
|
||||
#define SCNxFAST8 "x"
|
||||
#define SCNXFAST8 "X"
|
||||
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNxLEAST16 "hx"
|
||||
#define SCNXLEAST16 "hX"
|
||||
#define SCNoFAST16 "ho"
|
||||
#define SCNuFAST16 "hu"
|
||||
#define SCNxFAST16 "hx"
|
||||
#define SCNXFAST16 "hX"
|
||||
|
||||
#define SCNo32 "lo"
|
||||
#define SCNu32 "lu"
|
||||
#define SCNx32 "lx"
|
||||
#define SCNX32 "lX"
|
||||
#define SCNoLEAST32 "lo"
|
||||
#define SCNuLEAST32 "lu"
|
||||
#define SCNxLEAST32 "lx"
|
||||
#define SCNXLEAST32 "lX"
|
||||
#define SCNoFAST32 "lo"
|
||||
#define SCNuFAST32 "lu"
|
||||
#define SCNxFAST32 "lx"
|
||||
#define SCNXFAST32 "lX"
|
||||
|
||||
#define SCNo64 "I64o"
|
||||
#define SCNu64 "I64u"
|
||||
#define SCNx64 "I64x"
|
||||
#define SCNX64 "I64X"
|
||||
#define SCNoLEAST64 "I64o"
|
||||
#define SCNuLEAST64 "I64u"
|
||||
#define SCNxLEAST64 "I64x"
|
||||
#define SCNXLEAST64 "I64X"
|
||||
#define SCNoFAST64 "I64o"
|
||||
#define SCNuFAST64 "I64u"
|
||||
#define SCNxFAST64 "I64x"
|
||||
#define SCNXFAST64 "I64X"
|
||||
|
||||
#define SCNoMAX "I64o"
|
||||
#define SCNuMAX "I64u"
|
||||
#define SCNxMAX "I64x"
|
||||
#define SCNXMAX "I64X"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNoPTR "I64o"
|
||||
# define SCNuPTR "I64u"
|
||||
# define SCNxPTR "I64x"
|
||||
# define SCNXPTR "I64X"
|
||||
#else // _WIN64 ][
|
||||
# define SCNoPTR "lo"
|
||||
# define SCNuPTR "lu"
|
||||
# define SCNxPTR "lx"
|
||||
# define SCNXPTR "lX"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
|
@ -1,247 +0,0 @@
|
|||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2008 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
|
@ -1,151 +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 <stdio.h>
|
||||
#include "emuware/emuware.h"
|
||||
#include "endian.h"
|
||||
|
||||
void Endian_A16_Swap(void *src, uint32 nelements)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 tmp = nsrc[i * 2];
|
||||
|
||||
nsrc[i * 2] = nsrc[i * 2 + 1];
|
||||
nsrc[i * 2 + 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_A32_Swap(void *src, uint32 nelements)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 tmp1 = nsrc[i * 4];
|
||||
uint8 tmp2 = nsrc[i * 4 + 1];
|
||||
|
||||
nsrc[i * 4] = nsrc[i * 4 + 3];
|
||||
nsrc[i * 4 + 1] = nsrc[i * 4 + 2];
|
||||
|
||||
nsrc[i * 4 + 2] = tmp2;
|
||||
nsrc[i * 4 + 3] = tmp1;
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_A64_Swap(void *src, uint32 nelements)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *nsrc = (uint8 *)src;
|
||||
|
||||
for(i = 0; i < nelements; i++)
|
||||
{
|
||||
uint8 *base = &nsrc[i * 8];
|
||||
|
||||
for(int z = 0; z < 4; z++)
|
||||
{
|
||||
uint8 tmp = base[z];
|
||||
|
||||
base[z] = base[7 - z];
|
||||
base[7 - z] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_A16_NE_LE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Endian_A16_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A32_NE_LE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Endian_A32_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A64_NE_LE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Endian_A64_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
void Endian_A16_NE_BE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
Endian_A16_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A32_NE_BE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
Endian_A32_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_A64_NE_BE(void *src, uint32 nelements)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
Endian_A64_Swap(src, nelements);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void FlipByteOrder(uint8 *src, uint32 count)
|
||||
{
|
||||
uint8 *start=src;
|
||||
uint8 *end=src+count-1;
|
||||
|
||||
if((count&1) || !count) return; /* This shouldn't happen. */
|
||||
|
||||
count >>= 1;
|
||||
|
||||
while(count--)
|
||||
{
|
||||
uint8 tmp;
|
||||
|
||||
tmp=*end;
|
||||
*end=*start;
|
||||
*start=tmp;
|
||||
end--;
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
void Endian_V_NE_LE(void *src, uint32 bytesize)
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
FlipByteOrder((uint8 *)src, bytesize);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Endian_V_NE_BE(void *src, uint32 bytesize)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
FlipByteOrder((uint8 *)src, bytesize);
|
||||
#endif
|
||||
}
|
|
@ -1,296 +0,0 @@
|
|||
#ifndef __MDFN_ENDIAN_H
|
||||
#define __MDFN_ENDIAN_H
|
||||
|
||||
#pragma warning(once : 4519)
|
||||
static INLINE uint32 BitsExtract(const uint8* ptr, const size_t bit_offset, const size_t bit_count)
|
||||
{
|
||||
uint32 ret = 0;
|
||||
|
||||
for(size_t x = 0; x < bit_count; x++)
|
||||
{
|
||||
size_t co = bit_offset + x;
|
||||
bool b = (ptr[co >> 3] >> (co & 7)) & 1;
|
||||
|
||||
ret |= (uint64)b << x;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static INLINE void BitsIntract(uint8* ptr, const size_t bit_offset, const size_t bit_count, uint32 value)
|
||||
{
|
||||
for(size_t x = 0; x < bit_count; x++)
|
||||
{
|
||||
size_t co = bit_offset + x;
|
||||
bool b = (value >> x) & 1;
|
||||
uint8 tmp = ptr[co >> 3];
|
||||
|
||||
tmp &= ~(1 << (co & 7));
|
||||
tmp |= b << (co & 7);
|
||||
|
||||
ptr[co >> 3] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Regarding safety of calling MDFN_*sb<true> on dynamically-allocated memory with new uint8[], see C++ standard 3.7.3.1(i.e. it should be
|
||||
safe provided the offsets into the memory are aligned/multiples of the MDFN_*sb access type). malloc()'d and calloc()'d
|
||||
memory should be safe as well.
|
||||
|
||||
Statically-allocated arrays/memory should be unioned with a big POD type or C++11 "alignas"'d. (May need to audit code to ensure
|
||||
this is being done).
|
||||
*/
|
||||
|
||||
void Endian_A16_Swap(void *src, uint32 nelements);
|
||||
void Endian_A32_Swap(void *src, uint32 nelements);
|
||||
void Endian_A64_Swap(void *src, uint32 nelements);
|
||||
|
||||
void Endian_A16_NE_LE(void *src, uint32 nelements);
|
||||
void Endian_A32_NE_LE(void *src, uint32 nelements);
|
||||
void Endian_A64_NE_LE(void *src, uint32 nelements);
|
||||
|
||||
void Endian_A16_NE_BE(void *src, uint32 nelements);
|
||||
void Endian_A32_NE_BE(void *src, uint32 nelements);
|
||||
void Endian_A64_NE_BE(void *src, uint32 nelements);
|
||||
|
||||
void Endian_V_NE_LE(void *src, uint32 bytesize);
|
||||
void Endian_V_NE_BE(void *src, uint32 bytesize);
|
||||
|
||||
static INLINE uint16 MDFN_bswap16(uint16 v)
|
||||
{
|
||||
return (v << 8) | (v >> 8);
|
||||
}
|
||||
|
||||
static INLINE uint32 MDFN_bswap32(uint32 v)
|
||||
{
|
||||
return (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24);
|
||||
}
|
||||
|
||||
static INLINE uint64 MDFN_bswap64(uint64 v)
|
||||
{
|
||||
//octoshock edit
|
||||
//return (v << 56) | (v >> 56) | ((v & 0xFF00) << 40) | ((v >> 40) & 0xFF00) | ((uint64)MDFN_bswap32(v >> 16) << 16);
|
||||
return (v << 56) | (v >> 56) | ((v & 0xFF00) << 40) | ((v >> 40) & 0xFF00) | ((uint64)MDFN_bswap32(((uint32)v) >> 16) << 16);
|
||||
}
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
#define MDFN_ENDIANH_IS_BIGENDIAN 0
|
||||
#else
|
||||
#define MDFN_ENDIANH_IS_BIGENDIAN 1
|
||||
#endif
|
||||
|
||||
//
|
||||
// X endian.
|
||||
//
|
||||
template<int isbigendian, typename T, bool aligned>
|
||||
static INLINE T MDFN_deXsb(const void* ptr)
|
||||
{
|
||||
T tmp;
|
||||
|
||||
memcpy(&tmp, MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), sizeof(T));
|
||||
|
||||
if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN)
|
||||
{
|
||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins.");
|
||||
|
||||
if(sizeof(T) == 8)
|
||||
return (T)MDFN_bswap64(tmp);
|
||||
else if(sizeof(T) == 4)
|
||||
return (T)MDFN_bswap32(tmp);
|
||||
else if(sizeof(T) == 2)
|
||||
return (T)MDFN_bswap16(tmp);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//
|
||||
// Native endian.
|
||||
//
|
||||
template<typename T, bool aligned = false>
|
||||
static INLINE T MDFN_densb(const void* ptr)
|
||||
{
|
||||
return MDFN_deXsb<-1, T, aligned>(ptr);
|
||||
}
|
||||
|
||||
//
|
||||
// Little endian.
|
||||
//
|
||||
template<typename T, bool aligned = false>
|
||||
static INLINE T MDFN_delsb(const void* ptr)
|
||||
{
|
||||
return MDFN_deXsb<0, T, aligned>(ptr);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE uint16 MDFN_de16lsb(const void* ptr)
|
||||
{
|
||||
return MDFN_delsb<uint16, aligned>(ptr);
|
||||
}
|
||||
|
||||
static INLINE uint32 MDFN_de24lsb(const void* ptr)
|
||||
{
|
||||
const uint8* morp = (const uint8*)ptr;
|
||||
return(morp[0]|(morp[1]<<8)|(morp[2]<<16));
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE uint32 MDFN_de32lsb(const void* ptr)
|
||||
{
|
||||
return MDFN_delsb<uint32, aligned>(ptr);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE uint64 MDFN_de64lsb(const void* ptr)
|
||||
{
|
||||
return MDFN_delsb<uint64, aligned>(ptr);
|
||||
}
|
||||
|
||||
//
|
||||
// Big endian.
|
||||
//
|
||||
template<typename T, bool aligned = false>
|
||||
static INLINE T MDFN_demsb(const void* ptr)
|
||||
{
|
||||
return MDFN_deXsb<1, T, aligned>(ptr);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE uint16 MDFN_de16msb(const void* ptr)
|
||||
{
|
||||
return MDFN_demsb<uint16, aligned>(ptr);
|
||||
}
|
||||
|
||||
static INLINE uint32 MDFN_de24msb(const void* ptr)
|
||||
{
|
||||
const uint8* morp = (const uint8*)ptr;
|
||||
return((morp[2]<<0)|(morp[1]<<8)|(morp[0]<<16));
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE uint32 MDFN_de32msb(const void* ptr)
|
||||
{
|
||||
return MDFN_demsb<uint32, aligned>(ptr);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE uint64 MDFN_de64msb(const void* ptr)
|
||||
{
|
||||
return MDFN_demsb<uint64, aligned>(ptr);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
//
|
||||
// X endian.
|
||||
//
|
||||
template<int isbigendian, typename T, bool aligned>
|
||||
static INLINE void MDFN_enXsb(void* ptr, T value)
|
||||
{
|
||||
T tmp = value;
|
||||
|
||||
if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN)
|
||||
{
|
||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins.");
|
||||
|
||||
if(sizeof(T) == 8)
|
||||
tmp = (T)MDFN_bswap64(value);
|
||||
else if(sizeof(T) == 4)
|
||||
tmp = (T)MDFN_bswap32(value);
|
||||
else if(sizeof(T) == 2)
|
||||
tmp = (T)MDFN_bswap16(value);
|
||||
}
|
||||
|
||||
memcpy(MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), &tmp, sizeof(T));
|
||||
}
|
||||
|
||||
//
|
||||
// Native endian.
|
||||
//
|
||||
template<typename T, bool aligned = false>
|
||||
static INLINE void MDFN_ennsb(void* ptr, T value)
|
||||
{
|
||||
MDFN_enXsb<-1, T, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
//
|
||||
// Little endian.
|
||||
//
|
||||
template<typename T, bool aligned = false>
|
||||
static INLINE void MDFN_enlsb(void* ptr, T value)
|
||||
{
|
||||
MDFN_enXsb<0, T, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE void MDFN_en16lsb(void* ptr, uint16 value)
|
||||
{
|
||||
MDFN_enlsb<uint16, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
static INLINE void MDFN_en24lsb(void* ptr, uint32 value)
|
||||
{
|
||||
uint8* morp = (uint8*)ptr;
|
||||
|
||||
morp[0] = value;
|
||||
morp[1] = value >> 8;
|
||||
morp[2] = value >> 16;
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE void MDFN_en32lsb(void* ptr, uint32 value)
|
||||
{
|
||||
MDFN_enlsb<uint32, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE void MDFN_en64lsb(void* ptr, uint64 value)
|
||||
{
|
||||
MDFN_enlsb<uint64, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Big endian.
|
||||
//
|
||||
template<typename T, bool aligned = false>
|
||||
static INLINE void MDFN_enmsb(void* ptr, T value)
|
||||
{
|
||||
MDFN_enXsb<1, T, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE void MDFN_en16msb(void* ptr, uint16 value)
|
||||
{
|
||||
MDFN_enmsb<uint16, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
static INLINE void MDFN_en24msb(void* ptr, uint32 value)
|
||||
{
|
||||
uint8* morp = (uint8*)ptr;
|
||||
|
||||
morp[0] = value;
|
||||
morp[1] = value >> 8;
|
||||
morp[2] = value >> 16;
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE void MDFN_en32msb(void* ptr, uint32 value)
|
||||
{
|
||||
MDFN_enmsb<uint32, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
template<bool aligned = false>
|
||||
static INLINE void MDFN_en64msb(void* ptr, uint64 value)
|
||||
{
|
||||
MDFN_enmsb<uint64, aligned>(ptr, value);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,155 +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 <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "emuware/emuware.h"
|
||||
#include "error.h"
|
||||
|
||||
MDFN_Error::MDFN_Error() noexcept
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
MDFN_Error::MDFN_Error(int errno_code_new, const char *format, ...) noexcept
|
||||
{
|
||||
errno_code = errno_code_new;
|
||||
|
||||
error_message = NULL;
|
||||
|
||||
int size = 128;
|
||||
for(;;) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
error_message = (char*)malloc(size);
|
||||
size *= 2;
|
||||
int ret = vsprintf(error_message, format, ap);
|
||||
va_end(ap);
|
||||
if(ret>=0)
|
||||
break;
|
||||
free(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MDFN_Error::MDFN_Error(const ErrnoHolder &enh)
|
||||
{
|
||||
errno_code = enh.Errno();
|
||||
|
||||
int size = 128;
|
||||
for(;;) {
|
||||
error_message = (char*)malloc(size);
|
||||
size *= 2;
|
||||
int ret = sprintf("%s", enh.StrError());
|
||||
if(ret>=0)
|
||||
break;
|
||||
free(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MDFN_Error::~MDFN_Error() noexcept
|
||||
{
|
||||
if(error_message)
|
||||
{
|
||||
free(error_message);
|
||||
error_message = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
MDFN_Error::MDFN_Error(const MDFN_Error &ze_error) noexcept
|
||||
{
|
||||
if(ze_error.error_message)
|
||||
error_message = strdup(ze_error.error_message);
|
||||
else
|
||||
error_message = NULL;
|
||||
|
||||
errno_code = ze_error.errno_code;
|
||||
}
|
||||
|
||||
MDFN_Error& MDFN_Error::operator=(const MDFN_Error &ze_error) noexcept
|
||||
{
|
||||
char *new_error_message = ze_error.error_message ? strdup(ze_error.error_message) : NULL;
|
||||
int new_errno_code = ze_error.errno_code;
|
||||
|
||||
if(error_message)
|
||||
free(error_message);
|
||||
|
||||
error_message = new_error_message;
|
||||
errno_code = new_errno_code;
|
||||
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
const char * MDFN_Error::what(void) const noexcept
|
||||
{
|
||||
if(!error_message)
|
||||
return("Error allocating memory for the error message!");
|
||||
|
||||
return(error_message);
|
||||
}
|
||||
|
||||
int MDFN_Error::GetErrno(void) const noexcept
|
||||
{
|
||||
return(errno_code);
|
||||
}
|
||||
|
||||
static const char *srr_wrap(int ret, const char *local_strerror)
|
||||
{
|
||||
if(ret == -1)
|
||||
return("ERROR IN strerror_r()!!!");
|
||||
|
||||
return(local_strerror);
|
||||
}
|
||||
|
||||
static const char *srr_wrap(const char *ret, const char *local_strerror)
|
||||
{
|
||||
if(ret == NULL)
|
||||
return("ERROR IN strerror_r()!!!");
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void ErrnoHolder::SetErrno(int the_errno)
|
||||
{
|
||||
local_errno = the_errno;
|
||||
|
||||
if(the_errno == 0)
|
||||
local_strerror[0] = 0;
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_STRERROR_R
|
||||
const char *retv;
|
||||
|
||||
retv = srr_wrap(strerror_r(the_errno, local_strerror, 256), local_strerror);
|
||||
|
||||
if(retv != local_strerror)
|
||||
strncpy(local_strerror, retv, 255);
|
||||
|
||||
#else // No strerror_r :(
|
||||
|
||||
strncpy(local_strerror, strerror(the_errno), 255);
|
||||
|
||||
#endif
|
||||
|
||||
local_strerror[255] = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
#ifndef __MDFN_ERROR_H
|
||||
#define __MDFN_ERROR_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <exception>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
class ErrnoHolder;
|
||||
class MDFN_Error : public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
MDFN_Error() noexcept;
|
||||
|
||||
MDFN_Error(int errno_code_new, const char *format, ...) noexcept MDFN_FORMATSTR(gnu_printf, 3, 4);
|
||||
MDFN_Error(const ErrnoHolder &enh);
|
||||
|
||||
~MDFN_Error() noexcept;
|
||||
|
||||
MDFN_Error(const MDFN_Error &ze_error) noexcept;
|
||||
MDFN_Error & operator=(const MDFN_Error &ze_error) noexcept;
|
||||
|
||||
virtual const char *what(void) const noexcept;
|
||||
int GetErrno(void) const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
int errno_code;
|
||||
char *error_message;
|
||||
};
|
||||
|
||||
class ErrnoHolder
|
||||
{
|
||||
public:
|
||||
|
||||
ErrnoHolder()
|
||||
{
|
||||
//SetErrno(0);
|
||||
local_errno = 0;
|
||||
local_strerror[0] = 0;
|
||||
}
|
||||
|
||||
ErrnoHolder(int the_errno)
|
||||
{
|
||||
SetErrno(the_errno);
|
||||
}
|
||||
|
||||
inline int Errno(void) const
|
||||
{
|
||||
return(local_errno);
|
||||
}
|
||||
|
||||
const char *StrError(void) const
|
||||
{
|
||||
return(local_strerror);
|
||||
}
|
||||
|
||||
void operator=(int the_errno)
|
||||
{
|
||||
SetErrno(the_errno);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void SetErrno(int the_errno);
|
||||
|
||||
int local_errno;
|
||||
char local_strerror[256];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,366 +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 "emuware/emuware.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "general.h"
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#define _(X) X
|
||||
|
||||
#ifdef WIN32
|
||||
#define PSS "\\"
|
||||
#else
|
||||
#define PSS "/"
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
bool untrusted_fip_check;
|
||||
} s_settings;
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
static string BaseDirectory;
|
||||
static string FileBase;
|
||||
static string FileExt; /* Includes the . character, as in ".nes" */
|
||||
static string FileBaseDirectory;
|
||||
|
||||
void MDFN_SetBaseDirectory(const std::string& dir)
|
||||
{
|
||||
BaseDirectory = string(dir);
|
||||
}
|
||||
|
||||
std::string MDFN_GetBaseDirectory(void)
|
||||
{
|
||||
return BaseDirectory;
|
||||
}
|
||||
|
||||
// Really dumb, maybe we should use boost?
|
||||
static bool IsAbsolutePath(const char *path)
|
||||
{
|
||||
#if PSS_STYLE==4
|
||||
if(path[0] == ':')
|
||||
#elif PSS_STYLE==1
|
||||
if(path[0] == '/')
|
||||
#else
|
||||
if(path[0] == '\\'
|
||||
#if PSS_STYLE!=3
|
||||
|| path[0] == '/'
|
||||
#endif
|
||||
)
|
||||
#endif
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if defined(WIN32) || defined(DOS)
|
||||
if((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'))
|
||||
{
|
||||
if(path[1] == ':')
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
static bool IsAbsolutePath(const std::string &path)
|
||||
{
|
||||
return(IsAbsolutePath(path.c_str()));
|
||||
}
|
||||
|
||||
bool MDFN_IsFIROPSafe(const std::string &path)
|
||||
{
|
||||
//
|
||||
// First, check for any 8-bit characters, and print a warning about portability.
|
||||
//
|
||||
for(size_t x = 0; x < path.size(); x++)
|
||||
{
|
||||
if(path[x] & 0x80)
|
||||
{
|
||||
printf(_("WARNING: Referenced path \"%s\" contains at least one 8-bit non-ASCII character; this may cause portability issues.\n"), path.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We could make this more OS-specific, but it shouldn't hurt to try to weed out usage of characters that are path
|
||||
// separators in one OS but not in another, and we'd also run more of a risk of missing a special path separator case
|
||||
// in some OS.
|
||||
if(!s_settings.untrusted_fip_check)
|
||||
return(true);
|
||||
|
||||
if(path.find('\0') != string::npos)
|
||||
return(false);
|
||||
|
||||
if(path.find(':') != string::npos)
|
||||
return(false);
|
||||
|
||||
if(path.find('\\') != string::npos)
|
||||
return(false);
|
||||
|
||||
if(path.find('/') != string::npos)
|
||||
return(false);
|
||||
|
||||
#if defined(DOS) || defined(WIN32)
|
||||
//
|
||||
// http://support.microsoft.com/kb/74496
|
||||
//
|
||||
{
|
||||
static const char* dev_names[] =
|
||||
{
|
||||
"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM1", "COM2", "COM3", "COM4", "LPT1", "LPT2", "LPT3", NULL
|
||||
};
|
||||
|
||||
for(const char** ls = dev_names; *ls != NULL; ls++)
|
||||
{
|
||||
if(!strcasecmp(*ls, path.c_str()))
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void MDFN_GetFilePathComponents(const std::string &file_path, std::string *dir_path_out, std::string *file_base_out, std::string *file_ext_out)
|
||||
{
|
||||
size_t final_ds; // in file_path
|
||||
string file_name;
|
||||
size_t fn_final_dot; // in local var file_name
|
||||
// Temporary output:
|
||||
string dir_path, file_base, file_ext;
|
||||
|
||||
#if PSS_STYLE==4
|
||||
final_ds = file_path.find_last_of(':');
|
||||
#elif PSS_STYLE==1
|
||||
final_ds = file_path.find_last_of('/');
|
||||
#else
|
||||
final_ds = file_path.find_last_of('\\');
|
||||
|
||||
#if PSS_STYLE!=3
|
||||
{
|
||||
size_t alt_final_ds = file_path.find_last_of('/');
|
||||
|
||||
if(final_ds == string::npos || (alt_final_ds != string::npos && alt_final_ds > final_ds))
|
||||
final_ds = alt_final_ds;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(final_ds == string::npos)
|
||||
{
|
||||
dir_path = string(".");
|
||||
file_name = file_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir_path = file_path.substr(0, final_ds);
|
||||
file_name = file_path.substr(final_ds + 1);
|
||||
}
|
||||
|
||||
fn_final_dot = file_name.find_last_of('.');
|
||||
|
||||
if(fn_final_dot != string::npos)
|
||||
{
|
||||
file_base = file_name.substr(0, fn_final_dot);
|
||||
file_ext = file_name.substr(fn_final_dot);
|
||||
}
|
||||
else
|
||||
{
|
||||
file_base = file_name;
|
||||
file_ext = string("");
|
||||
}
|
||||
|
||||
if(dir_path_out)
|
||||
*dir_path_out = dir_path;
|
||||
|
||||
if(file_base_out)
|
||||
*file_base_out = file_base;
|
||||
|
||||
if(file_ext_out)
|
||||
*file_ext_out = file_ext;
|
||||
}
|
||||
|
||||
std::string MDFN_EvalFIP(const std::string &dir_path, const std::string &rel_path, bool skip_safety_check)
|
||||
{
|
||||
if(!skip_safety_check && !MDFN_IsFIROPSafe(rel_path))
|
||||
throw MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting.\n"), rel_path.c_str());
|
||||
|
||||
if(IsAbsolutePath(rel_path.c_str()))
|
||||
return(rel_path);
|
||||
else
|
||||
{
|
||||
return(dir_path + std::string(PSS) + rel_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef std::map<char, std::string> FSMap;
|
||||
|
||||
static std::string EvalPathFS(const std::string &fstring, /*const (won't work because entry created if char doesn't exist) */ FSMap &fmap)
|
||||
{
|
||||
std::string ret = "";
|
||||
const char *str = fstring.c_str();
|
||||
bool in_spec = false;
|
||||
|
||||
while(*str)
|
||||
{
|
||||
int c = *str;
|
||||
|
||||
if(!in_spec && c == '%')
|
||||
in_spec = true;
|
||||
else if(in_spec == true)
|
||||
{
|
||||
if(c == '%')
|
||||
ret = ret + std::string("%");
|
||||
else
|
||||
ret = ret + fmap[(char)c];
|
||||
in_spec = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
char ct[2];
|
||||
ct[0] = c;
|
||||
ct[1] = 0;
|
||||
ret += std::string(ct);
|
||||
}
|
||||
|
||||
str++;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void CreateMissingDirs(const char *path)
|
||||
{
|
||||
const char *s = path;
|
||||
bool first_psep = true;
|
||||
char last_char = 0;
|
||||
const char char_test1 = '/', char_test2 = '/';
|
||||
|
||||
|
||||
while(*s)
|
||||
{
|
||||
if(*s == char_test1 || *s == char_test2)
|
||||
{
|
||||
if(last_char != *s) //char_test1 && last_char != char_test2)
|
||||
{
|
||||
if(!first_psep)
|
||||
{
|
||||
char tmpbuf[(s - path) + 1];
|
||||
tmpbuf[s - path] = 0;
|
||||
strncpy(tmpbuf, path, s - path);
|
||||
|
||||
puts(tmpbuf);
|
||||
//MDFN_mkdir(tmpbuf, S_IRWXU);
|
||||
}
|
||||
}
|
||||
|
||||
first_psep = false;
|
||||
}
|
||||
last_char = *s;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const char * GetFNComponent(const char *str)
|
||||
{
|
||||
const char *tp1;
|
||||
|
||||
#if PSS_STYLE==4
|
||||
tp1=((char *)strrchr(str,':'));
|
||||
#elif PSS_STYLE==1
|
||||
tp1=((char *)strrchr(str,'/'));
|
||||
#else
|
||||
tp1=((char *)strrchr(str,'\\'));
|
||||
#if PSS_STYLE!=3
|
||||
{
|
||||
const char *tp3;
|
||||
tp3=((char *)strrchr(str,'/'));
|
||||
if(tp1<tp3) tp1=tp3;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(tp1)
|
||||
return(tp1+1);
|
||||
else
|
||||
return(str);
|
||||
}
|
||||
|
||||
void GetFileBase(const char *f)
|
||||
{
|
||||
const char *tp1,*tp3;
|
||||
|
||||
#if PSS_STYLE==4
|
||||
tp1=((char *)strrchr(f,':'));
|
||||
#elif PSS_STYLE==1
|
||||
tp1=((char *)strrchr(f,'/'));
|
||||
#else
|
||||
tp1=((char *)strrchr(f,'\\'));
|
||||
#if PSS_STYLE!=3
|
||||
tp3=((char *)strrchr(f,'/'));
|
||||
if(tp1<tp3) tp1=tp3;
|
||||
#endif
|
||||
#endif
|
||||
if(!tp1)
|
||||
{
|
||||
tp1=f;
|
||||
FileBaseDirectory = ".";
|
||||
}
|
||||
else
|
||||
{
|
||||
char* tmpfn = (char*)alloca(tp1 - f + 1);
|
||||
|
||||
memcpy(tmpfn,f,tp1-f);
|
||||
tmpfn[tp1-f]=0;
|
||||
FileBaseDirectory = string(tmpfn);
|
||||
|
||||
tp1++;
|
||||
}
|
||||
|
||||
if(((tp3=strrchr(f,'.'))!=NULL) && (tp3>tp1))
|
||||
{
|
||||
char* tmpbase = (char*)alloca(tp3 - tp1 + 1);
|
||||
|
||||
memcpy(tmpbase,tp1,tp3-tp1);
|
||||
tmpbase[tp3-tp1]=0;
|
||||
FileBase = string(tmpbase);
|
||||
FileExt = string(tp3);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileBase = string(tp1);
|
||||
FileExt = "";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef _GENERAL_H
|
||||
#define _GENERAL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#if 0
|
||||
class FilePathMaker
|
||||
{
|
||||
|
||||
|
||||
void SetBaseDirectory(const char* path);
|
||||
std::string GetBaseDirectory(void);
|
||||
|
||||
void BuildPath(unsigned type, int id1, const char* cd1);
|
||||
|
||||
static void GetFileBase(
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
void MDFN_SetBaseDirectory(const std::string& dir);
|
||||
std::string MDFN_GetBaseDirectory(void);
|
||||
|
||||
void GetFileBase(const char *f);
|
||||
|
||||
// File-inclusion for-read-only path, for PSF and CUE/TOC sheet usage.
|
||||
bool MDFN_IsFIROPSafe(const std::string &path);
|
||||
|
||||
std::string MDFN_MakeFName(int type, int id1, const char *cd1);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MDFNMKF_STATE = 0,
|
||||
MDFNMKF_SNAP,
|
||||
MDFNMKF_SAV,
|
||||
MDFNMKF_CHEAT,
|
||||
MDFNMKF_PALETTE,
|
||||
MDFNMKF_IPS,
|
||||
MDFNMKF_MOVIE,
|
||||
MDFNMKF_AUX,
|
||||
MDFNMKF_SNAP_DAT,
|
||||
MDFNMKF_CHEAT_TMP,
|
||||
MDFNMKF_FIRMWARE
|
||||
} MakeFName_Type;
|
||||
|
||||
std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1);
|
||||
INLINE std::string MDFN_MakeFName(MakeFName_Type type, int id1, const std::string& cd1) { return MDFN_MakeFName(type, id1, cd1.c_str()); }
|
||||
const char * GetFNComponent(const char *str);
|
||||
|
||||
void MDFN_GetFilePathComponents(const std::string &file_path, std::string *dir_path_out, std::string *file_base_out = NULL, std::string *file_ext_out = NULL);
|
||||
std::string MDFN_EvalFIP(const std::string &dir_path, const std::string &rel_path, bool skip_safety_check = false);
|
||||
#endif
|
|
@ -1,87 +0,0 @@
|
|||
#ifndef __MDFN_MATH_OPS_H
|
||||
#define __MDFN_MATH_OPS_H
|
||||
|
||||
// Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
// Rounds up to the nearest power of 2.
|
||||
static INLINE uint64 round_up_pow2(uint64 v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v |= v >> 32;
|
||||
v++;
|
||||
|
||||
v += (v == 0);
|
||||
|
||||
return(v);
|
||||
}
|
||||
|
||||
static INLINE uint32 uilog2(uint32 v)
|
||||
{
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
|
||||
|
||||
static const uint32 MultiplyDeBruijnBitPosition[32] =
|
||||
{
|
||||
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
||||
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
||||
};
|
||||
|
||||
v |= v >> 1; // first round down to one less than a power of 2
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
|
||||
return MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];
|
||||
}
|
||||
|
||||
// Some compilers' optimizers and some platforms might fubar the generated code from these macros,
|
||||
// so some tests are run in...tests.cpp
|
||||
#define sign_8_to_s16(_value) ((int16)(int8)(_value))
|
||||
#define sign_9_to_s16(_value) (((int16)((unsigned int)(_value) << 7)) >> 7)
|
||||
#define sign_10_to_s16(_value) (((int16)((uint32)(_value) << 6)) >> 6)
|
||||
#define sign_11_to_s16(_value) (((int16)((uint32)(_value) << 5)) >> 5)
|
||||
#define sign_12_to_s16(_value) (((int16)((uint32)(_value) << 4)) >> 4)
|
||||
#define sign_13_to_s16(_value) (((int16)((uint32)(_value) << 3)) >> 3)
|
||||
#define sign_14_to_s16(_value) (((int16)((uint32)(_value) << 2)) >> 2)
|
||||
#define sign_15_to_s16(_value) (((int16)((uint32)(_value) << 1)) >> 1)
|
||||
|
||||
// This obviously won't convert higher-than-32 bit numbers to signed 32-bit ;)
|
||||
// Also, this shouldn't be used for 8-bit and 16-bit signed numbers, since you can
|
||||
// convert those faster with typecasts...
|
||||
#define sign_x_to_s32(_bits, _value) (((int32)((uint32)(_value) << (32 - _bits))) >> (32 - _bits))
|
||||
|
||||
static INLINE int32 clamp_to_u8(int32 i)
|
||||
{
|
||||
if(i & 0xFFFFFF00)
|
||||
i = (((~i) >> 30) & 0xFF);
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
static INLINE int32 clamp_to_u16(int32 i)
|
||||
{
|
||||
if(i & 0xFFFF0000)
|
||||
i = (((~i) >> 31) & 0xFFFF);
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
template<typename T, typename U, typename V> static INLINE void clamp(T *val, U minimum, V maximum)
|
||||
{
|
||||
if(*val < minimum)
|
||||
{
|
||||
//printf("Warning: clamping to minimum(%d)\n", (int)minimum);
|
||||
*val = minimum;
|
||||
}
|
||||
if(*val > maximum)
|
||||
{
|
||||
//printf("Warning: clamping to maximum(%d)\n", (int)maximum);
|
||||
*val = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,560 +0,0 @@
|
|||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Sept 2001: fixed const & error conditions per
|
||||
mods suggested by S. Parent & A. Lillich.
|
||||
June 2002: Tim Dodd added detection and handling of incomplete
|
||||
source sequences, enhanced error detection, added casts
|
||||
to eliminate compiler warnings.
|
||||
July 2003: slight mods to back out aggressive FFFE detection.
|
||||
Jan 2004: updated switches in from-UTF8 conversions.
|
||||
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
|
||||
|
||||
See the header file "ConvertUTF.h" for complete documentation.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "../types.h"
|
||||
#include "ConvertUTF.h"
|
||||
#ifdef CVTUTF_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const int halfShift = 10; /* used for shifting by 10 bits */
|
||||
|
||||
static const UTF32 halfBase = 0x0010000UL;
|
||||
static const UTF32 halfMask = 0x3FFUL;
|
||||
|
||||
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
||||
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
||||
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
||||
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
if (target >= targetEnd) {
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch = *source++;
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_LEGAL_UTF32) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
UTF32 ch, ch2;
|
||||
while (source < sourceEnd) {
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target >= targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
*target++ = ch;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
#ifdef CVTUTF_DEBUG
|
||||
if (result == sourceIllegal) {
|
||||
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||
* get the number of trailing bytes that are supposed to follow it.
|
||||
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
||||
* left as-is for anyone who may want to do such conversion, which was
|
||||
* allowed in earlier algorithms.
|
||||
*/
|
||||
static const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||
* This table contains as many values as there might be trailing bytes
|
||||
* in a UTF-8 sequence.
|
||||
*/
|
||||
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
||||
|
||||
/*
|
||||
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
|
||||
* into the first byte, depending on how many bytes follow. There are
|
||||
* as many entries in this table as there are UTF-8 sequence types.
|
||||
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
|
||||
* for *legal* UTF-8 will be 4 or fewer bytes total.
|
||||
*/
|
||||
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* The interface converts a whole buffer to avoid function-call overhead.
|
||||
* Constants have been gathered. Loops & conditionals have been removed as
|
||||
* much as possible for efficiency, in favor of drop-through switches.
|
||||
* (See "Note A" at the bottom of the file for equivalent code.)
|
||||
* If your compiler supports it, the "isLegalUTF8" call can be turned
|
||||
* into an inline function.
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
UTF32 ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Figure out how many bytes the result will require */
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
||||
* This must be called with the length pre-determined by the first byte.
|
||||
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
||||
* length = trailingBytesForUTF8[*source]+1;
|
||||
* and the sequence is illegal right away if there aren't that many bytes
|
||||
* available.
|
||||
* If presented with a length > 4, this returns false. The Unicode
|
||||
* definition of UTF-8 goes up to 4-byte sequences.
|
||||
*/
|
||||
|
||||
static bool isLegalUTF8(const UTF8 *source, int length) {
|
||||
UTF8 a;
|
||||
const UTF8 *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return false;
|
||||
/* Everything else falls through when "true"... */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
|
||||
|
||||
switch (*source) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return false; break;
|
||||
case 0xED: if (a > 0x9F) return false; break;
|
||||
case 0xF0: if (a < 0x90) return false; break;
|
||||
case 0xF4: if (a > 0x8F) return false; break;
|
||||
default: if (a < 0x80) return false;
|
||||
}
|
||||
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||
}
|
||||
if (*source > 0xF4) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 sequence is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
|
||||
int length = trailingBytesForUTF8[*source]+1;
|
||||
if (source+length > sourceEnd) {
|
||||
return false;
|
||||
}
|
||||
return isLegalUTF8(source, length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_UTF16) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
source -= (extraBytesToRead+1); /* return to the start */
|
||||
break; /* Bail out; shouldn't continue */
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
ch = *source++;
|
||||
if (flags == strictConversion ) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Figure out how many bytes the result will require. Turn any
|
||||
* illegally large UTF32 things (> Plane 17) into replacement chars.
|
||||
*/
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
result = sourceIllegal;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6;
|
||||
case 4: ch += *source++; ch <<= 6;
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up the source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||
/*
|
||||
* UTF-16 surrogate values are illegal in UTF-32, and anything
|
||||
* over Plane 17 (> 0x10FFFF) is illegal.
|
||||
*/
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = ch;
|
||||
}
|
||||
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
|
||||
result = sourceIllegal;
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
UTF32 *MakeUTF32FromUTF8(UTF8 *string)
|
||||
{
|
||||
UTF32 *ret, *tstart;
|
||||
const UTF8 *tstring = string;
|
||||
|
||||
size_t string_length = strlen((char *)string);
|
||||
|
||||
tstart = ret = (UTF32 *)malloc(string_length * sizeof(UTF32) + 1);
|
||||
|
||||
ConvertUTF8toUTF32(&tstring, &string[string_length], &tstart, &tstart[string_length], lenientConversion);
|
||||
|
||||
*tstart = 0;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Note A.
|
||||
The fall-through switches in UTF-8 reading code save a
|
||||
temp variable, some decrements & conditionals. The switches
|
||||
are equivalent to the following loop:
|
||||
{
|
||||
int tmpBytesToRead = extraBytesToRead+1;
|
||||
do {
|
||||
ch += *source++;
|
||||
--tmpBytesToRead;
|
||||
if (tmpBytesToRead) ch <<= 6;
|
||||
} while (tmpBytesToRead > 0);
|
||||
}
|
||||
In UTF-8 writing code, the switches on "bytesToWrite" are
|
||||
similarly unrolled loops.
|
||||
|
||||
--------------------------------------------------------------------- */
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||
|
||||
Several funtions are included here, forming a complete set of
|
||||
conversions between the three formats. UTF-7 is not included
|
||||
here, but is handled in a separate source file.
|
||||
|
||||
Each of these routines takes pointers to input buffers and output
|
||||
buffers. The input buffers are const.
|
||||
|
||||
Each routine converts the text between *sourceStart and sourceEnd,
|
||||
putting the result into the buffer between *targetStart and
|
||||
targetEnd. Note: the end pointers are *after* the last item: e.g.
|
||||
*(sourceEnd - 1) is the last item.
|
||||
|
||||
The return result indicates whether the conversion was successful,
|
||||
and if not, whether the problem was in the source or target buffers.
|
||||
(Only the first encountered problem is indicated.)
|
||||
|
||||
After the conversion, *sourceStart and *targetStart are both
|
||||
updated to point to the end of last text successfully converted in
|
||||
the respective buffers.
|
||||
|
||||
Input parameters:
|
||||
sourceStart - pointer to a pointer to the source buffer.
|
||||
The contents of this are modified on return so that
|
||||
it points at the next thing to be converted.
|
||||
targetStart - similarly, pointer to pointer to the target buffer.
|
||||
sourceEnd, targetEnd - respectively pointers to the ends of the
|
||||
two buffers, for overflow checking only.
|
||||
|
||||
These conversion functions take a ConversionFlags argument. When this
|
||||
flag is set to strict, both irregular sequences and isolated surrogates
|
||||
will cause an error. When the flag is set to lenient, both irregular
|
||||
sequences and isolated surrogates are converted.
|
||||
|
||||
Whether the flag is strict or lenient, all illegal sequences will cause
|
||||
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
|
||||
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
|
||||
must check for illegal sequences.
|
||||
|
||||
When the flag is set to lenient, characters over 0x10FFFF are converted
|
||||
to the replacement character; otherwise (when the flag is set to strict)
|
||||
they constitute an error.
|
||||
|
||||
Output parameters:
|
||||
The value "sourceIllegal" is returned from some routines if the input
|
||||
sequence is malformed. When "sourceIllegal" is returned, the source
|
||||
value will point to the illegal value that caused the problem. E.g.,
|
||||
in UTF-8 when a sequence is malformed, it points to the start of the
|
||||
malformed sequence.
|
||||
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Fixes & updates, Sept 2001.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific.
|
||||
The C standard does not guarantee that wchar_t has at least
|
||||
16 bits, so wchar_t is no less portable than unsigned short!
|
||||
All should be unsigned values to avoid sign extension during
|
||||
bit mask & shift operations.
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
/* Some fundamental constants */
|
||||
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
||||
#define UNI_MAX_BMP (UTF32)0x0000FFFF
|
||||
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
|
||||
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
|
||||
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
|
||||
|
||||
typedef enum {
|
||||
conversionOK, /* conversion successful */
|
||||
sourceExhausted, /* partial character in source, but hit end */
|
||||
targetExhausted, /* insuff. room in target for conversion */
|
||||
sourceIllegal /* source sequence is illegal/malformed */
|
||||
} ConversionResult;
|
||||
|
||||
typedef enum {
|
||||
strictConversion = 0,
|
||||
lenientConversion
|
||||
} ConversionFlags;
|
||||
|
||||
/* This is for C++ and does no harm in C */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
|
||||
/* Extra Mednafen convenience functions. */
|
||||
UTF32 *MakeUTF32FromUTF8(UTF8 *string);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
|
@ -1,2 +0,0 @@
|
|||
mednafen_SOURCES += string/escape.cpp string/trim.cpp string/ConvertUTF.cpp
|
||||
|
|
@ -1,157 +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 "escape.h"
|
||||
|
||||
static unsigned int hex_nibble_to_val(char nibble)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
nibble = tolower(nibble);
|
||||
|
||||
if(nibble >= '0' && nibble <= '9')
|
||||
ret = nibble - '0';
|
||||
else
|
||||
ret = nibble - 'a';
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void unescape_string(char *string)
|
||||
{
|
||||
char *src = string;
|
||||
bool inescape = 0;
|
||||
uint8 hoval = 0;
|
||||
int inhex = 0;
|
||||
int inoctal = 0;
|
||||
|
||||
while(*src)
|
||||
{
|
||||
if(*src == '\\')
|
||||
{
|
||||
inescape = TRUE;
|
||||
inhex = 0;
|
||||
inoctal = 0;
|
||||
}
|
||||
else if(inhex)
|
||||
{
|
||||
if(inhex == 1)
|
||||
{
|
||||
hoval = hex_nibble_to_val(*src) << 4;
|
||||
inhex++;
|
||||
}
|
||||
else if(inhex == 2)
|
||||
{
|
||||
hoval |= hex_nibble_to_val(*src);
|
||||
*string = hoval;
|
||||
string++;
|
||||
hoval = 0;
|
||||
inhex = 0;
|
||||
}
|
||||
}
|
||||
else if(inoctal)
|
||||
{
|
||||
if(inoctal == 1)
|
||||
{
|
||||
hoval = (*src - '0') * 8 * 8;
|
||||
}
|
||||
else if(inoctal == 2)
|
||||
{
|
||||
hoval += (*src - '0') * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
hoval += *src - '0';
|
||||
*string = hoval;
|
||||
string++;
|
||||
hoval = 0;
|
||||
inoctal = 0;
|
||||
}
|
||||
}
|
||||
else if(inescape)
|
||||
{
|
||||
switch(*src)
|
||||
{
|
||||
case 'a': *string = 7; string++; break;
|
||||
case 'b': *string = 8; string++; break;
|
||||
case 'f': *string = 12; string++; break;
|
||||
case 'n': *string = 10; string++; break;
|
||||
case 'r': *string = 13; string++; break;
|
||||
case 't': *string = 9; string++; break;
|
||||
case 'v': *string = 11; string++; break;
|
||||
|
||||
case '\\': *string = '\\'; string++; break;
|
||||
case '?': *string = '?'; string++; break;
|
||||
case '\'': *string = '\''; string++; break;
|
||||
case '"': *string = '"'; string++; break;
|
||||
|
||||
case 'o': inoctal = 1; break;
|
||||
case 'x': inhex = 1; break;
|
||||
|
||||
|
||||
default: *string = *src; string++; break;
|
||||
}
|
||||
inescape = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*string = *src;
|
||||
string++;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*string = 0;
|
||||
}
|
||||
|
||||
char *escape_string(const char *text)
|
||||
{
|
||||
uint32 slen = strlen(text);
|
||||
char *ret = (char*)malloc(slen * 4 + 1); // \xFF
|
||||
char *outoo = ret;
|
||||
|
||||
for(uint32 x = 0; x < slen; x++)
|
||||
{
|
||||
int c = (uint8)text[x];
|
||||
|
||||
if(c < 0x20 || c == 0x7F || c == '\\' || c == '\'' || c == '"')
|
||||
{
|
||||
*outoo++ = '\\';
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case '\\': *outoo++ = '\\'; break;
|
||||
case '\'': *outoo++ = '\''; break;
|
||||
case '"': *outoo++ = '"'; break;
|
||||
case 7: *outoo++ = 'a'; break;
|
||||
case 8: *outoo++ = 'b'; break;
|
||||
case 12: *outoo++ = 'f'; break;
|
||||
case 10: *outoo++ = 'n'; break;
|
||||
case 13: *outoo++ = 'r'; break;
|
||||
case 9: *outoo++ = 't'; break;
|
||||
case 11: *outoo++ = 'v'; break;
|
||||
|
||||
default: outoo += sprintf(outoo, "x%02x", c); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
*outoo++ = c;
|
||||
}
|
||||
|
||||
*outoo = 0;
|
||||
|
||||
return(ret);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef __MDFN_ESCAPE_H
|
||||
#define __MDFN_ESCAPE_H
|
||||
|
||||
// These functions are safe to call before calling MDFNI_Initialize().
|
||||
|
||||
void unescape_string(char *string);
|
||||
char* escape_string(const char *text);
|
||||
|
||||
#endif
|
|
@ -1,147 +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 <string>
|
||||
#include "emuware/emuware.h"
|
||||
#include "trim.h"
|
||||
|
||||
// Remove whitespace from beginning of string
|
||||
void MDFN_ltrim(char *string)
|
||||
{
|
||||
int32 di, si;
|
||||
bool InWhitespace = true;
|
||||
|
||||
di = si = 0;
|
||||
|
||||
while(string[si])
|
||||
{
|
||||
if(InWhitespace && (string[si] == ' ' || string[si] == '\r' || string[si] == '\n' || string[si] == '\t' || string[si] == 0x0b))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
InWhitespace = false;
|
||||
string[di] = string[si];
|
||||
di++;
|
||||
}
|
||||
si++;
|
||||
}
|
||||
string[di] = 0;
|
||||
}
|
||||
|
||||
// Remove whitespace from end of string
|
||||
void MDFN_rtrim(char *string)
|
||||
{
|
||||
int32 len = strlen(string);
|
||||
|
||||
if(len)
|
||||
{
|
||||
for(int32 x = len - 1; x >= 0; x--)
|
||||
{
|
||||
if(string[x] == ' ' || string[x] == '\r' || string[x] == '\n' || string[x] == '\t' || string[x] == 0x0b)
|
||||
string[x] = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MDFN_trim(char *string)
|
||||
{
|
||||
MDFN_rtrim(string);
|
||||
MDFN_ltrim(string);
|
||||
}
|
||||
|
||||
|
||||
// Remove whitespace from beginning of string
|
||||
void MDFN_ltrim(std::string &string)
|
||||
{
|
||||
size_t len = string.length();
|
||||
size_t di, si;
|
||||
bool InWhitespace = true;
|
||||
|
||||
di = si = 0;
|
||||
|
||||
while(si < len)
|
||||
{
|
||||
if(InWhitespace && (string[si] == ' ' || string[si] == '\r' || string[si] == '\n' || string[si] == '\t' || string[si] == 0x0b))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
InWhitespace = false;
|
||||
string[di] = string[si];
|
||||
di++;
|
||||
}
|
||||
si++;
|
||||
}
|
||||
|
||||
string.resize(di);
|
||||
}
|
||||
|
||||
// Remove whitespace from end of string
|
||||
void MDFN_rtrim(std::string &string)
|
||||
{
|
||||
size_t len = string.length();
|
||||
|
||||
if(len)
|
||||
{
|
||||
size_t x = len;
|
||||
size_t new_len = len;
|
||||
|
||||
do
|
||||
{
|
||||
x--;
|
||||
|
||||
if(!(string[x] == ' ' || string[x] == '\r' || string[x] == '\n' || string[x] == '\t' || string[x] == 0x0b))
|
||||
break;
|
||||
|
||||
new_len--;
|
||||
} while(x);
|
||||
|
||||
string.resize(new_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MDFN_trim(std::string &string)
|
||||
{
|
||||
MDFN_rtrim(string);
|
||||
MDFN_ltrim(string);
|
||||
}
|
||||
|
||||
|
||||
char *MDFN_RemoveControlChars(char *str)
|
||||
{
|
||||
char *orig = str;
|
||||
|
||||
if(str)
|
||||
{
|
||||
while(*str)
|
||||
{
|
||||
if((unsigned char)*str < 0x20)
|
||||
*str = 0x20;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
return(orig);
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef __MDFN_STRING_TRIM_H
|
||||
#define __MDFN_STRING_TRIM_H
|
||||
|
||||
void MDFN_ltrim(char *string);
|
||||
void MDFN_rtrim(char *string);
|
||||
void MDFN_trim(char *string);
|
||||
|
||||
void MDFN_ltrim(std::string &string);
|
||||
void MDFN_rtrim(std::string &string);
|
||||
void MDFN_trim(std::string &string);
|
||||
|
||||
char *MDFN_RemoveControlChars(char *str);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,270 +0,0 @@
|
|||
/*************************************************************************
|
||||
*
|
||||
* $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 */
|
|
@ -1,375 +0,0 @@
|
|||
/*************************************************************************
|
||||
*
|
||||
* $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
|
@ -1,183 +0,0 @@
|
|||
/*************************************************************************
|
||||
*
|
||||
* $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 */
|
|
@ -1,496 +0,0 @@
|
|||
/*************************************************************************
|
||||
*
|
||||
* $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
|
@ -1,681 +0,0 @@
|
|||
/*************************************************************************
|
||||
*
|
||||
* $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 */
|
|
@ -1,106 +0,0 @@
|
|||
// TODO/WIP
|
||||
|
||||
/* 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 <sys/stat.h>
|
||||
#include "mednafen.h"
|
||||
#include "Stream.h"
|
||||
#include "FileStream.h"
|
||||
|
||||
#include <trio/trio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
|
||||
FileStream::FileStream(const char *path, const int mode): OpenedMode(mode)
|
||||
{
|
||||
if(!(fp = fopen(path, (mode == FileStream::MODE_WRITE) ? "wb" : "rb")))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file %s"), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
FileStream::~FileStream()
|
||||
{
|
||||
}
|
||||
|
||||
uint64 FileStream::attributes(void)
|
||||
{
|
||||
uint64 ret = ATTRIBUTE_SEEKABLE;
|
||||
|
||||
switch(OpenedMode)
|
||||
{
|
||||
case FileStream::MODE_READ:
|
||||
ret |= ATTRIBUTE_READABLE;
|
||||
break;
|
||||
case FileStream::MODE_WRITE_SAFE:
|
||||
case FileStream::MODE_WRITE:
|
||||
ret |= ATTRIBUTE_WRITEABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64 FileStream::read(void *data, uint64 count, bool error_on_eos)
|
||||
{
|
||||
return fread(data, 1, count, fp);
|
||||
}
|
||||
|
||||
void FileStream::write(const void *data, uint64 count)
|
||||
{
|
||||
fwrite(data, 1, count, fp);
|
||||
}
|
||||
|
||||
void FileStream::seek(int64 offset, int whence)
|
||||
{
|
||||
fseeko(fp, offset, whence);
|
||||
}
|
||||
|
||||
int64 FileStream::tell(void)
|
||||
{
|
||||
return ftello(fp);
|
||||
}
|
||||
|
||||
int64 FileStream::size(void) {
|
||||
struct stat buf;
|
||||
|
||||
fstat(fileno(fp), &buf);
|
||||
|
||||
return(buf.st_size);
|
||||
}
|
||||
|
||||
void FileStream::close(void)
|
||||
{
|
||||
if(!fp)
|
||||
return;
|
||||
|
||||
FILE *tmp = fp;
|
||||
fp = NULL;
|
||||
fclose(tmp);
|
||||
}
|
|
@ -1,56 +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
|
||||
*/
|
||||
|
||||
// TODO/WIP
|
||||
|
||||
#ifndef __MDFN_FILESTREAM_H
|
||||
#define __MDFN_FILESTREAM_H
|
||||
|
||||
#include "Stream.h"
|
||||
#include "FileWrapper.h"
|
||||
|
||||
class FileStream : public Stream
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
MODE_READ = FileWrapper::MODE_READ,
|
||||
MODE_WRITE = FileWrapper::MODE_WRITE,
|
||||
MODE_WRITE_SAFE = FileWrapper::MODE_WRITE_SAFE,
|
||||
};
|
||||
|
||||
FileStream(const char *path, const int mode);
|
||||
virtual ~FileStream();
|
||||
|
||||
virtual uint64 attributes(void);
|
||||
|
||||
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
|
||||
virtual void write(const void *data, uint64 count);
|
||||
virtual void seek(int64 offset, int whence);
|
||||
virtual int64 tell(void);
|
||||
virtual int64 size(void);
|
||||
virtual void close(void);
|
||||
|
||||
private:
|
||||
FILE *fp;
|
||||
const int OpenedMode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,135 +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 <sys/stat.h>
|
||||
#include "mednafen.h"
|
||||
#include "FileWrapper.h"
|
||||
|
||||
#include <trio/trio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Some really bad preprocessor abuse follows to handle platforms that don't have fseeko and ftello...and of course
|
||||
// for largefile support on Windows:
|
||||
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
|
||||
// For special uses, IE in classes that take a path or a FileWrapper & in the constructor, and the FileWrapper non-pointer member
|
||||
// is in the initialization list for the path constructor but not the constructor with FileWrapper&
|
||||
|
||||
FileWrapper::FileWrapper(const char *path, const int mode, const char *purpose) : OpenedMode(mode)
|
||||
{
|
||||
if(!(fp = fopen(path, (mode == MODE_WRITE) ? "wb" : "rb")))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
|
||||
throw(MDFN_Error(ene.Errno(), _("Error opening file %s"), ene.StrError()));
|
||||
}
|
||||
}
|
||||
|
||||
FileWrapper::~FileWrapper()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void FileWrapper::close(void)
|
||||
{
|
||||
if(!fp)
|
||||
return;
|
||||
|
||||
FILE *tmp = fp;
|
||||
fp = NULL;
|
||||
fclose(tmp);
|
||||
}
|
||||
|
||||
uint64 FileWrapper::read(void *data, uint64 count, bool error_on_eof)
|
||||
{
|
||||
return fread(data, 1, count, fp);
|
||||
}
|
||||
|
||||
void FileWrapper::flush(void)
|
||||
{
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void FileWrapper::write(const void *data, uint64 count)
|
||||
{
|
||||
fwrite(data, 1, count, fp);
|
||||
}
|
||||
|
||||
int FileWrapper::scanf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
ret = trio_vfscanf(fp, format, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FileWrapper::put_char(int c)
|
||||
{
|
||||
fputc(c, fp);
|
||||
}
|
||||
|
||||
void FileWrapper::put_string(const char *str)
|
||||
{
|
||||
write(str, strlen(str));
|
||||
}
|
||||
|
||||
// We need to decide whether to prohibit NULL characters in output and input strings via std::string.
|
||||
// Yes for correctness, no for potential security issues(though unlikely in context all things considered).
|
||||
void FileWrapper::put_string(const std::string &str)
|
||||
{
|
||||
write(str.data(), str.size());
|
||||
}
|
||||
|
||||
char *FileWrapper::get_line(char *buf_s, int buf_size)
|
||||
{
|
||||
return ::fgets(buf_s, buf_size, fp);
|
||||
}
|
||||
|
||||
|
||||
void FileWrapper::seek(int64 offset, int whence)
|
||||
{
|
||||
fseeko(fp, offset, whence);
|
||||
}
|
||||
|
||||
int64 FileWrapper::size(void)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
fstat(fileno(fp), &buf);
|
||||
|
||||
return(buf.st_size);
|
||||
}
|
||||
|
||||
int64 FileWrapper::tell(void)
|
||||
{
|
||||
return ftello(fp);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef __MDFN_FILEWRAPPER_H
|
||||
#define __MDFN_FILEWRAPPER_H
|
||||
|
||||
// A stdio FILE wrapper(with some BSD and POSIXisms, and a little dash of Win32, thrown in for special behaviors)
|
||||
class FileWrapper
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
MODE_READ = 0,
|
||||
MODE_WRITE,
|
||||
MODE_WRITE_SAFE // Will throw an exception instead of overwriting an existing file.
|
||||
};
|
||||
|
||||
FileWrapper(const char *path, const int mode, const char *purpose = NULL);
|
||||
~FileWrapper();
|
||||
|
||||
uint64 read(void *data, uint64 count, bool error_on_eof = true);
|
||||
|
||||
void write(const void *data, uint64 count);
|
||||
|
||||
int scanf(const char *format, ...) MDFN_FORMATSTR(scanf, 2, 3);
|
||||
|
||||
void put_char(int c);
|
||||
|
||||
void put_string(const char *str);
|
||||
void put_string(const std::string &str);
|
||||
|
||||
char *get_line(char *s, int size); // Same semantics as fgets(), for now
|
||||
|
||||
void seek(int64 offset, int whence);
|
||||
|
||||
int64 tell(void);
|
||||
|
||||
int64 size(void);
|
||||
|
||||
void flush(void);
|
||||
|
||||
void close(void); // Flushes and closes the underlying OS/C lib file. Calling any other method of this class after a call to
|
||||
// this method is illegal(except for the implicit call to the destructor).
|
||||
//
|
||||
// This is necessary since there can be errors when closing a file, and we can't safely throw an
|
||||
// exception from the destructor.
|
||||
//
|
||||
// Manually calling this method isn't strictly necessary, it'll be called from the destructor
|
||||
// automatically, but calling is strongly recommended when the file is opened for writing.
|
||||
private:
|
||||
|
||||
FileWrapper & operator=(const FileWrapper &); // Assignment operator
|
||||
FileWrapper(const FileWrapper &); // Copy constructor
|
||||
|
||||
FILE *fp;
|
||||
const int OpenedMode;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,112 +0,0 @@
|
|||
// TODO/WIP
|
||||
|
||||
/* 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 "octoshock.h"
|
||||
#include "Stream.h"
|
||||
|
||||
//#include <trio/trio.h>
|
||||
|
||||
Stream::Stream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Stream::~Stream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Stream::put_line(const std::string& str)
|
||||
{
|
||||
char l = '\n';
|
||||
|
||||
write(&str[0], str.size());
|
||||
write(&l, sizeof(l));
|
||||
}
|
||||
|
||||
|
||||
void Stream::print_format(const char *format, ...)
|
||||
{
|
||||
//char *str = NULL;
|
||||
//int rc;
|
||||
|
||||
//va_list ap;
|
||||
|
||||
//va_start(ap, format);
|
||||
|
||||
//rc = trio_vasprintf(&str, format, ap);
|
||||
|
||||
//va_end(ap);
|
||||
|
||||
//if(rc < 0)
|
||||
// throw MDFN_Error(0, "Error in trio_vasprintf()");
|
||||
//else
|
||||
//{
|
||||
// try // Bleck
|
||||
// {
|
||||
// write(str, rc);
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// free(str);
|
||||
// throw;
|
||||
// }
|
||||
// free(str);
|
||||
//}
|
||||
}
|
||||
|
||||
int Stream::get_line(std::string &str)
|
||||
{
|
||||
uint8 c;
|
||||
|
||||
str.clear(); // or str.resize(0)??
|
||||
|
||||
while(read(&c, sizeof(c), false) > 0)
|
||||
{
|
||||
if(c == '\r' || c == '\n' || c == 0)
|
||||
return(c);
|
||||
|
||||
str.push_back(c);
|
||||
}
|
||||
|
||||
return(str.length() ? 256 : -1);
|
||||
}
|
||||
|
||||
StreamFilter::StreamFilter()
|
||||
{
|
||||
target_stream = NULL;
|
||||
}
|
||||
|
||||
StreamFilter::StreamFilter(Stream *target_arg)
|
||||
{
|
||||
target_stream = target_arg;
|
||||
}
|
||||
|
||||
StreamFilter::~StreamFilter()
|
||||
{
|
||||
if(target_stream)
|
||||
delete target_stream;
|
||||
}
|
||||
|
||||
Stream* StreamFilter::steal(void)
|
||||
{
|
||||
Stream *ret = target_stream;
|
||||
target_stream = NULL;
|
||||
return ret;
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
#ifndef __MDFN_STREAM_H
|
||||
#define __MDFN_STREAM_H
|
||||
|
||||
// TODO/WIP
|
||||
|
||||
// TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument.
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h> // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT.
|
||||
#include <string>
|
||||
|
||||
#include "octoshock.h"
|
||||
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
|
||||
Stream();
|
||||
virtual ~Stream();
|
||||
|
||||
enum
|
||||
{
|
||||
ATTRIBUTE_READABLE = 1U << 0,
|
||||
ATTRIBUTE_WRITEABLE = 1U << 1,
|
||||
ATTRIBUTE_SEEKABLE = 1U << 2,
|
||||
ATTRIBUTE_SLOW_SEEK = 1U << 3,
|
||||
ATTRIBUTE_SLOW_SIZE = 1U << 4
|
||||
};
|
||||
virtual uint64 attributes(void) = 0;
|
||||
|
||||
virtual uint8 *map(void) = 0; // Map the entirety of the stream data into the address space of the process, if possible, and return a pointer.
|
||||
// (the returned pointer must be cached, and returned on any subsequent calls to map() without an unmap()
|
||||
// in-between, to facilitate a sort of "feature-testing", to determine if an alternative like "MemoryStream"
|
||||
// should be used).
|
||||
//
|
||||
// If the mapping fails for whatever reason, return NULL rather than throwing an exception.
|
||||
//
|
||||
|
||||
virtual void unmap(void) = 0; // Unmap the stream data from the address space. (Possibly invalidating the pointer returned from map()).
|
||||
// (must automatically be called, if necessary, from the destructor).
|
||||
//
|
||||
// If the data can't be "unmapped" as such because it was never mmap()'d or similar in the first place(such as with MemoryStream),
|
||||
// then this will be a nop.
|
||||
|
||||
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;
|
||||
virtual void write(const void *data, uint64 count) = 0;
|
||||
|
||||
virtual void seek(int64 offset, int whence = SEEK_SET) = 0;
|
||||
inline void rewind(void)
|
||||
{
|
||||
seek(0, SEEK_SET);
|
||||
}
|
||||
virtual int64 tell(void) = 0;
|
||||
virtual int64 size(void) = 0;
|
||||
virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream.
|
||||
// Necessary since this operation can fail(running out of disk space, for instance),
|
||||
// and throw an exception in the destructor would be a Bad Idea(TM).
|
||||
//
|
||||
// Manually calling this function isn't strictly necessary, but recommended when the
|
||||
// stream is writeable; it will be called automatically from the destructor, with any
|
||||
// exceptions thrown caught and logged.
|
||||
|
||||
//
|
||||
// Utility functions(TODO):
|
||||
//
|
||||
INLINE uint8 get_u8(void)
|
||||
{
|
||||
uint8 ret;
|
||||
|
||||
read(&ret, sizeof(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
INLINE void put_u8(uint8 c)
|
||||
{
|
||||
write(&c, sizeof(c));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_NE(void)
|
||||
{
|
||||
T ret;
|
||||
|
||||
read(&ret, sizeof(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_NE(T c)
|
||||
{
|
||||
write(&c, sizeof(c));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_RE(void)
|
||||
{
|
||||
uint8 tmp[sizeof(T)];
|
||||
T ret = 0;
|
||||
|
||||
read(tmp, sizeof(tmp));
|
||||
|
||||
for(unsigned i = 0; i < sizeof(T); i++)
|
||||
ret |= (T)tmp[i] << (i * 8);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_RE(T c)
|
||||
{
|
||||
uint8 tmp[sizeof(T)];
|
||||
|
||||
for(unsigned i = 0; i < sizeof(T); i++)
|
||||
tmp[i] = ((uint8 *)&c)[sizeof(T) - 1 - i];
|
||||
|
||||
write(tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_LE(void)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
return get_NE<T>();
|
||||
#else
|
||||
return get_RE<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_LE(T c)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
return put_NE<T>(c);
|
||||
#else
|
||||
return put_RE<T>(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE T get_BE(void)
|
||||
{
|
||||
#ifndef LSB_FIRST
|
||||
return get_NE<T>();
|
||||
#else
|
||||
return get_RE<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void put_BE(T c)
|
||||
{
|
||||
#ifndef LSB_FIRST
|
||||
return put_NE<T>(c);
|
||||
#else
|
||||
return put_RE<T>(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or 256 on EOF and
|
||||
// data has been read into "str", and -1 on EOF when no data has been read into "str".
|
||||
// The line-end char won't be added to "str".
|
||||
// It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n).
|
||||
// ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part
|
||||
// of it would be up to the STL implementation).
|
||||
// Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream)
|
||||
virtual int get_line(std::string &str);
|
||||
|
||||
virtual void put_line(const std::string& str);
|
||||
|
||||
virtual void print_format(const char *format, ...);
|
||||
|
||||
#if 0
|
||||
int scanf(const char *format, ...) MDFN_FORMATSTR(gnu_scanf, 2, 3);
|
||||
void put_string(const char *str);
|
||||
void put_string(const std::string &str);
|
||||
#endif
|
||||
};
|
||||
|
||||
// StreamFilter takes ownership of the Stream pointer passed, and will delete it in its destructor.
|
||||
class StreamFilter : public Stream
|
||||
{
|
||||
public:
|
||||
|
||||
StreamFilter();
|
||||
StreamFilter(Stream *target_arg);
|
||||
virtual ~StreamFilter();
|
||||
|
||||
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;
|
||||
virtual void write(const void *data, uint64 count) = 0;
|
||||
virtual void seek(int64 offset, int whence) = 0;
|
||||
virtual int64 tell(void) = 0;
|
||||
virtual int64 size(void) = 0;
|
||||
virtual void close(void) = 0;
|
||||
|
||||
virtual Stream *steal(void);
|
||||
|
||||
private:
|
||||
Stream *target_stream;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.33627.172
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "octoshock", "octoshock.vcxproj", "{8610A02C-7420-4237-89D3-31BBC9A459AD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniclient", "..\test\miniclient\miniclient.vcxproj", "{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8610A02C-7420-4237-89D3-31BBC9A459AD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8610A02C-7420-4237-89D3-31BBC9A459AD}.Debug|x64.Build.0 = Debug|x64
|
||||
{8610A02C-7420-4237-89D3-31BBC9A459AD}.Release|x64.ActiveCfg = Release|x64
|
||||
{8610A02C-7420-4237-89D3-31BBC9A459AD}.Release|x64.Build.0 = Release|x64
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Debug|x64.Build.0 = Debug|x64
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Release|x64.ActiveCfg = Release|x64
|
||||
{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6A43C902-0FB5-4B9E-8E9F-D2417DCDFA5B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,169 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{8610A02C-7420-4237-89D3-31BBC9A459AD}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>EW_EXPORT;WANT_LEC_CHECK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)..\..\..\Assets\dll\$(TargetName).dll"
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)..\..\..\output\dll\$(TargetName).dll"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>EW_EXPORT;WANT_LEC_CHECK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)..\..\..\Assets\dll\$(TargetName).dll"
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)..\..\..\output\dll\$(TargetName).dll"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\cdrom\CDUtility.cpp" />
|
||||
<ClCompile Include="..\cdrom\crc32.cpp" />
|
||||
<ClCompile Include="..\cdrom\galois.cpp" />
|
||||
<ClCompile Include="..\cdrom\l-ec.cpp" />
|
||||
<ClCompile Include="..\cdrom\lec.cpp" />
|
||||
<ClCompile Include="..\cdrom\recover-raw.cpp" />
|
||||
<ClCompile Include="..\emuware\emuware.cpp" />
|
||||
<ClCompile Include="..\emuware\EW_state.cpp" />
|
||||
<ClCompile Include="..\endian.cpp" />
|
||||
<ClCompile Include="..\error.cpp" />
|
||||
<ClCompile Include="..\octoshock.cpp" />
|
||||
<ClCompile Include="..\psx\cdc.cpp" />
|
||||
<ClCompile Include="..\psx\cpu.cpp" />
|
||||
<ClCompile Include="..\psx\dis.cpp" />
|
||||
<ClCompile Include="..\psx\dma.cpp" />
|
||||
<ClCompile Include="..\psx\frontio.cpp" />
|
||||
<ClCompile Include="..\psx\gpu.cpp" />
|
||||
<ClCompile Include="..\psx\gpu_line.cpp" />
|
||||
<ClCompile Include="..\psx\gpu_polygon.cpp" />
|
||||
<ClCompile Include="..\psx\gpu_sprite.cpp" />
|
||||
<ClCompile Include="..\psx\gte.cpp" />
|
||||
<ClCompile Include="..\psx\input\dualanalog.cpp" />
|
||||
<ClCompile Include="..\psx\input\dualshock.cpp" />
|
||||
<ClCompile Include="..\psx\input\gamepad.cpp" />
|
||||
<ClCompile Include="..\psx\input\guncon.cpp" />
|
||||
<ClCompile Include="..\psx\input\justifier.cpp" />
|
||||
<ClCompile Include="..\psx\input\memcard.cpp" />
|
||||
<ClCompile Include="..\psx\input\mouse.cpp" />
|
||||
<ClCompile Include="..\psx\input\multitap.cpp" />
|
||||
<ClCompile Include="..\psx\input\negcon.cpp" />
|
||||
<ClCompile Include="..\psx\irq.cpp" />
|
||||
<ClCompile Include="..\psx\mdec.cpp" />
|
||||
<ClCompile Include="..\psx\psx.cpp" />
|
||||
<ClCompile Include="..\psx\sio.cpp" />
|
||||
<ClCompile Include="..\psx\spu.cpp" />
|
||||
<ClCompile Include="..\psx\timer.cpp" />
|
||||
<ClCompile Include="..\Stream.cpp" />
|
||||
<ClCompile Include="..\tests.cpp" />
|
||||
<ClCompile Include="..\video\convert.cpp" />
|
||||
<ClCompile Include="..\video\Deinterlacer.cpp" />
|
||||
<ClCompile Include="..\video\surface.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\cdrom\CDUtility.h" />
|
||||
<ClInclude Include="..\cdrom\dvdisaster.h" />
|
||||
<ClInclude Include="..\cdrom\galois-inlines.h" />
|
||||
<ClInclude Include="..\cdrom\lec.h" />
|
||||
<ClInclude Include="..\cdrom\SimpleFIFO.h" />
|
||||
<ClInclude Include="..\emuware\emuware.h" />
|
||||
<ClInclude Include="..\emuware\EW_state.h" />
|
||||
<ClInclude Include="..\emuware\msvc\inttypes.h" />
|
||||
<ClInclude Include="..\emuware\msvc\stdint.h" />
|
||||
<ClInclude Include="..\endian.h" />
|
||||
<ClInclude Include="..\error.h" />
|
||||
<ClInclude Include="..\git.h" />
|
||||
<ClInclude Include="..\math_ops.h" />
|
||||
<ClInclude Include="..\octoshock.h" />
|
||||
<ClInclude Include="..\psx\cdc.h" />
|
||||
<ClInclude Include="..\psx\cpu.h" />
|
||||
<ClInclude Include="..\psx\debug.h" />
|
||||
<ClInclude Include="..\psx\dis.h" />
|
||||
<ClInclude Include="..\psx\dma.h" />
|
||||
<ClInclude Include="..\psx\FastFIFO.h" />
|
||||
<ClInclude Include="..\psx\frontio.h" />
|
||||
<ClInclude Include="..\psx\gpu.h" />
|
||||
<ClInclude Include="..\psx\gte.h" />
|
||||
<ClInclude Include="..\psx\input\dualanalog.h" />
|
||||
<ClInclude Include="..\psx\input\dualshock.h" />
|
||||
<ClInclude Include="..\psx\input\gamepad.h" />
|
||||
<ClInclude Include="..\psx\input\guncon.h" />
|
||||
<ClInclude Include="..\psx\input\justifier.h" />
|
||||
<ClInclude Include="..\psx\input\memcard.h" />
|
||||
<ClInclude Include="..\psx\input\mouse.h" />
|
||||
<ClInclude Include="..\psx\input\multitap.h" />
|
||||
<ClInclude Include="..\psx\input\negcon.h" />
|
||||
<ClInclude Include="..\psx\irq.h" />
|
||||
<ClInclude Include="..\psx\masmem.h" />
|
||||
<ClInclude Include="..\psx\mdec.h" />
|
||||
<ClInclude Include="..\psx\psx.h" />
|
||||
<ClInclude Include="..\psx\sio.h" />
|
||||
<ClInclude Include="..\psx\spu.h" />
|
||||
<ClInclude Include="..\psx\timer.h" />
|
||||
<ClInclude Include="..\Stream.h" />
|
||||
<ClInclude Include="..\tests.h" />
|
||||
<ClInclude Include="..\video.h" />
|
||||
<ClInclude Include="..\video\convert.h" />
|
||||
<ClInclude Include="..\video\Deinterlacer.h" />
|
||||
<ClInclude Include="..\video\surface.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\psx\gpu_common.inc" />
|
||||
<None Include="..\psx\spu_fir_table.inc" />
|
||||
<None Include="..\psx\spu_reverb.inc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,269 +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="..\video\convert.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>
|
||||
<ClCompile Include="..\tests.cpp" />
|
||||
<ClCompile Include="..\cdrom\lec.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\l-ec.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\recover-raw.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\galois.cpp">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\cdrom\crc32.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="..\video\convert.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>
|
||||
<ClInclude Include="..\cdrom\dvdisaster.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\galois-inlines.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\cdrom\lec.h">
|
||||
<Filter>cdrom</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\psx\debug.h">
|
||||
<Filter>psx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\psx\FastFIFO.h">
|
||||
<Filter>psx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\tests.h" />
|
||||
<ClInclude Include="..\video.h" />
|
||||
</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_common.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,629 +0,0 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
9E11BE571A41204F00CC7F6B /* CDUtility.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDEB1A41204F00CC7F6B /* CDUtility.cpp */; };
|
||||
9E11BE581A41204F00CC7F6B /* CDUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BDEC1A41204F00CC7F6B /* CDUtility.h */; };
|
||||
9E11BE591A41204F00CC7F6B /* crc32.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDED1A41204F00CC7F6B /* crc32.cpp */; };
|
||||
9E11BE5C1A41204F00CC7F6B /* galois.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDF01A41204F00CC7F6B /* galois.cpp */; };
|
||||
9E11BE5D1A41204F00CC7F6B /* l-ec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDF11A41204F00CC7F6B /* l-ec.cpp */; };
|
||||
9E11BE5E1A41204F00CC7F6B /* lec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDF21A41204F00CC7F6B /* lec.cpp */; };
|
||||
9E11BE5F1A41204F00CC7F6B /* lec.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BDF31A41204F00CC7F6B /* lec.h */; };
|
||||
9E11BE601A41204F00CC7F6B /* recover-raw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDF41A41204F00CC7F6B /* recover-raw.cpp */; };
|
||||
9E11BE631A41204F00CC7F6B /* emuware.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDF81A41204F00CC7F6B /* emuware.cpp */; };
|
||||
9E11BE641A41204F00CC7F6B /* emuware.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BDF91A41204F00CC7F6B /* emuware.h */; };
|
||||
9E11BE651A41204F00CC7F6B /* EW_state.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BDFA1A41204F00CC7F6B /* EW_state.cpp */; };
|
||||
9E11BE661A41204F00CC7F6B /* EW_state.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BDFB1A41204F00CC7F6B /* EW_state.h */; };
|
||||
9E11BE691A41204F00CC7F6B /* PACKED.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE001A41204F00CC7F6B /* PACKED.h */; };
|
||||
9E11BE6A1A41204F00CC7F6B /* PACKED_END.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE011A41204F00CC7F6B /* PACKED_END.h */; };
|
||||
9E11BE6B1A41204F00CC7F6B /* endian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE021A41204F00CC7F6B /* endian.cpp */; };
|
||||
9E11BE6C1A41204F00CC7F6B /* endian.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE031A41204F00CC7F6B /* endian.h */; };
|
||||
9E11BE6D1A41204F00CC7F6B /* error.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE041A41204F00CC7F6B /* error.h */; };
|
||||
9E11BE741A41204F00CC7F6B /* git.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE0B1A41204F00CC7F6B /* git.h */; };
|
||||
9E11BE751A41204F00CC7F6B /* math_ops.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE0C1A41204F00CC7F6B /* math_ops.h */; };
|
||||
9E11BE761A41204F00CC7F6B /* octoshock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE0D1A41204F00CC7F6B /* octoshock.cpp */; };
|
||||
9E11BE771A41204F00CC7F6B /* octoshock.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE0E1A41204F00CC7F6B /* octoshock.h */; };
|
||||
9E11BE781A41204F00CC7F6B /* cdc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE101A41204F00CC7F6B /* cdc.cpp */; };
|
||||
9E11BE791A41204F00CC7F6B /* cdc.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE111A41204F00CC7F6B /* cdc.h */; };
|
||||
9E11BE7A1A41204F00CC7F6B /* cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE121A41204F00CC7F6B /* cpu.cpp */; };
|
||||
9E11BE7B1A41204F00CC7F6B /* cpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE131A41204F00CC7F6B /* cpu.h */; };
|
||||
9E11BE7C1A41204F00CC7F6B /* cpu_bigswitch.inc in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE141A41204F00CC7F6B /* cpu_bigswitch.inc */; };
|
||||
9E11BE7D1A41204F00CC7F6B /* cpu_computedgoto.inc in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE151A41204F00CC7F6B /* cpu_computedgoto.inc */; };
|
||||
9E11BE801A41204F00CC7F6B /* dis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE181A41204F00CC7F6B /* dis.cpp */; };
|
||||
9E11BE811A41204F00CC7F6B /* dis.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE191A41204F00CC7F6B /* dis.h */; };
|
||||
9E11BE821A41204F00CC7F6B /* dma.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE1A1A41204F00CC7F6B /* dma.cpp */; };
|
||||
9E11BE831A41204F00CC7F6B /* dma.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE1B1A41204F00CC7F6B /* dma.h */; };
|
||||
9E11BE841A41204F00CC7F6B /* frontio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE1C1A41204F00CC7F6B /* frontio.cpp */; };
|
||||
9E11BE851A41204F00CC7F6B /* frontio.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE1D1A41204F00CC7F6B /* frontio.h */; };
|
||||
9E11BE861A41204F00CC7F6B /* gpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE1E1A41204F00CC7F6B /* gpu.cpp */; };
|
||||
9E11BE871A41204F00CC7F6B /* gpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE1F1A41204F00CC7F6B /* gpu.h */; };
|
||||
9E11BE881A41204F00CC7F6B /* gpu_common.inc in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE201A41204F00CC7F6B /* gpu_common.inc */; };
|
||||
9E11BE891A41204F00CC7F6B /* gpu_line.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE211A41204F00CC7F6B /* gpu_line.cpp */; };
|
||||
9E11BE8A1A41204F00CC7F6B /* gpu_polygon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE221A41204F00CC7F6B /* gpu_polygon.cpp */; };
|
||||
9E11BE8B1A41204F00CC7F6B /* gpu_sprite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE231A41204F00CC7F6B /* gpu_sprite.cpp */; };
|
||||
9E11BE8C1A41204F00CC7F6B /* gte.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE241A41204F00CC7F6B /* gte.cpp */; };
|
||||
9E11BE8D1A41204F00CC7F6B /* gte.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE251A41204F00CC7F6B /* gte.h */; };
|
||||
9E11BE8E1A41204F00CC7F6B /* dualanalog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE271A41204F00CC7F6B /* dualanalog.cpp */; };
|
||||
9E11BE8F1A41204F00CC7F6B /* dualanalog.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE281A41204F00CC7F6B /* dualanalog.h */; };
|
||||
9E11BE901A41204F00CC7F6B /* dualshock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE291A41204F00CC7F6B /* dualshock.cpp */; };
|
||||
9E11BE911A41204F00CC7F6B /* dualshock.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE2A1A41204F00CC7F6B /* dualshock.h */; };
|
||||
9E11BE921A41204F00CC7F6B /* gamepad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE2B1A41204F00CC7F6B /* gamepad.cpp */; };
|
||||
9E11BE931A41204F00CC7F6B /* gamepad.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE2C1A41204F00CC7F6B /* gamepad.h */; };
|
||||
9E11BE941A41204F00CC7F6B /* guncon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE2D1A41204F00CC7F6B /* guncon.cpp */; };
|
||||
9E11BE951A41204F00CC7F6B /* guncon.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE2E1A41204F00CC7F6B /* guncon.h */; };
|
||||
9E11BE961A41204F00CC7F6B /* justifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE2F1A41204F00CC7F6B /* justifier.cpp */; };
|
||||
9E11BE971A41204F00CC7F6B /* justifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE301A41204F00CC7F6B /* justifier.h */; };
|
||||
9E11BE981A41204F00CC7F6B /* memcard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE311A41204F00CC7F6B /* memcard.cpp */; };
|
||||
9E11BE991A41204F00CC7F6B /* memcard.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE321A41204F00CC7F6B /* memcard.h */; };
|
||||
9E11BE9A1A41204F00CC7F6B /* mouse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE331A41204F00CC7F6B /* mouse.cpp */; };
|
||||
9E11BE9B1A41204F00CC7F6B /* mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE341A41204F00CC7F6B /* mouse.h */; };
|
||||
9E11BE9C1A41204F00CC7F6B /* multitap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE351A41204F00CC7F6B /* multitap.cpp */; };
|
||||
9E11BE9D1A41204F00CC7F6B /* multitap.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE361A41204F00CC7F6B /* multitap.h */; };
|
||||
9E11BE9E1A41204F00CC7F6B /* negcon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE371A41204F00CC7F6B /* negcon.cpp */; };
|
||||
9E11BE9F1A41204F00CC7F6B /* negcon.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE381A41204F00CC7F6B /* negcon.h */; };
|
||||
9E11BEA01A41204F00CC7F6B /* irq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE391A41204F00CC7F6B /* irq.cpp */; };
|
||||
9E11BEA11A41204F00CC7F6B /* irq.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE3A1A41204F00CC7F6B /* irq.h */; };
|
||||
9E11BEA21A41204F00CC7F6B /* masmem.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE3D1A41204F00CC7F6B /* masmem.h */; };
|
||||
9E11BEA31A41204F00CC7F6B /* mdec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE3E1A41204F00CC7F6B /* mdec.cpp */; };
|
||||
9E11BEA41A41204F00CC7F6B /* mdec.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE3F1A41204F00CC7F6B /* mdec.h */; };
|
||||
9E11BEA51A41204F00CC7F6B /* psx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE401A41204F00CC7F6B /* psx.cpp */; };
|
||||
9E11BEA61A41204F00CC7F6B /* psx.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE411A41204F00CC7F6B /* psx.h */; };
|
||||
9E11BEA71A41204F00CC7F6B /* sio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE421A41204F00CC7F6B /* sio.cpp */; };
|
||||
9E11BEA81A41204F00CC7F6B /* sio.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE431A41204F00CC7F6B /* sio.h */; };
|
||||
9E11BEA91A41204F00CC7F6B /* spu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE441A41204F00CC7F6B /* spu.cpp */; };
|
||||
9E11BEAA1A41204F00CC7F6B /* spu.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE451A41204F00CC7F6B /* spu.h */; };
|
||||
9E11BEAB1A41204F00CC7F6B /* spu_fir_table.inc in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE461A41204F00CC7F6B /* spu_fir_table.inc */; };
|
||||
9E11BEAC1A41204F00CC7F6B /* spu_reverb.inc in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE471A41204F00CC7F6B /* spu_reverb.inc */; };
|
||||
9E11BEAD1A41204F00CC7F6B /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE481A41204F00CC7F6B /* timer.cpp */; };
|
||||
9E11BEAE1A41204F00CC7F6B /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE491A41204F00CC7F6B /* timer.h */; };
|
||||
9E11BEAF1A41204F00CC7F6B /* Stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE4A1A41204F00CC7F6B /* Stream.cpp */; };
|
||||
9E11BEB01A41204F00CC7F6B /* Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE4B1A41204F00CC7F6B /* Stream.h */; };
|
||||
9E11BEB11A41204F00CC7F6B /* Deinterlacer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE4D1A41204F00CC7F6B /* Deinterlacer.cpp */; };
|
||||
9E11BEB21A41204F00CC7F6B /* Deinterlacer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE4E1A41204F00CC7F6B /* Deinterlacer.h */; };
|
||||
9E11BEB31A41204F00CC7F6B /* surface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9E11BE4F1A41204F00CC7F6B /* surface.cpp */; };
|
||||
9E11BEB41A41204F00CC7F6B /* surface.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BE501A41204F00CC7F6B /* surface.h */; };
|
||||
9E11BEB81A41213D00CC7F6B /* dvdisaster.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BEB71A41213D00CC7F6B /* dvdisaster.h */; };
|
||||
9E11BEBA1A41215900CC7F6B /* SimpleFIFO.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E11BEB91A41215900CC7F6B /* SimpleFIFO.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
9E11BDDF1A411DA300CC7F6B /* liboctoshock.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = liboctoshock.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9E11BDEB1A41204F00CC7F6B /* CDUtility.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CDUtility.cpp; sourceTree = "<group>"; };
|
||||
9E11BDEC1A41204F00CC7F6B /* CDUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDUtility.h; sourceTree = "<group>"; };
|
||||
9E11BDED1A41204F00CC7F6B /* crc32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crc32.cpp; sourceTree = "<group>"; };
|
||||
9E11BDF01A41204F00CC7F6B /* galois.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = galois.cpp; sourceTree = "<group>"; };
|
||||
9E11BDF11A41204F00CC7F6B /* l-ec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "l-ec.cpp"; sourceTree = "<group>"; };
|
||||
9E11BDF21A41204F00CC7F6B /* lec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lec.cpp; sourceTree = "<group>"; };
|
||||
9E11BDF31A41204F00CC7F6B /* lec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lec.h; sourceTree = "<group>"; };
|
||||
9E11BDF41A41204F00CC7F6B /* recover-raw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "recover-raw.cpp"; sourceTree = "<group>"; };
|
||||
9E11BDF81A41204F00CC7F6B /* emuware.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emuware.cpp; sourceTree = "<group>"; };
|
||||
9E11BDF91A41204F00CC7F6B /* emuware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emuware.h; sourceTree = "<group>"; };
|
||||
9E11BDFA1A41204F00CC7F6B /* EW_state.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EW_state.cpp; sourceTree = "<group>"; };
|
||||
9E11BDFB1A41204F00CC7F6B /* EW_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EW_state.h; sourceTree = "<group>"; };
|
||||
9E11BE001A41204F00CC7F6B /* PACKED.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PACKED.h; sourceTree = "<group>"; };
|
||||
9E11BE011A41204F00CC7F6B /* PACKED_END.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PACKED_END.h; sourceTree = "<group>"; };
|
||||
9E11BE021A41204F00CC7F6B /* endian.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = endian.cpp; path = ../endian.cpp; sourceTree = "<group>"; };
|
||||
9E11BE031A41204F00CC7F6B /* endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = endian.h; path = ../endian.h; sourceTree = "<group>"; };
|
||||
9E11BE041A41204F00CC7F6B /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = error.h; path = ../error.h; sourceTree = "<group>"; };
|
||||
9E11BE0B1A41204F00CC7F6B /* git.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = git.h; path = ../git.h; sourceTree = "<group>"; };
|
||||
9E11BE0C1A41204F00CC7F6B /* math_ops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = math_ops.h; path = ../math_ops.h; sourceTree = "<group>"; };
|
||||
9E11BE0D1A41204F00CC7F6B /* octoshock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = octoshock.cpp; path = ../octoshock.cpp; sourceTree = "<group>"; };
|
||||
9E11BE0E1A41204F00CC7F6B /* octoshock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = octoshock.h; path = ../octoshock.h; sourceTree = "<group>"; };
|
||||
9E11BE101A41204F00CC7F6B /* cdc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cdc.cpp; sourceTree = "<group>"; };
|
||||
9E11BE111A41204F00CC7F6B /* cdc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cdc.h; sourceTree = "<group>"; };
|
||||
9E11BE121A41204F00CC7F6B /* cpu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpu.cpp; sourceTree = "<group>"; };
|
||||
9E11BE131A41204F00CC7F6B /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = "<group>"; };
|
||||
9E11BE141A41204F00CC7F6B /* cpu_bigswitch.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = cpu_bigswitch.inc; sourceTree = "<group>"; };
|
||||
9E11BE151A41204F00CC7F6B /* cpu_computedgoto.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = cpu_computedgoto.inc; sourceTree = "<group>"; };
|
||||
9E11BE181A41204F00CC7F6B /* dis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dis.cpp; sourceTree = "<group>"; };
|
||||
9E11BE191A41204F00CC7F6B /* dis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dis.h; sourceTree = "<group>"; };
|
||||
9E11BE1A1A41204F00CC7F6B /* dma.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dma.cpp; sourceTree = "<group>"; };
|
||||
9E11BE1B1A41204F00CC7F6B /* dma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dma.h; sourceTree = "<group>"; };
|
||||
9E11BE1C1A41204F00CC7F6B /* frontio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = frontio.cpp; sourceTree = "<group>"; };
|
||||
9E11BE1D1A41204F00CC7F6B /* frontio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = frontio.h; sourceTree = "<group>"; };
|
||||
9E11BE1E1A41204F00CC7F6B /* gpu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gpu.cpp; sourceTree = "<group>"; };
|
||||
9E11BE1F1A41204F00CC7F6B /* gpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gpu.h; sourceTree = "<group>"; };
|
||||
9E11BE201A41204F00CC7F6B /* gpu_common.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = gpu_common.inc; sourceTree = "<group>"; };
|
||||
9E11BE211A41204F00CC7F6B /* gpu_line.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gpu_line.cpp; sourceTree = "<group>"; };
|
||||
9E11BE221A41204F00CC7F6B /* gpu_polygon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gpu_polygon.cpp; sourceTree = "<group>"; };
|
||||
9E11BE231A41204F00CC7F6B /* gpu_sprite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gpu_sprite.cpp; sourceTree = "<group>"; };
|
||||
9E11BE241A41204F00CC7F6B /* gte.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gte.cpp; sourceTree = "<group>"; };
|
||||
9E11BE251A41204F00CC7F6B /* gte.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gte.h; sourceTree = "<group>"; };
|
||||
9E11BE271A41204F00CC7F6B /* dualanalog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dualanalog.cpp; sourceTree = "<group>"; };
|
||||
9E11BE281A41204F00CC7F6B /* dualanalog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dualanalog.h; sourceTree = "<group>"; };
|
||||
9E11BE291A41204F00CC7F6B /* dualshock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dualshock.cpp; sourceTree = "<group>"; };
|
||||
9E11BE2A1A41204F00CC7F6B /* dualshock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dualshock.h; sourceTree = "<group>"; };
|
||||
9E11BE2B1A41204F00CC7F6B /* gamepad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gamepad.cpp; sourceTree = "<group>"; };
|
||||
9E11BE2C1A41204F00CC7F6B /* gamepad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gamepad.h; sourceTree = "<group>"; };
|
||||
9E11BE2D1A41204F00CC7F6B /* guncon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = guncon.cpp; sourceTree = "<group>"; };
|
||||
9E11BE2E1A41204F00CC7F6B /* guncon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = guncon.h; sourceTree = "<group>"; };
|
||||
9E11BE2F1A41204F00CC7F6B /* justifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = justifier.cpp; sourceTree = "<group>"; };
|
||||
9E11BE301A41204F00CC7F6B /* justifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = justifier.h; sourceTree = "<group>"; };
|
||||
9E11BE311A41204F00CC7F6B /* memcard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memcard.cpp; sourceTree = "<group>"; };
|
||||
9E11BE321A41204F00CC7F6B /* memcard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memcard.h; sourceTree = "<group>"; };
|
||||
9E11BE331A41204F00CC7F6B /* mouse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mouse.cpp; sourceTree = "<group>"; };
|
||||
9E11BE341A41204F00CC7F6B /* mouse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mouse.h; sourceTree = "<group>"; };
|
||||
9E11BE351A41204F00CC7F6B /* multitap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = multitap.cpp; sourceTree = "<group>"; };
|
||||
9E11BE361A41204F00CC7F6B /* multitap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = multitap.h; sourceTree = "<group>"; };
|
||||
9E11BE371A41204F00CC7F6B /* negcon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = negcon.cpp; sourceTree = "<group>"; };
|
||||
9E11BE381A41204F00CC7F6B /* negcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = negcon.h; sourceTree = "<group>"; };
|
||||
9E11BE391A41204F00CC7F6B /* irq.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = irq.cpp; sourceTree = "<group>"; };
|
||||
9E11BE3A1A41204F00CC7F6B /* irq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = irq.h; sourceTree = "<group>"; };
|
||||
9E11BE3D1A41204F00CC7F6B /* masmem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = masmem.h; sourceTree = "<group>"; };
|
||||
9E11BE3E1A41204F00CC7F6B /* mdec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mdec.cpp; sourceTree = "<group>"; };
|
||||
9E11BE3F1A41204F00CC7F6B /* mdec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mdec.h; sourceTree = "<group>"; };
|
||||
9E11BE401A41204F00CC7F6B /* psx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = psx.cpp; sourceTree = "<group>"; };
|
||||
9E11BE411A41204F00CC7F6B /* psx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = psx.h; sourceTree = "<group>"; };
|
||||
9E11BE421A41204F00CC7F6B /* sio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sio.cpp; sourceTree = "<group>"; };
|
||||
9E11BE431A41204F00CC7F6B /* sio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sio.h; sourceTree = "<group>"; };
|
||||
9E11BE441A41204F00CC7F6B /* spu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spu.cpp; sourceTree = "<group>"; };
|
||||
9E11BE451A41204F00CC7F6B /* spu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spu.h; sourceTree = "<group>"; };
|
||||
9E11BE461A41204F00CC7F6B /* spu_fir_table.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = spu_fir_table.inc; sourceTree = "<group>"; };
|
||||
9E11BE471A41204F00CC7F6B /* spu_reverb.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = spu_reverb.inc; sourceTree = "<group>"; };
|
||||
9E11BE481A41204F00CC7F6B /* timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timer.cpp; sourceTree = "<group>"; };
|
||||
9E11BE491A41204F00CC7F6B /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = "<group>"; };
|
||||
9E11BE4A1A41204F00CC7F6B /* Stream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Stream.cpp; path = ../Stream.cpp; sourceTree = "<group>"; };
|
||||
9E11BE4B1A41204F00CC7F6B /* Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Stream.h; path = ../Stream.h; sourceTree = "<group>"; };
|
||||
9E11BE4D1A41204F00CC7F6B /* Deinterlacer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Deinterlacer.cpp; sourceTree = "<group>"; };
|
||||
9E11BE4E1A41204F00CC7F6B /* Deinterlacer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Deinterlacer.h; sourceTree = "<group>"; };
|
||||
9E11BE4F1A41204F00CC7F6B /* surface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = surface.cpp; sourceTree = "<group>"; };
|
||||
9E11BE501A41204F00CC7F6B /* surface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = surface.h; sourceTree = "<group>"; };
|
||||
9E11BEB71A41213D00CC7F6B /* dvdisaster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dvdisaster.h; sourceTree = "<group>"; };
|
||||
9E11BEB91A41215900CC7F6B /* SimpleFIFO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleFIFO.h; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
9E11BDDC1A411DA300CC7F6B /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
9E11BDD61A411DA300CC7F6B = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E11BDE61A41204F00CC7F6B /* cdrom */,
|
||||
9E11BDF71A41204F00CC7F6B /* emuware */,
|
||||
9E11BE021A41204F00CC7F6B /* endian.cpp */,
|
||||
9E11BE031A41204F00CC7F6B /* endian.h */,
|
||||
9E11BE041A41204F00CC7F6B /* error.h */,
|
||||
9E11BE0B1A41204F00CC7F6B /* git.h */,
|
||||
9E11BE0C1A41204F00CC7F6B /* math_ops.h */,
|
||||
9E11BE0D1A41204F00CC7F6B /* octoshock.cpp */,
|
||||
9E11BE0E1A41204F00CC7F6B /* octoshock.h */,
|
||||
9E11BE0F1A41204F00CC7F6B /* psx */,
|
||||
9E11BE4A1A41204F00CC7F6B /* Stream.cpp */,
|
||||
9E11BE4B1A41204F00CC7F6B /* Stream.h */,
|
||||
9E11BE4C1A41204F00CC7F6B /* video */,
|
||||
9E11BDE01A411DA300CC7F6B /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E11BDE01A411DA300CC7F6B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E11BDDF1A411DA300CC7F6B /* liboctoshock.dylib */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E11BDE61A41204F00CC7F6B /* cdrom */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E11BEB91A41215900CC7F6B /* SimpleFIFO.h */,
|
||||
9E11BDEC1A41204F00CC7F6B /* CDUtility.h */,
|
||||
9E11BEB71A41213D00CC7F6B /* dvdisaster.h */,
|
||||
9E11BDEB1A41204F00CC7F6B /* CDUtility.cpp */,
|
||||
9E11BDED1A41204F00CC7F6B /* crc32.cpp */,
|
||||
9E11BDF01A41204F00CC7F6B /* galois.cpp */,
|
||||
9E11BDF11A41204F00CC7F6B /* l-ec.cpp */,
|
||||
9E11BDF21A41204F00CC7F6B /* lec.cpp */,
|
||||
9E11BDF31A41204F00CC7F6B /* lec.h */,
|
||||
9E11BDF41A41204F00CC7F6B /* recover-raw.cpp */,
|
||||
);
|
||||
name = cdrom;
|
||||
path = ../cdrom;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E11BDF71A41204F00CC7F6B /* emuware */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E11BDF81A41204F00CC7F6B /* emuware.cpp */,
|
||||
9E11BDF91A41204F00CC7F6B /* emuware.h */,
|
||||
9E11BDFA1A41204F00CC7F6B /* EW_state.cpp */,
|
||||
9E11BDFB1A41204F00CC7F6B /* EW_state.h */,
|
||||
9E11BE001A41204F00CC7F6B /* PACKED.h */,
|
||||
9E11BE011A41204F00CC7F6B /* PACKED_END.h */,
|
||||
);
|
||||
name = emuware;
|
||||
path = ../emuware;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E11BE0F1A41204F00CC7F6B /* psx */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E11BE101A41204F00CC7F6B /* cdc.cpp */,
|
||||
9E11BE111A41204F00CC7F6B /* cdc.h */,
|
||||
9E11BE121A41204F00CC7F6B /* cpu.cpp */,
|
||||
9E11BE131A41204F00CC7F6B /* cpu.h */,
|
||||
9E11BE141A41204F00CC7F6B /* cpu_bigswitch.inc */,
|
||||
9E11BE151A41204F00CC7F6B /* cpu_computedgoto.inc */,
|
||||
9E11BE181A41204F00CC7F6B /* dis.cpp */,
|
||||
9E11BE191A41204F00CC7F6B /* dis.h */,
|
||||
9E11BE1A1A41204F00CC7F6B /* dma.cpp */,
|
||||
9E11BE1B1A41204F00CC7F6B /* dma.h */,
|
||||
9E11BE1C1A41204F00CC7F6B /* frontio.cpp */,
|
||||
9E11BE1D1A41204F00CC7F6B /* frontio.h */,
|
||||
9E11BE1E1A41204F00CC7F6B /* gpu.cpp */,
|
||||
9E11BE1F1A41204F00CC7F6B /* gpu.h */,
|
||||
9E11BE201A41204F00CC7F6B /* gpu_common.inc */,
|
||||
9E11BE211A41204F00CC7F6B /* gpu_line.cpp */,
|
||||
9E11BE221A41204F00CC7F6B /* gpu_polygon.cpp */,
|
||||
9E11BE231A41204F00CC7F6B /* gpu_sprite.cpp */,
|
||||
9E11BE241A41204F00CC7F6B /* gte.cpp */,
|
||||
9E11BE251A41204F00CC7F6B /* gte.h */,
|
||||
9E11BE261A41204F00CC7F6B /* input */,
|
||||
9E11BE391A41204F00CC7F6B /* irq.cpp */,
|
||||
9E11BE3A1A41204F00CC7F6B /* irq.h */,
|
||||
9E11BE3D1A41204F00CC7F6B /* masmem.h */,
|
||||
9E11BE3E1A41204F00CC7F6B /* mdec.cpp */,
|
||||
9E11BE3F1A41204F00CC7F6B /* mdec.h */,
|
||||
9E11BE401A41204F00CC7F6B /* psx.cpp */,
|
||||
9E11BE411A41204F00CC7F6B /* psx.h */,
|
||||
9E11BE421A41204F00CC7F6B /* sio.cpp */,
|
||||
9E11BE431A41204F00CC7F6B /* sio.h */,
|
||||
9E11BE441A41204F00CC7F6B /* spu.cpp */,
|
||||
9E11BE451A41204F00CC7F6B /* spu.h */,
|
||||
9E11BE461A41204F00CC7F6B /* spu_fir_table.inc */,
|
||||
9E11BE471A41204F00CC7F6B /* spu_reverb.inc */,
|
||||
9E11BE481A41204F00CC7F6B /* timer.cpp */,
|
||||
9E11BE491A41204F00CC7F6B /* timer.h */,
|
||||
);
|
||||
name = psx;
|
||||
path = ../psx;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E11BE261A41204F00CC7F6B /* input */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E11BE271A41204F00CC7F6B /* dualanalog.cpp */,
|
||||
9E11BE281A41204F00CC7F6B /* dualanalog.h */,
|
||||
9E11BE291A41204F00CC7F6B /* dualshock.cpp */,
|
||||
9E11BE2A1A41204F00CC7F6B /* dualshock.h */,
|
||||
9E11BE2B1A41204F00CC7F6B /* gamepad.cpp */,
|
||||
9E11BE2C1A41204F00CC7F6B /* gamepad.h */,
|
||||
9E11BE2D1A41204F00CC7F6B /* guncon.cpp */,
|
||||
9E11BE2E1A41204F00CC7F6B /* guncon.h */,
|
||||
9E11BE2F1A41204F00CC7F6B /* justifier.cpp */,
|
||||
9E11BE301A41204F00CC7F6B /* justifier.h */,
|
||||
9E11BE311A41204F00CC7F6B /* memcard.cpp */,
|
||||
9E11BE321A41204F00CC7F6B /* memcard.h */,
|
||||
9E11BE331A41204F00CC7F6B /* mouse.cpp */,
|
||||
9E11BE341A41204F00CC7F6B /* mouse.h */,
|
||||
9E11BE351A41204F00CC7F6B /* multitap.cpp */,
|
||||
9E11BE361A41204F00CC7F6B /* multitap.h */,
|
||||
9E11BE371A41204F00CC7F6B /* negcon.cpp */,
|
||||
9E11BE381A41204F00CC7F6B /* negcon.h */,
|
||||
);
|
||||
path = input;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E11BE4C1A41204F00CC7F6B /* video */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E11BE4D1A41204F00CC7F6B /* Deinterlacer.cpp */,
|
||||
9E11BE4E1A41204F00CC7F6B /* Deinterlacer.h */,
|
||||
9E11BE4F1A41204F00CC7F6B /* surface.cpp */,
|
||||
9E11BE501A41204F00CC7F6B /* surface.h */,
|
||||
);
|
||||
name = video;
|
||||
path = ../video;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
9E11BDDD1A411DA300CC7F6B /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9E11BEA11A41204F00CC7F6B /* irq.h in Headers */,
|
||||
9E11BE831A41204F00CC7F6B /* dma.h in Headers */,
|
||||
9E11BE9D1A41204F00CC7F6B /* multitap.h in Headers */,
|
||||
9E11BEB01A41204F00CC7F6B /* Stream.h in Headers */,
|
||||
9E11BE6A1A41204F00CC7F6B /* PACKED_END.h in Headers */,
|
||||
9E11BE771A41204F00CC7F6B /* octoshock.h in Headers */,
|
||||
9E11BE691A41204F00CC7F6B /* PACKED.h in Headers */,
|
||||
9E11BE661A41204F00CC7F6B /* EW_state.h in Headers */,
|
||||
9E11BEB81A41213D00CC7F6B /* dvdisaster.h in Headers */,
|
||||
9E11BEAA1A41204F00CC7F6B /* spu.h in Headers */,
|
||||
9E11BEB21A41204F00CC7F6B /* Deinterlacer.h in Headers */,
|
||||
9E11BE811A41204F00CC7F6B /* dis.h in Headers */,
|
||||
9E11BE911A41204F00CC7F6B /* dualshock.h in Headers */,
|
||||
9E11BE8F1A41204F00CC7F6B /* dualanalog.h in Headers */,
|
||||
9E11BE991A41204F00CC7F6B /* memcard.h in Headers */,
|
||||
9E11BE971A41204F00CC7F6B /* justifier.h in Headers */,
|
||||
9E11BE951A41204F00CC7F6B /* guncon.h in Headers */,
|
||||
9E11BEA61A41204F00CC7F6B /* psx.h in Headers */,
|
||||
9E11BE931A41204F00CC7F6B /* gamepad.h in Headers */,
|
||||
9E11BE9B1A41204F00CC7F6B /* mouse.h in Headers */,
|
||||
9E11BEBA1A41215900CC7F6B /* SimpleFIFO.h in Headers */,
|
||||
9E11BE581A41204F00CC7F6B /* CDUtility.h in Headers */,
|
||||
9E11BE791A41204F00CC7F6B /* cdc.h in Headers */,
|
||||
9E11BE7B1A41204F00CC7F6B /* cpu.h in Headers */,
|
||||
9E11BE5F1A41204F00CC7F6B /* lec.h in Headers */,
|
||||
9E11BE6D1A41204F00CC7F6B /* error.h in Headers */,
|
||||
9E11BE6C1A41204F00CC7F6B /* endian.h in Headers */,
|
||||
9E11BE641A41204F00CC7F6B /* emuware.h in Headers */,
|
||||
9E11BE741A41204F00CC7F6B /* git.h in Headers */,
|
||||
9E11BE751A41204F00CC7F6B /* math_ops.h in Headers */,
|
||||
9E11BE9F1A41204F00CC7F6B /* negcon.h in Headers */,
|
||||
9E11BE8D1A41204F00CC7F6B /* gte.h in Headers */,
|
||||
9E11BE871A41204F00CC7F6B /* gpu.h in Headers */,
|
||||
9E11BEA41A41204F00CC7F6B /* mdec.h in Headers */,
|
||||
9E11BEB41A41204F00CC7F6B /* surface.h in Headers */,
|
||||
9E11BE851A41204F00CC7F6B /* frontio.h in Headers */,
|
||||
9E11BEA81A41204F00CC7F6B /* sio.h in Headers */,
|
||||
9E11BEAE1A41204F00CC7F6B /* timer.h in Headers */,
|
||||
9E11BEA21A41204F00CC7F6B /* masmem.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
9E11BDDE1A411DA300CC7F6B /* octoshock */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 9E11BDE31A411DA300CC7F6B /* Build configuration list for PBXNativeTarget "octoshock" */;
|
||||
buildPhases = (
|
||||
9E11BDDB1A411DA300CC7F6B /* Sources */,
|
||||
9E11BDDC1A411DA300CC7F6B /* Frameworks */,
|
||||
9E11BDDD1A411DA300CC7F6B /* Headers */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = octoshock;
|
||||
productName = octoshock;
|
||||
productReference = 9E11BDDF1A411DA300CC7F6B /* liboctoshock.dylib */;
|
||||
productType = "com.apple.product-type.library.dynamic";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
9E11BDD71A411DA300CC7F6B /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0610;
|
||||
ORGANIZATIONNAME = bizhawk;
|
||||
TargetAttributes = {
|
||||
9E11BDDE1A411DA300CC7F6B = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 9E11BDDA1A411DA300CC7F6B /* Build configuration list for PBXProject "octoshock" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 9E11BDD61A411DA300CC7F6B;
|
||||
productRefGroup = 9E11BDE01A411DA300CC7F6B /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
9E11BDDE1A411DA300CC7F6B /* octoshock */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
9E11BDDB1A411DA300CC7F6B /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9E11BEA71A41204F00CC7F6B /* sio.cpp in Sources */,
|
||||
9E11BE8C1A41204F00CC7F6B /* gte.cpp in Sources */,
|
||||
9E11BE5E1A41204F00CC7F6B /* lec.cpp in Sources */,
|
||||
9E11BEA01A41204F00CC7F6B /* irq.cpp in Sources */,
|
||||
9E11BE651A41204F00CC7F6B /* EW_state.cpp in Sources */,
|
||||
9E11BEB31A41204F00CC7F6B /* surface.cpp in Sources */,
|
||||
9E11BE7C1A41204F00CC7F6B /* cpu_bigswitch.inc in Sources */,
|
||||
9E11BE8A1A41204F00CC7F6B /* gpu_polygon.cpp in Sources */,
|
||||
9E11BE781A41204F00CC7F6B /* cdc.cpp in Sources */,
|
||||
9E11BE801A41204F00CC7F6B /* dis.cpp in Sources */,
|
||||
9E11BE9C1A41204F00CC7F6B /* multitap.cpp in Sources */,
|
||||
9E11BE631A41204F00CC7F6B /* emuware.cpp in Sources */,
|
||||
9E11BEAC1A41204F00CC7F6B /* spu_reverb.inc in Sources */,
|
||||
9E11BE881A41204F00CC7F6B /* gpu_common.inc in Sources */,
|
||||
9E11BEA31A41204F00CC7F6B /* mdec.cpp in Sources */,
|
||||
9E11BE861A41204F00CC7F6B /* gpu.cpp in Sources */,
|
||||
9E11BEA91A41204F00CC7F6B /* spu.cpp in Sources */,
|
||||
9E11BE6B1A41204F00CC7F6B /* endian.cpp in Sources */,
|
||||
9E11BE981A41204F00CC7F6B /* memcard.cpp in Sources */,
|
||||
9E11BEAB1A41204F00CC7F6B /* spu_fir_table.inc in Sources */,
|
||||
9E11BE841A41204F00CC7F6B /* frontio.cpp in Sources */,
|
||||
9E11BE961A41204F00CC7F6B /* justifier.cpp in Sources */,
|
||||
9E11BE8E1A41204F00CC7F6B /* dualanalog.cpp in Sources */,
|
||||
9E11BE5D1A41204F00CC7F6B /* l-ec.cpp in Sources */,
|
||||
9E11BE941A41204F00CC7F6B /* guncon.cpp in Sources */,
|
||||
9E11BE7D1A41204F00CC7F6B /* cpu_computedgoto.inc in Sources */,
|
||||
9E11BE7A1A41204F00CC7F6B /* cpu.cpp in Sources */,
|
||||
9E11BE761A41204F00CC7F6B /* octoshock.cpp in Sources */,
|
||||
9E11BE921A41204F00CC7F6B /* gamepad.cpp in Sources */,
|
||||
9E11BE571A41204F00CC7F6B /* CDUtility.cpp in Sources */,
|
||||
9E11BE821A41204F00CC7F6B /* dma.cpp in Sources */,
|
||||
9E11BEA51A41204F00CC7F6B /* psx.cpp in Sources */,
|
||||
9E11BEB11A41204F00CC7F6B /* Deinterlacer.cpp in Sources */,
|
||||
9E11BE601A41204F00CC7F6B /* recover-raw.cpp in Sources */,
|
||||
9E11BEAF1A41204F00CC7F6B /* Stream.cpp in Sources */,
|
||||
9E11BE9A1A41204F00CC7F6B /* mouse.cpp in Sources */,
|
||||
9E11BE9E1A41204F00CC7F6B /* negcon.cpp in Sources */,
|
||||
9E11BE5C1A41204F00CC7F6B /* galois.cpp in Sources */,
|
||||
9E11BE901A41204F00CC7F6B /* dualshock.cpp in Sources */,
|
||||
9E11BE891A41204F00CC7F6B /* gpu_line.cpp in Sources */,
|
||||
9E11BEAD1A41204F00CC7F6B /* timer.cpp in Sources */,
|
||||
9E11BE591A41204F00CC7F6B /* crc32.cpp in Sources */,
|
||||
9E11BE8B1A41204F00CC7F6B /* gpu_sprite.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
9E11BDE11A411DA300CC7F6B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libstdc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
"_USRDLL=1",
|
||||
"OCTOSHOCK_EXPORTS=1",
|
||||
"_DEBUG=1",
|
||||
"_CRT_SECURE_NO_WARNINGS=1",
|
||||
"EW_EXPORT=1",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
9E11BDE21A411DA300CC7F6B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libstdc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"_CRT_SECURE_NO_WARNINGS=1",
|
||||
"EW_EXPORT=1",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
9E11BDE41A411DA300CC7F6B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
9E11BDE51A411DA300CC7F6B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
9E11BDDA1A411DA300CC7F6B /* Build configuration list for PBXProject "octoshock" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9E11BDE11A411DA300CC7F6B /* Debug */,
|
||||
9E11BDE21A411DA300CC7F6B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
9E11BDE31A411DA300CC7F6B /* Build configuration list for PBXNativeTarget "octoshock" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9E11BDE41A411DA300CC7F6B /* Debug */,
|
||||
9E11BDE51A411DA300CC7F6B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 9E11BDD71A411DA300CC7F6B /* Project object */;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:octoshock.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -1,182 +0,0 @@
|
|||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dvdisaster.h"
|
||||
#include "octoshock.h"
|
||||
#include "CDUtility.h"
|
||||
|
||||
// Kill_LEC_Correct();
|
||||
|
||||
|
||||
namespace CDUtility
|
||||
{
|
||||
|
||||
// lookup table for crc calculation
|
||||
static uint16 subq_crctab[256] =
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
|
||||
|
||||
static uint8 scramble_table[2352 - 12];
|
||||
|
||||
static bool CDUtility_Inited = false;
|
||||
|
||||
static void InitScrambleTable(void)
|
||||
{
|
||||
unsigned cv = 1;
|
||||
|
||||
for (unsigned i = 12; i < 2352; i++)
|
||||
{
|
||||
unsigned char z = 0;
|
||||
|
||||
for (int b = 0; b < 8; b++)
|
||||
{
|
||||
z |= (cv & 1) << b;
|
||||
|
||||
int feedback = ((cv >> 1) & 1) ^ (cv & 1);
|
||||
cv = (cv >> 1) | (feedback << 14);
|
||||
}
|
||||
|
||||
scramble_table[i - 12] = z;
|
||||
}
|
||||
|
||||
//for(int i = 0; i < 2352 - 12; i++)
|
||||
// printf("0x%02x, ", scramble_table[i]);
|
||||
}
|
||||
|
||||
void CDUtility_Init(void)
|
||||
{
|
||||
if (!CDUtility_Inited)
|
||||
{
|
||||
#ifdef WANT_LEC_CHECK
|
||||
Init_LEC_Correct();
|
||||
InitScrambleTable();
|
||||
#endif
|
||||
|
||||
CDUtility_Inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
|
||||
{
|
||||
CDUtility_Init();
|
||||
|
||||
return !!ValidateRawSector(sector_data, xa);
|
||||
}
|
||||
|
||||
bool subq_check_checksum(const uint8 *SubQBuf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
uint16 stored_crc = 0;
|
||||
|
||||
stored_crc = SubQBuf[0xA] << 8;
|
||||
stored_crc |= SubQBuf[0xB];
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
|
||||
|
||||
crc = ~crc;
|
||||
|
||||
return(crc == stored_crc);
|
||||
}
|
||||
|
||||
void subq_generate_checksum(uint8 *buf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
|
||||
|
||||
// Checksum
|
||||
buf[0xa] = ~(crc >> 8);
|
||||
buf[0xb] = ~(crc);
|
||||
}
|
||||
|
||||
|
||||
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
|
||||
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
|
||||
{
|
||||
assert(in_buf != out_buf);
|
||||
|
||||
memset(out_buf, 0, 96);
|
||||
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
{
|
||||
for(unsigned i = 0; i < 96; i++)
|
||||
{
|
||||
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
|
||||
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
|
||||
{
|
||||
assert(in_buf != out_buf);
|
||||
|
||||
for(unsigned d = 0; d < 12; d++)
|
||||
{
|
||||
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
|
||||
{
|
||||
uint8 rawb = 0;
|
||||
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
{
|
||||
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
|
||||
}
|
||||
out_buf[(d << 3) + bitpoodle] = rawb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
#ifndef __MDFN_CDROM_CDUTILITY_H
|
||||
#define __MDFN_CDROM_CDUTILITY_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace CDUtility
|
||||
{
|
||||
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
|
||||
// It will also be called automatically if needed for the first time a function in this namespace that requires
|
||||
// the initialization function to be called is called, for potential
|
||||
// usage in constructors of statically-declared objects.
|
||||
void CDUtility_Init(void);
|
||||
|
||||
// Quick definitions here:
|
||||
//
|
||||
// ABA - Absolute block address, synonymous to absolute MSF
|
||||
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a
|
||||
//
|
||||
// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
|
||||
// lba = aba - 150
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
ADR_NOQINFO = 0x00,
|
||||
ADR_CURPOS = 0x01,
|
||||
ADR_MCN = 0x02,
|
||||
ADR_ISRC = 0x03
|
||||
};
|
||||
|
||||
|
||||
struct TOC_Track
|
||||
{
|
||||
uint8 adr;
|
||||
uint8 control;
|
||||
uint32 lba;
|
||||
};
|
||||
|
||||
// SubQ control field flags.
|
||||
enum
|
||||
{
|
||||
SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
|
||||
SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
|
||||
SUBQ_CTRLF_DATA = 0x04, // Data track.
|
||||
SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DISC_TYPE_CDDA_OR_M1 = 0x00,
|
||||
DISC_TYPE_CD_I = 0x10,
|
||||
DISC_TYPE_CD_XA = 0x20
|
||||
};
|
||||
|
||||
struct TOC
|
||||
{
|
||||
INLINE TOC()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
INLINE void Clear(void)
|
||||
{
|
||||
first_track = last_track = 0;
|
||||
disc_type = 0;
|
||||
|
||||
memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
|
||||
}
|
||||
|
||||
INLINE int FindTrackByLBA(uint32 LBA)
|
||||
{
|
||||
for(int32 track = first_track; track <= (last_track + 1); track++)
|
||||
{
|
||||
if(track == (last_track + 1))
|
||||
{
|
||||
if(LBA < tracks[100].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(LBA < tracks[track].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint8 first_track;
|
||||
uint8 last_track;
|
||||
uint8 disc_type;
|
||||
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
|
||||
// Also, for convenience, tracks[last_track + 1] will always refer
|
||||
// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).
|
||||
};
|
||||
|
||||
//
|
||||
// Address conversion functions.
|
||||
//
|
||||
static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
|
||||
{
|
||||
return(f_a + 75 * s_a + 75 * 60 * m_a);
|
||||
}
|
||||
|
||||
static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
*m_a = aba / 75 / 60;
|
||||
*s_a = (aba - *m_a * 75 * 60) / 75;
|
||||
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
|
||||
}
|
||||
|
||||
static INLINE int32 ABA_to_LBA(uint32 aba)
|
||||
{
|
||||
return(aba - 150);
|
||||
}
|
||||
|
||||
static INLINE uint32 LBA_to_ABA(int32 lba)
|
||||
{
|
||||
return(lba + 150);
|
||||
}
|
||||
|
||||
static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
|
||||
{
|
||||
return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
|
||||
}
|
||||
|
||||
static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
|
||||
}
|
||||
|
||||
//
|
||||
// BCD conversion functions
|
||||
//
|
||||
static INLINE bool BCD_is_valid(uint8 bcd_number)
|
||||
{
|
||||
if((bcd_number & 0xF0) >= 0xA0)
|
||||
return(false);
|
||||
|
||||
if((bcd_number & 0x0F) >= 0x0A)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
static INLINE uint8 BCD_to_U8(uint8 bcd_number)
|
||||
{
|
||||
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
|
||||
}
|
||||
|
||||
static INLINE uint8 U8_to_BCD(uint8 num)
|
||||
{
|
||||
return( ((num / 10) << 4) + (num % 10) );
|
||||
}
|
||||
|
||||
// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
|
||||
// Returns "true" if errors weren't detected, or they were corrected succesfully.
|
||||
// Returns "false" if errors couldn't be corrected.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);
|
||||
|
||||
// Returns false on checksum mismatch, true on match.
|
||||
bool subq_check_checksum(const uint8 *subq_buf);
|
||||
|
||||
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
|
||||
// in subq_buf.
|
||||
void subq_generate_checksum(uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
|
||||
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
|
||||
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,155 +0,0 @@
|
|||
#ifndef __MDFN_SIMPLEFIFO_H
|
||||
#define __MDFN_SIMPLEFIFO_H
|
||||
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../math_ops.h"
|
||||
|
||||
template<typename T>
|
||||
class SimpleFIFO
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
SimpleFIFO(uint32 the_size) // Size should be a power of 2!
|
||||
{
|
||||
data.resize((unsigned long)round_up_pow2(the_size));
|
||||
size = the_size;
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
INLINE ~SimpleFIFO()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
INLINE void SaveStatePostLoad(void)
|
||||
{
|
||||
//I think this is crap about file format (buffer size) change recovery. screw it.
|
||||
//read_pos %= data.size();
|
||||
//write_pos %= data.size();
|
||||
//in_count %= (data.size() + 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
INLINE int StateAction(StateMem *sm, int load, int data_only, const char* sname)
|
||||
{
|
||||
SFORMAT StateRegs[] =
|
||||
{
|
||||
std::vector<T> data;
|
||||
uint32 size;
|
||||
|
||||
SFVAR(read_pos),
|
||||
SFVAR(write_pos),
|
||||
SFVAR(in_count),
|
||||
SFEND;
|
||||
}
|
||||
int ret = MDFNSS_StateAction(sm, load, data_only, sname);
|
||||
|
||||
if(load)
|
||||
{
|
||||
read_pos %= data.size();
|
||||
write_pos %= data.size();
|
||||
in_count %= (data.size() + 1);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
INLINE uint32 CanRead(void)
|
||||
{
|
||||
return(in_count);
|
||||
}
|
||||
|
||||
INLINE uint32 CanWrite(void)
|
||||
{
|
||||
return(size - in_count);
|
||||
}
|
||||
|
||||
INLINE T ReadUnit(bool peek = false)
|
||||
{
|
||||
T ret;
|
||||
|
||||
assert(in_count > 0);
|
||||
|
||||
ret = data[read_pos];
|
||||
|
||||
if(!peek)
|
||||
{
|
||||
read_pos = (read_pos + 1) & (data.size() - 1);
|
||||
in_count--;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
INLINE uint8 ReadByte(bool peek = false)
|
||||
{
|
||||
assert(sizeof(T) == 1);
|
||||
|
||||
return(ReadUnit(peek));
|
||||
}
|
||||
|
||||
INLINE void Write(const T *happy_data, uint32 happy_count)
|
||||
{
|
||||
assert(CanWrite() >= happy_count);
|
||||
|
||||
while(happy_count)
|
||||
{
|
||||
data[write_pos] = *happy_data;
|
||||
|
||||
write_pos = (write_pos + 1) & (data.size() - 1);
|
||||
in_count++;
|
||||
happy_data++;
|
||||
happy_count--;
|
||||
}
|
||||
}
|
||||
|
||||
INLINE void WriteUnit(const T& wr_data)
|
||||
{
|
||||
Write(&wr_data, 1);
|
||||
}
|
||||
|
||||
INLINE void WriteByte(const T& wr_data)
|
||||
{
|
||||
assert(sizeof(T) == 1);
|
||||
Write(&wr_data, 1);
|
||||
}
|
||||
|
||||
|
||||
INLINE void Flush(void)
|
||||
{
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
//private:
|
||||
std::vector<T> data;
|
||||
uint32 size;
|
||||
uint32 read_pos; // Read position
|
||||
uint32 write_pos; // Write position
|
||||
uint32 in_count; // Number of units in the FIFO
|
||||
|
||||
template<bool isReader> void SyncState(EW::NewState *ns)
|
||||
{
|
||||
//I dont like this class...
|
||||
|
||||
PSS(&data[0], data.capacity()*sizeof(T));
|
||||
NSS(read_pos);
|
||||
NSS(write_pos);
|
||||
NSS(in_count);
|
||||
|
||||
|
||||
SaveStatePostLoad();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,130 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* CRC32 code based upon public domain code by Ross Williams (see notes below)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
/***
|
||||
*** EDC checksum used in CDROM sectors
|
||||
***/
|
||||
|
||||
/*****************************************************************/
|
||||
/* */
|
||||
/* CRC LOOKUP TABLE */
|
||||
/* ================ */
|
||||
/* The following CRC lookup table was generated automagically */
|
||||
/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
|
||||
/* Program V1.0 using the following model parameters: */
|
||||
/* */
|
||||
/* Width : 4 bytes. */
|
||||
/* Poly : 0x8001801BL */
|
||||
/* Reverse : TRUE. */
|
||||
/* */
|
||||
/* For more information on the Rocksoft^tm Model CRC Algorithm, */
|
||||
/* see the document titled "A Painless Guide to CRC Error */
|
||||
/* Detection Algorithms" by Ross Williams */
|
||||
/* (ross@guest.adelaide.edu.au.). This document is likely to be */
|
||||
/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
unsigned long edctable[256] =
|
||||
{
|
||||
0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
|
||||
0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
|
||||
0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
|
||||
0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
|
||||
0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
|
||||
0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
|
||||
0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
|
||||
0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
|
||||
0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
|
||||
0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
|
||||
0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
|
||||
0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
|
||||
0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
|
||||
0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
|
||||
0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
|
||||
0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
|
||||
0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
|
||||
0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
|
||||
0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
|
||||
0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
|
||||
0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
|
||||
0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
|
||||
0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
|
||||
0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
|
||||
0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
|
||||
0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
|
||||
0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
|
||||
0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
|
||||
0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
|
||||
0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
|
||||
0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
|
||||
0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
|
||||
0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
|
||||
0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
|
||||
0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
|
||||
0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
|
||||
0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
|
||||
0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
|
||||
0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
|
||||
0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
|
||||
0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
|
||||
0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
|
||||
0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
|
||||
0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
|
||||
0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
|
||||
0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
|
||||
0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
|
||||
0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
|
||||
0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
|
||||
0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
|
||||
0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
|
||||
0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
|
||||
0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
|
||||
0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
|
||||
0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
|
||||
0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
|
||||
0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
|
||||
0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
|
||||
0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
|
||||
0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
|
||||
0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
|
||||
0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
|
||||
0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
|
||||
0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
|
||||
};
|
||||
|
||||
/*
|
||||
* CDROM EDC calculation
|
||||
*/
|
||||
|
||||
uint32 EDCCrc32(const unsigned char *data, int len)
|
||||
{
|
||||
uint32 crc = 0;
|
||||
|
||||
while(len--)
|
||||
crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return crc;
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef DVDISASTER_H
|
||||
#define DVDISASTER_H
|
||||
|
||||
/* "Dare to be gorgeous and unique.
|
||||
* But don't ever be cryptic or otherwise unfathomable.
|
||||
* Make it unforgettably great."
|
||||
*
|
||||
* From "A Final Note on Style",
|
||||
* Amiga Intuition Reference Manual, 1986, p. 231
|
||||
*/
|
||||
|
||||
/***
|
||||
*** I'm too lazy to mess with #include dependencies.
|
||||
*** Everything #includeable is rolled up herein...
|
||||
*/
|
||||
|
||||
#include "octoshock.h"
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/***
|
||||
*** dvdisaster.c
|
||||
***/
|
||||
|
||||
void PrepareDeadSector(void);
|
||||
|
||||
void CreateEcc(void);
|
||||
void FixEcc(void);
|
||||
void Verify(void);
|
||||
|
||||
uint32 EDCCrc32(const unsigned char*, int);
|
||||
|
||||
/***
|
||||
*** galois.c
|
||||
***
|
||||
* This is currently the hardcoded GF(2**8).
|
||||
* int32 gives abundant space for the GF.
|
||||
* Squeezing it down to uint8 won't probably gain much,
|
||||
* so we implement this defensively here.
|
||||
*
|
||||
* Note that some performance critical stuff needs to
|
||||
* be #included from galois-inlines.h
|
||||
*/
|
||||
|
||||
/* Galois field parameters for 8bit symbol Reed-Solomon code */
|
||||
|
||||
#define GF_SYMBOLSIZE 8
|
||||
#define GF_FIELDSIZE (1<<GF_SYMBOLSIZE)
|
||||
#define GF_FIELDMAX (GF_FIELDSIZE-1)
|
||||
#define GF_ALPHA0 GF_FIELDMAX
|
||||
|
||||
/* Lookup tables for Galois field arithmetic */
|
||||
|
||||
typedef struct _GaloisTables
|
||||
{ int32 gfGenerator; /* GF generator polynomial */
|
||||
int32 *indexOf; /* log */
|
||||
int32 *alphaTo; /* inverse log */
|
||||
int32 *encAlphaTo; /* inverse log optimized for encoder */
|
||||
} GaloisTables;
|
||||
|
||||
/* Lookup and working tables for the ReedSolomon codecs */
|
||||
|
||||
typedef struct _ReedSolomonTables
|
||||
{ GaloisTables *gfTables;/* from above */
|
||||
int32 *gpoly; /* RS code generator polynomial */
|
||||
int32 fcr; /* first consecutive root of RS generator polynomial */
|
||||
int32 primElem; /* primitive field element */
|
||||
int32 nroots; /* degree of RS generator polynomial */
|
||||
int32 ndata; /* data bytes per ecc block */
|
||||
} ReedSolomonTables;
|
||||
|
||||
GaloisTables* CreateGaloisTables(int32);
|
||||
void FreeGaloisTables(GaloisTables*);
|
||||
|
||||
ReedSolomonTables *CreateReedSolomonTables(GaloisTables*, int32, int32, int);
|
||||
void FreeReedSolomonTables(ReedSolomonTables*);
|
||||
|
||||
/***
|
||||
*** l-ec.c
|
||||
***/
|
||||
|
||||
#define N_P_VECTORS 86 /* 43 16bit p vectors */
|
||||
#define P_VECTOR_SIZE 26 /* using RS(26,24) ECC */
|
||||
|
||||
#define N_Q_VECTORS 52 /* 26 16bit q vectors */
|
||||
#define Q_VECTOR_SIZE 45 /* using RS(45,43) ECC */
|
||||
|
||||
#define P_PADDING 229 /* padding values for */
|
||||
#define Q_PADDING 210 /* shortened RS code */
|
||||
|
||||
int PToByteIndex(int, int);
|
||||
int QToByteIndex(int, int);
|
||||
void ByteIndexToP(int, int*, int*);
|
||||
void ByteIndexToQ(int, int*, int*);
|
||||
|
||||
void GetPVector(unsigned char*, unsigned char*, int);
|
||||
void SetPVector(unsigned char*, unsigned char*, int);
|
||||
void FillPVector(unsigned char*, unsigned char, int);
|
||||
void AndPVector(unsigned char*, unsigned char, int);
|
||||
void OrPVector(unsigned char*, unsigned char, int);
|
||||
|
||||
void GetQVector(unsigned char*, unsigned char*, int);
|
||||
void SetQVector(unsigned char*, unsigned char*, int);
|
||||
void FillQVector(unsigned char*, unsigned char, int);
|
||||
void AndQVector(unsigned char*, unsigned char, int);
|
||||
void OrQVector(unsigned char*, unsigned char, int);
|
||||
|
||||
int DecodePQ(ReedSolomonTables*, unsigned char*, int, int*, int);
|
||||
|
||||
int CountC2Errors(unsigned char*);
|
||||
|
||||
/***
|
||||
*** misc.c
|
||||
***/
|
||||
|
||||
char* sgettext(char*);
|
||||
char* sgettext_utf8(char*);
|
||||
|
||||
int64 uchar_to_int64(unsigned char*);
|
||||
void int64_to_uchar(unsigned char*, int64);
|
||||
|
||||
void CalcSectors(int64, int64*, int*);
|
||||
|
||||
/***
|
||||
*** recover-raw.c
|
||||
***/
|
||||
|
||||
#define CD_RAW_SECTOR_SIZE 2352
|
||||
#define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
|
||||
|
||||
int CheckEDC(const unsigned char*, bool);
|
||||
int CheckMSF(unsigned char*, int);
|
||||
|
||||
|
||||
int ValidateRawSector(unsigned char *frame, bool xaMode);
|
||||
bool Init_LEC_Correct(void);
|
||||
void Kill_LEC_Correct(void);
|
||||
|
||||
|
||||
#endif /* DVDISASTER_H */
|
|
@ -1,40 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
/*
|
||||
* The following routine is performance critical.
|
||||
*/
|
||||
|
||||
static inline int mod_fieldmax(int x)
|
||||
{
|
||||
while (x >= GF_FIELDMAX)
|
||||
{
|
||||
x -= GF_FIELDMAX;
|
||||
x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
#include "galois-inlines.h"
|
||||
|
||||
/***
|
||||
*** Galois field arithmetic.
|
||||
***
|
||||
* Calculations are done over the extension field GF(2**n).
|
||||
* Be careful not to overgeneralize these arithmetics;
|
||||
* they only work for the case of GF(p**n) with p being prime.
|
||||
*/
|
||||
|
||||
/* Initialize the Galois field tables */
|
||||
|
||||
|
||||
GaloisTables* CreateGaloisTables(int32 gf_generator)
|
||||
{
|
||||
GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
|
||||
int32 b,log;
|
||||
|
||||
/* Allocate the tables.
|
||||
The encoder uses a special version of alpha_to which has the mod_fieldmax()
|
||||
folded into the table. */
|
||||
|
||||
gt->gfGenerator = gf_generator;
|
||||
|
||||
gt->indexOf = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->alphaTo = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->encAlphaTo = (int32 *)calloc(2*GF_FIELDSIZE, sizeof(int32));
|
||||
|
||||
/* create the log/ilog values */
|
||||
|
||||
for(b=1, log=0; log<GF_FIELDMAX; log++)
|
||||
{ gt->indexOf[b] = log;
|
||||
gt->alphaTo[log] = b;
|
||||
b = b << 1;
|
||||
if(b & GF_FIELDSIZE)
|
||||
b = b ^ gf_generator;
|
||||
}
|
||||
|
||||
if(b!=1)
|
||||
{
|
||||
printf("Failed to create the Galois field log tables!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* we're even closed using infinity (makes things easier) */
|
||||
|
||||
gt->indexOf[0] = GF_ALPHA0; /* log(0) = inf */
|
||||
gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */
|
||||
|
||||
for(b=0; b<2*GF_FIELDSIZE; b++)
|
||||
gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
|
||||
|
||||
return gt;
|
||||
}
|
||||
|
||||
void FreeGaloisTables(GaloisTables *gt)
|
||||
{
|
||||
if(gt->indexOf) free(gt->indexOf);
|
||||
if(gt->alphaTo) free(gt->alphaTo);
|
||||
if(gt->encAlphaTo) free(gt->encAlphaTo);
|
||||
|
||||
free(gt);
|
||||
}
|
||||
|
||||
/***
|
||||
*** Create the the Reed-Solomon generator polynomial
|
||||
*** and some auxiliary data structures.
|
||||
*/
|
||||
|
||||
ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
|
||||
int32 first_consecutive_root,
|
||||
int32 prim_elem,
|
||||
int nroots_in)
|
||||
{ ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));
|
||||
int32 i,j,root;
|
||||
|
||||
rt->gfTables = gt;
|
||||
rt->fcr = first_consecutive_root;
|
||||
rt->primElem = prim_elem;
|
||||
rt->nroots = nroots_in;
|
||||
rt->ndata = GF_FIELDMAX - rt->nroots;
|
||||
|
||||
rt->gpoly = (int32 *)calloc((rt->nroots+1), sizeof(int32));
|
||||
|
||||
/* Create the RS code generator polynomial */
|
||||
|
||||
rt->gpoly[0] = 1;
|
||||
|
||||
for(i=0, root=first_consecutive_root*prim_elem; i<rt->nroots; i++, root+=prim_elem)
|
||||
{ rt->gpoly[i+1] = 1;
|
||||
|
||||
/* Multiply gpoly by alpha**(root+x) */
|
||||
|
||||
for(j=i; j>0; j--)
|
||||
{
|
||||
if(rt->gpoly[j] != 0)
|
||||
rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
|
||||
else
|
||||
rt->gpoly[j] = rt->gpoly[j-1];
|
||||
}
|
||||
|
||||
rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
|
||||
}
|
||||
|
||||
/* Store the polynomials index for faster encoding */
|
||||
|
||||
for(i=0; i<=rt->nroots; i++)
|
||||
rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
|
||||
|
||||
#if 0
|
||||
/* for the precalculated unrolled loops only */
|
||||
|
||||
for(i=gt->nroots-1; i>0; i--)
|
||||
PrintCLI(
|
||||
" par_idx[((++spk)&%d)] ^= enc_alpha_to[feedback + %3d];\n",
|
||||
nroots-1,gt->gpoly[i]);
|
||||
|
||||
PrintCLI(" par_idx[sp] = enc_alpha_to[feedback + %3d];\n",
|
||||
gt->gpoly[0]);
|
||||
#endif
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
void FreeReedSolomonTables(ReedSolomonTables *rt)
|
||||
{
|
||||
if(rt->gpoly) free(rt->gpoly);
|
||||
|
||||
free(rt);
|
||||
}
|
|
@ -1,478 +0,0 @@
|
|||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
|
||||
#include "galois-inlines.h"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/***
|
||||
*** Mapping between cd frame and parity vectors
|
||||
***/
|
||||
|
||||
/*
|
||||
* Mapping of frame bytes to P/Q Vectors
|
||||
*/
|
||||
|
||||
int PToByteIndex(int p, int i)
|
||||
{ return 12 + p + i*86;
|
||||
}
|
||||
|
||||
void ByteIndexToP(int b, int *p, int *i)
|
||||
{ *p = (b-12)%86;
|
||||
*i = (b-12)/86;
|
||||
}
|
||||
|
||||
int QToByteIndex(int q, int i)
|
||||
{ int offset = 12 + (q & 1);
|
||||
|
||||
if(i == 43) return 2248+q;
|
||||
if(i == 44) return 2300+q;
|
||||
|
||||
q&=~1;
|
||||
return offset + (q*43 + i*88) % 2236;
|
||||
}
|
||||
|
||||
void ByteIndexToQ(int b, int *q, int *i)
|
||||
{ int x,y,offset;
|
||||
|
||||
if(b >= 2300)
|
||||
{ *i = 44;
|
||||
*q = (b-2300);
|
||||
return;
|
||||
}
|
||||
|
||||
if(b >= 2248)
|
||||
{ *i = 43;
|
||||
*q = (b-2248);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = b&1;
|
||||
b = (b-12)/2;
|
||||
x = b/43;
|
||||
y = (b-(x*43))%26;
|
||||
*i = b-(x*43);
|
||||
*q = 2*((x+26-y)%26)+offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are 86 vectors of P-parity, yielding a RS(26,24) code.
|
||||
*/
|
||||
|
||||
void GetPVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
data[i] = frame[w_idx];
|
||||
}
|
||||
|
||||
void SetPVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] = data[i];
|
||||
}
|
||||
|
||||
void FillPVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] = data;
|
||||
}
|
||||
|
||||
void OrPVector(unsigned char *frame, unsigned char value, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] |= value;
|
||||
}
|
||||
|
||||
void AndPVector(unsigned char *frame, unsigned char value, int n)
|
||||
{ int i;
|
||||
int w_idx = n+12;
|
||||
|
||||
for(i=0; i<26; i++, w_idx+=86)
|
||||
frame[w_idx] &= value;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are 52 vectors of Q-parity, yielding a RS(45,43) code.
|
||||
*/
|
||||
|
||||
void GetQVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
data[i] = frame[(w_idx % 2236) + offset];
|
||||
|
||||
data[43] = frame[2248 + n];
|
||||
data[44] = frame[2300 + n];
|
||||
}
|
||||
|
||||
void SetQVector(unsigned char *frame, unsigned char *data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] = data[i];
|
||||
|
||||
frame[2248 + n] = data[43];
|
||||
frame[2300 + n] = data[44];
|
||||
}
|
||||
|
||||
void FillQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] = data;
|
||||
|
||||
frame[2248 + n] = data;
|
||||
frame[2300 + n] = data;
|
||||
}
|
||||
|
||||
void OrQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] |= data;
|
||||
|
||||
frame[2248 + n] |= data;
|
||||
frame[2300 + n] |= data;
|
||||
}
|
||||
|
||||
void AndQVector(unsigned char *frame, unsigned char data, int n)
|
||||
{ int offset = 12 + (n & 1);
|
||||
int w_idx = (n&~1) * 43;
|
||||
int i;
|
||||
|
||||
for(i=0; i<43; i++, w_idx+=88)
|
||||
frame[(w_idx % 2236) + offset] &= data;
|
||||
|
||||
frame[2248 + n] &= data;
|
||||
frame[2300 + n] &= data;
|
||||
}
|
||||
|
||||
/***
|
||||
*** C2 error counting
|
||||
***/
|
||||
|
||||
int CountC2Errors(unsigned char *frame)
|
||||
{ int i,count = 0;
|
||||
frame += 2352;
|
||||
|
||||
for(i=0; i<294; i++, frame++)
|
||||
{ if(*frame & 0x01) count++;
|
||||
if(*frame & 0x02) count++;
|
||||
if(*frame & 0x04) count++;
|
||||
if(*frame & 0x08) count++;
|
||||
if(*frame & 0x10) count++;
|
||||
if(*frame & 0x20) count++;
|
||||
if(*frame & 0x40) count++;
|
||||
if(*frame & 0x80) count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/***
|
||||
*** L-EC error correction for CD raw data sectors
|
||||
***/
|
||||
|
||||
/*
|
||||
* These could be used from ReedSolomonTables,
|
||||
* but hardcoding them is faster.
|
||||
*/
|
||||
|
||||
#define NROOTS 2
|
||||
#define LEC_FIRST_ROOT 0 //GF_ALPHA0
|
||||
#define LEC_PRIM_ELEM 1
|
||||
#define LEC_PRIMTH_ROOT 1
|
||||
|
||||
/*
|
||||
* Calculate the error syndrome
|
||||
*/
|
||||
|
||||
int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
int *erasure_list, int erasure_count)
|
||||
{ GaloisTables *gt = rt->gfTables;
|
||||
int syndrome[NROOTS];
|
||||
int lambda[NROOTS+1];
|
||||
int omega[NROOTS+1];
|
||||
int b[NROOTS+1];
|
||||
int reg[NROOTS+1];
|
||||
int root[NROOTS];
|
||||
int loc[NROOTS];
|
||||
int syn_error;
|
||||
int deg_lambda,lambda_roots;
|
||||
int deg_omega;
|
||||
int shortened_size = GF_FIELDMAX - padding;
|
||||
int corrected = 0;
|
||||
int i,j,k;
|
||||
int r,el;
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
|
||||
syn_error = 0;
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ syn_error |= syndrome[i];
|
||||
syndrome[i] = gt->indexOf[syndrome[i]];
|
||||
}
|
||||
|
||||
/*** If the syndrome is zero, everything is fine. */
|
||||
|
||||
if(!syn_error)
|
||||
return 0;
|
||||
|
||||
/*** Initialize lambda to be the erasure locator polynomial */
|
||||
|
||||
lambda[0] = 1;
|
||||
lambda[1] = lambda[2] = 0;
|
||||
|
||||
erasure_list[0] += padding;
|
||||
erasure_list[1] += padding;
|
||||
|
||||
if(erasure_count > 2) /* sanity check */
|
||||
erasure_count = 0;
|
||||
|
||||
if(erasure_count > 0)
|
||||
{ lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
|
||||
|
||||
for(i=1; i<erasure_count; i++)
|
||||
{ int u = mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[i]));
|
||||
|
||||
for(j=i+1; j>0; j--)
|
||||
{ int tmp = gt->indexOf[lambda[j-1]];
|
||||
|
||||
if(tmp != GF_ALPHA0)
|
||||
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
b[i] = gt->indexOf[lambda[i]];
|
||||
|
||||
/*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
|
||||
|
||||
r = erasure_count; /* r is the step number */
|
||||
el = erasure_count;
|
||||
|
||||
/* Compute discrepancy at the r-th step in poly-form */
|
||||
|
||||
while(++r <= NROOTS)
|
||||
{ int discr_r = 0;
|
||||
|
||||
for(i=0; i<r; i++)
|
||||
if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
|
||||
discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
|
||||
|
||||
discr_r = gt->indexOf[discr_r];
|
||||
|
||||
if(discr_r == GF_ALPHA0)
|
||||
{ /* B(x) = x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
else
|
||||
{ int t[NROOTS+1];
|
||||
|
||||
/* T(x) = lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(b[i] != GF_ALPHA0)
|
||||
t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
|
||||
else t[i+1] = lambda[i+1];
|
||||
}
|
||||
|
||||
if(2*el <= r+erasure_count-1)
|
||||
{ el = r + erasure_count - el;
|
||||
|
||||
/* B(x) <-- inv(discr_r) * lambda(x) */
|
||||
for(i=0; i<=NROOTS; i++)
|
||||
b[i] = (lambda[i] == 0) ? GF_ALPHA0
|
||||
: mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
|
||||
}
|
||||
else
|
||||
{ /* 2 lines below: B(x) <-- x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
|
||||
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/*** Convert lambda to index form and compute deg(lambda(x)) */
|
||||
|
||||
deg_lambda = 0;
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
{ lambda[i] = gt->indexOf[lambda[i]];
|
||||
if(lambda[i] != GF_ALPHA0)
|
||||
deg_lambda = i;
|
||||
}
|
||||
|
||||
/*** Find roots of the error+erasure locator polynomial by Chien search */
|
||||
|
||||
memcpy(reg+1, lambda+1, NROOTS*sizeof(reg[0]));
|
||||
lambda_roots = 0; /* Number of roots of lambda(x) */
|
||||
|
||||
for(i=1, k=LEC_PRIMTH_ROOT-1; i<=GF_FIELDMAX; i++, k=mod_fieldmax(k+LEC_PRIMTH_ROOT))
|
||||
{ int q=1; /* lambda[0] is always 0 */
|
||||
|
||||
for(j=deg_lambda; j>0; j--)
|
||||
{ if(reg[j] != GF_ALPHA0)
|
||||
{ reg[j] = mod_fieldmax(reg[j] + j);
|
||||
q ^= gt->alphaTo[reg[j]];
|
||||
}
|
||||
}
|
||||
|
||||
if(q != 0) continue; /* Not a root */
|
||||
|
||||
/* store root in index-form and the error location number */
|
||||
|
||||
root[lambda_roots] = i;
|
||||
loc[lambda_roots] = k;
|
||||
|
||||
/* If we've already found max possible roots, abort the search to save time */
|
||||
|
||||
if(++lambda_roots == deg_lambda) break;
|
||||
}
|
||||
|
||||
/* deg(lambda) unequal to number of roots => uncorrectable error detected
|
||||
This is not reliable for very small numbers of roots, e.g. nroots = 2 */
|
||||
|
||||
if(deg_lambda != lambda_roots)
|
||||
{ return -1;
|
||||
}
|
||||
|
||||
/* Compute err+eras evaluator poly omega(x) = syn(x)*lambda(x)
|
||||
(modulo x**nroots). in index form. Also find deg(omega). */
|
||||
|
||||
deg_omega = deg_lambda-1;
|
||||
|
||||
for(i=0; i<=deg_omega; i++)
|
||||
{ int tmp = 0;
|
||||
|
||||
for(j=i; j>=0; j--)
|
||||
{ if((syndrome[i - j] != GF_ALPHA0) && (lambda[j] != GF_ALPHA0))
|
||||
tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
|
||||
}
|
||||
|
||||
omega[i] = gt->indexOf[tmp];
|
||||
}
|
||||
|
||||
/* Compute error values in poly-form.
|
||||
num1 = omega(inv(X(l))),
|
||||
num2 = inv(X(l))**(FIRST_ROOT-1) and
|
||||
den = lambda_pr(inv(X(l))) all in poly-form. */
|
||||
|
||||
for(j=lambda_roots-1; j>=0; j--)
|
||||
{ int num1 = 0;
|
||||
int num2;
|
||||
int den;
|
||||
int location = loc[j];
|
||||
|
||||
for(i=deg_omega; i>=0; i--)
|
||||
{ if(omega[i] != GF_ALPHA0)
|
||||
num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
|
||||
}
|
||||
|
||||
num2 = gt->alphaTo[mod_fieldmax(root[j] * (LEC_FIRST_ROOT - 1) + GF_FIELDMAX)];
|
||||
den = 0;
|
||||
|
||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
||||
|
||||
for(i=MIN(deg_lambda, NROOTS-1) & ~1; i>=0; i-=2)
|
||||
{ if(lambda[i+1] != GF_ALPHA0)
|
||||
den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
|
||||
}
|
||||
|
||||
/* Apply error to data */
|
||||
|
||||
if(num1 != 0 && location >= padding)
|
||||
{
|
||||
corrected++;
|
||||
data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
|
||||
+ GF_FIELDMAX - gt->indexOf[den])];
|
||||
|
||||
/* If no erasures were given, at most one error was corrected.
|
||||
Return its position in erasure_list[0]. */
|
||||
|
||||
if(!erasure_count)
|
||||
erasure_list[0] = location-padding;
|
||||
}
|
||||
#if 1
|
||||
else return -3;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
}
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
#if 1
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i])
|
||||
return -2;
|
||||
#endif
|
||||
|
||||
return corrected;
|
||||
}
|
||||
|
||||
|
|
@ -1,691 +0,0 @@
|
|||
/* cdrdao - write audio CD-Rs in disc-at-once mode
|
||||
*
|
||||
* Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lec.h"
|
||||
|
||||
#define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */
|
||||
|
||||
#define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */
|
||||
|
||||
#define LEC_HEADER_OFFSET 12
|
||||
#define LEC_DATA_OFFSET 16
|
||||
#define LEC_MODE1_DATA_LEN 2048
|
||||
#define LEC_MODE1_EDC_OFFSET 2064
|
||||
#define LEC_MODE1_INTERMEDIATE_OFFSET 2068
|
||||
#define LEC_MODE1_P_PARITY_OFFSET 2076
|
||||
#define LEC_MODE1_Q_PARITY_OFFSET 2248
|
||||
#define LEC_MODE2_FORM1_DATA_LEN (2048+8)
|
||||
#define LEC_MODE2_FORM1_EDC_OFFSET 2072
|
||||
#define LEC_MODE2_FORM2_DATA_LEN (2324+8)
|
||||
#define LEC_MODE2_FORM2_EDC_OFFSET 2348
|
||||
|
||||
|
||||
typedef u_int8_t gf8_t;
|
||||
|
||||
static u_int8_t GF8_LOG[256];
|
||||
static gf8_t GF8_ILOG[256];
|
||||
|
||||
static const class Gf8_Q_Coeffs_Results_01 {
|
||||
private:
|
||||
u_int16_t table[43][256];
|
||||
public:
|
||||
Gf8_Q_Coeffs_Results_01();
|
||||
~Gf8_Q_Coeffs_Results_01() {}
|
||||
const u_int16_t *operator[] (int i) const { return &table[i][0]; }
|
||||
operator const u_int16_t *() const { return &table[0][0]; }
|
||||
} CF8_Q_COEFFS_RESULTS_01;
|
||||
|
||||
static const class CrcTable {
|
||||
private:
|
||||
u_int32_t table[256];
|
||||
public:
|
||||
CrcTable();
|
||||
~CrcTable() {}
|
||||
u_int32_t operator[](int i) const { return table[i]; }
|
||||
operator const u_int32_t *() const { return table; }
|
||||
} CRCTABLE;
|
||||
|
||||
static const class ScrambleTable {
|
||||
private:
|
||||
u_int8_t table[2340];
|
||||
public:
|
||||
ScrambleTable();
|
||||
~ScrambleTable() {}
|
||||
u_int8_t operator[](int i) const { return table[i]; }
|
||||
operator const u_int8_t *() const { return table; }
|
||||
} SCRAMBLE_TABLE;
|
||||
|
||||
/* Creates the logarithm and inverse logarithm table that is required
|
||||
* for performing multiplication in the GF(8) domain.
|
||||
*/
|
||||
static void gf8_create_log_tables()
|
||||
{
|
||||
u_int8_t log;
|
||||
u_int16_t b;
|
||||
|
||||
for (b = 0; b <= 255; b++) {
|
||||
GF8_LOG[b] = 0;
|
||||
GF8_ILOG[b] = 0;
|
||||
}
|
||||
|
||||
b = 1;
|
||||
|
||||
for (log = 0; log < 255; log++) {
|
||||
GF8_LOG[(u_int8_t)b] = log;
|
||||
GF8_ILOG[log] = (u_int8_t)b;
|
||||
|
||||
b <<= 1;
|
||||
|
||||
if ((b & 0x100) != 0)
|
||||
b ^= GF8_PRIM_POLY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Addition in the GF(8) domain: just the XOR of the values.
|
||||
*/
|
||||
#define gf8_add(a, b) (a) ^ (b)
|
||||
|
||||
|
||||
/* Multiplication in the GF(8) domain: add the logarithms (modulo 255)
|
||||
* and return the inverse logarithm. Not used!
|
||||
*/
|
||||
#if 0
|
||||
static gf8_t gf8_mult(gf8_t a, gf8_t b)
|
||||
{
|
||||
int16_t sum;
|
||||
|
||||
if (a == 0 || b == 0)
|
||||
return 0;
|
||||
|
||||
sum = GF8_LOG[a] + GF8_LOG[b];
|
||||
|
||||
if (sum >= 255)
|
||||
sum -= 255;
|
||||
|
||||
return GF8_ILOG[sum];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Division in the GF(8) domain: Like multiplication but logarithms a
|
||||
* subtracted.
|
||||
*/
|
||||
static gf8_t gf8_div(gf8_t a, gf8_t b)
|
||||
{
|
||||
int16_t sum;
|
||||
|
||||
assert(b != 0);
|
||||
|
||||
if (a == 0)
|
||||
return 0;
|
||||
|
||||
sum = GF8_LOG[a] - GF8_LOG[b];
|
||||
|
||||
if (sum < 0)
|
||||
sum += 255;
|
||||
|
||||
return GF8_ILOG[sum];
|
||||
}
|
||||
|
||||
Gf8_Q_Coeffs_Results_01::Gf8_Q_Coeffs_Results_01()
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t c;
|
||||
gf8_t GF8_COEFFS_HELP[2][45];
|
||||
u_int8_t GF8_Q_COEFFS[2][45];
|
||||
|
||||
|
||||
gf8_create_log_tables();
|
||||
|
||||
/* build matrix H:
|
||||
* 1 1 ... 1 1
|
||||
* a^44 a^43 ... a^1 a^0
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_COEFFS_HELP[0][j] = 1; /* e0 */
|
||||
GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */
|
||||
}
|
||||
|
||||
|
||||
/* resolve equation system for parity byte 0 and 1 */
|
||||
|
||||
/* e1' = e1 + e0 */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j],
|
||||
GF8_COEFFS_HELP[0][j]);
|
||||
}
|
||||
|
||||
/* e1'' = e1' / (a^1 + 1) */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]);
|
||||
}
|
||||
|
||||
/* e0' = e0 + e1 / a^1 */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j],
|
||||
gf8_div(GF8_COEFFS_HELP[1][j],
|
||||
GF8_ILOG[1]));
|
||||
}
|
||||
|
||||
/* e0'' = e0' / (1 + 1 / a^1) */
|
||||
for (j = 0; j < 45; j++) {
|
||||
GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the products of 0..255 with all of the Q coefficients in
|
||||
* advance. When building the scalar product between the data vectors
|
||||
* and the P/Q vectors the individual products can be looked up in
|
||||
* this table
|
||||
*
|
||||
* The P parity coefficients are just a subset of the Q coefficients so
|
||||
* that we do not need to create a separate table for them.
|
||||
*/
|
||||
|
||||
for (j = 0; j < 43; j++) {
|
||||
|
||||
table[j][0] = 0;
|
||||
|
||||
for (i = 1; i < 256; i++) {
|
||||
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]];
|
||||
if (c >= 255) c -= 255;
|
||||
table[j][i] = GF8_ILOG[c];
|
||||
|
||||
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]];
|
||||
if (c >= 255) c -= 255;
|
||||
table[j][i] |= GF8_ILOG[c]<<8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'.
|
||||
*/
|
||||
static u_int32_t mirror_bits(u_int32_t d, int bits)
|
||||
{
|
||||
int i;
|
||||
u_int32_t r = 0;
|
||||
|
||||
for (i = 0; i < bits; i++) {
|
||||
r <<= 1;
|
||||
|
||||
if ((d & 0x1) != 0)
|
||||
r |= 0x1;
|
||||
|
||||
d >>= 1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide
|
||||
* and reversed (i.e. the bit stream is divided by the EDC_POLY with the
|
||||
* LSB first order).
|
||||
*/
|
||||
CrcTable::CrcTable ()
|
||||
{
|
||||
u_int32_t i, j;
|
||||
u_int32_t r;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
r = mirror_bits(i, 8);
|
||||
|
||||
r <<= 24;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if ((r & 0x80000000) != 0) {
|
||||
r <<= 1;
|
||||
r ^= EDC_POLY;
|
||||
}
|
||||
else {
|
||||
r <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
r = mirror_bits(r, 32);
|
||||
|
||||
table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates the CRC of given data with given lengths based on the
|
||||
* table lookup algorithm.
|
||||
*/
|
||||
static u_int32_t calc_edc(u_int8_t *data, int len)
|
||||
{
|
||||
u_int32_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
crc = CRCTABLE[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Build the scramble table as defined in the yellow book. The bytes
|
||||
12 to 2351 of a sector will be XORed with the data of this table.
|
||||
*/
|
||||
ScrambleTable::ScrambleTable()
|
||||
{
|
||||
u_int16_t i, j;
|
||||
u_int16_t reg = 1;
|
||||
u_int8_t d;
|
||||
|
||||
for (i = 0; i < 2340; i++) {
|
||||
d = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
d >>= 1;
|
||||
|
||||
if ((reg & 0x1) != 0)
|
||||
d |= 0x80;
|
||||
|
||||
if ((reg & 0x1) != ((reg >> 1) & 0x1)) {
|
||||
reg >>= 1;
|
||||
reg |= 0x4000; /* 15-bit register */
|
||||
}
|
||||
else {
|
||||
reg >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
table[i] = d;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calc EDC for a MODE 1 sector
|
||||
*/
|
||||
static void calc_mode1_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16);
|
||||
|
||||
sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Calc EDC for a XA form 1 sector
|
||||
*/
|
||||
static void calc_mode2_form1_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
|
||||
LEC_MODE2_FORM1_DATA_LEN);
|
||||
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Calc EDC for a XA form 2 sector
|
||||
*/
|
||||
static void calc_mode2_form2_edc(u_int8_t *sector)
|
||||
{
|
||||
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
|
||||
LEC_MODE2_FORM2_DATA_LEN);
|
||||
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
|
||||
sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
|
||||
}
|
||||
|
||||
/* Writes the sync pattern to the given sector.
|
||||
*/
|
||||
static void set_sync_pattern(u_int8_t *sector)
|
||||
{
|
||||
sector[0] = 0;
|
||||
|
||||
sector[1] = sector[2] = sector[3] = sector[4] = sector[5] =
|
||||
sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff;
|
||||
|
||||
sector[11] = 0;
|
||||
}
|
||||
|
||||
|
||||
static u_int8_t bin2bcd(u_int8_t b)
|
||||
{
|
||||
return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f);
|
||||
}
|
||||
|
||||
/* Builds the sector header.
|
||||
*/
|
||||
static void set_sector_header(u_int8_t mode, u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75));
|
||||
sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60);
|
||||
sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75);
|
||||
sector[LEC_HEADER_OFFSET + 3] = mode;
|
||||
}
|
||||
|
||||
/* Calculate the P parities for the sector.
|
||||
* The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
|
||||
*/
|
||||
static void calc_P_parity(u_int8_t *sector)
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t p01_msb, p01_lsb;
|
||||
u_int8_t *p_lsb_start;
|
||||
u_int8_t *p_lsb;
|
||||
u_int8_t *p0, *p1;
|
||||
u_int8_t d0,d1;
|
||||
|
||||
p_lsb_start = sector + LEC_HEADER_OFFSET;
|
||||
|
||||
p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
|
||||
p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
|
||||
|
||||
for (i = 0; i <= 42; i++) {
|
||||
p_lsb = p_lsb_start;
|
||||
|
||||
p01_lsb = p01_msb = 0;
|
||||
|
||||
for (j = 19; j <= 42; j++) {
|
||||
d0 = *p_lsb;
|
||||
d1 = *(p_lsb+1);
|
||||
|
||||
p01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
|
||||
p01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
|
||||
|
||||
p_lsb += 2 * 43;
|
||||
}
|
||||
|
||||
*p0 = p01_lsb;
|
||||
*(p0 + 1) = p01_msb;
|
||||
|
||||
*p1 = p01_lsb>>8;
|
||||
*(p1 + 1) = p01_msb>>8;
|
||||
|
||||
p0 += 2;
|
||||
p1 += 2;
|
||||
|
||||
p_lsb_start += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the Q parities for the sector.
|
||||
* The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
|
||||
*/
|
||||
static void calc_Q_parity(u_int8_t *sector)
|
||||
{
|
||||
int i, j;
|
||||
u_int16_t q01_lsb, q01_msb;
|
||||
u_int8_t *q_lsb_start;
|
||||
u_int8_t *q_lsb;
|
||||
u_int8_t *q0, *q1, *q_start;
|
||||
u_int8_t d0,d1;
|
||||
|
||||
q_lsb_start = sector + LEC_HEADER_OFFSET;
|
||||
|
||||
q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
||||
q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
||||
q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
|
||||
|
||||
for (i = 0; i <= 25; i++) {
|
||||
q_lsb = q_lsb_start;
|
||||
|
||||
q01_lsb = q01_msb = 0;
|
||||
|
||||
for (j = 0; j <= 42; j++) {
|
||||
d0 = *q_lsb;
|
||||
d1 = *(q_lsb+1);
|
||||
|
||||
q01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
|
||||
q01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
|
||||
|
||||
q_lsb += 2 * 44;
|
||||
|
||||
if (q_lsb >= q_start) {
|
||||
q_lsb -= 2 * 1118;
|
||||
}
|
||||
}
|
||||
|
||||
*q0 = q01_lsb;
|
||||
*(q0 + 1) = q01_msb;
|
||||
|
||||
*q1 = q01_lsb>>8;
|
||||
*(q1 + 1) = q01_msb>>8;
|
||||
|
||||
q0 += 2;
|
||||
q1 += 2;
|
||||
|
||||
q_lsb_start += 2 * 43;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encodes a MODE 0 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide
|
||||
*/
|
||||
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
u_int16_t i;
|
||||
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(0, adr, sector);
|
||||
|
||||
sector += 16;
|
||||
|
||||
for (i = 0; i < 2336; i++)
|
||||
*sector++ = 0;
|
||||
}
|
||||
|
||||
/* Encodes a MODE 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(1, adr, sector);
|
||||
|
||||
calc_mode1_edc(sector);
|
||||
|
||||
/* clear the intermediate field */
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] =
|
||||
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0;
|
||||
|
||||
calc_P_parity(sector);
|
||||
calc_Q_parity(sector);
|
||||
}
|
||||
|
||||
/* Encodes a MODE 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Encodes a XA form 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
|
||||
calc_mode2_form1_edc(sector);
|
||||
|
||||
/* P/Q partiy must not contain the sector header so clear it */
|
||||
sector[LEC_HEADER_OFFSET] =
|
||||
sector[LEC_HEADER_OFFSET + 1] =
|
||||
sector[LEC_HEADER_OFFSET + 2] =
|
||||
sector[LEC_HEADER_OFFSET + 3] = 0;
|
||||
|
||||
calc_P_parity(sector);
|
||||
calc_Q_parity(sector);
|
||||
|
||||
/* finally add the sector header */
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Encodes a XA form 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector)
|
||||
{
|
||||
set_sync_pattern(sector);
|
||||
|
||||
calc_mode2_form2_edc(sector);
|
||||
|
||||
set_sector_header(2, adr, sector);
|
||||
}
|
||||
|
||||
/* Scrambles and byte swaps an encoded sector.
|
||||
* 'sector' must be 2352 byte wide.
|
||||
*/
|
||||
void lec_scramble(u_int8_t *sector)
|
||||
{
|
||||
u_int16_t i;
|
||||
const u_int8_t *stable = SCRAMBLE_TABLE;
|
||||
u_int8_t *p = sector;
|
||||
u_int8_t tmp;
|
||||
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
/* just swap bytes of sector sync */
|
||||
tmp = *p;
|
||||
*p = *(p + 1);
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
for (;i < (2352 / 2); i++) {
|
||||
/* scramble and swap bytes */
|
||||
tmp = *p ^ *stable++;
|
||||
*p = *(p + 1) ^ *stable++;
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *infile;
|
||||
char *outfile;
|
||||
int fd_in, fd_out;
|
||||
u_int8_t buffer1[2352];
|
||||
u_int8_t buffer2[2352];
|
||||
u_int32_t lba;
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < 2048; i++)
|
||||
buffer1[i + 16] = 234;
|
||||
|
||||
lba = 150;
|
||||
|
||||
for (i = 0; i < 100000; i++) {
|
||||
lec_encode_mode1_sector(lba, buffer1);
|
||||
lec_scramble(buffer2);
|
||||
lba++;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (argc != 3)
|
||||
return 1;
|
||||
|
||||
infile = argv[1];
|
||||
outfile = argv[2];
|
||||
|
||||
|
||||
if ((fd_in = open(infile, O_RDONLY)) < 0) {
|
||||
perror("Cannot open input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd_out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
|
||||
perror("Cannot open output file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lba = 150;
|
||||
|
||||
do {
|
||||
if (read(fd_in, buffer1, 2352) != 2352)
|
||||
break;
|
||||
|
||||
switch (*(buffer1 + 12 + 3)) {
|
||||
case 1:
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048);
|
||||
|
||||
lec_encode_mode1_sector(lba, buffer2);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ((*(buffer1 + 12 + 4 + 2) & 0x20) != 0) {
|
||||
/* form 2 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2324 + 8);
|
||||
lec_encode_mode2_form2_sector(lba, buffer2);
|
||||
}
|
||||
else {
|
||||
/* form 1 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048 + 8);
|
||||
lec_encode_mode2_form1_sector(lba, buffer2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(buffer1, buffer2, 2352) != 0) {
|
||||
printf("Verify error at lba %ld\n", lba);
|
||||
}
|
||||
|
||||
lec_scramble(buffer2);
|
||||
write(fd_out, buffer2, 2352);
|
||||
|
||||
lba++;
|
||||
} while (1);
|
||||
|
||||
close(fd_in);
|
||||
close(fd_out);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,77 +0,0 @@
|
|||
/* cdrdao - write audio CD-Rs in disc-at-once mode
|
||||
*
|
||||
* Copyright (C) 1998-2002 Andreas Mueller <mueller@daneb.ping.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LEC_H__
|
||||
#define __LEC_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef uint32_t u_int32_t;
|
||||
typedef uint16_t u_int16_t;
|
||||
typedef uint8_t u_int8_t;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/* Encodes a MODE 0 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide
|
||||
*/
|
||||
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a MODE 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a MODE 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a XA form 1 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Encodes a XA form 2 sector.
|
||||
* 'adr' is the current physical sector address
|
||||
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
|
||||
* offset 16
|
||||
*/
|
||||
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector);
|
||||
|
||||
/* Scrambles and byte swaps an encoded sector.
|
||||
* 'sector' must be 2352 byte wide.
|
||||
*/
|
||||
void lec_scramble(u_int8_t *sector);
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue