1 |
dpavlin |
1 |
/* |
2 |
|
|
* HT Editor |
3 |
|
|
* stream.cc |
4 |
|
|
* |
5 |
|
|
* Copyright (C) 1999-2002 Stefan Weyergraf |
6 |
|
|
* |
7 |
|
|
* This program is free software; you can redistribute it and/or modify |
8 |
|
|
* it under the terms of the GNU General Public License version 2 as |
9 |
|
|
* published by the Free Software Foundation. |
10 |
|
|
* |
11 |
|
|
* This program is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU General Public License |
17 |
|
|
* along with this program; if not, write to the Free Software |
18 |
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
#include <cerrno> |
22 |
|
|
#include <fcntl.h> |
23 |
|
|
#include <limits.h> |
24 |
|
|
#include <new> |
25 |
|
|
#include <cstring> |
26 |
|
|
#include <cstdio> |
27 |
|
|
#include <cstdlib> |
28 |
|
|
#include <sys/stat.h> /* for mode definitions */ |
29 |
|
|
#include <sys/types.h> /* for mode definitions */ |
30 |
|
|
#include <unistd.h> |
31 |
|
|
|
32 |
|
|
#include "debug.h" |
33 |
|
|
#include "except.h" |
34 |
|
|
#include "system/sys.h" |
35 |
|
|
#include "snprintf.h" |
36 |
|
|
#include "stream.h" |
37 |
|
|
|
38 |
|
|
/* |
39 |
|
|
* Listener |
40 |
|
|
*/ |
41 |
|
|
#if 0 |
42 |
|
|
class Listener: public Object { |
43 |
|
|
public: |
44 |
|
|
StreamEventListener *listener; |
45 |
|
|
StreamEvent notify_mask; |
46 |
|
|
|
47 |
|
|
Listener(StreamEventListener *l, StreamEvent nmask) |
48 |
|
|
{ |
49 |
|
|
listener = l; |
50 |
|
|
notify_mask = nmask; |
51 |
|
|
} |
52 |
|
|
|
53 |
|
|
/* extends Object */ |
54 |
|
|
virtual int compareTo(const Object *obj) const |
55 |
|
|
{ |
56 |
|
|
return ((Listener*)obj)->listener == listener ? 0 : 1; |
57 |
|
|
} |
58 |
|
|
}; |
59 |
|
|
#endif |
60 |
|
|
/* |
61 |
|
|
* Stream |
62 |
|
|
*/ |
63 |
|
|
#define STREAM_COPYBUF_SIZE (64*1024) |
64 |
|
|
|
65 |
|
|
Stream::Stream() |
66 |
|
|
{ |
67 |
|
|
mAccessMode = IOAM_NULL; |
68 |
|
|
// mListeners = NULL; |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
Stream::~Stream() |
72 |
|
|
{ |
73 |
|
|
// if (mListeners) delete mListeners; |
74 |
|
|
} |
75 |
|
|
/* |
76 |
|
|
void Stream::addEventListener(StreamEventListener *l, StreamEvent mask) |
77 |
|
|
{ |
78 |
|
|
if (!mListeners) mListeners = new Array(true); |
79 |
|
|
*mListeners += new Listener(l, mask); |
80 |
|
|
} |
81 |
|
|
*/ |
82 |
|
|
void Stream::checkAccess(IOAccessMode mask) |
83 |
|
|
{ |
84 |
|
|
if (mAccessMode & mask != mask) throw IOException(EACCES); |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
/** |
88 |
|
|
* Copy (whole) stream to another (i.e. copy until EOF) |
89 |
|
|
* @param stream Stream to copy this Stream to |
90 |
|
|
* @returns number of bytes copied |
91 |
|
|
*/ |
92 |
|
|
uint Stream::copyAllTo(Stream *stream) |
93 |
|
|
{ |
94 |
|
|
byte *buf = new byte[STREAM_COPYBUF_SIZE]; |
95 |
|
|
uint result = 0; |
96 |
|
|
uint r, t; |
97 |
|
|
do { |
98 |
|
|
uint k = STREAM_COPYBUF_SIZE; |
99 |
|
|
r = read(buf, k); |
100 |
|
|
ASSERT(r <= k); |
101 |
|
|
t = stream->write(buf, r); |
102 |
|
|
ASSERT(t <= r); |
103 |
|
|
result += t; |
104 |
|
|
if (t != k) break; |
105 |
|
|
} while (t); |
106 |
|
|
delete[] buf; |
107 |
|
|
return result; |
108 |
|
|
} |
109 |
|
|
|
110 |
|
|
/** |
111 |
|
|
* Copy (partial) stream to another |
112 |
|
|
* @param stream Stream to copy this Stream to |
113 |
|
|
* @param count maximum number of bytes to copy |
114 |
|
|
* @returns number of bytes copied |
115 |
|
|
*/ |
116 |
|
|
uint Stream::copyTo(Stream *stream, uint count) |
117 |
|
|
{ |
118 |
|
|
byte *buf = new byte[STREAM_COPYBUF_SIZE]; |
119 |
|
|
uint result = 0; |
120 |
|
|
while (count) { |
121 |
|
|
uint k = STREAM_COPYBUF_SIZE; |
122 |
|
|
if (k > count) k = count; |
123 |
|
|
uint r = read(buf, k); |
124 |
|
|
ASSERT(r <= k); |
125 |
|
|
uint t = stream->write(buf, r); |
126 |
|
|
ASSERT(t <= r); |
127 |
|
|
count -= t; |
128 |
|
|
result += t; |
129 |
|
|
if (t != k) break; |
130 |
|
|
} |
131 |
|
|
delete[] buf; |
132 |
|
|
return result; |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
/** |
136 |
|
|
* Get access-mode |
137 |
|
|
*/ |
138 |
|
|
IOAccessMode Stream::getAccessMode() const |
139 |
|
|
{ |
140 |
|
|
return mAccessMode; |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
/** |
144 |
|
|
* Get descriptive name |
145 |
|
|
*/ |
146 |
|
|
String &Stream::getDesc(String &result) const |
147 |
|
|
{ |
148 |
|
|
result = ""; |
149 |
|
|
return result; |
150 |
|
|
} |
151 |
|
|
/* |
152 |
|
|
void Stream::notifyListeners(StreamEvent event,...) |
153 |
|
|
{ |
154 |
|
|
if (!mListeners) return; |
155 |
|
|
foreach(Listener, l, *mListeners, |
156 |
|
|
if (l->notify_mask & event) { |
157 |
|
|
va_list ap; |
158 |
|
|
va_start(ap, event); |
159 |
|
|
l->listener->handleEvent(event, ap); |
160 |
|
|
va_end(ap); |
161 |
|
|
} |
162 |
|
|
); |
163 |
|
|
} |
164 |
|
|
*/ |
165 |
|
|
/** |
166 |
|
|
* Set access-mode |
167 |
|
|
*/ |
168 |
|
|
int Stream::setAccessMode(IOAccessMode mode) |
169 |
|
|
{ |
170 |
|
|
mAccessMode = mode; |
171 |
|
|
return 0; |
172 |
|
|
} |
173 |
|
|
|
174 |
|
|
/** |
175 |
|
|
* Read from stream. |
176 |
|
|
* Read up to <i>size</i> bytes from stream into <i>buf</i>. |
177 |
|
|
* If less than <i>size</i> bytes are read, the exact number is |
178 |
|
|
* returned and a (temporary) end-of-file (EOF) is encountered. |
179 |
|
|
* |
180 |
|
|
* @param buf pointer to bytes to read |
181 |
|
|
* @param size number of bytes to read |
182 |
|
|
* @returns number of bytes read |
183 |
|
|
* @throws IOException |
184 |
|
|
*/ |
185 |
|
|
uint Stream::read(void *buf, uint size) |
186 |
|
|
{ |
187 |
|
|
return 0; |
188 |
|
|
} |
189 |
|
|
|
190 |
|
|
/** |
191 |
|
|
* Exact read from stream. |
192 |
|
|
* Read exactly <i>size</i> bytes from stream into <i>buf</i>. |
193 |
|
|
* If less than <i>size</i> bytes are read, IOException is thrown. |
194 |
|
|
* |
195 |
|
|
* @param buf pointer to bytes to read |
196 |
|
|
* @param size number of bytes to read |
197 |
|
|
* @throws IOException |
198 |
|
|
*/ |
199 |
|
|
//#include "snprintf.h" |
200 |
|
|
void Stream::readx(void *buf, uint size) |
201 |
|
|
{ |
202 |
|
|
// File *f = dynamic_cast<File*>(this); |
203 |
|
|
// FileOfs t = f ? f->tell() : mkfofs(0); |
204 |
|
|
if (read(buf, size) != size) { |
205 |
|
|
// FileOfs sz = f ? f->getSize() : mkfofs(0); |
206 |
|
|
// ht_printf("readx failed, ofs = 0x%qx, size = %d (file size 0x%qx)\n", t, size, sz); |
207 |
|
|
throw IOException(EIO); |
208 |
|
|
} |
209 |
|
|
} |
210 |
|
|
/* |
211 |
|
|
void Stream::removeEventListener(StreamEventListener *l) |
212 |
|
|
{ |
213 |
|
|
Listener t(l, SEV_NULL); |
214 |
|
|
bool b = (*mListeners -= &t); |
215 |
|
|
ASSERT(b); |
216 |
|
|
} |
217 |
|
|
*/ |
218 |
|
|
/** |
219 |
|
|
* Write to stream. |
220 |
|
|
* Write up to <i>size</i> bytes from <i>buf</i> into stream. |
221 |
|
|
* If less than <i>size</i> bytes are written, the exact number is |
222 |
|
|
* returned and a (temporary) end-of-file (EOF) is encountered. |
223 |
|
|
* |
224 |
|
|
* @param buf pointer to bytes to write |
225 |
|
|
* @param size number of bytes to write |
226 |
|
|
* @returns number of bytes written |
227 |
|
|
* @throws IOException |
228 |
|
|
*/ |
229 |
|
|
uint Stream::write(const void *buf, uint size) |
230 |
|
|
{ |
231 |
|
|
return 0; |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
/** |
235 |
|
|
* Exact write to stream. |
236 |
|
|
* Write exactly <i>size</i> bytes from <i>buf</i> into stream. |
237 |
|
|
* If less than <i>size</i> bytes are written, IOException is thrown. |
238 |
|
|
* |
239 |
|
|
* @param buf pointer to bytes to write |
240 |
|
|
* @param size number of bytes to write |
241 |
|
|
* @throws IOException |
242 |
|
|
*/ |
243 |
|
|
void Stream::writex(const void *buf, uint size) |
244 |
|
|
{ |
245 |
|
|
if (write(buf, size) != size) throw IOException(EIO); |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
/* |
249 |
|
|
* StreamLayer |
250 |
|
|
*/ |
251 |
|
|
|
252 |
|
|
StreamLayer::StreamLayer(Stream *s, bool own) : Stream() |
253 |
|
|
{ |
254 |
|
|
mStream = s; |
255 |
|
|
mOwnStream = own; |
256 |
|
|
} |
257 |
|
|
|
258 |
|
|
StreamLayer::~StreamLayer() |
259 |
|
|
{ |
260 |
|
|
if (mOwnStream) delete mStream; |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
IOAccessMode StreamLayer::getAccessMode() const |
264 |
|
|
{ |
265 |
|
|
return mStream->getAccessMode(); |
266 |
|
|
} |
267 |
|
|
|
268 |
|
|
String &StreamLayer::getDesc(String &result) const |
269 |
|
|
{ |
270 |
|
|
return mStream->getDesc(result); |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
int StreamLayer::setAccessMode(IOAccessMode mode) |
274 |
|
|
{ |
275 |
|
|
return mStream->setAccessMode(mode); |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
uint StreamLayer::read(void *buf, uint size) |
279 |
|
|
{ |
280 |
|
|
return mStream->read(buf, size); |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
uint StreamLayer::write(const void *buf, uint size) |
284 |
|
|
{ |
285 |
|
|
return mStream->write(buf, size); |
286 |
|
|
} |
287 |
|
|
|
288 |
|
|
Stream *StreamLayer::getLayered() const |
289 |
|
|
{ |
290 |
|
|
return mStream; |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
void StreamLayer::setLayered(Stream *newLayered, bool ownNewLayered) |
294 |
|
|
{ |
295 |
|
|
mStream = newLayered; |
296 |
|
|
mOwnStream = ownNewLayered; |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
/* |
300 |
|
|
* A File |
301 |
|
|
*/ |
302 |
|
|
|
303 |
|
|
File::File() |
304 |
|
|
{ |
305 |
|
|
mcount = 0; |
306 |
|
|
} |
307 |
|
|
|
308 |
|
|
#define FILE_TRANSFER_BUFSIZE 4*1024 |
309 |
|
|
/** |
310 |
|
|
* Low-level control function. |
311 |
|
|
* @param cmd file control command number |
312 |
|
|
* @returns 0 on success, POSIX.1 I/O error code on error |
313 |
|
|
*/ |
314 |
|
|
int File::cntl(uint cmd, ...) |
315 |
|
|
{ |
316 |
|
|
va_list vargs; |
317 |
|
|
va_start(vargs, cmd); |
318 |
|
|
int ret = vcntl(cmd, vargs); |
319 |
|
|
va_end(vargs); |
320 |
|
|
return ret; |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
void fileMove(File *file, FileOfs src, FileOfs dest, FileOfs size) |
324 |
|
|
{ |
325 |
|
|
if (dest < src) { |
326 |
|
|
char tbuf[FILE_TRANSFER_BUFSIZE]; |
327 |
|
|
while (size != 0) { |
328 |
|
|
FileOfs k = size; |
329 |
|
|
if (k > sizeof tbuf) k = sizeof tbuf; |
330 |
|
|
file->seek(src); |
331 |
|
|
file->readx(tbuf, k); |
332 |
|
|
file->seek(dest); |
333 |
|
|
file->writex(tbuf, k); |
334 |
|
|
src += k; |
335 |
|
|
dest += k; |
336 |
|
|
size -= k; |
337 |
|
|
} |
338 |
|
|
} else if (dest > src) { |
339 |
|
|
src += size; |
340 |
|
|
dest += size; |
341 |
|
|
char tbuf[FILE_TRANSFER_BUFSIZE]; |
342 |
|
|
while (size != 0) { |
343 |
|
|
FileOfs k = size; |
344 |
|
|
if (k > sizeof tbuf) k = sizeof tbuf; |
345 |
|
|
src -= k; |
346 |
|
|
dest -= k; |
347 |
|
|
file->seek(src); |
348 |
|
|
file->readx(tbuf, k); |
349 |
|
|
file->seek(dest); |
350 |
|
|
file->writex(tbuf, k); |
351 |
|
|
size -= k; |
352 |
|
|
} |
353 |
|
|
} |
354 |
|
|
} |
355 |
|
|
|
356 |
|
|
/** |
357 |
|
|
* Delete bytes from file. |
358 |
|
|
* Delete <i>size</i> bytes at current file pointer and shorten file |
359 |
|
|
* accordingly. |
360 |
|
|
Does not modify the current file pointer. |
361 |
|
|
* |
362 |
|
|
* @param size number of bytes to delete |
363 |
|
|
* @throws IOException |
364 |
|
|
*/ |
365 |
|
|
void File::del(uint size) |
366 |
|
|
{ |
367 |
|
|
FileOfs t = tell(); |
368 |
|
|
FileOfs o = t+size; |
369 |
|
|
if (o > getSize()) throw IOException(EINVAL); |
370 |
|
|
FileOfs s = getSize()-o; |
371 |
|
|
fileMove(this, o, t, s); |
372 |
|
|
truncate(getSize()-size); |
373 |
|
|
seek(t); |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
/** |
377 |
|
|
* Extend file. |
378 |
|
|
* Extend file to new size <i>newsize</i>. |
379 |
|
|
* The current file pointer is undefined (but valid) after this operation. |
380 |
|
|
* |
381 |
|
|
* @param newsize new extended file size |
382 |
|
|
* @throws IOException |
383 |
|
|
*/ |
384 |
|
|
void File::extend(FileOfs newsize) |
385 |
|
|
{ |
386 |
|
|
if (getSize() > newsize) throw IOException(EINVAL); |
387 |
|
|
if (getSize() == newsize) return; |
388 |
|
|
|
389 |
|
|
FileOfs save_ofs = tell(); |
390 |
|
|
int e = 0; |
391 |
|
|
|
392 |
|
|
IOAccessMode oldmode = getAccessMode(); |
393 |
|
|
if (!(oldmode & IOAM_WRITE)) { |
394 |
|
|
int f = setAccessMode(oldmode | IOAM_WRITE); |
395 |
|
|
if (f) throw IOException(f); |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
FileOfs s = getSize(); |
399 |
|
|
char buf[FILE_TRANSFER_BUFSIZE]; |
400 |
|
|
memset(buf, 0, sizeof buf); |
401 |
|
|
newsize -= s; |
402 |
|
|
seek(s); |
403 |
|
|
while (newsize != 0) { |
404 |
|
|
uint k = MIN(sizeof buf, newsize); |
405 |
|
|
uint l = write(buf, k); |
406 |
|
|
if (l != k) { |
407 |
|
|
e = EIO; |
408 |
|
|
break; |
409 |
|
|
} |
410 |
|
|
newsize -= l; |
411 |
|
|
} |
412 |
|
|
|
413 |
|
|
if (!(oldmode & IOAM_WRITE)) { |
414 |
|
|
int f = setAccessMode(oldmode); |
415 |
|
|
if (f) e = f; |
416 |
|
|
} |
417 |
|
|
if (e) throw IOException(e); |
418 |
|
|
seek(save_ofs); |
419 |
|
|
} |
420 |
|
|
|
421 |
|
|
/** |
422 |
|
|
* Get filename. |
423 |
|
|
* |
424 |
|
|
* @param result String that receives the filename |
425 |
|
|
* @returns its argument |
426 |
|
|
*/ |
427 |
|
|
String &File::getFilename(String &result) const |
428 |
|
|
{ |
429 |
|
|
result = ""; |
430 |
|
|
return result; |
431 |
|
|
} |
432 |
|
|
|
433 |
|
|
/** |
434 |
|
|
* Get file size. |
435 |
|
|
* |
436 |
|
|
* @returns file size |
437 |
|
|
*/ |
438 |
|
|
FileOfs File::getSize() const |
439 |
|
|
{ |
440 |
|
|
return 0; |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
#define FILE_INSERT_BUFSIZE 4*1024 |
444 |
|
|
/** |
445 |
|
|
* Insert bytes into file. |
446 |
|
|
* Insert <i>size</i> bytes from <i>buf</i> at the current file pointer |
447 |
|
|
* into the file and extend file accordingly. |
448 |
|
|
* |
449 |
|
|
* @param buf pointer to buffer that holds at least <i>size</i> bytes |
450 |
|
|
* @param size number of bytes to insert |
451 |
|
|
* @throws IOException |
452 |
|
|
*/ |
453 |
|
|
void File::insert(const void *buf, uint size) |
454 |
|
|
{ |
455 |
|
|
FileOfs t = tell(); |
456 |
|
|
FileOfs s = getSize()-t; |
457 |
|
|
extend(getSize()+size); |
458 |
|
|
fileMove(this, t, t+size, s); |
459 |
|
|
seek(t); |
460 |
|
|
writex(buf, size); |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
/** |
464 |
|
|
* Get file status in a portable way. |
465 |
|
|
* @param s structure that receives the file status |
466 |
|
|
*/ |
467 |
|
|
void File::pstat(pstat_t &s) const |
468 |
|
|
{ |
469 |
|
|
s.caps = 0; |
470 |
|
|
} |
471 |
|
|
|
472 |
|
|
/** |
473 |
|
|
* Set current file pointer. |
474 |
|
|
* @param offset new value for current file pointer |
475 |
|
|
*/ |
476 |
|
|
void File::seek(FileOfs offset) |
477 |
|
|
{ |
478 |
|
|
throw NotImplementedException(HERE); |
479 |
|
|
} |
480 |
|
|
|
481 |
|
|
/** |
482 |
|
|
* Get current file pointer. |
483 |
|
|
* @returns current file pointer |
484 |
|
|
*/ |
485 |
|
|
FileOfs File::tell() const |
486 |
|
|
{ |
487 |
|
|
return 0; |
488 |
|
|
} |
489 |
|
|
|
490 |
|
|
/** |
491 |
|
|
* Truncate file. |
492 |
|
|
* Truncate file to new size <i>newsize</i>. |
493 |
|
|
* The current file pointer is undefined (but valid) after this operation. |
494 |
|
|
* |
495 |
|
|
* @param newsize new truncated file size |
496 |
|
|
* @throws IOException |
497 |
|
|
*/ |
498 |
|
|
void File::truncate(FileOfs newsize) |
499 |
|
|
{ |
500 |
|
|
if (getSize() < newsize) throw IOException(EINVAL); |
501 |
|
|
if (getSize() == newsize) return; |
502 |
|
|
|
503 |
|
|
throw NotImplementedException(HERE); |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
/** |
507 |
|
|
* Vararg wrapper for cntl() |
508 |
|
|
*/ |
509 |
|
|
int File::vcntl(uint cmd, va_list vargs) |
510 |
|
|
{ |
511 |
|
|
switch (cmd) { |
512 |
|
|
case FCNTL_GET_MOD_COUNT: { // int &mcount |
513 |
|
|
int *mc = va_arg(vargs, int *); |
514 |
|
|
*mc = mcount; |
515 |
|
|
return 0; |
516 |
|
|
} |
517 |
|
|
} |
518 |
|
|
return ENOSYS; |
519 |
|
|
} |
520 |
|
|
|
521 |
|
|
/* |
522 |
|
|
* FileLayer |
523 |
|
|
*/ |
524 |
|
|
FileLayer::FileLayer(File *f, bool own_f) : File() |
525 |
|
|
{ |
526 |
|
|
mFile = f; |
527 |
|
|
mOwnFile = own_f; |
528 |
|
|
} |
529 |
|
|
|
530 |
|
|
FileLayer::~FileLayer() |
531 |
|
|
{ |
532 |
|
|
if (mOwnFile) delete mFile; |
533 |
|
|
} |
534 |
|
|
|
535 |
|
|
void FileLayer::del(uint size) |
536 |
|
|
{ |
537 |
|
|
return mFile->del(size); |
538 |
|
|
} |
539 |
|
|
|
540 |
|
|
void FileLayer::extend(FileOfs newsize) |
541 |
|
|
{ |
542 |
|
|
return mFile->extend(newsize); |
543 |
|
|
} |
544 |
|
|
|
545 |
|
|
IOAccessMode FileLayer::getAccessMode() const |
546 |
|
|
{ |
547 |
|
|
return mFile->getAccessMode(); |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
String &FileLayer::getDesc(String &result) const |
551 |
|
|
{ |
552 |
|
|
return mFile->getDesc(result); |
553 |
|
|
} |
554 |
|
|
|
555 |
|
|
String &FileLayer::getFilename(String &result) const |
556 |
|
|
{ |
557 |
|
|
return mFile->getFilename(result); |
558 |
|
|
} |
559 |
|
|
|
560 |
|
|
FileOfs FileLayer::getSize() const |
561 |
|
|
{ |
562 |
|
|
return mFile->getSize(); |
563 |
|
|
} |
564 |
|
|
|
565 |
|
|
void FileLayer::insert(const void *buf, uint size) |
566 |
|
|
{ |
567 |
|
|
return mFile->insert(buf, size); |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
void FileLayer::pstat(pstat_t &s) const |
571 |
|
|
{ |
572 |
|
|
return mFile->pstat(s); |
573 |
|
|
} |
574 |
|
|
|
575 |
|
|
uint FileLayer::read(void *buf, uint size) |
576 |
|
|
{ |
577 |
|
|
return mFile->read(buf, size); |
578 |
|
|
} |
579 |
|
|
|
580 |
|
|
void FileLayer::seek(FileOfs offset) |
581 |
|
|
{ |
582 |
|
|
return mFile->seek(offset); |
583 |
|
|
} |
584 |
|
|
|
585 |
|
|
int FileLayer::setAccessMode(IOAccessMode mode) |
586 |
|
|
{ |
587 |
|
|
return mFile->setAccessMode(mode); |
588 |
|
|
} |
589 |
|
|
|
590 |
|
|
File *FileLayer::getLayered() const |
591 |
|
|
{ |
592 |
|
|
return mFile; |
593 |
|
|
} |
594 |
|
|
|
595 |
|
|
void FileLayer::setLayered(File *newLayered, bool ownNewLayered) |
596 |
|
|
{ |
597 |
|
|
mFile = newLayered; |
598 |
|
|
mOwnFile = ownNewLayered; |
599 |
|
|
} |
600 |
|
|
|
601 |
|
|
FileOfs FileLayer::tell() const |
602 |
|
|
{ |
603 |
|
|
return mFile->tell(); |
604 |
|
|
} |
605 |
|
|
|
606 |
|
|
void FileLayer::truncate(FileOfs newsize) |
607 |
|
|
{ |
608 |
|
|
return mFile->truncate(newsize); |
609 |
|
|
} |
610 |
|
|
|
611 |
|
|
int FileLayer::vcntl(uint cmd, va_list vargs) |
612 |
|
|
{ |
613 |
|
|
return mFile->vcntl(cmd, vargs); |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
uint FileLayer::write(const void *buf, uint size) |
617 |
|
|
{ |
618 |
|
|
return mFile->write(buf, size); |
619 |
|
|
} |
620 |
|
|
|
621 |
|
|
#if 0 |
622 |
|
|
/* |
623 |
|
|
* LocalFileFD |
624 |
|
|
*/ |
625 |
|
|
|
626 |
|
|
/** |
627 |
|
|
* create open file |
628 |
|
|
*/ |
629 |
|
|
LocalFileFD::LocalFileFD(const String &aFilename, IOAccessMode am, FileOpenMode om) |
630 |
|
|
: File(), mFilename(aFilename) |
631 |
|
|
{ |
632 |
|
|
mOpenMode = om; |
633 |
|
|
fd = -1; |
634 |
|
|
own_fd = false; |
635 |
|
|
int e = setAccessMode(am); |
636 |
|
|
if (e) throw IOException(e); |
637 |
|
|
mOpenMode = FOM_EXISTS; |
638 |
|
|
} |
639 |
|
|
|
640 |
|
|
/** |
641 |
|
|
* map a file descriptor [fd] |
642 |
|
|
*/ |
643 |
|
|
LocalFileFD::LocalFileFD(int f, bool own_f, IOAccessMode am) |
644 |
|
|
: File() |
645 |
|
|
{ |
646 |
|
|
mFilename = NULL; |
647 |
|
|
fd = f; |
648 |
|
|
own_fd = own_f; |
649 |
|
|
offset = 0; |
650 |
|
|
int e = File::setAccessMode(am); |
651 |
|
|
if (e) throw IOException(e); |
652 |
|
|
} |
653 |
|
|
|
654 |
|
|
LocalFileFD::~LocalFileFD() |
655 |
|
|
{ |
656 |
|
|
if (own_fd && (fd>=0)) ::close(fd); |
657 |
|
|
} |
658 |
|
|
|
659 |
|
|
String &LocalFileFD::getDesc(String &result) const |
660 |
|
|
{ |
661 |
|
|
result = mFilename; |
662 |
|
|
return result; |
663 |
|
|
} |
664 |
|
|
|
665 |
|
|
String &LocalFileFD::getFilename(String &result) const |
666 |
|
|
{ |
667 |
|
|
result = mFilename; |
668 |
|
|
return result; |
669 |
|
|
} |
670 |
|
|
|
671 |
|
|
FileOfs LocalFileFD::getSize() const |
672 |
|
|
{ |
673 |
|
|
uint t = tell(); |
674 |
|
|
uint r = ::lseek(fd, 0, SEEK_END); |
675 |
|
|
lseek(fd, t, SEEK_SET); |
676 |
|
|
return r; |
677 |
|
|
} |
678 |
|
|
|
679 |
|
|
uint LocalFileFD::read(void *buf, uint size) |
680 |
|
|
{ |
681 |
|
|
if (!(getAccessMode() & IOAM_READ)) throw IOException(EACCES); |
682 |
|
|
errno = 0; |
683 |
|
|
uint r = ::read(fd, buf, size); |
684 |
|
|
int e = errno; |
685 |
|
|
if (e) { |
686 |
|
|
off_t r = ::lseek(fd, 0, SEEK_SET); |
687 |
|
|
offset = r; |
688 |
|
|
if (e != EAGAIN) throw IOException(e); |
689 |
|
|
return 0; |
690 |
|
|
} else { |
691 |
|
|
offset += r; |
692 |
|
|
return r; |
693 |
|
|
} |
694 |
|
|
} |
695 |
|
|
|
696 |
|
|
void LocalFileFD::seek(FileOfs o) |
697 |
|
|
{ |
698 |
|
|
if (o == offset) return; |
699 |
|
|
off_t r = ::lseek(fd, o, SEEK_SET); |
700 |
|
|
offset = r; |
701 |
|
|
if (offset != o) throw IOException(EIO); |
702 |
|
|
} |
703 |
|
|
|
704 |
|
|
int LocalFileFD::setAccessMode(IOAccessMode am) |
705 |
|
|
{ |
706 |
|
|
IOAccessMode orig_access_mode = getAccessMode(); |
707 |
|
|
int e = setAccessModeInternal(am); |
708 |
|
|
if (e && setAccessModeInternal(orig_access_mode)) |
709 |
|
|
throw IOException(e); |
710 |
|
|
return e; |
711 |
|
|
} |
712 |
|
|
|
713 |
|
|
int LocalFileFD::setAccessModeInternal(IOAccessMode am) |
714 |
|
|
{ |
715 |
|
|
//RETRY: |
716 |
|
|
if (getAccessMode() == am) return 0; |
717 |
|
|
if (fd >= 0) { |
718 |
|
|
// must own fd to change its access mode cause we can't |
719 |
|
|
// reopen a fd. right ? |
720 |
|
|
if (!own_fd) throw NotImplementedException(HERE); |
721 |
|
|
// FIXME: race condition here, how to reopen a fd atomically ? |
722 |
|
|
close(fd); |
723 |
|
|
fd = -1; |
724 |
|
|
} |
725 |
|
|
File::setAccessMode(IOAM_NULL); |
726 |
|
|
|
727 |
|
|
int mode = 0; |
728 |
|
|
|
729 |
|
|
if ((am & IOAM_READ) && (am & IOAM_WRITE)) mode = O_RDWR; |
730 |
|
|
else if (am & IOAM_READ) mode = O_RDONLY; |
731 |
|
|
else if (am & IOAM_WRITE) mode = O_WRONLY; |
732 |
|
|
|
733 |
|
|
// mode |= O_BINARY; |
734 |
|
|
|
735 |
|
|
switch (mOpenMode) { |
736 |
|
|
case FOM_APPEND: |
737 |
|
|
mode |= O_APPEND; |
738 |
|
|
break; |
739 |
|
|
case FOM_CREATE: |
740 |
|
|
mode |= O_CREAT | O_TRUNC; |
741 |
|
|
break; |
742 |
|
|
case FOM_EXISTS: |
743 |
|
|
; |
744 |
|
|
} |
745 |
|
|
|
746 |
|
|
int e = 0; |
747 |
|
|
if (am != IOAM_NULL) { |
748 |
|
|
pstat_t s; |
749 |
|
|
fd = ::open(mFilename, mode); |
750 |
|
|
if (fd < 0) e = errno; |
751 |
|
|
if (!e) { |
752 |
|
|
own_fd = true; |
753 |
|
|
e = sys_pstat_fd(s, fd); |
754 |
|
|
if (!e) { |
755 |
|
|
if (HT_S_ISDIR(s.mode)) { |
756 |
|
|
e = EISDIR; |
757 |
|
|
} else if (!HT_S_ISREG(s.mode) && !HT_S_ISBLK(s.mode)) { |
758 |
|
|
e = EINVAL; |
759 |
|
|
} |
760 |
|
|
} |
761 |
|
|
} |
762 |
|
|
} |
763 |
|
|
return e ? e : File::setAccessMode(am); |
764 |
|
|
} |
765 |
|
|
|
766 |
|
|
FileOfs LocalFileFD::tell() const |
767 |
|
|
{ |
768 |
|
|
return offset; |
769 |
|
|
} |
770 |
|
|
|
771 |
|
|
void LocalFileFD::truncate(FileOfs newsize) |
772 |
|
|
{ |
773 |
|
|
errno = 0; |
774 |
|
|
int e = sys_truncate_fd(fd, newsize); |
775 |
|
|
if (errno) e = errno; |
776 |
|
|
if (e) throw IOException(e); |
777 |
|
|
} |
778 |
|
|
|
779 |
|
|
int LocalFileFD::vcntl(uint cmd, va_list vargs) |
780 |
|
|
{ |
781 |
|
|
switch (cmd) { |
782 |
|
|
case FCNTL_FLUSH_STAT: { |
783 |
|
|
IOAccessMode m = getAccessMode(); |
784 |
|
|
int e, f; |
785 |
|
|
e = setAccessMode(IOAM_NULL); |
786 |
|
|
f = setAccessMode(m); |
787 |
|
|
return e ? e : f; |
788 |
|
|
} |
789 |
|
|
case FCNTL_GET_FD: { // (int &fd) |
790 |
|
|
int *pfd = va_arg(vargs, int*); |
791 |
|
|
*pfd = fd; |
792 |
|
|
return 0; |
793 |
|
|
} |
794 |
|
|
} |
795 |
|
|
return File::vcntl(cmd, vargs); |
796 |
|
|
} |
797 |
|
|
|
798 |
|
|
uint LocalFileFD::write(const void *buf, uint size) |
799 |
|
|
{ |
800 |
|
|
if (!(getAccessMode() & IOAM_WRITE)) throw IOException(EACCES); |
801 |
|
|
errno = 0; |
802 |
|
|
uint r = ::write(fd, buf, size); |
803 |
|
|
int e = errno; |
804 |
|
|
if (e) { |
805 |
|
|
off_t r = ::lseek(fd, 0, SEEK_SET); |
806 |
|
|
offset = r; |
807 |
|
|
if (e != EAGAIN) throw IOException(e); |
808 |
|
|
return 0; |
809 |
|
|
} else { |
810 |
|
|
offset += r; |
811 |
|
|
return r; |
812 |
|
|
} |
813 |
|
|
} |
814 |
|
|
#endif |
815 |
|
|
|
816 |
|
|
/* |
817 |
|
|
* StdIoFile |
818 |
|
|
*/ |
819 |
|
|
|
820 |
|
|
/** |
821 |
|
|
* create open file |
822 |
|
|
*/ |
823 |
|
|
LocalFile::LocalFile(const String &aFilename, IOAccessMode am, FileOpenMode om) |
824 |
|
|
: File(), mFilename(aFilename) |
825 |
|
|
{ |
826 |
|
|
mOpenMode = om; |
827 |
|
|
file = NULL; |
828 |
|
|
own_file = false; |
829 |
|
|
offset = 0; |
830 |
|
|
int e = setAccessMode(am); |
831 |
|
|
if (e) throw IOException(e); |
832 |
|
|
mOpenMode = FOM_EXISTS; |
833 |
|
|
} |
834 |
|
|
|
835 |
|
|
/** |
836 |
|
|
* map a file stream [FILE*] |
837 |
|
|
*/ |
838 |
|
|
LocalFile::LocalFile(FILE *f, bool own_f, IOAccessMode am) |
839 |
|
|
: File() |
840 |
|
|
{ |
841 |
|
|
mFilename = NULL; |
842 |
|
|
file = f; |
843 |
|
|
own_file = own_f; |
844 |
|
|
int e = LocalFile::setAccessMode(am); |
845 |
|
|
if (e) throw IOException(e); |
846 |
|
|
} |
847 |
|
|
|
848 |
|
|
LocalFile::~LocalFile() |
849 |
|
|
{ |
850 |
|
|
if (own_file && file) fclose(file); |
851 |
|
|
} |
852 |
|
|
|
853 |
|
|
String &LocalFile::getDesc(String &result) const |
854 |
|
|
{ |
855 |
|
|
result = mFilename; |
856 |
|
|
return result; |
857 |
|
|
} |
858 |
|
|
|
859 |
|
|
String &LocalFile::getFilename(String &result) const |
860 |
|
|
{ |
861 |
|
|
result = mFilename; |
862 |
|
|
return result; |
863 |
|
|
} |
864 |
|
|
|
865 |
|
|
FileOfs LocalFile::getSize() const |
866 |
|
|
{ |
867 |
|
|
int t = tell(); |
868 |
|
|
fseek(file, 0, SEEK_END); |
869 |
|
|
int r = ftell(file); |
870 |
|
|
fseek(file, t, SEEK_SET); |
871 |
|
|
return r; |
872 |
|
|
} |
873 |
|
|
|
874 |
|
|
void LocalFile::pstat(pstat_t &s) const |
875 |
|
|
{ |
876 |
|
|
sys_pstat(s, mFilename.contentChar()); |
877 |
|
|
} |
878 |
|
|
|
879 |
|
|
uint LocalFile::read(void *buf, uint size) |
880 |
|
|
{ |
881 |
|
|
if (!(getAccessMode() & IOAM_READ)) throw IOException(EACCES); |
882 |
|
|
errno = 0; |
883 |
|
|
uint r = fread(buf, 1, size, file); |
884 |
|
|
if (errno) throw IOException(errno); |
885 |
|
|
offset += r; |
886 |
|
|
return r; |
887 |
|
|
} |
888 |
|
|
|
889 |
|
|
void LocalFile::seek(FileOfs o) |
890 |
|
|
{ |
891 |
|
|
if (o == offset) return; |
892 |
|
|
int e = fseek(file, o, SEEK_SET); |
893 |
|
|
if (e) throw IOException(e); |
894 |
|
|
offset = o; // unreliable for DJGPP |
895 |
|
|
} |
896 |
|
|
|
897 |
|
|
int LocalFile::setAccessMode(IOAccessMode am) |
898 |
|
|
{ |
899 |
|
|
IOAccessMode orig_access_mode = getAccessMode(); |
900 |
|
|
int e = setAccessModeInternal(am); |
901 |
|
|
if (e && setAccessModeInternal(orig_access_mode)) |
902 |
|
|
throw IOException(e); |
903 |
|
|
return e; |
904 |
|
|
} |
905 |
|
|
|
906 |
|
|
int LocalFile::setAccessModeInternal(IOAccessMode am) |
907 |
|
|
{ |
908 |
|
|
//RETRY: |
909 |
|
|
if (getAccessMode() == am) return 0; |
910 |
|
|
char *mode = NULL; |
911 |
|
|
|
912 |
|
|
switch (mOpenMode) { |
913 |
|
|
case FOM_APPEND: |
914 |
|
|
mode = "ab+"; |
915 |
|
|
break; |
916 |
|
|
case FOM_CREATE: |
917 |
|
|
if (am & IOAM_WRITE) mode = "wb"; |
918 |
|
|
if (am & IOAM_READ) mode = "wb+"; |
919 |
|
|
break; |
920 |
|
|
case FOM_EXISTS: |
921 |
|
|
if (am & IOAM_READ) mode = "rb"; |
922 |
|
|
if (am & IOAM_WRITE) mode = "rb+"; |
923 |
|
|
break; |
924 |
|
|
} |
925 |
|
|
|
926 |
|
|
int e = 0; |
927 |
|
|
if (am != IOAM_NULL) { |
928 |
|
|
pstat_t s; |
929 |
|
|
if (file) { |
930 |
|
|
file = freopen(mFilename.contentChar(), mode, file); |
931 |
|
|
if (!file) setAccessMode(IOAM_NULL); |
932 |
|
|
} else { |
933 |
|
|
file = fopen(mFilename.contentChar(), mode); |
934 |
|
|
} |
935 |
|
|
if (!file) e = errno; |
936 |
|
|
if (!e) { |
937 |
|
|
own_file = true; |
938 |
|
|
e = sys_pstat_fd(s, fileno(file)); |
939 |
|
|
if (!e) { |
940 |
|
|
if (HT_S_ISDIR(s.mode)) { |
941 |
|
|
e = EISDIR; |
942 |
|
|
} else if (!HT_S_ISREG(s.mode) && !HT_S_ISBLK(s.mode)) { |
943 |
|
|
e = EINVAL; |
944 |
|
|
} |
945 |
|
|
} |
946 |
|
|
} |
947 |
|
|
} |
948 |
|
|
return e ? e : File::setAccessMode(am); |
949 |
|
|
} |
950 |
|
|
|
951 |
|
|
FileOfs LocalFile::tell() const |
952 |
|
|
{ |
953 |
|
|
return offset; |
954 |
|
|
} |
955 |
|
|
|
956 |
|
|
void LocalFile::truncate(FileOfs newsize) |
957 |
|
|
{ |
958 |
|
|
errno = 0; |
959 |
|
|
|
960 |
|
|
IOAccessMode old_am = getAccessMode(); |
961 |
|
|
int e; |
962 |
|
|
e = setAccessMode(IOAM_NULL); |
963 |
|
|
if (!e) { |
964 |
|
|
e = sys_truncate(mFilename.contentChar(), newsize); |
965 |
|
|
if (errno) e = errno; |
966 |
|
|
} |
967 |
|
|
if (!e) e = setAccessMode(old_am); |
968 |
|
|
if (e) throw IOException(e); |
969 |
|
|
} |
970 |
|
|
|
971 |
|
|
int LocalFile::vcntl(uint cmd, va_list vargs) |
972 |
|
|
{ |
973 |
|
|
switch (cmd) { |
974 |
|
|
case FCNTL_FLUSH_STAT: { |
975 |
|
|
IOAccessMode m = getAccessMode(); |
976 |
|
|
int e, f; |
977 |
|
|
e = setAccessMode(IOAM_NULL); |
978 |
|
|
f = setAccessMode(m); |
979 |
|
|
return e ? e : f; |
980 |
|
|
} |
981 |
|
|
case FCNTL_GET_FD: { // (int &fd) |
982 |
|
|
if (file) { |
983 |
|
|
int *pfd = va_arg(vargs, int*); |
984 |
|
|
*pfd = fileno(file); |
985 |
|
|
return 0; |
986 |
|
|
} |
987 |
|
|
break; |
988 |
|
|
} |
989 |
|
|
} |
990 |
|
|
return File::vcntl(cmd, vargs); |
991 |
|
|
} |
992 |
|
|
|
993 |
|
|
uint LocalFile::write(const void *buf, uint size) |
994 |
|
|
{ |
995 |
|
|
if (!(getAccessMode() & IOAM_WRITE)) throw IOException(EACCES); |
996 |
|
|
errno = 0; |
997 |
|
|
uint r = fwrite(buf, 1, size, file); |
998 |
|
|
if (errno) throw IOException(errno); |
999 |
|
|
offset += r; |
1000 |
|
|
return r; |
1001 |
|
|
} |
1002 |
|
|
|
1003 |
|
|
/* |
1004 |
|
|
* TempFile |
1005 |
|
|
*/ |
1006 |
|
|
TempFile::TempFile(uint am) : LocalFile(tmpfile(), true, am) |
1007 |
|
|
{ |
1008 |
|
|
} |
1009 |
|
|
|
1010 |
|
|
String &TempFile::getDesc(String &result) const |
1011 |
|
|
{ |
1012 |
|
|
result = "temporary file"; |
1013 |
|
|
return result; |
1014 |
|
|
} |
1015 |
|
|
|
1016 |
|
|
void TempFile::pstat(pstat_t &s) const |
1017 |
|
|
{ |
1018 |
|
|
s.caps = pstat_size; |
1019 |
|
|
s.size = getSize(); |
1020 |
|
|
} |
1021 |
|
|
|
1022 |
|
|
/* |
1023 |
|
|
* MemMapFile |
1024 |
|
|
*/ |
1025 |
|
|
MemMapFile::MemMapFile(void *b, uint s) : ConstMemMapFile(b, s) |
1026 |
|
|
{ |
1027 |
|
|
} |
1028 |
|
|
|
1029 |
|
|
uint MemMapFile::write(const void *b, uint size) |
1030 |
|
|
{ |
1031 |
|
|
if (pos > this->size) return 0; // or throw exception? |
1032 |
|
|
if (pos+size > this->size) size = this->size - pos; |
1033 |
|
|
memmove(((byte*)buf)+pos, b, size); |
1034 |
|
|
pos += size; |
1035 |
|
|
return size; |
1036 |
|
|
} |
1037 |
|
|
|
1038 |
|
|
/* |
1039 |
|
|
* ConstMemMapFile |
1040 |
|
|
*/ |
1041 |
|
|
ConstMemMapFile::ConstMemMapFile(const void *b, uint s) |
1042 |
|
|
: File() |
1043 |
|
|
{ |
1044 |
|
|
buf = b; |
1045 |
|
|
pos = 0; |
1046 |
|
|
size = s; |
1047 |
|
|
} |
1048 |
|
|
|
1049 |
|
|
String &ConstMemMapFile::getDesc(String &result) const |
1050 |
|
|
{ |
1051 |
|
|
result = "MemMapFile"; |
1052 |
|
|
return result; |
1053 |
|
|
} |
1054 |
|
|
|
1055 |
|
|
FileOfs ConstMemMapFile::getSize() const |
1056 |
|
|
{ |
1057 |
|
|
return size; |
1058 |
|
|
} |
1059 |
|
|
|
1060 |
|
|
uint ConstMemMapFile::read(void *b, uint size) |
1061 |
|
|
{ |
1062 |
|
|
if (pos > this->size) return 0; |
1063 |
|
|
if (pos+size > this->size) size = this->size - pos; |
1064 |
|
|
memmove(b, (const byte*)buf+pos, size); |
1065 |
|
|
pos += size; |
1066 |
|
|
return size; |
1067 |
|
|
} |
1068 |
|
|
|
1069 |
|
|
void ConstMemMapFile::seek(FileOfs offset) |
1070 |
|
|
{ |
1071 |
|
|
pos = offset; |
1072 |
|
|
} |
1073 |
|
|
|
1074 |
|
|
FileOfs ConstMemMapFile::tell() const |
1075 |
|
|
{ |
1076 |
|
|
return pos; |
1077 |
|
|
} |
1078 |
|
|
|
1079 |
|
|
/* |
1080 |
|
|
* A file layer, representing a cropped version of a file |
1081 |
|
|
*/ |
1082 |
|
|
CroppedFile::CroppedFile(File *file, bool own_file, FileOfs aCropStart, FileOfs aCropSize) |
1083 |
|
|
: FileLayer(file, own_file) |
1084 |
|
|
{ |
1085 |
|
|
mCropStart = aCropStart; |
1086 |
|
|
mHasCropSize = true; |
1087 |
|
|
mCropSize = aCropSize; |
1088 |
|
|
seek(0); |
1089 |
|
|
} |
1090 |
|
|
|
1091 |
|
|
CroppedFile::CroppedFile(File *file, bool own_file, FileOfs aCropStart) |
1092 |
|
|
: FileLayer(file, own_file) |
1093 |
|
|
{ |
1094 |
|
|
mCropStart = aCropStart; |
1095 |
|
|
mHasCropSize = false; |
1096 |
|
|
seek(0); |
1097 |
|
|
} |
1098 |
|
|
|
1099 |
|
|
void CroppedFile::extend(FileOfs newsize) |
1100 |
|
|
{ |
1101 |
|
|
throw IOException(ENOSYS); |
1102 |
|
|
} |
1103 |
|
|
|
1104 |
|
|
String &CroppedFile::getDesc(String &result) const |
1105 |
|
|
{ |
1106 |
|
|
String s; |
1107 |
|
|
if (mHasCropSize) { |
1108 |
|
|
result.assignFormat("[->0x%qx,0x%qx] of %y", mCropStart, mCropSize, &FileLayer::getDesc(s)); |
1109 |
|
|
} else { |
1110 |
|
|
result.assignFormat("[->0x%qx] of %y", mCropStart, &FileLayer::getDesc(s)); |
1111 |
|
|
} |
1112 |
|
|
return result; |
1113 |
|
|
} |
1114 |
|
|
|
1115 |
|
|
FileOfs CroppedFile::getSize() const |
1116 |
|
|
{ |
1117 |
|
|
FileOfs lsize = FileLayer::getSize(); |
1118 |
|
|
if (lsize < mCropStart) return 0; |
1119 |
|
|
lsize -= mCropStart; |
1120 |
|
|
if (mHasCropSize) { |
1121 |
|
|
if (lsize > mCropSize) lsize = mCropSize; |
1122 |
|
|
} |
1123 |
|
|
return lsize; |
1124 |
|
|
} |
1125 |
|
|
|
1126 |
|
|
void CroppedFile::pstat(pstat_t &s) const |
1127 |
|
|
{ |
1128 |
|
|
FileLayer::pstat(s); |
1129 |
|
|
if (s.caps & pstat_size) { |
1130 |
|
|
s.size = getSize(); |
1131 |
|
|
} |
1132 |
|
|
} |
1133 |
|
|
|
1134 |
|
|
uint CroppedFile::read(void *buf, uint size) |
1135 |
|
|
{ |
1136 |
|
|
FileOfs offset = FileLayer::tell(); |
1137 |
|
|
if (offset<mCropStart) return 0; |
1138 |
|
|
if (mHasCropSize) { |
1139 |
|
|
if (offset >= mCropStart+mCropSize) return 0; |
1140 |
|
|
if (offset+size >= mCropStart+mCropSize) size = mCropStart+mCropSize-offset; |
1141 |
|
|
} |
1142 |
|
|
// ht_printf("CroppedFile::read 0x%08x bytes @ 0x%08qx\n", size, offset); |
1143 |
|
|
return FileLayer::read(buf, size); |
1144 |
|
|
} |
1145 |
|
|
|
1146 |
|
|
void CroppedFile::seek(FileOfs offset) |
1147 |
|
|
{ |
1148 |
|
|
/* if (mHasCropSize) { |
1149 |
|
|
... |
1150 |
|
|
if (offset>mCropStart) throw IOException(EIO); |
1151 |
|
|
}*/ |
1152 |
|
|
FileLayer::seek(offset+mCropStart); |
1153 |
|
|
} |
1154 |
|
|
|
1155 |
|
|
FileOfs CroppedFile::tell() const |
1156 |
|
|
{ |
1157 |
|
|
FileOfs offset = FileLayer::tell(); |
1158 |
|
|
if (offset<mCropStart) throw IOException(EIO); |
1159 |
|
|
return offset - mCropStart; |
1160 |
|
|
} |
1161 |
|
|
|
1162 |
|
|
void CroppedFile::truncate(FileOfs newsize) |
1163 |
|
|
{ |
1164 |
|
|
// not implemented because not considered safe |
1165 |
|
|
throw IOException(ENOSYS); |
1166 |
|
|
} |
1167 |
|
|
|
1168 |
|
|
uint CroppedFile::write(const void *buf, uint size) |
1169 |
|
|
{ |
1170 |
|
|
FileOfs offset = FileLayer::tell(); |
1171 |
|
|
if (offset<mCropStart) return 0; |
1172 |
|
|
if (mHasCropSize) { |
1173 |
|
|
if (offset >= mCropStart+mCropSize) return 0; |
1174 |
|
|
if (offset+size >= mCropStart+mCropSize) size = mCropStart+mCropSize-offset; |
1175 |
|
|
} |
1176 |
|
|
return FileLayer::write(buf, size); |
1177 |
|
|
} |
1178 |
|
|
|
1179 |
|
|
/* |
1180 |
|
|
* NullFile |
1181 |
|
|
*/ |
1182 |
|
|
NullFile::NullFile() : File() |
1183 |
|
|
{ |
1184 |
|
|
} |
1185 |
|
|
|
1186 |
|
|
void NullFile::extend(FileOfs newsize) |
1187 |
|
|
{ |
1188 |
|
|
if (newsize!=0) throw IOException(EINVAL); |
1189 |
|
|
} |
1190 |
|
|
|
1191 |
|
|
String &NullFile::getDesc(String &result) const |
1192 |
|
|
{ |
1193 |
|
|
result = "null device"; |
1194 |
|
|
return result; |
1195 |
|
|
} |
1196 |
|
|
|
1197 |
|
|
FileOfs NullFile::getSize() const |
1198 |
|
|
{ |
1199 |
|
|
return 0; |
1200 |
|
|
} |
1201 |
|
|
|
1202 |
|
|
void NullFile::pstat(pstat_t &s) const |
1203 |
|
|
{ |
1204 |
|
|
s.caps = pstat_size; |
1205 |
|
|
s.size = getSize(); |
1206 |
|
|
} |
1207 |
|
|
|
1208 |
|
|
uint NullFile::read(void *buf, uint size) |
1209 |
|
|
{ |
1210 |
|
|
return 0; |
1211 |
|
|
} |
1212 |
|
|
|
1213 |
|
|
void NullFile::seek(FileOfs offset) |
1214 |
|
|
{ |
1215 |
|
|
if (offset!=0) throw IOException(EINVAL); |
1216 |
|
|
} |
1217 |
|
|
|
1218 |
|
|
int NullFile::setAccessMode(IOAccessMode am) |
1219 |
|
|
{ |
1220 |
|
|
return (am == getAccessMode()) ? 0 : EACCES; |
1221 |
|
|
} |
1222 |
|
|
|
1223 |
|
|
FileOfs NullFile::tell() const |
1224 |
|
|
{ |
1225 |
|
|
return 0; |
1226 |
|
|
} |
1227 |
|
|
|
1228 |
|
|
void NullFile::truncate(FileOfs newsize) |
1229 |
|
|
{ |
1230 |
|
|
if (newsize!=0) throw IOException(EINVAL); |
1231 |
|
|
} |
1232 |
|
|
|
1233 |
|
|
uint NullFile::write(const void *buf, uint size) |
1234 |
|
|
{ |
1235 |
|
|
return 0; |
1236 |
|
|
} |
1237 |
|
|
|
1238 |
|
|
/* |
1239 |
|
|
* MemoryFile |
1240 |
|
|
*/ |
1241 |
|
|
|
1242 |
|
|
#define MEMORYFILE_GROW_FACTOR_NUM 4 |
1243 |
|
|
#define MEMORYFILE_GROW_FACTOR_DENOM 3 |
1244 |
|
|
#define MEMORYFILE_MIN_BUFSIZE 32 |
1245 |
|
|
|
1246 |
|
|
MemoryFile::MemoryFile(FileOfs o, uint size, IOAccessMode mode) : File() |
1247 |
|
|
{ |
1248 |
|
|
ofs = o; |
1249 |
|
|
dsize = size; |
1250 |
|
|
buf = NULL; |
1251 |
|
|
ibufsize = size; |
1252 |
|
|
if (ibufsize < MEMORYFILE_MIN_BUFSIZE) ibufsize = MEMORYFILE_MIN_BUFSIZE; |
1253 |
|
|
resizeBuf(ibufsize); |
1254 |
|
|
memset(buf, 0, dsize); |
1255 |
|
|
mcount = 0; |
1256 |
|
|
|
1257 |
|
|
pos = 0; |
1258 |
|
|
int e = setAccessMode(mode); |
1259 |
|
|
if (e) throw IOException(e); |
1260 |
|
|
} |
1261 |
|
|
|
1262 |
|
|
MemoryFile::~MemoryFile() |
1263 |
|
|
{ |
1264 |
|
|
free(buf); |
1265 |
|
|
} |
1266 |
|
|
|
1267 |
|
|
byte *MemoryFile::getBufPtr() const |
1268 |
|
|
{ |
1269 |
|
|
return buf; |
1270 |
|
|
} |
1271 |
|
|
|
1272 |
|
|
void MemoryFile::extend(FileOfs newsize) |
1273 |
|
|
{ |
1274 |
|
|
// MemoryFiles may not be > 2G |
1275 |
|
|
if (newsize > 0x7fffffff) throw IOException(EINVAL); |
1276 |
|
|
if (newsize < getSize()) throw IOException(EINVAL); |
1277 |
|
|
if (newsize == getSize()) return; |
1278 |
|
|
while (bufsize<newsize) extendBuf(); |
1279 |
|
|
memset(buf+dsize, 0, newsize-dsize); |
1280 |
|
|
dsize = newsize; |
1281 |
|
|
mcount++; |
1282 |
|
|
} |
1283 |
|
|
|
1284 |
|
|
void MemoryFile::extendBuf() |
1285 |
|
|
{ |
1286 |
|
|
resizeBuf(extendBufSize(bufsize)); |
1287 |
|
|
} |
1288 |
|
|
|
1289 |
|
|
uint MemoryFile::extendBufSize(uint bufsize) |
1290 |
|
|
{ |
1291 |
|
|
return bufsize * MEMORYFILE_GROW_FACTOR_NUM / MEMORYFILE_GROW_FACTOR_DENOM; |
1292 |
|
|
} |
1293 |
|
|
|
1294 |
|
|
IOAccessMode MemoryFile::getAccessMode() const |
1295 |
|
|
{ |
1296 |
|
|
return Stream::getAccessMode(); |
1297 |
|
|
} |
1298 |
|
|
|
1299 |
|
|
String &MemoryFile::getDesc(String &result) const |
1300 |
|
|
{ |
1301 |
|
|
result = "MemoryFile"; |
1302 |
|
|
return result; |
1303 |
|
|
} |
1304 |
|
|
|
1305 |
|
|
FileOfs MemoryFile::getSize() const |
1306 |
|
|
{ |
1307 |
|
|
return dsize; |
1308 |
|
|
} |
1309 |
|
|
|
1310 |
|
|
void MemoryFile::pstat(pstat_t &s) const |
1311 |
|
|
{ |
1312 |
|
|
s.caps = pstat_size; |
1313 |
|
|
s.size = getSize(); |
1314 |
|
|
} |
1315 |
|
|
|
1316 |
|
|
uint MemoryFile::read(void *b, uint size) |
1317 |
|
|
{ |
1318 |
|
|
if ((pos+size) > dsize) { |
1319 |
|
|
if (pos >= dsize) return 0; |
1320 |
|
|
size = dsize-pos; |
1321 |
|
|
} |
1322 |
|
|
memcpy(b, buf+pos, size); |
1323 |
|
|
pos += size; |
1324 |
|
|
return size; |
1325 |
|
|
} |
1326 |
|
|
|
1327 |
|
|
void MemoryFile::resizeBuf(uint newsize) |
1328 |
|
|
{ |
1329 |
|
|
bufsize = newsize; |
1330 |
|
|
|
1331 |
|
|
ASSERT(dsize <= bufsize); |
1332 |
|
|
|
1333 |
|
|
buf = (byte*)realloc(buf, bufsize ? bufsize : 1); |
1334 |
|
|
if (!buf) throw std::bad_alloc(); |
1335 |
|
|
} |
1336 |
|
|
|
1337 |
|
|
void MemoryFile::seek(FileOfs o) |
1338 |
|
|
{ |
1339 |
|
|
if (o<ofs) throw IOException(EINVAL); |
1340 |
|
|
pos = o-ofs; |
1341 |
|
|
} |
1342 |
|
|
|
1343 |
|
|
int MemoryFile::setAccessMode(IOAccessMode mode) |
1344 |
|
|
{ |
1345 |
|
|
int e = Stream::setAccessMode(mode); |
1346 |
|
|
if (e) return e; |
1347 |
|
|
seek(ofs); |
1348 |
|
|
return 0; |
1349 |
|
|
} |
1350 |
|
|
|
1351 |
|
|
uint MemoryFile::shrinkBufSize(uint bufsize) |
1352 |
|
|
{ |
1353 |
|
|
return bufsize * MEMORYFILE_GROW_FACTOR_DENOM / MEMORYFILE_GROW_FACTOR_NUM; |
1354 |
|
|
} |
1355 |
|
|
|
1356 |
|
|
void MemoryFile::shrinkBuf() |
1357 |
|
|
{ |
1358 |
|
|
resizeBuf(shrinkBufSize(bufsize)); |
1359 |
|
|
} |
1360 |
|
|
|
1361 |
|
|
FileOfs MemoryFile::tell() const |
1362 |
|
|
{ |
1363 |
|
|
return pos+ofs; |
1364 |
|
|
} |
1365 |
|
|
|
1366 |
|
|
void MemoryFile::truncate(FileOfs newsize) |
1367 |
|
|
{ |
1368 |
|
|
dsize = newsize; |
1369 |
|
|
|
1370 |
|
|
uint s = ibufsize; |
1371 |
|
|
while (s<dsize) s = extendBufSize(s); |
1372 |
|
|
|
1373 |
|
|
resizeBuf(s); |
1374 |
|
|
mcount++; |
1375 |
|
|
} |
1376 |
|
|
|
1377 |
|
|
uint MemoryFile::write(const void *b, uint size) |
1378 |
|
|
{ |
1379 |
|
|
while (pos+size >= bufsize) extendBuf(); |
1380 |
|
|
memmove(((byte*)buf)+pos, b, size); |
1381 |
|
|
pos += size; |
1382 |
|
|
if (pos>dsize) dsize = pos; |
1383 |
|
|
mcount++; |
1384 |
|
|
return size; |
1385 |
|
|
} |
1386 |
|
|
|
1387 |
|
|
/* |
1388 |
|
|
* string stream functions |
1389 |
|
|
*/ |
1390 |
|
|
|
1391 |
|
|
char *fgetstrz(File *file) |
1392 |
|
|
{ |
1393 |
|
|
FileOfs o = file->tell(); |
1394 |
|
|
/* get string size */ |
1395 |
|
|
char buf[64]; |
1396 |
|
|
int s, z = 0; |
1397 |
|
|
bool found = false; |
1398 |
|
|
while (!found) { |
1399 |
|
|
s = file->read(buf, 64); |
1400 |
|
|
for (int i=0; i<s; i++) { |
1401 |
|
|
z++; |
1402 |
|
|
if (buf[i] == 0) { |
1403 |
|
|
found = true; |
1404 |
|
|
break; |
1405 |
|
|
} |
1406 |
|
|
} |
1407 |
|
|
} |
1408 |
|
|
/* read string */ |
1409 |
|
|
char *str = (char*)malloc(z); |
1410 |
|
|
if (!str) throw std::bad_alloc(); |
1411 |
|
|
file->seek(o); |
1412 |
|
|
file->readx(str, z); |
1413 |
|
|
return str; |
1414 |
|
|
} |
1415 |
|
|
|
1416 |
|
|
// FIXME: more dynamical solution appreciated |
1417 |
|
|
#define REASONABLE_STRING_LIMIT 1024 |
1418 |
|
|
|
1419 |
|
|
char *getstrz(Stream *stream) |
1420 |
|
|
{ |
1421 |
|
|
/* get string size */ |
1422 |
|
|
char buf[REASONABLE_STRING_LIMIT]; |
1423 |
|
|
int z = 0; |
1424 |
|
|
while (1) { |
1425 |
|
|
stream->readx(buf+z, 1); |
1426 |
|
|
z++; |
1427 |
|
|
if (z >= REASONABLE_STRING_LIMIT) { |
1428 |
|
|
z = REASONABLE_STRING_LIMIT; |
1429 |
|
|
break; |
1430 |
|
|
} |
1431 |
|
|
if (buf[z-1] == 0) break; |
1432 |
|
|
} |
1433 |
|
|
if (!z) return NULL; |
1434 |
|
|
char *str = (char*)malloc(z); |
1435 |
|
|
if (!str) throw std::bad_alloc(); |
1436 |
|
|
memmove(str, buf, z-1); |
1437 |
|
|
str[z-1] = 0; |
1438 |
|
|
return str; |
1439 |
|
|
} |
1440 |
|
|
|
1441 |
|
|
void putstrz(Stream *stream, const char *str) |
1442 |
|
|
{ |
1443 |
|
|
stream->writex(str, strlen(str)+1); |
1444 |
|
|
} |
1445 |
|
|
|
1446 |
|
|
char *getstrp(Stream *stream) |
1447 |
|
|
{ |
1448 |
|
|
unsigned char l; |
1449 |
|
|
stream->readx(&l, 1); |
1450 |
|
|
char *str = (char*)malloc(l+1); |
1451 |
|
|
if (!str) throw std::bad_alloc(); |
1452 |
|
|
stream->readx(str, l); |
1453 |
|
|
*(str+l) = 0; |
1454 |
|
|
return str; |
1455 |
|
|
} |
1456 |
|
|
|
1457 |
|
|
void putstrp(Stream *stream, const char *str) |
1458 |
|
|
{ |
1459 |
|
|
unsigned char l = strlen(str); |
1460 |
|
|
stream->writex(&l, 1); |
1461 |
|
|
stream->writex(str, l); |
1462 |
|
|
} |
1463 |
|
|
|
1464 |
|
|
char *getstrw(Stream *stream) |
1465 |
|
|
{ |
1466 |
|
|
short t; |
1467 |
|
|
byte lbuf[2]; |
1468 |
|
|
stream->readx(lbuf, 2); |
1469 |
|
|
int l = lbuf[0] | lbuf[1] << 8; |
1470 |
|
|
char *a = (char*)malloc(l+1); |
1471 |
|
|
if (!a) throw std::bad_alloc(); |
1472 |
|
|
for (int i=0; i<l; i++) { |
1473 |
|
|
stream->readx(&t, 2); |
1474 |
|
|
a[i] = (char)t; |
1475 |
|
|
} |
1476 |
|
|
a[l] = 0; |
1477 |
|
|
return a; |
1478 |
|
|
} |
1479 |
|
|
|
1480 |
|
|
void putstrw(Stream *stream, const char *str) |
1481 |
|
|
{ |
1482 |
|
|
/* FIXME: someone implement me ? */ |
1483 |
|
|
throw NotImplementedException(HERE); |
1484 |
|
|
} |
1485 |
|
|
|