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 java.util.zip.Deflater; tikhomirov@534: tikhomirov@618: import org.tmatesoft.hg.core.HgIOException; tikhomirov@534: import org.tmatesoft.hg.core.SessionContext; tikhomirov@628: import org.tmatesoft.hg.repo.HgRuntimeException; tikhomirov@534: import org.tmatesoft.hg.util.LogFacility.Severity; tikhomirov@530: tikhomirov@530: /** tikhomirov@530: * tikhomirov@530: * @author Artem Tikhomirov tikhomirov@530: * @author TMate Software Ltd. tikhomirov@530: */ tikhomirov@530: public class RevlogCompressor { tikhomirov@534: private final SessionContext ctx; tikhomirov@530: private final Deflater zip; tikhomirov@534: private DataSerializer.DataSource sourceData; tikhomirov@534: private int compressedLen; tikhomirov@530: tikhomirov@534: public RevlogCompressor(SessionContext sessionCtx) { tikhomirov@534: ctx = sessionCtx; tikhomirov@530: zip = new Deflater(); tikhomirov@530: } tikhomirov@530: tikhomirov@534: public void reset(DataSerializer.DataSource source) { tikhomirov@530: sourceData = source; tikhomirov@534: compressedLen = -1; tikhomirov@530: } tikhomirov@530: tikhomirov@534: // out stream is not closed! tikhomirov@628: public int writeCompressedData(DataSerializer out) throws HgIOException, HgRuntimeException { tikhomirov@530: zip.reset(); tikhomirov@534: DeflaterDataSerializer dds = new DeflaterDataSerializer(out, zip, sourceData.serializeLength()); tikhomirov@534: sourceData.serialize(dds); tikhomirov@534: dds.finish(); tikhomirov@530: return zip.getTotalOut(); tikhomirov@530: } tikhomirov@530: tikhomirov@628: public int getCompressedLength() throws HgRuntimeException { tikhomirov@534: if (compressedLen != -1) { tikhomirov@534: return compressedLen; tikhomirov@530: } tikhomirov@534: Counter counter = new Counter(); tikhomirov@534: try { tikhomirov@534: compressedLen = writeCompressedData(counter); tikhomirov@534: assert counter.totalWritten == compressedLen; tikhomirov@534: return compressedLen; tikhomirov@618: } catch (HgIOException ex) { tikhomirov@534: // can't happen provided we write to our stream that does nothing but byte counting tikhomirov@534: ctx.getLog().dump(getClass(), Severity.Error, ex, "Failed estimating compressed length of revlog data"); tikhomirov@534: return counter.totalWritten; // use best known value so far tikhomirov@534: } tikhomirov@534: } tikhomirov@534: tikhomirov@534: private static class Counter extends DataSerializer { tikhomirov@534: public int totalWritten = 0; tikhomirov@534: tikhomirov@618: public void writeByte(byte... values) throws HgIOException { tikhomirov@534: totalWritten += values.length; tikhomirov@534: } tikhomirov@534: tikhomirov@618: public void writeInt(int... values) throws HgIOException { tikhomirov@534: totalWritten += 4 * values.length; tikhomirov@534: } tikhomirov@534: tikhomirov@618: public void write(byte[] data, int offset, int length) throws HgIOException { tikhomirov@534: totalWritten += length; tikhomirov@534: } tikhomirov@530: } tikhomirov@530: }