Worked around some ZIP-related bugs.

This commit is contained in:
sk89q 2010-12-31 01:18:08 -08:00
parent 98de15fb4e
commit 59afcce512
4 changed files with 201 additions and 19 deletions

View File

@ -23,9 +23,11 @@ import de.schlichtherle.io.*;
import de.schlichtherle.io.File; import de.schlichtherle.io.File;
import de.schlichtherle.io.FileInputStream; import de.schlichtherle.io.FileInputStream;
import java.io.*; 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 * @author sk89q
*/ */
@ -90,8 +92,9 @@ public class TrueZipAlphaChunkStore extends NestedFileChunkStore {
protected InputStream getInputStream(String f1, String f2, String name) protected InputStream getInputStream(String f1, String f2, String name)
throws DataException, IOException { throws DataException, IOException {
String file = f1 + File.separator + f2 + File.separator + name; String file = f1 + File.separator + f2 + File.separator + name;
File f = new File(path, file);
try { try {
return new FileInputStream(new File(path.getAbsolutePath(), file)); return new FileInputStream(f.getAbsolutePath());
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
throw new MissingChunkException(); throw new MissingChunkException();
} }
@ -104,8 +107,10 @@ public class TrueZipAlphaChunkStore extends NestedFileChunkStore {
* @return * @return
*/ */
private File findWorldPath(File path) { private File findWorldPath(File path) {
if ((new File(path, "world")).exists()) { File f = new File(path, "world");
return new File(path, "world");
if (path.contains(f)) {
return f;
} }
return searchForPath(path); return searchForPath(path);
@ -119,21 +124,15 @@ public class TrueZipAlphaChunkStore extends NestedFileChunkStore {
*/ */
private File searchForPath(File path) { private File searchForPath(File path) {
String[] children = path.list(); String[] children = path.list();
// listFiles() returns java.io.File[]
Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$");
if (children == null) { if (children == null) {
return null; return null;
} else { } else {
for (String child : children) { for (String f : children) {
File f = new File(path, child); if (pattern.matcher(f).matches()) {
return (File)(new File(path, f)).getParentFile();
if (f.isFile() && f.getName().equals("level.dat")) {
return path;
} else if (f.isDirectory()) {
File res = findWorldPath(f);
if (res != null) {
return res;
}
} }
} }
} }

View File

@ -0,0 +1,166 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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<? extends ZipEntry> 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();
}
}

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.data; package com.sk89q.worldedit.data;
import java.io.*; import java.io.*;
import java.util.regex.Pattern;
import java.util.zip.*; import java.util.zip.*;
import java.util.Enumeration; import java.util.Enumeration;
@ -102,7 +103,9 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore {
// So, the data is not in the root directory // So, the data is not in the root directory
if (testEntry == null) { if (testEntry == null) {
// Let's try a world/ sub-directory // 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... // So not there either...
if (testEntry == null) { if (testEntry == null) {
@ -112,7 +115,7 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore {
testEntry = (ZipEntry)e.nextElement(); testEntry = (ZipEntry)e.nextElement();
// Whoo, found level.dat! // Whoo, found level.dat!
if (testEntry.getName().matches(".+/level\\.dat")) { if (pattern.matcher(testEntry.getName()).matches()) {
file = testEntry.getName().replaceAll("level\\.dat$", "") file = testEntry.getName().replaceAll("level\\.dat$", "")
+ file; + file;
break; break;
@ -124,7 +127,7 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore {
} }
} }
ZipEntry entry = zip.getEntry(file); ZipEntry entry = getEntry(file);
if (entry == null) { if (entry == null) {
throw new MissingChunkException(); throw new MissingChunkException();
} }
@ -135,6 +138,20 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore {
} }
} }
/**
* 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. * Close resources.
* *

View File

@ -57,7 +57,7 @@ public class Snapshot {
public ChunkStore getChunkStore() throws IOException, DataException { public ChunkStore getChunkStore() throws IOException, DataException {
if (file.getName().toLowerCase().endsWith(".zip")) { if (file.getName().toLowerCase().endsWith(".zip")) {
try { try {
return new TrueZipAlphaChunkStore(file); return new TrueZipLegacyAlphaChunkStore(file);
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
return new ZippedAlphaChunkStore(file); return new ZippedAlphaChunkStore(file);
} }