从字节数组的末尾过滤数据(智能卡响应)

时间:2016-04-01 14:19:33

标签: java arrays bytearray smartcard

我有byte[]例如[83, 97, 103, 117, 110, -1, -1, -1, .....]。我的数据字节由83到110的字节表示,其余的是默认字节。如何通过数据过滤掉字节数组末尾的-1?

实际上,我试图从智能卡中读取数据。我需要读取具有固定大小的卡的特定扇区的数据。要读取数据,我必须指定要读取的数据的长度。现在的问题是,在阅读时,我的应用程序无法说出实际数据的长度。因此,我必须读取整个扇区,然后从读取字节数组中解析/过滤掉数据。正如我所说,在数组中的数据字节结束后,剩下的都是-1。

有更好的方法来实现这一目标吗?

1 个答案:

答案 0 :(得分:2)

您可以从结尾开始查找不是值-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信息,该命令包含正在读取的文件的长度。这假设您的智能卡实现符合该格式,并且数据位于基本文件中。如果文件大小大于文件中包含的信息,那么您只能希望协议以某种方式定义大小。