-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from inwc3/FooterSupport
Add map footer support
- Loading branch information
Showing
3 changed files
with
248 additions
and
0 deletions.
There are no files selected for viewing
213 changes: 213 additions & 0 deletions
213
src/main/java/net/moonlightflower/wc3libs/bin/app/MapFooter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.