]> git.tdb.fi Git - libs/core.git/blob - source/io/slice.cpp
63df62f29f841d164d5c52e7f80506c16a5a128f
[libs/core.git] / source / io / slice.cpp
1 #include <stdexcept>
2 #include "slice.h"
3
4 using namespace std;
5
6 namespace Msp {
7 namespace IO {
8
9 Slice::Slice(Seekable &b, SeekOffset s, SeekOffset l):
10         below(b),
11         start_offset(s),
12         length(l),
13         position(0),
14         sync_position(true)
15 {
16         if(s<0 || l<0)
17                 throw invalid_argument("Slice");
18
19         Base::Synchronize sync(below);
20         mode = below.get_mode()&M_RDWR;
21         below.signal_flush_required.connect(sigc::mem_fun(this, &Slice::flush));
22 }
23
24 void Slice::flush()
25 {
26         sync_position = true;
27 }
28
29 unsigned Slice::prepare_op(unsigned size, Mode m)
30 {
31         check_access(m);
32
33         if(sync_position)
34         {
35                 SeekOffset pos = below.seek(start_offset+position, S_BEG)-start_offset;
36                 if(pos!=position)
37                         throw runtime_error("failed to restore position");
38                 sync_position = false;
39         }
40
41         SeekOffset remaining = length-position;
42         if(size>remaining)
43                 size = remaining;
44         if(!size && m==M_READ)
45                 set_eof();
46
47         return size;
48 }
49
50 unsigned Slice::do_write(const char *data, unsigned size)
51 {
52         Base::Synchronize sync(below);
53         size = prepare_op(size, M_WRITE);
54         if(!size)
55                 return 0;
56
57         unsigned len = below.write(data, size);
58         position += len;
59         return len;
60 }
61
62 unsigned Slice::do_read(char *data, unsigned size)
63 {
64         Base::Synchronize sync(below);
65         size = prepare_op(size, M_READ);
66         if(!size)
67                 return 0;
68
69         unsigned len = below.read(data, size);
70         if(!len && below.eof())
71                 set_eof();
72         position += len;
73         return len;
74 }
75
76 unsigned Slice::put(char c)
77 {
78         Base::Synchronize sync(below);
79         if(!prepare_op(1, M_WRITE))
80                 return 0;
81
82         unsigned len = below.put(c);
83         position += len;
84         return len;
85 }
86
87 int Slice::get()
88 {
89         Base::Synchronize sync(below);
90         if(!prepare_op(1, M_READ))
91                 return 0;
92
93         int c = below.get();
94         if(c==-1 && below.eof())
95                 set_eof();
96         else
97                 ++position;
98         return c;
99 }
100
101 SeekOffset Slice::seek(SeekOffset off, SeekType type)
102 {
103         Base::Synchronize sync(below);
104         off += start_offset;
105         if(type==S_CUR)
106                 off += position;
107         else if(type==S_END)
108                 off += length;
109         else if(type!=S_BEG)
110                 throw invalid_argument("Slice::seek");
111
112         if(off<start_offset || off>start_offset+length)
113                 throw bad_seek(off, type);
114
115         signal_flush_required.emit();
116
117         position = below.seek(off, S_BEG)-start_offset;
118         sync_position = false;
119         return position;
120 }
121
122 } // namespace IO
123 } // namespace Msp