Changes to make Checksum work reliably, changed CRC quite a bit to simplify it and support .jar.gz, and added MakeTorrent.

This commit is contained in:
Travis Burtrum 2012-01-05 22:47:38 -05:00 committed by moparisthebest
parent 9ac9b3a6a4
commit ccca912418
5 changed files with 339 additions and 42 deletions

View File

@ -20,17 +20,13 @@
package org.moparscape.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.moparscape.res.impl.Downloader;
import java.io.*;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.CRC32;
import java.util.zip.*;
/**
* This is a class loader that loads classes from jars on the filesystem, optionally checking the CRC of the classes and
@ -109,7 +105,7 @@ public class CRCClassLoader extends ClassLoader {
//new Update(backupURL, jarFileLoc, true);
// use ResourceGrabber
int jarWait = org.moparscape.res.ResourceGrabber.getRG().download(backupURL, jarFileLoc);
if(org.moparscape.res.ResourceGrabber.getRG().waitCatch(jarWait)){
if (org.moparscape.res.ResourceGrabber.getRG().waitCatch(jarWait)) {
jarFileLoc = org.moparscape.res.ResourceGrabber.getRG().firstFileEndsWithIgnoreCase(jarWait, "jar");
org.moparscape.res.ResourceGrabber.getRG().freeResources(jarWait);
}
@ -142,9 +138,6 @@ public class CRCClassLoader extends ClassLoader {
return;
}
JarFile jf = new JarFile(f);
Enumeration entries = jf.entries();
if (updateCRC)
classes = new HashMap<String, byte[]>();
@ -153,33 +146,36 @@ public class CRCClassLoader extends ClassLoader {
crcVal = 0;
crc = new CRC32();
}
byte[] buffer = new byte[1024];
/*
JarFile jf = new JarFile(f);
Enumeration entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry entry = (JarEntry) entries.nextElement();
*/
InputStream is = new FileInputStream(f);
if (jarFileLoc.toLowerCase().endsWith(".gz"))
is = new GZIPInputStream(is);
ZipInputStream in = new ZipInputStream(is);
ZipEntry entry;
while ((entry = in.getNextEntry()) != null) {
if (entry.getName().endsWith(".class")) {
InputStream in = jf.getInputStream(entry);
//InputStream in = jf.getInputStream(entry);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
while ((len = in.read(buffer)) >= 0)
baos.write(buffer, 0, len);
baos.flush();
in.close();
baos.close();
// update crc
byte[] classArr = baos.toByteArray();
OutputStream out = baos;
if (updateCRC)
crc.update(classArr);
//in = new CheckedInputStream(in, crc);
out = new CheckedOutputStream(out, crc);
Downloader.writeStream(in, out);
String className = entry.getName().substring(0, entry.getName().lastIndexOf(".")).replaceAll("/", ".");
//if (updateCRC) System.out.println("class name: " + className);
// save class
classes.put(className, classArr);
classes.put(className, baos.toByteArray());
}
}
jf.close();
//jf.close();
in.close();
if (updateCRC)
crcVal = crc.getValue();

View File

@ -23,7 +23,9 @@ package org.moparscape.res;
import org.moparscape.res.impl.Downloader;
import java.io.*;
import java.util.Arrays;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
import java.util.zip.Checksum;
/**
@ -131,7 +133,8 @@ public class ChecksumInfo {
cs.reset();
checksumCalculated = true;
try {
Downloader.writeStream(new ChecksumInputStream(is, cs), os == null ? new NullOutputStream() : os);
//Downloader.writeStream(new ChecksumInputStream(is, cs), os == null ? new NullOutputStream() : os);
Downloader.writeStream(new CheckedInputStream(is, cs), os == null ? new NullOutputStream() : os);
} catch (Exception e) {
// if there is an exception, just ignore it
}
@ -143,15 +146,19 @@ public class ChecksumInfo {
return;
if (path.isFile()) {
try {
Downloader.writeStream(new ChecksumInputStream(new FileInputStream(path), cs), nos);
//Downloader.writeStream(new ChecksumInputStream(new FileInputStream(path), cs), nos);
Downloader.writeStream(new CheckedInputStream(new FileInputStream(path), cs), nos);
} catch (Exception e) {
// if there is an exception, just ignore it
}
return;
}
for (File file : path.listFiles(filter)) {
System.out.println("Checksum so far: " + cs.getValue());
System.out.println("Checking filename: " + file.getAbsolutePath());
File[] children = path.listFiles(filter);
// checksums depend on order, so we must sort them
Arrays.sort(children);
for (File file : children) {
//System.out.println("Checksum so far: " + cs.getValue());
//System.out.println("Checking filename: " + file.getAbsolutePath());
recursiveChecksum(file, cs, nos, filter);
}

View File

@ -0,0 +1,239 @@
package org.moparscape.res;
/*
* Copyright (C) 2012 moparisthebest
*
* 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/>.
*
* Official forums are http://www.moparscape.org/smf/
* Email me at admin@moparisthebest.com , I read it but don't usually respond.
*/
import org.moparscape.Debug;
import org.moparscape.classloader.CRCClassLoader;
import org.moparscape.res.impl.Downloader;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class MakeTorrent {
private long crc = 0;
private File torrentFile = null;
private File sharedFile = null;
private String infoHash = null;
public static MakeTorrent askForFile(Component parent) {
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
if (fc.showOpenDialog(parent) != JFileChooser.APPROVE_OPTION) {
System.out.println("Open command cancelled by user.");
return null;
}
return new MakeTorrent(fc.getSelectedFile());
}
public MakeTorrent(String sharedFile) {
this(new File(sharedFile));
}
public MakeTorrent(File sharedFile) {
this(sharedFile, "udp://tracker.moparisthebest.com:2710/announce", "http://tracker.moparisthebest.com/announce");
}
public MakeTorrent(File sharedFile, String... announceURL) {
this.sharedFile = sharedFile;
String absolutePath = sharedFile.getAbsolutePath();
System.out.println("Creating torrent from: " + absolutePath);
torrentFile = new File(absolutePath + ".torrent");
try {
this.createTorrent(announceURL);
} catch (Exception e) {
System.out.println("Creating torrent failed: " + e.getMessage());
Debug.debug(e);
return;
}
// now calculate and print info about the torrent, like the CRC
try {
if (absolutePath.toLowerCase().endsWith(".jar") || absolutePath.toLowerCase().endsWith(".jar.gz")) {
System.out.println("Detected jar file, calculating CRC with CRCClassLoader");
crc = new CRCClassLoader(absolutePath).getCRC();
} else if (Downloader.supportsExtraction(absolutePath)) {
System.out.println("Detected file to extract, calculating CRC of extracted files only.");
crc = Downloader.crcExtractFile(absolutePath);
// debugging stuff below, it should (and currently does) produce the same CRC
/*
System.out.println("initial crc: "+crc);
File tmpDir = Downloader.createTempDir();
if(Downloader.extractFile(absolutePath, tmpDir.getAbsolutePath()))
crc = crcFile(tmpDir.getAbsolutePath());
System.out.println("later crc: "+crc + " temp dir: "+tmpDir.getAbsolutePath());
*/
}
// if crc is still 0, just calculate the CRC of the sharedFile itself
if (crc == 0)
crc = crcFile(absolutePath);
} catch (Exception e) {
System.out.println("Calculating CRC for torrent failed: " + e.getMessage());
Debug.debug(e);
return;
}
System.out.println("CRC of torrent: " + crc);
String magnet = String.format("magnet:?xt=urn:sha1:%s&dn=%s", infoHash, urlEncode(sharedFile.getName()));
for (String tracker : announceURL)
magnet += "&tr=" + urlEncode(tracker);
System.out.println("magnet link: " + magnet);
}
public static String urlEncode(String url) {
try {
return URLEncoder.encode(url, "UTF-8");
} catch (Exception e) {
return url;
}
}
public static long crcFile(String file) {
ChecksumInfo ci = new ChecksumInfo();
ci.checksumMatch(file);
return ci.getChecksum();
}
private void encodeObject(Object o, OutputStream out) throws IOException {
if (o instanceof String)
encodeString((String) o, out);
else if (o instanceof Map)
encodeMap((Map) o, out);
else if (o instanceof byte[])
encodeBytes((byte[]) o, out);
else if (o instanceof String[])
encodeStringArray((String[]) o, out);
else if (o instanceof Number)
encodeLong(((Number) o).longValue(), out);
else
throw new Error("Unencodable type");
}
private void encodeLong(long value, OutputStream out) throws IOException {
out.write('i');
out.write(Long.toString(value).getBytes("US-ASCII"));
out.write('e');
}
private void encodeBytes(byte[] bytes, OutputStream out) throws IOException {
out.write(Integer.toString(bytes.length).getBytes("US-ASCII"));
out.write(':');
out.write(bytes);
}
private void encodeStringArray(String[] list, OutputStream out) throws IOException {
out.write('l');
out.write('l');
for (String str : list)
encodeString(str, out);
out.write('e');
out.write('e');
}
private void encodeString(String str, OutputStream out) throws IOException {
encodeBytes(str.getBytes("UTF-8"), out);
}
private void encodeMap(Map<String, Object> map, OutputStream out) throws IOException {
// Sort the map. A generic encoder should sort by key bytes
SortedMap<String, Object> sortedMap = new TreeMap<String, Object>(map);
out.write('d');
for (String key : sortedMap.keySet()) {
encodeString(key, out);
encodeObject(sortedMap.get(key), out);
}
out.write('e');
}
private byte[] hashPieces(File file, int pieceLength) throws IOException {
MessageDigest sha1;
try {
sha1 = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
throw new Error("SHA1 not supported");
}
InputStream in = new FileInputStream(file);
ByteArrayOutputStream pieces = new ByteArrayOutputStream();
byte[] bytes = new byte[pieceLength];
int pieceByteCount = 0, readCount = in.read(bytes, 0, pieceLength);
while (readCount != -1) {
pieceByteCount += readCount;
sha1.update(bytes, 0, readCount);
if (pieceByteCount == pieceLength) {
pieceByteCount = 0;
pieces.write(sha1.digest());
}
readCount = in.read(bytes, 0, pieceLength - pieceByteCount);
}
in.close();
byte[] sha1Digest = sha1.digest();
this.infoHash = new java.math.BigInteger(1, sha1Digest).toString(16);
if (pieceByteCount > 0)
pieces.write(sha1Digest);
return pieces.toByteArray();
}
public void createTorrent(String... announceURL) throws IOException {
final int pieceLength = 512 * 1024;
Map<String, Object> info = new HashMap<String, Object>();
info.put("name", sharedFile.getName());
info.put("length", sharedFile.length());
info.put("piece length", pieceLength);
info.put("pieces", hashPieces(sharedFile, pieceLength));
Map<String, Object> metainfo = new HashMap<String, Object>();
if (announceURL != null && announceURL.length > 0) {
metainfo.put("announce", announceURL[0]);
// todo: this currently doesn't work
if (announceURL.length > 1)
metainfo.put("announce-list", announceURL);
}
metainfo.put("created by", "libtorrent");
metainfo.put("creation date", 1325820676);
metainfo.put("info", info);
OutputStream out = new FileOutputStream(torrentFile);
encodeMap(metainfo, out);
out.close();
}
public static void main(String[] args) throws Exception {
Debug.debug = true;
//MakeTorrent.askForFile(null);
new MakeTorrent("/home/mopar/IdeaProjects/MoparScape4/cachedump/minimal317.9.zip");
new MakeTorrent("/home/mopar/IdeaProjects/MoparScape4/cachedump/minimal317.9.zip.gz");
System.out.println("my crc: " + MakeTorrent.crcFile("/home/mopar/onefifty/cachetest/minimal317"));
new MakeTorrent("/home/mopar/IdeaProjects/MoparScape4/dist/client317.jar");
System.out.println("old CRC of jar: 48487200");
new MakeTorrent("/home/mopar/IdeaProjects/MoparScape4/dist/client317.jar.gz");
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2012 moparisthebest
*
* 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/>.
*
* Official forums are http://www.moparscape.org/smf/
* Email me at admin@moparisthebest.com , I read it but don't usually respond.
*/
package org.moparscape.res;
import java.io.IOException;
import java.io.OutputStream;
/**
* Created by IntelliJ IDEA.
* User: mopar
* Date: 1/5/12
* Time: 2:21 PM
* To change this template use File | Settings | File Templates.
*/
public class NullOutputStream extends OutputStream {
@Override
public void write(byte[] b, int off, int len) {
}
@Override
public void write(int b) {
}
@Override
public void write(byte[] b) throws IOException {
}
}

View File

@ -21,7 +21,6 @@
package org.moparscape.res.impl;
import org.moparscape.res.ChecksumInfo;
import org.moparscape.res.ChecksumInputStream;
import org.moparscape.res.DownloadListener;
import java.io.*;
@ -170,8 +169,6 @@ public abstract class Downloader {
callback.extracting("Extracting " + fileName, length, "to " + savePath + "...");
is = new ProgressInputStream(is, callback);
}
if(cs != null)
is = new ChecksumInputStream(is, cs);
//if(true)throw new RuntimeException("woohoo! fake exceptions!");
fileName = fileName.toLowerCase();
@ -203,7 +200,7 @@ public abstract class Downloader {
// if we are here, this is our java_client.win32.exe, and the CRC is correct, now just write it out to the file
// this should be quick enough I'm not going to bother with a ProgressInputStream
//writeStream(new ByteArrayInputStream(baos.toByteArray()), new FileOutputStream(savePath + fileName));
OutputStream fos = getOutputStream(savePath, fileName);
OutputStream fos = getOutputStream(savePath, fileName, cs);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
@ -211,7 +208,7 @@ public abstract class Downloader {
}
if (callback != null)
callback.setExtraInfo("Extracting File: " + fileName);
writeStream(new GZIPInputStream(is), getOutputStream(savePath, fileName));
writeStream(new GZIPInputStream(is), getOutputStream(savePath, fileName, cs));
return true;
} else if (fileName.endsWith(".zip")) {
// if we are here, the streams are all set up to unzip below, so don't do anything
@ -222,6 +219,7 @@ public abstract class Downloader {
return false;
}
ZipInputStream zin = new ZipInputStream(is);
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) {
String name = entry.getName();
@ -236,7 +234,8 @@ public abstract class Downloader {
continue;
if (callback != null)
callback.setExtraInfo("Extracting File: " + name);
writeStream(zin, getOutputStream(savePath, name));
//System.out.printf("Extracting File: '%s' crc so far: '%d'\n", name, cs == null? 0 : cs.getValue());
writeStream(zin, getOutputStream(savePath, name, cs));
}
//try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); }
}
@ -252,11 +251,17 @@ public abstract class Downloader {
}
// helper method to supply NullOutputStream if savePath is null
private static OutputStream getOutputStream(String savePath, String fileName) throws FileNotFoundException{
private static OutputStream getOutputStream(String savePath, String fileName, Checksum cs) throws FileNotFoundException{
OutputStream ret = null;
if(savePath == null || fileName == null)
return new org.moparscape.res.NullOutputStream();
ret = new org.moparscape.res.NullOutputStream();
else
return new FileOutputStream(savePath + fileName);
ret = new FileOutputStream(savePath + fileName);
if(cs != null)
ret = new CheckedOutputStream(ret, cs);
return ret;
}
public static File createTempDir() {