1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
|
package uk.ac.bristol.star.cdf;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import uk.ac.bristol.star.cdf.record.AttributeDescriptorRecord;
import uk.ac.bristol.star.cdf.record.AttributeEntryDescriptorRecord;
import uk.ac.bristol.star.cdf.record.Buf;
import uk.ac.bristol.star.cdf.record.CdfDescriptorRecord;
import uk.ac.bristol.star.cdf.record.DataReader;
import uk.ac.bristol.star.cdf.record.GlobalDescriptorRecord;
import uk.ac.bristol.star.cdf.record.Record;
import uk.ac.bristol.star.cdf.record.RecordFactory;
import uk.ac.bristol.star.cdf.record.VariableDescriptorRecord;
/**
* Provides all the data and metadata in a CDF file in a high-level
* read-only easy to use form.
*
* @author Mark Taylor
* @since 20 Jun 2013
*/
public class CdfContent {
private final CdfInfo cdfInfo_;
private final GlobalAttribute[] globalAtts_;
private final VariableAttribute[] variableAtts_;
private final Variable[] variables_;
/**
* Constructs a CdfContent from a CdfReader.
* This reads the attribute metadata and entries and variable metadata.
* Record data for variables is not read at construction time.
*
* @param crdr object which knows how to read CDF records
*/
public CdfContent( CdfReader crdr ) throws IOException {
// Get basic information from reader.
Buf buf = crdr.getBuf();
RecordFactory recordFact = crdr.getRecordFactory();
CdfDescriptorRecord cdr = crdr.getCdr();
// Get global descriptor record.
GlobalDescriptorRecord gdr =
recordFact.createRecord( buf, cdr.gdrOffset,
GlobalDescriptorRecord.class );
// Store global format information.
boolean rowMajor = Record.hasBit( cdr.flags, 0 );
int[] rDimSizes = gdr.rDimSizes;
int leapSecondLastUpdated = gdr.leapSecondLastUpdated;
cdfInfo_ = new CdfInfo( rowMajor, rDimSizes, leapSecondLastUpdated );
// Read the rVariable and zVariable records.
VariableDescriptorRecord[] rvdrs =
walkVariableList( buf, recordFact, gdr.nrVars, gdr.rVdrHead );
VariableDescriptorRecord[] zvdrs =
walkVariableList( buf, recordFact, gdr.nzVars, gdr.zVdrHead );
// Collect the rVariables and zVariables into a single list.
// Turn the rVariable and zVariable records into a single list of
// Variable objects.
VariableDescriptorRecord[] vdrs = arrayConcat( rvdrs, zvdrs );
variables_ = new Variable[ vdrs.length ];
for ( int iv = 0; iv < vdrs.length; iv++ ) {
variables_[ iv ] = new Variable( vdrs[ iv ], cdfInfo_, recordFact );
}
// Read the attributes records (global and variable attributes
// are found in the same list).
AttributeDescriptorRecord[] adrs =
walkAttributeList( buf, recordFact, gdr.numAttr, gdr.adrHead );
// Read the entries for all the attributes, and turn the records
// with their entries into two lists, one of global attributes and
// one of variable attributes.
List<GlobalAttribute> gAttList = new ArrayList<GlobalAttribute>();
List<VariableAttribute> vAttList = new ArrayList<VariableAttribute>();
for ( int ia = 0; ia < adrs.length; ia++ ) {
AttributeDescriptorRecord adr = adrs[ ia ];
AttributeEntry[] grEntries =
walkEntryList( buf, recordFact,
adr.nGrEntries, adr.maxGrEntry,
adr.agrEdrHead, cdfInfo_ );
AttributeEntry[] zEntries =
walkEntryList( buf, recordFact,
adr.nZEntries, adr.maxZEntry,
adr.azEdrHead, cdfInfo_ );
boolean isGlobal = Record.hasBit( adr.scope, 0 );
if ( isGlobal ) {
// grEntries are gEntries
AttributeEntry[] gEntries = arrayConcat( grEntries, zEntries );
gAttList.add( new GlobalAttribute( adr.name, gEntries ) );
}
else {
// grEntries are rEntries
vAttList.add( new VariableAttribute( adr.name, grEntries,
zEntries ) );
}
}
globalAtts_ = gAttList.toArray( new GlobalAttribute[ 0 ] );
variableAtts_ = vAttList.toArray( new VariableAttribute[ 0 ] );
}
/**
* Returns the global attributes.
*
* @return global attribute array, in order
*/
public GlobalAttribute[] getGlobalAttributes() {
return globalAtts_;
}
/**
* Returns the variable attributes.
*
* @return variable attribute array, in order
*/
public VariableAttribute[] getVariableAttributes() {
return variableAtts_;
}
/**
* Returns the variables.
*
* @return variable array, in order
*/
public Variable[] getVariables() {
return variables_;
}
/**
* Returns some global information about the CDF file.
*
* @return CDF info
*/
public CdfInfo getCdfInfo() {
return cdfInfo_;
}
/**
* Follows a linked list of Variable Descriptor Records
* and returns an array of them.
*
* @param buf data buffer
* @param recordFact record factory
* @param nvar number of VDRs in list
* @param head offset into buffer of first VDR
* @return list of VDRs
*/
private static VariableDescriptorRecord[]
walkVariableList( Buf buf, RecordFactory recordFact,
int nvar, long head ) throws IOException {
VariableDescriptorRecord[] vdrs = new VariableDescriptorRecord[ nvar ];
long off = head;
for ( int iv = 0; iv < nvar; iv++ ) {
VariableDescriptorRecord vdr =
recordFact.createRecord( buf, off,
VariableDescriptorRecord.class );
vdrs[ iv ] = vdr;
off = vdr.vdrNext;
}
return vdrs;
}
/**
* Follows a linked list of Attribute Descriptor Records
* and returns an array of them.
*
* @param buf data buffer
* @param recordFact record factory
* @param natt number of ADRs in list
* @param head offset into buffer of first ADR
* @return list of ADRs
*/
private static AttributeDescriptorRecord[]
walkAttributeList( Buf buf, RecordFactory recordFact,
int natt, long head ) throws IOException {
AttributeDescriptorRecord[] adrs =
new AttributeDescriptorRecord[ natt ];
long off = head;
for ( int ia = 0; ia < natt; ia++ ) {
AttributeDescriptorRecord adr =
recordFact.createRecord( buf, off,
AttributeDescriptorRecord.class );
adrs[ ia ] = adr;
off = adr.adrNext;
}
return adrs;
}
/**
* Follows a linked list of Attribute Entry Descriptor Records
* and returns an array of entry values.
*
* @param buf data buffer
* @param recordFact record factory
* @param nent number of entries
* @param maxient largest entry index (AEDR num field value)
* @param head offset into buffer of first AEDR
* @param info global information about the CDF file
* @return entry values
*/
private static AttributeEntry[] walkEntryList( Buf buf,
RecordFactory recordFact,
int nent, int maxient,
long head, CdfInfo info )
throws IOException {
AttributeEntry[] entries = new AttributeEntry[ maxient + 1 ];
long off = head;
for ( int ie = 0; ie < nent; ie++ ) {
AttributeEntryDescriptorRecord aedr =
recordFact.createRecord( buf, off,
AttributeEntryDescriptorRecord.class );
entries[ aedr.num ] = readEntry( aedr, info );
off = aedr.aedrNext;
}
return entries;
}
/**
* Obtains the value of an entry from an Atribute Entry Descriptor Record.
*
* @param aedr attribute entry descriptor record
* @param info global information about the CDF file
* @return entry value
*/
private static AttributeEntry
readEntry( AttributeEntryDescriptorRecord aedr,
CdfInfo info ) throws IOException {
DataType dataType = DataType.getDataType( aedr.dataType, info );
final int nitem;
final int nelPerItem;
final int[] dimSizes;
final boolean[] dimVarys;
if ( dataType.hasMultipleElementsPerItem() ) {
nitem = 1;
nelPerItem = aedr.numElems;
dimSizes = new int[ 0 ];
dimVarys = new boolean[ 0 ];
}
else {
nitem = aedr.numElems;
nelPerItem = 1;
dimSizes = new int[] { nitem };
dimVarys = new boolean[] { true };
}
DataReader dataReader = new DataReader( dataType, nelPerItem, nitem );
Object va = dataReader.createValueArray();
dataReader.readValue( aedr.getBuf(), aedr.getValueOffset(), va );
return new AttributeEntry( dataType, va, nitem );
}
/**
* Concatenates two arrays to form a single one.
*
* @param a1 first array
* @param a2 second array
* @return concatenated array
*/
private static <T> T[] arrayConcat( T[] a1, T[] a2 ) {
int count = a1.length + a2.length;
List<T> list = new ArrayList<T>( count );
list.addAll( Arrays.asList( a1 ) );
list.addAll( Arrays.asList( a2 ) );
Class eClazz = a1.getClass().getComponentType();
@SuppressWarnings("unchecked")
T[] result =
(T[]) list.toArray( (Object[]) Array.newInstance( eClazz, count ) );
return result;
}
}
|