1 #include "serialise.hh"
11 BufferedSink::~BufferedSink()
13 /* We can't call flush() here, because C++ for some insane reason
14 doesn't allow you to call virtual methods from a destructor. */
20 void BufferedSink::operator () (const unsigned char * data
, size_t len
)
22 if (!buffer
) buffer
= new unsigned char[bufSize
];
25 /* Optimisation: bypass the buffer if the data exceeds the
27 if (bufPos
+ len
>= bufSize
) {
32 /* Otherwise, copy the bytes to the buffer. Flush the buffer
34 size_t n
= bufPos
+ len
> bufSize
? bufSize
- bufPos
: len
;
35 memcpy(buffer
+ bufPos
, data
, n
);
36 data
+= n
; bufPos
+= n
; len
-= n
;
37 if (bufPos
== bufSize
) flush();
42 void BufferedSink::flush()
44 if (bufPos
== 0) return;
46 bufPos
= 0; // don't trigger the assert() in ~BufferedSink()
53 try { flush(); } catch (...) { ignoreException(); }
57 size_t threshold
= 256 * 1024 * 1024;
59 static void warnLargeDump()
61 printMsg(lvlError
, "warning: dumping very large path (> 256 MiB); this may run out of memory");
65 void FdSink::write(const unsigned char * data
, size_t len
)
67 static bool warned
= false;
68 if (warn
&& !warned
) {
70 if (written
> threshold
) {
75 writeFull(fd
, data
, len
);
79 void Source::operator () (unsigned char * data
, size_t len
)
82 size_t n
= read(data
, len
);
88 BufferedSource::~BufferedSource()
94 size_t BufferedSource::read(unsigned char * data
, size_t len
)
96 if (!buffer
) buffer
= new unsigned char[bufSize
];
98 if (!bufPosIn
) bufPosIn
= readUnbuffered(buffer
, bufSize
);
100 /* Copy out the data in the buffer. */
101 size_t n
= len
> bufPosIn
- bufPosOut
? bufPosIn
- bufPosOut
: len
;
102 memcpy(data
, buffer
+ bufPosOut
, n
);
104 if (bufPosIn
== bufPosOut
) bufPosIn
= bufPosOut
= 0;
109 bool BufferedSource::hasData()
111 return bufPosOut
< bufPosIn
;
115 size_t FdSource::readUnbuffered(unsigned char * data
, size_t len
)
120 n
= ::read(fd
, (char *) data
, bufSize
);
121 } while (n
== -1 && errno
== EINTR
);
122 if (n
== -1) throw SysError("reading from file");
123 if (n
== 0) throw EndOfFile("unexpected end-of-file");
128 size_t StringSource::read(unsigned char * data
, size_t len
)
130 if (pos
== s
.size()) throw EndOfFile("end of string reached");
131 size_t n
= s
.copy((char *) data
, len
, pos
);
137 void writePadding(size_t len
, Sink
& sink
)
140 unsigned char zero
[8];
141 memset(zero
, 0, sizeof(zero
));
142 sink(zero
, 8 - (len
% 8));
147 void writeInt(unsigned int n
, Sink
& sink
)
149 unsigned char buf
[8];
150 memset(buf
, 0, sizeof(buf
));
152 buf
[1] = (n
>> 8) & 0xff;
153 buf
[2] = (n
>> 16) & 0xff;
154 buf
[3] = (n
>> 24) & 0xff;
155 sink(buf
, sizeof(buf
));
159 void writeLongLong(unsigned long long n
, Sink
& sink
)
161 unsigned char buf
[8];
163 buf
[1] = (n
>> 8) & 0xff;
164 buf
[2] = (n
>> 16) & 0xff;
165 buf
[3] = (n
>> 24) & 0xff;
166 buf
[4] = (n
>> 32) & 0xff;
167 buf
[5] = (n
>> 40) & 0xff;
168 buf
[6] = (n
>> 48) & 0xff;
169 buf
[7] = (n
>> 56) & 0xff;
170 sink(buf
, sizeof(buf
));
174 void writeString(const unsigned char * buf
, size_t len
, Sink
& sink
)
178 writePadding(len
, sink
);
182 void writeString(const string
& s
, Sink
& sink
)
184 writeString((const unsigned char *) s
.data(), s
.size(), sink
);
188 template<class T
> void writeStrings(const T
& ss
, Sink
& sink
)
190 writeInt(ss
.size(), sink
);
191 foreach (typename
T::const_iterator
, i
, ss
)
192 writeString(*i
, sink
);
195 template void writeStrings(const Paths
& ss
, Sink
& sink
);
196 template void writeStrings(const PathSet
& ss
, Sink
& sink
);
199 void readPadding(size_t len
, Source
& source
)
202 unsigned char zero
[8];
203 size_t n
= 8 - (len
% 8);
205 for (unsigned int i
= 0; i
< n
; i
++)
206 if (zero
[i
]) throw SerialisationError("non-zero padding");
211 unsigned int readInt(Source
& source
)
213 unsigned char buf
[8];
214 source(buf
, sizeof(buf
));
215 if (buf
[4] || buf
[5] || buf
[6] || buf
[7])
216 throw SerialisationError("implementation cannot deal with > 32-bit integers");
225 unsigned long long readLongLong(Source
& source
)
227 unsigned char buf
[8];
228 source(buf
, sizeof(buf
));
230 ((unsigned long long) buf
[0]) |
231 ((unsigned long long) buf
[1] << 8) |
232 ((unsigned long long) buf
[2] << 16) |
233 ((unsigned long long) buf
[3] << 24) |
234 ((unsigned long long) buf
[4] << 32) |
235 ((unsigned long long) buf
[5] << 40) |
236 ((unsigned long long) buf
[6] << 48) |
237 ((unsigned long long) buf
[7] << 56);
241 size_t readString(unsigned char * buf
, size_t max
, Source
& source
)
243 size_t len
= readInt(source
);
244 if (len
> max
) throw Error("string is too long");
246 readPadding(len
, source
);
251 string
readString(Source
& source
)
253 size_t len
= readInt(source
);
254 unsigned char * buf
= new unsigned char[len
];
255 AutoDeleteArray
<unsigned char> d(buf
);
257 readPadding(len
, source
);
258 return string((char *) buf
, len
);
262 template<class T
> T
readStrings(Source
& source
)
264 unsigned int count
= readInt(source
);
267 ss
.insert(ss
.end(), readString(source
));
271 template Paths
readStrings(Source
& source
);
272 template PathSet
readStrings(Source
& source
);
275 void StringSink::operator () (const unsigned char * data
, size_t len
)
277 static bool warned
= false;
278 if (!warned
&& s
.size() > threshold
) {
282 s
.append((const char *) data
, len
);