Programing

자바 스크립트 유형 배열 및 엔디안

lottogame 2020. 12. 29. 06:40
반응형

자바 스크립트 유형 배열 및 엔디안


WebGL을 사용하여 바이너리 인코딩 된 메시 파일을 렌더링하고 있습니다. 바이너리 파일은 big-endian 형식으로 작성됩니다 (16 진수 편집기에서 파일을 열거 나 fiddler를 사용하여 네트워크 트래픽을 확인하여 확인할 수 있습니다). Float32Array 또는 Int32Array를 사용하여 이진 응답을 읽으려고하면 이진이 리틀 엔디안으로 해석되고 내 값이 잘못되었습니다.

// Interpret first 32bits in buffer as an int
var wrongValue = new Int32Array(binaryArrayBuffer)[0];

http://www.khronos.org/registry/typedarray/specs/latest/ 에서 형식화 된 배열의 기본 엔디안에 대한 참조를 찾을 수 없으므로 거래가 무엇인지 궁금합니다. 형식화 된 배열을 사용하여 읽을 때 모든 이진 데이터가 리틀 엔디안이어야한다고 가정해야합니까?

문제를 해결하기 위해 DataView 개체 (이전 링크에서 설명)를 사용하고 다음을 호출 할 수 있습니다.

// Interpret first 32bits in buffer as an int
var correctValue = new DataView(binaryArrayBuffer).getInt32(0);

"getInt32"와 같은 DataView 함수는 기본적으로 빅 엔디안 값을 읽습니다.

(참고 : Google Chrome 15 및 Firefox 8을 사용하여 테스트했으며 둘 다 동일한 방식으로 작동합니다.)


슬프게도 현재 동작은 엔디안이 기본 하드웨어의 동작이라는 것입니다. 거의 모든 데스크톱 컴퓨터가 x86이므로 리틀 엔디안을 의미합니다. 대부분의 ARM OS는 리틀 엔디안 모드를 사용합니다 (ARM 프로세서는 바이 엔디안이므로 둘 중 하나에서 작동 할 수 있음).

이것이 다소 슬픈 이유는 자신의 코드가 빅 엔디안 하드웨어에서 작동하는지 여부를 테스트하는 사람이 거의 없다는 것을 의미하고, 수행하는 작업을 손상 시키며, 전체 웹 플랫폼이 구현 및 플랫폼 전반에 걸쳐 균일하게 작동하는 코드를 중심으로 설계되었다는 사실을 의미합니다. 이것이 깨지는.


참고로 다음 자바 스크립트 함수를 사용하여 컴퓨터의 엔디안을 확인할 수 있습니다. 그런 다음 적절하게 형식이 지정된 파일을 클라이언트에 전달할 수 있습니다 (서버에 파일의 두 가지 버전, 빅 엔디안 및 리틀 엔디안을 저장할 수 있음).

function checkEndian() {
    var arrayBuffer = new ArrayBuffer(2);
    var uint8Array = new Uint8Array(arrayBuffer);
    var uint16array = new Uint16Array(arrayBuffer);
    uint8Array[0] = 0xAA; // set first byte
    uint8Array[1] = 0xBB; // set second byte
    if(uint16array[0] === 0xBBAA) return "little endian";
    if(uint16array[0] === 0xAABB) return "big endian";
    else throw new Error("Something crazy just happened");
}

귀하의 경우에는 리틀 엔디안으로 파일을 다시 생성하거나 리틀 엔디안으로 만들기 위해 전체 데이터 구조를 실행해야 할 것입니다. 위의 방법을 비틀어 사용하면 즉시 엔디안을 바꿀 수 있습니다 (실제로 권장되지는 않으며 전체 구조가 꽉 찬 유형 인 경우에만 의미가 있습니다. 실제로 필요에 따라 바이트를 교체하는 스텁 함수를 만들 수 있습니다).

function swapBytes(buf, size) {
    var bytes = new Uint8Array(buf);
    var len = bytes.length;
    var holder;

    if (size == 'WORD') {
        // 16 bit
        for (var i = 0; i<len; i+=2) {
            holder = bytes[i];
            bytes[i] = bytes[i+1];
            bytes[i+1] = holder;
        }
    } else if (size == 'DWORD') {
        // 32 bit
        for (var i = 0; i<len; i+=4) {
            holder = bytes[i];
            bytes[i] = bytes[i+3];
            bytes[i+3] = holder;
            holder = bytes[i+1];
            bytes[i+1] = bytes[i+2];
            bytes[i+2] = holder;
        }
    }
}

여기 http://www.khronos.org/registry/typedarray/specs/latest/ (사양이 완전히 구현 된 경우)에서 가져 오면 다음을 사용할 수 있습니다.

new DataView(binaryArrayBuffer).getInt32(0, true) // For little endian
new DataView(binaryArrayBuffer).getInt32(0, false) // For big endian

However, if you can't use those method because they aren't implemented, you can always check the file's magic value (almost every format has a magic value) on the header to see if you need to invert it according to your endiannes.

Also, you can save endiannes-specific files on your server and use them accordingly to the detected host endiannes.


The other answers seem a bit outdated to me, so here's a link to the latest spec:

http://www.khronos.org/registry/typedarray/specs/latest/#2.1

In particular:

The typed array view types operate with the endianness of the host computer.

The DataView type operates upon data with a specified endianness (big-endian or little-endian).

So if you want to read/write data in Big Endian (Network Byte Order), see: http://www.khronos.org/registry/typedarray/specs/latest/#DATAVIEW

// For multi-byte values, the optional littleEndian argument
// indicates whether a big-endian or little-endian value should be
// read. If false or undefined, a big-endian value is read.

Quick way to check endianness

/** @returns {Boolean} true if system is big endian */
function isBigEndian() {
    const array = new Uint8Array(4);
    const view = new Uint32Array(array.buffer);
    return !((view[0] = 1) & array[0]);
}

How it works:

  • an array of 4 bytes is created;
  • a 32-bit view wraps that array;
  • view[0] = 1 sets the array to hold 32-bit value 1;
  • now comes the important part: if system is big endian, that 1 is being hold by the rightmost byte (little comes last); if it is little endian, it is the leftmost byte that stores it (little comes first). So doing a bitwise AND with the leftmost byte returns false if the machine is big endian;
  • the function finally converts it to a boolean by applying the ! operator to the result of the & operation, while also inverting it so that it returns true for big endian.

ReferenceURL : https://stackoverflow.com/questions/7869752/javascript-typed-arrays-and-endianness

반응형