📄 bffparse.m
字号:
function bffspec = bffparse(bffcont)
% bffparse - parse BFF binary file format description
%
% FORMAT: bffspec = bffparse(bffcont)
%
% Input fields:
%
% bffcont 1xN char: BFF specification file name or content
%
% Output fields:
%
% bffspec 1x1 struct with BFF specification
%
% See also bffdocu, bffio
% Version: v0.7b
% Build: 7083014
% Date: Aug-30 2007, 2:51 PM CEST
% Author: Jochen Weber, Brain Innovation, B.V., Maastricht, NL
% URL/Info: http://wiki.brainvoyager.com/BVQXtools
bffversion = 'v0.7b';
default_tiosize = Inf;
% create persistent datatype sizes struct if needed
persistent bff_dtsize;
if isempty(bff_dtsize)
bff_dtsize = struct( ...
'double', 8, ...
'int16', 2, ...
'int32', 4, ...
'int64', 8, ...
'int8', 1, ...
'single', 4, ...
'uchar', 1, ...
'uint16', 2, ...
'uint32', 4, ...
'uint64', 8, ...
'uint8', 1 ...
);
end
% argument check
if nargin < 1 || ...
~ischar(bffcont) || ...
isempty(bffcont)
error( ...
'BVQXtools:BadArgument', ...
'Invalid BFF specification argument given.' ...
);
end
% check for line feeds and try to read file
if ~any(bffcont == char(10))
if exist(bffcont, 'file') ~= 2
error( ...
'BVQXtools:FileNotFound', ...
'Either invalid content or file not found.' ...
);
end
% read bffspec
try
bffcont = asciiread(bffcont);
catch
rethrow(lasterror);
end
end
% check content
if isempty(strfind(bffcont, 'BinaryFileFormat'))
error( ...
'BVQXtools:BadBFFSpec', ...
'Invalid BFF specification file/content given.' ...
);
end
% split into lines
bfflines = splittocell(bffcont(:)', char([10, 13]), 1, 1);
% remove empty ones and comments
for lc = length(bfflines):-1:1
% deblank lines
bffline = deblank(bfflines{lc});
% remove comment
bffcomm = find(bffline == '#');
if ~isempty(bffcomm)
bffline(bffcomm(1):end) = [];
bfflines{lc} = bffline;
end
% if is empty, remove line
if isempty(bffline)
bfflines(lc) = [];
continue;
end
end
% initialize content
bffspec = struct;
bffspec.FFTYPE = 'BFF';
bffspec.BFFVERSION = bffversion;
bffspec.AfterReadCode = '';
bffspec.BeforeWriteCode = '';
bffspec.Description = 'All files';
bffspec.EncodingSyntax = 'native';
bffspec.Extensions = {};
bffspec.FilenameMatch = {};
bffspec.Filetype = 'Custom BFF file';
bffspec.ListOfFields = cell2struct(cell(0,0,0), {}, 3);
bffspec.Loops = struct;
bffspec.Magic = cell2struct(cell(0,0,0), {}, 3);
bffspec.NewFileCode = '';
bffspec.TransIOSize = default_tiosize;
bffspec.Variables = struct;
% parse content
lc = 1;
llc = length(bfflines);
while (lc <= llc)
% regexpi line matches '<TOKEN>:<VALUE>' ?
bffline = bfflines{lc};
[tlmatcht{1:3}] = regexpi( ...
bffline, '^([a-z][a-z_0-9]*)\:\s*(.*)\s*$');
tlmatcht = tlmatcht{3};
% continue with next line if no match
lc = lc + 1;
if isempty(tlmatcht)
continue;
end
% handle those sections/keywords:
bffkey = bffline(tlmatcht{1}(1, 1):tlmatcht{1}(1, 2));
bffval = bffline(tlmatcht{1}(2, 1):tlmatcht{1}(2, 2));
switch (lower(bffkey))
% after read code snippet
case {'afterreadcode'}
% find "EndAfterReadCode"
endline = llc + 1;
for slc = lc:llc
if ~isempty(regexpi(bfflines{slc}, '^endafterreadcode'))
endline = slc - 1;
break;
end
end
% check endline
if endline > llc
error( ...
'BVQXtools:BadBFFSpec', ...
'Unclosed AfterReadCode section in BFF spec.' ...
);
end
% generate and check code snippet
codesnip = gluetostring(bfflines(lc:endline), char(10), 1);
tcodesnip = codesnip;
tcodesnip(tcodesnip == '$' | tcodesnip == '@') = [];
try
eval(['if 1==0,' tcodesnip ';end']);
catch
error( ...
'BVQXtools:BadBFFSpec', ...
'Syntax error detected in AfterReadCode: ''%s''.', ...
lasterr ...
);
end
% store code
bffspec.AfterReadCode = codesnip;
% before write code snippet
case {'beforewritecode'}
% find "EndBeforeWriteCode"
endline = llc + 1;
for slc = lc:llc
if ~isempty(regexpi(bfflines{slc}, '^endbeforewritecode'))
endline = slc - 1;
break;
end
end
% check endline
if endline > llc
error( ...
'BVQXtools:BadBFFSpec', ...
'Unclosed BeforeWriteCode section in BFF spec.' ...
);
end
% generate and check code snippet
codesnip = gluetostring(bfflines(lc:endline), char(10), 1);
tcodesnip = codesnip;
tcodesnip(tcodesnip == '$' | tcodesnip == '@') = [];
try
eval(['if 1==0,' tcodesnip ';end']);
catch
error( ...
'BVQXtools:BadBFFSpec', ...
'Syntax error detected in BeforeWriteCode: ''%s''.', ...
lasterr ...
);
end
% store code
bffspec.BeforeWriteCode = codesnip;
% file open description
case {'description'}
bffspec.Description = splittocell(bffval, ';,', 1, 1);
% encoding syntax
case {'encodingsyntax'}
bffspec.EncodingSyntax = bffval;
% valid extensions list
case {'extensions'}
bffspec.Extensions = splittocell(bffval, ';,. ', 1, 1);
% valid extensions list
case {'filenamematch'}
bffspec.FilenameMatch = splittocell(bffval, ';, ', 1, 1);
% list of fields
case {'listoffields'}
% find "EndListOfFields" line
endline = llc + 1;
for slc = (lc + 1):llc
if ~isempty(regexpi(bfflines{slc}, '^endlistoffields'))
endline = slc - 1;
break;
end
end
blc = lc;
lc = endline + 1;
% invalid ListOfFields
if lc > llc
error( ...
'BVQXtools:BadBFFSpec', ...
'Unclosed or bad ListOfFields block.' ...
);
end
% list/table field separator
listsep = bffval;
% get rule headers
rhead = splittocell(bfflines{blc}, listsep, 0);
% build header struct
hstruct = struct;
for hfc = 1:length(rhead)
hfield = lower(makelabel(rhead{hfc}));
hstruct.(hfield) = hfc;
rhead{hfc} = hfield;
end
blc = blc + 1;
% bail out if invalid header given
if ~isfield(hstruct, 'type') || ...
~isfield(hstruct, 'cond') || ...
~isfield(hstruct, 'disktype') || ...
~isfield(hstruct, 'datatype') || ...
~isfield(hstruct, 'dim') || ...
~isfield(hstruct, 'default') || ...
~isfield(hstruct, 'varname')
warning( ...
'BVQXtools:BadBFFSpec', ...
'ListOfFields with bad headers.' ...
);
continue;
end
% get list of header field names (in their order)
hfields = fieldnames(hstruct);
nfields = length(hfields);
% build empty field list struct
frules = cell2struct(cell(1, 1, nfields), hfields, 3);
frules.disksize = 0;
frules(1) = [];
% check global fieldlist struct
tfields = fieldnames(bffspec.ListOfFields);
% no rules yet -> OK
if isempty(tfields)
bffspec.ListOfFields = frules;
% otherwise compare header fields
else
% assume no mismatch
headermismatch = false;
% check number of fields
if length(tfields) ~= length(fieldnames(frules))
headermismatch = true;
else
% only if still content in tfields, check names
for tfc = 1:nfields
if ~strcmp(tfields{tfc}, hfields{tfc})
headermismatch = true;
break;
end
end
end
% if mismatch give warning and continue with next block
if headermismatch
warning( ...
'BVQXtools:BadBFFSpec', ...
'ListOfFields blocks must match in their headers.' ...
);
continue;
end
end
% build list of rules to consider
actrules = frules;
for slc = blc:endline
% split to fields
rcont = splittocell(bfflines{slc}, listsep, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -