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