javascript - जावास्क्रिप्ट टाइप एरियर और एंडियनस




endianness webgl (4)

धीरज की जाँच करने का त्वरित तरीका

/** @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]);
}

यह काम किस प्रकार करता है:

  • 4 बाइट्स की एक सरणी बनाई जाती है;
  • 32-बिट दृश्य उस सरणी को लपेटता है;
  • view[0] = 1 32-बिट मान 1 रखने के लिए सरणी सेट करता है;
  • अब महत्वपूर्ण हिस्सा आता है: यदि सिस्टम बड़ा एंडियन है, तो 1 को सबसे दाहिनी बाइट द्वारा पकड़ लिया जाता है (थोड़ा अंतिम आता है); यदि यह थोड़ा एंडियन है, तो यह सबसे बाईं बाइट है जो इसे स्टोर करता है (थोड़ा पहले आता है)। तो एक बिटवाइज़ करना और सबसे बाईं बाइट के साथ यदि मशीन बड़ा एंडियन है तो झूठा लौट आता है;
  • समारोह अंत में इसे लागू करके एक बूलियन में बदल देता है ! ऑपरेटर ऑपरेशन के परिणाम के लिए, जबकि यह भी पलट रहा है कि यह बड़े एंडियन के लिए सही है।

मैं बाइनरी एन्कोडेड मेष फ़ाइल रेंडर करने के लिए WebGL का उपयोग कर रहा हूं। बाइनरी फ़ाइल को बड़े-एंडियन प्रारूप में लिखा गया है (मैं हेक्स संपादक में फ़ाइल को खोलकर या फ़िडलर का उपयोग करके नेटवर्क ट्रैफ़िक को देखकर इसे सत्यापित कर सकता हूं)। जब मैं फ्लोट 32 एरे या इंट 32 एरे का उपयोग करके बाइनरी प्रतिक्रिया को पढ़ने की कोशिश करता हूं, तो बाइनरी को छोटे-एंडियन के रूप में व्याख्या किया जाता है और मेरे मूल्य गलत हैं:

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

DataView फ़ंक्शन "getInt32" डिफ़ॉल्ट रूप से बड़े-एंडियन मानों को पढ़ता है।

(नोट: मैंने Google Chrome 15 और Firefox 8 का उपयोग करके परीक्षण किया है और वे दोनों समान व्यवहार करते हैं)


FYI करें आप मशीन की समाप्ति का निर्धारण करने के लिए निम्नलिखित जावास्क्रिप्ट फ़ंक्शन का उपयोग कर सकते हैं, जिसके बाद आप क्लाइंट को एक उचित स्वरूपित फ़ाइल पास कर सकते हैं (आप सर्वर पर फ़ाइल के दो संस्करणों को स्टोर कर सकते हैं, बड़ा एंडियन और थोड़ा एंडियन:

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

हालाँकि, यदि आप उन विधियों का उपयोग नहीं कर सकते हैं क्योंकि वे कार्यान्वित नहीं किए जाते हैं, तो आप हेडर पर हमेशा फ़ाइल के जादू मूल्य (लगभग हर प्रारूप में एक जादू मूल्य है) की जांच कर सकते हैं यह देखने के लिए कि क्या आपको अपने एंडियन के अनुसार उल्टा करने की आवश्यकता है।

इसके अलावा, आप एंडियननेस-विशिष्ट फ़ाइलों को अपने सर्वर पर सहेज सकते हैं और पता लगाए गए होस्ट एंडियन के अनुसार उनका उपयोग कर सकते हैं।


वर्तमान व्यवहार, कुछ हद तक दुख की बात है, कि अंतःकरण अंतर्निहित हार्डवेयर का है। जैसा कि लगभग सभी डेस्कटॉप कंप्यूटर x86 हैं, इसका मतलब थोड़ा-सा एंडियन है। अधिकांश एआरएम ओएस छोटे-एंडियन मोड का उपयोग करते हैं (एआरएम प्रोसेसर द्वि-एंडियन हैं और इस प्रकार दोनों में काम कर सकते हैं)।

इसका कारण कुछ हद तक दुखद है कि इसका मतलब है कि लगभग कोई भी यह परीक्षण नहीं करेगा कि उनका कोड बड़े-एंडियन हार्डवेयर पर काम करता है या नहीं, इससे क्या नुकसान होता है, और यह तथ्य कि पूरे वेब प्लेटफॉर्म को कार्यान्वयन और प्लेटफार्मों पर समान रूप से काम करने वाले कोड के आसपास डिज़ाइन किया गया था, जो यह टूट जाता है।






arraybuffer