bool CDIF_ST::Eject(bool eject_status) { if(UnrecoverableError) return(false); try { int32_t old_de = DiscEjected; DiscEjected = eject_status; if(old_de != DiscEjected) { disc_cdaccess->Eject(eject_status); if(!eject_status) // Re-read the TOC { disc_cdaccess->Read_TOC(&disc_toc); if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track) throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track)); } } } catch(std::exception &e) { log_cb(RETRO_LOG_ERROR, "%s\n", e.what()); return(false); } return(true); }
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)); }
static void LoadPRG(Stream *fp) { uint32 t; unsigned z; z = uchead.ID[3] - '0'; // FIXME hex if(z > 15) throw MDFN_Error(0, "Invalid PRG ROM index '%c'.\n", uchead.ID[3]); MDFN_printf(_("PRG ROM %u size: %u\n"), z, uchead.info); if(malloced[z]) free(malloced[z]); t = FixRomSize(uchead.info, 2048); malloced[z] = (uint8 *)MDFN_malloc_T(t, _("PRG ROM")); mallocedsizes[z] = t; memset(malloced[z] + uchead.info, 0xFF, t - uchead.info); fp->read(malloced[z], uchead.info); SetupCartPRGMapping(z,malloced[z],t,0); }
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); } }
void CDIF_MT::RT_EjectDisc(bool eject_status, bool skip_actual_eject) { int32_t old_de = DiscEjected; DiscEjected = eject_status; if(old_de != DiscEjected) { if(!skip_actual_eject) disc_cdaccess->Eject(eject_status); if(!eject_status) // Re-read the TOC { disc_cdaccess->Read_TOC(&disc_toc); if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track) throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track)); } SBWritePos = 0; ra_lba = 0; ra_count = 0; last_read_lba = ~0U; memset(SectorBuffers, 0, SBSize * sizeof(CDIF_Sector_Buffer)); } }
// 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; slock_lock((slock_t*)ze_mutex); if(blocking) { while(ze_queue.size() == 0) // while, not just if. scond_wait((scond_t*)ze_cond, (slock_t*)ze_mutex); } if(ze_queue.size() == 0) ret = false; else { *message = ze_queue.front(); ze_queue.pop(); } slock_unlock((slock_t*)ze_mutex); if(ret && message->message == CDIF_MSG_FATAL_ERROR) throw MDFN_Error(0, "%s", message->str_message.c_str()); return(ret); }
// Integrity checking is experimental, and needs work to function properly(in the emulator cores). static int SendIntegrity(void) { StateMem sm; md5_context md5; uint8 digest[16]; memset(&sm, 0, sizeof(StateMem)); // Do not do a raw/data-only state for speed, due to lack of endian and bool conversion. if(!MDFNSS_SaveSM(&sm, 0, false)) { throw MDFN_Error(0, _("Error during save state generation.")); } md5.starts(); md5.update(sm.data, sm.len); md5.finish(digest); free(sm.data); //for(int i = 15; i >= 0; i--) // printf("%02x", digest[i]); //puts(""); SendCommand(MDFNNPCMD_INTEGRITY_RES, 16, digest); return(1); }
MemoryStream::MemoryStream(uint64 size_hint) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0) { data_buffer_size = 0; data_buffer_alloced = (size_hint > SIZE_MAX) ? SIZE_MAX : size_hint; if(!(data_buffer = (uint8*)realloc(data_buffer, (size_t)data_buffer_alloced))) throw MDFN_Error(ErrnoHolder(errno)); }
FileWrapper::FileWrapper(const char *path, const int mode, const char *purpose) : OpenedMode(mode) { path_save = std::string(path); if(mode == MODE_READ) fp = fopen(path, "rb"); else if(mode == MODE_WRITE) fp = fopen(path, "wb"); else if(mode == MODE_WRITE_SAFE) // SO ANNOYING { int open_flags = O_WRONLY | O_CREAT | O_EXCL; #ifdef O_BINARY open_flags |= O_BINARY; #elif defined(_O_BINARY) open_flags |= _O_BINARY; #endif #if defined(S_IRGRP) && defined(S_IROTH) int tmpfd = open(path, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); #else int tmpfd = open(path, open_flags, S_IRUSR | S_IWUSR); #endif if(tmpfd == -1) { ErrnoHolder ene(errno); if(purpose) throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\" for \"%s\": %s"), path_save.c_str(), purpose, ene.StrError())); else throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\": %s"), path_save.c_str(), ene.StrError())); } fp = fdopen(tmpfd, "wb"); } if(!fp) { ErrnoHolder ene(errno); if(purpose) throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\" for \"%s\": %s"), path_save.c_str(), purpose, ene.StrError())); else throw(MDFN_Error(ene.Errno(), _("Error opening file \"%s\": %s"), path_save.c_str(), ene.StrError())); } }
void FileWrapper::flush(void) { if(fflush(fp) == EOF) { ErrnoHolder ene(errno); throw(MDFN_Error(ene.Errno(), _("Error flushing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError())); } }
void FileWrapper::write(const void *data, uint64 count) { if(fwrite(data, 1, count, fp) != count) { ErrnoHolder ene(errno); throw(MDFN_Error(ene.Errno(), _("Error writing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError())); } }
void FileWrapper::put_char(int c) { if(fputc(c, fp) == EOF) { ErrnoHolder ene(errno); throw(MDFN_Error(ene.Errno(), _("Error writing to opened file \"%s\": %s"), path_save.c_str(), ene.StrError())); } }
void FileWrapper::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::truncate(uint64 length) { if(fflush(fp) == EOF) { ErrnoHolder ene(errno); throw(MDFN_Error(ene.Errno(), _("Error truncating opened file \"%s\": %s"), path_save.c_str(), ene.StrError())); } }
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())); } }
MCGenjin::MCGenjin(Blip_Buffer *bb, const uint8 *rr, uint32 rr_size) { uint8 revision, num256_pages, region, cs_di[2]; if(rr_size < 8192) throw MDFN_Error(0, _("MCGenjin ROM size is too small!")); if(memcmp(rr + 0x1FD0, "MCGENJIN", 8)) throw MDFN_Error(0, _("MC Genjin header magic missing!")); rom.resize(round_up_pow2(rr_size)); memcpy(&rom[0], rr, rr_size); revision = rom[0x1FD8]; num256_pages = rom[0x1FD9]; region = rom[0x1FDA]; cs_di[0] = rom[0x1FDB]; cs_di[1] = rom[0x1FDC]; for(unsigned i = 0; i < 2; i++) { switch(cs_di[i]) { default: for(unsigned si = 0; si < i; si++) // FIXME: auto ptr to make this not necessary delete cs[si]; throw MDFN_Error(0, _("Unsupported MCGENJIN device on CS%d: 0x%02x"), i, cs_di[i]); break; case 0x00: MDFN_printf(_("CS%d: Unused\n"), i); cs[i] = new MCGenjin_CS_Device(); break; case 0x10 ... 0x18: case 0x20 ... 0x28: MDFN_printf(_("CS%d: %uKiB %sRAM\n"), i, 8 << (cs_di[i] & 0xF), (cs_di[i] & 0x20) ? "Nonvolatile " : ""); cs[i] = new MCGenjin_CS_Device_RAM(8192 << (cs_di[i] & 0xF), (bool)(cs_di[i] & 0x20)); break; } } }
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())); } }
static void RecvState(const uint32 clen) { StateMem sm; std::vector<uint8> cbuf; std::vector<uint8> buf; memset(&sm, 0, sizeof(StateMem)); if(clen < 4) { throw MDFN_Error(0, _("Compressed save state data is too small: %u"), clen); } if(clen > 8 * 1024 * 1024) // Compressed length sanity check - 8 MiB max. { throw MDFN_Error(0, _("Compressed save state data is too large: %u"), clen); } cbuf.resize(clen); MDFND_RecvData(&cbuf[0], clen); uLongf len = MDFN_de32lsb(&cbuf[0]); if(len > 12 * 1024 * 1024) // Uncompressed length sanity check - 12 MiB max. { throw MDFN_Error(0, _("Uncompressed save state data is too large: %llu"), (unsigned long long)len); } buf.resize(len); uncompress((Bytef *)&buf[0], &len, (Bytef *)&cbuf[0] + 4, clen - 4); sm.data = &buf[0]; sm.len = len; if(!MDFNSS_LoadSM(&sm, 0, 0)) { throw MDFN_Error(0, _("Error during save state loading.")); } if(MDFNMOV_IsRecording()) MDFNMOV_RecordState(); }
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; }
void MDFNSS_LoadSM(Stream *st, bool data_only) { if(MDFN_LIKELY(data_only)) { StateMem sm(st); MDFN_StateAction(&sm, MEDNAFEN_VERSION_NUMERIC, true); sm.ThrowDeferred(); } else { uint8 header[32]; uint32 width, height, preview_len; uint32 stateversion; uint32 total_len; int64 start_pos; bool svbe; start_pos = st->tell(); st->read(header, 32); if(memcmp(header, "MEDNAFENSVESTATE", 16) && memcmp(header, "MDFNSVST", 8)) throw MDFN_Error(0, _("Missing/Wrong save state header ID.")); stateversion = MDFN_de32lsb(header + 16); total_len = MDFN_de32lsb(header + 20) & 0x7FFFFFFF; svbe = MDFN_de32lsb(header + 20) & 0x80000000; width = MDFN_de32lsb(header + 24); height = MDFN_de32lsb(header + 28); preview_len = width * height * 3; if((int)stateversion < 0x900) // Ensuring that (int)stateversion is > 0 is the most important part. throw MDFN_Error(0, _("Invalid/Unsupported version in save state header.")); st->seek(preview_len, SEEK_CUR); // Skip preview StateMem sm(st, start_pos + total_len, svbe); MDFN_StateAction(&sm, stateversion, false); // Load state data. sm.ThrowDeferred(); st->seek(start_pos + total_len, SEEK_SET); // Seek to just beyond end of save state before returning. } }
MemoryStream::MemoryStream(const MemoryStream *zs) { data_buffer_size = zs->data_buffer_size; data_buffer_alloced = zs->data_buffer_alloced; if(!(data_buffer = (uint8*)malloc((size_t)data_buffer_alloced))) throw MDFN_Error(ErrnoHolder(errno)); memcpy(data_buffer, zs->data_buffer, (size_t)data_buffer_size); position = zs->position; }
FileStream::FileStream(const char *path, const int mode) { fp = filestream_open(path, (mode == MODE_WRITE || mode == MODE_WRITE_INPLACE) ? RETRO_VFS_FILE_ACCESS_WRITE : RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); if (!fp) { ErrnoHolder ene(errno); MDFN_Error(ene.Errno(), "Error opening file:\n%s\n%s", path, ene.StrError()); } }
void MemoryStream::write(const void *data, uint64 count) { uint64 nrs = position + count; if(nrs < position) throw MDFN_Error(ErrnoHolder(EFBIG)); grow_if_necessary(nrs); memmove(&data_buffer[position], data, (size_t)count); position += count; }
CDIF_ST::CDIF_ST(CDAccess *cda) : disc_cdaccess(cda) { //puts("***WARNING USING SINGLE-THREADED CD READER***"); UnrecoverableError = false; DiscEjected = 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)); }
uint64 FileWrapper::read(void *data, uint64 count, bool error_on_eof) { uint64 read_count; clearerr(fp); read_count = fread(data, 1, count, fp); if(read_count != count) { ErrnoHolder ene(errno); if(ferror(fp)) throw(MDFN_Error(ene.Errno(), _("Error reading from opened file \"%s\": %s"), path_save.c_str(), ene.StrError())); if(error_on_eof) throw(MDFN_Error(ene.Errno(), _("Error reading from opened file \"%s\": %s"), path_save.c_str(), "EOF")); } return(read_count); }
uint32 NetClient_WS2::Receive(void *data, uint32 len) { int rv; rv = recv(*(SOCKET*)sd, (char *)data, len, 0); if(rv < 0) { int errcode = WSAGetLastError(); if(errcode != WSAEWOULDBLOCK && errcode != WSAEINTR) { throw MDFN_Error(0, _("recv() failed: %d %s"), errcode, ErrCodeToString(errcode).c_str()); } return(0); } else if(rv == 0) { throw MDFN_Error(0, _("recv() failed: peer has closed connection")); } return rv; }
uint32 NetClient_POSIX::Receive(void *data, uint32 len) { ssize_t rv; rv = recv(fd, data, len, 0); if(rv < 0) { if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { ErrnoHolder ene(errno); throw MDFN_Error(ene.Errno(), _("recv() failed: %s"), ene.StrError()); } return(0); } else if(rv == 0) { throw MDFN_Error(0, _("recv() failed: peer has closed connection")); } return rv; }
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; }
static void LoadNSF(Stream *fp) { NSF_HEADER NSFHeader; fp->read(&NSFHeader, 0x80); // NULL-terminate strings just in case. NSFHeader.GameName[31] = NSFHeader.Artist[31] = NSFHeader.Copyright[31] = 0; MDFN_zapctrlchars((char*)NSFHeader.GameName); MDFN_zapctrlchars((char*)NSFHeader.Artist); MDFN_zapctrlchars((char*)NSFHeader.Copyright); MDFN_trim((char*)NSFHeader.GameName); MDFN_trim((char*)NSFHeader.Artist); MDFN_trim((char*)NSFHeader.Copyright); NSFInfo->GameName = std::string((const char *)NSFHeader.GameName); NSFInfo->Artist = std::string((const char *)NSFHeader.Artist); NSFInfo->Copyright = std::string((const char *)NSFHeader.Copyright); NSFInfo->LoadAddr = NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh << 8); NSFInfo->InitAddr = NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh << 8); NSFInfo->PlayAddr = NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh << 8); uint64 tmp_size = fp->size() - 0x80; if(tmp_size > 16 * 1024 * 1024) throw MDFN_Error(0, _("NSF is too large.")); NSFInfo->NSFSize = tmp_size; NSFInfo->NSFMaxBank = ((NSFInfo->NSFSize+(NSFInfo->LoadAddr&0xfff)+4095)/4096); NSFInfo->NSFMaxBank = round_up_pow2(NSFInfo->NSFMaxBank); NSFInfo->NSFDATA = new uint8[NSFInfo->NSFMaxBank * 4096]; memset(NSFInfo->NSFDATA, 0x00, NSFInfo->NSFMaxBank*4096); fp->read(NSFInfo->NSFDATA+(NSFInfo->LoadAddr&0xfff), NSFInfo->NSFSize); NSFInfo->NSFMaxBank--; NSFInfo->VideoSystem = NSFHeader.VideoSystem; NSFInfo->SoundChip = NSFHeader.SoundChip; NSFInfo->TotalSongs = NSFHeader.TotalSongs; if(NSFHeader.StartingSong == 0) NSFHeader.StartingSong = 1; NSFInfo->StartingSong = NSFHeader.StartingSong - 1; memcpy(NSFInfo->BankSwitch, NSFHeader.BankSwitch, 8); }