mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-13 21:58:15 +00:00
trunk contents moved to root
This commit is contained in:
111
src/com/jpexs/browsers/cache/CacheEntry.java
vendored
Normal file
111
src/com/jpexs/browsers/cache/CacheEntry.java
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache;
|
||||
|
||||
import com.jpexs.helpers.LimitedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class CacheEntry {
|
||||
|
||||
public abstract String getRequestURL();
|
||||
|
||||
public abstract Map<String, String> getResponseHeaders();
|
||||
|
||||
public abstract String getStatusLine();
|
||||
|
||||
public abstract String getRequestMethod();
|
||||
|
||||
public abstract InputStream getResponseRawDataStream();
|
||||
|
||||
public InputStream getResponseDataStream() {
|
||||
String contentLengthStr = getHeader("Content-Length");
|
||||
int contentLength = -1;
|
||||
if (contentLengthStr != null) {
|
||||
try {
|
||||
contentLength = Integer.parseInt(contentLengthStr);
|
||||
} catch (NumberFormatException nex) {
|
||||
}
|
||||
}
|
||||
final InputStream rawIs = getResponseRawDataStream();
|
||||
InputStream is = rawIs;
|
||||
if (contentLength > -1) {
|
||||
is = new LimitedInputStream(is, contentLength);
|
||||
}
|
||||
|
||||
String encoding = getHeader("Content-Encoding");
|
||||
if (encoding != null) {
|
||||
switch (encoding) {
|
||||
case "gzip":
|
||||
try {
|
||||
is = new GZIPInputStream(is);
|
||||
} catch (IOException ex) {
|
||||
is = null;
|
||||
//ignore
|
||||
}
|
||||
break;
|
||||
case "deflate":
|
||||
is = new InflaterInputStream(is);
|
||||
break;
|
||||
default: //unknown
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ("chunked".equals(getHeader("Transfer-Encoding"))) {
|
||||
is = new ChunkedInputStream(is);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getRequestURL();
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
String st = getStatusLine();
|
||||
if (st == null) {
|
||||
return 0;
|
||||
}
|
||||
String parts[] = st.split(" ");
|
||||
try {
|
||||
return Integer.parseInt(parts[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public String getHeader(String header) {
|
||||
Map<String, String> m = getResponseHeaders();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
for (String k : m.keySet()) {
|
||||
if (k.toLowerCase().equals(header.toLowerCase())) {
|
||||
return m.get(k);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
30
src/com/jpexs/browsers/cache/CacheImplementation.java
vendored
Normal file
30
src/com/jpexs/browsers/cache/CacheImplementation.java
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface CacheImplementation {
|
||||
|
||||
public List<CacheEntry> getEntries();
|
||||
|
||||
public void refresh();
|
||||
}
|
||||
45
src/com/jpexs/browsers/cache/CacheReader.java
vendored
Normal file
45
src/com/jpexs/browsers/cache/CacheReader.java
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache;
|
||||
|
||||
import com.jpexs.browsers.cache.chrome.ChromeCache;
|
||||
import com.jpexs.browsers.cache.firefox.FirefoxCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheReader {
|
||||
|
||||
public static final String BROWSER_FIREFOX = "firefox";
|
||||
public static final String BROWSER_CHROME = "chrome";
|
||||
|
||||
public static String[] availableBrowsers() {
|
||||
return new String[]{BROWSER_FIREFOX, BROWSER_CHROME};
|
||||
}
|
||||
|
||||
public static CacheImplementation getBrowserCache(String browser) {
|
||||
switch (browser) {
|
||||
case BROWSER_CHROME:
|
||||
return ChromeCache.getInstance();
|
||||
case BROWSER_FIREFOX:
|
||||
return FirefoxCache.getInstance();
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid browser:" + browser);
|
||||
}
|
||||
}
|
||||
}
|
||||
96
src/com/jpexs/browsers/cache/ChunkedInputStream.java
vendored
Normal file
96
src/com/jpexs/browsers/cache/ChunkedInputStream.java
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ChunkedInputStream extends InputStream {
|
||||
|
||||
private final InputStream is;
|
||||
private int chunkPos = 0;
|
||||
private int chunkLen = 0;
|
||||
private boolean end = false;
|
||||
private boolean first = true;
|
||||
|
||||
public ChunkedInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (end) {
|
||||
return -1;
|
||||
}
|
||||
if (chunkPos >= chunkLen) {
|
||||
if (!first) {
|
||||
if (is.read() != '\r') {
|
||||
throw new IOException("Invalid chunk");
|
||||
}
|
||||
if (is.read() != '\n') {
|
||||
throw new IOException("Invalid chunk");
|
||||
}
|
||||
}
|
||||
String lenStr = readLine();
|
||||
try {
|
||||
chunkLen = Integer.parseInt(lenStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IOException("Invalid chunk");
|
||||
}
|
||||
if (chunkLen == 0) {
|
||||
is.read(); // \r
|
||||
is.read(); // \n
|
||||
end = true;
|
||||
return -1;
|
||||
}
|
||||
chunkPos = 0;
|
||||
first = false;
|
||||
}
|
||||
|
||||
chunkPos++;
|
||||
return is.read();
|
||||
}
|
||||
|
||||
private String readLine() throws IOException {
|
||||
int i;
|
||||
boolean inr = false;
|
||||
String ret = "";
|
||||
while ((i = is.read()) > -1) {
|
||||
if (inr) {
|
||||
inr = false;
|
||||
if (i == '\n') {
|
||||
break;
|
||||
} else {
|
||||
ret += "\r";
|
||||
}
|
||||
}
|
||||
if (i == '\r') {
|
||||
inr = true;
|
||||
continue;
|
||||
}
|
||||
ret += (char) i;
|
||||
}
|
||||
if (inr) {
|
||||
ret += "\r";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
48
src/com/jpexs/browsers/cache/RafInputStream.java
vendored
Normal file
48
src/com/jpexs/browsers/cache/RafInputStream.java
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class RafInputStream extends InputStream {
|
||||
|
||||
private final RandomAccessFile raf;
|
||||
private long pos = 0;
|
||||
|
||||
public RafInputStream(RandomAccessFile raf) {
|
||||
this.raf = raf;
|
||||
try {
|
||||
pos = raf.getFilePointer();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(RafInputStream.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
raf.seek(pos++);
|
||||
return raf.read();
|
||||
}
|
||||
}
|
||||
69
src/com/jpexs/browsers/cache/chrome/BlockFileHeader.java
vendored
Normal file
69
src/com/jpexs/browsers/cache/chrome/BlockFileHeader.java
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BlockFileHeader {
|
||||
|
||||
static final int kBlockHeaderSize = 8192; // Two pages: almost 64k entries
|
||||
static final int kMaxBlocks = (kBlockHeaderSize - 80) * 8;
|
||||
long magic; // c3 ca 04 c1
|
||||
long version; // 00 00 02 00
|
||||
int this_file;
|
||||
int next_file;
|
||||
int entry_size;
|
||||
int num_entries;
|
||||
int max_entries;
|
||||
int empty[] = new int[4];
|
||||
int hints[] = new int[4];
|
||||
int updating;
|
||||
int user[] = new int[5];
|
||||
long allocation_map[] = new long[kMaxBlocks / 32];
|
||||
|
||||
public BlockFileHeader(InputStream is) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
magic = iis.readUInt32();
|
||||
version = iis.readUInt32();
|
||||
this_file = iis.readInt16();
|
||||
next_file = iis.readInt16();
|
||||
entry_size = iis.readInt32();
|
||||
num_entries = iis.readInt32();
|
||||
max_entries = iis.readInt32();
|
||||
empty = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
empty[i] = iis.readInt32();
|
||||
}
|
||||
hints = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hints[i] = iis.readInt32();
|
||||
}
|
||||
updating = iis.readInt32();
|
||||
user = new int[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
user[i] = iis.readInt32();
|
||||
}
|
||||
for (int i = 0; i < allocation_map.length; i++) {
|
||||
allocation_map[i] = iis.readUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
122
src/com/jpexs/browsers/cache/chrome/CacheAddr.java
vendored
Normal file
122
src/com/jpexs/browsers/cache/chrome/CacheAddr.java
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import com.jpexs.browsers.cache.RafInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheAddr {
|
||||
|
||||
public static final int EXTERNAL = 0;
|
||||
public static final int RANKINGS = 1;
|
||||
public static final int BLOCK_256 = 2;
|
||||
public static final int BLOCK_1K = 3;
|
||||
public static final int BLOCK_4K = 4;
|
||||
public static final int BLOCK_FILES = 5;
|
||||
public static final int BLOCK_ENTRIES = 6;
|
||||
public static final int BLOCK_EVICTED = 7;
|
||||
public static final String blockNames[] = new String[]{"EXTERNAL", "RANKINGS", "BLOCK_256", "BLOCK_1K", "BLOCK_4K", "BLOCK_FILES", "BLOCK_ENTRIES", "BLOCK_EVICTED"};
|
||||
public static final int blockSizes[] = new int[]{0, 36, 256, 1024, 4096, 8, 104, 48};
|
||||
public static final long kInitializedMask = 0x80000000L;
|
||||
public static final long kFileTypeMask = 0x70000000L;
|
||||
public static final int kFileTypeOffset = 28;
|
||||
public static final long kReservedBitsMask = 0x0c000000L;
|
||||
public static final long kNumBlocksMask = 0x03000000L;
|
||||
public static final int kNumBlocksOffset = 24;
|
||||
public static final long kFileSelectorMask = 0x00ff0000L;
|
||||
public static final int FileSelectorOffset = 16;
|
||||
public static final long kStartBlockMask = 0x0000FFFFL;
|
||||
public static final long kFileNameMask = 0x0FFFFFFFL;
|
||||
public boolean initialized;
|
||||
public int fileType;
|
||||
public int numBlocks;
|
||||
public int fileSelector;
|
||||
public int startBlock;
|
||||
public int fileName;
|
||||
public long val;
|
||||
public File rootPath;
|
||||
private final Map<Integer, RandomAccessFile> dataFiles;
|
||||
private final File externalFilesDir;
|
||||
|
||||
public CacheAddr(InputStream is, File rootPath, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
this.dataFiles = dataFiles;
|
||||
this.rootPath = rootPath;
|
||||
this.externalFilesDir = externalFilesDir;
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
val = iis.readUInt32();
|
||||
initialized = (val & kInitializedMask) == kInitializedMask;
|
||||
fileType = (int) ((val & kFileTypeMask) >> kFileTypeOffset);
|
||||
if (fileType == EXTERNAL) {
|
||||
fileName = (int) (val & kFileNameMask);
|
||||
} else {
|
||||
numBlocks = (int) ((val & kNumBlocksMask) >> kNumBlocksOffset);
|
||||
fileSelector = (int) ((val & kFileSelectorMask) >> FileSelectorOffset);
|
||||
startBlock = (int) (val & kStartBlockMask);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String ft = blockNames[fileType];
|
||||
if (fileType == EXTERNAL) {
|
||||
return ft + ":" + fileName;
|
||||
}
|
||||
if (!initialized) {
|
||||
return "uninitialized";
|
||||
}
|
||||
return ft + ": numBlocks " + numBlocks + " fileSelector " + fileSelector + " startBlock " + startBlock;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (!initialized) {
|
||||
return null;
|
||||
}
|
||||
switch (fileType) {
|
||||
case EXTERNAL:
|
||||
String fileNameStr = Long.toHexString(fileName);
|
||||
while (fileNameStr.length() < 6) {
|
||||
fileNameStr = "0" + fileNameStr;
|
||||
}
|
||||
fileNameStr = "f_" + fileNameStr;
|
||||
return new RafInputStream(new RandomAccessFile(new File(externalFilesDir, fileNameStr), "r"));
|
||||
case BLOCK_1K:
|
||||
case BLOCK_256:
|
||||
case BLOCK_4K:
|
||||
|
||||
RandomAccessFile raf;
|
||||
|
||||
if (dataFiles.containsKey(fileSelector)) {
|
||||
raf = dataFiles.get(fileSelector);
|
||||
} else {
|
||||
raf = new RandomAccessFile(rootPath + "\\data_" + fileSelector, "r");
|
||||
dataFiles.put(fileSelector, raf);
|
||||
}
|
||||
raf.seek(BlockFileHeader.kBlockHeaderSize + startBlock * blockSizes[fileType]);
|
||||
return new RafInputStream(raf);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
194
src/com/jpexs/browsers/cache/chrome/ChromeCache.java
vendored
Normal file
194
src/com/jpexs/browsers/cache/chrome/ChromeCache.java
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import com.jpexs.browsers.cache.CacheImplementation;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ChromeCache implements CacheImplementation {
|
||||
|
||||
private static ChromeCache instance;
|
||||
private File tempDir;
|
||||
private List<File> dataFiles;
|
||||
private File indexFile;
|
||||
|
||||
private ChromeCache() {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
free();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static ChromeCache getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ChromeCache();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
private boolean loaded = false;
|
||||
private Index index;
|
||||
|
||||
@Override
|
||||
public List<CacheEntry> getEntries() {
|
||||
if (!loaded) {
|
||||
refresh();
|
||||
}
|
||||
if (!loaded) {
|
||||
return null;
|
||||
}
|
||||
List<CacheEntry> ret = new ArrayList<>();
|
||||
try {
|
||||
List<EntryStore> entries = index.getEntries();
|
||||
for (EntryStore en : entries) {
|
||||
if (en.state == EntryStore.ENTRY_NORMAL) {
|
||||
String key = en.getKey();
|
||||
if (key != null && !key.trim().isEmpty()) {
|
||||
ret.add(en);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
free();
|
||||
File cacheDir = null;
|
||||
try {
|
||||
cacheDir = getCacheDirectory();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (cacheDir == null) {
|
||||
return;
|
||||
}
|
||||
File systemTempDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
File originalIndexFile = new File(cacheDir + File.separator + "index");
|
||||
tempDir = new File(systemTempDir, "cacheView" + System.identityHashCode(this));
|
||||
tempDir.mkdir();
|
||||
indexFile = new File(tempDir, "index");
|
||||
try {
|
||||
Files.copy(originalIndexFile.toPath(), indexFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
File originalDataFile;
|
||||
dataFiles = new ArrayList<>();
|
||||
for (int i = 0; (originalDataFile = new File(cacheDir, "data_" + i)).exists(); i++) {
|
||||
File dataFile = new File(tempDir, "data_" + i);
|
||||
dataFiles.add(dataFile);
|
||||
try {
|
||||
Files.copy(originalDataFile.toPath(), dataFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
index = new Index(indexFile, cacheDir);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
private enum OSId {
|
||||
|
||||
WINDOWS, OSX, UNIX
|
||||
}
|
||||
|
||||
private static OSId getOSId() {
|
||||
PrivilegedAction<String> doGetOSName = new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
};
|
||||
OSId id = OSId.UNIX;
|
||||
String osName = AccessController.doPrivileged(doGetOSName);
|
||||
if (osName != null) {
|
||||
if (osName.toLowerCase().startsWith("mac os x")) {
|
||||
id = OSId.OSX;
|
||||
} else if (osName.contains("Windows")) {
|
||||
id = OSId.WINDOWS;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static File getCacheDirectory() throws IOException {
|
||||
String userHome = null;
|
||||
File ret = null;
|
||||
try {
|
||||
userHome = System.getProperty("user.home");
|
||||
} catch (SecurityException ignore) {
|
||||
}
|
||||
if (userHome != null) {
|
||||
OSId osId = getOSId();
|
||||
if (osId == OSId.WINDOWS) {
|
||||
ret = new File(userHome + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cache\\");
|
||||
if (!ret.exists()) {
|
||||
ret = new File(userHome + "\\Local Settings\\Application Data\\Google\\Chrome\\User Data\\Default\\Cache");
|
||||
}
|
||||
} else if (osId == OSId.OSX) {
|
||||
ret = new File(userHome + "/Library/Caches/Google/Chrome/Default/Cache");
|
||||
} else {
|
||||
ret = new File(userHome + "/.config/google-chrome/Default/Application Cache/Cache/");
|
||||
if (!ret.exists()) {
|
||||
ret = new File(userHome + "/.cache/chromium/Default/Cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((ret != null) && !ret.exists()) {
|
||||
return null;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
private void free() {
|
||||
if (loaded) {
|
||||
index.free();
|
||||
indexFile.delete();
|
||||
for (File d : dataFiles) {
|
||||
d.delete();
|
||||
}
|
||||
tempDir.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/com/jpexs/browsers/cache/chrome/EntryFlags.java
vendored
Normal file
27
src/com/jpexs/browsers/cache/chrome/EntryFlags.java
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EntryFlags {
|
||||
|
||||
public static final int PARENT_ENTRY = 1;
|
||||
public static final int CHILD_ENTRY = 1 << 1;
|
||||
}
|
||||
28
src/com/jpexs/browsers/cache/chrome/EntryState.java
vendored
Normal file
28
src/com/jpexs/browsers/cache/chrome/EntryState.java
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EntryState {
|
||||
|
||||
public static final int ENTRY_NORMAL = 0;
|
||||
public static final int ENTRY_EVICTED = 1;
|
||||
public static final int ENTRY_DOOMED = 2;
|
||||
}
|
||||
153
src/com/jpexs/browsers/cache/chrome/EntryStore.java
vendored
Normal file
153
src/com/jpexs/browsers/cache/chrome/EntryStore.java
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EntryStore extends CacheEntry {
|
||||
|
||||
public static final int ENTRY_NORMAL = 0;
|
||||
public static final int ENTRY_EVICTED = 1; // The entry was recently evicted from the cache.
|
||||
public static final int ENTRY_DOOMED = 2; // The entry was doomed
|
||||
public static final int PARENT_ENTRY = 1; // This entry has children (sparse) entries.
|
||||
public static final int CHILD_ENTRY = 1 << 1;
|
||||
public long hash; // Full hash of the key.
|
||||
public CacheAddr next; // Next entry with the same hash or bucket.
|
||||
public CacheAddr rankings_node; // Rankings node for this entry.
|
||||
public int reuse_count; // How often is this entry used.
|
||||
public int refetch_count; // How often is this fetched from the net.
|
||||
public int state; // Current state.
|
||||
public long creation_time;
|
||||
public int key_len;
|
||||
public CacheAddr long_key; // Optional address of a long key.
|
||||
public int data_size[] = new int[4]; // We can store up to 4 data streams for each
|
||||
public CacheAddr data_addr[] = new CacheAddr[4]; // entry.
|
||||
public long flags; // Any combination of EntryFlags.
|
||||
public int pad[] = new int[4];
|
||||
public long self_hash; // The hash of EntryStore up to this point.
|
||||
public byte key[] = new byte[256 - 24 * 4]; // null terminated
|
||||
|
||||
public EntryStore(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
hash = iis.readUInt32();
|
||||
next = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
rankings_node = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
reuse_count = iis.readInt32();
|
||||
refetch_count = iis.readInt32();
|
||||
state = iis.readInt32();
|
||||
creation_time = iis.readUInt64();
|
||||
key_len = iis.readInt32();
|
||||
long_key = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
data_size = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data_size[i] = iis.readInt32();
|
||||
}
|
||||
data_addr = new CacheAddr[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data_addr[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
flags = iis.readUInt32();
|
||||
pad = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pad[i] = iis.readInt32();
|
||||
}
|
||||
self_hash = iis.readUInt32();
|
||||
key = new byte[256 - 24 * 4];
|
||||
iis.read(key);
|
||||
}
|
||||
|
||||
public HttpResponseInfo getResponseInfo() {
|
||||
try {
|
||||
InputStream is = data_addr[0].getInputStream();
|
||||
if (is == null) {
|
||||
return null;
|
||||
}
|
||||
return new HttpResponseInfo(is);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(EntryStore.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getResponseDataSize() {
|
||||
return data_size[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResponseRawDataStream() {
|
||||
try {
|
||||
return data_addr[1].getInputStream();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(EntryStore.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
if (key_len < 0) {
|
||||
return null;
|
||||
}
|
||||
return new String(key, 0, key_len > key.length || key_len < 0 ? key.length : key_len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestURL() {
|
||||
return getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getResponseHeaders() {
|
||||
HttpResponseInfo ri = getResponseInfo();
|
||||
if (ri == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
List<String> headers = ri.headers;
|
||||
Map<String, String> ret = new HashMap<>();
|
||||
for (int h = 1; h < headers.size(); h++) {
|
||||
String hs = headers.get(h);
|
||||
if (hs.contains(":")) {
|
||||
String hp[] = hs.split(":");
|
||||
ret.put(hp[0].trim(), hp[1].trim());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusLine() {
|
||||
HttpResponseInfo ri = getResponseInfo();
|
||||
return ri.headers.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestMethod() {
|
||||
return "GET";
|
||||
}
|
||||
}
|
||||
107
src/com/jpexs/browsers/cache/chrome/HttpResponseInfo.java
vendored
Normal file
107
src/com/jpexs/browsers/cache/chrome/HttpResponseInfo.java
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class HttpResponseInfo {
|
||||
|
||||
public long flags;
|
||||
public int version;
|
||||
public long request_time;
|
||||
public long response_time;
|
||||
public long payload_size;
|
||||
public List<String> headers;
|
||||
// The version of the response info used when persisting response info.
|
||||
public static final int RESPONSE_INFO_VERSION = 3;
|
||||
// The minimum version supported for deserializing response info.
|
||||
public static final int RESPONSE_INFO_MINIMUM_VERSION = 1;
|
||||
// We reserve up to 8 bits for the version number.
|
||||
public static final int RESPONSE_INFO_VERSION_MASK = 0xFF;
|
||||
// This bit is set if the response info has a cert at the end.
|
||||
// Version 1 serialized only the end-entity certificate, while subsequent
|
||||
// versions include the available certificate chain.
|
||||
public static final int RESPONSE_INFO_HAS_CERT = 1 << 8;
|
||||
// This bit is set if the response info has a security-bits field (security
|
||||
// strength, in bits, of the SSL connection) at the end.
|
||||
public static final int RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9;
|
||||
// This bit is set if the response info has a cert status at the end.
|
||||
public static final int RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10;
|
||||
// This bit is set if the response info has vary header data.
|
||||
public static final int RESPONSE_INFO_HAS_VARY_DATA = 1 << 11;
|
||||
// This bit is set if the request was cancelled before completion.
|
||||
public static final int RESPONSE_INFO_TRUNCATED = 1 << 12;
|
||||
// This bit is set if the response was received via SPDY.
|
||||
public static final int RESPONSE_INFO_WAS_SPDY = 1 << 13;
|
||||
// This bit is set if the request has NPN negotiated.
|
||||
public static final int RESPONSE_INFO_WAS_NPN = 1 << 14;
|
||||
// This bit is set if the request was fetched via an explicit proxy.
|
||||
public static final int RESPONSE_INFO_WAS_PROXY = 1 << 15;
|
||||
// This bit is set if the response info has an SSL connection status field.
|
||||
// This contains the ciphersuite used to fetch the resource as well as the
|
||||
// protocol version, compression method and whether SSLv3 fallback was used.
|
||||
public static final int RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16;
|
||||
// This bit is set if the response info has protocol version.
|
||||
public static final int RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17;
|
||||
// This bit is set if the response info has connection info.
|
||||
public static final int RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18;
|
||||
// This bit is set if the request has http authentication.
|
||||
public static final int RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19;
|
||||
|
||||
public String getHeaderValue(String header) {
|
||||
for (String h : headers) {
|
||||
if (h.contains(":")) {
|
||||
String keyval[] = h.split(":");
|
||||
String key = keyval[0].trim().toLowerCase();
|
||||
String val = keyval[1].trim();
|
||||
if (header.toLowerCase().equals(key)) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public HttpResponseInfo(InputStream is) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
payload_size = iis.readUInt32();
|
||||
flags = iis.readInt();
|
||||
version = (int) (flags & RESPONSE_INFO_VERSION_MASK);
|
||||
if (version < RESPONSE_INFO_MINIMUM_VERSION || version > RESPONSE_INFO_VERSION) {
|
||||
throw new RuntimeException("unexpected response info version: " + version);
|
||||
}
|
||||
request_time = iis.readInt64();
|
||||
response_time = iis.readInt64();
|
||||
String headersStr = iis.readString();
|
||||
headers = new ArrayList<>();
|
||||
int nulpos;
|
||||
while ((nulpos = headersStr.indexOf(0)) > 0) {
|
||||
String h = headersStr.substring(0, nulpos);
|
||||
headersStr = headersStr.substring(nulpos + 1);
|
||||
headers.add(h);
|
||||
}
|
||||
|
||||
//TODO: Read SSL info
|
||||
}
|
||||
}
|
||||
79
src/com/jpexs/browsers/cache/chrome/Index.java
vendored
Normal file
79
src/com/jpexs/browsers/cache/chrome/Index.java
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Index {
|
||||
|
||||
IndexHeader header;
|
||||
CacheAddr table[];
|
||||
public static final int kIndexTablesize = 0x10000;
|
||||
public File rootDir;
|
||||
private final Map<Integer, RandomAccessFile> dataFiles;
|
||||
private final File externalFilesDir;
|
||||
|
||||
public void free() {
|
||||
for (RandomAccessFile r : dataFiles.values()) {
|
||||
try {
|
||||
r.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<EntryStore> getEntries() throws IOException {
|
||||
List<EntryStore> ret = new ArrayList<>();
|
||||
for (CacheAddr ca : table) {
|
||||
InputStream is = ca.getInputStream();
|
||||
if (is != null) {
|
||||
EntryStore es = new EntryStore(is, rootDir, dataFiles, externalFilesDir);
|
||||
ret.add(es);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Index(File file, File externalFilesDir) throws IOException {
|
||||
dataFiles = new HashMap<>();
|
||||
this.externalFilesDir = externalFilesDir;
|
||||
try (FileInputStream is = new FileInputStream(file)) {
|
||||
rootDir = file.getParentFile();
|
||||
header = new IndexHeader(is, rootDir, dataFiles, externalFilesDir);
|
||||
int tsize = kIndexTablesize;
|
||||
if (header.table_len > 0) {
|
||||
tsize = header.table_len;
|
||||
}
|
||||
table = new CacheAddr[tsize];
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
table[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/com/jpexs/browsers/cache/chrome/IndexHeader.java
vendored
Normal file
64
src/com/jpexs/browsers/cache/chrome/IndexHeader.java
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IndexHeader {
|
||||
|
||||
long magic; //c3 ca 03 c1
|
||||
long version; //01 00 02 00
|
||||
int num_entries;
|
||||
int num_bytes;
|
||||
int last_file;
|
||||
int this_id;
|
||||
CacheAddr stats;
|
||||
int table_len;
|
||||
int crash;
|
||||
int experiment;
|
||||
long create_time;
|
||||
int pad[] = new int[52];
|
||||
LruData lru;
|
||||
|
||||
public IndexHeader(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
magic = iis.readUInt32();
|
||||
version = iis.readUInt32();
|
||||
num_entries = iis.readInt32();
|
||||
num_bytes = iis.readInt32();
|
||||
last_file = iis.readInt32();
|
||||
this_id = iis.readInt32();
|
||||
stats = new CacheAddr(iis, rootDir, dataFiles, externalFilesDir);
|
||||
table_len = iis.readInt32();
|
||||
crash = iis.readInt32();
|
||||
experiment = iis.readInt32();
|
||||
create_time = iis.readUInt64();
|
||||
pad = new int[52];
|
||||
for (int i = 0; i < 52; i++) {
|
||||
pad[i] = iis.readInt32();
|
||||
}
|
||||
lru = new LruData(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
}
|
||||
79
src/com/jpexs/browsers/cache/chrome/IndexInputStream.java
vendored
Normal file
79
src/com/jpexs/browsers/cache/chrome/IndexInputStream.java
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IndexInputStream extends InputStream {
|
||||
|
||||
private final InputStream is;
|
||||
public long pos = 0;
|
||||
|
||||
public long getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public IndexInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int r = is.read();
|
||||
//System.out.print("$"+Integer.toHexString(r));
|
||||
pos++;
|
||||
return r;
|
||||
}
|
||||
|
||||
public long readUInt32() throws IOException {
|
||||
long r = (((long) read()) + ((long) (read() << 8)) + ((long) (read() << 16)) + ((long) (read() << 24))) & 0xffffffffL;
|
||||
//System.out.println("");
|
||||
return r;
|
||||
}
|
||||
|
||||
public long readUInt64() throws IOException {
|
||||
return readUInt32() + (readUInt32() << 32);
|
||||
}
|
||||
|
||||
public long readInt64() throws IOException {
|
||||
return readUInt64(); //FIXME
|
||||
}
|
||||
|
||||
public int readInt32() throws IOException {
|
||||
return (int) readUInt32();
|
||||
}
|
||||
|
||||
public int readInt16() throws IOException {
|
||||
return (short) ((int) read() + (int) (read() << 8));
|
||||
}
|
||||
|
||||
public long readInt() throws IOException {
|
||||
return readInt32();
|
||||
}
|
||||
|
||||
public String readString() throws IOException {
|
||||
int len = (int) readInt();
|
||||
byte data[] = new byte[len];
|
||||
read(data);
|
||||
return new String(data);
|
||||
}
|
||||
}
|
||||
71
src/com/jpexs/browsers/cache/chrome/LruData.java
vendored
Normal file
71
src/com/jpexs/browsers/cache/chrome/LruData.java
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class LruData {
|
||||
|
||||
int pad1[] = new int[2];
|
||||
int filled;
|
||||
int sizes[] = new int[5];
|
||||
CacheAddr heads[] = new CacheAddr[5];
|
||||
CacheAddr tails[] = new CacheAddr[5];
|
||||
CacheAddr transaction;
|
||||
int operation;
|
||||
int operation_list;
|
||||
int pad2[] = new int[7];
|
||||
|
||||
public LruData(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
pad1 = new int[2];
|
||||
pad1[0] = iis.readInt32();
|
||||
pad1[1] = iis.readInt32();
|
||||
filled = iis.readInt32();
|
||||
sizes = new int[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sizes[i] = iis.readInt32();
|
||||
}
|
||||
sizes = new int[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sizes[i] = iis.readInt32();
|
||||
}
|
||||
heads = new CacheAddr[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
heads[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
tails = new CacheAddr[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
tails[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
transaction = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
operation = iis.readInt32();
|
||||
operation_list = iis.readInt32();
|
||||
pad2 = new int[7];
|
||||
for (int i = 0; i < 7; i++) {
|
||||
pad2[i] = iis.readInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/com/jpexs/browsers/cache/chrome/RankingsNode.java
vendored
Normal file
32
src/com/jpexs/browsers/cache/chrome/RankingsNode.java
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.chrome;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class RankingsNode {
|
||||
|
||||
public long last_used;
|
||||
public long last_modified;
|
||||
CacheAddr next;
|
||||
CacheAddr prev;
|
||||
CacheAddr contents;
|
||||
int dirty;
|
||||
long self_hash;
|
||||
}
|
||||
51
src/com/jpexs/browsers/cache/firefox/CacheInputStream.java
vendored
Normal file
51
src/com/jpexs/browsers/cache/firefox/CacheInputStream.java
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.firefox;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheInputStream extends InputStream {
|
||||
|
||||
private final InputStream is;
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return is.available();
|
||||
}
|
||||
|
||||
public CacheInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return is.read();
|
||||
}
|
||||
|
||||
public long readInt32() throws IOException {
|
||||
return (read() << 24) + (read() << 16) + (read() << 8) + read();
|
||||
}
|
||||
|
||||
public int readInt16() throws IOException {
|
||||
return (read() << 8) + read();
|
||||
}
|
||||
}
|
||||
72
src/com/jpexs/browsers/cache/firefox/CacheMap.java
vendored
Normal file
72
src/com/jpexs/browsers/cache/firefox/CacheMap.java
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.firefox;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheMap {
|
||||
|
||||
public long version;
|
||||
public long datasize;
|
||||
public long entryCount;
|
||||
public long dirtyFlag;
|
||||
public long recordCount;
|
||||
public long evictionRank[];
|
||||
public long bucketUsage[];
|
||||
public List<MapBucket> mapBuckets;
|
||||
|
||||
public CacheMap(File file) throws IOException {
|
||||
File cacheDir = file.getParentFile();
|
||||
CacheInputStream cis = new CacheInputStream(new FileInputStream(file));
|
||||
version = cis.readInt32();
|
||||
datasize = cis.readInt32();
|
||||
entryCount = cis.readInt32();
|
||||
dirtyFlag = cis.readInt32();
|
||||
recordCount = cis.readInt32();
|
||||
evictionRank = new long[32];
|
||||
for (int i = 0; i < evictionRank.length; i++) {
|
||||
evictionRank[i] = cis.readInt32();
|
||||
}
|
||||
bucketUsage = new long[32];
|
||||
for (int i = 0; i < bucketUsage.length; i++) {
|
||||
bucketUsage[i] = cis.readInt32();
|
||||
}
|
||||
mapBuckets = new ArrayList<>();
|
||||
Map<Integer, RandomAccessFile> cacheFiles = new HashMap<>();
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
cacheFiles.put(i, new RandomAccessFile(new File(cacheDir, "_CACHE_00" + i + "_"), "r"));
|
||||
}
|
||||
while (cis.available() > 0) {
|
||||
MapBucket mb = new MapBucket(cis, cacheDir, cacheFiles);
|
||||
if (mb.hash == 0) {
|
||||
continue;
|
||||
}
|
||||
mapBuckets.add(mb);
|
||||
}
|
||||
}
|
||||
}
|
||||
161
src/com/jpexs/browsers/cache/firefox/FirefoxCache.java
vendored
Normal file
161
src/com/jpexs/browsers/cache/firefox/FirefoxCache.java
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.firefox;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import com.jpexs.browsers.cache.CacheImplementation;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FirefoxCache implements CacheImplementation {
|
||||
|
||||
private static FirefoxCache instance;
|
||||
|
||||
private FirefoxCache() {
|
||||
}
|
||||
|
||||
public static FirefoxCache getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new FirefoxCache();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
private boolean loaded = false;
|
||||
private CacheMap map;
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
File dir = getCacheDirectory();
|
||||
if (dir == null) {
|
||||
return;
|
||||
}
|
||||
File cacheMapFile = new File(dir, "_CACHE_MAP_");
|
||||
try {
|
||||
map = new CacheMap(cacheMapFile);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(FirefoxCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CacheEntry> getEntries() {
|
||||
if (!loaded) {
|
||||
refresh();
|
||||
}
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
List<CacheEntry> ret = new ArrayList<>();
|
||||
|
||||
ret.addAll(map.mapBuckets);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private enum OSId {
|
||||
|
||||
WINDOWS, OSX, UNIX
|
||||
}
|
||||
|
||||
private static OSId getOSId() {
|
||||
PrivilegedAction<String> doGetOSName = new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
};
|
||||
OSId id = OSId.UNIX;
|
||||
String osName = AccessController.doPrivileged(doGetOSName);
|
||||
if (osName != null) {
|
||||
if (osName.toLowerCase().startsWith("mac os x")) {
|
||||
id = OSId.OSX;
|
||||
} else if (osName.contains("Windows")) {
|
||||
id = OSId.WINDOWS;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static File getProfileDirectory() {
|
||||
File profilesDir = getProfilesDirectory();
|
||||
if (profilesDir == null) {
|
||||
return null;
|
||||
}
|
||||
File profiles[] = profilesDir.listFiles();
|
||||
File profileDir = null;
|
||||
for (File f : profiles) {
|
||||
if (f.isDirectory()) {
|
||||
if (f.getName().matches("[a-z0-9]+\\.default")) {
|
||||
profileDir = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return profileDir;
|
||||
}
|
||||
|
||||
public static File getCacheDirectory() {
|
||||
File profileDir = getProfileDirectory();
|
||||
File cacheDir = null;
|
||||
if (profileDir != null) {
|
||||
cacheDir = new File(profileDir, "Cache");
|
||||
}
|
||||
if (cacheDir == null) {
|
||||
return null;
|
||||
}
|
||||
if (!cacheDir.exists()) {
|
||||
return null;
|
||||
}
|
||||
return cacheDir;
|
||||
}
|
||||
|
||||
public static File getProfilesDirectory() {
|
||||
String userHome = null;
|
||||
File profilesDir = null;
|
||||
try {
|
||||
userHome = System.getProperty("user.home");
|
||||
} catch (SecurityException ignore) {
|
||||
}
|
||||
if (userHome != null) {
|
||||
OSId osId = getOSId();
|
||||
if (osId == OSId.WINDOWS) {
|
||||
profilesDir = new File(userHome + "\\AppData\\Local\\Mozilla\\Firefox\\Profiles");
|
||||
if (!profilesDir.exists()) {
|
||||
profilesDir = new File(userHome + "\\Local Settings\\Application Data\\Mozilla\\Firefox\\Profiles");
|
||||
}
|
||||
} else if (osId == OSId.OSX) {
|
||||
profilesDir = new File(userHome + "/Library/Caches/Firefox/Profiles");
|
||||
} else {
|
||||
profilesDir = new File(userHome + "/.mozilla/firefox");
|
||||
}
|
||||
}
|
||||
if ((profilesDir == null) || !profilesDir.exists()) {
|
||||
return null;
|
||||
}
|
||||
return profilesDir;
|
||||
}
|
||||
}
|
||||
28
src/com/jpexs/browsers/cache/firefox/IncompatibleVersionException.java
vendored
Normal file
28
src/com/jpexs/browsers/cache/firefox/IncompatibleVersionException.java
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 etrik
|
||||
*
|
||||
* 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.jpexs.browsers.cache.firefox;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author petrik
|
||||
*/
|
||||
public class IncompatibleVersionException extends Exception {
|
||||
|
||||
public IncompatibleVersionException(int version) {
|
||||
super("Incompatible version: " + version);
|
||||
}
|
||||
}
|
||||
116
src/com/jpexs/browsers/cache/firefox/Location.java
vendored
Normal file
116
src/com/jpexs/browsers/cache/firefox/Location.java
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.firefox;
|
||||
|
||||
import com.jpexs.browsers.cache.RafInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Location {
|
||||
|
||||
public int locationSelector;
|
||||
public int extraBlocks;
|
||||
public long blockNumber;
|
||||
public int fileGeneration;
|
||||
public int fileSize;
|
||||
public boolean isMetadata;
|
||||
public long hash;
|
||||
private final File rootDir;
|
||||
public static final long eReservedMask = 0x4C000000L;
|
||||
public static final long eLocationSelectorMask = 0x30000000L;
|
||||
public static final int eLocationSelectorOffset = 28;
|
||||
public static final long eExtraBlocksMask = 0x03000000L;
|
||||
public static final int eExtraBlocksOffset = 24;
|
||||
public static final long eBlockNumberMask = 0x00FFFFFFL;
|
||||
public static final long eFileGenerationMask = 0x000000FFL;
|
||||
public static final long eFileSizeMask = 0x00FFFF00L;
|
||||
public static final int eFileSizeOffset = 8;
|
||||
public static final long eFileReservedMask = 0x4F000000L;
|
||||
|
||||
public static int size_shift(int idx) {
|
||||
return (2 * ((idx) - 1));
|
||||
}
|
||||
|
||||
public static int bitmapSizeForIndex(int idx) {
|
||||
return ((idx > 0) ? (131072 >> size_shift(idx)) : 0);
|
||||
}
|
||||
|
||||
public static int blockSizeForIndex(int idx) {
|
||||
return ((idx > 0) ? (256 << size_shift(idx)) : 0);
|
||||
}
|
||||
/*
|
||||
#define BLOCK_SIZE_FOR_INDEX(idx) ((idx) ? (256 << SIZE_SHIFT(idx)) : 0)
|
||||
#define BITMAP_SIZE_FOR_INDEX(idx) ((idx) ? (131072 >> SIZE_SHIFT(idx)) : 0)
|
||||
*/
|
||||
private final Map<Integer, RandomAccessFile> dataFiles;
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
String fileName = getFileName();
|
||||
if (locationSelector > 0) {
|
||||
RandomAccessFile raf = dataFiles.get(locationSelector);
|
||||
raf.seek(bitmapSizeForIndex(locationSelector) / 8 + blockSizeForIndex(locationSelector) * blockNumber);
|
||||
return new RafInputStream(raf);
|
||||
}
|
||||
return new FileInputStream(new File(rootDir, fileName));
|
||||
}
|
||||
|
||||
public Location(long val, boolean isMetadata, long hash, File rootDir, Map<Integer, RandomAccessFile> dataFiles) {
|
||||
this.hash = hash;
|
||||
this.dataFiles = dataFiles;
|
||||
this.rootDir = rootDir;
|
||||
this.isMetadata = isMetadata;
|
||||
locationSelector = (int) ((val & eLocationSelectorMask) >> eLocationSelectorOffset);
|
||||
if (locationSelector > 0) {
|
||||
extraBlocks = (int) ((val & eExtraBlocksMask) >> eExtraBlocksOffset);
|
||||
blockNumber = (int) (val & eBlockNumberMask);
|
||||
} else {
|
||||
fileSize = (int) ((val & eFileSizeMask) >> eFileSizeOffset);
|
||||
fileGeneration = (int) (val & eFileGenerationMask);
|
||||
}
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
if (locationSelector > 0) {
|
||||
return "_CACHE_00" + locationSelector + "_";
|
||||
}
|
||||
String hashHex = Long.toHexString(hash & 0xffffffffL).toUpperCase();
|
||||
while (hashHex.length() < 8) {
|
||||
hashHex = "0" + hashHex;
|
||||
}
|
||||
String genHex = Integer.toHexString(fileGeneration);
|
||||
while (genHex.length() < 2) {
|
||||
genHex = "0" + genHex;
|
||||
}
|
||||
return hashHex.charAt(0) + File.separator + hashHex.substring(1, 1 + 2) + File.separator + hashHex.substring(3) + (isMetadata ? "m" : "d") + genHex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (locationSelector > 0) {
|
||||
return getFileName() + " block " + blockNumber + " extraBlocks " + extraBlocks;
|
||||
}
|
||||
return getFileName();
|
||||
}
|
||||
}
|
||||
129
src/com/jpexs/browsers/cache/firefox/MapBucket.java
vendored
Normal file
129
src/com/jpexs/browsers/cache/firefox/MapBucket.java
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.firefox;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class MapBucket extends CacheEntry {
|
||||
|
||||
public long hash;
|
||||
public long enviction;
|
||||
public Location dataLocation;
|
||||
public Location metadataLocation;
|
||||
private MetaData metadata;
|
||||
|
||||
public MapBucket(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles) throws IOException {
|
||||
CacheInputStream cis = new CacheInputStream(is);
|
||||
hash = cis.readInt32();
|
||||
enviction = cis.readInt32();
|
||||
dataLocation = new Location(cis.readInt32(), false, hash, rootDir, dataFiles);
|
||||
metadataLocation = new Location(cis.readInt32(), true, hash, rootDir, dataFiles);
|
||||
}
|
||||
|
||||
public InputStream getMetaDataStream() throws IOException {
|
||||
return metadataLocation.getInputStream();
|
||||
}
|
||||
|
||||
public MetaData getMetaData() {
|
||||
if (metadata == null) {
|
||||
try {
|
||||
metadata = new MetaData(getMetaDataStream());
|
||||
} catch (IncompatibleVersionException ie) {
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestURL() {
|
||||
String req = null;
|
||||
MetaData m = getMetaData();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
req = m.request;
|
||||
if (req == null) {
|
||||
return null;
|
||||
}
|
||||
if (req.startsWith("HTTP:")) {
|
||||
req = req.substring("HTTP:".length());
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getResponseHeaders() {
|
||||
MetaData m = getMetaData();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
String responseHead = m.response.get("response-head");
|
||||
if (responseHead == null) {
|
||||
return null;
|
||||
}
|
||||
String headers[] = responseHead.split("\r\n");
|
||||
Map<String, String> ret = new HashMap<>();
|
||||
for (int h = 1; h < headers.length; h++) {
|
||||
String hs = headers[h];
|
||||
if (hs.contains(":")) {
|
||||
String hp[] = hs.split(":");
|
||||
ret.put(hp[0].trim(), hp[1].trim());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusLine() {
|
||||
MetaData m = getMetaData();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
String responseHead = m.response.get("response-head");
|
||||
String headers[] = responseHead.split("\r\n");
|
||||
return headers[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestMethod() {
|
||||
return "GET"; //No POST caching in Firefox
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResponseRawDataStream() {
|
||||
try {
|
||||
return dataLocation.getInputStream();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
79
src/com/jpexs/browsers/cache/firefox/MetaData.java
vendored
Normal file
79
src/com/jpexs/browsers/cache/firefox/MetaData.java
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* 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.jpexs.browsers.cache.firefox;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class MetaData {
|
||||
|
||||
public int majorVersion;
|
||||
public int minorVersion;
|
||||
public long location;
|
||||
public long fetchCount;
|
||||
public long firstFetchTime;
|
||||
public long lastFetchTime;
|
||||
public long expireTime;
|
||||
public long dataSize;
|
||||
public long requestSize;
|
||||
public long infoSize;
|
||||
public String request;
|
||||
public Map<String, String> response;
|
||||
|
||||
public MetaData(InputStream is) throws IOException, IncompatibleVersionException {
|
||||
CacheInputStream cis = new CacheInputStream(is);
|
||||
majorVersion = cis.readInt16();
|
||||
if (majorVersion != 1) {
|
||||
throw new IncompatibleVersionException(majorVersion);
|
||||
}
|
||||
minorVersion = cis.readInt16();
|
||||
location = cis.readInt32();
|
||||
fetchCount = cis.readInt32();
|
||||
firstFetchTime = cis.readInt32();
|
||||
lastFetchTime = cis.readInt32();
|
||||
expireTime = cis.readInt32();
|
||||
dataSize = cis.readInt32();
|
||||
requestSize = cis.readInt32();
|
||||
infoSize = cis.readInt32();
|
||||
byte req[] = new byte[(int) requestSize];
|
||||
cis.read(req);
|
||||
request = new String(req, 0, (int) requestSize - 1/*Ends with char 0*/);
|
||||
byte res[] = new byte[(int) infoSize];
|
||||
cis.read(res);
|
||||
String responseStr = new String(res);
|
||||
int nulpos;
|
||||
boolean inKey = true;
|
||||
String key = null;
|
||||
response = new HashMap<>();
|
||||
while ((nulpos = responseStr.indexOf(0)) > 0) {
|
||||
String v = responseStr.substring(0, nulpos);
|
||||
responseStr = responseStr.substring(nulpos + 1);
|
||||
if (inKey) {
|
||||
key = v;
|
||||
} else {
|
||||
response.put(key, v);
|
||||
}
|
||||
inKey = !inKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user