Annotations added, warnings removed
This commit is contained in:
parent
a37e5328d7
commit
ac585ac926
|
@ -22,6 +22,8 @@
|
|||
|
||||
package no.nordicsemi.android.dfu.internal;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
|
@ -31,13 +33,15 @@ import java.io.InputStream;
|
|||
import no.nordicsemi.android.dfu.internal.exception.HexFileValidationException;
|
||||
|
||||
/**
|
||||
* Reads the binary content from the HEX file using IntelHex standard: http://www.interlog.com/~speff/usefulinfo/Hexfrmt.pdf.
|
||||
* Reads the binary content from the HEX file using IntelHex standard:
|
||||
* http://www.interlog.com/~speff/usefulinfo/Hexfrmt.pdf.
|
||||
* Truncates the HEX file from all meta data and returns only the BIN content.
|
||||
* <p>
|
||||
* In nRF51 chips memory a SoftDevice starts at address 0x1000. From 0x0000 to 0x1000 there is MBR sector (since SoftDevice 7.0.0) which should not be transmitted using DFU. Therefore this class skips
|
||||
* all data from addresses below 0x1000.
|
||||
* </p>
|
||||
* In nRF51 chips memory a SoftDevice starts at address 0x1000. From 0x0000 to 0x1000 there is
|
||||
* MBR sector (since SoftDevice 7.0.0) which should not be transmitted using DFU. Therefore this
|
||||
* class skips all data from addresses below 0x1000.
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public class HexInputStream extends FilterInputStream {
|
||||
private final int LINE_LENGTH = 128;
|
||||
|
||||
|
@ -50,18 +54,18 @@ public class HexInputStream extends FilterInputStream {
|
|||
private final int MBRSize;
|
||||
|
||||
/**
|
||||
* Creates the HEX Input Stream. The constructor calculates the size of the BIN content which is available through {@link #sizeInBytes()}. If HEX file is invalid then the bin size is 0.
|
||||
*
|
||||
* @param in
|
||||
* the input stream to read from
|
||||
* @param mbrSize
|
||||
* The MBR (Master Boot Record) size in bytes. Data with addresses below than number will be trimmed and not transferred to DFU target.
|
||||
* @throws HexFileValidationException
|
||||
* if HEX file is invalid. F.e. there is no semicolon (':') on the beginning of each line.
|
||||
* @throws java.io.IOException
|
||||
* if the stream is closed or another IOException occurs.
|
||||
* Creates the HEX Input Stream. The constructor calculates the size of the BIN content which
|
||||
* is available through {@link #sizeInBytes()}. If HEX file is invalid then the bin size is 0.
|
||||
*
|
||||
* @param in the input stream to read from.
|
||||
* @param mbrSize the MBR (Master Boot Record) size in bytes. Data with addresses below than
|
||||
* number will be trimmed and not transferred to DFU target.
|
||||
* @throws HexFileValidationException if HEX file is invalid, e.g. there is no semicolon (':')
|
||||
* on the beginning of each line.
|
||||
* @throws IOException if the stream is closed or another IOException occurs.
|
||||
*/
|
||||
public HexInputStream(final InputStream in, final int mbrSize) throws HexFileValidationException, IOException {
|
||||
public HexInputStream(@NonNull final InputStream in, final int mbrSize)
|
||||
throws HexFileValidationException, IOException {
|
||||
super(new BufferedInputStream(in));
|
||||
this.localBuf = new byte[LINE_LENGTH];
|
||||
this.localPos = LINE_LENGTH; // we are at the end of the local buffer, new one must be obtained
|
||||
|
@ -72,7 +76,19 @@ public class HexInputStream extends FilterInputStream {
|
|||
this.available = calculateBinSize(mbrSize);
|
||||
}
|
||||
|
||||
public HexInputStream(final byte[] data, final int mbrSize) throws HexFileValidationException, IOException {
|
||||
/**
|
||||
* Creates the HEX Input Stream. The constructor calculates the size of the BIN content which
|
||||
* is available through {@link #sizeInBytes()}. If HEX file is invalid then the bin size is 0.
|
||||
*
|
||||
* @param data the input stream to read from.
|
||||
* @param mbrSize the MBR (Master Boot Record) size in bytes. Data with addresses below than
|
||||
* * number will be trimmed and not transferred to DFU target.
|
||||
* @throws HexFileValidationException if HEX file is invalid, e.g. there is no semicolon (':')
|
||||
* on the beginning of each line.
|
||||
* @throws IOException if the stream is closed or another IOException occurs.
|
||||
*/
|
||||
public HexInputStream(@NonNull final byte[] data, final int mbrSize)
|
||||
throws HexFileValidationException, IOException {
|
||||
super(new ByteArrayInputStream(data));
|
||||
this.localBuf = new byte[LINE_LENGTH];
|
||||
this.localPos = LINE_LENGTH; // we are at the end of the local buffer, new one must be obtained
|
||||
|
@ -83,6 +99,7 @@ public class HexInputStream extends FilterInputStream {
|
|||
this.available = calculateBinSize(mbrSize);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private int calculateBinSize(final int mbrSize) throws IOException {
|
||||
int binSize = 0;
|
||||
final InputStream in = this.in;
|
||||
|
@ -100,50 +117,52 @@ public class HexInputStream extends FilterInputStream {
|
|||
offset = readAddress(in);// reading the offset
|
||||
type = readByte(in); // reading the line type
|
||||
switch (type) {
|
||||
case 0x01:
|
||||
// end of file
|
||||
return binSize;
|
||||
case 0x04: {
|
||||
// extended linear address record
|
||||
/*
|
||||
* The HEX file may contain jump to different addresses. The MSB of LBA (Linear Base Address) is given using the line type 4.
|
||||
* We only support files where bytes are located together, no jumps are allowed. Therefore the newULBA may be only lastULBA + 1 (or any, if this is the first line of the HEX)
|
||||
*/
|
||||
final int newULBA = readAddress(in);
|
||||
if (binSize > 0 && newULBA != (lastBaseAddress >> 16) + 1)
|
||||
case 0x01:
|
||||
// end of file
|
||||
return binSize;
|
||||
lastBaseAddress = newULBA << 16;
|
||||
skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
case 0x02: {
|
||||
// extended segment address record
|
||||
final int newSBA = readAddress(in) << 4;
|
||||
if (binSize > 0 && (newSBA >> 16) != (lastBaseAddress >> 16) + 1)
|
||||
return binSize;
|
||||
lastBaseAddress = newSBA;
|
||||
skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
case 0x00:
|
||||
// data type line
|
||||
lastAddress = lastBaseAddress + offset;
|
||||
if (lastAddress >= mbrSize) // we must skip all data from below last MBR address (default 0x1000) as those are the MBR. The Soft Device starts at the end of MBR (0x1000), the app and bootloader farther more
|
||||
binSize += lineSize;
|
||||
// no break!
|
||||
default:
|
||||
final long toBeSkipped = lineSize * 2 /* 2 hex per one byte */+ 2 /* check sum */;
|
||||
skip(in, toBeSkipped);
|
||||
break;
|
||||
}
|
||||
// skip end of line
|
||||
while (true) {
|
||||
b = in.read();
|
||||
|
||||
if (b != '\n' && b != '\r') {
|
||||
case 0x04: {
|
||||
// extended linear address record
|
||||
/*
|
||||
* The HEX file may contain jump to different addresses.
|
||||
* The MSB of LBA (Linear Base Address) is given using the line type 4.
|
||||
* We only support files where bytes are located together, no jumps are
|
||||
* allowed. Therefore the newULBA may be only lastULBA + 1 (or any,
|
||||
* if this is the first line of the HEX)
|
||||
*/
|
||||
final int newULBA = readAddress(in);
|
||||
if (binSize > 0 && newULBA != (lastBaseAddress >> 16) + 1)
|
||||
return binSize;
|
||||
lastBaseAddress = newULBA << 16;
|
||||
skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
case 0x02: {
|
||||
// extended segment address record
|
||||
final int newSBA = readAddress(in) << 4;
|
||||
if (binSize > 0 && (newSBA >> 16) != (lastBaseAddress >> 16) + 1)
|
||||
return binSize;
|
||||
lastBaseAddress = newSBA;
|
||||
skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
case 0x00:
|
||||
// data type line
|
||||
lastAddress = lastBaseAddress + offset;
|
||||
// we must skip all data from below last MBR address (default 0x1000)
|
||||
// as those are the MBR. The Soft Device starts at the end of MBR (0x1000),
|
||||
// the app and bootloader farther more
|
||||
if (lastAddress >= mbrSize)
|
||||
binSize += lineSize;
|
||||
// no break!
|
||||
default:
|
||||
final long toBeSkipped = lineSize * 2 /* 2 hex per one byte */ + 2 /* check sum */;
|
||||
skip(in, toBeSkipped);
|
||||
break;
|
||||
}
|
||||
// skip end of line
|
||||
do {
|
||||
b = in.read();
|
||||
} while (b == '\n' || b == '\r');
|
||||
}
|
||||
} finally {
|
||||
in.reset();
|
||||
|
@ -160,9 +179,8 @@ public class HexInputStream extends FilterInputStream {
|
|||
*
|
||||
* @param buffer buffer to be filled
|
||||
* @return the size of the buffer
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public int readPacket(byte[] buffer) throws HexFileValidationException, IOException {
|
||||
public int readPacket(@NonNull byte[] buffer) throws IOException {
|
||||
int i = 0;
|
||||
while (i < buffer.length) {
|
||||
if (localPos < size) {
|
||||
|
@ -178,23 +196,23 @@ public class HexInputStream extends FilterInputStream {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
public int read() {
|
||||
throw new UnsupportedOperationException("Please, use readPacket() method instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
public int read(@NonNull byte[] buffer) throws IOException {
|
||||
return readPacket(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int count) throws IOException {
|
||||
public int read(@NonNull byte[] buffer, int offset, int count) {
|
||||
throw new UnsupportedOperationException("Please, use readPacket() method instead");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of bytes.
|
||||
*
|
||||
*
|
||||
* @return total number of bytes available
|
||||
*/
|
||||
public int sizeInBytes() {
|
||||
|
@ -202,25 +220,24 @@ public class HexInputStream extends FilterInputStream {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of packets with given size that are needed to get all available data
|
||||
*
|
||||
* @param packetSize
|
||||
* the maximum packet size
|
||||
* Returns the total number of packets with given size that are needed to get all
|
||||
* available data.
|
||||
*
|
||||
* @param packetSize the maximum packet size
|
||||
* @return the number of packets needed to get all the content
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public int sizeInPackets(final int packetSize) throws IOException {
|
||||
public int sizeInPackets(final int packetSize) {
|
||||
final int sizeInBytes = sizeInBytes();
|
||||
|
||||
return sizeInBytes / packetSize + ((sizeInBytes % packetSize) > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads new line from the input stream. Input stream must be a HEX file. The first line is always skipped.
|
||||
*
|
||||
* Reads new line from the input stream. Input stream must be a HEX file.
|
||||
* The first line is always skipped.
|
||||
*
|
||||
* @return the number of data bytes in the new line. 0 if end of file.
|
||||
* @throws java.io.IOException
|
||||
* if this stream is closed or another IOException occurs.
|
||||
* @throws java.io.IOException if this stream is closed or another IOException occurs.
|
||||
*/
|
||||
private int readLine() throws IOException {
|
||||
// end of file reached
|
||||
|
@ -234,23 +251,21 @@ public class HexInputStream extends FilterInputStream {
|
|||
int lineSize, type, offset;
|
||||
do {
|
||||
// skip end of line
|
||||
while (true) {
|
||||
do {
|
||||
b = in.read();
|
||||
pos++;
|
||||
|
||||
if (b != '\n' && b != '\r') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (b == '\n' || b == '\r');
|
||||
|
||||
/*
|
||||
* Each line starts with comma (':')
|
||||
* Data is written in HEX, so each 2 ASCII letters give one byte.
|
||||
* After the comma there is one byte (2 HEX signs) with line length (normally 10 -> 0x10 -> 16 bytes -> 32 HEX characters)
|
||||
* After the comma there is one byte (2 HEX signs) with line length
|
||||
* (normally 10 -> 0x10 -> 16 bytes -> 32 HEX characters)
|
||||
* After that there is a 4 byte of an address. This part may be skipped.
|
||||
* There is a packet type after the address (1 byte = 2 HEX characters). 00 is the valid data. Other values can be skipped when
|
||||
* converting to BIN file.
|
||||
* Then goes n bytes of data followed by 1 byte (2 HEX chars) of checksum, which is also skipped in BIN file.
|
||||
* There is a packet type after the address (1 byte = 2 HEX characters).
|
||||
* 00 is the valid data. Other values can be skipped when converting to BIN file.
|
||||
* Then goes n bytes of data followed by 1 byte (2 HEX chars) of checksum,
|
||||
* which is also skipped in BIN file.
|
||||
*/
|
||||
checkComma(b); // checking the comma at the beginning
|
||||
lineSize = readByte(in); // reading the length of the data in this line
|
||||
|
@ -262,41 +277,41 @@ public class HexInputStream extends FilterInputStream {
|
|||
|
||||
// if the line type is no longer data type (0x00), we've reached the end of the file
|
||||
switch (type) {
|
||||
case 0x00:
|
||||
// data type
|
||||
if (lastAddress + offset < MBRSize) { // skip MBR
|
||||
type = -1; // some other than 0
|
||||
pos += skip(in, lineSize * 2 /* 2 hex per one byte */+ 2 /* check sum */);
|
||||
case 0x00:
|
||||
// data type
|
||||
if (lastAddress + offset < MBRSize) { // skip MBR
|
||||
type = -1; // some other than 0
|
||||
pos += skip(in, lineSize * 2 /* 2 hex per one byte */ + 2 /* check sum */);
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
// end of file
|
||||
pos = -1;
|
||||
return 0;
|
||||
case 0x02: {
|
||||
// extended segment address
|
||||
final int address = readAddress(in) << 4;
|
||||
pos += 4;
|
||||
if (bytesRead > 0 && (address >> 16) != (lastAddress >> 16) + 1)
|
||||
return 0;
|
||||
lastAddress = address;
|
||||
pos += skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
// end of file
|
||||
pos = -1;
|
||||
return 0;
|
||||
case 0x02: {
|
||||
// extended segment address
|
||||
final int address = readAddress(in) << 4;
|
||||
pos += 4;
|
||||
if (bytesRead > 0 && (address >> 16) != (lastAddress >> 16) + 1)
|
||||
return 0;
|
||||
lastAddress = address;
|
||||
pos += skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
case 0x04: {
|
||||
// extended linear address
|
||||
final int address = readAddress(in);
|
||||
pos += 4;
|
||||
if (bytesRead > 0 && address != (lastAddress >> 16) + 1)
|
||||
return 0;
|
||||
lastAddress = address << 16;
|
||||
pos += skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
final long toBeSkipped = lineSize * 2 /* 2 hex per one byte */+ 2 /* check sum */;
|
||||
pos += skip(in, toBeSkipped);
|
||||
break;
|
||||
case 0x04: {
|
||||
// extended linear address
|
||||
final int address = readAddress(in);
|
||||
pos += 4;
|
||||
if (bytesRead > 0 && address != (lastAddress >> 16) + 1)
|
||||
return 0;
|
||||
lastAddress = address << 16;
|
||||
pos += skip(in, 2 /* check sum */);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
final long toBeSkipped = lineSize * 2 /* 2 hex per one byte */ + 2 /* check sum */;
|
||||
pos += skip(in, toBeSkipped);
|
||||
break;
|
||||
}
|
||||
} while (type != 0);
|
||||
|
||||
|
@ -326,22 +341,23 @@ public class HexInputStream extends FilterInputStream {
|
|||
throw new HexFileValidationException("Not a HEX file");
|
||||
}
|
||||
|
||||
private long skip(final InputStream in, final long offset) throws IOException {
|
||||
private long skip(@NonNull final InputStream in, final long offset) throws IOException {
|
||||
long skipped = in.skip(offset);
|
||||
// try to skip 2 times as skip(..) method does not guarantee to skip exactly given number of bytes
|
||||
// try to skip 2 times as skip(..) method does not guarantee to skip exactly
|
||||
// given number of bytes
|
||||
if (skipped < offset)
|
||||
skipped += in.skip(offset - skipped);
|
||||
return skipped;
|
||||
}
|
||||
|
||||
private int readByte(final InputStream in) throws IOException {
|
||||
private int readByte(@NonNull final InputStream in) throws IOException {
|
||||
final int first = asciiToInt(in.read());
|
||||
final int second = asciiToInt(in.read());
|
||||
|
||||
return first << 4 | second;
|
||||
}
|
||||
|
||||
private int readAddress(final InputStream in) throws IOException {
|
||||
private int readAddress(@NonNull final InputStream in) throws IOException {
|
||||
return readByte(in) << 8 | readByte(in);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue