2015-07-21 37 views
1

背景前子不能編碼/解碼小尾數

我試圖使用preon庫來編碼/解碼的二進制數據。當我爲big endian配置字節順序時,我的1字節結構工作正常,但是對於小端字節失敗。看起來,字節數影響了preon中的字節內數據。它出現在同一問題this問題涉及,但不能解決小尾數方面。


我附上了一個簡單的案例來說明問題。

PreonLittleEndianNumber.java中是否存在缺陷,或者在指定little endian字節順序時preon根本無法工作?


PreonTest.java

package me; 

import org.codehaus.preon.Codec; 
import org.codehaus.preon.Codecs; 
import org.codehaus.preon.DecodingException; 
import org.junit.Test; 

import java.io.IOException; 

import org.junit.Assert; 

public class PreonTest { 

    @Test 
    public void bigEndianDecodeEncodeTest() { 

     byte[] testByte = {(byte) 0xDE}; 
     Codec<PreonBigEndianNumber> bigCodec = Codecs.create(PreonBigEndianNumber.class); 

     try { 

      // Big Endian Decode/Encode Test 
      PreonBigEndianNumber pben = Codecs.decode(bigCodec, testByte); 
      byte[] testByte1 = Codecs.encode(pben, bigCodec); 
      Assert.assertArrayEquals(testByte, testByte1); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (DecodingException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Test 
    public void bigEndianEncodeDecodeTest() { 

     PreonBigEndianNumber pben = new PreonBigEndianNumber((byte)0xDE); 
     Codec<PreonBigEndianNumber> bigCodec = Codecs.create(PreonBigEndianNumber.class); 

     try { 

      byte[] testByte1 = Codecs.encode(pben, bigCodec); 
      PreonBigEndianNumber pben2 = Codecs.decode(bigCodec, testByte1); 
      Assert.assertEquals(pben, pben2); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (DecodingException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Test 
    public void littleEndianDecodeEncodeTest() { 

     byte[] testByte = {(byte) 0xDE}; 
     Codec<PreonLittleEndianNumber> littleCodec = Codecs.create(PreonLittleEndianNumber.class); 

     try { 

      // Big Endian Decode/Encode Test 
      PreonLittleEndianNumber plen = Codecs.decode(littleCodec, testByte); 
      byte[] testByte1 = Codecs.encode(plen, littleCodec); 
      Assert.assertArrayEquals(testByte, testByte1); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (DecodingException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Test 
    public void littleEndianEncodeDecodeTest() { 

     PreonLittleEndianNumber plen = new PreonLittleEndianNumber((byte)0xDE); 
     Codec<PreonLittleEndianNumber> littleCodec = Codecs.create(PreonLittleEndianNumber.class); 

     try { 

      byte[] testByte1 = Codecs.encode(plen, littleCodec); 
      PreonLittleEndianNumber plen2 = Codecs.decode(littleCodec, testByte1); 
      Assert.assertEquals(plen, plen2); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (DecodingException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

PreonBigEndianNumber.java

package me; 

import org.codehaus.preon.annotation.BoundNumber; 
import org.codehaus.preon.buffer.ByteOrder; 

public class PreonBigEndianNumber { 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit7; 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit6; 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit5; 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit4; 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit3; 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit2; 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit1; 
    @BoundNumber(size="1", byteOrder=ByteOrder.BigEndian) public byte bit0; 

    /** 
    * Default constructor 
    */ 
    public PreonBigEndianNumber() { 

    } 

    public PreonBigEndianNumber(byte value) { 
     bit7 = (byte) ((0b10000000 & value) >>> 7); 
     bit6 = (byte) ((0b01000000 & value) >>> 6); 
     bit5 = (byte) ((0b00100000 & value) >>> 5); 
     bit4 = (byte) ((0b00010000 & value) >>> 4); 
     bit3 = (byte) ((0b00001000 & value) >>> 3); 
     bit2 = (byte) ((0b00000100 & value) >>> 2); 
     bit1 = (byte) ((0b00000010 & value) >>> 1); 
     bit0 = (byte) ((0b00000001 & value) >>> 0); 
    } 

    public byte getByte() { 
     // Pack bits back into an int 
     int b = 0; 
     int shift = 0; 
     for (int i=7;i>=0;i--) { 
      b = (b << shift); 
      if  (i==0) {b += bit0;} 
      else if (i==1) {b += bit1;} 
      else if (i==2) {b += bit2;} 
      else if (i==3) {b += bit3;} 
      else if (i==4) {b += bit4;} 
      else if (i==5) {b += bit5;} 
      else if (i==6) {b += bit6;} 
      else if (i==7) {b += bit7;} 
      shift = 1; 
     } 
     return (byte) b; 
    } 

    @Override 
    public String toString() { 
     return bit7 + 
       bit6 + 
       bit5 + 
       bit4 + 
       " " + 
       bit3 + 
       bit2 + 
       bit1 + 
       bit0; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) {return true;} 
     if (o == null || getClass() != o.getClass()) {return false;} 

     PreonBigEndianNumber preonBits = (PreonBigEndianNumber) o; 
     if (bit7 != preonBits.bit7) {return false;} 
     if (bit6 != preonBits.bit6) {return false;} 
     if (bit5 != preonBits.bit5) {return false;} 
     if (bit4 != preonBits.bit4) {return false;} 
     if (bit3 != preonBits.bit3) {return false;} 
     if (bit2 != preonBits.bit2) {return false;} 
     if (bit1 != preonBits.bit1) {return false;} 
     return bit0 == preonBits.bit0; 
    } 

    @Override 
    public int hashCode() { 
     int result = (int) bit7; 
     result = 31 * result + (int) bit6; 
     result = 31 * result + (int) bit5; 
     result = 31 * result + (int) bit4; 
     result = 31 * result + (int) bit3; 
     result = 31 * result + (int) bit2; 
     result = 31 * result + (int) bit1; 
     result = 31 * result + (int) bit0; 
     return result; 
    } 
} 

PreonLittleEndianNumber.java

package me; 

import org.codehaus.preon.annotation.BoundNumber; 
import org.codehaus.preon.buffer.ByteOrder; 

public class PreonLittleEndianNumber { 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit7; 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit6; 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit5; 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit4; 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit3; 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit2; 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit1; 
    @BoundNumber(size="1", byteOrder=ByteOrder.LittleEndian) public byte bit0; 

    /** 
    * Default constructor 
    */ 
    public PreonLittleEndianNumber() { 

    } 

    public PreonLittleEndianNumber(byte value) { 
     bit7 = (byte) ((0b10000000 & value) >>> 7); 
     bit6 = (byte) ((0b01000000 & value) >>> 6); 
     bit5 = (byte) ((0b00100000 & value) >>> 5); 
     bit4 = (byte) ((0b00010000 & value) >>> 4); 
     bit3 = (byte) ((0b00001000 & value) >>> 3); 
     bit2 = (byte) ((0b00000100 & value) >>> 2); 
     bit1 = (byte) ((0b00000010 & value) >>> 1); 
     bit0 = (byte) ((0b00000001 & value) >>> 0); 
    } 

    public byte getByte() { 
     // Pack bits back into an int 
     int b = 0; 
     int shift = 0; 
     for (int i=7;i>=0;i--) { 
      b = (b << shift); 
      if  (i==0) {b += bit0;} 
      else if (i==1) {b += bit1;} 
      else if (i==2) {b += bit2;} 
      else if (i==3) {b += bit3;} 
      else if (i==4) {b += bit4;} 
      else if (i==5) {b += bit5;} 
      else if (i==6) {b += bit6;} 
      else if (i==7) {b += bit7;} 
      shift = 1; 
     } 
     return (byte) b; 
    } 

    @Override 
    public String toString() { 
     return bit7 + 
       bit6 + 
       bit5 + 
       bit4 + 
       " " + 
       bit3 + 
       bit2 + 
       bit1 + 
       bit0; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) {return true;} 
     if (o == null || getClass() != o.getClass()) {return false;} 

     PreonLittleEndianNumber preonBits = (PreonLittleEndianNumber) o; 
     if (bit7 != preonBits.bit7) {return false;} 
     if (bit6 != preonBits.bit6) {return false;} 
     if (bit5 != preonBits.bit5) {return false;} 
     if (bit4 != preonBits.bit4) {return false;} 
     if (bit3 != preonBits.bit3) {return false;} 
     if (bit2 != preonBits.bit2) {return false;} 
     if (bit1 != preonBits.bit1) {return false;} 
     return bit0 == preonBits.bit0; 
    } 

    @Override 
    public int hashCode() { 
     int result = (int) bit7; 
     result = 31 * result + (int) bit6; 
     result = 31 * result + (int) bit5; 
     result = 31 * result + (int) bit4; 
     result = 31 * result + (int) bit3; 
     result = 31 * result + (int) bit2; 
     result = 31 * result + (int) bit1; 
     result = 31 * result + (int) bit0; 
     return result; 
    } 
} 

的pom.xml

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 

<modelVersion>4.0.0</modelVersion> 

<groupId>me</groupId> 
<artifactId>parser</artifactId> 
<version>1.0</version> 

<repositories> 
    <repository> 
     <id>atlassian-repo</id> 
     <name>Atlassian Repository</name> 
     <url>https://maven.atlassian.com/repository/public</url> 
    </repository> 
    <repository> 
     <id>limbo-repository</id> 
     <url>http://limbo.sourceforge.net/repository</url> 
     <snapshots> 
      <enabled>false</enabled> 
     </snapshots> 
     <releases> 
      <enabled>true</enabled> 
     </releases> 
    </repository> 
    <repository> 
     <id>pecia-repository</id> 
     <url>http://pecia.sourceforge.net/repository</url> 
     <snapshots> 
      <enabled>false</enabled> 
     </snapshots> 
     <releases> 
      <enabled>true</enabled> 
     </releases> 
    </repository> 
</repositories> 

<dependencies> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>4.12</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.codehaus.preon</groupId> 
     <artifactId>preon-binding</artifactId> 
     <version>1.1-SNAPSHOT</version> 
    </dependency> 
    <dependency> 
     <groupId>org.codehaus.preon</groupId> 
     <artifactId>preon-el</artifactId> 
     <version>1.1-SNAPSHOT</version> 
    </dependency> 
    <dependency> 
     <groupId>org.codehaus.preon</groupId> 
     <artifactId>preon-emitter</artifactId> 
     <version>1.1-SNAPSHOT</version> 
    </dependency> 
    <dependency> 
     <groupId>org.codehaus.preon</groupId> 
     <artifactId>preon-io</artifactId> 
     <version>1.1-SNAPSHOT</version> 
    </dependency> 
</dependencies> 

回答

2

我經歷了同樣的問題。看來,對於ByteOrder.BigEndianByteOrder.LittleEndian解碼是不同的。但是,編碼是相同的。這意味着當您使用ByteOrder.LittleEndian時,編碼和解碼之間的往返將不正確。

ByteOrder.BigEndian的解碼使用MSB 0比特編號,ByteOrder.LittleEndian的解碼使用LSB 0比特編碼解碼。考慮到這一點,我認爲ByteOrder.LittleEndian的編碼器壞了。

我分叉前子(https://github.com/jdl17/preon/)的當前庫和進行必要的修改。伴隨着這些變化,我發現我需要納入最初在拉請求(https://github.com/preon/preon/pull/25)提交mrumpf沖洗修復。我進一步擴展它以允許在flush上規定字節序。

除了上述變化,叉還包括實現用於對SelectFromCode的ListCodecFactory和編碼方法的編碼和解碼方法的改變。最後,我將ANTLR從3.3更新到了3.5.2,因此它可以與Java 8一起工作。

所有這些已經作爲拉動請求提交回到插件(https://github.com/preon/preon/pull/35)。

我也應該評論一下,我添加了一些例程來在小端和大端排序中正確編碼布爾值。然而,目前實施的束縛不允許的字節順序標註,目前硬編碼爲ByteOrder.BigEndian。這超出了我的工作範圍,我不需要使用布爾值來進行解碼和編碼。但是,如果您打算使用編碼爲ByteOrder.LittleEndian的布爾值,請注意這一點。

希望這將解決您的問題。

除此之外,拉請求實現對ListCodecFactory和用於SelectFromCode編碼方法的編碼和解碼方法。

相關問題