Adding CRC32 feature in Secure DFU, not completed.
This commit is contained in:
parent
7c82d575be
commit
09cb5f76eb
|
@ -31,6 +31,7 @@ import android.preference.PreferenceManager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
import no.nordicsemi.android.dfu.internal.exception.DeviceDisconnectedException;
|
import no.nordicsemi.android.dfu.internal.exception.DeviceDisconnectedException;
|
||||||
import no.nordicsemi.android.dfu.internal.exception.DfuException;
|
import no.nordicsemi.android.dfu.internal.exception.DfuException;
|
||||||
|
@ -255,12 +256,14 @@ import no.nordicsemi.android.dfu.internal.scanner.BootloaderScannerFactory;
|
||||||
* @throws DeviceDisconnectedException
|
* @throws DeviceDisconnectedException
|
||||||
* @throws UploadAbortedException
|
* @throws UploadAbortedException
|
||||||
*/
|
*/
|
||||||
protected void writeInitData(final BluetoothGattCharacteristic characteristic) throws DfuException, DeviceDisconnectedException, UploadAbortedException {
|
protected void writeInitData(final BluetoothGattCharacteristic characteristic, final CRC32 crc32) throws DfuException, DeviceDisconnectedException, UploadAbortedException {
|
||||||
try {
|
try {
|
||||||
byte[] data = new byte[20];
|
byte[] data = new byte[20];
|
||||||
int size;
|
int size;
|
||||||
while ((size = mInitPacketStream.read(data, 0, data.length)) != -1) {
|
while ((size = mInitPacketStream.read(data, 0, data.length)) != -1) {
|
||||||
writeInitPacket(characteristic, data, size);
|
writeInitPacket(characteristic, data, size);
|
||||||
|
if (crc32 != null)
|
||||||
|
crc32.update(data, 0, size);
|
||||||
}
|
}
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
loge("Error while reading Init packet file", e);
|
loge("Error while reading Init packet file", e);
|
||||||
|
|
|
@ -249,14 +249,13 @@ import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
||||||
int size;
|
int size;
|
||||||
try {
|
try {
|
||||||
size = initPacketStream.available();
|
size = initPacketStream.available();
|
||||||
} catch (final IOException e) {
|
} catch (final Exception e) {
|
||||||
size = 0;
|
size = 0;
|
||||||
// not possible
|
|
||||||
}
|
}
|
||||||
mInitPacketSizeInBytes = size;
|
mInitPacketSizeInBytes = size;
|
||||||
try {
|
try {
|
||||||
size = firmwareStream.available();
|
size = firmwareStream.available();
|
||||||
} catch (final IOException e) {
|
} catch (final Exception e) {
|
||||||
size = 0;
|
size = 0;
|
||||||
// not possible
|
// not possible
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,6 +416,10 @@ public abstract class DfuBaseService extends IntentService implements DfuProgres
|
||||||
* Thrown when the firmware file is not word-aligned. The firmware size must be dividable by 4 bytes.
|
* Thrown when the firmware file is not word-aligned. The firmware size must be dividable by 4 bytes.
|
||||||
*/
|
*/
|
||||||
public static final int ERROR_FILE_SIZE_INVALID = ERROR_MASK | 0x0C;
|
public static final int ERROR_FILE_SIZE_INVALID = ERROR_MASK | 0x0C;
|
||||||
|
/**
|
||||||
|
* Thrown when the received CRC does not match with the calculated one. The service will try 3 times to send the data, and if the CRC fails each time this error will be thrown.
|
||||||
|
*/
|
||||||
|
public static final int ERROR_CRC_ERROR = ERROR_MASK | 0x0D;
|
||||||
/**
|
/**
|
||||||
* Flag set when the DFU target returned a DFU error. Look for DFU specification to get error codes.
|
* Flag set when the DFU target returned a DFU error. Look for DFU specification to get error codes.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -47,7 +47,10 @@ import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
||||||
/** This method must return true if the device is compatible with this DFU implementation, false otherwise. */
|
/** This method must return true if the device is compatible with this DFU implementation, false otherwise. */
|
||||||
boolean hasRequiredCharacteristics(final BluetoothGatt gatt);
|
boolean hasRequiredCharacteristics(final BluetoothGatt gatt);
|
||||||
|
|
||||||
/** Initializes the DFU implementation and does some initial setting up. */
|
/**
|
||||||
|
* Initializes the DFU implementation and does some initial setting up.
|
||||||
|
* @return true if initialization was successful and the DFU process may begin, false to finish teh DFU service
|
||||||
|
*/
|
||||||
boolean initialize(final Intent intent, final BluetoothGatt gatt, final int fileType, final InputStream firmwareStream, final InputStream initPacketStream) throws DfuException, DeviceDisconnectedException, UploadAbortedException;
|
boolean initialize(final Intent intent, final BluetoothGatt gatt, final int fileType, final InputStream firmwareStream, final InputStream initPacketStream) throws DfuException, DeviceDisconnectedException, UploadAbortedException;
|
||||||
|
|
||||||
/** Performs the DFU process. */
|
/** Performs the DFU process. */
|
||||||
|
|
|
@ -521,7 +521,7 @@ import no.nordicsemi.android.error.LegacyDfuError;
|
||||||
writeOpCode(mControlPointCharacteristic, OP_CODE_INIT_DFU_PARAMS_START);
|
writeOpCode(mControlPointCharacteristic, OP_CODE_INIT_DFU_PARAMS_START);
|
||||||
|
|
||||||
logi("Sending " + mImageSizeInBytes + " bytes of init packet");
|
logi("Sending " + mImageSizeInBytes + " bytes of init packet");
|
||||||
writeInitData(mPacketCharacteristic);
|
writeInitData(mPacketCharacteristic, null);
|
||||||
|
|
||||||
logi("Sending the Initialize DFU Parameters COMPLETE (Op Code = 2, Value = 1)");
|
logi("Sending the Initialize DFU Parameters COMPLETE (Op Code = 2, Value = 1)");
|
||||||
writeOpCode(mControlPointCharacteristic, OP_CODE_INIT_DFU_PARAMS_COMPLETE);
|
writeOpCode(mControlPointCharacteristic, OP_CODE_INIT_DFU_PARAMS_COMPLETE);
|
||||||
|
|
|
@ -28,8 +28,11 @@ import android.bluetooth.BluetoothGattService;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
import no.nordicsemi.android.dfu.internal.exception.DeviceDisconnectedException;
|
import no.nordicsemi.android.dfu.internal.exception.DeviceDisconnectedException;
|
||||||
import no.nordicsemi.android.dfu.internal.exception.DfuException;
|
import no.nordicsemi.android.dfu.internal.exception.DfuException;
|
||||||
|
@ -139,6 +142,17 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
return dfuService != null;
|
return dfuService != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean initialize(final Intent intent, final BluetoothGatt gatt, final int fileType, final InputStream firmwareStream, final InputStream initPacketStream) throws DfuException, DeviceDisconnectedException, UploadAbortedException {
|
||||||
|
if (initPacketStream == null) {
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "The Init packet is required by this version DFU Bootloader");
|
||||||
|
mService.terminateConnection(gatt, DfuBaseService.ERROR_INIT_PACKET_REQUIRED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.initialize(intent, gatt, fileType, firmwareStream, initPacketStream);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasRequiredCharacteristics(final BluetoothGatt gatt) {
|
public boolean hasRequiredCharacteristics(final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService dfuService = gatt.getService(DFU_SERVICE_UUID);
|
final BluetoothGattService dfuService = gatt.getService(DFU_SERVICE_UUID);
|
||||||
|
@ -191,6 +205,7 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
// End
|
// End
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
final CRC32 crc32 = new CRC32(); // Used to calculate CRC32 of the Init packet
|
||||||
ObjectChecksum checksum;
|
ObjectChecksum checksum;
|
||||||
ObjectInfo info;
|
ObjectInfo info;
|
||||||
byte[] response;
|
byte[] response;
|
||||||
|
@ -206,35 +221,108 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
// Ignore this. DFU target will send an error if init packet is too large after sending the 'Create object' command
|
// Ignore this. DFU target will send an error if init packet is too large after sending the 'Create object' command
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Init packet is sent different way in this implementation than the firmware, and receiving PRNs is not implemented.
|
// Can we resume? If the offset obtained from the device is greater then zero we can compare it with the local init packet CRC
|
||||||
// This value might have been stored on the device, so we have to explicitly disable PRNs.
|
// and resume sending the init packet, or even skip sending it if the whole file was sent before.
|
||||||
logi("Disabling Packet Receipt Notifications (Op Code = 2, Value = 0)");
|
boolean skipSendingInitPacket = false;
|
||||||
setPacketReceiptNotifications(0);
|
boolean resumeSendingInitPacket = false;
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Packet Receipt Notif disabled (Op Code = 2, Value = 0)");
|
if (info.offset > 0) {
|
||||||
|
try {
|
||||||
|
// Read the same number of bytes from the current init packet to calculate local CRC32
|
||||||
|
final byte[] buffer = new byte[info.offset];
|
||||||
|
mInitPacketStream.read(buffer);
|
||||||
|
// Calculate the CRC32
|
||||||
|
crc32.update(buffer);
|
||||||
|
final int crc = (int) (crc32.getValue() & 0xFFFFFFFL);
|
||||||
|
|
||||||
// TODO resume uploading
|
if (info.CRC32 == crc) {
|
||||||
|
logi("Init packet CRC is the same");
|
||||||
|
if (info.offset == mInitPacketSizeInBytes) {
|
||||||
|
// The whole init packet was sent and it is equal to one we try to send now.
|
||||||
|
// There is no need to send it again. We may try to resume sending data.
|
||||||
|
logi("-> Whole Init packet was sent before");
|
||||||
|
skipSendingInitPacket = true;
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Command object match Init packet");
|
||||||
|
} else {
|
||||||
|
logi("-> " + info.offset + " bytes of Init packet were sent before");
|
||||||
|
resumeSendingInitPacket = true;
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Resuming sending Init packet...");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// A different Init packet was sent before, or the error occurred while sending.
|
||||||
|
// We have to send the while Init packet again.
|
||||||
|
mInitPacketStream.reset();
|
||||||
|
crc32.reset();
|
||||||
|
}
|
||||||
|
} catch (final IOException e) {
|
||||||
|
loge("Error while reading " + info.offset + " bytes from the init packet stream", e);
|
||||||
|
try {
|
||||||
|
// Go back to the beginning of the stream, we will send the whole init packet
|
||||||
|
mInitPacketStream.reset();
|
||||||
|
crc32.reset();
|
||||||
|
} catch (final IOException e1) {
|
||||||
|
loge("Error while resetting the init packet stream", e1);
|
||||||
|
mService.terminateConnection(gatt, DfuBaseService.ERROR_FILE_IO_EXCEPTION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the Init object
|
if (!skipSendingInitPacket) {
|
||||||
logi("Creating Init packet object (Op Code = 1, Type = 1, Size = " + mInitPacketSizeInBytes + ")");
|
// The Init packet is sent different way in this implementation than the firmware, and receiving PRNs is not implemented.
|
||||||
writeCreateRequest(OBJECT_COMMAND, mInitPacketSizeInBytes);
|
// This value might have been stored on the device, so we have to explicitly disable PRNs.
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Command object created");
|
logi("Disabling Packet Receipt Notifications (Op Code = 2, Value = 0)");
|
||||||
|
setPacketReceiptNotifications(0);
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Packet Receipt Notif disabled (Op Code = 2, Value = 0)");
|
||||||
|
|
||||||
// Write Init data to the Packet Characteristic
|
for (int i = 0; i <= 2; i++) {
|
||||||
logi("Sending " + mInitPacketSizeInBytes + " bytes of init packet...");
|
if (!resumeSendingInitPacket) {
|
||||||
writeInitData(mPacketCharacteristic);
|
// Create the Init object
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Command object sent");
|
logi("Creating Init packet object (Op Code = 1, Type = 1, Size = " + mInitPacketSizeInBytes + ")");
|
||||||
|
writeCreateRequest(OBJECT_COMMAND, mInitPacketSizeInBytes);
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Command object created");
|
||||||
|
}
|
||||||
|
// Write Init data to the Packet Characteristic
|
||||||
|
logi("Sending " + (mInitPacketSizeInBytes - info.offset) + " bytes of init packet...");
|
||||||
|
writeInitData(mPacketCharacteristic, crc32);
|
||||||
|
final int crc = (int) (crc32.getValue() & 0xFFFFFFFL);
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Command object sent (CRC = %08X)", crc));
|
||||||
|
|
||||||
// Calculate Checksum
|
// Calculate Checksum
|
||||||
logi("Sending Calculate Checksum command (Op Code = 3)");
|
logi("Sending Calculate Checksum command (Op Code = 3)");
|
||||||
checksum = readChecksum();
|
checksum = readChecksum();
|
||||||
// TODO validate
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32));
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32));
|
logi(String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32));
|
||||||
logi(String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32));
|
|
||||||
|
|
||||||
// Execute Init packet
|
if (crc != checksum.CRC32) {
|
||||||
logi("Executing init packet (Op Code = 4)");
|
if (i < 2) {
|
||||||
writeExecute();
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_WARNING, "CRC32 does not match! Retrying...(" + (i + 2) + "/3)");
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Command object executed");
|
logi("CRC32 does not match! Retrying...(" + (i + 2) + "/3)");
|
||||||
|
try {
|
||||||
|
// Go back to the beginning, we will send the whole Init packet again
|
||||||
|
resumeSendingInitPacket = false;
|
||||||
|
mInitPacketStream.reset();
|
||||||
|
crc32.reset();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
loge("Error while resetting the init packet stream", e);
|
||||||
|
mService.terminateConnection(gatt, DfuBaseService.ERROR_FILE_IO_EXCEPTION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loge("CRC32 does not match!");
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "CRC32 does not match!");
|
||||||
|
mService.terminateConnection(gatt, DfuBaseService.ERROR_CRC_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute Init packet
|
||||||
|
logi("Executing init packet (Op Code = 4)");
|
||||||
|
writeExecute();
|
||||||
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Command object executed");
|
||||||
|
}
|
||||||
|
|
||||||
// Send the number of packets of firmware before receiving a receipt notification
|
// Send the number of packets of firmware before receiving a receipt notification
|
||||||
final int numberOfPacketsBeforeNotification = mPacketsBeforeNotification;
|
final int numberOfPacketsBeforeNotification = mPacketsBeforeNotification;
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
package no.nordicsemi.android.dfu.internal;
|
package no.nordicsemi.android.dfu.internal;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
@ -30,6 +32,7 @@ import java.io.InputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
@ -61,6 +64,7 @@ public class ArchiveInputStream extends ZipInputStream {
|
||||||
/** Contains bytes arrays with BIN files. HEX files are converted to BIN before being added to this map. */
|
/** Contains bytes arrays with BIN files. HEX files are converted to BIN before being added to this map. */
|
||||||
private Map<String, byte[]> entries;
|
private Map<String, byte[]> entries;
|
||||||
private Manifest manifest;
|
private Manifest manifest;
|
||||||
|
private CRC32 crc32;
|
||||||
|
|
||||||
private byte[] applicationBytes;
|
private byte[] applicationBytes;
|
||||||
private byte[] softDeviceBytes;
|
private byte[] softDeviceBytes;
|
||||||
|
@ -75,6 +79,9 @@ public class ArchiveInputStream extends ZipInputStream {
|
||||||
private int applicationSize;
|
private int applicationSize;
|
||||||
private int bytesRead;
|
private int bytesRead;
|
||||||
|
|
||||||
|
private byte[] markedSource;
|
||||||
|
private int bytesReadFromMarkedSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* The ArchiveInputStream read HEX or BIN files from the Zip stream. It may skip some of them, depending on the value of the types parameter.
|
* The ArchiveInputStream read HEX or BIN files from the Zip stream. It may skip some of them, depending on the value of the types parameter.
|
||||||
|
@ -103,6 +110,7 @@ public class ArchiveInputStream extends ZipInputStream {
|
||||||
public ArchiveInputStream(final InputStream stream, final int mbrSize, final int types) throws IOException {
|
public ArchiveInputStream(final InputStream stream, final int mbrSize, final int types) throws IOException {
|
||||||
super(stream);
|
super(stream);
|
||||||
|
|
||||||
|
this.crc32 = new CRC32();
|
||||||
this.entries = new HashMap<>();
|
this.entries = new HashMap<>();
|
||||||
this.bytesRead = 0;
|
this.bytesRead = 0;
|
||||||
this.bytesReadFromCurrentSource = 0;
|
this.bytesReadFromCurrentSource = 0;
|
||||||
|
@ -254,7 +262,7 @@ public class ArchiveInputStream extends ZipInputStream {
|
||||||
* but than it MUST include at least one of the following files: softdevice.bin/hex, bootloader.bin/hex, application.bin/hex.
|
* but than it MUST include at least one of the following files: softdevice.bin/hex, bootloader.bin/hex, application.bin/hex.
|
||||||
* To support the init packet such ZIP file should contain also application.dat and/or system.dat (with the CRC16 of a SD, BL or SD+BL together).
|
* To support the init packet such ZIP file should contain also application.dat and/or system.dat (with the CRC16 of a SD, BL or SD+BL together).
|
||||||
*/
|
*/
|
||||||
private void parseZip(int mbrSize) throws IOException {
|
private void parseZip(final int mbrSize) throws IOException {
|
||||||
final byte[] buffer = new byte[1024];
|
final byte[] buffer = new byte[1024];
|
||||||
String manifestData = null;
|
String manifestData = null;
|
||||||
|
|
||||||
|
@ -304,7 +312,7 @@ public class ArchiveInputStream extends ZipInputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(final byte[] buffer) throws IOException {
|
public int read(@NonNull final byte[] buffer) throws IOException {
|
||||||
int maxSize = currentSource.length - bytesReadFromCurrentSource;
|
int maxSize = currentSource.length - bytesReadFromCurrentSource;
|
||||||
int size = buffer.length <= maxSize ? buffer.length : maxSize;
|
int size = buffer.length <= maxSize ? buffer.length : maxSize;
|
||||||
System.arraycopy(currentSource, bytesReadFromCurrentSource, buffer, 0, size);
|
System.arraycopy(currentSource, bytesReadFromCurrentSource, buffer, 0, size);
|
||||||
|
@ -322,9 +330,42 @@ public class ArchiveInputStream extends ZipInputStream {
|
||||||
size += nextSize;
|
size += nextSize;
|
||||||
}
|
}
|
||||||
bytesRead += size;
|
bytesRead += size;
|
||||||
|
crc32.update(buffer, 0, size);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the current position in the stream. The parameter is ignored.
|
||||||
|
* @param readlimit this parameter is ignored, can be anything
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void mark(final int readlimit) {
|
||||||
|
markedSource = currentSource;
|
||||||
|
bytesReadFromMarkedSource = bytesReadFromCurrentSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() throws IOException {
|
||||||
|
currentSource = markedSource;
|
||||||
|
bytesReadFromCurrentSource = bytesReadFromMarkedSource;
|
||||||
|
|
||||||
|
// Restore the CRC to the value is was on mark.
|
||||||
|
crc32.reset();
|
||||||
|
if (currentSource == bootloaderBytes && softDeviceBytes != null) {
|
||||||
|
crc32.update(softDeviceBytes);
|
||||||
|
}
|
||||||
|
crc32.update(currentSource, 0, bytesReadFromCurrentSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCrc32() {
|
||||||
|
return (int) (crc32.getValue() & 0xFFFFFFFFL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the manifest object if it was specified in the ZIP file.
|
* Returns the manifest object if it was specified in the ZIP file.
|
||||||
* @return the manifest object
|
* @return the manifest object
|
||||||
|
|
Loading…
Reference in New Issue