% FLOATREAD - Read matrix from float file ssuming four byte floating point number
%               Can use FSEEK to read an arbitrary (contiguous) submatrix.
%
% Usage:        >> a = floatread(filename,size,'format',offset) 
%
% Inputs:
%   filename - name of the file
%   size     - determine the number of float elements to be read and 
%              the dimensions of the resulting matrix. If the last element 
%              of 'size' is Inf, the size of the last dimension is determined
%              by the file length. If size is 'square,' FLOATREAD attempts 
%              to read a square 2-D matrix.
%
% Optional inputs:
%  'format'  - the option FORMAT argument specifies the storage format as
%              defined by FOPEN. Default format ([]) is 'native'.
%  offset    - either the number of first floats to skip from the beginning of the
%              float file, OR a cell array containing the dimensions of the original 
%              data matrix and a starting position vector in that data matrix. 
%
%              Example: % Read a [3 10] submatrix of a four-dimensional float matrix 
%                >> a = floatread('mydata.fdt',[3 10],'native',{[[3 10 4 5],[1,1,3,4]});
%              % Note: The 'size' and 'offset' arguments must be compatible both
%              % with each other and with the size and ordering of the float file.
% 
% Author: Sigurd Enghoff, CNL / Salk Institute, La Jolla, 7/1998 
%
% See also: FLOATWRITE, FOPEN

% Copyright (C) Sigurd Enghoff, CNL / Salk Institute, La Jolla, 7/1998
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

% 04-26-99  modified by Sigurd Enghoff to handle variable-sized and
%           multi-dimensional data.
% 07-08-99  modified by Sigurd Enghoff, FORMAT argument added.
% 02-08-00  help updated for toolbox inclusion -sm
% 02-14-00  added segment arg -sm
% 08-14-00  added size 'square' option -sm
% 01-25-02  reformated help & license, added links -ad 

function A = floatread(fname,Asize,fform,offset)

if nargin<2
  help floatread
  return
end

if ~exist('fform') || isempty(fform) || fform(1)==0
	fform = 'native';
end

if ~exist('offset') 
	offset = 0;
end

fid = fopen(fname,'rb',fform);
if fid>0 
 if exist('offset')
   if iscell(offset)
     if length(offset) ~= 2
        error('offset must be a positive integer or a 2-item cell array');
     end
     datasize = offset{1};
     startpos = offset{2};
     if length(datasize) ~= length(startpos)
        error('offset must be a positive integer or a 2-item cell array');
     end
     for k=1:length(datasize)
       if startpos(k) < 1 || startpos(k) > datasize(k)
          error('offset must be a positive integer or a 2-item cell array');
       end
     end
     if length(Asize)> length(datasize)
        error('offset must be a positive integer or a 2-item cell array');
     end
     for k=1:length(Asize)-1
         if startpos(k) ~= 1 
            error('offset must be a positive integer or a 2-item cell array');
         end
     end
     sizedim = length(Asize);
     if Asize(sizedim) + startpos(sizedim) - 1 > datasize(sizedim)
        error('offset must be a positive integer or a 2-item cell array');
     end
     for k=1:length(Asize)-1
         if Asize(k) ~= datasize(k)
            error('offset must be a positive integer or a 2-item cell array');
         end
     end

     offset = 0;
     jumpfac = 1;
     for k=1:length(startpos)
           offset = offset + jumpfac * (startpos(k)-1);
           jumpfac = jumpfac * datasize(k);
     end

   elseif length(offset) > 1
     error('offset must be a positive integer or a 2-item cell array');
   end
   
   % perform the fseek() operation
   % -----------------------------
   stts = fseek(fid,4*offset,'bof');

   if stts ~= 0
     error('floatread(): fseek() error.');
     return
   end
 end

% determine what 'square' means
% -----------------------------
 if ischar('Asize')
   if iscell(offset)
         if length(datasize) ~= 2 || datasize(1) ~= datasize(2)
              error('size ''square'' must refer to a square 2-D matrix');
         end
         Asize = [datsize(1) datasize(2)];
   elseif strcmp(Asize,'square')
         fseek(fid,0,'eof'); % go to end of file
         bytes = ftell(fid); % get byte position
         fseek(fid,0,'bof'); % rewind
         bytes = bytes/4; % nfloats
         froot = sqrt(bytes);
         if round(froot)*round(froot) ~= bytes
              error('floatread(): filelength is not square.')
         else
              Asize = [round(froot) round(froot)];
         end
   end
 end
 A = fread(fid,prod(Asize),'float');
else
 error('floatread() fopen() error.');
 return
end

% fprintf('   %d floats read\n',prod(size(A)));

% interpret last element of Asize if 'Inf'
% ----------------------------------------
if Asize(end) == Inf
	Asize = Asize(1:end-1);
	A = reshape(A,[Asize length(A)/prod(Asize)]);
else
	A = reshape(A,Asize);
end

fclose(fid);
