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();
}
}