Your IP : 216.73.216.48
/* This file is part of Strigi Desktop Search
*
* Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef STRIGI_STREAMBASE_H
#define STRIGI_STREAMBASE_H
#include <stdio.h>
#include <string>
#include <strigi/strigiconfig.h>
#define INT32MAX 0x7FFFFFFFL
namespace Strigi {
/** Used to indicate the current status of a Stream */
enum StreamStatus {
Ok /**< Stream is capable of being read from */,
Eof /**< The end of the Stream has been reached */,
Error /**< An error occurred. Use error() to find out more information */
};
// java mapping: long=int64, int=int32, byte=uint8_t
/**
* The base of all Streams. Do not inherit directly from this class,
* but from (an instance of) StreamBase
*
* This class contains all the non-virtual StreamBase methods
* that don't depend on a specific Stream type
*
* Developer comment: This is needed because of win32 compilation.
* When we want to access a function outside a lib, we have to export them,
* but we can't export the template class because this would be somewhat
* stupid / does not work by design :)
* Because of this I've introduced this StreamBaseBase class
*/
class STREAMS_EXPORT StreamBaseBase { //krazy:exclude=dpointer
protected:
/** The size of the stream (-1 if unknown) */
int64_t m_size;
/** The position of the stream */
int64_t m_position;
/**
* @brief String representation of the last error, or
* an empty string otherwise
*/
std::string m_error;
/** The status of the stream - see StreamStatus */
StreamStatus m_status;
public:
/**
* @brief Constructor: initialises everything to sane defaults
**/
StreamBaseBase() :m_size(-1), m_position(0), m_status(Ok) {}
/**
* @brief Destructor
**/
virtual ~StreamBaseBase() {}
/**
* @brief Return a string representation of the last error.
* If no error has occurred, an empty string is returned.
**/
const char* error() const { return m_error.c_str(); }
/**
* @brief Return the status of the stream.
**/
StreamStatus status() const { return m_status; }
/**
* @brief Get the current position in the stream.
* The value obtained from this function can be used to reset the stream.
**/
int64_t position() const { return m_position; }
/**
* @brief Return the size of the stream.
*
* The size of the stream is always known if the end of the stream
* has been reached. In all other cases, this may return -1 to
* indicate the size of the stream is unknown.
*
* @return the size of the stream, if it is known, or -1 if the size
* of the stream is unknown
**/
int64_t size() const { return m_size; }
};
/**
* @brief Base class for stream read access to a data source.
*
* This class is based on the interface java.io.InputStream. It provides
* a uniform interface for accessing streamed resources.
*
* The main difference with the Java equivalent is a performance improvement.
* When reading data, data is not copied into a buffer provided by the caller,
* but a pointer to the read data is provided. This makes this interface
* especially useful for deriving from it and implementing filters or
* transformers.
*/
template <class T>
class StreamBase : public StreamBaseBase {
public:
StreamBase() { }
virtual ~StreamBase(){}
/**
* @brief Reads items from the stream and sets @p start to point to
* the first item that was read.
*
* Note: unless stated otherwise in the documentation for that method,
* this pointer will no longer be valid after calling another method of
* this class. The pointer will also no longer be valid after the class
* is destroyed.
*
* The functions inherited from StreamBaseBase do not invalidate the pointer.
*
* At least @p min items will be read from the stream, unless an error occurs
* or the end of the stream is reached. Under no circumstances will more than
* @p max items be read.
*
* If the end of the stream is reached before @p min items are read, the
* read is still considered successful and the number of items read will
* be returned.
*
* @param start pointer passed by reference that will be set to point to
* the retrieved array of items. If the end of the stream
* is encountered or an error occurs, the value of @p start
* is undefined
* @param min the minimal number of items to read from the stream. This
* value should be larger than 0. If it is 0 or smaller, the
* result is undefined
* @param max the maximal number of items to read from the stream.
* If this value is smaller than @p min, there is no limit on
* the number of items that can be read
* @return the number of items that were read. @c -1 is returned if
* end of the stream has already been reached. @c -2 is returned
* if an error has occurred
**/
virtual int32_t read(const T*& start, int32_t min, int32_t max) = 0;
/**
* @brief Skip @p ntoskip items.
*
* If an error occurs, or the end of the stream is encountered, fewer
* than @p ntoskip items may be skipped. This can be checked by comparing
* the return value to @p ntoskip.
*
* Calling this function invalidates the data pointer that was obtained from
* StreamBase::read.
*
* @param ntoskip the number of items that should be skipped
* @return the number of items skipped
**/
virtual int64_t skip(int64_t ntoskip);
/**
* @brief Repositions this stream to a given position.
*
* A call to StreamBase::reset is only guaranteed to be successful when
* the requested position lies within the segment of a stream
* corresponding to a valid pointer obtained from StreamBase::read.
* In this case, the pointer will not be invalidated.
*
* Calling this function invalidates the data pointer that was obtained from
* StreamBase::read unless the conditions outlined above apply.
*
* To read n items, leaving the stream at the same position as before, you
* can do the following:
* @code
* int64_t start = stream.position();
* if ( stream.read(data, min, max) > 0 ) {
* stream.reset(start);
* // The data pointer is still valid here
* }
* @endcode
*
* @param pos the position in the stream you want to go to, relative to
* the start of the stream
* @return the new position in the stream
**/
virtual int64_t reset(int64_t pos) = 0;
};
/** Abstract class for a stream of bytes */
typedef StreamBase<char> InputStream;
/** Abstract class for a stream of Unicode characters */
typedef StreamBase<wchar_t> Reader;
template <class T>
int64_t
StreamBase<T>::skip(int64_t ntoskip) {
const T* begin;
int32_t nread;
int64_t skipped = 0;
while (ntoskip > 0) {
// make sure we do not overflow uint32_t
int32_t maxstep = (int32_t)((ntoskip > 10000000)
?10000000 :ntoskip);
// the default implementation is to simply read the data that we want
// to skip
nread = read(begin, 1, maxstep);
if (nread < -1 ) {
// an error occurred
return nread;
} else if (nread < 1) {
// the end of the stream was encountered
ntoskip = 0;
} else {
skipped += nread;
ntoskip -= nread;
}
}
return skipped;
}
} // end namespace Strigi
#endif