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

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 上面的代码。请注意,这些方法是私有的,因为我没有测试 startend 值(它们可以调换或取反)。您可能还想包括一些具有不同 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 信息,其中包含正在读取的文件的长度。这假定您的智能卡实现符合该格式,并且数据位于基本文件中。如果文件大小大于文件中包含的信息,那么您只能希望协议以某种方式定义大小。