从字节数组末尾过滤数据(智能卡响应)
Filter data from the end of a byte array (smart card response)
我有一个 byte[]
例如 [83, 97, 103, 117, 110, -1, -1, -1, .....]
。我的数据字节由 83 到 110 字节表示,其余为默认字节。如何通过数据过滤掉字节数组末尾的-1来提取?
实际上,我正在尝试从智能卡中读取数据。我需要从具有固定大小的卡的特定扇区读取数据。要读取数据,我必须指定要读取的数据的长度。现在的问题是,在读取时,我的应用程序无法说明数据的实际长度。所以,我必须读取整个扇区,然后 parse/filter 从读取的字节数组中取出数据。正如我所说,数组中我的数据字节结束后,剩下的都是-1。
有没有更好的实现方法?
您可以查找第一个 不是 值 -1 的值,从末尾开始。然后使用 Arrays
方法之一将剩余值复制到新数组中。由于数组绝对小于 65KiB,可能小于 256 字节,这与内存或速度无关。如果您真的不想复制字节,您也可以只存储长度或将结果包装在适当大小的 ByteBuffer
中。
所以这里有一些 Java 上面的代码。请注意,这些方法是私有的,因为我没有测试 start
和 end
值(它们可以调换或取反)。您可能还想包括一些具有不同 start
值的测试和其他一般边界检查。
此代码不检查值是否在问题中定义的范围内。
private static final byte PADDING_BYTE = (byte) 0xFF;
private static int determineUnpaddedEnd(byte[] array, int start, int end) {
// end is exclusive
int paddingOffset = end - 1;
while (paddingOffset >= start
&& array[paddingOffset] == PADDING_BYTE) {
paddingOffset--;
}
// returns either start or the location of the last padding byte
return paddingOffset + 1;
}
private static byte[] removePadding(byte[] array) {
int unpaddedEnd = determineUnpaddedEnd(array, 0, array.length);
return Arrays.copyOf(array, unpaddedEnd);
}
private static ByteBuffer removePadding(ByteBuffer buf) {
int start = buf.position();
int paddingOffset = buf.limit() -1;
while (paddingOffset >= start
&& buf.get(paddingOffset) == PADDING_BYTE) {
paddingOffset--;
}
buf.limit(paddingOffset + 1);
return buf;
}
public static void main(String[] args) {
Map<byte[], Integer> testVectors = new HashMap<>();
testVectors.put(new byte[0], 0);
testVectors.put(new byte[] {-1}, 0);
testVectors.put(new byte[] {1, -1}, 1);
testVectors.put(new byte[] {83, 97, 103, 117, 110, -1, -1, -1}, 5);
int testcase = 1;
for (Entry<byte[], Integer> test : testVectors.entrySet()) {
System.out.println(testcase++);
byte[] array = test.getKey();
int value = determineUnpaddedEnd(array, 0, array.length);
if (value != test.getValue()) {
throw new IllegalStateException("Maarten cannot program anymore");
}
System.out.println(Arrays.toString(removePadding(array)));
System.out.println(removePadding(ByteBuffer.wrap(array)));
}
}
更好的方法可能是使用正确的 ISO 7816-4 SELECT
命令读出 FCP 信息,其中包含正在读取的文件的长度。这假定您的智能卡实现符合该格式,并且数据位于基本文件中。如果文件大小大于文件中包含的信息,那么您只能希望协议以某种方式定义大小。
我有一个 byte[]
例如 [83, 97, 103, 117, 110, -1, -1, -1, .....]
。我的数据字节由 83 到 110 字节表示,其余为默认字节。如何通过数据过滤掉字节数组末尾的-1来提取?
实际上,我正在尝试从智能卡中读取数据。我需要从具有固定大小的卡的特定扇区读取数据。要读取数据,我必须指定要读取的数据的长度。现在的问题是,在读取时,我的应用程序无法说明数据的实际长度。所以,我必须读取整个扇区,然后 parse/filter 从读取的字节数组中取出数据。正如我所说,数组中我的数据字节结束后,剩下的都是-1。
有没有更好的实现方法?
您可以查找第一个 不是 值 -1 的值,从末尾开始。然后使用 Arrays
方法之一将剩余值复制到新数组中。由于数组绝对小于 65KiB,可能小于 256 字节,这与内存或速度无关。如果您真的不想复制字节,您也可以只存储长度或将结果包装在适当大小的 ByteBuffer
中。
所以这里有一些 Java 上面的代码。请注意,这些方法是私有的,因为我没有测试 start
和 end
值(它们可以调换或取反)。您可能还想包括一些具有不同 start
值的测试和其他一般边界检查。
此代码不检查值是否在问题中定义的范围内。
private static final byte PADDING_BYTE = (byte) 0xFF;
private static int determineUnpaddedEnd(byte[] array, int start, int end) {
// end is exclusive
int paddingOffset = end - 1;
while (paddingOffset >= start
&& array[paddingOffset] == PADDING_BYTE) {
paddingOffset--;
}
// returns either start or the location of the last padding byte
return paddingOffset + 1;
}
private static byte[] removePadding(byte[] array) {
int unpaddedEnd = determineUnpaddedEnd(array, 0, array.length);
return Arrays.copyOf(array, unpaddedEnd);
}
private static ByteBuffer removePadding(ByteBuffer buf) {
int start = buf.position();
int paddingOffset = buf.limit() -1;
while (paddingOffset >= start
&& buf.get(paddingOffset) == PADDING_BYTE) {
paddingOffset--;
}
buf.limit(paddingOffset + 1);
return buf;
}
public static void main(String[] args) {
Map<byte[], Integer> testVectors = new HashMap<>();
testVectors.put(new byte[0], 0);
testVectors.put(new byte[] {-1}, 0);
testVectors.put(new byte[] {1, -1}, 1);
testVectors.put(new byte[] {83, 97, 103, 117, 110, -1, -1, -1}, 5);
int testcase = 1;
for (Entry<byte[], Integer> test : testVectors.entrySet()) {
System.out.println(testcase++);
byte[] array = test.getKey();
int value = determineUnpaddedEnd(array, 0, array.length);
if (value != test.getValue()) {
throw new IllegalStateException("Maarten cannot program anymore");
}
System.out.println(Arrays.toString(removePadding(array)));
System.out.println(removePadding(ByteBuffer.wrap(array)));
}
}
更好的方法可能是使用正确的 ISO 7816-4 SELECT
命令读出 FCP 信息,其中包含正在读取的文件的长度。这假定您的智能卡实现符合该格式,并且数据位于基本文件中。如果文件大小大于文件中包含的信息,那么您只能希望协议以某种方式定义大小。