]> git.tdb.fi Git - libs/core.git/blob - source/io/slice.cpp
d53a63b13bd17a966f11de2f4766fb57e8880807
[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::set_block(bool)
25 {
26         throw logic_error("Slice::set_block");
27 }
28
29 void Slice::flush()
30 {
31         sync_position = true;
32 }
33
34 unsigned Slice::prepare_op(unsigned size, Mode m)
35 {
36         check_access(m);
37
38         if(sync_position)
39         {
40                 SeekOffset pos = below.seek(start_offset+position, S_BEG)-start_offset;
41                 if(pos!=position)
42                         throw runtime_error("failed to restore position");
43                 sync_position = false;
44         }
45
46         SeekOffset remaining = length-position;
47         if(size>remaining)
48                 size = remaining;
49         if(!size && m==M_READ)
50                 set_eof();
51
52         return size;
53 }
54
55 unsigned Slice::do_write(const char *data, unsigned size)
56 {
57         Base::Synchronize sync(below);
58         size = prepare_op(size, M_WRITE);
59         if(!size)
60                 return 0;
61
62         unsigned len = below.write(data, size);
63         position += len;
64         return len;
65 }
66
67 unsigned Slice::do_read(char *data, unsigned size)
68 {
69         Base::Synchronize sync(below);
70         size = prepare_op(size, M_READ);
71         if(!size)
72                 return 0;
73
74         unsigned len = below.read(data, size);
75         if(!len && below.eof())
76                 set_eof();
77         position += len;
78         return len;
79 }
80
81 unsigned Slice::put(char c)
82 {
83         Base::Synchronize sync(below);
84         if(!prepare_op(1, M_WRITE))
85                 return 0;
86
87         unsigned len = below.put(c);
88         position += len;
89         return len;
90 }
91
92 int Slice::get()
93 {
94         Base::Synchronize sync(below);
95         if(!prepare_op(1, M_READ))
96                 return -1;
97
98         int c = below.get();
99         if(c==-1 && below.eof())
100                 set_eof();
101         else
102                 ++position;
103         return c;
104 }
105
106 const Handle &Slice::get_handle(Mode)
107 {
108         throw logic_error("Slice::get_handle");
109 }
110
111 SeekOffset Slice::seek(SeekOffset off, SeekType type)
112 {
113         Base::Synchronize sync(below);
114         off += start_offset;
115         if(type==S_CUR)
116                 off += position;
117         else if(type==S_END)
118                 off += length;
119         else if(type!=S_BEG)
120                 throw invalid_argument("Slice::seek");
121
122         if(off<start_offset || off>start_offset+length)
123                 throw bad_seek(off, type);
124
125         signal_flush_required.emit();
126
127         position = below.seek(off, S_BEG)-start_offset;
128         sync_position = false;
129         return position;
130 }
131
132 } // namespace IO
133 } // namespace Msp