Skip to content

Commit

Permalink
Fixed possible corruption of CHU resources on save
Browse files Browse the repository at this point in the history
  • Loading branch information
Argent77 committed Oct 6, 2014
1 parent bac1a5d commit 3dd0f23
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 31 deletions.
143 changes: 127 additions & 16 deletions src/infinity/resource/chu/ChuResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Pair<Integer>> listControls;
private int ofsPanels, numPanels, sizePanels, ofsControls, numControls;

public ChuResource(ResourceEntry entry) throws Exception
{
super(entry);
Expand All @@ -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<Pair<Integer>>();
}
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>(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>(Integer.valueOf(ofs), Integer.valueOf(0)));
}
}

18 changes: 17 additions & 1 deletion src/infinity/resource/chu/Control.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 ---------------------
Expand All @@ -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"));
Expand Down Expand Up @@ -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;
}

Expand Down
36 changes: 24 additions & 12 deletions src/infinity/resource/chu/Window.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 ---------------------
Expand All @@ -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);
Expand Down Expand Up @@ -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"));
Expand Down
4 changes: 2 additions & 2 deletions src/infinity/resource/sto/StoResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public AddRemovable[] getAddRemovables() throws Exception
// --------------------- End Interface HasAddRemovable ---------------------


// --------------------- Begin Interface HasDetailViewer ---------------------
// --------------------- Begin Interface HasViewerTabs ---------------------

@Override
public int getViewerTabCount()
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3dd0f23

Please sign in to comment.