com.hfg.bio.seq.format.abi.ABIF Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
package com.hfg.bio.seq.format.abi;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.hfg.bio.Nucleotide;
import com.hfg.bio.seq.NucleicAcid;
import com.hfg.bio.seq.SeqQualityScores;
import com.hfg.bio.seq.format.SeqIOException;
import com.hfg.graphics.ColorUtil;
import com.hfg.graphics.TextUtil;
import com.hfg.html.attribute.HTMLColor;
import com.hfg.svg.SVG;
import com.hfg.svg.SvgGroup;
import com.hfg.svg.SvgPath;
import com.hfg.svg.SvgText;
import com.hfg.svg.path.SvgPathLineToCmd;
import com.hfg.svg.path.SvgPathMoveToCmd;
import com.hfg.util.ByteUtil;
import com.hfg.util.StringUtil;
import com.hfg.util.io.ByteSource;
//------------------------------------------------------------------------------
/**
* Extracts data from ABIF (ab1) format sequencing chromatographic trace files.
*
* @author J. Alex Taylor, hairyfatguy.com
*/
//------------------------------------------------------------------------------
// com.hfg XML/HTML Coding Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
// [email protected]
//------------------------------------------------------------------------------
// See http://www6.appliedbiosystems.com/support/software_community/ABIF_File_Format.pdf
public class ABIF
{
private int mVersionNum;
private String mInstrumentClass;
private String mInstrumentFamily;
private String mInstrumentName;
private String mMachineName;
private String mInstrumentParameters;
private String mBaseOrder;
private Integer mLane;
private String mBasecallerSeq;
private short[] mBasecallerQualityScores;
private short[] mBasecallerPeakLocations;
private String mUserSeq;
private short[] mUserQualityScores;
private short[] mUserPeakLocations;
private Integer mNumTraceDataPoints;
private Short mMaxTraceDataValue;
private Map mTraceDataMap = new HashMap<>(4);
private String mSampleName;
private String mSampleComment;
private String mSampleTrackingID;
private String mQC_Warnings;
private String mQC_Errors;
private Long mQV20_Score;
private String mQV20_Status;
private Date mRunDate;
private Integer mMaxQualityValue;
private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
private static FontRenderContext sFRC = new FontRenderContext(new AffineTransform(), true, true);
// These represent the file tags that we are currently parsing
private enum FileTag
{
CMNT, // Sample comment
DATA, // instances 9-12: short[] holding analyzed color data
FWO_, // Sequencing Analysis Filter wheel order. Fixed for 3500 at "GATC"
HCFG, // 1st instance: The instrument class. All upper case, no spaces.
// 2nd instance: The instrument family. All upper case, no spaces.
// 3rd instance: The official instrument name. Mixed case, minus any special formatting.
// 4th instance: Instrument parameters. Contains key-value pairs of instrument configuration
// information, separated by semicolons. Four parameters are included initially:
// UnitID=, CPUBoard=, ArraySize=<# of capillaries>,
// SerialNumber=.
LANE, // Sample's lane or capillary number
LIMS, // Sample tracking ID
MCHN, // Machine Name.
PBAS, // 1st instance: Array of sequence characters edited by user
// 2nd instance: Array of sequence characters as called by Basecaller
PCON, // 1st instance: Array of quality values (0-255) as edited by user
// 2nd instance: Array of quality values (0-255) as called by Basecaller
phQL, // Maximum quality value
PLOC, // 1st instance: Array of peak locations edited by user
// 2nd instance: Array of peak locations as called by Basecaller
QcRs, // 1st instance: QC warnings, a concatenated comma-separated string (3500/3500xl specific?)
// 2nd instance: QC errors, a concatenated comma-separated string (3500/3500xl specific?)
QV20, // 1st instance: QV20+ value (3500/3500xl specific?)
// 2nd instance: One of 'Pass', 'Fail', or 'Check' (3500/3500xl specific?)
RUND, // 1st instance: Run started date
// 2nd instance: Run stopped date
RUNT, // 1st instance: Run started time
// 2nd instance: Run stopped time
SMPL // Sequencing analysis sample name
}
//###########################################################################
// CONSTRUCTORS
//###########################################################################
//---------------------------------------------------------------------------
public ABIF(File inFile)
throws IOException
{
if (! inFile.exists())
{
throw new IOException("The specified ABIF file " + StringUtil.singleQuote(inFile.getPath()) + " doesn't exist!");
}
if (! inFile.canRead())
{
throw new IOException("You do not have read access to the specified ABIF file " + StringUtil.singleQuote(inFile.getPath()) + "!");
}
RandomAccessFile randomAccessFile = null;
try
{
randomAccessFile = new RandomAccessFile(inFile, "r");
init(new ByteSource(randomAccessFile));
}
finally
{
randomAccessFile.close();
}
}
//---------------------------------------------------------------------------
public ABIF(byte[] inBytes)
throws IOException
{
init(new ByteSource(inBytes));
}
//###########################################################################
// PUBLIC METHODS
//###########################################################################
//---------------------------------------------------------------------------
public int getABIF_FormatVersionNum()
{
return mVersionNum;
}
//---------------------------------------------------------------------------
public Integer getLane()
{
return mLane;
}
//---------------------------------------------------------------------------
public String getInstrumentClass()
{
return mInstrumentClass;
}
//---------------------------------------------------------------------------
public String getInstrumentFamily()
{
return mInstrumentFamily;
}
//---------------------------------------------------------------------------
public String getInstrumentName()
{
return mInstrumentName;
}
//---------------------------------------------------------------------------
public String getMachineName()
{
return mMachineName;
}
//---------------------------------------------------------------------------
public Date getRunDate()
{
return mRunDate;
}
//---------------------------------------------------------------------------
public String getSampleName()
{
return mSampleName;
}
//---------------------------------------------------------------------------
public String getSampleTrackingID()
{
return mSampleTrackingID;
}
//---------------------------------------------------------------------------
public String getSampleComment()
{
return mSampleComment;
}
//---------------------------------------------------------------------------
public String getBasecallerSeq()
{
return mBasecallerSeq;
}
//---------------------------------------------------------------------------
public short[] getBasecallerPeakLocations()
{
return mBasecallerPeakLocations;
}
//---------------------------------------------------------------------------
public short[] getBasecallerQualityScores()
{
return mBasecallerQualityScores;
}
//---------------------------------------------------------------------------
public String getUserSeq()
{
return mUserSeq;
}
//---------------------------------------------------------------------------
public short[] getUserQualityScores()
{
return mUserQualityScores;
}
//---------------------------------------------------------------------------
public Integer getMaxQualityScore()
{
return mMaxQualityValue;
}
//---------------------------------------------------------------------------
public short[] getUserPeakLocations()
{
return mUserPeakLocations;
}
//---------------------------------------------------------------------------
public short[] getTraceValues(Nucleotide inNucleotide)
{
return mTraceDataMap.get(Character.toUpperCase(inNucleotide.getOneLetterCode()));
}
//---------------------------------------------------------------------------
/**
3500/3500xl specific: Returns any QC warnings as a concatenated comma-separated string.
@return QC warnings
*/
public String getQC_Warnings()
{
return mQC_Warnings;
}
//---------------------------------------------------------------------------
/**
3500/3500xl specific: Returns any QC errors as a concatenated comma-separated string.
@return QC errors or null
*/
public String getQC_Errors()
{
return mQC_Errors;
}
//---------------------------------------------------------------------------
/**
3500/3500xl specific: Returns the QV20+ value.
@return QV20+ score or null
*/
public Long getQV20_Score()
{
return mQV20_Score;
}
//---------------------------------------------------------------------------
/**
3500/3500xl specific: Returns the QV20 status as one of 'Pass', 'Fail', or 'Check'.
@return QV20 status or null
*/
public String getQV20_Status()
{
return mQV20_Status;
}
//---------------------------------------------------------------------------
public NucleicAcid toNucleicAcid()
{
NucleicAcid seq = new NucleicAcid().setID(getSampleName());
if (StringUtil.isSet(getUserSeq()))
{
seq.setSequence(StringUtil.isSet(getUserSeq()) ? getUserSeq() : getBasecallerSeq());
}
short[] qualityScores = null;
if (getUserQualityScores() != null)
{
qualityScores = getUserQualityScores();
}
else if (getBasecallerQualityScores() != null)
{
qualityScores = getBasecallerQualityScores();
}
if (qualityScores != null)
{
seq.setSeqQualityScores(new SeqQualityScores(qualityScores));
}
return seq;
}
//--------------------------------------------------------------------------
/**
Returns the largest trace intensity value - helpful for scaling.
* @return the largest trace intensity value
*/
public short getMaxTraceValue()
{
if (null == mMaxTraceDataValue)
{
short maxValue = 0;
for (short[] colorDataValues : mTraceDataMap.values())
{
for (short value : colorDataValues)
{
if (value > maxValue)
{
maxValue = value;
}
}
}
mMaxTraceDataValue = maxValue;
}
return mMaxTraceDataValue;
}
//--------------------------------------------------------------------------
public SVG toSVG()
{
int height = 400;
int width = mNumTraceDataPoints * 2;
Font font = Font.decode("Arial-PLAIN-9");
int marginSize = 20;
// Determine the scale.
double xScalingFactor = width / (float) mNumTraceDataPoints;
double yScalingFactor = height / (float) getMaxTraceValue();
double yQualityScalingFactor = height / (float) getMaxQualityScore();
int scaledMaxY = (int) (getMaxTraceValue() * yScalingFactor);
int scaledMaxQualityY = (int) (getMaxQualityScore() * yQualityScalingFactor);
int lineHeight = (int) TextUtil.getStringRect("A", font).getHeight();
short[] peakLocations = getUserPeakLocations();
if (null == peakLocations)
{
peakLocations = getBasecallerPeakLocations();
}
SVG svg = new SVG();
svg.setFont(font);
// Display the quality scores in the background
short[] qualityScores = getUserQualityScores();
if (null == qualityScores)
{
qualityScores = getBasecallerQualityScores();
}
if (qualityScores != null)
{
SvgGroup group = svg.addGroup().setClass("quality");
group.addStyle("stroke:#" + ColorUtil.colorToHex(HTMLColor.DARK_GRAY));
SvgPath path = group.addPath().addPathCommand(new SvgPathMoveToCmd().addPoint(new Point2D.Float(marginSize, height + marginSize)));
List lineToValues = new ArrayList<>(peakLocations.length * 4);
float prevPeakX = 0;
for (int i = 0; i < peakLocations.length; i++)
{
float scaledPeakX = marginSize + (float) (peakLocations[i] * xScalingFactor);
float nextScaledPeakX = (i < qualityScores.length - 1 ? marginSize + (float) (peakLocations[i + 1] * xScalingFactor) : width - marginSize);
float leftX = (i > 0 ? scaledPeakX - (scaledPeakX - prevPeakX)/2f : marginSize);
float rightX = (i < qualityScores.length ? scaledPeakX + (nextScaledPeakX - scaledPeakX)/2f : width - marginSize);
float y = marginSize + scaledMaxQualityY - (int) (qualityScores[i] * yQualityScalingFactor);
lineToValues.add(leftX);
lineToValues.add(y);
lineToValues.add(rightX);
lineToValues.add(y);
prevPeakX = scaledPeakX;
}
lineToValues.add(width - (float) marginSize);
lineToValues.add(marginSize + (float) scaledMaxQualityY);
path.addPathCommand(new SvgPathLineToCmd().setRawNumbers(lineToValues));
path.setFill(HTMLColor.LIGHT_GRAY).addStyle("fill-opacity:0.4; stroke-opacity:0.2");
}
// Display the nucleotide traces
for (Character nucleotide : new Character[] {'A', 'C', 'G', 'T'})
{
short[] traceValues = mTraceDataMap.get(nucleotide);
SvgGroup group = svg.addGroup().setClass(nucleotide + "");
group.addStyle("stroke:#" + ColorUtil.colorToHex(getColorForNucleotide(nucleotide)));
SvgPath path = group.addPath().addPathCommand(new SvgPathMoveToCmd().addPoint(new Point2D.Float(marginSize, height - marginSize)));
List lineToValues = new ArrayList<>(traceValues.length * 2);
for (int i = 0; i < traceValues.length; i++)
{
float x = marginSize + (int) (i * xScalingFactor);
float y = marginSize + scaledMaxY - (int) (traceValues[i] * yScalingFactor);
lineToValues.add(x);
lineToValues.add(y);
}
path.addPathCommand(new SvgPathLineToCmd().setRawNumbers(lineToValues));
path.setFill(null);
}
// Display the called (or user-specified) sequence along the top
String sequence = getUserSeq();
if (null == sequence)
{
sequence = getBasecallerSeq();
}
if (StringUtil.isSet(sequence)
&& peakLocations != null)
{
SvgGroup group = svg.addGroup().setClass("sequence");
// Used to better calculate text placement
Rectangle2D textBoundBox = font.getStringBounds("A", 0, "A".length(), sFRC);
for (int i = 0; i < peakLocations.length; i++)
{
short peakLocation = peakLocations[i];
char nucleotide = sequence.charAt(i);
float x = marginSize + (int) ((peakLocation * xScalingFactor) - (textBoundBox.getWidth() / 2));
float y = marginSize;
SvgText label = group.addText(nucleotide + "", font, new Point.Float(x, y));
label.setFill(getColorForNucleotide(nucleotide));
if ((i+1)%10 == 0)
{
x = marginSize + (int) (peakLocation * xScalingFactor);
y = marginSize + lineHeight;
group.addText((i + 1) + "", font, new Point.Float(x, y)).setFill(Color.LIGHT_GRAY);
}
}
}
return svg;
}
//--------------------------------------------------------------------------
Color getColorForNucleotide(Character inNucleotide)
{
Color color;
switch (inNucleotide)
{
case 'A':
color = HTMLColor.GREEN;
break;
case 'C':
color = HTMLColor.BLUE;
break;
case 'G':
color = HTMLColor.BLACK;
break;
case 'T':
color = HTMLColor.RED;
break;
default:
color = HTMLColor.DARK_GRAY;
}
return color;
}
//###########################################################################
// PRIVATE METHODS
//###########################################################################
//---------------------------------------------------------------------------
private void init(ByteSource inByteSource)
throws IOException
{
DirectoryEntry header = readHeader(inByteSource);
// Skip to the directory entries
inByteSource.seek(header.getDataOffset());
// Read directory entries (located at the end of the file)
List dirEntries = new ArrayList<>(header.getNumElements());
for (int i = 0; i < header.getNumElements(); i++)
{
dirEntries.add(new DirectoryEntry(inByteSource));
}
extractData(inByteSource, dirEntries);
}
//---------------------------------------------------------------------------
private DirectoryEntry readHeader(ByteSource inByteSource)
throws IOException
{
byte[] fileSignature = new byte[4];
inByteSource.read(fileSignature);
if (! new String(fileSignature).equals("ABIF"))
{
throw new SeqIOException("ABIF file signature not found!");
}
mVersionNum = ByteUtil.get2ByteInt(inByteSource, mByteOrder);
// Read the dir entry
DirectoryEntry dirEntry = new DirectoryEntry(inByteSource);
// The dataSize should be exactly the size required for the entries (numElements x elementSize)
// TODO: Add sanity check
return dirEntry;
}
//---------------------------------------------------------------------------
private void extractData(ByteSource inByteSource, List inDirEntries)
throws IOException
{
// Create a temporary list for the trace value data
List traceValueList = new ArrayList<>(4);
for (int i = 0; i < 4; i++)
{
traceValueList.add(null);
}
short maxQualityScore = 0;
for (DirectoryEntry dirEntry : inDirEntries)
{
if (dirEntry.getTagName().equals(FileTag.CMNT.name()))
{
mSampleComment = getStringValueForDirectoryEntry(inByteSource, dirEntry);
}
else if (dirEntry.getTagName().equals(FileTag.DATA.name()))
{
if (dirEntry.getTagNum() >= 9
&& dirEntry.getTagNum() <= 12)
{
inByteSource.seek(dirEntry.getDataOffset());
short[] traceValues = ByteUtil.getShortArray(inByteSource, dirEntry.getNumElements(), mByteOrder);
int index = dirEntry.getTagNum() - 9;
// Since we may not yet know the base order, store the trace values in an array temporarily;
traceValueList.set(index, traceValues);
if (null == mNumTraceDataPoints)
{
mNumTraceDataPoints = traceValues.length;
}
}
}
else if (dirEntry.getTagName().equals(FileTag.FWO_.name()))
{
mBaseOrder = new String(ByteUtil.getBytesFromInt(dirEntry.getDataOffset()));
}
else if (dirEntry.getTagName().equals(FileTag.HCFG.name()))
{
String value = getStringValueForDirectoryEntry(inByteSource, dirEntry);
if (1 == dirEntry.getTagNum())
{
mInstrumentClass = value;
}
else if (2 == dirEntry.getTagNum())
{
mInstrumentFamily = value;
}
else if (3 == dirEntry.getTagNum())
{
mInstrumentName = value;
}
else if (4 == dirEntry.getTagNum())
{
mInstrumentParameters = value;
}
}
else if (dirEntry.getTagName().equals(FileTag.LANE.name()))
{
byte[] bytes = ByteUtil.getBytesFromInt(dirEntry.getDataOffset());
mLane = ByteUtil.get2ByteInt(bytes, mByteOrder);
}
else if (dirEntry.getTagName().equals(FileTag.LIMS.name()))
{
mSampleTrackingID = getStringValueForDirectoryEntry(inByteSource, dirEntry);
}
else if (dirEntry.getTagName().equals(FileTag.MCHN.name()))
{
mMachineName = getStringValueForDirectoryEntry(inByteSource, dirEntry);
}
else if (dirEntry.getTagName().equals(FileTag.PBAS.name()))
{
inByteSource.seek(dirEntry.getDataOffset());
String seqString = ByteUtil.getString(inByteSource, dirEntry.getDataSize());
if (1 == dirEntry.getTagNum())
{
mUserSeq = seqString;
}
else if (2 == dirEntry.getTagNum())
{
mBasecallerSeq = seqString;
}
}
else if (dirEntry.getTagName().equals(FileTag.PCON.name()))
{
inByteSource.seek(dirEntry.getDataOffset());
byte[] bytes = new byte[dirEntry.getDataSize()];
inByteSource.read(bytes);
// Converting the unsigned byte values to shorts for ease of handling
short[] qualityScores = new short[dirEntry.getDataSize()];
for (int i = 0; i < bytes.length; i++)
{
short qualityScore = (short) bytes[i];
qualityScores[i] = qualityScore;
if (qualityScore > maxQualityScore)
{
maxQualityScore = qualityScore;
}
}
if (1 == dirEntry.getTagNum())
{
mUserQualityScores = qualityScores;
}
else if (2 == dirEntry.getTagNum())
{
mBasecallerQualityScores = qualityScores;
}
}
else if (dirEntry.getTagName().equals(FileTag.phQL.name()))
{
mMaxQualityValue = (int) ByteUtil.getShort(ByteUtil.getBytesFromInt(dirEntry.getDataOffset()), 0, mByteOrder);
}
else if (dirEntry.getTagName().equals(FileTag.PLOC.name()))
{
inByteSource.seek(dirEntry.getDataOffset());
short[] peakLocations = ByteUtil.getShortArray(inByteSource, dirEntry.getNumElements(), mByteOrder);
if (1 == dirEntry.getTagNum())
{
mUserPeakLocations = peakLocations;
}
else if (2 == dirEntry.getTagNum())
{
mBasecallerPeakLocations = peakLocations;
}
}
else if (dirEntry.getTagName().equals(FileTag.QcRs.name()))
{
if (1 == dirEntry.getTagNum())
{
mQC_Warnings = getStringValueForDirectoryEntry(inByteSource, dirEntry);
}
else if (2 == dirEntry.getTagNum())
{
mQC_Errors = getStringValueForDirectoryEntry(inByteSource, dirEntry);
}
}
else if (dirEntry.getTagName().equals(FileTag.QV20.name()))
{
if (1 == dirEntry.getTagNum())
{
inByteSource.seek(dirEntry.getDataOffset());
mQV20_Score = ByteUtil.getLong(inByteSource, mByteOrder);
}
else if (2 == dirEntry.getTagNum())
{
mQV20_Status = getStringValueForDirectoryEntry(inByteSource, dirEntry);
}
}
else if (dirEntry.getTagName().equals(FileTag.RUND.name())
&& 1 == dirEntry.getTagNum())
{
byte[] bytes = ByteUtil.getBytesFromInt(dirEntry.getDataOffset());
int year = ByteUtil.get2ByteInt(bytes, 0, mByteOrder);
int month = ByteUtil.get1ByteInt(bytes, 2);
int day = ByteUtil.get1ByteInt(bytes, 3);
Calendar cal = new GregorianCalendar();
if (mRunDate != null)
{
cal.setTime(mRunDate);
}
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
mRunDate = cal.getTime();
}
else if (dirEntry.getTagName().equals(FileTag.RUNT.name())
&& 1 == dirEntry.getTagNum())
{
byte[] bytes = ByteUtil.getBytesFromInt(dirEntry.getDataOffset());
int hour = ByteUtil.get1ByteInt(bytes, 0);
int minute = ByteUtil.get1ByteInt(bytes, 1);
int second = ByteUtil.get1ByteInt(bytes, 2);
int hsecond = ByteUtil.get1ByteInt(bytes, 3);
Calendar cal = new GregorianCalendar();
if (mRunDate != null)
{
cal.setTime(mRunDate);
}
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, second);
mRunDate = cal.getTime();
}
else if (dirEntry.getTagName().equals(FileTag.SMPL.name()))
{
mSampleName = getStringValueForDirectoryEntry(inByteSource, dirEntry);
}
}
if (null == mMaxQualityValue)
{
mMaxQualityValue = (int) maxQualityScore;
}
// Now construct the trace data map
for (int i = 0; i < 4; i++)
{
mTraceDataMap.put(Character.toUpperCase(mBaseOrder.charAt(i)), traceValueList.get(i));
}
}
//---------------------------------------------------------------------------
private String getStringValueForDirectoryEntry(ByteSource inByteSource, DirectoryEntry inDirEntry)
throws IOException
{
String value;
if (inDirEntry.getDataSize() <= 4)
{
value = new String(ByteUtil.getBytesFromInt(inDirEntry.getDataOffset()));
int zeroIndex = value.indexOf(0);
if (zeroIndex >= 0)
{
value = value.substring(0, zeroIndex);
}
}
else
{
inByteSource.seek(inDirEntry.getDataOffset());
value = ByteUtil.getString(inByteSource, inDirEntry.getDataSize());
}
// Pascal type string with the lenght as the first byte?
if (18 == inDirEntry.getElementType()
&& value.length() > 1)
{
value = value.substring(1);
}
return value;
}
//###########################################################################
// INNER CLASS
//###########################################################################
private class DirectoryEntry
{
private String mTagName;
private int mTagNum;
private int mElementType;
private int mElementSize;
private int mNumElements;
private int mDataSize;
private int mDataOffset;
private int mDataHandle;
//------------------------------------------------------------------------
public DirectoryEntry(ByteSource inByteSource)
throws IOException
{
mTagName = ByteUtil.getString(inByteSource, 4);
mTagNum = ByteUtil.getInt(inByteSource, mByteOrder);
mElementType = ByteUtil.get2ByteInt(inByteSource, mByteOrder);
mElementSize = ByteUtil.get2ByteInt(inByteSource, mByteOrder);
mNumElements = ByteUtil.getInt(inByteSource, mByteOrder);
mDataSize = ByteUtil.getInt(inByteSource, mByteOrder);
mDataOffset = ByteUtil.getInt(inByteSource, mByteOrder);
mDataHandle = ByteUtil.getInt(inByteSource, mByteOrder);
}
//------------------------------------------------------------------------
public String getTagName()
{
return mTagName;
}
//------------------------------------------------------------------------
public int getTagNum()
{
return mTagNum;
}
//------------------------------------------------------------------------
public int getElementType()
{
return mElementType;
}
//------------------------------------------------------------------------
public int getNumElements()
{
return mNumElements;
}
//------------------------------------------------------------------------
public int getDataSize()
{
return mDataSize;
}
//------------------------------------------------------------------------
public int getDataOffset()
{
return mDataOffset;
}
//------------------------------------------------------------------------
@Override
public String toString()
{
return mTagName;
}
}
}