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