tikhomirov@22: /* tikhomirov@73: * Copyright (c) 2010-2011 TMate Software Ltd tikhomirov@73: * tikhomirov@73: * This program is free software; you can redistribute it and/or modify tikhomirov@73: * it under the terms of the GNU General Public License as published by tikhomirov@73: * the Free Software Foundation; version 2 of the License. tikhomirov@73: * tikhomirov@73: * This program is distributed in the hope that it will be useful, tikhomirov@73: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@73: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@73: * GNU General Public License for more details. tikhomirov@73: * tikhomirov@73: * For information on how to redistribute this software under tikhomirov@73: * the terms of a license other than GNU General Public License tikhomirov@102: * contact TMate Software at support@hg4j.com tikhomirov@22: */ tikhomirov@73: package org.tmatesoft.hg.internal; tikhomirov@0: tikhomirov@0: import java.io.BufferedInputStream; tikhomirov@0: import java.io.DataInput; tikhomirov@0: import java.io.DataInputStream; tikhomirov@0: import java.io.File; tikhomirov@0: import java.io.FileInputStream; tikhomirov@0: import java.math.BigInteger; tikhomirov@376: import java.nio.ByteBuffer; tikhomirov@376: import java.nio.channels.FileChannel; tikhomirov@0: import java.util.zip.Inflater; tikhomirov@0: tikhomirov@0: /** tikhomirov@73: * Utility to test/debug/troubleshoot tikhomirov@73: * tikhomirov@73: * @author Artem Tikhomirov tikhomirov@73: * @author TMate Software Ltd. tikhomirov@0: */ tikhomirov@73: public class RevlogDump { tikhomirov@0: tikhomirov@73: /** tikhomirov@73: * Takes 3 command line arguments - tikhomirov@73: * repository path, tikhomirov@73: * path to index file (i.e. store/data/hello.c.i) in the repository (relative) tikhomirov@73: * and "dumpData" whether to print actual content or just revlog headers tikhomirov@73: */ tikhomirov@0: public static void main(String[] args) throws Exception { tikhomirov@73: String repo = "/temp/hg/hello/.hg/"; tikhomirov@73: String filename = "store/00changelog.i"; tikhomirov@22: // String filename = "store/data/hello.c.i"; tikhomirov@4: // String filename = "store/data/docs/readme.i"; tikhomirov@73: boolean dumpData = true; tikhomirov@88: if (args.length > 1) { tikhomirov@73: repo = args[0]; tikhomirov@73: filename = args[1]; tikhomirov@88: dumpData = args.length > 2 ? "dumpData".equals(args[2]) : false; tikhomirov@73: } tikhomirov@0: // tikhomirov@376: DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File(repo, filename)))); tikhomirov@0: DataInput di = dis; tikhomirov@0: dis.mark(10); tikhomirov@0: int versionField = di.readInt(); tikhomirov@0: dis.reset(); tikhomirov@0: final int INLINEDATA = 1 << 16; tikhomirov@0: tikhomirov@376: final boolean inlineData = (versionField & INLINEDATA) != 0; tikhomirov@0: System.out.printf("%#8x, inline: %b\n", versionField, inlineData); tikhomirov@376: FileChannel dataStream = null; tikhomirov@376: if (!inlineData && dumpData) { tikhomirov@376: dataStream = new FileInputStream(new File(repo, filename.substring(0, filename.length()-2) + ".d")).getChannel(); tikhomirov@376: } tikhomirov@73: System.out.println("Index Offset Flags Packed Actual Base Rev Link Rev Parent1 Parent2 nodeid"); tikhomirov@376: int entryIndex = 0; tikhomirov@0: while (dis.available() > 0) { tikhomirov@0: long l = di.readLong(); tikhomirov@376: long offset = entryIndex == 0 ? 0 : (l >>> 16); tikhomirov@0: int flags = (int) (l & 0X0FFFF); tikhomirov@0: int compressedLen = di.readInt(); tikhomirov@0: int actualLen = di.readInt(); tikhomirov@0: int baseRevision = di.readInt(); tikhomirov@0: int linkRevision = di.readInt(); tikhomirov@0: int parent1Revision = di.readInt(); tikhomirov@0: int parent2Revision = di.readInt(); tikhomirov@0: byte[] buf = new byte[32]; tikhomirov@0: di.readFully(buf, 12, 20); tikhomirov@168: dis.skipBytes(12); tikhomirov@168: // CAN'T USE skip() here without extra precautions. E.g. I ran into situation when tikhomirov@168: // buffer was 8192 and BufferedInputStream was at position 8182 before attempt to skip(12). tikhomirov@168: // BIS silently skips available bytes and leaves me two extra bytes that ruin the rest of the code. tikhomirov@376: System.out.printf("%4d:%14d %6X %10d %10d %10d %10d %8d %8d %040x\n", entryIndex, offset, flags, compressedLen, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, new BigInteger(buf)); tikhomirov@376: String resultString; tikhomirov@376: byte[] data = new byte[compressedLen]; tikhomirov@0: if (inlineData) { tikhomirov@0: di.readFully(data); tikhomirov@376: } else if (dumpData) { tikhomirov@376: dataStream.position(offset); tikhomirov@376: dataStream.read(ByteBuffer.wrap(data)); tikhomirov@376: } tikhomirov@376: if (dumpData) { tikhomirov@376: if (compressedLen == 0) { tikhomirov@376: resultString = ""; tikhomirov@3: } else { tikhomirov@376: if (data[0] == 0x78 /* 'x' */) { tikhomirov@376: Inflater zlib = new Inflater(); tikhomirov@376: zlib.setInput(data, 0, compressedLen); tikhomirov@376: byte[] result = new byte[actualLen*2]; tikhomirov@376: int resultLen = zlib.inflate(result); tikhomirov@376: zlib.end(); tikhomirov@376: resultString = new String(result, 0, resultLen, "UTF-8"); tikhomirov@376: } else if (data[0] == 0x75 /* 'u' */) { tikhomirov@376: resultString = new String(data, 1, data.length - 1, "UTF-8"); tikhomirov@376: } else { tikhomirov@376: resultString = new String(data); tikhomirov@376: } tikhomirov@3: } tikhomirov@376: System.out.println(resultString); tikhomirov@0: } tikhomirov@376: entryIndex++; tikhomirov@0: } tikhomirov@0: dis.close(); tikhomirov@376: if (dataStream != null) { tikhomirov@376: dataStream.close(); tikhomirov@376: } tikhomirov@0: // tikhomirov@0: } tikhomirov@0: }