package ua.stu.scplib.structure; import java.io.IOException; import java.util.BitSet; import java.util.Iterator; import java.util.TreeMap; import ua.stu.scplib.attribute.BinaryInputStream; /** * <p>A class to encapsulate the SCP-ECG Pointers to Data Areas section.</p> * * @author stu */ public class Section0 extends Section { /** * <p>Get a string name for this section.</p> * * @return a string name for this section */ public String getSectionName() { return "Pointers to Data Areas"; } private int[] sectionIDNumbers; private long[] sectionLengths; private long[] sectionIndexes; public int[] getSectionIDNumbers() { return sectionIDNumbers; } public long[] getSectionLengths() { return sectionLengths; } public long[] getSectionIndexes() { return sectionIndexes; } public Section0(SectionHeader header) { super(header); } public long read(BinaryInputStream i) throws IOException { /* if (sectionBytesRemaining%10 != 0) { throw new IOException("Section 0 (Pointer Section) variable data length not a multiple of 10"); }*/ System.out.println(sectionBytesRemaining%10); int numberOfSections = (int)(sectionBytesRemaining/10); sectionIDNumbers = new int [numberOfSections]; sectionLengths = new long[numberOfSections]; sectionIndexes = new long[numberOfSections]; int section=0; while (sectionBytesRemaining > 0) { sectionIDNumbers[section] = i.readUnsigned16(); bytesRead+=2; sectionBytesRemaining-=2; sectionLengths[section] = i.readUnsigned32(); bytesRead+=4; sectionBytesRemaining-=4; sectionIndexes[section] = i.readUnsigned32(); bytesRead+=4; sectionBytesRemaining-=4; ++section; } skipToEndOfSectionIfNotAlreadyThere(i); return bytesRead; } public String toString() { StringBuffer strbuf = new StringBuffer(); if (sectionIDNumbers != null) { strbuf.append("Section 0 number of pointers = "+sectionIDNumbers.length+"\n"); for (int section=0; section<sectionIDNumbers.length; ++section) { strbuf.append("\tSection ID Number = "+sectionIDNumbers[section]+" dec (0x"+Integer.toHexString(sectionIDNumbers[section])+")\n"); strbuf.append("\t\tSection Length = "+sectionLengths[section]+" dec (0x"+Long.toHexString(sectionLengths[section])+")\n"); strbuf.append("\t\tSection Index = "+sectionIndexes[section]+" dec (0x"+Long.toHexString(sectionIndexes[section])+")\n"); } } return strbuf.toString(); } public String validate() { StringBuffer strbuf = new StringBuffer(); if (!new String(header.getReservedBytes()).equals("SCPECG")) { strbuf.append("Section 0 header reserved bytes not SCPECG\n"); } if (sectionIDNumbers == null) { strbuf.append("Section 0 contains no pointers\n"); } return strbuf.toString(); } /** * <p>Validate the section against the contents of other sections.</p> * * <p>Specifically, checks pointers and lengths.</p> * * @param sections all the sections * @return the validation results as a <code>String</code> */ public String validateAgainstOtherSections(TreeMap sections) { StringBuffer strbuf = new StringBuffer(); // first check that all lengths and indexes in Section 0 match the reality of the sections ... BitSet check0Through11Referenced = new BitSet(12); if (sectionIDNumbers != null) { for (int section=0; section<sectionIDNumbers.length; ++section) { Section targetSection = (Section)(sections.get(new Integer(sectionIDNumbers[section]))); if (sectionLengths[section] != 0) { // sections may be referenced but be zero length (i.e. be absent) if (targetSection == null) { strbuf.append("Section 0 references Section "+sectionIDNumbers[section]+" that does not exist\n"); } else { if (sectionLengths[section] != targetSection.getSectionHeader().getSectionLength()) { strbuf.append("Section 0 reference to Section "+sectionIDNumbers[section]+" length mismatch "); strbuf.append("Section 0 says "+sectionLengths[section]); strbuf.append(" but length is actually "+targetSection.getSectionHeader().getSectionLength()+"\n"); } if (sectionIndexes[section] != targetSection.getSectionHeader().getByteOffset()+1) { // SCP-ECG indexes are from 1, not 0 strbuf.append("Section 0 reference to Section "+sectionIDNumbers[section]+" index mismatch "); strbuf.append("Section 0 says "+sectionIndexes[section]); strbuf.append(" but index is actually "+(targetSection.getSectionHeader().getByteOffset()+1)+"\n"); } } } else { if (sectionIndexes[section] != 0) { strbuf.append("Section 0 reference to Section "+sectionIDNumbers[section]+" specifies zero length "); strbuf.append("but index is not null\n"); } } // while we are at it, check that the mandatory references to sections 0 through 11 are present if (sectionIDNumbers[section] >= 0 && sectionIDNumbers[section] <= 11) { check0Through11Referenced.set(sectionIDNumbers[section]); } } } // check that the mandatory references to sections 0 through 11 are reference, regardless of whether the section is actually present ... if (check0Through11Referenced.cardinality() != 12) { for (int section=0; section<=11; ++section) { if (!check0Through11Referenced.get(section)) { strbuf.append("Section 0 does not reference Section "+section+" even though it is mandatory to do so\n"); } } } // then check that all sections have references from Section 0 ... Iterator i = sections.keySet().iterator(); while (i.hasNext()) { int wantID = ((Integer)(i.next())).intValue(); // the key itself is sufficient, since it is the section ID number boolean found=false; for (int section=0; section<sectionIDNumbers.length; ++section) { if (sectionIDNumbers[section] == wantID) { found=true; break; } } if (!found) { strbuf.append("Section 0 does not reference Section "+wantID+" even though it is present\n"); } } return strbuf.toString(); } }