Code covered by the BSD License  

Highlights from
3D Cube Slice

from 3D Cube Slice by Oren Rosen
Enables reading 2 dim slices of 3 dim matrix stored in MAT file

[s, swapbyteorder]=where(filename, varargin)
function [s, swapbyteorder]=where(filename, varargin)
% WHERE returns byte offsets to the variables in a -v6 MAT-file.
%
% So far, WHERE has been tested with both little- and big- endian files on
% Windows but not on Mac or other big-endian platforms.
%
% The output from WHERE is similar to that of WHOS but can be used to map
% variables in a a MAT-file and therefore to read/write to them using
% fread/fwrite or memmapfile.
%
% WHERE can be used on Level 5 & 7 MAT-files but only maps those variables
% stored in Level 5 format up to -v6.
% Gzip compressed data saved with SAVE -v7 will be skipped over and not
% mapped.
% Files saved with SAVE -v7.3 (introduced in R2006b) presently
% cause WHERE to terminate.
%
% Examples:
% WHERE(FILENAME),
% WHERE(FILENAME, VARNAME)
% and WHERE(FILENAME, VARNAME, FIELD1/PROP1, FIELD2/PROP2....)
% display the results
%
% S=WHERE(FILENAME)
% S=WHERE(FILENAME, VARNAME, FIELD1/PROP1, FIELD2/PROP2....)
% S=WHERE(FILENAME, VARNAME)
% [S,SWAP]=WHERE(FILENAME)
% [S,SWAP]=WHERE(FILENAME, VARNAME)
% [S,SWAP]=WHERE(FILENAME, VARNAME, FIELD1/PROP1, FIELD2/PROP2....)
%
% S=WHERE(FILENAME, TAGOFFSET)
% [S, SWAP]=WHERE(FILENAME, TAGOFFSET)
% return information about the variable at the supplied tag offset. The
% tag offset would normally be derived from a previous call to WHERE.
%
% FILENAME and VARNAME are strings
% If VARNAME is specified, only information relating to that variable will
% be returned. If field/property names are not specified, wildcards ('*')
% can be used as with WHOS.
%
% WHERE produces a structure  output (S) similar to WHOS but with
% additional fields as described below
%
% SWAP is set to 1 if the endian order of the file is different from that
% of the host computer.
%
% For a standard MATLAB matrix class:
%    S = WHERE(...) returns a structure with the fields:
%         name    -- variable name
%         size    -- variable size
%         bytes   -- number of bytes allocated for the array
%         class   -- class of variable
%         global  -- logical indicating whether variable is global
%         sparse  -- logical indicating whether value is sparse
%         complex -- logical indicating whether value is complex
%         nesting -- struct with the following two fields:
%            function -- name of function where variable is defined
%            level    -- nesting level of the function
%         flags -- 8 bit uint: currently indicates complex, global, logical
%                   and persistent data - see MAT-file documentation
%         TagOffset -- the offset into the file to the Tag for this
%                      variable
%         DataOffset -- a cell containing a structure with a field
%                       '.DiscOffset' which specifies the offset into the
%                       file for the data area of this variable.
%                       For complex data,DiscOffset is a 1x2 vector with
%                       offsets to both real and  imaginary parts.
%         DiscClass -- a cell containing the storage format for the variable
%                       on disc - which may be different from class -
%                       as a string or 1x2 cell array of strings for
%                       complex data with the DiscClass for both real and
%                       imaginary parts
%
% Flags, TagOffset, DataOffset and DiscFormat are supplied by WHERE. The
% remaining fields are derived from a call to WHOS by WHERE (and will vary
% according to the version of WHOS being used).
%
% For structures and objects
% If the variable is a structure or object, DataOffset will be a cell array
% of structures describing each field or property of the variable as above.
%
% With a double precision float variable var=1:10 saved
% to file myfile.mat with the MATLAB 'SAVE MYFILE VAR -V6' command
%
% WHERE('myfile','var') then produces:
%
% ----------------------------------------------------------------------
% 	Name 	Size    Bytes       Class   	TagOffset   DataOffset
% ----------------------------------------------------------------------
% 	var     1x10      80    uint8=>double		128         184
%
% Note that to save disc space, MATLAB stores var as uint8 and it needs to
% be cast to double (hence uint8=>double i.e. DiscClass=>Class).
%
% If var is a structure the output might look as follows:
%
% -------------------------------------------------------------------------
% 	Name    	Size    Bytes           Class       TagOffset DataOffset
% -------------------------------------------------------------------------
% 	var          1x1    1068       struct=>struct       128
% 	.field1      1x1   	48          uint8=>double		224   276
% 	.field2      1x6   	64           uint16=>char		280   336
% 	.field3      1x10  	64          uint8=>double		352   408
% 	.field4      1x1   	280        struct=>struct		424   NaN
%
% A TagOffset is returned for the structure, and for each field. Names,
% DataOffsets and formats are supplied for each field. However, structures
% within structures (as for field4) are not analyzed further and
% DataOffsets are returned as NaN. To analyze these fields further use the
% WHERE(FILENAME,VARNAME, FIELD1/PROP1, FIELD2/PROP2....) form e.g for a
% structure S containing a structure A containing a structure B containing
% a matrix C use where(filename,'S','A','B','C'). This form recursively calls
% WHERE(FILENAME, TAGOFFSET) to dig through the nest.
%
% Details for objects are returned as above for structures.
%
% If 'unknown' appears in a class field it indicates that the variable has
% not been fully analyzed by WHERE. In this case, DiscOffset will be NaN.
% This will be the case for custom variables, functions, structure arrays,
% cells and sparse arrays (TagOffsets will be returned for these if they are
% fields/properties of a structure/object).With compressed data
% (v7) all offsets will be NaNs.
%
% See also WHOS
%
% Author: Malcolm Lidierth 07/06
% Copyright  Kings College London 2006
%
% Revisions: 16.09.06 WHERET functionality incorporated into WHERE
%                     Coding generally tidied - global variables removed
%            21.09.06 Now works with big-endian files on Windows
%
%
% This program is distributed without any warranty,
% without even the implied warranty of fitness for a particular purpose.

% Matlab standard codes for data formats
mi=StandardMiCodes();
mx=StandardMxCodes();

% CHECK MATLAB VERSION
v=version;
v=str2double(v(1:3));
if v<7
    error('WHERE: MATLAB Version 7 or higher required');
end


% DEFAULT RETURN VALUES
s=[];
swapbyteorder=[];

% CHECK ARGUMENTS
if nargin<1
    disp('WHERE: filename must be specified');
    return
end

if nargin>2
    for argn=1:nargin-1
        if ~isempty(strfind(varargin{argn},'*'))
            disp('WHERE: wildcards not permitted with field/property search');
            return
        end
    end
end

% Append default .mat extension if none supplied
[pathstr, name, ext] = fileparts(filename);
if isempty(ext)
    filename=[pathstr name '.mat'];
end

% BEGINNING OF MAIN FUNCTION
% Called as where(filename,TagOffset)
if nargin==2 && isnumeric(varargin{1})
    [platform,maxsize,system_endian] = computer;
    [fh, swapbyteorder]=MATOpen(filename,'r');
    if fh<0
        return
    end
    fseek(fh,double(varargin{1}),'bof');
    s(1).name='';
    NumberOfVar=1;
else
    %Otherwise
    try
        s=whos('-file',filename);
    catch
        m=lasterror;
        disp(sprintf('WHERE: %s',m.message));
        s=[];
        return
    end
    NumberOfVar=length(s);
    if nargin>=2
        s=whos('-file',filename, varargin{1});
    end
    [platform,maxsize,system_endian] = computer;
    [fh, swapbyteorder]=MATOpen(filename,'r');
    if fh<0
        return
    end
    fseek(fh,128,'bof');
end

[f1, p1, fileformat]= fopen(fh);

%>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
%MAIN ROUTINE

% Default return values
for variable=1:length(s)
    s(variable).flags=uint8(0);
    s(variable).TagOffset=NaN;
    s(variable).DataOffset{1}.DiscOffset=[NaN NaN];
    s(variable).DiscClass={'unknown' 'unknown'};
end

% LOOP FOR EACH VARIABLE
for variable=1:NumberOfVar

    [Name TOffset nbytes VClass flags dum1 dim DiscClass DiscOffset]...
        =GetVariableHeader(fh);

    % If where(filename, tagoffset) call type, s(1).name will be empty
    if strcmp(Name,'0123456789') && ~isempty(s(1).name)
        continue
    end

    if nargin==2 && isnumeric(varargin{1})
        % Called as where(filename,TagOffset)
        ThisVar=1;
        s(1).name=Name;
        s(1).size=dim;
        s(1).class=VClass;
        s(1).bytes=nbytes;
        s(1).global=bitget(flags,3);
        s(1).complex=bitget(flags,4);
        s(1).flags=uint8(flags);
        s(1).TagOffset=TOffset;
        s(1).DataOffset{1}.DiscOffset=DiscOffset;
        s(1).DiscClass=DiscClass;
    else
        % Otherwise
        ThisVar=0;
        for ivar=1:length(s)
            if strcmp(Name,s(ivar).name)
                ThisVar=ivar;
                break;
            end
        end
    end

    % This variable not in required list
    if ThisVar==0
        fseek(fh,double(TOffset+nbytes+8),'bof');
        continue
    end

    %Return values if a standard MATLAB matrix
    s(ThisVar).flags=uint8(flags);
    s(ThisVar).TagOffset=TOffset;
    s(ThisVar).DataOffset{1}.DiscOffset=DiscOffset;
    s(ThisVar).DiscClass=DiscClass;

    % But, check if we are dealing with a structure
    % If so, s(i).DataOffset becomes a cell array with one
    % element for each field
    if strcmpi(VClass,'struct') || strcmpi(VClass,'object')
        % object
        if strcmpi(VClass,'object')
            ObjectType=fread(fh,1,'uint32=>uint32');
            if (system_endian=='L' && ObjectType>intmax('uint16')) ||...
                    (system_endian=='B' && ObjectType<intmax('uint16'))
                fseek(fh,-4,'cof');
                [ObjectBytes, ObjectType, values]=GetSmallDataElement(fh, fileformat);
                % ObjectType=mi{ObjectType};
            else
                ObjectType=mi{ObjectType};
                ObjectBytes=fread(fh,1,'uint32');
                temp=fread(fh,ObjectBytes,ObjectType);
                ByteAlign(fh);
            end
        end

        % object or structure
        [a b FieldNameLength]=GetSmallDataElement(fh, fileformat);
        FieldNameType=fread(fh,1,'uint32');
        FieldNameType=mi{FieldNameType};
        FieldNameArraySize=fread(fh,1,'uint32');
        for f=1:FieldNameArraySize/FieldNameLength
            s(ThisVar).DataOffset{f}.name=...
                deblank(fread(fh,double(FieldNameLength),[FieldNameType '=>char'])');
        end
        ByteAlign(fh);

        for f=1:FieldNameArraySize/FieldNameLength
            [name os n cl flags bytes dim DiscClass DiscOffset]...
                =GetVariableHeader(fh);
            s(ThisVar).DataOffset{f}.size=dim;
            s(ThisVar).DataOffset{f}.class=cl;
            s(ThisVar).DataOffset{f}.bytes=n;
            s(ThisVar).DataOffset{f}.global=bitget(flags,3);
            s(ThisVar).DataOffset{f}.complex=bitget(flags,4);
            s(ThisVar).DataOffset{f}.flags=uint8(flags);
            s(ThisVar).DataOffset{f}.TagOffset=os;
            s(ThisVar).DataOffset{f}.DiscOffset=DiscOffset;
            s(ThisVar).DataOffset{f}.DiscClass=DiscClass;
            fseek(fh,double(os+n+8),'bof');
        end

    end
    %Next variable on disc
    fseek(fh,double(TOffset+nbytes+8),'bof');

end

% Failed to find field or property
if isempty(s)
    disp(sprintf('WHERE: the variable "%s" was not found',varargin{1}));
    s=[];
    return;
end

% Digging through nested fields/properties
if nargin>=3
    for argn=2:length(varargin)
        found=false;
        for indexn=1:length(s(1).DataOffset)
            if strcmp(s(1).DataOffset{indexn}.name,varargin{argn})==1
                %Re-entrant call to where
                s=where(filename, s(1).DataOffset{indexn}.TagOffset);
                found=true;
                break;
            end
        end
        if found==false
            s=[];
            mess='';
            for w=1:argn
                mess=horzcat(mess,[varargin{w} '.']);
            end
            mess=mess(1:end-1);
            disp(sprintf('WHERE: The field or property %s was not found',mess));
            return;
        end
    end
end

% Form the name if WHERE was called with field/property list
if nargin>2
    for narg=2:nargin-1
        s(1).name=[s(1).name varargin{narg-1} '.'];
    end
    s(1).name=[s(1).name varargin{end}];
end

% If no output arguments, display the results
if nargout==0
    DisplayOutput(s);
end

fclose(fh);

%<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    function [N_name, TagOffset, NumberOfBytes, AF_class, AF_flags,...
            DA_NumberOfBytes, DA_dim, DiscClass, DiscOffset]=GetVariableHeader(fh)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        N_name='0123456789';%invalid variable name
        DiscClass{1}='unknown';
        AF_class='compressed';
        AF_flags=uint8(0);
        DiscOffset=NaN;
        DA_NumberOfBytes=NaN;
        DA_dim=[NaN NaN];

        %Read the Tag
        TagOffset=ftell(fh);
        DataType=fread(fh,1,'uint32=>uint32');
        DataType=mi{DataType};
        NumberOfBytes=fread(fh,1,'uint32');
        if strcmpi(DataType,'compressed')
            fseek(fh,TagOffset+NumberOfBytes+8,'bof');
            return
        end

        %Array Flags
        fread(fh,1,'uint32=>uint32');
        fread(fh,1,'uint32=>uint32');

        temp=fread(fh,4,'uint8=>uint8');
        if strcmp(fileformat,'ieee-le')
            AF_flags=temp(2);
            AF_class=mx{temp(1)};
        else
            AF_flags=temp(3);
            AF_class=mx{temp(4)};
        end


        % Check this is a mappable class - if not return & skip to next entry
        if strcmpi(AF_class,'custom') ||...
                strcmpi(AF_class,'cell') ||...
                strcmpi(AF_class,'function') ||...
                strcmpi(AF_class,'sparse')
            fseek(fh,TagOffset+NumberOfBytes+8,'bof');
            ByteAlign(fh);
            return
        end


        fseek(fh,4,'cof');

        %Dimensions array
        temp=fread(fh,1,'uint32=>uint32');
        DA_DataType=mi{temp};
        DA_NumberOfBytes=fread(fh,1,'uint32');
        n=DA_NumberOfBytes/sizeof(DA_DataType);
        DA_dim=fread(fh,n,DA_DataType);

        if strcmpi(AF_class,'struct') && max(DA_dim)>1
            fseek(fh,TagOffset+NumberOfBytes+8,'bof');
            ByteAlign(fh);
            return
        end
        ByteAlign(fh);

        %Name Array
        N_DataType=fread(fh,1,'uint32');
        if (system_endian=='L' && N_DataType>intmax('uint16')) ||...
                (system_endian=='B' && N_DataType<intmax('uint16'))
            fseek(fh,-4,'cof');
            [N_NumberOfBytes, N_DataType, values]=GetSmallDataElement(fh, fileformat);
            %            N_DataType=mi{N_DataType};
            N_name=char(values);
        else
            N_DataType=mi{N_DataType};
            N_NumberOfBytes=fread(fh,1,'uint32');
            n=N_NumberOfBytes/sizeof(N_DataType);
            N_name=fread(fh,n,[N_DataType '=>char'])';
        end
        N_name=deblank(N_name);
        ByteAlign(fh);

        switch AF_class
            case 'struct'
                DiscClass{1}='struct';
                DiscOffset=NaN;
            case 'object'
                DiscClass{1}='object';
                DiscOffset=NaN;
            case 'unknown'
                fseek(fh,TagOffset+NumberOfBytes+8,'bof');
            otherwise
                temp=fread(fh,1,'uint32');
                if (system_endian=='L' && temp>intmax('uint16')) ||...
                        (system_endian=='B' && temp<intmax('uint16'))
                    fseek(fh,-4,'cof');
                    [BytesOfData, temp, values]=GetSmallDataElement(fh, fileformat);
                    DiscOffset=ftell(fh)-4;
                else
                    BytesOfData=fread(fh,1,'uint32');
                    DiscOffset=ftell(fh);
                end
                DiscClass{1}=mi{temp};
                if bitget(AF_flags,4)% complex data
                    fseek(fh,DiscOffset+BytesOfData,'bof');
                    ByteAlign(fh);
                    temp=fread(fh,1,'uint32');
                    BytesOfData(2)=NaN;
                    if (system_endian=='L' && temp>intmax('uint16')) ||...
                            (system_endian=='B' && temp<intmax('uint16'))
                        fseek(fh,-4,'cof');
                        [BytesOfData(2), temp, values]=GetSmallDataElement(fh, fileformat);
                        DiscOffset(2)=ftell(fh)-4;
                    else
                        fread(fh,1,'uint32');
                        DiscOffset(2)=ftell(fh);
                    end
                    DiscClass{2}=mi{temp};
                end
        end
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function DisplayOutput(s)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%General header
fprintf('\n-------------------------------------------------------------------------------------------------\n');
fprintf('\t%-8s\t',...
    'Name',...
    'Size',...
    'Bytes',...
    'Class',...
    'TagOffset',...
    'DataOffset');
fprintf('\n');
fprintf('---------------------------------------------------------------------------------------------------\n');

%Loop for each variable

for i=1:length(s)

    if bitget(s(i).flags,4)==1
        c='(real)';
    else
        c='';
    end
    fprintf('\n\t%-12s\t',s(i).name);
    n=ndims(s(i).size);
    for j=1:n-1
        fprintf('%8dx',s(i).size(j));
    end
    fprintf('%-8d',s(i).size(n));
    fprintf('%-10d%15s',...
        s(i).bytes,[s(i).DiscClass{1} '=>' s(i).class c])
    fprintf('\t\t%-12d',s(i).TagOffset);

    % Structure/object or simple matrix
    if isfield(s(i).DataOffset{1},'name')
        fprintf('\n');
        for k=1:length(s(i).DataOffset)
            if s(i).DataOffset{k}.complex==1
                c='(real)';
            else
                c='';
            end
            fprintf('\t.%-12s\t',s(i).DataOffset{k}.name);
            n=ndims(s(i).DataOffset{k}.size);
            for j=1:n-1
                fprintf('%8dx',s(i).DataOffset{k}.size(j));
            end
            fprintf('%-8d\t',s(i).DataOffset{k}.size(n));
            fprintf('%-10d%15s',s(i).DataOffset{k}.bytes,...
                [s(i).DataOffset{k}.DiscClass{1} '=>' s(i).DataOffset{k}.class c]);
            fprintf('\t\t%-12d',s(i).DataOffset{k}.TagOffset);
            fprintf('\t%-12d \n',s(i).DataOffset{k}.DiscOffset(1));
            %Second line for imaginary part if complex
            if bitget(s(i).DataOffset{k}.flags,4)==1
                fprintf('%70s',...
                    [s(i).DataOffset{k}.DiscClass{2} '=>' s(i).DataOffset{k}.class '(imag)']);
                fprintf('\t%20d \n',s(i).DataOffset{k}.DiscOffset(2));
            end
        end
    else
        %Simple matrix
        fprintf('\t%-12d \n',s(i).DataOffset{1}.DiscOffset(1));
    end

    %Second line for imaginary part if complex
    if s(i).complex==1
        fprintf('%70s',...
            [s(i).DiscClass{2} '=>' s(i).class '(imag)']);
        fprintf('\t%20d \n',s(i).DataOffset{1}.DiscOffset(2));
    end
end
end



Contact us at files@mathworks.com