From 59afcce512f06b4cbb660c1125b7bc93cdac60cd Mon Sep 17 00:00:00 2001 From: sk89q Date: Fri, 31 Dec 2010 01:18:08 -0800 Subject: [PATCH] Worked around some ZIP-related bugs. --- .../data/TrueZipAlphaChunkStore.java | 29 ++- .../data/TrueZipLegacyAlphaChunkStore.java | 166 ++++++++++++++++++ .../worldedit/data/ZippedAlphaChunkStore.java | 23 ++- .../sk89q/worldedit/snapshots/Snapshot.java | 2 +- 4 files changed, 201 insertions(+), 19 deletions(-) create mode 100644 src/com/sk89q/worldedit/data/TrueZipLegacyAlphaChunkStore.java diff --git a/src/com/sk89q/worldedit/data/TrueZipAlphaChunkStore.java b/src/com/sk89q/worldedit/data/TrueZipAlphaChunkStore.java index 8452b6e0b..326cb3a8d 100644 --- a/src/com/sk89q/worldedit/data/TrueZipAlphaChunkStore.java +++ b/src/com/sk89q/worldedit/data/TrueZipAlphaChunkStore.java @@ -23,9 +23,11 @@ import de.schlichtherle.io.*; import de.schlichtherle.io.File; import de.schlichtherle.io.FileInputStream; import java.io.*; +import java.util.regex.Pattern; /** - * Represents the chunk store used by Minecraft alpha. + * Represents the chunk store used by Minecraft alpha. This driver uses + * TrueZip to read zip files, althoguh it currently does not work well. * * @author sk89q */ @@ -90,8 +92,9 @@ public class TrueZipAlphaChunkStore extends NestedFileChunkStore { protected InputStream getInputStream(String f1, String f2, String name) throws DataException, IOException { String file = f1 + File.separator + f2 + File.separator + name; + File f = new File(path, file); try { - return new FileInputStream(new File(path.getAbsolutePath(), file)); + return new FileInputStream(f.getAbsolutePath()); } catch (FileNotFoundException e) { throw new MissingChunkException(); } @@ -104,8 +107,10 @@ public class TrueZipAlphaChunkStore extends NestedFileChunkStore { * @return */ private File findWorldPath(File path) { - if ((new File(path, "world")).exists()) { - return new File(path, "world"); + File f = new File(path, "world"); + + if (path.contains(f)) { + return f; } return searchForPath(path); @@ -119,21 +124,15 @@ public class TrueZipAlphaChunkStore extends NestedFileChunkStore { */ private File searchForPath(File path) { String[] children = path.list(); - // listFiles() returns java.io.File[] + + Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$"); if (children == null) { return null; } else { - for (String child : children) { - File f = new File(path, child); - - if (f.isFile() && f.getName().equals("level.dat")) { - return path; - } else if (f.isDirectory()) { - File res = findWorldPath(f); - if (res != null) { - return res; - } + for (String f : children) { + if (pattern.matcher(f).matches()) { + return (File)(new File(path, f)).getParentFile(); } } } diff --git a/src/com/sk89q/worldedit/data/TrueZipLegacyAlphaChunkStore.java b/src/com/sk89q/worldedit/data/TrueZipLegacyAlphaChunkStore.java new file mode 100644 index 000000000..cc8b28459 --- /dev/null +++ b/src/com/sk89q/worldedit/data/TrueZipLegacyAlphaChunkStore.java @@ -0,0 +1,166 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.data; + +import java.io.*; +import java.util.regex.Pattern; +import java.util.zip.ZipException; +import java.util.Enumeration; +import de.schlichtherle.util.zip.*; + +/** + * Represents the chunk store used by Minecraft alpha but zipped. Uses + * the replacement classes for java.util.zip.* from TrueZip. + * + * @author sk89q + */ +public class TrueZipLegacyAlphaChunkStore extends NestedFileChunkStore { + /** + * ZIP file. + */ + @SuppressWarnings("unused") + private File zipFile; + /** + * Actual ZIP. + */ + private ZipFile zip; + /** + * Folder inside the ZIP file to read from, if any. + */ + private String folder; + + /** + * Create an instance. The folder argument lets you choose a folder or + * path to look into in the ZIP for the files. Use a blank string for + * the folder to not look into a subdirectory. + * + * @param zipFile + * @param folder + * @throws IOException + * @throws ZIPException + */ + public TrueZipLegacyAlphaChunkStore(File zipFile, String folder) + throws IOException, ZipException { + this.zipFile = zipFile; + this.folder = folder; + + zip = new ZipFile(zipFile); + } + + /** + * Create an instance. The subfolder containing the chunk data will + * be detected. + * + * @param zipFile + * @param folder + * @throws IOException + * @throws ZIPException + */ + public TrueZipLegacyAlphaChunkStore(File zipFile) + throws IOException, ZipException { + this.zipFile = zipFile; + + zip = new ZipFile(zipFile); + } + + /** + * Get the input stream for a chunk file. + * + * @param f1 + * @param f2 + * @param name + * @return + * @throws IOException + * @throws DataException + */ + @SuppressWarnings("unchecked") + protected InputStream getInputStream(String f1, String f2, String name) + throws IOException, DataException { + String file = f1 + "/" + f2 + "/" + name; + + // Detect subfolder for the world's files + if (folder != null) { + if (!folder.equals("")) { + file = folder + "/" + file; + } + } else { + ZipEntry testEntry = zip.getEntry("level.dat"); + + // So, the data is not in the root directory + if (testEntry == null) { + // Let's try a world/ sub-directory + testEntry = getEntry("world/level.dat"); + + Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$"); + + // So not there either... + if (testEntry == null) { + for (Enumeration e = zip.entries(); + e.hasMoreElements(); ) { + + testEntry = (ZipEntry)e.nextElement(); + + // Whoo, found level.dat! + if (pattern.matcher(testEntry.getName()).matches()) { + file = testEntry.getName().replaceAll("level\\.dat$", "") + + file; + break; + } + } + } else { + file = "world/" + file; + } + } + } + + ZipEntry entry = getEntry(file); + if (entry == null) { + throw new MissingChunkException(); + } + try { + return zip.getInputStream(entry); + } catch (ZipException e) { + throw new IOException("Failed to read " + file + " in ZIP"); + } + } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file + * @return + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } + + /** + * Close resources. + * + * @throws IOException + */ + public void close() throws IOException { + zip.close(); + } +} diff --git a/src/com/sk89q/worldedit/data/ZippedAlphaChunkStore.java b/src/com/sk89q/worldedit/data/ZippedAlphaChunkStore.java index 7e08d3c97..d8c0b7024 100644 --- a/src/com/sk89q/worldedit/data/ZippedAlphaChunkStore.java +++ b/src/com/sk89q/worldedit/data/ZippedAlphaChunkStore.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.data; import java.io.*; +import java.util.regex.Pattern; import java.util.zip.*; import java.util.Enumeration; @@ -102,7 +103,9 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore { // So, the data is not in the root directory if (testEntry == null) { // Let's try a world/ sub-directory - testEntry = zip.getEntry("world/level.dat"); + testEntry = getEntry("world/level.dat"); + + Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$"); // So not there either... if (testEntry == null) { @@ -112,7 +115,7 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore { testEntry = (ZipEntry)e.nextElement(); // Whoo, found level.dat! - if (testEntry.getName().matches(".+/level\\.dat")) { + if (pattern.matcher(testEntry.getName()).matches()) { file = testEntry.getName().replaceAll("level\\.dat$", "") + file; break; @@ -124,7 +127,7 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore { } } - ZipEntry entry = zip.getEntry(file); + ZipEntry entry = getEntry(file); if (entry == null) { throw new MissingChunkException(); } @@ -134,6 +137,20 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore { throw new IOException("Failed to read " + file + " in ZIP"); } } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file + * @return + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } /** * Close resources. diff --git a/src/com/sk89q/worldedit/snapshots/Snapshot.java b/src/com/sk89q/worldedit/snapshots/Snapshot.java index 1eae74883..976b7048a 100644 --- a/src/com/sk89q/worldedit/snapshots/Snapshot.java +++ b/src/com/sk89q/worldedit/snapshots/Snapshot.java @@ -57,7 +57,7 @@ public class Snapshot { public ChunkStore getChunkStore() throws IOException, DataException { if (file.getName().toLowerCase().endsWith(".zip")) { try { - return new TrueZipAlphaChunkStore(file); + return new TrueZipLegacyAlphaChunkStore(file); } catch (NoClassDefFoundError e) { return new ZippedAlphaChunkStore(file); }