2012-04-07 23 views
6

मैं सी में ++ निम्नलिखित पायथन कोड का अनुवाद करने में कोशिश कर रहा हूँ:अनपैक हेक्स एन्कोड तैरता

import struct 
import binascii 


inputstring = ("0000003F" "0000803F" "AD10753F" "00000080") 
num_vals = 4 

for i in range(num_vals): 
    rawhex = inputstring[i*8:(i*8)+8] 

    # <f for little endian float 
    val = struct.unpack("<f", binascii.unhexlify(rawhex))[0] 
    print val 

    # Output: 
    # 0.5 
    # 1.0 
    # 0.957285702229 
    # -0.0 

तो यह हेक्स एन्कोड स्ट्रिंग के 32-बिट के लायक पढ़ता है, इसके साथ एक बाइट सरणी में बदल जाता है unhexlify विधि, और इसे थोड़ा-अंतराल फ्लोट मान के रूप में व्याख्या करता है।

लगभग काम करता है के बाद, लेकिन कोड तरह का भद्दा है (और पिछले 00000080 गलत तरीके से पार्स करता है):

#include <sstream> 
#include <iostream> 


int main() 
{ 
    // The hex-encoded string, and number of values are loaded from a file. 
    // The num_vals might be wrong, so some basic error checking is needed. 
    std::string inputstring = "0000003F" "0000803F" "AD10753F" "00000080"; 
    int num_vals = 4; 


    std::istringstream ss(inputstring); 

    for(unsigned int i = 0; i < num_vals; ++i) 
    { 
     char rawhex[8]; 

// The ifdef is wrong. It is not the way to detect endianness (it's 
// always defined) 
#ifdef BIG_ENDIAN 
     rawhex[6] = ss.get(); 
     rawhex[7] = ss.get(); 

     rawhex[4] = ss.get(); 
     rawhex[5] = ss.get(); 

     rawhex[2] = ss.get(); 
     rawhex[3] = ss.get(); 

     rawhex[0] = ss.get(); 
     rawhex[1] = ss.get(); 
#else 
     rawhex[0] = ss.get(); 
     rawhex[1] = ss.get(); 

     rawhex[2] = ss.get(); 
     rawhex[3] = ss.get(); 

     rawhex[4] = ss.get(); 
     rawhex[5] = ss.get(); 

     rawhex[6] = ss.get(); 
     rawhex[7] = ss.get(); 
#endif 

     if(ss.good()) 
     { 
      std::stringstream convert; 
      convert << std::hex << rawhex; 
      int32_t val; 
      convert >> val; 

      std::cerr << (*(float*)(&val)) << "\n"; 
     } 
     else 
     { 
      std::ostringstream os; 
      os << "Not enough values in LUT data. Found " << i; 
      os << ". Expected " << num_vals; 
      std::cerr << os.str() << std::endl; 
      throw std::exception(); 
     } 
    } 
} 

(ओएस पर संकलित X 10.7/जीसीसी-4.2.1, एक सरल g++ blah.cpp के साथ)

विशेष रूप से, मैं BIG_ENDIAN मैक्रो सामान से छुटकारा पाना चाहता हूं, क्योंकि मुझे यकीन है कि ऐसा करने के लिए एक अच्छा तरीका है, this post चर्चा करता है।

कुछ अन्य यादृच्छिक विवरण - मैं बूस्ट का उपयोग नहीं कर सकता (परियोजना के लिए बहुत बड़ी निर्भरता)। स्ट्रिंग आम तौर पर 1536 98304 के बीच (8 * 3) और नाव मूल्यों (32 * 3), अधिक से अधिक 786432 (64 * 3) में शामिल होंगे

(EDIT2: एक और मूल्य वर्धित, 00000080 == -0.0)

उत्तर

0

इसी को हम साथ समाप्त हो गया है, OpenColorIO/src/core/FileFormatIridasLook.cpp

// convert hex ascii to int 
    // return true on success, false on failure 
    bool hexasciitoint(char& ival, char character) 
    { 
     if(character>=48 && character<=57) // [0-9] 
     { 
      ival = static_cast<char>(character-48); 
      return true; 
     } 
     else if(character>=65 && character<=70) // [A-F] 
     { 
      ival = static_cast<char>(10+character-65); 
      return true; 
     } 
     else if(character>=97 && character<=102) // [a-f] 
     { 
      ival = static_cast<char>(10+character-97); 
      return true; 
     } 

     ival = 0; 
     return false; 
    } 

    // convert array of 8 hex ascii to f32 
    // The input hexascii is required to be a little-endian representation 
    // as used in the iridas file format 
    // "AD10753F" -> 0.9572857022285461f on ALL architectures 

    bool hexasciitofloat(float& fval, const char * ascii) 
    { 
     // Convert all ASCII numbers to their numerical representations 
     char asciinums[8]; 
     for(unsigned int i=0; i<8; ++i) 
     { 
      if(!hexasciitoint(asciinums[i], ascii[i])) 
      { 
       return false; 
      } 
     } 

     unsigned char * fvalbytes = reinterpret_cast<unsigned char *>(&fval); 

#if OCIO_LITTLE_ENDIAN 
     // Since incoming values are little endian, and we're on little endian 
     // preserve the byte order 
     fvalbytes[0] = (unsigned char) (asciinums[1] | (asciinums[0] << 4)); 
     fvalbytes[1] = (unsigned char) (asciinums[3] | (asciinums[2] << 4)); 
     fvalbytes[2] = (unsigned char) (asciinums[5] | (asciinums[4] << 4)); 
     fvalbytes[3] = (unsigned char) (asciinums[7] | (asciinums[6] << 4)); 
#else 
     // Since incoming values are little endian, and we're on big endian 
     // flip the byte order 
     fvalbytes[3] = (unsigned char) (asciinums[1] | (asciinums[0] << 4)); 
     fvalbytes[2] = (unsigned char) (asciinums[3] | (asciinums[2] << 4)); 
     fvalbytes[1] = (unsigned char) (asciinums[5] | (asciinums[4] << 4)); 
     fvalbytes[0] = (unsigned char) (asciinums[7] | (asciinums[6] << 4)); 
#endif 
     return true; 
    } 
1

मुझे लगता है कि पूरे istringstring व्यवसाय एक ओवरकिल है। एक बार में खुद को एक अंक का विश्लेषण करना बहुत आसान है।

सबसे पहले, एक पूर्णांक में एक हेक्स अंकों कन्वर्ट करने के लिए एक समारोह बनाने के लिए:

signed char htod(char c) 
{ 
    c = tolower(c); 
    if(isdigit(c)) 
    return c - '0'; 

    if(c >= 'a' && c <= 'f') 
    return c - 'a'; 

    return -1; 
} 

तो बस एक पूर्णांक में स्ट्रिंग परिवर्तित करते हैं। नीचे दिया गया कोड त्रुटियों की जांच नहीं करता है और बड़ी सहनशीलता मानता है - लेकिन आपको विवरण भरने में सक्षम होना चाहिए।

unsigned long t = 0; 
for(int i = 0; i < s.length(); ++i) 
    t = (t << 4) & htod(s[i]); 

फिर अपने नाव

float f = * (float *) &t; 
+0

मुझे लगता है कि आप का मतलब (ग - 'ए') (अहस्ताक्षरित uint32_t ठीक होने की संभावना भी काम करेगा साथ अमरदीप का जवाब) + 10; यह मानते हुए कि यह केवल अपरकेस ए –

+0

होगा, इसके अलावा, इसे अंक-दर-अंक स्वयं करने का लाभ यह है कि आप एंडियन-नेस –

+0

@OrgnlDave के आधार पर बाएं से दाएं या दाएं से बाएं लूप कर सकते हैं - यही कारण है कि 'tolower' वहाँ है। हां एंडियन-नेस पर, हालांकि यह थोड़ा ट्रिकियर बन जाता है (एक बाइट अंकों के लिए स्वैप नहीं होता है) –

1

है निम्न अपना अपडेट किया गया #ifdef BIG_ENDIAN ब्लॉक को दूर करने के लिए संशोधित कोड है। यह एक रीड तकनीक का उपयोग करता है जो मेजबान बाइट ऑर्डर स्वतंत्र होना चाहिए। यह iostream std :: हेक्स ऑपरेटर के साथ संगत एक बड़े एंडियन स्ट्रिंग प्रारूप में हेक्स बाइट्स (जो आपकी स्रोत स्ट्रिंग में थोड़ा एंडियन है) पढ़कर ऐसा करता है। एक बार इस प्रारूप में यह कोई फर्क नहीं पड़ता कि मेजबान बाइट ऑर्डर क्या है।

इसके अतिरिक्त, यह rawhex में एक बग को ठीक करता है, कुछ मामलों में कचरे के पीछे convert में डालने के लिए शून्य समाप्त होने की आवश्यकता है।

मेरे पास परीक्षण करने के लिए एक बड़ी एंडियन प्रणाली नहीं है, इसलिए कृपया अपने प्लेटफ़ॉर्म पर सत्यापित करें। यह सिग्विन के तहत संकलित और परीक्षण किया गया था।

#include <sstream> 
#include <iostream> 

int main() 
{ 
    // The hex-encoded string, and number of values are loaded from a file. 
    // The num_vals might be wrong, so some basic error checking is needed. 
    std::string inputstring = "0000003F0000803FAD10753F00000080"; 
    int num_vals = 4; 
    std::istringstream ss(inputstring); 
    size_t const k_DataSize = sizeof(float); 
    size_t const k_HexOctetLen = 2; 

    for (uint32_t i = 0; i < num_vals; ++i) 
    { 
     char rawhex[k_DataSize * k_HexOctetLen + 1]; 

     // read little endian string into memory array 
     for (uint32_t j=k_DataSize; (j > 0) && ss.good(); --j) 
     { 
      ss.read(rawhex + ((j-1) * k_HexOctetLen), k_HexOctetLen); 
     } 

     // terminate the string (needed for safe conversion) 
     rawhex[k_DataSize * k_HexOctetLen] = 0; 

     if (ss.good()) 
     { 
      std::stringstream convert; 
      convert << std::hex << rawhex; 
      uint32_t val; 
      convert >> val; 

      std::cerr << (*(float*)(&val)) << "\n"; 
     } 
     else 
     { 
      std::ostringstream os; 
      os << "Not enough values in LUT data. Found " << i; 
      os << ". Expected " << num_vals; 
      std::cerr << os.str() << std::endl; 
      throw std::exception(); 
     } 
    } 
} 
+0

यह बहुत अच्छा दिखता है, लेकिन कुछ कोड मूल कोड की तुलना में गलत तरीके से पढ़ रहे हैं। मैंने 'AD10753F' के साथ उदाहरण स्ट्रिंग को अपडेट किया है, जो लगभग 0.9ish होना चाहिए, लेकिन 4.6e-41 के रूप में पढ़ा जाता है या इस – dbr

+1

' ntohl' इस उपयोग के लिए गलत है: यह बड़े-एंडियन को देशी-एंडियन में परिवर्तित करता है , जबकि वांछित रूपांतरण देशी-एंडियन के लिए थोड़ा-अंत है। – ephemient

+0

यह संस्करण पहले संस्करण में एक स्ट्रिंग ऑर्डर समस्या को ठीक करता है। आपके सभी तीन परीक्षण मान एक छोटी एंडियन मशीन पर सही तरीके से प्रदर्शित होते हैं। यदि आपके पास पहुंच है तो कृपया एक बड़ी एंडियन प्रणाली पर सत्यापित करें। –