2011-12-23 1 views
21

나는 모든 다른 정보 비트를 읽는 프로그램을 사용하여 STFS 파일 형식에 대한 이해를 높이려고합니다. 어떤 오프셋이 어떤 정보를 포함하는지에 대한 참조가있는 웹 사이트를 사용하여 바이너리 판독기가있는 코드를 작성하여 올바른 변수에 값을 넣습니다.C# - Big Endian의 바이너리 리더?

문제는 모든 데이터가 Big Endian으로 지원되며 이진 판독기가 읽는 모든 것이 Little Endian입니다. 그래서 이것을 고치는 가장 좋은 방법은 무엇입니까?

반전 된 바이트 배열을 반환하는 Binary 리더의 모방 클래스를 만들 수 있습니까? 내가 모든 것을 다시 쓸 필요가 없도록 big endian으로 읽을 수 있도록 클래스 인스턴스에서 변경할 수있는 것이 있습니까?

도움을 주시면 감사하겠습니다.

편집 : Encoding.BigEndianUnicode를 매개 변수로 추가했지만 리틀 엔디안을 읽습니다.

+4

스키트 하나를 썼다 :

/// <summary> /// Get's a byte array from a point in a source byte array and reverses the bytes. Note, if the current platform is not in LittleEndian the input array is assumed to be BigEndian and the bytes are not returned in reverse order /// </summary> /// <param name="byteArray">The source array to get reversed bytes for</param> /// <param name="startIndex">The index in the source array at which to begin the reverse</param> /// <param name="count">The number of bytes to reverse</param> /// <returns>A new array containing the reversed bytes, or a sub set of the array not reversed.</returns> public static byte[] ReverseForBigEndian(this byte[] byteArray, int startIndex, int count) { if (BitConverter.IsLittleEndian) return byteArray.Reverse(startIndex, count); else return byteArray.SubArray(startIndex, count); } public static byte[] Reverse(this byte[] byteArray, int startIndex, int count) { byte[] ret = new byte[count]; for (int i = startIndex + (count - 1); i >= startIndex; --i) { byte b = byteArray[i]; ret[(startIndex + (count - 1)) - i] = b; } return ret; } public static byte[] SubArray(this byte[] byteArray, int startIndex, int count) { byte[] ret = new byte[count]; for (int i = 0; i < count; ++i) ret[0] = byteArray[i + startIndex]; return ret; } 

그래서이 예제 코드를 상상 : 이와 같이

, 나는 실제로 단지 대신 큰 클래스를 만드는 일부 바이트 [] 확장을 썼다에 http : // www.yoda.arachsys.com/csharp/miscutil/ –

+0

@HansPassant, 내 코드 소스를 만들 필요가있는 DLL 중 하나일까요? 왜 일부 DLL은 그것을 요구합니까? – mowwwalker

+0

Walkerneo zmbq이 3 분 전에 본질적으로 같은 대답을했기 때문에 대답을 삭제했습니다. 엔디안 개념은 바이트 배열에 적용되지 않으며 단어, dwords, qwords 등, 즉 2, 4, 8 등의 바이트 그룹에만 적용됩니다. 많은 코드를 변경한다는 것은 유감이지만 남자는 남자가해야 할 일을해야합니다. –

답변

31

난 내 자신의 질문에 대답하는 것이 하나 아니지만, 나는 몇 가지 간단한 코드 원 정확히 수행했습니다

class BinaryReader2 : BinaryReader { 
    public BinaryReader2(System.IO.Stream stream) : base(stream) { } 

    public override int ReadInt32() 
    { 
     var data = base.ReadBytes(4); 
     Array.Reverse(data); 
     return BitConverter.ToInt32(data, 0); 
    } 

    public Int16 ReadInt16() 
    { 
     var data = base.ReadBytes(2); 
     Array.Reverse(data); 
     return BitConverter.ToInt16(data, 0); 
    } 

    public Int64 ReadInt64() 
    { 
     var data = base.ReadBytes(8); 
     Array.Reverse(data); 
     return BitConverter.ToInt64(data, 0); 
    } 

    public UInt32 ReadUInt32() 
    { 
     var data = base.ReadBytes(4); 
     Array.Reverse(data); 
     return BitConverter.ToUInt32(data, 0); 
    } 

} 

내가 아는 그 무엇을의 나는 원했지만 그것을 쓰는 방법을 몰랐다. 이 페이지를 찾았을 때 도움이되었습니다. http://www.codekeep.net/snippets/870c4ab3-419b-4dd2-a950-6d45beaf1295.aspx

+12

주제에서 벗어나지 만 클래스의 필드 ('a16' 등)는 불필요하다. 구성 중에 배열을 할당하지만 각 메소드 내에서 해당 배열을'Read' 함수가 반환 한 새로운 배열로 대체합니다. 각 메소드에'var a32 = base.ReadBytes ... '를 넣고 필드를 제거 할 수 있습니다. –

+15

그들은 불필요하지 않고 유해합니다. 스레드 안전 코드를 (잠재적으로 공유 기본 스트림을 무시하고) 공유 상태 상황으로 전환합니다. – skolima

+4

되돌리기 전에'BitConverter.IsLittleEndian'을 체크하고 싶을 것입니다. '거짓'이면 반대로 변경할 필요가 없습니다. –

5

저는 STFS에 익숙하지 않지만 endianess를 변경하는 것은 비교적 쉽습니다. "네트워크 주문"은 빅 엔디안이므로 네트워크에서 호스트 주문으로 변환하면됩니다.

이미 그렇게하는 코드가 있기 때문에 쉽습니다. 여기에 설명 된 바와 같이, IPAddress.NetworkToHostOrder 봐 : ntohs() and ntohl() equivalent?

9

IMHO 다른 클래스를 새로 만들 필요가 없으므로 조금 더 나은 대답이 될 수 있습니다. big-endian 호출이 명확하고 big 및 little-endian 호출을 허용합니다. 스트림에서 혼합 될 수 있습니다.

public static class Helpers 
{ 
    // Note this MODIFIES THE GIVEN ARRAY then returns a reference to the modified array. 
    public static byte[] Reverse(this byte[] b) 
    { 
    Array.Reverse(b); 
    return b; 
    } 

    public static UInt16 ReadUInt16BE(this BinaryReader binRdr) 
    { 
    return BitConverter.ToUInt16(binRdr.ReadBytesRequired(sizeof(UInt16)).Reverse(), 0); 
    } 

    public static Int16 ReadInt16BE(this BinaryReader binRdr) 
    { 
    return BitConverter.ToInt16(binRdr.ReadBytesRequired(sizeof(Int16)).Reverse(), 0); 
    } 

    public static UInt32 ReadUInt32BE(this BinaryReader binRdr) 
    { 
    return BitConverter.ToUInt32(binRdr.ReadBytesRequired(sizeof(UInt32)).Reverse(), 0); 
    } 

    public static Int32 ReadInt32BE(this BinaryReader binRdr) 
    { 
    return BitConverter.ToInt32(binRdr.ReadBytesRequired(sizeof(Int32)).Reverse(), 0); 
    } 

    public static byte[] ReadBytesRequired(this BinaryReader binRdr, int byteCount) 
    { 
    var result = binRdr.ReadBytes(byteCount); 

    if (result.Length != byteCount) 
     throw new EndOfStreamException(string.Format("{0} bytes required from stream, but only {1} returned.", byteCount, result.Length)); 

    return result; 
    } 
} 
+7

되돌리기 전에'BitConverter.IsLittleEndian'을 반드시 확인하십시오. –

4

내 의견으로는 이렇게하는 것이 좋습니다. BigEndian에서 LittleEndian으로 변환하려는 이유는 읽히는 바이트가 BigEndian에 있고 그들에 대해 계산하는 OS가 LittleEndian에서 작동하는 경우입니다.

C#은 더 이상 윈도우 전용 언어가 아닙니다. Mono와 같은 포트와 Windows Phone 7/8, Xbox 360/Xbox One, Windwos CE, Windows 8 Mobile, MONO가있는 Linux, MONO가있는 Apple 등의 다른 Microsoft 플랫폼과 같은 포트를 사용하면 운영 플랫폼이 BigEndian. 어떤 경우에도 코드를 변환하지 않으면 스스로 망쳐 버릴 수 있습니다.

BitConverter에는 이미 "IsLittleEndian"이라는 필드가 있습니다.이 필드를 사용하면 운영 환경이 LittleEndian인지 여부를 확인할 수 있습니다. 그런 다음 조건부로 되돌릴 수 있습니다.

byte[] fontBytes = byte[240000]; //some data loaded in here, E.G. a TTF TrueTypeCollection font file. (which is in BigEndian) 

int _ttcVersionMajor = BitConverter.ToUint16(fontBytes.ReverseForBigEndian(4, 2), 0); 

//output 
_ttcVersionMajor = 1 //TCCHeader is version 1