00001 /* 00002 * ExternalStream.cc 00003 * 00004 * Smalltalk like class library for C++ 00005 * Abstract external stream. 00006 * 00007 * Copyright (c) 2003 Milan Cermak 00008 */ 00009 /* 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * This library is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with this library; if not, write to the Free Software 00022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 */ 00024 #include <stlib/ExternalStream.h> 00025 00026 #include <stlib/ByteArray.h> 00027 #include <stlib/Character.h> 00028 #include <stlib/IOAccessor.h> 00029 #include <stlib/IOBuffer.h> 00030 #include <stlib/SequenceableCollection.h> 00031 #include <stlib/String.h> 00032 #include <stlib/WriteStream.h> 00033 #include <stlib/Error.h> 00034 00035 ExternalStream::ExternalStream(IOAccessor *accessor) 00036 { 00037 io_accessor = accessor; 00038 io_buffer = new IOBuffer(io_accessor); 00039 PositionableStream::initialize(io_buffer->buffer()); 00040 _position = io_buffer->firstDataPosition(); 00041 read_limit = 0; 00042 write_limit = -1; 00043 } 00044 00045 /* Class-accessing protocol */ 00046 String *ExternalStream::className(void) const 00047 { 00048 return new String("ExternalStream"); 00049 } 00050 00051 /* Accessing protocol */ 00052 SequenceableCollection *ExternalStream::contents(void) 00053 { 00054 long dataSize; 00055 Stream *newCollectionStream; 00056 00057 dataSize = io_accessor->dataSize(); 00058 newCollectionStream = contentSpeciesFor(dataSize < 256 ? 256 : dataSize) 00059 ->writeStream(); 00060 while (!atEnd()) { 00061 newCollectionStream->nextPut(next()); 00062 } 00063 return newCollectionStream->contents(); 00064 } 00065 00066 /* Positioning protocol */ 00067 long ExternalStream::readPosition(void) 00068 { 00069 // openIfClosed(); 00070 return io_buffer->currentBufferPosition() + _position; 00071 } 00072 00073 /* Status protocol */ 00074 void ExternalStream::close(void) 00075 { 00076 if (!closed()) { 00077 closeConnection(); 00078 io_buffer = nil; 00079 collection = contentSpeciesFor(0); 00080 } 00081 } 00082 00083 bool ExternalStream::closed(void) 00084 { 00085 return io_buffer == nil; 00086 } 00087 00088 void ExternalStream::commit(void) 00089 { 00090 io_buffer->commit(); 00091 } 00092 00093 /* Testing protocol */ 00094 bool ExternalStream::atEnd(void) 00095 { 00096 if (!basicAtEnd()) return false; 00097 if (!nextBuffer()) return true; 00098 return _position == read_limit; 00099 } 00100 00101 bool ExternalStream::isBinary(void) 00102 { 00103 return true; 00104 } 00105 00106 bool ExternalStream::isExternalStream(void) 00107 { 00108 return true; 00109 } 00110 00111 /* Private protocol */ 00112 void ExternalStream::closeConnection(void) 00113 { 00114 try { 00115 flush(); 00116 io_accessor->close(); 00117 _position = read_limit = 0; 00118 write_limit = -1; 00119 } 00120 catch (Error *ex) { 00121 /* Do nothing */ 00122 } 00123 } 00124 00125 bool ExternalStream::nextBuffer(void) 00126 { 00127 long offset; 00128 00129 flush(); 00130 collection = io_buffer->nextAndSetOffset(offset); 00131 _position = offset; 00132 read_limit = io_buffer->lastDataPosition(); 00133 return read_limit > _position; 00134 } 00135 00136 Object *ExternalStream::pastEnd(void) 00137 { 00138 // openIfClosed(); 00139 if (_position < read_limit) 00140 return collection->at(_position++); 00141 if (nextBuffer()) 00142 return collection->at(_position++); 00143 /* End of stream. Must be signaled somehow. */ 00144 return nil; 00145 } 00146 00147 void ExternalStream::setPosition(long index) 00148 { 00149 long offset; 00150 00151 if (index < 0) { 00152 Error *ex = new Error(new String("Attempt to position to a negative number."), 00153 new String(__PRETTY_FUNCTION__)); 00154 ex->raiseFrom(this); 00155 } 00156 flush(); 00157 collection = io_buffer->readPositionAndSetOffset(index, offset); 00158 _position = offset; 00159 read_limit = io_buffer->lastDataPosition(); 00160 }