function metaStruct = TDMS_preprocessFile(fid,tdmsFileName,params)
%TDMS_preprocessFile Populates props and gets segment information
%
% NOTE: This file shouldn't be called directly by the user
%
% metaStruct = TDMS_preprocessFile(fid,tdmsFileName,params)
%
% INPUTS
% =======================================================================
% fid : file id of opened tdms file, may be null if INDEX_DEBUG is true
% tdmsFileName : full path to tdms file OR tdms index file for INDEX_DEBUG
% params : all optional inputs from TDMS_readTDMSFile
%
% OUTPUTS
% =======================================================================
% metaStruct :
% structure with fields:
%
% The following 3 variables are all the same length, and have one index
% for each unique object. Each object may be one of the following types,
% file root, group object, or channel object. Only channel objects may
% have data.
%
% rawDataInfo : (structure array)
% NOTE: This holds the most recent info for an object, and can be
% changed on a per segment basis, segInfo is used to hold
% information that is needed per segement
%
% .lengthOfIndex - length of raw data index (not used)
% .dataType - enumerated dataType (Labview)
% .dimensionData - currently ignored (should be 1d)
% .numberOfValues - # of values to read each time
% .totalSizeBytes - # of bytes per values
% .numberProperties - # of properties defined for the object
% .infoSet - a logical on whether or not this data has
% been set (for error checking)
% .propNames - a cell array for definining property names
% .propValues - cell array for holding property values
%
% numberDataPoints : an array which specifies the # of data points for
% each object (used for preallocation)
% objectNameList : (cell array of strings) names of all objects in the
% TDMS file
%
% Info for each segment ...
%
% segInfo : (struct array)
% .rawPos - position of raw data for that segment
% .kTocNewObjList - flag on whether a new channel list was
% created or not
% .objOrder - array specifying indices of the objects to assign
% data to, order specifies read order, and values
% are indexed
% into the objectNameList & rawDataInfo struct
% .nRawObjects - length of objOrder
% .nSamplesRead - array, # of samples to read for each object
% .isInterleaved - logical, whether that segment uses interleaved
% data or not
% .isBigEndian - logical
% .nChunks - # of times to read data using the parameters
% above before moving onto the next segment
%
% See also: TDMS_processLeadIn, TDMS_getDataSize, TDMS_getPropValue
%PARAMETERS - passed in from TDMS_readTDMSFile
%==========================================================================
UTC_DIFF = params.UTC_DIFF;
MAX_NUM_OBJECTS = params.MAX_NUM_OBJECTS;
MAX_NUM_PROPS = params.MAX_NUM_PROPS;
N_SEGS_GUESS = params.N_SEGS_GUESS;
N_SEGS_INC = params.N_SEGS_INC;
DEBUG = params.DEBUG;
DATE_STR_FORMAT = params.DATE_STR_FORMAT;
UNICODE_FORMAT = params.STRING_ENCODING;
USE_INDEX = params.USE_INDEX;
INIT_CHUNK_SIZE = params.INIT_CHUNK_SIZE;
TDMS_INDEX_EXT = params.TDMS_INDEX_EXT;
MACHINE_FORMAT = params.MACHINE_FORMAT;
STRING_ENCODING = params.STRING_ENCODING;
CURRENT_VERSION = params.CURRENT_VERSION;
INDEX_DEBUG = params.INDEX_DEBUG;
%DONT CHANGE THESE
%==========================================================================
LEAD_IN_LENGTH = 28; %# of bytes of lead in
%FIGURING OUT WHICH FILE TO READ
%==========================================================================
[tdmsPathToFile,tdmsNameOnly] = fileparts(tdmsFileName);
if isempty(params.META_STRUCT)
isIndexFID = false;
if USE_INDEX || INDEX_DEBUG
if INDEX_DEBUG
indexFile = tdmsFileName;
else
indexFile = fullfile(tdmsPathToFile,[tdmsNameOnly TDMS_INDEX_EXT]);
end
if exist(indexFile,'file')
fid = fopen(indexFile,'r',MACHINE_FORMAT,STRING_ENCODING);
isIndexFID = true;
else
%Just use the tdms file, which we have already tested to exist
if INDEX_DEBUG
%NOTE: With INDEX_DEBUG we explicitly passed in the index
%file to read and parse (generally for debugging purposes
%so if it doesn't exist, then we have a problem
error('Specified tdms_index file doesn not exist')
end
end
end
else
%Quits early if meta struct input is valid
%======================================================================
metaStruct = params.META_STRUCT;
if ~isstruct(metaStruct) || ~isfield(metaStruct,'version') || ~isfield(metaStruct,'fileName')
error('The META_STRUCT parameter passed should be a structure with fields "version" and "fileName"')
end
if metaStruct.version ~= CURRENT_VERSION
error('Mismatch in version creation, version of struct %d, please run with latest version: %d')
end
if ~strcmpi(metaStruct.fileName,tdmsNameOnly)
fprintf('Filename from metaStruct: %s\n',metaStruct.fileName);
fprintf('Filename from input: %s\n',tdmsNameOnly);
error('Mismatch in filenames, see printout above')
end
return
end
if isIndexFID
lastLetter = double('h'); %used for .tdms_index files
else
lastLetter = double('m'); %used for .tdms files
end
%INITIALIZE OUTPUTS
%==========================================================================
curNumTotalObjects = 0; %Current # of objects
numberDataPoints = zeros(1,MAX_NUM_OBJECTS);
objectNameList = cell(1,MAX_NUM_OBJECTS); %names of all objects
rawDataInfo = initRawInfoStruct(MAX_NUM_PROPS,MAX_NUM_OBJECTS);
segInfo = initSegStruct(N_SEGS_GUESS);
%==========================================================================
%TEMP VARIABLES
%==========================================================================
objectHasRawData = false(1,MAX_NUM_OBJECTS); %This is needed for adding
%# of data points together
ranOnce = false;
nSegs = 0;
%Get eof & return to start
fseek(fid,0,1);
eofPosition = ftell(fid);
fseek(fid,0,-1);
%START OF READING
%==========================================================================
curPosCounter = 0; %Used to keep track of where in the actual tdms file we
%would be at various points, this is used for parsing verification as well
%as assisting with more complicated reads
while ftell(fid) ~= eofPosition
nSegs = nSegs + 1;
if nSegs > length(segInfo)
segInfo = [segInfo initSegStruct(N_SEGS_INC)]; %#ok<AGROW>
end
if DEBUG
disp('------ START OF DEBUG -------')
fprintf(2,'CURRENT SEGMENT: %d\n',nSegs);
fprintf(2,'Current file position: %d\n',curPosCounter);
end
%LEAD IN HANDLING
%======================================================================
[flags,info,eof_error] = TDMS_processLeadIn(fid,lastLetter);
if eof_error
%This should only happen once at the end
fprintf(2,['WARNING: File was not closed properly.\n' ...
'Data will most likely be missing at the end of the file\n']);
nSegs = nSegs - 1;
break
end
curPosCounter = curPosCounter + LEAD_IN_LENGTH + info.segLength;
segInfo(nSegs).rawPos = curPosCounter -