0

Preonを使用して、可変長レコードのシーケンスとして構造化されたバイナリファイルを解析しようとしています。レコードごとに、レコード長(バイト単位)を指定する数値があります。

これが私がやろうとしていることの単純化されたバージョンです:

package test.preon; 

import nl.flotsam.preon.annotation.BoundList; 
import nl.flotsam.preon.annotation.BoundNumber; 
import java.util.List; 

public class BinFile { 
    @BoundNumber(size="16") int numberOfRecords; 
    @BoundList(type=Record.class, size="numberOfRecords") List<Record> records; 

    public int getNumberOfRecords() { 
        return numberOfRecords;
    } 

    public List<Record> getRecords() { 
        return records;
    } 

    public class Record { 
        @BoundNumber(size="16") int recordLength; 
        @BoundList(size="recordLength") byte[] data; 

        public int getRecordLength() { 
            return recordLength; 
        } 

        public byte[] getData() { 
            return data; 
        } 
    } 
}

したがって、numberOfRecordsはファイル内のレコード数を指定し、recordLengthは各レコードの長さを指定します。問題は、numberOfRecordsはBinFileで正常に機能しますが、PreonがRecordのrecordLengthを解決できないことです。

これが私が得る例外です:

nl.flotsam.limbo.BindingException: Failed to resolve recordLength on class test.preon.BinFile
at nl.flotsam.preon.codec.BindingsContext$BindingsResolver.get(BindingsContext.java:412)
at nl.flotsam.preon.codec.BindingsContext$BindingReference.resolve(BindingsContext.java:247)
at nl.flotsam.preon.codec.BindingsContext$BindingReference.resolve(BindingsContext.java:189)
at nl.flotsam.limbo.ast.ReferenceNode.eval(ReferenceNode.java:57)
at nl.flotsam.limbo.ast.ArithmeticNode$Operator$5.eval(ArithmeticNode.java:109)
at nl.flotsam.limbo.ast.ArithmeticNode.eval(ArithmeticNode.java:250)
at nl.flotsam.limbo.ast.ArithmeticNode.eval(ArithmeticNode.java:33)
at nl.flotsam.limbo.ast.ArithmeticNode$Operator$3.eval(ArithmeticNode.java:83)
at nl.flotsam.limbo.ast.ArithmeticNode.eval(ArithmeticNode.java:250)
at nl.flotsam.limbo.ast.ArithmeticNode.eval(ArithmeticNode.java:33)
at nl.flotsam.limbo.ast.ArithmeticNode$Operator$5.eval(ArithmeticNode.java:109)
at nl.flotsam.limbo.ast.ArithmeticNode.eval(ArithmeticNode.java:250)
at nl.flotsam.limbo.ast.ArithmeticNode.eval(ArithmeticNode.java:33)
at nl.flotsam.preon.codec.ListCodecFactory$SwitchingListCodec.decode(ListCodecFactory.java:458)
at nl.flotsam.preon.codec.ListCodecFactory$SwitchingListCodec.decode(ListCodecFactory.java:443)
at nl.flotsam.preon.binding.StandardBindingFactory$FieldBinding.load(StandardBindingFactory.java:128)
at nl.flotsam.preon.codec.ObjectCodecFactory$ObjectCodec.decode(ObjectCodecFactory.java:251)
at nl.flotsam.preon.DefaultCodecFactory$DefaultCodec.decode(DefaultCodecFactory.java:173)
at nl.flotsam.preon.Codecs.decode(Codecs.java:218)
at nl.flotsam.preon.Codecs.decode(Codecs.java:199)
    ...

size = "recordLength"を定数(たとえばsize = "42")に変更しても、例外は発生しません(ただし、もちろん、レコード長は常に同じである必要があります)。

レコード長を可変にする他の方法はありますか、それとも別の方法で整理する必要がありますか?

興味のある方は、これが私が使用したJUnitテストです。

package test.preon;

import org.junit.Test;
import static org.junit.Assert.*;
import nl.flotsam.preon.Codecs;
import nl.flotsam.preon.Codec;
import nl.flotsam.preon.DecodingException;
import test.preon.BinFile;
import test.preon.BinFile.Record;
import java.util.List;

public class BinFileTest {

    @Test
    public void parseBinFile() throws DecodingException {
        Codec<BinFile> codec = Codecs.create(BinFile.class);
        byte[] buffer = new byte[] {
                2, 0, 
                3, 0, 
                'a', 'b', 'c',
                4, 0,
                '1', '2', '3', '4'
        };
        BinFile b = Codecs.decode(codec, buffer);

        assertEquals(b.getNumberOfRecords(), 2);

        List<Record> rL = b.getRecords();

        assertEquals(rL.size(), 2);

        Record r0 = rL.get(0);
        assertEquals(r0.getRecordLength(), 3);
        assertEquals(new String(r0.getData()), "abc");

        Record r1 = rL.get(1);
        assertEquals(r1.getRecordLength(), 4);
        assertEquals(new String(r1.getData()), "1234");
    }
}
4

2 に答える 2

1

バグに遭遇したことがわかりました。ListCodecFactoryには、さまざまな状況で生成するコーデックのタイプを決定するためのポリシーがあり、この場合、間違ったコーデックを選択することがわかります。私はそれのためのパッチを持っています、そしてあなたが興味を持っているなら私はあなたにそれを送ることができます。

于 2010-03-04T00:07:00.510 に答える
1

PREON-16PREON-17の2つのバグレポートを作成しました。最初のものは、上記で概説した問題を解決します。2つ目は、ここで言及する価値のある、わずかに関連する問題を解決します。

以下のコードでは、「records」と呼ばれるリスト内のTest2要素のサイズは、Test1によって完全に定義されています。(Test2のサイズは、基本的にTest2.valueの文字数であり、Test1の「nrCharacters」属性によって決定されます。)

この結果として、Preonはレコードのリストの読み取りを最適化することができます。すべてのレコードを一度に読み取る必要はありません。代わりに、それをスキップして、必要な場合にのみそれらの要素を読み取ることができます。(要素の開始位置は、基本的に要素インデックスの関数です。)

ただし、問題は、Test2のインスタンスが読み取られる前に、要素のサイズを計算する必要があることです。Test2のコンテキストに基づく参照が含まれているため、それらの参照を書き直す必要があります。実際、サイズ式全体(この場合は単純なものですが)を書き直す必要があります。これはPREON-17で解決されています。

 public static class Test1 {

        @BoundNumber(size = "8")
        public int nrRecords;

        @BoundNumber(size = "8")
        public int nrCharacters;

        @BoundList(size = "nrRecords", type = Test2.class)
        public List<Test2> records;

        public static class Test2 {

            @BoundString(size = "outer.nrCharacters")
            public String value;

        }

    }
于 2010-08-27T15:21:00.353 に答える