INLINE void MemoryStream::grow_if_necessary(uint64 new_required_size) { if(new_required_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 > (UINT64_C(1) << 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, (size_t)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; } }
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; }
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, (size_t)data_buffer_alloced))) throw MDFN_Error(ErrnoHolder(errno)); }
uint64 CDIF_Stream_Thing::read(void *data, uint64 count, bool error_on_eos) { uint64_t rp; 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(rp = position; rp < (position + count); rp = (rp &~ 2047) + 2048) { uint8_t buf[2048]; if(!cdintf->ReadSector(buf, start_lba + (rp / 2048), 1)) throw MDFN_Error(ErrnoHolder(EIO)); memcpy((uint8_t*)data + (rp - position), buf + (rp & 2047), std::min<uint64>(2048 - (rp & 2047),count - (rp - position)) ); } position += count; return count; }
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)); }
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; }
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; }
MemoryStream::MemoryStream(Stream *stream) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0) { if((position = stream->tell()) != 0) stream->seek(0, SEEK_SET); data_buffer_size = stream->size(); data_buffer_alloced = data_buffer_size; if(!(data_buffer = (uint8*)realloc(data_buffer, (size_t)data_buffer_alloced))) throw MDFN_Error(ErrnoHolder(errno)); stream->read(data_buffer, data_buffer_size); stream->close(); delete stream; }
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; } data_buffer_alloced = std::max<uint64>(data_buffer_alloced, 1); 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); }
void ExtMemStream::write(const void *data, uint64 count) { uint64 nrs = position + count; if(ro) throw MDFN_Error(EINVAL, _("Write attempted to read-only ExtMemStream.")); if(nrs < position) throw MDFN_Error(ErrnoHolder(EFBIG)); grow_if_necessary(nrs, position); memmove(&data_buffer[position], data, count); position += count; }
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); }
void CDIF_Stream_Thing::seek(int64 offset, int whence) { int64 new_position; switch(whence) { 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 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_MAX) throw MDFN_Error(ErrnoHolder(ENOMEM)); 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(data_buffer_alloced > SIZE_MAX) throw MDFN_Error(ErrnoHolder(ENOMEM)); 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; const uint64 new_data_buffer_alloced = std::max<uint64>(data_buffer_size, 1); new_data_buffer = (uint8*)realloc(data_buffer, new_data_buffer_alloced); if(new_data_buffer != NULL) { data_buffer = new_data_buffer; data_buffer_alloced = new_data_buffer_alloced; } } } else { data_buffer_size = size(); data_buffer_size -= std::min<uint64>(data_buffer_size, tell()); data_buffer_alloced = std::max<uint64>(data_buffer_size, 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(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; }
void CDIF_Stream_Thing::write(const void *data, uint64 count) { throw MDFN_Error(ErrnoHolder(EBADF)); }