diff --git a/src/infinity/resource/chu/ChuResource.java b/src/infinity/resource/chu/ChuResource.java index 0ea36ca7e..477a950f1 100644 --- a/src/infinity/resource/chu/ChuResource.java +++ b/src/infinity/resource/chu/ChuResource.java @@ -7,15 +7,23 @@ import infinity.datatype.SectionCount; import infinity.datatype.SectionOffset; import infinity.datatype.TextString; +import infinity.datatype.Unknown; import infinity.resource.AbstractStruct; import infinity.resource.Resource; import infinity.resource.key.ResourceEntry; +import infinity.util.DynamicArray; +import infinity.util.Pair; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; public final class ChuResource extends AbstractStruct implements Resource //, HasAddRemovable { + private List> listControls; + private int ofsPanels, numPanels, sizePanels, ofsControls, numControls; + public ChuResource(ResourceEntry entry) throws Exception { super(entry); @@ -41,31 +49,134 @@ public void write(OutputStream os) throws IOException // --------------------- End Interface Writeable --------------------- + // Write 'size' number of zeros to the output stream + void writeGap(OutputStream os, int startOfs, int endOfs) throws IOException + { + while (startOfs < endOfs) { + os.write(0); + startOfs++; + } + } + + /** Returns the starting offset of available panels. */ + public int getPanelsOffset() + { + return ofsPanels; + } + + /** Returns the number of available panels. */ + public int getPanelCount() + { + return numPanels; + } + + /** Returns the starting offset of the control table. */ + public int getControlsOffset() + { + return ofsControls; + } + + /** Returns the number of available controls. */ + public int getControlCount() + { + return numControls; + } + + /** Returns the absolute starting offset of the control at the given index. */ + public int getControlOffset(int index) + { + if (index >= 0 && index < listControls.size()) { + return listControls.get(index).getFirst(); + } else { + return 0; + } + } + + /** Returns the size of the control at the given index. */ + public int getControlSize(int index) + { + if (index >= 0 && index < listControls.size()) { + return listControls.get(index).getSecond(); + } else { + return 0; + } + } + + /** Returns the panel size in bytes. */ + public int getPanelSize() + { + return sizePanels; + } + @Override protected int read(byte buffer[], int offset) throws Exception { + initData(buffer, offset); + list.add(new TextString(buffer, offset, 4, "Signature")); list.add(new TextString(buffer, offset + 4, 4, "Version")); - SectionCount numwindows = new SectionCount(buffer, offset + 8, 4, "# panels", - Window.class); - list.add(numwindows); - SectionOffset controlsoffset = new SectionOffset(buffer, offset + 12, "Controls offset", - Control.class); - list.add(controlsoffset); - SectionOffset windowsoffset = new SectionOffset(buffer, offset + 16, "Panels offset", - Window.class); - list.add(windowsoffset); - - offset = windowsoffset.getValue(); - int endoffset = offset; - int windowsize = Math.abs(controlsoffset.getValue() - windowsoffset.getValue()) / numwindows.getValue(); - for (int i = 0; i < numwindows.getValue(); i++) { - Window window = new Window(this, buffer, offset, i, windowsize); + list.add(new SectionCount(buffer, offset + 8, 4, "# panels", Window.class)); + list.add(new SectionOffset(buffer, offset + 12, "Controls offset", Control.class)); + list.add(new SectionOffset(buffer, offset + 16, "Panels offset", Window.class)); + offset += 20; + + // handling optional gap between header and panels section + int endoffset = Math.min(getPanelsOffset(), getControlsOffset()); + if (offset < endoffset) { + list.add(new Unknown(buffer, offset, endoffset - offset, "Unused")); + } + + offset = endoffset; + for (int i = 0; i < getPanelCount(); i++) { + Window window = new Window(this, buffer, offset, i); offset = window.getEndOffset(); - endoffset = Math.max(endoffset, window.readControls(buffer, controlsoffset.getValue())); + endoffset = Math.max(endoffset, window.readControls(buffer)); list.add(window); } + + // handling optional gap between panels section and controls section + if (offset < ofsControls) { + list.add(new Unknown(buffer, offset, ofsControls - offset, "Unused")); + } + return Math.max(offset, endoffset); } + + // initialize data required to reconstruct the original resource on save + private void initData(byte[] buffer, int offset) + { + // loading header data + numPanels = DynamicArray.getInt(buffer, offset + 8); + ofsControls = DynamicArray.getInt(buffer, offset + 12); + ofsPanels = DynamicArray.getInt(buffer, offset + 16); + sizePanels = Math.abs(ofsControls - ofsPanels) / numPanels; + if (sizePanels >= 36) sizePanels = 36; else if (sizePanels >= 28) sizePanels = 28; + + // loading controls data + numControls = 0; + int curOfs = ofsPanels; + for (int i = 0; i < numPanels; i++) { + int numCtrl = DynamicArray.getShort(buffer, curOfs + 14); + int startIdx = DynamicArray.getShort(buffer, curOfs + 24); + numControls = Math.max(numControls, startIdx + numCtrl); + curOfs += sizePanels; + } + + // Adding offset/size pairs for each control + curOfs = ofsControls; + if (listControls == null) { + listControls = new ArrayList>(); + } + int ofs = 0, len = 0; + for (int i = 0; i < numControls; i++, curOfs += 8) { + ofs = DynamicArray.getInt(buffer, curOfs); + len = DynamicArray.getInt(buffer, curOfs + 4); + listControls.add(new Pair(Integer.valueOf(ofs), Integer.valueOf(len))); + } + + // adding virtual entry for determining the true size of the last control entry + ofs = Math.max(ofs + len, buffer.length); + listControls.add(new Pair(Integer.valueOf(ofs), Integer.valueOf(0))); + } } diff --git a/src/infinity/resource/chu/Control.java b/src/infinity/resource/chu/Control.java index 2387e523b..722a68109 100644 --- a/src/infinity/resource/chu/Control.java +++ b/src/infinity/resource/chu/Control.java @@ -31,9 +31,12 @@ final class Control extends AbstractStruct // implements AddRemovable "Right justify"}; private static final String s_case[] = {"Normal case", "Upper case only", "Lower case only"}; - Control(AbstractStruct superStruct, byte buffer[], int offset, int number) throws Exception + private final int size; + + Control(AbstractStruct superStruct, byte buffer[], int offset, int number, int size) throws Exception { super(superStruct, String.format(FMT_NAME, number), buffer, offset); + this.size = size; } // --------------------- Begin Interface Writeable --------------------- @@ -55,9 +58,15 @@ public int read(byte buffer[], int offset) return offset + 8; } + public int getControlSize() + { + return size; + } + public int readControl(byte buffer[]) { int offset = ((HexNumber)getAttribute("Offset")).getValue(); + int endOffset = offset + getControlSize(); list.add(new DecNumber(buffer, offset, 2, "Control ID")); list.add(new DecNumber(buffer, offset + 2, 2, "Buffer length")); list.add(new DecNumber(buffer, offset + 4, 2, "Position: X")); @@ -164,6 +173,13 @@ public int readControl(byte buffer[]) offset += len.getValue(); break; } + + // handling optional gap between controls + if (offset < endOffset) { + list.add(new Unknown(buffer, offset, endOffset - offset, "Unused")); + offset = endOffset; + } + return offset; } diff --git a/src/infinity/resource/chu/Window.java b/src/infinity/resource/chu/Window.java index a279b7209..278ead9d8 100644 --- a/src/infinity/resource/chu/Window.java +++ b/src/infinity/resource/chu/Window.java @@ -9,6 +9,7 @@ import infinity.datatype.Flag; import infinity.datatype.ResourceRef; import infinity.datatype.TextString; +import infinity.datatype.Unknown; import infinity.datatype.UnsignDecNumber; import infinity.resource.AbstractStruct; import infinity.resource.StructEntry; @@ -26,15 +27,12 @@ final class Window extends AbstractStruct // implements AddRemovable Window() throws Exception { - super(null, "Panel", new byte[28], 0); + super(null, "Panel", new byte[36], 0); } - Window(AbstractStruct superStruct, byte buffer[], int offset, int nr, int size) throws Exception + Window(AbstractStruct superStruct, byte buffer[], int offset, int nr) throws Exception { - super(superStruct, String.format(FMT_NAME, nr), buffer, (size >= 36) ? (offset + 8) : offset); - if (size >= 36) { - list.add(0, new TextString(buffer, offset, 8, "Name")); - } + super(superStruct, String.format(FMT_NAME, nr), buffer, offset); } // --------------------- Begin Interface Writeable --------------------- @@ -54,15 +52,24 @@ public void write(OutputStream os) throws IOException // --------------------- End Interface Writeable --------------------- + public ChuResource getChu() + { + if (getSuperStruct() instanceof ChuResource) { + return (ChuResource)getSuperStruct(); + } else { + return null; + } + } - public int readControls(byte buffer[], int controlsoffset) throws Exception + public int readControls(byte buffer[]) throws Exception { - long numctrl = ((UnsignDecNumber)getAttribute("# controls")).getValue(); - long first = ((UnsignDecNumber)getAttribute("First control index")).getValue(); - controlsoffset += (int)(first * (long)8); + int numctrl = (int)((UnsignDecNumber)getAttribute("# controls")).getValue(); + int first = (int)((UnsignDecNumber)getAttribute("First control index")).getValue(); + int controlsoffset = getChu().getControlsOffset() + (first*8); int endoffset = controlsoffset; for (int i = 0; i < numctrl; i++) { - Control control = new Control(this, buffer, controlsoffset, i); + int size = getChu().getControlOffset(first+i+1) - getChu().getControlOffset(first+i); + Control control = new Control(this, buffer, controlsoffset, i, size); controlsoffset = control.getEndOffset(); endoffset = control.readControl(buffer); list.add(control); @@ -91,7 +98,12 @@ public void writeControlsTable(OutputStream os) throws IOException @Override protected int read(byte buffer[], int offset) throws Exception { - list.add(new DecNumber(buffer, offset, 4, "Panel ID")); + if (getChu().getPanelSize() == 36) { + list.add(0, new TextString(buffer, offset, 8, "Name")); + offset += 8; + } + list.add(new DecNumber(buffer, offset, 2, "Panel ID")); + list.add(new Unknown(buffer, offset + 2, 2)); list.add(new DecNumber(buffer, offset + 4, 2, "Position: X")); list.add(new DecNumber(buffer, offset + 6, 2, "Position: Y")); list.add(new DecNumber(buffer, offset + 8, 2, "Width")); diff --git a/src/infinity/resource/sto/StoResource.java b/src/infinity/resource/sto/StoResource.java index c7dadccd2..4a021f3e2 100644 --- a/src/infinity/resource/sto/StoResource.java +++ b/src/infinity/resource/sto/StoResource.java @@ -68,7 +68,7 @@ public AddRemovable[] getAddRemovables() throws Exception // --------------------- End Interface HasAddRemovable --------------------- -// --------------------- Begin Interface HasDetailViewer --------------------- +// --------------------- Begin Interface HasViewerTabs --------------------- @Override public int getViewerTabCount() @@ -96,7 +96,7 @@ public boolean viewerTabAddedBefore(int index) return true; } -// --------------------- End Interface HasDetailViewer --------------------- +// --------------------- End Interface HasViewerTabs --------------------- @Override protected int read(byte buffer[], int offset) throws Exception