From eedad559456b8e62ed3b9bd9e8253e5f8bcc02d6 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 8 Nov 2012 21:51:30 +0200 Subject: [PATCH] Add an I/O class to access a restricted range of bytes from another object --- source/io/slice.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++++ source/io/slice.h | 50 ++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 source/io/slice.cpp create mode 100644 source/io/slice.h diff --git a/source/io/slice.cpp b/source/io/slice.cpp new file mode 100644 index 0000000..423c1a6 --- /dev/null +++ b/source/io/slice.cpp @@ -0,0 +1,111 @@ +#include +#include "slice.h" + +using namespace std; + +namespace Msp { +namespace IO { + +Slice::Slice(Seekable &b, SeekOffset s, SeekOffset l): + below(b), + start_offset(s), + length(l), + position(0), + sync_position(true) +{ + if(s<0 || l<0) + throw invalid_argument("Slice"); + + mode = below.get_mode()&M_RDWR; + below.signal_flush_required.connect(sigc::mem_fun(this, &Slice::flush)); +} + +void Slice::flush() +{ + sync_position = true; +} + +unsigned Slice::prepare_op(unsigned size, Mode m) +{ + check_access(m); + + if(sync_position) + seek(position, S_BEG); + + SeekOffset remaining = start_offset+length-position; + if(size>remaining) + size = remaining; + if(!size && m==M_READ) + set_eof(); + + return size; +} + +unsigned Slice::do_write(const char *data, unsigned size) +{ + size = prepare_op(size, M_WRITE); + if(!size) + return 0; + + unsigned len = below.write(data, size); + position += len; + return len; +} + +unsigned Slice::do_read(char *data, unsigned size) +{ + size = prepare_op(size, M_READ); + if(!size) + return 0; + + unsigned len = below.read(data, size); + if(!len && below.eof()) + set_eof(); + position += len; + return len; +} + +unsigned Slice::put(char c) +{ + if(!prepare_op(1, M_WRITE)) + return 0; + + unsigned len = below.put(c); + position += len; + return len; +} + +int Slice::get() +{ + if(!prepare_op(1, M_READ)) + return 0; + + int c = below.get(); + if(c==-1 && below.eof()) + set_eof(); + else + ++position; + return c; +} + +SeekOffset Slice::seek(SeekOffset off, SeekType type) +{ + if(type==S_BEG) + off += start_offset; + else if(type==S_CUR) + off += position; + else if(type==S_END) + off += start_offset+length; + + if(offstart_offset+length) + throw bad_seek(off, type); + + signal_flush_required.emit(); + + position = below.seek(off, S_BEG)-start_offset; + sync_position = false; + return position; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/slice.h b/source/io/slice.h new file mode 100644 index 0000000..f611585 --- /dev/null +++ b/source/io/slice.h @@ -0,0 +1,50 @@ +#ifndef MSP_IO_SLICE_H_ +#define MSP_IO_SLICE_H_ + +#include "seekable.h" + +namespace Msp { +namespace IO { + +/** +Presents a part of seekable I/O object as if it was a complete object. This +allows in-place access to embedded resources where the loader expects to +receive a complete file. + +When a Slice is created, its read/write offset is placed at the beginning of +its range. If the offset of the underlying object is changed, the Slice will +restore it before the next access. This enables multiple Slices to be created +on top of the same object. +*/ +class Slice: public Seekable +{ +private: + Seekable &below; + SeekOffset start_offset; + SeekOffset length; + SeekOffset position; + bool sync_position; + +public: + Slice(Seekable &, SeekOffset, SeekOffset); + +private: + void flush(); + + unsigned prepare_op(unsigned, Mode); +protected: + virtual unsigned do_write(const char *, unsigned); + virtual unsigned do_read(char *, unsigned); + +public: + virtual unsigned put(char); + virtual int get(); + + virtual SeekOffset seek(SeekOffset, SeekType); + virtual SeekOffset tell() const { return position; } +}; + +} // namespace IO +} // namespace Msp + +#endif -- 2.43.0