⛏️ index : haiku.git

/*
 * Copyright 2004-2008, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */
#ifndef READ_HELPER_H
#define READ_HELPER_H


#include "TIFF.h"

#include <BufferIO.h>
#include <ByteOrder.h>


template<class T>
inline void
byte_swap(T &/*data*/)
{
	// Specialize for data types which actually swap
//	printf("DEAD MEAT!\n");
//	exit(1);
}


template<>
inline void
byte_swap(float &data)
{
	data = __swap_float(data);
}


template<>
inline void
byte_swap(int32 &data)
{
	data = __swap_int32(data);
}


template<>
inline void
byte_swap(uint32 &data)
{
	data = __swap_int32(data);
}


template<>
inline void
byte_swap(int16 &data)
{
	data = __swap_int16(data);
}


template<>
inline void
byte_swap(uint16 &data)
{
	data = __swap_int16(data);
}


class TReadHelper {
	public:
		TReadHelper(BPositionIO& stream)
			:
			fStream(&stream, 65536, false),
			fError(B_OK),
			fSwap(false)
		{
		}

		template<class T> inline void
		operator()(T &data)
		{
			fError = fStream.Read((void *)&data, sizeof(T));
			if (fError >= B_OK) {
				if (IsSwapping())
					byte_swap(data);
				return;
			}

			if (fError == 0)
				fError = B_ERROR;
			throw fError;
		}

		template<class T> inline void
		operator()(T data, size_t length)
		{
			fError = fStream.Read((void *)data, length);
			if (fError < (ssize_t)length)
				fError = B_ERROR;

			if (fError >= B_OK)
				return;

			throw fError;
		}

		template<class T> inline T
		Next()
		{
			T value;
			fError = fStream.Read((void *)&value, sizeof(T));
			if (fError > B_OK) {
				if (IsSwapping())
					byte_swap(value);
				return value;
			}

			if (fError == 0)
				fError = B_ERROR;
			throw fError;
		}

		inline uint32
		Next(uint16 type)
		{
			if (type == TIFF_UINT16_TYPE || type == TIFF_INT16_TYPE)
				return Next<uint16>();

			return Next<uint32>();
		}

		inline double
		NextDouble(uint16 type)
		{
			switch (type) {
				case TIFF_UINT16_TYPE:
					return Next<uint16>();
				case TIFF_UINT32_TYPE:
					return Next<uint32>();
				case TIFF_UFRACTION_TYPE:
				{
					double value = Next<uint32>();
					return value / Next<uint32>();
				}
				case TIFF_INT16_TYPE:
					return Next<int16>();
				case TIFF_INT32_TYPE:
					return Next<int32>();
				case TIFF_FRACTION_TYPE:
				{
					double value = Next<int32>();
					return value / Next<int32>();
				}
				case TIFF_FLOAT_TYPE:
					return Next<float>();
				case TIFF_DOUBLE_TYPE:
					return Next<double>();

				default:
					return Next<uint8>();
			}
		}

		inline void
		NextShorts(uint16* data, size_t length)
		{
			fError = fStream.Read(data, length * 2);
			if (fError < (ssize_t)length * 2)
				fError = B_ERROR;

			if (fError >= B_OK) {
				if (IsSwapping())
					swap_data(B_INT16_TYPE, data, length * 2, B_SWAP_ALWAYS);
				return;
			}

			throw fError;
		}

		status_t Status() const
			{ return fError >= B_OK ? B_OK : fError; };

		off_t Seek(off_t offset, int32 mode)
			{ return fStream.Seek(offset, mode); }
		off_t Position() const
			{ return fStream.Position(); }

		void SetSwap(bool yesNo) { fSwap = yesNo; };
		bool IsSwapping() const { return fSwap; };

		BPositionIO& Stream() { return fStream; }

	private:
		BBufferIO	fStream;
		status_t	fError;
		bool		fSwap;
};

#endif	// READ_HELPER_H