001
014
015 package com.liferay.portal.kernel.io.delta;
016
017 import java.io.IOException;
018
019 import java.nio.ByteBuffer;
020 import java.nio.channels.FileChannel;
021 import java.nio.channels.WritableByteChannel;
022
023
026 public class Patcher {
027
028 public void patch(
029 FileChannel originalFileChannel,
030 WritableByteChannel patchedWritableByteChannel,
031 ByteChannelReader deltaByteChannelReader)
032 throws IOException {
033
034 deltaByteChannelReader.resizeBuffer(5);
035
036 ByteBuffer deltaByteBuffer = deltaByteChannelReader.getBuffer();
037
038 deltaByteChannelReader.ensureData(5);
039
040 if (DeltaUtil.PROTOCOL_VERSION != deltaByteBuffer.get()) {
041 throw new IOException("Unknown protocol version");
042 }
043
044 int blockLength = deltaByteBuffer.getInt();
045
046 deltaByteChannelReader.resizeBuffer(
047 blockLength * DeltaUtil.BUFFER_FACTOR + 5);
048
049 deltaByteBuffer = deltaByteChannelReader.getBuffer();
050
051 while (true) {
052 deltaByteChannelReader.ensureData(1);
053
054 byte key = deltaByteBuffer.get();
055
056 if (key == DeltaUtil.REFERENCE_RANGE_KEY) {
057 deltaByteChannelReader.ensureData(9);
058
059 int firstBlockNumber = deltaByteBuffer.getInt();
060 int lastBlockNumber = deltaByteBuffer.getInt();
061
062 long position = firstBlockNumber * (long)blockLength;
063 long length =
064 (lastBlockNumber - firstBlockNumber + 1) *
065 (long)blockLength;
066
067 transfer(
068 originalFileChannel, patchedWritableByteChannel, position,
069 length);
070 }
071 else if (key == DeltaUtil.REFERENCE_KEY) {
072 deltaByteChannelReader.ensureData(4);
073
074 int blockNumber = deltaByteBuffer.getInt();
075
076 long position = blockNumber * (long)blockLength;
077
078 transfer(
079 originalFileChannel, patchedWritableByteChannel, position,
080 blockLength);
081 }
082 else if (key == DeltaUtil.DATA_KEY) {
083 deltaByteChannelReader.ensureData(4);
084
085 int length = deltaByteBuffer.getInt();
086
087 deltaByteChannelReader.ensureData(length);
088
089 int oldLimit = deltaByteBuffer.limit();
090
091 deltaByteBuffer.limit(deltaByteBuffer.position() + length);
092
093 patchedWritableByteChannel.write(deltaByteBuffer);
094
095 deltaByteBuffer.limit(oldLimit);
096 }
097 else if (key == DeltaUtil.EOF_KEY) {
098 return;
099 }
100 else {
101 throw new IOException("Invalid key");
102 }
103 }
104 }
105
106 protected void transfer(
107 FileChannel source, WritableByteChannel destination, long position,
108 long length)
109 throws IOException {
110
111 if (length > _NATIVE_TRANSFER_THRESHOLD) {
112 source.transferTo(position, length, destination);
113 }
114 else {
115 _transferByteBuffer.clear();
116 _transferByteBuffer.limit((int)length);
117
118 source.read(_transferByteBuffer, position);
119
120 _transferByteBuffer.flip();
121
122 destination.write(_transferByteBuffer);
123 }
124 }
125
126 private static final int _NATIVE_TRANSFER_THRESHOLD = 1000000;
127
128 private ByteBuffer _transferByteBuffer = ByteBuffer.allocate(
129 _NATIVE_TRANSFER_THRESHOLD);
130
131 }