tikhomirov@530: /* tikhomirov@530: * Copyright (c) 2013 TMate Software Ltd tikhomirov@530: * tikhomirov@530: * This program is free software; you can redistribute it and/or modify tikhomirov@530: * it under the terms of the GNU General Public License as published by tikhomirov@530: * the Free Software Foundation; version 2 of the License. tikhomirov@530: * tikhomirov@530: * This program is distributed in the hope that it will be useful, tikhomirov@530: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@530: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@530: * GNU General Public License for more details. tikhomirov@530: * tikhomirov@530: * For information on how to redistribute this software under tikhomirov@530: * the terms of a license other than GNU General Public License tikhomirov@530: * contact TMate Software at support@hg4j.com tikhomirov@530: */ tikhomirov@530: package org.tmatesoft.hg.internal; tikhomirov@530: tikhomirov@530: import static org.tmatesoft.hg.internal.Internals.REVLOGV1_RECORD_SIZE; tikhomirov@530: tikhomirov@530: import java.io.IOException; tikhomirov@530: import java.io.OutputStream; tikhomirov@530: import java.nio.ByteBuffer; tikhomirov@530: tikhomirov@530: import org.tmatesoft.hg.core.Nodeid; tikhomirov@530: tikhomirov@530: /** tikhomirov@530: * tikhomirov@532: * TODO check if index is too big and split into index+data tikhomirov@532: * tikhomirov@530: * @author Artem Tikhomirov tikhomirov@530: * @author TMate Software Ltd. tikhomirov@530: */ tikhomirov@530: public class RevlogStreamWriter { tikhomirov@530: tikhomirov@530: tikhomirov@530: public static class HeaderWriter { tikhomirov@530: private final ByteBuffer header; tikhomirov@530: private final boolean isInline; tikhomirov@530: private long offset; tikhomirov@530: private int length, compressedLength; tikhomirov@530: private int baseRev, linkRev, p1, p2; tikhomirov@530: private Nodeid nodeid; tikhomirov@530: tikhomirov@530: public HeaderWriter(boolean inline) { tikhomirov@530: isInline = inline; tikhomirov@530: header = ByteBuffer.allocate(REVLOGV1_RECORD_SIZE); tikhomirov@530: } tikhomirov@530: tikhomirov@530: public HeaderWriter offset(long offset) { tikhomirov@530: this.offset = offset; tikhomirov@530: return this; tikhomirov@530: } tikhomirov@530: tikhomirov@532: public int baseRevision() { tikhomirov@532: return baseRev; tikhomirov@532: } tikhomirov@532: tikhomirov@530: public HeaderWriter baseRevision(int baseRevision) { tikhomirov@530: this.baseRev = baseRevision; tikhomirov@530: return this; tikhomirov@530: } tikhomirov@530: tikhomirov@530: public HeaderWriter length(int len, int compressedLen) { tikhomirov@530: this.length = len; tikhomirov@530: this.compressedLength = compressedLen; tikhomirov@530: return this; tikhomirov@530: } tikhomirov@530: tikhomirov@530: public HeaderWriter parents(int parent1, int parent2) { tikhomirov@530: p1 = parent1; tikhomirov@530: p2 = parent2; tikhomirov@530: return this; tikhomirov@530: } tikhomirov@530: tikhomirov@530: public HeaderWriter linkRevision(int linkRevision) { tikhomirov@530: this.linkRev = linkRevision; tikhomirov@530: return this; tikhomirov@530: } tikhomirov@530: tikhomirov@530: public HeaderWriter nodeid(Nodeid n) { tikhomirov@530: this.nodeid = n; tikhomirov@530: return this; tikhomirov@530: } tikhomirov@530: tikhomirov@530: public void write(OutputStream out) throws IOException { tikhomirov@530: header.clear(); tikhomirov@530: if (offset == 0) { tikhomirov@530: int version = 1 /* RevlogNG */; tikhomirov@530: if (isInline) { tikhomirov@530: final int INLINEDATA = 1 << 16; // FIXME extract constant tikhomirov@530: version |= INLINEDATA; tikhomirov@530: } tikhomirov@530: header.putInt(version); tikhomirov@530: header.putInt(0); tikhomirov@530: } else { tikhomirov@530: header.putLong(offset << 16); tikhomirov@530: } tikhomirov@530: header.putInt(compressedLength); tikhomirov@530: header.putInt(length); tikhomirov@530: header.putInt(baseRev); tikhomirov@530: header.putInt(linkRev); tikhomirov@530: header.putInt(p1); tikhomirov@530: header.putInt(p2); tikhomirov@530: header.put(nodeid.toByteArray()); tikhomirov@530: // assume 12 bytes left are zeros tikhomirov@530: out.write(header.array()); tikhomirov@530: tikhomirov@530: // regardless whether it's inline or separate data, tikhomirov@530: // offset field always represent cumulative compressedLength tikhomirov@530: // (while offset in the index file with inline==true differs by n*sizeof(header), where n is entry's position in the file) tikhomirov@530: offset += compressedLength; tikhomirov@530: } tikhomirov@530: } tikhomirov@530: tikhomirov@533: tikhomirov@533: private final DigestHelper dh = new DigestHelper(); tikhomirov@533: tikhomirov@533: public void addRevision(byte[] content, int linkRevision, int p1, int p2) { tikhomirov@533: Nodeid p1Rev = parent(p1); tikhomirov@533: Nodeid p2Rev = parent(p2); tikhomirov@533: byte[] revisionBytes = dh.sha1(p1Rev, p2Rev, content).asBinary(); tikhomirov@533: //final Nodeid revision = Nodeid.fromBinary(revisionBytes, 0); tikhomirov@533: // cache last revision (its delta and baseRev) tikhomirov@533: PatchGenerator pg = new PatchGenerator(); tikhomirov@533: byte[] prev = null; tikhomirov@533: Patch patch = pg.delta(prev, content); tikhomirov@533: byte[] patchContent; tikhomirov@533: // rest as in HgCloneCommand tikhomirov@533: } tikhomirov@533: tikhomirov@533: private Nodeid parent(int parentIndex) { tikhomirov@533: return null; tikhomirov@530: } tikhomirov@530: }