work on texture pack redo
This commit is contained in:
parent
3f648e6692
commit
1e4f407976
|
@ -14,9 +14,8 @@ import org.json.JSONObject;
|
||||||
|
|
||||||
public class AssetRepository {
|
public class AssetRepository {
|
||||||
|
|
||||||
private static final HashMap<String,byte[]> filePool = new HashMap<>();
|
private static final HashMap<String,byte[]> filePool = new HashMap();
|
||||||
private static final HashMap<String,byte[]> filePoolTemp = new HashMap<>();
|
public static final HashMap<String, String> fileNameOverrides = new HashMap();
|
||||||
public static final HashMap<String, String> fileNameOverrides = new HashMap<>();
|
|
||||||
|
|
||||||
public static final void loadOverrides(JSONObject json) {
|
public static final void loadOverrides(JSONObject json) {
|
||||||
JSONObject overrides = json.optJSONObject("assetOverrides", null);
|
JSONObject overrides = json.optJSONObject("assetOverrides", null);
|
||||||
|
@ -34,33 +33,7 @@ public class AssetRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] def = null;
|
|
||||||
|
|
||||||
public static final void reset() throws IOException {
|
|
||||||
if (def != null) {
|
|
||||||
filePool.clear();
|
|
||||||
install(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final void installTemp(byte[] pkg) throws IOException {
|
|
||||||
filePoolTemp.clear();
|
|
||||||
filePoolTemp.putAll(filePool);
|
|
||||||
reset();
|
|
||||||
install(pkg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final void resetTemp() throws IOException {
|
|
||||||
filePool.clear();
|
|
||||||
filePool.putAll(filePoolTemp);
|
|
||||||
filePoolTemp.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final void install(byte[] pkg) throws IOException {
|
public static final void install(byte[] pkg) throws IOException {
|
||||||
if (def == null) {
|
|
||||||
def = pkg;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(pkg);
|
ByteArrayInputStream in = new ByteArrayInputStream(pkg);
|
||||||
|
|
||||||
byte[] header = new byte[8];
|
byte[] header = new byte[8];
|
||||||
|
|
217
src/main/java/net/lax1dude/eaglercraft/EPKDecompiler.java
Normal file
217
src/main/java/net/lax1dude/eaglercraft/EPKDecompiler.java
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
package net.lax1dude.eaglercraft;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import com.jcraft.jzlib.CRC32;
|
||||||
|
import com.jcraft.jzlib.GZIPInputStream;
|
||||||
|
import com.jcraft.jzlib.InflaterInputStream;
|
||||||
|
|
||||||
|
public class EPKDecompiler {
|
||||||
|
|
||||||
|
public static class FileEntry {
|
||||||
|
public final String type;
|
||||||
|
public final String name;
|
||||||
|
public final byte[] data;
|
||||||
|
protected FileEntry(String type, String name, byte[] data) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteArrayInputStream in2;
|
||||||
|
private DataInputStream in;
|
||||||
|
private InputStream zis;
|
||||||
|
private SHA1Digest dg;
|
||||||
|
private CRC32 crc32;
|
||||||
|
private int numFiles;
|
||||||
|
private boolean isFinished = false;
|
||||||
|
private boolean isOldFormat = false;
|
||||||
|
|
||||||
|
public EPKDecompiler(byte[] data) throws IOException {
|
||||||
|
in2 = new ByteArrayInputStream(data);
|
||||||
|
|
||||||
|
byte[] header = new byte[8];
|
||||||
|
in2.read(header);
|
||||||
|
|
||||||
|
if(Arrays.equals(header, new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)36,(byte)36})) {
|
||||||
|
byte[] endCode = new byte[] { (byte)':', (byte)':', (byte)':', (byte)'Y',
|
||||||
|
(byte)'E', (byte)'E', (byte)':', (byte)'>' };
|
||||||
|
for(int i = 0; i < 8; ++i) {
|
||||||
|
if(data[data.length - 8 + i] != endCode[i]) {
|
||||||
|
throw new IOException("EPK file is missing EOF code (:::YEE:>)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in2 = new ByteArrayInputStream(data, 8, data.length - 16);
|
||||||
|
initNew();
|
||||||
|
}else if(Arrays.equals(header, new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)33,(byte)33})) {
|
||||||
|
initOld();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOld() {
|
||||||
|
return isOldFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileEntry readFile() throws IOException {
|
||||||
|
if(!isOldFormat) {
|
||||||
|
return readFileNew();
|
||||||
|
}else {
|
||||||
|
return readFileOld();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initNew() throws IOException {
|
||||||
|
InputStream is = in2;
|
||||||
|
|
||||||
|
String vers = readASCII(is);
|
||||||
|
if(!vers.startsWith("ver2.")) {
|
||||||
|
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||||
|
}
|
||||||
|
|
||||||
|
is.skip(is.read()); // skip filename
|
||||||
|
is.skip(loadShort(is)); // skip comment
|
||||||
|
is.skip(8); // skip millis date
|
||||||
|
|
||||||
|
numFiles = loadInt(is);
|
||||||
|
|
||||||
|
char compressionType = (char)is.read();
|
||||||
|
|
||||||
|
switch(compressionType) {
|
||||||
|
case 'G':
|
||||||
|
zis = new GZIPInputStream(is);
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
zis = new InflaterInputStream(is);
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
zis = is;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IOException("Invalid or unsupported EPK compression: " + compressionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
crc32 = new CRC32();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileEntry readFileNew() throws IOException {
|
||||||
|
if(isFinished) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] typeBytes = new byte[4];
|
||||||
|
zis.read(typeBytes);
|
||||||
|
String type = readASCII(typeBytes);
|
||||||
|
|
||||||
|
if(numFiles == 0) {
|
||||||
|
if(!"END$".equals(type)) {
|
||||||
|
throw new IOException("EPK file is missing END code (END$)");
|
||||||
|
}
|
||||||
|
isFinished = true;
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
if("END$".equals(type)) {
|
||||||
|
throw new IOException("Unexpected END when there are still " + numFiles + " files remaining");
|
||||||
|
}else {
|
||||||
|
String name = readASCII(zis);
|
||||||
|
int len = loadInt(zis);
|
||||||
|
byte[] data;
|
||||||
|
|
||||||
|
if("FILE".equals(type)) {
|
||||||
|
if(len < 5) {
|
||||||
|
throw new IOException("File '" + name + "' is incomplete (no crc)");
|
||||||
|
}
|
||||||
|
|
||||||
|
int loadedCrc = loadInt(zis);
|
||||||
|
|
||||||
|
data = new byte[len - 5];
|
||||||
|
zis.read(data);
|
||||||
|
|
||||||
|
crc32.reset();
|
||||||
|
crc32.update(data, 0, data.length);
|
||||||
|
if((int)crc32.getValue() != loadedCrc) {
|
||||||
|
throw new IOException("File '" + name + "' has an invalid checksum");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(zis.read() != ':') {
|
||||||
|
throw new IOException("File '" + name + "' is incomplete");
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
data = new byte[len];
|
||||||
|
zis.read(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(zis.read() != '>') {
|
||||||
|
throw new IOException("Object '" + name + "' is incomplete");
|
||||||
|
}
|
||||||
|
|
||||||
|
--numFiles;
|
||||||
|
return new FileEntry(type, name, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int loadShort(InputStream is) throws IOException {
|
||||||
|
return (is.read() << 8) | is.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int loadInt(InputStream is) throws IOException {
|
||||||
|
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String readASCII(byte[] bytesIn) throws IOException {
|
||||||
|
char[] charIn = new char[bytesIn.length];
|
||||||
|
for(int i = 0; i < bytesIn.length; ++i) {
|
||||||
|
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||||
|
}
|
||||||
|
return new String(charIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String readASCII(InputStream bytesIn) throws IOException {
|
||||||
|
int len = bytesIn.read();
|
||||||
|
char[] charIn = new char[len];
|
||||||
|
for(int i = 0; i < len; ++i) {
|
||||||
|
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||||
|
}
|
||||||
|
return new String(charIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initOld() throws IOException {
|
||||||
|
isOldFormat = true;
|
||||||
|
dg = new SHA1Digest();
|
||||||
|
in = new DataInputStream(in2);
|
||||||
|
in.readUTF();
|
||||||
|
in = new DataInputStream(new InflaterInputStream(in2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileEntry readFileOld() throws IOException {
|
||||||
|
if(isFinished) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String s = in.readUTF();
|
||||||
|
if(s.equals(" end")) {
|
||||||
|
isFinished = true;
|
||||||
|
return null;
|
||||||
|
}else if(!s.equals("<file>")) {
|
||||||
|
throw new IOException("invalid epk file");
|
||||||
|
}
|
||||||
|
String path = in.readUTF();
|
||||||
|
byte[] digest = new byte[20];
|
||||||
|
byte[] digest2 = new byte[20];
|
||||||
|
in.read(digest);
|
||||||
|
int len = in.readInt();
|
||||||
|
byte[] file = new byte[len];
|
||||||
|
in.read(file);
|
||||||
|
dg.update(file, 0, len); dg.doFinal(digest2, 0);
|
||||||
|
if(!Arrays.equals(digest, digest2)) throw new IOException("invalid file hash for "+path);
|
||||||
|
if(!"</file>".equals(in.readUTF())) throw new IOException("invalid epk file");
|
||||||
|
return new FileEntry("FILE", path, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -93,7 +93,7 @@ public class GuiScreenRelay extends GuiScreen {
|
||||||
}
|
}
|
||||||
lastRefresh += 60l;
|
lastRefresh += 60l;
|
||||||
} else if(btn.id == 6) {
|
} else if(btn.id == 6) {
|
||||||
EaglerAdapter.downloadBytes("EaglerSPRelay.zip", AssetRepository.getResource("relay_download.zip"));
|
EaglerAdapter.downloadBytes("EaglerSPRelay.zip", EaglerAdapter.loadResourceBytes("relay_download.zip"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ public class TextureTerrainMap implements IconRegister {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadData() {
|
private void loadData() {
|
||||||
byte[] data = EaglerAdapter.loadResourceBytes("/" + map.basePath + name + ".png");
|
byte[] data = Minecraft.getMinecraft().texturePackList.getSelectedTexturePack().getResourceAsBytes("/" + map.basePath + name + ".png");
|
||||||
if(data == null) {
|
if(data == null) {
|
||||||
map.replaceTexture(this, map.missingData);
|
map.replaceTexture(this, map.missingData);
|
||||||
}else {
|
}else {
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package net.minecraft.client;
|
package net.minecraft.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.lax1dude.eaglercraft.AssetRepository;
|
|
||||||
import net.lax1dude.eaglercraft.DefaultSkinRenderer;
|
import net.lax1dude.eaglercraft.DefaultSkinRenderer;
|
||||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||||
import net.lax1dude.eaglercraft.EaglerProfile;
|
import net.lax1dude.eaglercraft.EaglerProfile;
|
||||||
|
@ -19,7 +17,6 @@ import net.lax1dude.eaglercraft.IntegratedServer;
|
||||||
import net.lax1dude.eaglercraft.IntegratedServerLAN;
|
import net.lax1dude.eaglercraft.IntegratedServerLAN;
|
||||||
import net.lax1dude.eaglercraft.Voice;
|
import net.lax1dude.eaglercraft.Voice;
|
||||||
import net.lax1dude.eaglercraft.WorkerNetworkManager;
|
import net.lax1dude.eaglercraft.WorkerNetworkManager;
|
||||||
import net.lax1dude.eaglercraft.adapter.SimpleStorage;
|
|
||||||
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
||||||
import net.lax1dude.eaglercraft.glemu.FixedFunctionShader;
|
import net.lax1dude.eaglercraft.glemu.FixedFunctionShader;
|
||||||
import net.minecraft.src.AchievementList;
|
import net.minecraft.src.AchievementList;
|
||||||
|
@ -83,7 +80,6 @@ import net.minecraft.src.StatCollector;
|
||||||
import net.minecraft.src.StatStringFormatKeyInv;
|
import net.minecraft.src.StatStringFormatKeyInv;
|
||||||
import net.minecraft.src.StringTranslate;
|
import net.minecraft.src.StringTranslate;
|
||||||
import net.minecraft.src.TextureManager;
|
import net.minecraft.src.TextureManager;
|
||||||
import net.minecraft.src.TexturePackCustom;
|
|
||||||
import net.minecraft.src.TexturePackList;
|
import net.minecraft.src.TexturePackList;
|
||||||
import net.minecraft.src.Timer;
|
import net.minecraft.src.Timer;
|
||||||
import net.minecraft.src.WorldClient;
|
import net.minecraft.src.WorldClient;
|
||||||
|
@ -340,14 +336,6 @@ public class Minecraft implements Runnable {
|
||||||
String s = EaglerAdapter.getServerToJoinOnLaunch();
|
String s = EaglerAdapter.getServerToJoinOnLaunch();
|
||||||
GuiScreen scr;
|
GuiScreen scr;
|
||||||
|
|
||||||
if (!TexturePackList.defaultTexturePack.getTexturePackFileName().equals(this.gameSettings.skin)) {
|
|
||||||
try {
|
|
||||||
AssetRepository.reset();
|
|
||||||
AssetRepository.install(SimpleStorage.get(this.gameSettings.skin));
|
|
||||||
this.texturePackList.selectedTexturePack = new TexturePackCustom(this.gameSettings.skin, TexturePackList.defaultTexturePack);
|
|
||||||
} catch (IOException ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s != null) {
|
if(s != null) {
|
||||||
scr = new GuiScreenEditProfile(new GuiConnecting(new GuiMainMenu(), this, new ServerData("Eaglercraft Server", s, false)));
|
scr = new GuiScreenEditProfile(new GuiConnecting(new GuiMainMenu(), this, new ServerData("Eaglercraft Server", s, false)));
|
||||||
}else {
|
}else {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import net.lax1dude.eaglercraft.EaglerImage;
|
||||||
import net.lax1dude.eaglercraft.EaglercraftRandom;
|
import net.lax1dude.eaglercraft.EaglercraftRandom;
|
||||||
import net.lax1dude.eaglercraft.TextureLocation;
|
import net.lax1dude.eaglercraft.TextureLocation;
|
||||||
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
public class FontRenderer {
|
public class FontRenderer {
|
||||||
/** Array of width of all the characters in default.png */
|
/** Array of width of all the characters in default.png */
|
||||||
|
@ -131,7 +132,7 @@ public class FontRenderer {
|
||||||
|
|
||||||
private void readFontTexture(String par1Str) {
|
private void readFontTexture(String par1Str) {
|
||||||
//EaglerImage e = EaglerImage.loadImage(EaglerAdapter.loadResourceBytes(par1Str));
|
//EaglerImage e = EaglerImage.loadImage(EaglerAdapter.loadResourceBytes(par1Str));
|
||||||
EaglerImage e = EaglerAdapter.loadPNG(EaglerAdapter.loadResourceBytes(par1Str));
|
EaglerImage e = EaglerAdapter.loadPNG(Minecraft.getMinecraft().texturePackList.getSelectedTexturePack().getResourceAsBytes(par1Str));
|
||||||
int[] var5 = e.data;
|
int[] var5 = e.data;
|
||||||
int var3 = e.w;
|
int var3 = e.w;
|
||||||
int var4 = e.h;
|
int var4 = e.h;
|
||||||
|
@ -174,7 +175,7 @@ public class FontRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readGlyphSizes() {
|
private void readGlyphSizes() {
|
||||||
this.glyphWidth = EaglerAdapter.loadResourceBytes("/font/glyph_sizes.bin");
|
this.glyphWidth = Minecraft.getMinecraft().texturePackList.getSelectedTexturePack().getResourceAsBytes("/font/glyph_sizes.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,7 +5,6 @@ import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.lax1dude.eaglercraft.AssetRepository;
|
|
||||||
import net.lax1dude.eaglercraft.ConfigConstants;
|
import net.lax1dude.eaglercraft.ConfigConstants;
|
||||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||||
import net.lax1dude.eaglercraft.EaglercraftRandom;
|
import net.lax1dude.eaglercraft.EaglercraftRandom;
|
||||||
|
@ -172,7 +171,7 @@ public class GuiMainMenu extends GuiScreen {
|
||||||
this.field_92019_w = this.field_92021_u + 12;
|
this.field_92019_w = this.field_92021_u + 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigConstants.panoramaBlur = AssetRepository.getResource("/title/no-pano-blur.flag") == null;
|
ConfigConstants.panoramaBlur = mc.texturePackList.getSelectedTexturePack().getResourceAsBytes("/title/no-pano-blur.flag") == null;
|
||||||
|
|
||||||
if(this.ackLines.isEmpty()) {
|
if(this.ackLines.isEmpty()) {
|
||||||
int width = 315;
|
int width = 315;
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
package net.minecraft.src;
|
package net.minecraft.src;
|
||||||
|
|
||||||
|
import net.lax1dude.eaglercraft.EPKDecompiler;
|
||||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||||
import net.lax1dude.eaglercraft.adapter.SimpleStorage;
|
import net.lax1dude.eaglercraft.EaglerInflater;
|
||||||
|
import net.lax1dude.eaglercraft.adapter.teavm.vfs.VFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
public class GuiTexturePacks extends GuiScreen {
|
public class GuiTexturePacks extends GuiScreen {
|
||||||
protected GuiScreen guiScreen;
|
protected GuiScreen guiScreen;
|
||||||
|
@ -33,7 +40,7 @@ public class GuiTexturePacks extends GuiScreen {
|
||||||
this.buttonList.add(new GuiSmallButton(5, this.width / 2 - 154, this.height - 48, var1.translateKey("texturePack.openFolder")));
|
this.buttonList.add(new GuiSmallButton(5, this.width / 2 - 154, this.height - 48, var1.translateKey("texturePack.openFolder")));
|
||||||
this.buttonList.add(new GuiSmallButton(6, this.width / 2 + 4, this.height - 48, var1.translateKey("gui.done")));
|
this.buttonList.add(new GuiSmallButton(6, this.width / 2 + 4, this.height - 48, var1.translateKey("gui.done")));
|
||||||
this.mc.texturePackList.updateAvaliableTexturePacks();
|
this.mc.texturePackList.updateAvaliableTexturePacks();
|
||||||
//this.fileLocation = (new File("texturepacks")).getAbsolutePath();
|
this.fileLocation = "texturepacks";
|
||||||
this.guiTexturePackSlot = new GuiTexturePackSlot(this);
|
this.guiTexturePackSlot = new GuiTexturePackSlot(this);
|
||||||
this.guiTexturePackSlot.registerScrollButtons(this.buttonList, 7, 8);
|
this.guiTexturePackSlot.registerScrollButtons(this.buttonList, 7, 8);
|
||||||
}
|
}
|
||||||
|
@ -98,7 +105,26 @@ public class GuiTexturePacks extends GuiScreen {
|
||||||
if (isSelectingPack && EaglerAdapter.getFileChooserResultAvailable()) {
|
if (isSelectingPack && EaglerAdapter.getFileChooserResultAvailable()) {
|
||||||
isSelectingPack = false;
|
isSelectingPack = false;
|
||||||
String name = EaglerAdapter.getFileChooserResultName();
|
String name = EaglerAdapter.getFileChooserResultName();
|
||||||
SimpleStorage.set(name.replaceAll("[^A-Za-z0-9_]", "_"), name.toLowerCase().endsWith(".zip") ? TexturePackList.zipToEpk(EaglerAdapter.getFileChooserResult()) : EaglerAdapter.getFileChooserResult());
|
String safeName = name.replaceAll("[^A-Za-z0-9_]", "_");
|
||||||
|
try {
|
||||||
|
if (name.toLowerCase().endsWith(".zip")) {
|
||||||
|
ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(EaglerAdapter.getFileChooserResult()));
|
||||||
|
ZipEntry entry;
|
||||||
|
while ((entry = zipInputStream.getNextEntry()) != null) {
|
||||||
|
if (entry.isDirectory()) continue;
|
||||||
|
new VFile(fileLocation, safeName, entry.getName()).setAllBytes(EaglerInflater.getBytesFromInputStream(zipInputStream));
|
||||||
|
}
|
||||||
|
zipInputStream.close();
|
||||||
|
} else {
|
||||||
|
EPKDecompiler epkDecompiler = new EPKDecompiler(EaglerAdapter.getFileChooserResult());
|
||||||
|
EPKDecompiler.FileEntry file;
|
||||||
|
while ((file = epkDecompiler.readFile()) != null) {
|
||||||
|
new VFile(fileLocation, safeName, file.name).setAllBytes(file.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
EaglerAdapter.clearFileChooserResult();
|
EaglerAdapter.clearFileChooserResult();
|
||||||
this.mc.displayGuiScreen(this);
|
this.mc.displayGuiScreen(this);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +137,7 @@ public class GuiTexturePacks extends GuiScreen {
|
||||||
List var3 = this.mc.texturePackList.availableTexturePacks();
|
List var3 = this.mc.texturePackList.availableTexturePacks();
|
||||||
|
|
||||||
if (par1) {
|
if (par1) {
|
||||||
SimpleStorage.set(((ITexturePack) var3.get(par2)).getTexturePackFileName(), null);
|
new VFile(fileLocation, ((ITexturePack) var3.get(par2)).getTexturePackFileName()).deleteAll();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
this.mc.texturePackList.setTexturePack((ITexturePack) var3.get(par2));
|
this.mc.texturePackList.setTexturePack((ITexturePack) var3.get(par2));
|
||||||
|
@ -122,7 +148,7 @@ public class GuiTexturePacks extends GuiScreen {
|
||||||
this.mc.texturePackList.setTexturePack((ITexturePack) var3.get(0));
|
this.mc.texturePackList.setTexturePack((ITexturePack) var3.get(0));
|
||||||
this.mc.renderEngine.refreshTextures();
|
this.mc.renderEngine.refreshTextures();
|
||||||
this.mc.renderGlobal.loadRenderers();
|
this.mc.renderGlobal.loadRenderers();
|
||||||
SimpleStorage.set(((ITexturePack) var3.get(par2)).getTexturePackFileName(), null);
|
new VFile(fileLocation, ((ITexturePack) var3.get(par2)).getTexturePackFileName()).deleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package net.minecraft.src;
|
package net.minecraft.src;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public interface ITexturePack {
|
public interface ITexturePack
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Delete the OpenGL texture id of the pack's thumbnail image, and close the zip
|
* Delete the OpenGL texture id of the pack's thumbnail image, and close the zip file in case of TexturePackCustom.
|
||||||
* file in case of TexturePackCustom.
|
|
||||||
*/
|
*/
|
||||||
void deleteTexturePack(RenderEngine var1);
|
void deleteTexturePack(RenderEngine var1);
|
||||||
|
|
||||||
|
@ -14,12 +15,12 @@ public interface ITexturePack {
|
||||||
*/
|
*/
|
||||||
void bindThumbnailTexture(RenderEngine var1);
|
void bindThumbnailTexture(RenderEngine var1);
|
||||||
|
|
||||||
InputStream func_98137_a(String var1, boolean var2);
|
InputStream func_98137_a(String var1, boolean var2) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives a texture resource as InputStream.
|
* Gives a texture resource as InputStream.
|
||||||
*/
|
*/
|
||||||
InputStream getResourceAsStream(String var1);
|
byte[] getResourceAsBytes(String var1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the texture pack ID
|
* Get the texture pack ID
|
||||||
|
@ -27,26 +28,21 @@ public interface ITexturePack {
|
||||||
String getTexturePackID();
|
String getTexturePackID();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file name of the texture pack, or Default if not from a custom
|
* Get the file name of the texture pack, or Default if not from a custom texture pack
|
||||||
* texture pack
|
|
||||||
*/
|
*/
|
||||||
String getTexturePackFileName();
|
String getTexturePackFileName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the first line of the texture pack description (read from the pack.txt
|
* Get the first line of the texture pack description (read from the pack.txt file)
|
||||||
* file)
|
|
||||||
*/
|
*/
|
||||||
String getFirstDescriptionLine();
|
String getFirstDescriptionLine();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the second line of the texture pack description (read from the pack.txt
|
* Get the second line of the texture pack description (read from the pack.txt file)
|
||||||
* file)
|
|
||||||
*/
|
*/
|
||||||
String getSecondDescriptionLine();
|
String getSecondDescriptionLine();
|
||||||
|
|
||||||
boolean func_98138_b(String var1, boolean var2);
|
boolean func_98138_b(String var1, boolean var2);
|
||||||
|
|
||||||
boolean isCompatible();
|
boolean isCompatible();
|
||||||
|
|
||||||
byte[] getResourceAsBytes(String par1Str);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
package net.minecraft.src;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import net.lax1dude.eaglercraft.AssetRepository;
|
|
||||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
|
||||||
import net.lax1dude.eaglercraft.adapter.SimpleStorage;
|
|
||||||
|
|
||||||
public class TexturePackCustom extends TexturePackImplementation {
|
|
||||||
public TexturePackCustom(String name, ITexturePack base) {
|
|
||||||
super(name, name, base);
|
|
||||||
try {
|
|
||||||
AssetRepository.installTemp(SimpleStorage.get(name));
|
|
||||||
this.loadThumbnailImage();
|
|
||||||
this.loadDescription();
|
|
||||||
AssetRepository.resetTemp();
|
|
||||||
} catch (IOException ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean func_98140_c(String par1Str) {
|
|
||||||
return EaglerAdapter.loadResource(par1Str) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCompatible() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected InputStream func_98139_b(String par1Str) throws IOException {
|
|
||||||
return EaglerAdapter.loadResource(par1Str);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getResourceAsBytes(String par1Str) {
|
|
||||||
return EaglerAdapter.loadResourceBytes(par1Str);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||||
|
|
||||||
public class TexturePackDefault extends TexturePackImplementation {
|
public class TexturePackDefault extends TexturePackImplementation {
|
||||||
public TexturePackDefault() {
|
public TexturePackDefault() {
|
||||||
super("default", "Default", (ITexturePack) null);
|
super("default", null, "Default", (ITexturePack) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,7 +25,7 @@ public class TexturePackDefault extends TexturePackImplementation {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InputStream func_98139_b(String par1Str) throws IOException {
|
protected InputStream func_98139_b(String par1Str) {
|
||||||
return EaglerAdapter.loadResource(par1Str);
|
return EaglerAdapter.loadResource(par1Str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
40
src/main/java/net/minecraft/src/TexturePackFolder.java
Normal file
40
src/main/java/net/minecraft/src/TexturePackFolder.java
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package net.minecraft.src;
|
||||||
|
|
||||||
|
import net.lax1dude.eaglercraft.adapter.teavm.vfs.VFile;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class TexturePackFolder extends TexturePackImplementation
|
||||||
|
{
|
||||||
|
public TexturePackFolder(String par1, VFile par2, ITexturePack par3ITexturePack)
|
||||||
|
{
|
||||||
|
super(par1, par2, par2.getName(), par3ITexturePack);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InputStream func_98139_b(String par1Str) throws IOException
|
||||||
|
{
|
||||||
|
VFile var2 = new VFile(this.texturePackFile, par1Str.substring(1));
|
||||||
|
|
||||||
|
if (!var2.exists())
|
||||||
|
{
|
||||||
|
throw new IOException(par1Str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new BufferedInputStream(var2.getInputStream());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean func_98140_c(String par1Str)
|
||||||
|
{
|
||||||
|
VFile var2 = new VFile(this.texturePackFile, par1Str);
|
||||||
|
return var2.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompatible()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,21 +7,26 @@ import java.io.InputStreamReader;
|
||||||
|
|
||||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||||
import net.lax1dude.eaglercraft.EaglerImage;
|
import net.lax1dude.eaglercraft.EaglerImage;
|
||||||
import net.lax1dude.eaglercraft.TextureLocation;
|
import net.lax1dude.eaglercraft.EaglerInflater;
|
||||||
|
import net.lax1dude.eaglercraft.adapter.teavm.vfs.VFile;
|
||||||
|
|
||||||
public abstract class TexturePackImplementation implements ITexturePack {
|
public abstract class TexturePackImplementation implements ITexturePack
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Texture pack ID as returnd by generateTexturePackID(). Used only internally
|
* Texture pack ID as returnd by generateTexturePackID(). Used only internally and not visible to the user.
|
||||||
* and not visible to the user.
|
|
||||||
*/
|
*/
|
||||||
private final String texturePackID;
|
private final String texturePackID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the texture pack's zip file/directory or "Default" for the
|
* The name of the texture pack's zip file/directory or "Default" for the builtin texture pack. Shown in the GUI.
|
||||||
* builtin texture pack. Shown in the GUI.
|
|
||||||
*/
|
*/
|
||||||
private final String texturePackFileName;
|
private final String texturePackFileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File object for the texture pack's zip file in TexturePackCustom or the directory in TexturePackFolder.
|
||||||
|
*/
|
||||||
|
protected final VFile texturePackFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First line of texture pack description (from /pack.txt) displayed in the GUI
|
* First line of texture pack description (from /pack.txt) displayed in the GUI
|
||||||
*/
|
*/
|
||||||
|
@ -39,9 +44,11 @@ public abstract class TexturePackImplementation implements ITexturePack {
|
||||||
/** The texture id for this pcak's thumbnail image. */
|
/** The texture id for this pcak's thumbnail image. */
|
||||||
private int thumbnailTextureName = -1;
|
private int thumbnailTextureName = -1;
|
||||||
|
|
||||||
protected TexturePackImplementation(String par1, String par3Str, ITexturePack par4ITexturePack) {
|
protected TexturePackImplementation(String par1, VFile par2File, String par3Str, ITexturePack par4ITexturePack)
|
||||||
|
{
|
||||||
this.texturePackID = par1;
|
this.texturePackID = par1;
|
||||||
this.texturePackFileName = par3Str;
|
this.texturePackFileName = par3Str;
|
||||||
|
this.texturePackFile = par2File;
|
||||||
this.field_98141_g = par4ITexturePack;
|
this.field_98141_g = par4ITexturePack;
|
||||||
this.loadThumbnailImage();
|
this.loadThumbnailImage();
|
||||||
this.loadDescription();
|
this.loadDescription();
|
||||||
|
@ -50,8 +57,10 @@ public abstract class TexturePackImplementation implements ITexturePack {
|
||||||
/**
|
/**
|
||||||
* Truncate strings to at most 34 characters. Truncates description lines
|
* Truncate strings to at most 34 characters. Truncates description lines
|
||||||
*/
|
*/
|
||||||
private static String trimStringToGUIWidth(String par0Str) {
|
private static String trimStringToGUIWidth(String par0Str)
|
||||||
if (par0Str != null && par0Str.length() > 34) {
|
{
|
||||||
|
if (par0Str != null && par0Str.length() > 34)
|
||||||
|
{
|
||||||
par0Str = par0Str.substring(0, 34);
|
par0Str = par0Str.substring(0, 34);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,48 +70,90 @@ public abstract class TexturePackImplementation implements ITexturePack {
|
||||||
/**
|
/**
|
||||||
* Load and initialize thumbnailImage from the the /pack.png file.
|
* Load and initialize thumbnailImage from the the /pack.png file.
|
||||||
*/
|
*/
|
||||||
protected void loadThumbnailImage() {
|
private void loadThumbnailImage()
|
||||||
//this.thumbnailImage = EaglerImage.loadImage(EaglerAdapter.loadResourceBytes("/pack.png"));
|
{
|
||||||
this.thumbnailImage = EaglerAdapter.loadPNG(EaglerAdapter.loadResourceBytes("/pack.png"));
|
InputStream var1 = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var1 = this.func_98137_a("/pack.png", false);
|
||||||
|
this.thumbnailImage = EaglerImage.loadImage(EaglerInflater.getBytesFromInputStream(var1));
|
||||||
|
}
|
||||||
|
catch (IOException var11)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (var1 != null)
|
||||||
|
{
|
||||||
|
var1.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException var10)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load texture pack description from /pack.txt file in the texture pack
|
* Load texture pack description from /pack.txt file in the texture pack
|
||||||
*/
|
*/
|
||||||
protected void loadDescription() {
|
protected void loadDescription()
|
||||||
|
{
|
||||||
InputStream var1 = null;
|
InputStream var1 = null;
|
||||||
BufferedReader var2 = null;
|
BufferedReader var2 = null;
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
var1 = this.func_98139_b("/pack.txt");
|
var1 = this.func_98139_b("/pack.txt");
|
||||||
var2 = new BufferedReader(new InputStreamReader(var1));
|
var2 = new BufferedReader(new InputStreamReader(var1));
|
||||||
this.firstDescriptionLine = trimStringToGUIWidth(var2.readLine());
|
this.firstDescriptionLine = trimStringToGUIWidth(var2.readLine());
|
||||||
this.secondDescriptionLine = trimStringToGUIWidth(var2.readLine());
|
this.secondDescriptionLine = trimStringToGUIWidth(var2.readLine());
|
||||||
} catch (IOException var12) {
|
}
|
||||||
|
catch (IOException var12)
|
||||||
|
{
|
||||||
;
|
;
|
||||||
} finally {
|
}
|
||||||
try {
|
finally
|
||||||
if (var2 != null) {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (var2 != null)
|
||||||
|
{
|
||||||
var2.close();
|
var2.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var1 != null) {
|
if (var1 != null)
|
||||||
|
{
|
||||||
var1.close();
|
var1.close();
|
||||||
}
|
}
|
||||||
} catch (IOException var11) {
|
}
|
||||||
|
catch (IOException var11)
|
||||||
|
{
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream func_98137_a(String par1Str, boolean par2) {
|
public InputStream func_98137_a(String par1Str, boolean par2) throws IOException
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
return this.func_98139_b(par1Str);
|
return this.func_98139_b(par1Str);
|
||||||
} catch (IOException var4) {
|
}
|
||||||
if (this.field_98141_g != null && par2) {
|
catch (IOException var4)
|
||||||
|
{
|
||||||
|
if (this.field_98141_g != null && par2)
|
||||||
|
{
|
||||||
return this.field_98141_g.func_98137_a(par1Str, true);
|
return this.field_98141_g.func_98137_a(par1Str, true);
|
||||||
}else {
|
}
|
||||||
return null;
|
else
|
||||||
|
{
|
||||||
|
throw var4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,47 +161,53 @@ public abstract class TexturePackImplementation implements ITexturePack {
|
||||||
/**
|
/**
|
||||||
* Gives a texture resource as InputStream.
|
* Gives a texture resource as InputStream.
|
||||||
*/
|
*/
|
||||||
public InputStream getResourceAsStream(String par1Str) {
|
public byte[] getResourceAsBytes(String par1Str)
|
||||||
return this.func_98137_a(par1Str, true);
|
{
|
||||||
|
try {
|
||||||
|
return EaglerInflater.getBytesFromInputStream(this.func_98137_a(par1Str, true));
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract InputStream func_98139_b(String var1) throws IOException;
|
protected abstract InputStream func_98139_b(String var1) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the OpenGL texture id of the pack's thumbnail image, and close the zip
|
* Delete the OpenGL texture id of the pack's thumbnail image, and close the zip file in case of TexturePackCustom.
|
||||||
* file in case of TexturePackCustom.
|
|
||||||
*/
|
*/
|
||||||
public void deleteTexturePack(RenderEngine par1RenderEngine) {
|
public void deleteTexturePack(RenderEngine par1RenderEngine)
|
||||||
if (this.thumbnailImage != null && this.thumbnailTextureName != -1) {
|
{
|
||||||
|
if (this.thumbnailImage != null && this.thumbnailTextureName != -1)
|
||||||
|
{
|
||||||
par1RenderEngine.deleteTexture(this.thumbnailTextureName);
|
par1RenderEngine.deleteTexture(this.thumbnailTextureName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final TextureLocation tex_unknown_pack = new TextureLocation("/gui/unknown_pack.png");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the texture id of the pack's thumbnail image, loading it if necessary.
|
* Bind the texture id of the pack's thumbnail image, loading it if necessary.
|
||||||
*/
|
*/
|
||||||
public void bindThumbnailTexture(RenderEngine par1RenderEngine) {
|
public void bindThumbnailTexture(RenderEngine par1RenderEngine)
|
||||||
if (this.thumbnailImage != null) {
|
{
|
||||||
if (this.thumbnailTextureName == -1) {
|
if (this.thumbnailImage != null)
|
||||||
|
{
|
||||||
|
if (this.thumbnailTextureName == -1)
|
||||||
|
{
|
||||||
this.thumbnailTextureName = par1RenderEngine.allocateAndSetupTexture(this.thumbnailImage);
|
this.thumbnailTextureName = par1RenderEngine.allocateAndSetupTexture(this.thumbnailImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, this.thumbnailTextureName);
|
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, this.thumbnailTextureName);
|
||||||
par1RenderEngine.resetBoundTexture();
|
par1RenderEngine.resetBoundTexture();
|
||||||
} else {
|
}
|
||||||
tex_unknown_pack.bindTexture();
|
else
|
||||||
|
{
|
||||||
|
par1RenderEngine.bindTexture("/gui/unknown_pack.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean func_98138_b(String par1Str, boolean par2) {
|
public boolean func_98138_b(String par1Str, boolean par2)
|
||||||
try {
|
{
|
||||||
boolean var3 = this.func_98140_c(par1Str);
|
boolean var3 = this.func_98140_c(par1Str);
|
||||||
return !var3 && par2 && this.field_98141_g != null ? this.field_98141_g.func_98138_b(par1Str, par2) : var3;
|
return !var3 && par2 && this.field_98141_g != null ? this.field_98141_g.func_98138_b(par1Str, par2) : var3;
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean func_98140_c(String var1);
|
public abstract boolean func_98140_c(String var1);
|
||||||
|
@ -158,31 +215,32 @@ public abstract class TexturePackImplementation implements ITexturePack {
|
||||||
/**
|
/**
|
||||||
* Get the texture pack ID
|
* Get the texture pack ID
|
||||||
*/
|
*/
|
||||||
public String getTexturePackID() {
|
public String getTexturePackID()
|
||||||
|
{
|
||||||
return this.texturePackID;
|
return this.texturePackID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file name of the texture pack, or Default if not from a custom
|
* Get the file name of the texture pack, or Default if not from a custom texture pack
|
||||||
* texture pack
|
|
||||||
*/
|
*/
|
||||||
public String getTexturePackFileName() {
|
public String getTexturePackFileName()
|
||||||
|
{
|
||||||
return this.texturePackFileName;
|
return this.texturePackFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the first line of the texture pack description (read from the pack.txt
|
* Get the first line of the texture pack description (read from the pack.txt file)
|
||||||
* file)
|
|
||||||
*/
|
*/
|
||||||
public String getFirstDescriptionLine() {
|
public String getFirstDescriptionLine()
|
||||||
|
{
|
||||||
return this.firstDescriptionLine;
|
return this.firstDescriptionLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the second line of the texture pack description (read from the pack.txt
|
* Get the second line of the texture pack description (read from the pack.txt file)
|
||||||
* file)
|
|
||||||
*/
|
*/
|
||||||
public String getSecondDescriptionLine() {
|
public String getSecondDescriptionLine()
|
||||||
|
{
|
||||||
return this.secondDescriptionLine;
|
return this.secondDescriptionLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +1,68 @@
|
||||||
package net.minecraft.src;
|
package net.minecraft.src;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.util.ArrayList;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.util.Collections;
|
||||||
import java.io.IOException;
|
import java.util.HashMap;
|
||||||
import java.util.*;
|
import java.util.Iterator;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.List;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.Map;
|
||||||
|
|
||||||
import net.lax1dude.eaglercraft.AssetRepository;
|
import net.lax1dude.eaglercraft.EaglerProfile;
|
||||||
import net.lax1dude.eaglercraft.EPK2Compiler;
|
import net.lax1dude.eaglercraft.adapter.teavm.vfs.VFile;
|
||||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
|
||||||
import net.lax1dude.eaglercraft.adapter.SimpleStorage;
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
public class TexturePackList {
|
public class TexturePackList
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* An instance of TexturePackDefault for the always available builtin texture
|
* An instance of TexturePackDefault for the always available builtin texture pack.
|
||||||
* pack.
|
|
||||||
*/
|
*/
|
||||||
public static final ITexturePack defaultTexturePack = new TexturePackDefault();
|
private static final ITexturePack defaultTexturePack = new TexturePackDefault();
|
||||||
|
|
||||||
/** The Minecraft instance. */
|
/** The Minecraft instance. */
|
||||||
private final Minecraft mc;
|
private final Minecraft mc;
|
||||||
|
|
||||||
/** The directory the texture packs will be loaded from. */
|
/** The directory the texture packs will be loaded from. */
|
||||||
//private final File texturePackDir;
|
private final VFile texturePackDir;
|
||||||
|
|
||||||
/** Folder for the multi-player texturepacks. Returns File. */
|
/** Folder for the multi-player texturepacks. Returns File. */
|
||||||
//private final File mpTexturePackFolder;
|
private final VFile mpTexturePackFolder;
|
||||||
|
|
||||||
/** The list of the available texture packs. */
|
/** The list of the available texture packs. */
|
||||||
private List availableTexturePacks = new ArrayList();
|
private List availableTexturePacks = new ArrayList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping of texture IDs to TexturePackBase objects used by
|
* A mapping of texture IDs to TexturePackBase objects used by updateAvaliableTexturePacks() to avoid reloading
|
||||||
* updateAvaliableTexturePacks() to avoid reloading texture packs that haven't
|
* texture packs that haven't changed on disk.
|
||||||
* changed on disk.
|
|
||||||
*/
|
*/
|
||||||
private Map texturePackCache = new HashMap();
|
private Map texturePackCache = new HashMap();
|
||||||
|
|
||||||
/** The TexturePack that will be used. */
|
/** The TexturePack that will be used. */
|
||||||
public ITexturePack selectedTexturePack;
|
private ITexturePack selectedTexturePack;
|
||||||
|
|
||||||
/** True if a texture pack is downloading in the background. */
|
/** True if a texture pack is downloading in the background. */
|
||||||
private boolean isDownloading;
|
private boolean isDownloading;
|
||||||
|
|
||||||
public TexturePackList(Minecraft par2Minecraft) {
|
public TexturePackList(Minecraft par2Minecraft)
|
||||||
|
{
|
||||||
this.mc = par2Minecraft;
|
this.mc = par2Minecraft;
|
||||||
//this.texturePackDir = new File(par1File, "texturepacks");
|
this.texturePackDir = new VFile("texturepacks");
|
||||||
//this.mpTexturePackFolder = new File(par1File, "texturepacks-mp-cache");
|
this.mpTexturePackFolder = new VFile("texturepacks-mp-cache");
|
||||||
this.updateAvaliableTexturePacks();
|
this.updateAvaliableTexturePacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the new TexturePack to be used, returning true if it has actually
|
* Sets the new TexturePack to be used, returning true if it has actually changed, false if nothing changed.
|
||||||
* changed, false if nothing changed.
|
|
||||||
*/
|
*/
|
||||||
public boolean setTexturePack(ITexturePack par1ITexturePack) {
|
public boolean setTexturePack(ITexturePack par1ITexturePack)
|
||||||
if (par1ITexturePack == this.selectedTexturePack) {
|
{
|
||||||
|
if (par1ITexturePack == this.selectedTexturePack)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
this.isDownloading = false;
|
this.isDownloading = false;
|
||||||
this.selectedTexturePack = par1ITexturePack;
|
this.selectedTexturePack = par1ITexturePack;
|
||||||
try {
|
|
||||||
AssetRepository.reset();
|
|
||||||
AssetRepository.install(SimpleStorage.get(this.selectedTexturePack.getTexturePackFileName()));
|
|
||||||
} catch (IOException ignored) {}
|
|
||||||
this.mc.gameSettings.skin = par1ITexturePack.getTexturePackFileName();
|
this.mc.gameSettings.skin = par1ITexturePack.getTexturePackFileName();
|
||||||
this.mc.gameSettings.saveOptions();
|
this.mc.gameSettings.saveOptions();
|
||||||
return true;
|
return true;
|
||||||
|
@ -73,38 +70,53 @@ public class TexturePackList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* filename must end in .zip or .epk
|
* filename must end in .zip
|
||||||
*/
|
*/
|
||||||
public void requestDownloadOfTexture(String par1Str) {
|
public void requestDownloadOfTexture(String par1Str)
|
||||||
|
{
|
||||||
String var2 = par1Str.substring(par1Str.lastIndexOf("/") + 1);
|
String var2 = par1Str.substring(par1Str.lastIndexOf("/") + 1);
|
||||||
|
|
||||||
if (var2.contains("?")) {
|
if (var2.contains("?"))
|
||||||
|
{
|
||||||
var2 = var2.substring(0, var2.indexOf("?"));
|
var2 = var2.substring(0, var2.indexOf("?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var2.toLowerCase().endsWith(".zip") || var2.toLowerCase().endsWith(".epk")) {
|
if (var2.endsWith(".zip"))
|
||||||
this.downloadTexture(par1Str, var2);
|
{
|
||||||
|
VFile var3 = new VFile(this.mpTexturePackFolder, var2);
|
||||||
|
this.downloadTexture(par1Str, var3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void downloadTexture(String par1Str, String par2File) {
|
private void downloadTexture(String par1Str, VFile par2File)
|
||||||
|
{
|
||||||
|
HashMap var3 = new HashMap();
|
||||||
|
GuiProgress var4 = new GuiProgress();
|
||||||
|
var3.put("X-Minecraft-Username", EaglerProfile.username);
|
||||||
|
var3.put("X-Minecraft-Version", "1.5.2");
|
||||||
|
var3.put("X-Minecraft-Supported-Resolutions", "16");
|
||||||
this.isDownloading = true;
|
this.isDownloading = true;
|
||||||
SimpleStorage.set(par2File.replaceAll("[^A-Za-z0-9_]", "_"), par2File.toLowerCase().endsWith(".zip") ? zipToEpk(EaglerAdapter.downloadURL(par1Str)) : EaglerAdapter.downloadURL(par1Str));
|
this.mc.displayGuiScreen(var4);
|
||||||
this.onDownloadFinished();
|
// todo: extract epk/zip to VFS, activate, and signal success
|
||||||
|
onDownloadFinished(); // temp
|
||||||
|
// SimpleStorage.set(par2File.replaceAll("[^A-Za-z0-9_]", "_"), par2File.toLowerCase().endsWith(".zip") ? zipToEpk(EaglerAdapter.downloadURL(par1Str)) : EaglerAdapter.downloadURL(par1Str));
|
||||||
|
// HttpUtil.downloadTexturePack(par2File, par1Str, new TexturePackDownloadSuccess(this), var3, 10000000, var4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if a texture pack is downloading in the background.
|
* Return true if a texture pack is downloading in the background.
|
||||||
*/
|
*/
|
||||||
public boolean getIsDownloading() {
|
public boolean getIsDownloading()
|
||||||
|
{
|
||||||
return this.isDownloading;
|
return this.isDownloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from Minecraft.loadWorld() if getIsDownloading() returned true to
|
* Called from Minecraft.loadWorld() if getIsDownloading() returned true to prepare the downloaded texture for
|
||||||
* prepare the downloaded texture for usage.
|
* usage.
|
||||||
*/
|
*/
|
||||||
public void onDownloadFinished() {
|
public void onDownloadFinished()
|
||||||
|
{
|
||||||
this.isDownloading = false;
|
this.isDownloading = false;
|
||||||
this.updateAvaliableTexturePacks();
|
this.updateAvaliableTexturePacks();
|
||||||
this.mc.scheduleTexturePackRefresh();
|
this.mc.scheduleTexturePackRefresh();
|
||||||
|
@ -113,41 +125,43 @@ public class TexturePackList {
|
||||||
/**
|
/**
|
||||||
* check the texture packs the client has installed
|
* check the texture packs the client has installed
|
||||||
*/
|
*/
|
||||||
public void updateAvaliableTexturePacks() {
|
public void updateAvaliableTexturePacks()
|
||||||
|
{
|
||||||
ArrayList var1 = new ArrayList();
|
ArrayList var1 = new ArrayList();
|
||||||
|
this.selectedTexturePack = defaultTexturePack;
|
||||||
var1.add(defaultTexturePack);
|
var1.add(defaultTexturePack);
|
||||||
Iterator var2 = this.getTexturePackDirContents().iterator();
|
Iterator var2 = this.getTexturePackDirContents().iterator();
|
||||||
|
|
||||||
while (var2.hasNext()) {
|
while (var2.hasNext())
|
||||||
String var3 = (String) var2.next();
|
{
|
||||||
|
VFile var3 = (VFile)var2.next();
|
||||||
|
String var4 = this.generateTexturePackID(var3);
|
||||||
|
|
||||||
Object var5 = (ITexturePack) this.texturePackCache.get(var3);
|
if (var4 != null)
|
||||||
|
{
|
||||||
|
Object var5 = (ITexturePack)this.texturePackCache.get(var4);
|
||||||
|
|
||||||
if (var5 == null) {
|
if (var5 == null)
|
||||||
try {
|
{
|
||||||
var5 = new TexturePackCustom(var3, defaultTexturePack);
|
var5 = new TexturePackFolder(var4, var3, defaultTexturePack);
|
||||||
this.texturePackCache.put(var3, var5);
|
this.texturePackCache.put(var4, var5);
|
||||||
} catch (RuntimeException e) {
|
|
||||||
e.printStackTrace(); // bad texture pack
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((ITexturePack) var5).getTexturePackFileName().equals(this.mc.gameSettings.skin)) {
|
if (((ITexturePack)var5).getTexturePackFileName().equals(this.mc.gameSettings.skin))
|
||||||
this.selectedTexturePack = (ITexturePack) var5;
|
{
|
||||||
try {
|
this.selectedTexturePack = (ITexturePack)var5;
|
||||||
AssetRepository.reset();
|
|
||||||
AssetRepository.install(SimpleStorage.get(this.selectedTexturePack.getTexturePackFileName()));
|
|
||||||
} catch (IOException ignored) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var1.add(var5);
|
var1.add(var5);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.availableTexturePacks.removeAll(var1);
|
this.availableTexturePacks.removeAll(var1);
|
||||||
var2 = this.availableTexturePacks.iterator();
|
var2 = this.availableTexturePacks.iterator();
|
||||||
|
|
||||||
while (var2.hasNext()) {
|
while (var2.hasNext())
|
||||||
ITexturePack var6 = (ITexturePack) var2.next();
|
{
|
||||||
|
ITexturePack var6 = (ITexturePack)var2.next();
|
||||||
var6.deleteTexturePack(this.mc.renderEngine);
|
var6.deleteTexturePack(this.mc.renderEngine);
|
||||||
this.texturePackCache.remove(var6.getTexturePackID());
|
this.texturePackCache.remove(var6.getTexturePackID());
|
||||||
}
|
}
|
||||||
|
@ -156,103 +170,104 @@ public class TexturePackList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an internal texture pack ID from the file/directory name, last
|
* Generate an internal texture pack ID from the file/directory name, last modification time, and file size. Returns
|
||||||
* modification time, and file size. Returns null if the file/directory is not a
|
* null if the file/directory is not a texture pack.
|
||||||
* texture pack.
|
|
||||||
*/
|
*/
|
||||||
// private String generateTexturePackID(File par1File) {
|
private String generateTexturePackID(VFile par1File)
|
||||||
// return par1File.isFile() && par1File.getName().toLowerCase().endsWith(".zip") ? par1File.getName() + ":" + par1File.length() + ":" + par1File.lastModified()
|
{
|
||||||
// : (par1File.isDirectory() && (new File(par1File, "pack.txt")).exists() ? par1File.getName() + ":folder:" + par1File.lastModified() : null);
|
return (new VFile(par1File, "pack.txt")).exists() ? par1File.getName() + ":folder" : null;
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a List<String> of file/directories in the texture pack directory.
|
* Return a List<File> of file/directories in the texture pack directory.
|
||||||
*/
|
*/
|
||||||
private List getTexturePackDirContents() {
|
private List getTexturePackDirContents()
|
||||||
return SimpleStorage.isAvailable() ? Arrays.asList(SimpleStorage.list()) : Collections.emptyList();
|
{
|
||||||
|
// TODO: MAKE THIS MORE EFFICIENT!! THIS IS A TEMPORARY FIX BC IM TIRED
|
||||||
|
List<String> strings = this.texturePackDir.list();
|
||||||
|
List<String> strings2 = new ArrayList<>();
|
||||||
|
List<VFile> files = new ArrayList<>();
|
||||||
|
for (String name : strings) {
|
||||||
|
name = name.substring(this.texturePackDir.getPath().length() + 1);
|
||||||
|
name = name.substring(0, name.indexOf('/'));
|
||||||
|
name = this.texturePackDir.getPath() + "/" + name;
|
||||||
|
if (strings2.contains(name)) continue;
|
||||||
|
strings2.add(name);
|
||||||
|
files.add(new VFile(name));
|
||||||
|
}
|
||||||
|
strings2.clear();
|
||||||
|
strings.clear();
|
||||||
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of the available texture packs.
|
* Returns a list of the available texture packs.
|
||||||
*/
|
*/
|
||||||
public List availableTexturePacks() {
|
public List availableTexturePacks()
|
||||||
|
{
|
||||||
return Collections.unmodifiableList(this.availableTexturePacks);
|
return Collections.unmodifiableList(this.availableTexturePacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITexturePack getSelectedTexturePack() {
|
public ITexturePack getSelectedTexturePack()
|
||||||
if (this.selectedTexturePack == null) {
|
{
|
||||||
this.selectedTexturePack = defaultTexturePack;
|
|
||||||
}
|
|
||||||
return this.selectedTexturePack;
|
return this.selectedTexturePack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean func_77300_f() {
|
public boolean func_77300_f()
|
||||||
if (!this.mc.gameSettings.serverTextures) {
|
{
|
||||||
|
if (!this.mc.gameSettings.serverTextures)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ServerData var1 = this.mc.getServerData();
|
ServerData var1 = this.mc.getServerData();
|
||||||
return var1 == null ? true : var1.func_78840_c();
|
return var1 == null ? true : var1.func_78840_c();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getAcceptsTextures() {
|
public boolean getAcceptsTextures()
|
||||||
if (!this.mc.gameSettings.serverTextures) {
|
{
|
||||||
|
if (!this.mc.gameSettings.serverTextures)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ServerData var1 = this.mc.getServerData();
|
ServerData var1 = this.mc.getServerData();
|
||||||
return var1 == null ? false : var1.getAcceptsTextures();
|
return var1 == null ? false : var1.getAcceptsTextures();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isDownloading(TexturePackList par0TexturePackList) {
|
static boolean isDownloading(TexturePackList par0TexturePackList)
|
||||||
|
{
|
||||||
return par0TexturePackList.isDownloading;
|
return par0TexturePackList.isDownloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the selectedTexturePack field (Inner class static accessor method).
|
* Set the selectedTexturePack field (Inner class static accessor method).
|
||||||
*/
|
*/
|
||||||
static ITexturePack setSelectedTexturePack(TexturePackList par0TexturePackList, ITexturePack par1ITexturePack) {
|
static ITexturePack setSelectedTexturePack(TexturePackList par0TexturePackList, ITexturePack par1ITexturePack)
|
||||||
|
{
|
||||||
return par0TexturePackList.selectedTexturePack = par1ITexturePack;
|
return par0TexturePackList.selectedTexturePack = par1ITexturePack;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
/**
|
|
||||||
* Generate an internal texture pack ID from the file/directory name, last
|
|
||||||
* modification time, and file size. Returns null if the file/directory is not a
|
|
||||||
* texture pack. (Inner class static accessor method).
|
|
||||||
|
|
||||||
static String generateTexturePackID(TexturePackList par0TexturePackList, File par1File) {
|
/**
|
||||||
|
* Generate an internal texture pack ID from the file/directory name, last modification time, and file size. Returns
|
||||||
|
* null if the file/directory is not a texture pack. (Inner class static accessor method).
|
||||||
|
*/
|
||||||
|
static String generateTexturePackID(TexturePackList par0TexturePackList, VFile par1File)
|
||||||
|
{
|
||||||
return par0TexturePackList.generateTexturePackID(par1File);
|
return par0TexturePackList.generateTexturePackID(par1File);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
static ITexturePack func_98143_h() {
|
static ITexturePack func_98143_h()
|
||||||
|
{
|
||||||
return defaultTexturePack;
|
return defaultTexturePack;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Minecraft getMinecraft(TexturePackList par0TexturePackList) {
|
static Minecraft getMinecraft(TexturePackList par0TexturePackList)
|
||||||
|
{
|
||||||
return par0TexturePackList.mc;
|
return par0TexturePackList.mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final byte[] zipToEpk(byte[] in) {
|
|
||||||
try {
|
|
||||||
EPK2Compiler epk2Compiler = new EPK2Compiler();
|
|
||||||
try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(in))) {
|
|
||||||
ZipEntry zipEntry;
|
|
||||||
byte[] bb = new byte[16000];
|
|
||||||
while ((zipEntry = zis.getNextEntry()) != null) {
|
|
||||||
if (zipEntry.isDirectory()) continue;
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
int len;
|
|
||||||
while ((len = zis.read(bb)) != -1) {
|
|
||||||
baos.write(bb, 0, len);
|
|
||||||
}
|
|
||||||
baos.close();
|
|
||||||
epk2Compiler.append(zipEntry.getName(), baos.toByteArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return epk2Compiler.complete();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package net.lax1dude.eaglercraft.adapter.teavm.vfs;
|
||||||
|
|
||||||
|
public class BooleanResult {
|
||||||
|
|
||||||
|
public static final BooleanResult TRUE = new BooleanResult(true);
|
||||||
|
public static final BooleanResult FALSE = new BooleanResult(false);
|
||||||
|
|
||||||
|
public final boolean bool;
|
||||||
|
|
||||||
|
private BooleanResult(boolean b) {
|
||||||
|
bool = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BooleanResult _new(boolean b) {
|
||||||
|
return b ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package net.lax1dude.eaglercraft.adapter.teavm.vfs;
|
||||||
|
|
||||||
|
public class SYS {
|
||||||
|
|
||||||
|
public static final VirtualFilesystem VFS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
VirtualFilesystem.VFSHandle vh = VirtualFilesystem.openVFS("_net_lax1dude_eaglercraft_adapter_teavm_vfs_VirtualFilesystem_1_5_2_eagStorage");
|
||||||
|
|
||||||
|
if(vh.vfs == null) {
|
||||||
|
System.err.println("Could not init filesystem!");
|
||||||
|
throw new RuntimeException("Could not init filesystem: VFSHandle.vfs was null");
|
||||||
|
}
|
||||||
|
|
||||||
|
VFS = vh.vfs;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package net.lax1dude.eaglercraft.adapter.teavm.vfs;
|
||||||
|
|
||||||
|
public interface VFSIterator {
|
||||||
|
|
||||||
|
public static class BreakLoop extends RuntimeException {
|
||||||
|
public BreakLoop() {
|
||||||
|
super("iterator loop break request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public default void end() {
|
||||||
|
throw new BreakLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next(VIteratorFile entry);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
package net.lax1dude.eaglercraft.adapter.teavm.vfs;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VFile {
|
||||||
|
|
||||||
|
public static final String pathSeperator = "/";
|
||||||
|
public static final String[] altPathSeperator = new String[] { "\\" };
|
||||||
|
|
||||||
|
public static String normalizePath(String p) {
|
||||||
|
for(int i = 0; i < altPathSeperator.length; ++i) {
|
||||||
|
p = p.replace(altPathSeperator[i], pathSeperator);
|
||||||
|
}
|
||||||
|
if(p.startsWith(pathSeperator)) {
|
||||||
|
p = p.substring(1);
|
||||||
|
}
|
||||||
|
if(p.endsWith(pathSeperator)) {
|
||||||
|
p = p.substring(0, p.length() - pathSeperator.length());
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] splitPath(String p) {
|
||||||
|
String[] pth = normalizePath(p).split(pathSeperator);
|
||||||
|
for(int i = 0; i < pth.length; ++i) {
|
||||||
|
pth[i] = pth[i].trim();
|
||||||
|
}
|
||||||
|
return pth;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String path;
|
||||||
|
|
||||||
|
public static String createPath(Object... p) {
|
||||||
|
ArrayList<String> r = new ArrayList<>();
|
||||||
|
for(int i = 0; i < p.length; ++i) {
|
||||||
|
if(p[i] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String gg = p[i].toString();
|
||||||
|
if(gg == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String[] parts = splitPath(gg);
|
||||||
|
for(int j = 0; j < parts.length; ++j) {
|
||||||
|
if(parts[j] == null || parts[j].equals(".")) {
|
||||||
|
continue;
|
||||||
|
}else if(parts[j].equals("..") && r.size() > 0) {
|
||||||
|
int k = r.size() - 1;
|
||||||
|
if(!r.get(k).equals("..")) {
|
||||||
|
r.remove(k);
|
||||||
|
}else {
|
||||||
|
r.add("..");
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
r.add(parts[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(r.size() > 0) {
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
for(int i = 0; i < r.size(); ++i) {
|
||||||
|
if(i > 0) {
|
||||||
|
s.append(pathSeperator);
|
||||||
|
}
|
||||||
|
s.append(r.get(i));
|
||||||
|
}
|
||||||
|
return s.toString();
|
||||||
|
}else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public VFile(Object... p) {
|
||||||
|
this.path = createPath(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return isRelative() ? null : SYS.VFS.getFile(path).getInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
return isRelative() ? null : SYS.VFS.getFile(path).getOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRelative() {
|
||||||
|
return path == null || path.contains("..");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canRead() {
|
||||||
|
return !isRelative() && SYS.VFS.fileExists(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path.equals("unnamed") ? null : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
if(path == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int i = path.indexOf(pathSeperator);
|
||||||
|
return i == -1 ? path : path.substring(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canWrite() {
|
||||||
|
return !isRelative();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParent() {
|
||||||
|
if(path == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int i = path.indexOf(pathSeperator);
|
||||||
|
return i == -1 ? ".." : path.substring(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return path == null ? 0 : path.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return path != null && o != null && (o instanceof VFile) && path.equals(((VFile)o).path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
return !isRelative() && SYS.VFS.fileExists(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete() {
|
||||||
|
return !isRelative() && SYS.VFS.deleteFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean renameTo(String p, boolean copy) {
|
||||||
|
if(!isRelative() && SYS.VFS.renameFile(path, p, copy)) {
|
||||||
|
path = p;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int length() {
|
||||||
|
return isRelative() ? -1 : SYS.VFS.getFile(path).getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getBytes(int fileOffset, byte[] array, int offset, int length) {
|
||||||
|
if(isRelative()) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException("File is relative");
|
||||||
|
}
|
||||||
|
SYS.VFS.getFile(path).getBytes(fileOffset, array, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheEnabled() {
|
||||||
|
if(isRelative()) {
|
||||||
|
throw new RuntimeException("File is relative");
|
||||||
|
}
|
||||||
|
SYS.VFS.getFile(path).setCacheEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getAllBytes() {
|
||||||
|
if(isRelative()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return SYS.VFS.getFile(path).getAllBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAllChars() {
|
||||||
|
if(isRelative()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return SYS.VFS.getFile(path).getAllChars();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAllLines() {
|
||||||
|
if(isRelative()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return SYS.VFS.getFile(path).getAllLines();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getAllBytes(boolean copy) {
|
||||||
|
if(isRelative()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return SYS.VFS.getFile(path).getAllBytes(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllChars(String bytes) {
|
||||||
|
if(isRelative()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return SYS.VFS.getFile(path).setAllChars(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllBytes(byte[] bytes) {
|
||||||
|
if(isRelative()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return SYS.VFS.getFile(path).setAllBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllBytes(byte[] bytes, boolean copy) {
|
||||||
|
if(isRelative()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return SYS.VFS.getFile(path).setAllBytes(bytes, copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> list() {
|
||||||
|
if(isRelative()) {
|
||||||
|
return Arrays.asList(path);
|
||||||
|
}
|
||||||
|
return SYS.VFS.listFiles(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteAll() {
|
||||||
|
return isRelative() ? 0 : SYS.VFS.deleteFiles(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,289 @@
|
||||||
|
package net.lax1dude.eaglercraft.adapter.teavm.vfs;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.teavm.interop.Async;
|
||||||
|
import org.teavm.interop.AsyncCallback;
|
||||||
|
import org.teavm.jso.JSBody;
|
||||||
|
import org.teavm.jso.JSObject;
|
||||||
|
import org.teavm.jso.dom.events.Event;
|
||||||
|
import org.teavm.jso.dom.events.EventListener;
|
||||||
|
import org.teavm.jso.indexeddb.IDBCursor;
|
||||||
|
import org.teavm.jso.indexeddb.IDBRequest;
|
||||||
|
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||||
|
import org.teavm.jso.typedarrays.Uint8Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not use an instance of this class outside of the VFSIterator.next() method
|
||||||
|
*/
|
||||||
|
public class VIteratorFile extends VFile {
|
||||||
|
|
||||||
|
static final VIteratorFile instance = new VIteratorFile();
|
||||||
|
|
||||||
|
private VIteratorFile() {
|
||||||
|
super("");
|
||||||
|
this.idx = -1;
|
||||||
|
this.cur = null;
|
||||||
|
this.vfs = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class VirtualIteratorOutputStream extends ByteArrayOutputStream {
|
||||||
|
|
||||||
|
private final VIteratorFile itr;
|
||||||
|
|
||||||
|
protected VirtualIteratorOutputStream(VIteratorFile itr) {
|
||||||
|
this.itr = itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
if(!itr.setAllBytes(super.toByteArray(), false)) {
|
||||||
|
throw new IOException("Could not close stream and write to \"" + itr.path + "\" on VFS \"" + itr.vfs.database + "\" (the file was probably deleted)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
private IDBCursor cur;
|
||||||
|
private VirtualFilesystem vfs;
|
||||||
|
private boolean wasDeleted;
|
||||||
|
|
||||||
|
@JSBody(params = { "k" }, script = "return ((typeof k) === \"string\") ? k : (((typeof k) === \"undefined\") ? null : (((typeof k[0]) === \"string\") ? k[0] : null));")
|
||||||
|
private static native String readKey(JSObject k);
|
||||||
|
|
||||||
|
static VIteratorFile create(int idx, VirtualFilesystem vfs, IDBCursor cur) {
|
||||||
|
String k = readKey(cur.getKey());
|
||||||
|
if(k == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
instance.update(idx, k, vfs, cur);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VFile makeVFile() {
|
||||||
|
return new VFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(int idx, String path, VirtualFilesystem vfs, IDBCursor cur) {
|
||||||
|
this.idx = idx;
|
||||||
|
this.path = path;
|
||||||
|
this.vfs = vfs;
|
||||||
|
this.cur = cur;
|
||||||
|
this.wasDeleted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return !wasDeleted ? new ByteArrayInputStream(getAllBytes()) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
return !wasDeleted ? new VirtualIteratorOutputStream(this) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRelative() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canRead() {
|
||||||
|
return !wasDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
if(path == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int i = path.indexOf(pathSeperator);
|
||||||
|
return i == -1 ? path : path.substring(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canWrite() {
|
||||||
|
return !wasDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParent() {
|
||||||
|
if(path == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int i = path.indexOf(pathSeperator);
|
||||||
|
return i == -1 ? ".." : path.substring(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return path == null ? 0 : path.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return path != null && o != null && (o instanceof VFile) && path.equals(((VFile)o).path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
return !wasDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete() {
|
||||||
|
return wasDeleted = AsyncHandlers.awaitRequest(cur.delete()).bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean renameTo(String p) {
|
||||||
|
byte[] data = getAllBytes();
|
||||||
|
String op = path;
|
||||||
|
path = p;
|
||||||
|
if(!setAllBytes(data)) {
|
||||||
|
path = op;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
path = op;
|
||||||
|
if(!delete()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
path = p;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int length() {
|
||||||
|
JSObject obj = cur.getValue();
|
||||||
|
|
||||||
|
if(obj == null) {
|
||||||
|
throw new RuntimeException("Value of entry is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayBuffer arr = readRow(obj);
|
||||||
|
|
||||||
|
if(arr == null) {
|
||||||
|
throw new RuntimeException("Value of the fucking value of the entry is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr.getByteLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getBytes(int fileOffset, byte[] array, int offset, int length) {
|
||||||
|
JSObject obj = cur.getValue();
|
||||||
|
|
||||||
|
if(obj == null) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException("Value of entry is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayBuffer arr = readRow(obj);
|
||||||
|
|
||||||
|
if(arr == null) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException("Value of the fucking value of the entry is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint8Array a = new Uint8Array(arr);
|
||||||
|
|
||||||
|
if(a.getLength() < fileOffset + length) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException("file '" + path + "' size was "+a.getLength()+" but user tried to read index "+(fileOffset + length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < length; ++i) {
|
||||||
|
array[i + offset] = (byte)a.get(i + fileOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheEnabled() {
|
||||||
|
// no
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(params = { "obj" }, script = "return (typeof obj === 'undefined') ? null : ((typeof obj.data === 'undefined') ? null : obj.data);")
|
||||||
|
private static native ArrayBuffer readRow(JSObject obj);
|
||||||
|
|
||||||
|
public byte[] getAllBytes() {
|
||||||
|
JSObject obj = cur.getValue();
|
||||||
|
|
||||||
|
if(obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayBuffer arr = readRow(obj);
|
||||||
|
|
||||||
|
if(arr == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint8Array a = new Uint8Array(arr);
|
||||||
|
int ii = a.getByteLength();
|
||||||
|
|
||||||
|
byte[] array = new byte[ii];
|
||||||
|
for(int i = 0; i < ii; ++i) {
|
||||||
|
array[i] = (byte)a.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAllChars() {
|
||||||
|
return VirtualFilesystem.utf8(getAllBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAllLines() {
|
||||||
|
return VirtualFilesystem.lines(VirtualFilesystem.utf8(getAllBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getAllBytes(boolean copy) {
|
||||||
|
return getAllBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllChars(String bytes) {
|
||||||
|
return setAllBytes(VirtualFilesystem.utf8(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> list() {
|
||||||
|
throw new RuntimeException("Cannot perform list all in VFS callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteAll() {
|
||||||
|
throw new RuntimeException("Cannot perform delete all in VFS callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(params = { "pat", "dat" }, script = "return { path: pat, data: dat };")
|
||||||
|
private static native JSObject writeRow(String name, ArrayBuffer data);
|
||||||
|
|
||||||
|
public boolean setAllBytes(byte[] bytes) {
|
||||||
|
ArrayBuffer a = new ArrayBuffer(bytes.length);
|
||||||
|
Uint8Array ar = new Uint8Array(a);
|
||||||
|
ar.set(bytes);
|
||||||
|
JSObject obj = writeRow(path, a);
|
||||||
|
BooleanResult r = AsyncHandlers.awaitRequest(cur.update(obj));
|
||||||
|
return r.bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllBytes(byte[] bytes, boolean copy) {
|
||||||
|
return setAllBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AsyncHandlers {
|
||||||
|
|
||||||
|
@Async
|
||||||
|
public static native BooleanResult awaitRequest(IDBRequest r);
|
||||||
|
|
||||||
|
private static void awaitRequest(IDBRequest r, final AsyncCallback<BooleanResult> cb) {
|
||||||
|
r.addEventListener("success", new EventListener<Event>() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(Event evt) {
|
||||||
|
cb.complete(BooleanResult._new(true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.addEventListener("error", new EventListener<Event>() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(Event evt) {
|
||||||
|
cb.complete(BooleanResult._new(false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,681 @@
|
||||||
|
package net.lax1dude.eaglercraft.adapter.teavm.vfs;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||||
|
import net.lax1dude.eaglercraft.adapter.teavm.TeaVMUtils;
|
||||||
|
import org.teavm.interop.Async;
|
||||||
|
import org.teavm.interop.AsyncCallback;
|
||||||
|
import org.teavm.jso.JSBody;
|
||||||
|
import org.teavm.jso.JSObject;
|
||||||
|
import org.teavm.jso.dom.events.EventListener;
|
||||||
|
import org.teavm.jso.indexeddb.EventHandler;
|
||||||
|
import org.teavm.jso.indexeddb.IDBCountRequest;
|
||||||
|
import org.teavm.jso.indexeddb.IDBCursor;
|
||||||
|
import org.teavm.jso.indexeddb.IDBCursorRequest;
|
||||||
|
import org.teavm.jso.indexeddb.IDBDatabase;
|
||||||
|
import org.teavm.jso.indexeddb.IDBFactory;
|
||||||
|
import org.teavm.jso.indexeddb.IDBGetRequest;
|
||||||
|
import org.teavm.jso.indexeddb.IDBObjectStoreParameters;
|
||||||
|
import org.teavm.jso.indexeddb.IDBOpenDBRequest;
|
||||||
|
import org.teavm.jso.indexeddb.IDBRequest;
|
||||||
|
import org.teavm.jso.indexeddb.IDBTransaction;
|
||||||
|
import org.teavm.jso.indexeddb.IDBVersionChangeEvent;
|
||||||
|
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||||
|
import org.teavm.jso.typedarrays.Int8Array;
|
||||||
|
|
||||||
|
public class VirtualFilesystem {
|
||||||
|
|
||||||
|
protected static class VirtualOutputStream extends ByteArrayOutputStream {
|
||||||
|
private final VFSFile file;
|
||||||
|
|
||||||
|
protected VirtualOutputStream(VFSFile file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
if(!file.setAllBytes(super.toByteArray(), false)) {
|
||||||
|
throw new IOException("Could not close stream and write to \"" + file.filePath + "\" on VFS \"" + file.virtualFilesystem.database + "\" (the file was probably deleted)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class VFSFile {
|
||||||
|
|
||||||
|
public final VirtualFilesystem virtualFilesystem;
|
||||||
|
protected boolean cacheEnabled;
|
||||||
|
protected String filePath;
|
||||||
|
protected int fileSize = -1;
|
||||||
|
protected boolean hasBeenDeleted = false;
|
||||||
|
protected boolean hasBeenAccessed = false;
|
||||||
|
protected boolean exists = false;
|
||||||
|
|
||||||
|
protected byte[] cache = null;
|
||||||
|
protected long cacheHit;
|
||||||
|
|
||||||
|
protected VFSFile(VirtualFilesystem vfs, String filePath, boolean cacheEnabled) {
|
||||||
|
this.virtualFilesystem = vfs;
|
||||||
|
this.filePath = filePath;
|
||||||
|
this.cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
if(cacheEnabled) {
|
||||||
|
setCacheEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof VFSFile) && ((VFSFile)o).filePath.equals(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return filePath.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
if(fileSize < 0) {
|
||||||
|
if(cacheEnabled) {
|
||||||
|
byte[] b = getAllBytes(false);
|
||||||
|
if(b != null) {
|
||||||
|
fileSize = b.length;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
ArrayBuffer dat = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||||
|
if(dat != null) {
|
||||||
|
fileSize = dat.getByteLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
byte[] dat = getAllBytes(false);
|
||||||
|
if(dat == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ByteArrayInputStream(dat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
return new VirtualOutputStream(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getBytes(int fileOffset, byte[] array, int offset, int length) {
|
||||||
|
if(hasBeenDeleted) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' has been deleted");
|
||||||
|
}else if(hasBeenAccessed && !exists) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' does not exist");
|
||||||
|
}
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
if(cacheEnabled && cache != null) {
|
||||||
|
System.arraycopy(cache, fileOffset, array, offset, length);
|
||||||
|
}else {
|
||||||
|
ArrayBuffer aa = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
if(aa != null) {
|
||||||
|
exists = true;
|
||||||
|
}else {
|
||||||
|
exists = false;
|
||||||
|
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' does not exist");
|
||||||
|
}
|
||||||
|
this.fileSize = aa.getByteLength();
|
||||||
|
if(cacheEnabled) {
|
||||||
|
cache = TeaVMUtils.wrapByteArrayBuffer(aa);
|
||||||
|
}
|
||||||
|
if(fileSize < fileOffset + length) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' size was "+fileSize+" but user tried to read index "+(fileOffset + length - 1));
|
||||||
|
}
|
||||||
|
TeaVMUtils.unwrapByteArray(array).set(new Int8Array(aa, fileOffset, length), offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheEnabled() {
|
||||||
|
if(!cacheEnabled && !hasBeenDeleted && !(hasBeenAccessed && !exists)) {
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
cache = getAllBytes(false);
|
||||||
|
cacheEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getAllBytes() {
|
||||||
|
return getAllBytes(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAllChars() {
|
||||||
|
return utf8(getAllBytes(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAllLines() {
|
||||||
|
return lines(getAllChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getAllBytes(boolean copy) {
|
||||||
|
if(hasBeenDeleted || (hasBeenAccessed && !exists)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
if(cacheEnabled && cache != null) {
|
||||||
|
byte[] b = cache;
|
||||||
|
if(copy) {
|
||||||
|
b = new byte[cache.length];
|
||||||
|
System.arraycopy(cache, 0, b, 0, cache.length);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}else {
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
ArrayBuffer b = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||||
|
if(b != null) {
|
||||||
|
exists = true;
|
||||||
|
}else {
|
||||||
|
exists = false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this.fileSize = b.getByteLength();
|
||||||
|
if(cacheEnabled) {
|
||||||
|
if(copy) {
|
||||||
|
cache = new byte[fileSize];
|
||||||
|
TeaVMUtils.unwrapByteArray(cache).set(new Int8Array(b));
|
||||||
|
}else {
|
||||||
|
cache = TeaVMUtils.wrapByteArrayBuffer(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TeaVMUtils.wrapByteArrayBuffer(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllChars(String bytes) {
|
||||||
|
return setAllBytes(utf8(bytes), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllBytes(byte[] bytes) {
|
||||||
|
return setAllBytes(bytes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setAllBytes(byte[] bytes, boolean copy) {
|
||||||
|
if(hasBeenDeleted || bytes == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
this.fileSize = bytes.length;
|
||||||
|
if(cacheEnabled) {
|
||||||
|
byte[] copz = bytes;
|
||||||
|
if(copy) {
|
||||||
|
copz = new byte[bytes.length];
|
||||||
|
System.arraycopy(bytes, 0, copz, 0, bytes.length);
|
||||||
|
}
|
||||||
|
cache = copz;
|
||||||
|
return sync();
|
||||||
|
}else {
|
||||||
|
boolean s = AsyncHandlers.writeWholeFile(virtualFilesystem.indexeddb, filePath,
|
||||||
|
TeaVMUtils.unwrapArrayBuffer(bytes)).bool;
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
exists = exists || s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean sync() {
|
||||||
|
if(cacheEnabled && cache != null && !hasBeenDeleted) {
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
boolean tryWrite = AsyncHandlers.writeWholeFile(virtualFilesystem.indexeddb, filePath,
|
||||||
|
TeaVMUtils.unwrapArrayBuffer(cache)).bool;
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
exists = exists || tryWrite;
|
||||||
|
return tryWrite;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete() {
|
||||||
|
if(!hasBeenDeleted && !(hasBeenAccessed && !exists)) {
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
if(!AsyncHandlers.deleteFile(virtualFilesystem.indexeddb, filePath).bool) {
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtualFilesystem.fileMap.remove(filePath);
|
||||||
|
hasBeenDeleted = true;
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
exists = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean rename(String newName, boolean copy) {
|
||||||
|
if(!hasBeenDeleted && !(hasBeenAccessed && !exists)) {
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
ArrayBuffer arr = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
if(arr != null) {
|
||||||
|
exists = true;
|
||||||
|
if(!AsyncHandlers.writeWholeFile(virtualFilesystem.indexeddb, newName, arr).bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!copy && !AsyncHandlers.deleteFile(virtualFilesystem.indexeddb, filePath).bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
exists = false;
|
||||||
|
}
|
||||||
|
if(!copy) {
|
||||||
|
virtualFilesystem.fileMap.remove(filePath);
|
||||||
|
filePath = newName;
|
||||||
|
virtualFilesystem.fileMap.put(newName, this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
if(hasBeenDeleted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cacheHit = EaglerAdapter.steadyTimeMillis();
|
||||||
|
if(hasBeenAccessed) {
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
exists = AsyncHandlers.fileExists(virtualFilesystem.indexeddb, filePath).bool;
|
||||||
|
hasBeenAccessed = true;
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final HashMap<String, VFSFile> fileMap = new HashMap<>();
|
||||||
|
|
||||||
|
public final String database;
|
||||||
|
private final IDBDatabase indexeddb;
|
||||||
|
|
||||||
|
public static class VFSHandle {
|
||||||
|
|
||||||
|
public final boolean failedInit;
|
||||||
|
public final boolean failedLocked;
|
||||||
|
public final String failedError;
|
||||||
|
public final VirtualFilesystem vfs;
|
||||||
|
|
||||||
|
public VFSHandle(boolean init, boolean locked, String error, VirtualFilesystem db) {
|
||||||
|
failedInit = init;
|
||||||
|
failedLocked = locked;
|
||||||
|
failedError = error;
|
||||||
|
vfs = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
if(failedInit) {
|
||||||
|
return "IDBFactory threw an exception, IndexedDB is most likely not supported in this browser." + (failedError == null ? "" : "\n\n" + failedError);
|
||||||
|
}
|
||||||
|
if(failedLocked) {
|
||||||
|
return "The filesystem requested is already in use on a different tab.";
|
||||||
|
}
|
||||||
|
if(failedError != null) {
|
||||||
|
return "The IDBFactory.open() request failed, reason: " + failedError;
|
||||||
|
}
|
||||||
|
return "Virtual Filesystem Object: " + vfs.database;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VFSHandle openVFS(String db) {
|
||||||
|
DatabaseOpen evt = AsyncHandlers.openDB(db);
|
||||||
|
if(evt.failedInit) {
|
||||||
|
return new VFSHandle(true, false, evt.failedError, null);
|
||||||
|
}
|
||||||
|
if(evt.failedLocked) {
|
||||||
|
return new VFSHandle(false, true, null, null);
|
||||||
|
}
|
||||||
|
if(evt.failedError != null) {
|
||||||
|
return new VFSHandle(false, false, evt.failedError, null);
|
||||||
|
}
|
||||||
|
return new VFSHandle(false, false, null, new VirtualFilesystem(db, evt.database));
|
||||||
|
}
|
||||||
|
|
||||||
|
private VirtualFilesystem(String db, IDBDatabase idb) {
|
||||||
|
database = db;
|
||||||
|
indexeddb = idb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
indexeddb.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VFSFile getFile(String path) {
|
||||||
|
return getFile(path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VFSFile getFile(String path, boolean cache) {
|
||||||
|
VFSFile f = fileMap.get(path);
|
||||||
|
if(f == null) {
|
||||||
|
fileMap.put(path, f = new VFSFile(this, path, cache));
|
||||||
|
}else {
|
||||||
|
if(cache) {
|
||||||
|
f.setCacheEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean renameFile(String oldName, String newName, boolean copy) {
|
||||||
|
return getFile(oldName).rename(newName, copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteFile(String path) {
|
||||||
|
return getFile(path).delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean fileExists(String path) {
|
||||||
|
return getFile(path).exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> listFiles(String prefix) {
|
||||||
|
final ArrayList<String> list = new ArrayList<>();
|
||||||
|
AsyncHandlers.iterateFiles(indexeddb, this, prefix, false, (v) -> {
|
||||||
|
list.add(v.getPath());
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteFiles(String prefix) {
|
||||||
|
return AsyncHandlers.deleteFiles(indexeddb, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int iterateFiles(String prefix, boolean rw, VFSIterator itr) {
|
||||||
|
return AsyncHandlers.iterateFiles(indexeddb, this, prefix, rw, itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int renameFiles(String oldPrefix, String newPrefix, boolean copy) {
|
||||||
|
List<String> filesToCopy = listFiles(oldPrefix);
|
||||||
|
int i = 0;
|
||||||
|
for(String str : filesToCopy) {
|
||||||
|
String f = VFile.createPath(newPrefix, str.substring(oldPrefix.length()));
|
||||||
|
if(!renameFile(str, f, copy)) {
|
||||||
|
System.err.println("Could not " + (copy ? "copy" : "rename") + " file \"" + str + "\" to \"" + f + "\" for some reason");
|
||||||
|
}else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flushCache(long age) {
|
||||||
|
long curr = EaglerAdapter.steadyTimeMillis();
|
||||||
|
Iterator<VFSFile> files = fileMap.values().iterator();
|
||||||
|
while(files.hasNext()) {
|
||||||
|
if(curr - files.next().cacheHit > age) {
|
||||||
|
files.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class DatabaseOpen {
|
||||||
|
|
||||||
|
protected final boolean failedInit;
|
||||||
|
protected final boolean failedLocked;
|
||||||
|
protected final String failedError;
|
||||||
|
|
||||||
|
protected final IDBDatabase database;
|
||||||
|
|
||||||
|
protected DatabaseOpen(boolean init, boolean locked, String error, IDBDatabase db) {
|
||||||
|
failedInit = init;
|
||||||
|
failedLocked = locked;
|
||||||
|
failedError = error;
|
||||||
|
database = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(script = "return ((typeof indexedDB) !== 'undefined') ? indexedDB : null;")
|
||||||
|
protected static native IDBFactory createIDBFactory();
|
||||||
|
|
||||||
|
protected static class AsyncHandlers {
|
||||||
|
|
||||||
|
@Async
|
||||||
|
protected static native DatabaseOpen openDB(String name);
|
||||||
|
|
||||||
|
private static void openDB(String name, final AsyncCallback<DatabaseOpen> cb) {
|
||||||
|
IDBFactory i = createIDBFactory();
|
||||||
|
if(i == null) {
|
||||||
|
cb.complete(new DatabaseOpen(false, false, "window.indexedDB was null or undefined", null));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final IDBOpenDBRequest f = i.open(name, 1);
|
||||||
|
f.setOnBlocked(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(new DatabaseOpen(false, true, null, null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.setOnSuccess(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(new DatabaseOpen(false, false, null, f.getResult()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.setOnError(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(new DatabaseOpen(false, false, "open error", null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.setOnUpgradeNeeded(new EventListener<IDBVersionChangeEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(IDBVersionChangeEvent evt) {
|
||||||
|
f.getResult().createObjectStore("filesystem", IDBObjectStoreParameters.create().keyPath("path"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
protected static native BooleanResult deleteFile(IDBDatabase db, String name);
|
||||||
|
|
||||||
|
private static void deleteFile(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
|
||||||
|
IDBTransaction tx = db.transaction("filesystem", "readwrite");
|
||||||
|
final IDBRequest r = tx.objectStore("filesystem").delete(makeTheFuckingKeyWork(name));
|
||||||
|
|
||||||
|
r.setOnSuccess(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(BooleanResult._new(true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.setOnError(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(BooleanResult._new(false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(params = { "obj" }, script = "return (typeof obj === 'undefined') ? null : ((typeof obj.data === 'undefined') ? null : obj.data);")
|
||||||
|
protected static native ArrayBuffer readRow(JSObject obj);
|
||||||
|
|
||||||
|
@JSBody(params = { "obj" }, script = "return [obj];")
|
||||||
|
private static native JSObject makeTheFuckingKeyWork(String k);
|
||||||
|
|
||||||
|
@Async
|
||||||
|
protected static native ArrayBuffer readWholeFile(IDBDatabase db, String name);
|
||||||
|
|
||||||
|
private static void readWholeFile(IDBDatabase db, String name, final AsyncCallback<ArrayBuffer> cb) {
|
||||||
|
IDBTransaction tx = db.transaction("filesystem", "readonly");
|
||||||
|
final IDBGetRequest r = tx.objectStore("filesystem").get(makeTheFuckingKeyWork(name));
|
||||||
|
r.setOnSuccess(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(readRow(r.getResult()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.setOnError(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(params = { "k" }, script = "return ((typeof k) === \"string\") ? k : (((typeof k) === \"undefined\") ? null : (((typeof k[0]) === \"string\") ? k[0] : null));")
|
||||||
|
private static native String readKey(JSObject k);
|
||||||
|
|
||||||
|
@JSBody(params = { "k" }, script = "return ((typeof k) === \"undefined\") ? null : (((typeof k.path) === \"undefined\") ? null : (((typeof k.path) === \"string\") ? k[0] : null));")
|
||||||
|
private static native String readRowKey(JSObject r);
|
||||||
|
|
||||||
|
@Async
|
||||||
|
protected static native Integer iterateFiles(IDBDatabase db, final VirtualFilesystem vfs, final String prefix, boolean rw, final VFSIterator itr);
|
||||||
|
|
||||||
|
private static void iterateFiles(IDBDatabase db, final VirtualFilesystem vfs, final String prefix, boolean rw, final VFSIterator itr, final AsyncCallback<Integer> cb) {
|
||||||
|
IDBTransaction tx = db.transaction("filesystem", rw ? "readwrite" : "readonly");
|
||||||
|
final IDBCursorRequest r = tx.objectStore("filesystem").openCursor();
|
||||||
|
final int[] res = new int[1];
|
||||||
|
r.setOnSuccess(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
IDBCursor c = r.getResult();
|
||||||
|
if(c == null || c.getKey() == null || c.getValue() == null) {
|
||||||
|
cb.complete(res[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String k = readKey(c.getKey());
|
||||||
|
if(k != null) {
|
||||||
|
if(k.startsWith(prefix)) {
|
||||||
|
int ci = res[0]++;
|
||||||
|
try {
|
||||||
|
itr.next(VIteratorFile.create(ci, vfs, c));
|
||||||
|
}catch(VFSIterator.BreakLoop ex) {
|
||||||
|
cb.complete(res[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.doContinue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.setOnError(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(res[0] > 0 ? res[0] : -1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
protected static native Integer deleteFiles(IDBDatabase db, final String prefix);
|
||||||
|
|
||||||
|
private static void deleteFiles(IDBDatabase db, final String prefix, final AsyncCallback<Integer> cb) {
|
||||||
|
IDBTransaction tx = db.transaction("filesystem", "readwrite");
|
||||||
|
final IDBCursorRequest r = tx.objectStore("filesystem").openCursor();
|
||||||
|
final int[] res = new int[1];
|
||||||
|
r.setOnSuccess(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
IDBCursor c = r.getResult();
|
||||||
|
if(c == null || c.getKey() == null || c.getValue() == null) {
|
||||||
|
cb.complete(res[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String k = readKey(c.getKey());
|
||||||
|
if(k != null) {
|
||||||
|
if(k.startsWith(prefix)) {
|
||||||
|
c.delete();
|
||||||
|
++res[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.doContinue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.setOnError(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(res[0] > 0 ? res[0] : -1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
protected static native BooleanResult fileExists(IDBDatabase db, String name);
|
||||||
|
|
||||||
|
private static void fileExists(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
|
||||||
|
IDBTransaction tx = db.transaction("filesystem", "readonly");
|
||||||
|
final IDBCountRequest r = tx.objectStore("filesystem").count(makeTheFuckingKeyWork(name));
|
||||||
|
r.setOnSuccess(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(BooleanResult._new(r.getResult() > 0));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.setOnError(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(BooleanResult._new(false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(params = { "pat", "dat" }, script = "return { path: pat, data: dat };")
|
||||||
|
protected static native JSObject writeRow(String name, ArrayBuffer data);
|
||||||
|
|
||||||
|
@Async
|
||||||
|
protected static native BooleanResult writeWholeFile(IDBDatabase db, String name, ArrayBuffer data);
|
||||||
|
|
||||||
|
private static void writeWholeFile(IDBDatabase db, String name, ArrayBuffer data, final AsyncCallback<BooleanResult> cb) {
|
||||||
|
IDBTransaction tx = db.transaction("filesystem", "readwrite");
|
||||||
|
final IDBRequest r = tx.objectStore("filesystem").put(writeRow(name, data));
|
||||||
|
|
||||||
|
r.setOnSuccess(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(BooleanResult._new(true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.setOnError(new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent() {
|
||||||
|
cb.complete(BooleanResult._new(false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] utf8(String str) {
|
||||||
|
if(str == null) return null;
|
||||||
|
return str.getBytes(Charset.forName("UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String utf8(byte[] str) {
|
||||||
|
if(str == null) return null;
|
||||||
|
return new String(str, Charset.forName("UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String CRLFtoLF(String str) {
|
||||||
|
if(str == null) return null;
|
||||||
|
str = str.indexOf('\r') != -1 ? str.replace("\r", "") : str;
|
||||||
|
str = str.trim();
|
||||||
|
if(str.endsWith("\n")) {
|
||||||
|
str = str.substring(0, str.length() - 1);
|
||||||
|
}
|
||||||
|
if(str.startsWith("\n")) {
|
||||||
|
str = str.substring(1);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] lines(String str) {
|
||||||
|
if(str == null) return null;
|
||||||
|
return CRLFtoLF(str).split("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user