package com.novoda.downloadmanager.lib; import java.io.IOException; import java.io.InputStream; class TarTruncator implements DataTransferer { private static final byte BYTE_ZERO = 0x0; private final DataWriter dataWriter; public TarTruncator(DataWriter dataWriter) { this.dataWriter = dataWriter; } @Override public DownloadTask.State transferData(DownloadTask.State state, InputStream in) throws StopRequestException { DownloadTask.State newState = state; try { byte[] buffer = new byte[Constants.TAR_RECORD_SIZE]; byte[] previousBuffer = new byte[Constants.TAR_RECORD_SIZE]; byte[] swappingRef; int read; int previouslyRead = 0; while ((read = readRecord(in, buffer)) > 0) { newState = dataWriter.write(newState, previousBuffer, previouslyRead); swappingRef = previousBuffer; previousBuffer = buffer; buffer = swappingRef; previouslyRead = read; } newState = dataWriter.write(newState, previousBuffer, findMarkerToTruncateEof(previousBuffer, previouslyRead)); state.shouldPause = true; state.totalBytes = state.currentBytes; return newState; } catch (IOException e) { // It was doing the same thing in regular and exception cases return newState; } } private static int findMarkerToTruncateEof(byte[] buffer, int length) { int position = length; while (position >= Constants.TAR_BLOCK_SIZE && isRangeFullOfZeroes(buffer, position - Constants.TAR_BLOCK_SIZE, position)) { position = position - Constants.TAR_BLOCK_SIZE; } return position; } private static boolean isRangeFullOfZeroes(byte[] buffer, int start, int end) { for (int i = start; i < end; i++) { if (buffer[i] != BYTE_ZERO) { return false; } } return true; } private static int readRecord(InputStream fileInputStream, byte[] buffer) throws IOException { int read = 0; int readLast; while (read < Constants.TAR_RECORD_SIZE) { readLast = fileInputStream.read(buffer, read, Constants.TAR_RECORD_SIZE - read); if (readLast == Constants.NO_BYTES_READ) { return read; } read += readLast; } return read; } }