Skip to content

Commit

Permalink
Merge pull request #6 from inwc3/FooterSupport
Browse files Browse the repository at this point in the history
Add map footer support
  • Loading branch information
WaterKnight authored Mar 3, 2018
2 parents 76eb357 + 56c1ec1 commit c3e26b1
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 0 deletions.
213 changes: 213 additions & 0 deletions src/main/java/net/moonlightflower/wc3libs/bin/app/MapFooter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package net.moonlightflower.wc3libs.bin.app;

import net.moonlightflower.wc3libs.bin.*;
import net.moonlightflower.wc3libs.bin.Reader;
import net.moonlightflower.wc3libs.bin.Writer;
import net.moonlightflower.wc3libs.misc.Id;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class MapFooter {
public final static Id START_TOKEN = Id.valueOf("NGIS");
public final static int DATA_SIZE = 256;

private byte[] _data;

public byte[] getData() {
return Arrays.copyOf(_data, DATA_SIZE);
}

public void setData(byte[] data) {
_data = Arrays.copyOf(data, DATA_SIZE);
}

public static class EncodingFormat extends Format<EncodingFormat.Enum> {
public enum Enum {
AUTO,
MAP_FOOTER_0x0,
}

public final static EncodingFormat AUTO = new EncodingFormat(Enum.AUTO, null);
public final static EncodingFormat MAP_FOOTER_0x0 = new EncodingFormat(Enum.MAP_FOOTER_0x0, 0xB);

@Nullable
public static EncodingFormat valueOf(@Nonnull Integer version) {
return get(EncodingFormat.class, version);
}

private EncodingFormat(@Nonnull Enum enumVal, @Nullable Integer version) {
super(enumVal, version);
}
}

public static class Writer extends net.moonlightflower.wc3libs.bin.Writer<EncodingFormat> {
@Override
public EncodingFormat getAutoFormat() {
return EncodingFormat.AUTO;
}

private MapFooter _mapFooter;

private void write_0x0(@Nonnull Wc3BinOutputStream stream) throws BinStream.StreamException {
long startPos = stream.getPos();

stream.writeId(START_TOKEN);

byte[] data = Arrays.copyOf(_mapFooter._data, DATA_SIZE);

stream.writeBytes(data);
}

public void exec(@Nonnull MapFooter mapFooter) throws BinStream.StreamException {
_mapFooter = mapFooter;

switch (getFormat().toEnum()) {
case AUTO:
case MAP_FOOTER_0x0: {
write_0x0(getStream());

break;
}
}
}

public Writer(@Nonnull Wc3BinOutputStream stream) {
super(stream);
}
}

public static class Reader extends net.moonlightflower.wc3libs.bin.Reader<EncodingFormat> {
public Reader(@Nonnull Wc3BinInputStream stream) {
super(stream);
}

@Override
public EncodingFormat getAutoFormat() {
return EncodingFormat.AUTO;
}

@Nonnull
public MapFooter exec() throws IOException {
return exec(new MapFooter());
}

private MapFooter _mapFooter;

private MapFooter exec(@Nonnull MapFooter mapFooter) throws IOException {
_mapFooter = mapFooter;

read(getFormat());

return _mapFooter;
}

@Nonnull
private MapFooter read(@Nonnull EncodingFormat format) throws IOException {
switch (format.toEnum()) {
case AUTO: {
return read_auto();
}
case MAP_FOOTER_0x0: {
return read_0x0();
}
default:
throw new EncodingFormat.InvalidFormatException(format);
}
}

@Nonnull
private MapFooter read_0x0() throws BinInputStream.StreamException {
Wc3BinInputStream stream = getStream();

Id startToken = stream.readId("startToken");

if (!startToken.equals(START_TOKEN)) throw new IllegalArgumentException("wrong startToken " + startToken);

_mapFooter._data = Arrays.copyOf(stream.readBytes(DATA_SIZE), DATA_SIZE);

return _mapFooter;
}

@Nonnull
private MapFooter read_auto() throws IOException {
return read_0x0();
}
}

public void writeToMapFile(@Nonnull File file) throws IOException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();

Wc3BinOutputStream stream = new Wc3BinOutputStream(byteStream);

Writer writer = new Writer(stream);

writer.exec(this);

stream.close();

byte[] bytes = byteStream.toByteArray();

RandomAccessFile fp = new RandomAccessFile(file, "r");

fp.seek(fp.length() - DATA_SIZE - 4);

byte[] startTokenBytes = new byte[4];

fp.read(startTokenBytes, 0, startTokenBytes.length);

fp.close();

Id startToken = Id.valueOf(new String(startTokenBytes, StandardCharsets.US_ASCII));

fp = new RandomAccessFile(file, "rw");

if (startToken.equals(START_TOKEN)) {
//start token is existing, assume that footer must be existing, substitute old one
fp.seek(fp.length() - DATA_SIZE - 4);
} else {
fp.seek(fp.length());
}

fp.write(bytes);

fp.close();
}

public static MapFooter ofMapFile(@Nonnull File file) throws IOException {
RandomAccessFile fp = new RandomAccessFile(file, "r");

fp.seek(fp.length() - DATA_SIZE - 4);

byte[] bytes = new byte[4 + DATA_SIZE];

fp.read(bytes);

fp.close();

Wc3BinInputStream stream = new Wc3BinInputStream(new ByteArrayInputStream(bytes));

Reader reader = new Reader(stream);

MapFooter mapFooter = reader.exec();

stream.close();

return mapFooter;
}

public static MapFooter ofFile(@Nonnull File file) throws IOException {
Wc3BinInputStream stream = new Wc3BinInputStream(file);

Reader reader = new Reader(stream);

MapFooter mapFooter = reader.exec();

stream.close();

return mapFooter;
}
}
35 changes: 35 additions & 0 deletions src/test/java/wc3libs/bin/app/MapFooterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package wc3libs.bin.app;

import net.moonlightflower.wc3libs.bin.Wc3BinInputStream;
import net.moonlightflower.wc3libs.bin.app.MapFooter;
import net.moonlightflower.wc3libs.bin.app.MapFooter;
import net.moonlightflower.wc3libs.bin.app.WPM;
import net.moonlightflower.wc3libs.port.Orient;
import org.testng.Assert;
import org.testng.annotations.Test;
import wc3libs.misc.Wc3LibTest;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class MapFooterTest extends Wc3LibTest {
@Test()
public void readWriteCycle() throws IOException {
File inFile = getFile("wc3data/Map/Forest_Defense_0.18w_sign.w3x");

MapFooter mapFooter = MapFooter.ofMapFile(inFile);

File outFile = File.createTempFile("wc3libsTest", "mapFooter");

Orient.copyFile(inFile, outFile, true);

mapFooter.writeToMapFile(outFile);

byte[] inBytes = Files.readAllBytes(inFile.toPath());
byte[] outBytes = Files.readAllBytes(outFile.toPath());

Assert.assertEquals(outBytes, inBytes);
}
}
Binary file not shown.

0 comments on commit c3e26b1

Please sign in to comment.