binary.h 5.48 KB

//make sure that this header file is only loaded once
#ifndef RTS_BINARY_H
#define RTS_BINARY_H

#include "../envi/envi_header.h"
#include "../math/vector.h"
#include <fstream>
#include <sys/stat.h>

namespace stim{

//This class contains a bunch of functions useful for multidimensional binary file access
template< typename T, unsigned int D = 3 >
class binary{

protected:
	std::fstream file;		//file stream used for reading and writing
	std::string name;		//file name

	unsigned long long int R[D];		//resolution
	unsigned int header;	//header size (in bytes)
	unsigned char* mask;	//pointer to a character array: 0 = background, 1 = foreground (or valid data)




	//basic initialization
	void init(){
		memset(R, 0, sizeof(unsigned int) * D);		//initialize the resolution to zero
		header = 0;									//initialize the header size to zero
		mask = NULL;
	}

	//returns the file size
	//	reads the file size from disk and returns it (in bytes)
	long long int get_file_size(){
#ifdef _WIN32
		struct _stat64 results;
		if(_stat64(name.c_str(), &results) == 0)
			return results.st_size;
#else
		struct stat results;
		if(stat(name.c_str(), &results) == 0)
			return results.st_size;
#endif
		else return 0;
	}

	//make sure that the specified file size matches the file size on disk
	//	returns true/false
	bool test_file_size(){
		long long int npts = 1;				//initialize the number of data points to 1
		for(unsigned int i = 0; i<D; i++)	//iterate over each dimension
			npts *= R[i];					//compute the total number of data points in the file
		long long int datasize = npts * sizeof(T);//multiply the sum by the size of the template parameter

		if(datasize + header == get_file_size()) return true;	//if the byte size matches the file size, we're golden
		else return false;					//otherwise return an error

	}

	//open the file specified in "name" for binary reading and writing
	bool open_file(std::string filename){
		//open the file as binary for reading and writing
		file.open(filename.c_str(), std::ios::in | std::ios::out | std::ios::binary);

		//if the file is successful
		if(file){
			name = filename;		//set the name
			if(test_file_size())	//test the file size
				return true;
		}
		
		return false;
	}

public:

	//open a file, given the file name, resolution (as a vector) and header size
	bool open(std::string filename, vec<unsigned int, D> r, unsigned int h = 0){

		for(unsigned int i = 0; i < D; i++)		//set the dimensions of the binary file object
			R[i] = r[i];

		header = h;				//save the header size

		if(!open_file(filename)) return false;	//open the binary file

		return test_file_size();
	}

	//crete a new binary file
	bool create(std::string filename, vec<unsigned int, D> r, unsigned int offset = 0){

		std::ofstream target(filename.c_str(), std::ios::binary);

		//initialize binary file
		T p = 0;
		for(unsigned int i =0; i < r[0] * r[1] * r[2]; i++){
			target.write((char*)(&p), sizeof(T));
		}

		for(unsigned int i = 0; i < D; i++)		//set the dimensions of the binary file object
			R[i] = r[i];

		header = offset;				//save the header size

		if(!open_file(filename)) return false;	//open the binary file

		return test_file_size();
	}

	//save one band from the memory to the file
	bool write_page( T * p, unsigned int page){

		if(p == NULL){
			std::cout<<"ERROR: unable to write into file, empty pointer"<<std::endl;
			exit(1);
		}

		file.seekg(R[1] * R[0] * page * sizeof(T), std::ios::beg);   //seek to the desired location on disk
		file.write((char *)p, R[0] * R[1] * sizeof(T));				 //write binary data

		return true;
	}

	//save one band of the file into the memory, and return the pointer
	bool read_page( T * p, unsigned int page){

		if (page >= R[2]){										//make sure the bank number is right
			std::cout<<"ERROR: page out of range"<<std::endl;
			return false;
		}

		file.seekg(R[1] * R[0] * page * sizeof(T), std::ios::beg);   //write into memory from the binary file
		file.read((char *)p, R[0] * R[1] * sizeof(T));

		return true;
	}

	//saves a hyperplane orthogonal to dimension d at intersection n
	bool read_plane(T * dest, unsigned int d, unsigned int n){

		//reset the file pointer back to the beginning of the file
		file.seekg(0, std::ios::beg);

		//compute the contiguous size C for each readable block
		unsigned int C = 1;
		for(unsigned int i = 0; i < d; i++)		//for each dimension less than d
			C *= R[i];							//compute the product

		//compute the non-contiguous size NC for each readable block
		unsigned int NC = 1;
		for(unsigned int i = d + 1; i < D; i++)
			NC *= R[i];

		//for all noncontiguous blocks, read each contiguous block that makes up the hyper-plane
		for(unsigned int nc = 0; nc < NC; nc++){
			file.seekg(n * C * sizeof(T), std::ios::cur);	//skip n contiguous blocks
			file.read( (char*)&dest[nc * C], C * sizeof(T));	//read one contiguous block
			file.seekg( (R[d] - n - 1) * C * sizeof(T), std::ios::cur);	//skip R[d] - n contiguous blocks
		}

		return true;

	}

	//save one pixel of the file into the memory, and return the pointer
	bool read_spectrum(T * p, unsigned x, unsigned y){

		unsigned int i;

		if ( x >= R[0] || y >= R[1]){							//make sure the sample and line number is right
			std::cout<<"ERROR: sample or line out of range"<<std::endl;
			return false;
		}

		file.seekg((x + y * R[0]) * sizeof(T), std::ios::beg);           //point to the certain sample and line
		for (i = 0; i < R[2]; i++)
		{
			file.read((char *)(p + i), sizeof(T));
			file.seekg((R[1] * R[0] - 1) * sizeof(T), std::ios::cur);    //go to the next band
		}

		return true;	
	}


};

}

#endif