2011-12-23 35 views
21

Tôi đang cố gắng cải thiện sự hiểu biết của mình về định dạng tệp STFS bằng cách sử dụng một chương trình để đọc tất cả các bit thông tin khác nhau. Sử dụng một trang web với một tham chiếu trong đó offsets chứa những thông tin, tôi đã viết một số mã mà có một người đọc nhị phân đi qua các tập tin và đặt các giá trị trong các biến chính xác.C# - Trình đọc nhị phân trong Big Endian?

Vấn đề là tất cả dữ liệu được SUPPOSED là Big Endian và mọi thứ mà trình đọc nhị phân đọc là Little Endian. Vậy, cách tốt nhất để khắc phục vấn đề này là gì?

Tôi có thể tạo lớp bắt chước của Trình đọc nhị phân trả về một mảng byte được đảo ngược không? Có cái gì tôi có thể thay đổi trong trường hợp lớp học mà sẽ làm cho nó đọc trong endian lớn vì vậy tôi không phải viết lại tất cả mọi thứ?

Mọi trợ giúp đều được đánh giá cao.

chỉnh sửa: Tôi đã thử thêm Encoding.BigEndianUnicode làm tham số, nhưng nó vẫn đọc chút cuối.

+4

Skeet đã viết một: http: // www.yoda.arachsys.com/csharp/miscutil/ –

+0

@ HansPassant, Đây có phải là một trong những dll yêu cầu tôi tạo mã nguồn mở của tôi không? Tại sao một số dll yêu cầu điều đó? – mowwwalker

+0

Walkerneo Tôi đã xóa câu trả lời của mình vì zmbq đã trả lời về cơ bản điều tương tự 3 phút trước tôi. Khái niệm về tính cuối cùng không áp dụng cho các mảng byte, chỉ với các từ, dwords, qwords, v.v., đó là các nhóm 2, 4, 8 và các byte khác. Tôi xin lỗi nếu nó có nghĩa là thay đổi rất nhiều mã, nhưng một người đàn ông phải làm những gì một người đàn ông phải làm. –

Trả lời

31

Tôi không thường một để trả lời câu hỏi của riêng tôi, nhưng tôi đã thực hiện chính xác những gì tôi muốn với một số mã đơn giản:

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); 
    } 

} 

tôi biết đó là những gì Tôi muốn, nhưng tôi không biết cách viết nó. Tôi tìm thấy trang này và nó giúp: http://www.codekeep.net/snippets/870c4ab3-419b-4dd2-a950-6d45beaf1295.aspx

+12

Tắt chủ đề, nhưng các trường của lớp học của bạn ('a16' vv) là không cần thiết. Bạn gán một mảng cho chúng trong khi xây dựng, nhưng trong mỗi phương thức bạn thay thế mảng đó bằng một mảng mới được trả về bởi hàm 'Read'. Bạn có thể đặt 'var a32 = base.ReadBytes ...' vào mỗi phương thức và loại bỏ các trường. –

+15

Chúng không cần thiết, chúng có hại. Biến những gì là (có khả năng, bỏ qua các dòng cơ bản chia sẻ) một mã thread an toàn vào một tình trạng chia sẻ trạng thái. – skolima

+4

Bạn có thể muốn kiểm tra 'BitConverter.IsLittleEndian' trước khi đảo ngược. Nếu nó là 'false' bạn không cần phải đảo ngược. –

5

Tôi không quen với STFS, nhưng việc thay đổi endianess tương đối dễ dàng. "Thứ tự mạng" là kết thúc lớn, vì vậy tất cả những gì bạn cần làm là dịch từ mạng sang thứ tự máy chủ.

Điều này rất dễ dàng vì đã có mã thực hiện điều đó. Nhìn vào IPAddress.NetworkToHostOrder, như đã giải thích ở đây: ntohs() and ntohl() equivalent?

9

IMHO một câu trả lời tốt hơn một chút vì nó không đòi hỏi một lớp học khác nhau để có newed-up, làm cho lớn về cuối nhỏ gọi rõ ràng và cho phép big- và ít về cuối nhỏ các cuộc gọi đến được trộn lẫn trong luồng.

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

Hãy nhớ kiểm tra 'BitConverter.IsLittleEndian' trước khi đảo ngược. –

4

Theo tôi, bạn muốn cẩn thận thực hiện việc này. Lý do người ta muốn chuyển đổi từ BigEndian sang LittleEndian là nếu các byte được đọc nằm trong BigEndian và hệ điều hành tính toán chống lại chúng đang hoạt động trong LittleEndian.

C# không còn là ngôn ngữ cửa sổ nữa. Với các cổng như Mono và các nền tảng khác của Microsoft như Windows Phone 7/8, Xbox 360/Xbox One, Windwos CE, Windows 8 Mobile, Linux Với MONO, Apple với MONO, v.v. Có thể là nền tảng điều hành có thể nằm trong BigEndian, trong trường hợp này bạn sẽ tự sửa lỗi nếu bạn đã chuyển đổi mã mà không thực hiện bất kỳ séc nào.

BitConverter đã có một trường trên đó được gọi là "IsLittleEndian", bạn có thể sử dụng điều này để xác định xem môi trường hoạt động có trong LittleEndian hay không. Sau đó, bạn có thể thực hiện việc đảo ngược có điều kiện.

Như vậy, tôi thực sự chỉ viết một số byte [] Tiện ích thay vì làm một lớp lớn:

/// <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; 
    } 

Vì vậy, tưởng tượng mã ví dụ này:

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 
Các vấn đề liên quan