⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bffio.m

📁 toolbox of BVQX, This is the access between BV and matlab. It will help you to analysis data from BV
💻 M
📖 第 1 页 / 共 3 页
字号:
function [varargout] = bffio(varargin)
% bffio  - read/write binary file with BFF spec (and content)
%
% FORMAT:       bffcont = bffio(filename, bffspec [, options])
%          OR   bffio(wfilename, bffspec, bffcont [, options])
%
% Input fields:
%
%       filename    filename of binary file to read
%       bffspec     either filename or content or spec struct of BFF
%       options     optional arguments, one of
%                   'verbose', 'v' or '-v' (for verbose reading/writing)
%                   'force', 'f', '-f' (for returning partial content)
%
%       wfilename   filename of binary file to write
%       bffcont     file content (struct)
%
% Output fields:
%
%       bffcont     file contents struct (depending on BFF)
%
% See also bffdocu, bffparse

% Version:  v0.7b
% Build:    7083014
% Date:     Aug-30 2007, 2:50 PM CEST
% Author:   Jochen Weber, Brain Innovation, B.V., Maastricht, NL
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

bffversion = 'v0.7b';

% argument check
if nargin < 2 || ...
   ~ischar(varargin{1}) || ...
    isempty(varargin{1}) || ...
   (~isstruct(varargin{2}) && ...
    ~ischar(varargin{2})) || ...
    isempty(varargin{2})
    error( ...
        'BVQXtools:BadArgument', ...
        'Bad or missing argument for bffio.' ...
    );
end
filename = varargin{1}(:)';
bffspec  = varargin{2}(:)';
bffcont  = [];

% default options
forcemode   = false;
verbosemode = false;
writemode   = false;

% bff content structure given
if nargin > 2 && ...
    isstruct(varargin{3}) && ...
   ~isempty(varargin{3})
    bffcont = varargin{3};
    writemode = true;
end

% check additional arguments
if nargin > 2
    for argc = 3:nargin

        % what is given
        argv = varargin{argc};

        % character argument
        if ischar(argv)

            % known argument
            switch lower(argv)

                % force mode
                case {'f', 'force', '-f'}
                    forcemode = true;

                % verbose mode
                case {'v', 'verbose', '-v'}
                    verbosemode = true;

            end

        % discard other arguments/options
        end
    end
end

% BFF is a valid SPEC struct
if isstruct(bffspec) && ...
   ~isempty(bffspec) && ...
    isfield(bffspec, 'AfterReadCode') && ...
    ischar(bffspec.AfterReadCode) && ...
    isfield(bffspec, 'BeforeWriteCode') && ...
    ischar(bffspec.BeforeWriteCode) && ...
    isfield(bffspec, 'EncodingSyntax') && ...
    ischar(bffspec.EncodingSyntax) && ...
   ~isempty(bffspec.EncodingSyntax) && ...
    isfield(bffspec, 'Extensions') && ...
    iscell(bffspec.Extensions) && ...
    isfield(bffspec, 'FilenameMatch') && ...
    iscell(bffspec.FilenameMatch) && ...
    isfield(bffspec, 'ListOfFields') && ...
    isstruct(bffspec.ListOfFields) && ...
    isfield(bffspec, 'Loops') && ...
    isstruct(bffspec.Loops) && ...
    isfield(bffspec, 'Magic') && ...
    isstruct(bffspec.Magic) && ...
    isfield(bffspec, 'TransIOSize') && ...
    isa(bffspec.TransIOSize, 'double') && ...
    length(bffspec.TransIOSize) == 1 && ...
    isfield(bffspec, 'Variables') && ...
    isstruct(bffspec.Variables)

% any other struct is rejected
elseif isstruct(bffspec)
    error( ...
        'BVQXtools:BadArgument', ...
        'Invalid struct BFF specification.' ...
    );

% for character arrays
elseif ischar(bffspec)

    % valid file contents (0x0a/0x0d delimited)
    if ...
        any(bffspec == char(10) | bffspec == char(13)) || ...
        exist(bffspec, 'file') == 2

        % parse content
        try
            if ~writemode
                varargout{1} = bffio( ...
                    filename, ...
                    bffparse(bffspec), ...
                    varargin{:});
            else
                [varargout{:}] = bffio( ...
                    filename, ...
                    bffparse(bffspec), ...
                    varargin{:});
            end
            return;
        catch
            rethrow(lasterror);
        end
    end

    % otherwise
    error( ...
        'BVQXtools:BadArgument', ...
        'Invalid bffspec argument given.' ...
    );

end

% initialize rules variables
rule  = bffspec.ListOfFields;
rules = length(rule);

% get critical transio size
tiosz = bffspec.TransIOSize;
tiole = bffspec.EncodingSyntax;

% get loops shortcut and prepare loopi struct, loopx
loops = bffspec.Loops;
loopf = fieldnames(loops);
if ~isempty(loopf)
    loopf = fieldnames(loops.(loopf{1}));
    loopi = cell2struct(cell(0, 0, length(loopf)), loopf, 3);
else
    loopi = struct;
end
loopx = {};

% get file extension
[fnamex{1:3}] = fileparts(filename);
fnamex = fnamex{3};
fnamex(fnamex == '.') = [];

% initialize output
if isempty(bffcont)
    bffcont = struct;
end

% initialize internal variables
namevars = struct;
namevars.BFFVERSION = bffversion;
namevars.BFFPATH    = fileparts(mfilename('fullpath'));
namevars.BFFREAD    = ~writemode;
namevars.BFFWRITE   =  writemode;
namevars.FILENAME   = filename;
namevars.EXTENSION  = fnamex;

% reading BFF content
if ~writemode

    % create transio object template if size suggests it
    if ~isinf(tiosz)
        try
            tioobjt = transio(filename, tiole, 'uint32', 0, [1, 1]);
        catch
            warning( ...
                'BVQXtools:TransIOError', ...
                'Error using transio for file ''%s''.', ...
                filename ...
            );
            tiosz = Inf;
        end
    end
    
    % check file (opening in little endian syntax by default)
    fid = fopen(filename, 'r', tiole);
    if fid < 1
        error( ...
            'BVQXtools:FileNotReadable', ...
            'File not readable: ''%s''.', ...
            filename ...
        );
    end

    % get file size
    fseek(fid, 0, 1);
    flen = ftell(fid);
    fseek(fid, 0, -1);
    namevars.FILESIZE   = flen;

% writing BFF content
else

    % BeforeWriteCode ?
    if ~isempty(bffspec.BeforeWriteCode)
        try
            eval(bff_parsecode( ...
                bffspec.BeforeWriteCode(:)', 'namevars', 'bffcont'));
        catch
            error( ...
                'BVQXtools:EvaluationError', ...
                'Error raised by BeforeWriteCode: ''%s''.', ...
                lasterr ...
            );
        end
    end

    % check open writable file
    wfilename = [filename '.tmp'];
    fid = fopen(wfilename, 'w', tiole);
    if fid < 1
        error( ...
            'BVQXtools:FileNotWritable', ...
            'File not writable: ''%s''.', ...
            wfilename ...
        );
    end

    % for verbose mode, we also need read access
    if verbosemode

        % close file (it has been truncated now)
        fclose(fid);

        % open again with write AND read access
        fid = fopen(wfilename, 'w+', tiole);
        if fid < 1
            warning( ...
                'BVQXtools:FileNotReadWritable', ...
                'File cannot be opened in ''w+'' mode: ''%s''.', ...
                wfilename ...
            );
            fid = fopen(wfilename, 'w', tiole);
            verbosemode = false;
        end

        % check file id once more, just to make sure
        if fid < 1
            error( ...
                'BVQXtools:FileNotWritable', ...
                'File not writable: ''%s''.', ...
                wfilename ...
            );
        end
    end
end

% grand loop
rulec = 1;  % pointer to next rule to process
loopc = 0;  % counter of loops (in which loop are we)

% try used for forcemode (on indentation !!!)
try % forcemode

while rulec <= rules

    % get shortcut to current rule to process (and subfields)
    prule = rule(rulec);
    rtype = lower(prule.type);
    rdisk = lower(prule.disktype);
    rdsks = prule.disksize;
    rdata = lower(prule.datatype);
    rcond = bff_parsecode(prule.cond,    'namevars', 'bffcont');
    rdim  = bff_parsecode(prule.dim,     'namevars', 'bffcont');
    % rdefv = bff_parsecode(prule.default, 'namevars', 'bffcont');
    rexpr = bff_parsecode(prule.varname, 'namevars', 'bffcont');

    % try to resolve dim
    if isempty(rdim)
        rdim = [1, 1];
    elseif ischar(rdim)
        try
            eval(['rdim=double([' rdim ']);']);
            if isempty(rdim)
                error('EMPTYDIM');
            elseif size(rdim, 2) < 2
                rdim = [1 rdim];
            end
        catch
            error( ...
                'BVQXtools:BadExpression', ...
                'Couldn''t evaluate DIM expression: ''%s''.', ...
                prule.dim ...
            );
        end
    end

    % what to do
    switch (rtype)

        % begin of a loop
        case {'bloop'}

            % check loop var syntax (and extract dim, if needed)
            [ldimmatcht{1:3}] = regexpi( ...
                rexpr, '^([a-z][a-z_0-9]*)(\(\d+\))?');
            ldimmatcht = ldimmatcht{3};
            if isempty(ldimmatcht)
                error( ...
                    'BVQXtools:BadBFFSpec', ...
                    'Invalid LOOP variable name given: ''%s''.', ...
                    rexpr ...
                );
            end
            lvname = rexpr(ldimmatcht{1}(1, 1):ldimmatcht{1}(1, 2));
            if size(ldimmatcht{1}, 1) > 1 && ...
                ldimmatcht{1}(2, 2) > ldimmatcht{1}(2, 1)
                ldim = str2double(rexpr(ldimmatcht{1}(2, 1):ldimmatcht{1}(2, 2)));
            else
                ldim = 1;
            end

            % check whether appropriate entry in Loops.(...) exists
            if ~isfield(loops, lvname) || ...
                length(loops.(lvname)) < ldim
                error( ...
                    'BVQXtools:BadBFFSpec', ...
                    'Invalid LOOP variable given (not found: ''%s''.', ...
                    rexpr ...
                );
            end

            % get specific loop info
            loopinfo = loops.(lvname)(ldim);

            % check whether the loop should be entered at all
            enterloop = true;
            if ~isempty(rcond)
                enterloop = false;
                try
                    eval(['if ' rcond ',enterloop = true;end']);
                catch
                    error( ...
                        'BVQXtools:BadExpression', ...
                        'Couldn''t evaluate COND expression: ''%s''.', ...
                        rcond ...
                    );
                end
            end

            % if we're entering the loop
            if enterloop

                % try to resolve loop dim
                try
                    loopinfo.dim = eval( ...
                        bff_parsecode(loopinfo.dim, 'namevars', 'bffcont'));
                catch
                    error( ...
                        'BVQXtools:BadExpression', ...
                        'Couldn''t evaluate LOOP.DIM expression: ''%s''.', ...
                        loopinfo.dim ...
                    );
                end

                % initialize loop counter
                try
                    eval(['namevars.' rexpr '=1;']);
                catch
                    error( ...
                        'BVQXtools:BadExpression', ...
                        'Error initializing LOOP counter ''%s'' to 1.', ...
                        rexpr ...
                    );
                end

                % only truly enter loop if dim is > 0
                if loopinfo.dim > 0

                    % increase loop counter and keep track of loop variable name
                    loopc = loopc + 1;
                    loopi(loopc) = loopinfo;
                    loopx{loopc} = rexpr;

                % otherwise
                else

                    % skip loop
                    rulec = loopinfo.lastrule;
                end

            % we're not entering the loop
            else

                % set current rule pointer to end of loop
                rulec = loopinfo.lastrule;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -