stream.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <errno.h>
00021 #include <string.h>
00022 #include <unistd.h>
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <fcntl.h>
00026 
00027 #include <archon/util/stream.H>
00028 
00029 namespace Archon
00030 {
00031   namespace Utilities
00032   {
00033     namespace Stream
00034     {
00035       using namespace std;
00036 
00037       struct StringReader: ReaderBase<char>
00038       {
00039         string s;
00040         int pos;
00041 
00042         int read(char *buffer, int size)
00043           throw(ReadException, UnexpectedException)
00044         {
00045           Mutex::Lock l(*this);
00046           int n = min(unsigned(size), s.size()-pos);
00047           s.copy(buffer, n, pos);
00048           pos += n;
00049           return n;
00050         }
00051 
00052         StringReader(string s): s(s), pos(0) {}
00053       };
00054 
00055       struct FileReader: ReaderBase<char>
00056       {
00057         int fildes;
00058 
00059         int read(char *buffer, int size)
00060           throw(ReadException, UnexpectedException)
00061         {
00062           int n = static_cast<int>(::read(fildes, buffer, size));
00063           if(n < 0) ARCHON_THROW1(ReadException, strerror(errno));
00064           return n;
00065         }
00066 
00067         FileReader(int fildes): fildes(fildes) {}
00068 
00069         virtual ~FileReader()
00070         {{ // The extra scope is needed to work around gcc3.2 bug #8287
00071           ::close(fildes);
00072         }}
00073       };
00074 
00075       struct FileWriter: WriterBase<char>
00076       {
00077         int fildes;
00078 
00079         int write(const char *buffer, int size)
00080           throw(WriteException, UnexpectedException)
00081         {
00082           int n = static_cast<int>(::write(fildes, buffer, size));
00083           if(n < 0) ARCHON_THROW1(WriteException, strerror(errno));
00084           return n;
00085         }
00086 
00087         FileWriter(int fildes): fildes(fildes) {}
00088 
00089         virtual ~FileWriter()
00090         {{ // The extra scope is needed to work around gcc3.2 bug #8287
00091           ::close(fildes);
00092         }}
00093       };
00094 
00095       struct Utf8StreamReader: ReaderBase<uchar>
00096       {
00097         Ref<Reader> subReader;
00098         static const int utf8BufferSize = 1024;
00099         char utf8Buffer[utf8BufferSize];
00100         int utf8BufferOffset;
00101 
00102         int read(uchar *buffer, int size)
00103           throw(ReadException, UnexpectedException)
00104         {
00105           Mutex::Lock l(*this);
00106           const int n = subReader->read(utf8Buffer+utf8BufferOffset,
00107                                         utf8BufferSize-utf8BufferOffset);
00108 
00109           const int m = Unicode::decodeUtf8(utf8Buffer, utf8BufferOffset+n,
00110                                             buffer, size);
00111 
00112           if(m) copy(utf8Buffer+m, utf8Buffer+utf8BufferOffset+n, utf8Buffer);
00113           utf8BufferOffset += n-m;
00114 
00115           return size;
00116         }
00117 
00118         Utf8StreamReader(Ref<Reader> subReader):
00119           subReader(subReader), utf8BufferOffset(0) {}
00120       };
00121 
00122       struct Utf8FileReader: ReaderBase<uchar>
00123       {
00124         int fildes;
00125         static const int utf8BufferSize = 1024;
00126         char utf8Buffer[utf8BufferSize];
00127         int utf8BufferOffset;
00128 
00129         int read(uchar *buffer, int size)
00130           throw(ReadException, UnexpectedException)
00131         {
00132           Mutex::Lock l(*this);
00133           const int n = static_cast<int>(::read(fildes, utf8Buffer+utf8BufferOffset,
00134                                     utf8BufferSize-utf8BufferOffset));
00135 
00136           if(n < 0) ARCHON_THROW1(ReadException, strerror(errno));
00137 
00138           const int m = Unicode::decodeUtf8(utf8Buffer, utf8BufferOffset+n,
00139                                             buffer, size);
00140 
00141           if(m) copy(utf8Buffer+m, utf8Buffer+utf8BufferOffset+n, utf8Buffer);
00142           utf8BufferOffset += n-m;
00143 
00144           return size;
00145         }
00146 
00147         Utf8FileReader(int fildes):
00148           fildes(fildes), utf8BufferOffset(0) {}
00149         virtual ~Utf8FileReader()
00150         {{
00151           ::close(fildes);
00152         }}
00153       };
00154 
00155 
00156       Ref<Reader> makeStringReader(string s)
00157       {
00158         return new StringReader(s);
00159       }
00160 
00161 
00162       Ref<Reader> makeFileReader(string fileName) throw(FileOpenException)
00163       {
00164         const int fildes = open(fileName.c_str(), O_RDONLY);
00165         if(fildes<0)
00166           ARCHON_THROW1(FileOpenException,
00167                         "Could not open \"" + fileName + "\" for reding: " +
00168                         strerror(errno));
00169         return new FileReader(fildes);
00170       }
00171 
00172       Ref<Reader> makeFileReader(int fildes)
00173       {
00174         return new FileReader(fildes);
00175       }
00176 
00177 
00178       Ref<Writer> makeFileWriter(string fileName) throw(FileOpenException)
00179       {
00180         const int fildes =
00181           creat(fileName.c_str(),
00182                 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00183         if(fildes<0)
00184           ARCHON_THROW1(FileOpenException,
00185                         "Could not open \"" + fileName + "\" for writing: " +
00186                         strerror(errno));
00187         return new FileWriter(fildes);
00188       }
00189 
00190       Ref<Writer> makeFileWriter(int fildes)
00191       {
00192         return new FileWriter(fildes);
00193       }
00194 
00195 
00196       Ref<UReader> makeUtf8StreamReader(Ref<Reader> r)
00197       {
00198         return new Utf8StreamReader(r);
00199       }
00200 
00201       Ref<UReader> makeUtf8FileReader(string fileName)
00202         throw(FileOpenException)
00203       {
00204         const int fildes = open(fileName.c_str(), O_RDONLY);
00205         if(fildes<0)
00206           ARCHON_THROW1(FileOpenException,
00207                         "Could not open \"" + fileName + "\" for reading: " +
00208                         strerror(errno));
00209         return new Utf8FileReader(fildes);
00210       }
00211 
00212       Ref<UReader> makeUtf8FileReader(int fildes)
00213       {
00214         return new Utf8FileReader(fildes);
00215       }
00216 
00217       string readIntoString(Ref<Reader> r)
00218         throw(ReadException, UnexpectedException)
00219       {
00220         string s;
00221         char b[4096];
00222         for(;;)
00223         {
00224           int n = r->read(b, 4096);
00225           if(!n) break;
00226           s.append(b, n);
00227         }
00228         return s;
00229       }
00230     }
00231   }
00232 }

Generated on Sun Jul 30 22:55:45 2006 for Archon by  doxygen 1.4.4