view src/com/tmate/hgkit/console/Main.java @ 2:08db726a0fb7

Shaping out low-level Hg structures
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Sun, 19 Dec 2010 05:41:31 +0100
parents dbd663faec1f
children 24bb4f365164
line wrap: on
line source
package com.tmate.hgkit.console;

import java.io.BufferedInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import com.tmate.hgkit.ll.Changeset;

/**
 * 
 * @author artem
 */
public class Main {

	public static void main(String[] args) throws Exception {
		LinkedList<Changeset> changelog = new LinkedList<Changeset>();
		//
		DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("/temp/hg/hello/" + ".hg/store/00changelog.i"))));
		DataInput di = dis;
		dis.mark(10);
		int versionField = di.readInt();
		dis.reset();
		final int INLINEDATA = 1 << 16;
		
		boolean inlineData = (versionField & INLINEDATA) != 0;
		System.out.printf("%#8x, inline: %b\n", versionField, inlineData);
		System.out.println("\tOffset\tFlags\tPacked\t  Actual\tBase Rev    Link Rev\tParent1\tParent2\tnodeid");
		int entryCount = 0;
		while (dis.available() > 0) {
			long l = di.readLong();
			long offset = l >>> 16;
			int flags = (int) (l & 0X0FFFF);
			int compressedLen = di.readInt();
			int actualLen = di.readInt();
			int baseRevision = di.readInt();
			int linkRevision = di.readInt();
			int parent1Revision = di.readInt();
			int parent2Revision = di.readInt();
			byte[] buf = new byte[32];
			di.readFully(buf, 12, 20);
			dis.skip(12);
			System.out.printf("%14d %6X %10d %10d %10d %10d %8d %8d     %040x\n", offset, flags, compressedLen, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, new BigInteger(buf));
			if (inlineData) {
				byte[] data = new byte[compressedLen];
				di.readFully(data);
				if (data[0] == 0x78 /* 'x' */) {
					Inflater zlib = new Inflater();
					zlib.setInput(data, 0, compressedLen);
					byte[] result = new byte[actualLen*2];
					int resultLen = zlib.inflate(result);
					zlib.end();
					if (resultLen != actualLen) {
						System.err.printf("Expected:%d, decomressed to:%d bytes\n", actualLen, resultLen);
					}
					String resultString;
					if (baseRevision != entryCount) {
						// this is a patch
						byte[] baseRevContent = changelog.get(baseRevision).rawData;
						LinkedList<PatchRecord> bins = new LinkedList<PatchRecord>();
						int p1, p2, len, patchElementIndex = 0;
						do {
							final int x = patchElementIndex;
							p1 = (result[x] << 24) | (result[x+1] << 16) | (result[x+2] << 8) | result[x+3];
							p2 = (result[x+4] << 24) | (result[x+5] << 16) | (result[x+6] << 8) | result[x+7];
							len = (result[x+8] << 24) | (result[x+9] << 16) | (result[x+10] << 8) | result[x+11];
							System.out.printf("%4d %4d %4d\n", p1, p2, len);
							patchElementIndex += 12 + len;
							bins.add(new PatchRecord(p1, p2, len, result, x+12));
						} while (patchElementIndex < resultLen);
						// 
						result = apply(baseRevContent, bins);
						resultLen = result.length;
					}
					resultString = new String(result, 0, resultLen, "UTF-8");
					System.out.println(resultString);
					entryCount++;
					Changeset changeset = new Changeset();
					changeset.read(result, 0, resultLen);
					changelog.add(changeset);
				} // TODO else if uncompressed
			}
		}
		dis.close();
		//
		System.out.println("\n\n");
		System.out.println("====================>");
		for (Changeset cset : changelog) {
			System.out.println(">");
			cset.dump();
			System.out.println("<");
		}
	}


	// mpatch.c : apply()
	private static byte[] apply(byte[] baseRevisionContent, List<PatchRecord> patch) {
		byte[] tempBuf = new byte[512]; // XXX
		int last = 0, destIndex = 0;
		for (PatchRecord pr : patch) {
			System.arraycopy(baseRevisionContent, last, tempBuf, destIndex, pr.start-last);
			destIndex += pr.start - last;
			System.arraycopy(pr.data, 0, tempBuf, destIndex, pr.data.length);
			destIndex += pr.data.length;
			last = pr.end;
		}
		System.arraycopy(baseRevisionContent, last, tempBuf, destIndex, baseRevisionContent.length - last);
		destIndex += baseRevisionContent.length - last; // total length
		byte[] rv = new byte[destIndex];
		System.arraycopy(tempBuf, 0, rv, 0, destIndex);
		return rv;
	}

	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);
		}
	}
}