/[pearpc]/src/tools/stream.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/tools/stream.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 6 months ago) by dpavlin
File size: 27906 byte(s)
import upstream CVS
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

  ViewVC Help
Powered by ViewVC 1.1.26