--- /dev/null
+#include <stdexcept>
+#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(off<start_offset || off>start_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