# HG changeset patch # User Artem Tikhomirov # Date 1294957899 -3600 # Node ID 205f9b59b4009c612fe61ccdb85a4a880234efbc # Parent 6061aa826a9e5562541360d7a5561dd57bf7e9c6 Strip parsing logic out from console frontend diff -r 6061aa826a9e -r 205f9b59b400 src/com/tmate/hgkit/console/Bundle.java --- a/src/com/tmate/hgkit/console/Bundle.java Thu Jan 13 20:02:21 2011 +0100 +++ b/src/com/tmate/hgkit/console/Bundle.java Thu Jan 13 23:31:39 2011 +0100 @@ -4,14 +4,11 @@ package com.tmate.hgkit.console; import java.io.File; -import java.util.LinkedList; -import com.tmate.hgkit.fs.DataAccess; import com.tmate.hgkit.fs.DataAccessProvider; -import com.tmate.hgkit.ll.Nodeid; +import com.tmate.hgkit.ll.HgBundle; /** - * @see http://mercurial.selenic.com/wiki/BundleFormat * * @author artem */ @@ -20,49 +17,7 @@ public static void main(String[] args) throws Exception { File bundleFile = new File("/temp/hg/hg-bundle-a78c980749e3.tmp"); DataAccessProvider dap = new DataAccessProvider(); - DataAccess da = dap.create(bundleFile); - try { - LinkedList names = new LinkedList(); - if (!da.isEmpty()) { - System.out.println("Changelog group"); - readGroup(da); - System.out.println("Manifest group"); - readGroup(da); - while (!da.isEmpty()) { - int fnameLen = da.readInt(); - if (fnameLen <= 4) { - break; // null chunk, the last one. - } - byte[] fname = new byte[fnameLen - 4]; - da.readBytes(fname, 0, fname.length); - names.add(new String(fname)); - System.out.println(names.getLast()); - readGroup(da); - } - } - System.out.println(names.size()); - for (String s : names) { - System.out.println(s); - } - } finally { - da.done(); - } - } - - private static void readGroup(DataAccess da) throws Exception { - int len = da.readInt(); - while (len > 4 && !da.isEmpty()) { - byte[] nb = new byte[80]; - da.readBytes(nb, 0, 80); - Nodeid node = Nodeid.fromBinary(nb, 0); - Nodeid p1 = Nodeid.fromBinary(nb, 20); - Nodeid p2 = Nodeid.fromBinary(nb, 40); - Nodeid cs = Nodeid.fromBinary(nb, 60); - byte[] data = new byte[len-84]; - da.readBytes(data, 0, data.length); - System.out.printf("%6d %s %s %s %s\n", len, node, p1, p2, cs); - System.out.println(new String(data)); - len = da.isEmpty() ? 0 : da.readInt(); - } + HgBundle hgBundle = new HgBundle(dap, bundleFile); + hgBundle.read(); } } diff -r 6061aa826a9e -r 205f9b59b400 src/com/tmate/hgkit/ll/HgBundle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/tmate/hgkit/ll/HgBundle.java Thu Jan 13 23:31:39 2011 +0100 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011 Artem Tikhomirov + */ +package com.tmate.hgkit.ll; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +import com.tmate.hgkit.fs.DataAccess; +import com.tmate.hgkit.fs.DataAccessProvider; + +/** + * @see http://mercurial.selenic.com/wiki/BundleFormat + * + * @author artem + */ +public class HgBundle { + + private final File bundleFile; + private final DataAccessProvider accessProvider; + + public HgBundle(DataAccessProvider dap, File bundle) { + accessProvider = dap; + bundleFile = bundle; + } + + public void read() throws IOException { + DataAccess da = accessProvider.create(bundleFile); + try { + LinkedList names = new LinkedList(); + if (!da.isEmpty()) { + System.out.println("Changelog group"); + List changelogGroup = readGroup(da); + for (GroupElement ge : changelogGroup) { + System.out.printf(" %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cs(), ge.patches.size()); + } + System.out.println("Manifest group"); + List manifestGroup = readGroup(da); + for (GroupElement ge : manifestGroup) { + System.out.printf(" %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cs(), ge.patches.size()); + } + while (!da.isEmpty()) { + int fnameLen = da.readInt(); + if (fnameLen <= 4) { + break; // null chunk, the last one. + } + byte[] fname = new byte[fnameLen - 4]; + da.readBytes(fname, 0, fname.length); + names.add(new String(fname)); + List fileGroup = readGroup(da); + System.out.println(names.getLast()); + for (GroupElement ge : fileGroup) { + System.out.printf(" %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cs(), ge.patches.size()); + } + } + } + System.out.println(names.size()); + for (String s : names) { + System.out.println(s); + } + } finally { + da.done(); + } + } + + private static List readGroup(DataAccess da) throws IOException { + int len = da.readInt(); + LinkedList rv = new LinkedList(); + while (len > 4 && !da.isEmpty()) { + byte[] nb = new byte[80]; + da.readBytes(nb, 0, 80); + int dataLength = len-84; + LinkedList patches = new LinkedList(); + while (dataLength > 0) { + RevlogStream.PatchRecord pr = RevlogStream.PatchRecord.read(da); + patches.add(pr); + dataLength -= pr.len + 12; + } + rv.add(new GroupElement(nb, patches)); + len = da.isEmpty() ? 0 : da.readInt(); + } + return rv; + } + + static class GroupElement { + private byte[] header; // byte[80] takes 120 bytes, 4 Nodeids - 192 + private List patches; + + GroupElement(byte[] fourNodeids, List patchList) { + assert fourNodeids != null && fourNodeids.length == 80; + // patchList.size() > 0 + header = fourNodeids; + patches = patchList; + } + public Nodeid node() { + return Nodeid.fromBinary(header, 0); + } + public Nodeid firstParent() { + return Nodeid.fromBinary(header, 20); + } + public Nodeid secondParent() { + return Nodeid.fromBinary(header, 40); + } + public Nodeid cs() { + return Nodeid.fromBinary(header, 60); + } + + } +} diff -r 6061aa826a9e -r 205f9b59b400 src/com/tmate/hgkit/ll/RevlogStream.java --- a/src/com/tmate/hgkit/ll/RevlogStream.java Thu Jan 13 20:02:21 2011 +0100 +++ b/src/com/tmate/hgkit/ll/RevlogStream.java Thu Jan 13 23:31:39 2011 +0100 @@ -190,12 +190,9 @@ LinkedList patches = new LinkedList(); int patchElementIndex = 0; do { - final int x = patchElementIndex; // shorthand - int p1 = ((data[x] & 0xFF)<< 24) | ((data[x+1] & 0xFF) << 16) | ((data[x+2] & 0xFF) << 8) | (data[x+3] & 0xFF); - int p2 = ((data[x+4] & 0xFF) << 24) | ((data[x+5] & 0xFF) << 16) | ((data[x+6] & 0xFF) << 8) | (data[x+7] & 0xFF); - int len = ((data[x+8] & 0xFF) << 24) | ((data[x+9] & 0xFF) << 16) | ((data[x+10] & 0xFF) << 8) | (data[x+11] & 0xFF); - patchElementIndex += 12 + len; - patches.add(new PatchRecord(p1, p2, len, data, x+12)); + PatchRecord pr = PatchRecord.read(data, patchElementIndex); + patches.add(pr); + patchElementIndex += 12 + pr.len; } while (patchElementIndex < data.length); // byte[] baseRevContent = lastData; @@ -305,16 +302,37 @@ } // @see http://mercurial.selenic.com/wiki/BundleFormat, in Changelog group description - static class PatchRecord { // copy of struct frag from mpatch.c + /*package-local*/ static class PatchRecord { // copy of struct frag from mpatch.c int start, end, len; byte[] data; - public PatchRecord(int p1, int p2, int len, byte[] src, int srcOffset) { - start = p1; - end = p2; - this.len = len; - data = new byte[len]; - System.arraycopy(src, srcOffset, data, 0, len); + // TODO consider PatchRecord that only records data position (absolute in data source), and acquires data as needed + private PatchRecord(int p1, int p2, int length, byte[] src) { + start = p1; + end = p2; + len = length; + data = src; } + + /*package-local*/ static PatchRecord read(byte[] data, int offset) { + final int x = offset; // shorthand + int p1 = ((data[x] & 0xFF)<< 24) | ((data[x+1] & 0xFF) << 16) | ((data[x+2] & 0xFF) << 8) | (data[x+3] & 0xFF); + int p2 = ((data[x+4] & 0xFF) << 24) | ((data[x+5] & 0xFF) << 16) | ((data[x+6] & 0xFF) << 8) | (data[x+7] & 0xFF); + int len = ((data[x+8] & 0xFF) << 24) | ((data[x+9] & 0xFF) << 16) | ((data[x+10] & 0xFF) << 8) | (data[x+11] & 0xFF); + byte[] dataCopy = new byte[len]; + System.arraycopy(data, x+12, dataCopy, 0, len); + return new PatchRecord(p1, p2, len, dataCopy); + } + + /*package-local*/ static PatchRecord read(DataAccess da) throws IOException { + int p1 = da.readInt(); + int p2 = da.readInt(); + int len = da.readInt(); + byte[] src = new byte[len]; + da.readBytes(src, 0, len); + return new PatchRecord(p1, p2, len, src); + } + + } }