2012-08-27 46 views
6

में बाइनरी फ़ाइल से zlib संपीड़ित डेटा निकालें मेरी कंपनी इलेक्ट्रोमोग्राफी डेटा के लिए एक विरासत फ़ाइल प्रारूप का उपयोग करती है, जो अब उत्पादन में नहीं है। हालांकि, रेट्रो-संगतता को बनाए रखने में कुछ रूचि है, इसलिए मैं उस फ़ाइल प्रारूप के लिए पाठक लिखने की संभावना का अध्ययन कर रहा हूं।पाइथन

डेल्फी में लिखे गए एक बहुत ही मजबूत पूर्व स्रोत कोड का विश्लेषण करके, फ़ाइल रीडर/लेखक ZLIB का उपयोग करता है, और हेक्सएडिटर के अंदर ऐसा लगता है कि बाइनरी ASCII में एक फ़ाइल हैडर ("प्लेयर", "विश्लेषक" जैसे फ़ील्ड के साथ) आसानी से पठनीय), कच्चे डेटा युक्त संपीड़ित स्ट्रिंग के बाद।

मेरे संदेह नहीं है: मैं आदेश की पहचान करने में कैसे आगे बढ़ना चाहिए:

  • यदि यह एक संकुचित धारा है,
  • संपीड़ित स्ट्रीम कहां से शुरू होती है और यह कहां समाप्त होती है;
विकिपीडिया से

:

zlib संकुचित डेटा आम तौर पर एक gzip या zlib आवरण के साथ लिखा है। रैपर शीर्षलेख और ट्रेलर जोड़कर कच्चे DEFLATE डेटा को समाहित करता है। यह स्ट्रीम पहचान और त्रुटि पहचान

क्या यह प्रासंगिक है?

मुझे और जानकारी पोस्ट करने में खुशी होगी, लेकिन मुझे नहीं पता कि सबसे प्रासंगिक क्या होगा।

किसी भी संकेत के लिए धन्यवाद।

संपादित करें: मेरे पास कामकाजी एप्लिकेशन है, और यदि आवश्यक हो तो फाइलों को 1kB से भी कम प्राप्त करने के लिए किसी भी समय की वास्तविक डेटा रिकॉर्ड करने के लिए इसका उपयोग कर सकते हैं।


कुछ नमूना फ़ाइलें:

एक ताजा तैयार किया, datastream बिना: https://dl.dropbox.com/u/4849855/Mio_File/HeltonEmpty.mio

ही ऊपर के रूप में के बाद एक बहुत ही कम (1 सेकंड?) Datastream सहेज लिया गया है: https://dl.dropbox.com/u/4849855/Mio_File/HeltonFilled.mio

एक अलग धारा, "हेल्टन" के बजाय "मैनको" नामक एक मरीज से, एक छोटी सी धारा (हेक्स देखने के लिए आदर्श) के साथ: https://dl.dropbox.com/u/4849855/Mio_File/manco_short.mio

निर्देश: प्रत्येक फ़ाइल एक रोगी (एक व्यक्ति) की फाइल होनी चाहिए। इन फ़ाइलों के अंदर, एक या अधिक परीक्षाएं सहेजी जाती हैं, प्रत्येक परीक्षा में एक या अधिक समय श्रृंखला होती है। प्रदान की गई फ़ाइलों में एक डेटा श्रृंखला के साथ केवल एक परीक्षा होती है।

+0

क्या मैं आपके प्रश्न को सही समझ रहा हूं: आपके पास फ़ाइल प्रारूप का कोई उचित विनिर्देश नहीं है और फ़ाइल प्रारूप की संरचना और लेआउट की पहचान करने के लिए रिवर्स इंजीनियरिंग तकनीकों के बारे में जानना चाहते हैं? –

+0

@ लुकासग्राफ मुझ पर बहुत मुश्किल नहीं लग रहा है, लेकिन जवाब है ... हाँ! यह इस फ़ाइल प्रारूप के साथ हमारी कंपनी का आखिरी प्रयास है, लेकिन हमारे लिए कोई भी प्रगति महत्वपूर्ण होगी। – heltonbiker

+0

ठीक है, बस इतना चाहता था कि मैं सही तरीके से प्रश्न समझूं। मेरा निर्णय लेने का मतलब नहीं था :) लेकिन पाइथन तो संभवतः कार्यान्वयन के लिए भाषा के रूप में लागू होता है, एक बार जब आप रिवर्स इंजीनियरिंग को फ़ाइल प्रारूप (एक बार कार्यान्वयन से अधिक समय लेते हैं) कर लेते हैं। –

उत्तर

6

शुरू करने के लिए, क्यों सभी मान्य ज़िप धाराओं के लिए फ़ाइलें स्कैन नहीं (यह छोटे फ़ाइलों के लिए काफी अच्छा है और प्रारूप यह पता लगाने की):

import zlib 
from glob import glob 

def zipstreams(filename): 
    """Return all zip streams and their positions in file.""" 
    with open(filename, 'rb') as fh: 
     data = fh.read() 
    i = 0 
    while i < len(data): 
     try: 
      zo = zlib.decompressobj() 
      yield i, zo.decompress(data[i:]) 
      i += len(data[i:]) - len(zo.unused_data) 
     except zlib.error: 
      i += 1 

for filename in glob('*.mio'): 
    print(filename) 
    for i, data in zipstreams(filename): 
     print (i, len(data)) 

ऐसा लगता है कि डेटा धाराओं थोड़ा-endian डबल परिशुद्धता शामिल फ़्लोटिंग पॉइंट डेटा:

import numpy 
from matplotlib import pyplot 

for filename in glob('*.mio'): 
    for i, data in zipstreams(filename): 
     if data: 
      a = numpy.fromstring(data, '<f8') 
      pyplot.plot(a[1:]) 
      pyplot.title(filename + ' - %i' % i) 
      pyplot.show() 
+1

मुझे आश्चर्य है, मेरे पास कोई शब्द नहीं है। यह सिर्फ काम करना चाहिए! बेशक मुझे कल (अब घर पर) subtleties का अध्ययन करना होगा, लेकिन मैं कुछ महत्वपूर्ण बिंदुओं पर टिप्पणी करने के लिए वापस आऊंगा ताकि दूसरों को फायदा हो सके। आपके लिए समय और ब्याज बहुत बहुत धन्यवाद! – heltonbiker

8

zlib DEFLATE एल्गोरिथ्म के साथ संकुचित डेटा चारों ओर एक पतली आवरण है और RFC1950 में परिभाषित किया गया है:

A zlib stream has the following structure: 

     0 1 
    +---+---+ 
    |CMF|FLG| (more-->) 
    +---+---+ 

    (if FLG.FDICT set) 

     0 1 2 3 
    +---+---+---+---+ 
    |  DICTID | (more-->) 
    +---+---+---+---+ 

    +=====================+---+---+---+---+ 
    |...compressed data...| ADLER32 | 
    +=====================+---+---+---+---+ 

तो यह पहले कम से कम दो, संभवतः छह बाइट्स और एक साथ 4 बाइट कहते हैं कच्चे डिफलेट संपीड़ित डेटा के बाद ADLER32 चेकसम।

पहले बाइट सीएमएफ (संपीड़न विधि और झंडे) है, जो मुख्यमंत्री (संपीड़न विधि) (पहले 4 बिट्स) और CINFO (संपीड़न जानकारी) (पिछले 4 बिट्स) में विभाजित है शामिल ।

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

सौभाग्य से, मैं ADLER32 एल्गोरिदम के लेखक मार्क एडलर द्वारा एक पोस्ट पर ठोकर खाई, जहां वह lists the most common and less common combinations of those two starting bytes

कि रास्ते से बाहर के साथ

, चलो हम कैसे zlib जांच करने के लिए अजगर का उपयोग कर सकते पर ध्यान दें:

>>> import zlib 
>>> msg = 'foo' 
>>> [hex(ord(b)) for b in zlib.compress(msg)] 
['0x78', '0x9c', '0x4b', '0xcb', '0xcf', '0x7', '0x0', '0x2', '0x82', '0x1', '0x45'] 

तो पायथन के zlib मॉड्यूल के द्वारा बनाई गई (डिफ़ॉल्ट विकल्पों का उपयोग कर) zlib डेटा 78 9c साथ शुरू होता है । हम उस स्क्रिप्ट को बनाने के लिए इसका उपयोग करेंगे जो एक कस्टम फ़ाइल प्रारूप लिखने के लिए एक प्रस्तावना को जोड़ता है, कुछ zlib संपीड़ित डेटा और एक पाद लेख।

हम तो एक दूसरे स्क्रिप्ट है कि दो बाइट पैटर्न के लिए एक फ़ाइल को स्कैन करता है लिखने सब कुछ है कि एक zlib धारा के रूप में इस प्रकार है और का पता लगा लेता decompressing शुरू होता है जहां धारा समाप्त होता है और पाद लेख शुरू होता है।

create.py

import zlib 

msg = 'foo' 
filename = 'foo.compressed' 

compressed_msg = zlib.compress(msg) 
data = 'HEADER' + compressed_msg + 'FOOTER' 

with open(filename, 'wb') as outfile: 
    outfile.write(data) 

यहाँ हम msg ले, zlib के साथ यह सेक, और एक शीर्ष लेख और पाद लेख इससे पहले कि हम यह एक फाइल करने के लिए लिखने के साथ उसके दोनों ओर।

शीर्षलेख और पाद लेख इस उदाहरण में निश्चित लंबाई के हैं, लेकिन वे निश्चित रूप से मनमाने ढंग से, अज्ञात लंबाई हो सकते हैं।

अब ऐसी स्क्रिप्ट के लिए जो ऐसी फ़ाइल में zlib स्ट्रीम ढूंढने का प्रयास करता है। क्योंकि के लिए यह उदाहरण हम जानते हैं कि मार्कर को उम्मीद है कि मैं केवल एक का उपयोग कर रहा हूं, लेकिन स्पष्ट रूप से सूची ZLIB_MARKERS ऊपर वर्णित पोस्ट के सभी मार्करों से भरी जा सकती है।

फ़ाइल की शुरुआत में
  • प्रारंभ और एक दो बाइट खोज खिड़की बनाने के लिए:

    ident.py

    import zlib 
    
    ZLIB_MARKERS = ['\x78\x9c'] 
    filename = 'foo.compressed' 
    
    infile = open(filename, 'r') 
    data = infile.read() 
    
    pos = 0 
    found = False 
    
    while not found: 
        window = data[pos:pos+2] 
        for marker in ZLIB_MARKERS: 
         if window == marker: 
          found = True 
          start = pos 
          print "Start of zlib stream found at byte %s" % pos 
          break 
        if pos == len(data): 
         break 
        pos += 1 
    
    if found: 
        header = data[:start] 
    
        rest_of_data = data[start:] 
        decomp_obj = zlib.decompressobj() 
        uncompressed_msg = decomp_obj.decompress(rest_of_data) 
    
        footer = decomp_obj.unused_data 
    
        print "Header: %s" % header 
        print "Message: %s" % uncompressed_msg 
        print "Footer: %s" % footer 
    
    if not found: 
        print "Sorry, no zlib streams starting with any of the markers found." 
    

    विचार यह है।

  • एक-बाइट वृद्धि में खोज विंडो को आगे ले जाएं।

  • प्रत्येक विंडो के लिए जांच करें कि क्या यह दो बाइट मार्करों में से किसी एक से मेल खाता है, जिसे हम परिभाषित करते हैं।

  • यदि कोई मिलान मिलता है, तो प्रारंभिक स्थिति रिकॉर्ड करें, खोज बंद करें और निम्नानुसार होने वाली सभी चीज़ों को कम करने का प्रयास करें।

अब, धारा के अंत खोजने दो मार्कर बाइट्स की तलाश के रूप में के रूप में तुच्छ नहीं है। zlib धाराओं को न तो एक निश्चित बाइट अनुक्रम द्वारा समाप्त किया जाता है और न ही उनकी लंबाई किसी भी शीर्ष लेख फ़ील्ड में इंगित होती है। इसकी बजाय इसे द्वारा चार बाइट ADLER32 चेकसम समाप्त कर दिया गया है जो इस बिंदु तक डेटा से मेल खाना चाहिए।

तरह से यह काम करता है कि आंतरिक सी समारोह inflate() लगातार धारा को संपीड़ित के रूप में यह इसे पढ़ता है की कोशिश कर रहा है, और रहता है अगर यह एक मिलान चेकसम, संकेत भर आता है कि अपनी कॉलर को, जो यह दर्शाता है कि के बाकी डेटा ज़्लिब स्ट्रीम का हिस्सा नहीं है।

पायथन में यह व्यवहार zlib.decompress() पर कॉल करने के बजाय डिकंप्रेशन ऑब्जेक्ट्स का उपयोग करते समय सामने आया है। पर Decompress ऑब्जेक्ट पर कॉलिंग string में एक zlib स्ट्रीम को डिक्रप्रेस करेगा और स्ट्रीम का हिस्सा था जो डिकंप्रेस्ड डेटा वापस कर देगा। स्ट्रीम का पालन करने वाली हर चीज unused_data में संग्रहीत की जाएगी और बाद में पुनर्प्राप्त की जा सकती है।

यह पहली स्क्रिप्ट के साथ बनाई गई एक फ़ाइल पर निम्नलिखित उत्पादन का उत्पादन करना चाहिए:

Start of zlib stream found at byte 6 
Header: HEADER 
Message: foo 
Footer: FOOTER 

उदाहरण आसानी से इसे मुद्रण के बजाय एक फ़ाइल असंपीड़ित संदेश लिखने के लिए संशोधित किया जा सकता। फिर आप पहले zlib संपीड़ित डेटा का विश्लेषण कर सकते हैं, और हेडर और पाद लेख में मेटाडेटा में ज्ञात फ़ील्ड को पहचानने का प्रयास कर सकते हैं।

+0

आपके द्वारा प्रदान की गई स्पष्टीकरण बहुत ही प्रबुद्ध है, और मैं इसे पूरी तरह से पढ़ने की योजना बना रहा हूं। अंत में, cgohlke ने कुछ हद तक ब्रूटफोर्स प्रदान किए जो मेरी छोटी आकार की फाइलों के लिए काम करते थे, लेकिन मुझे लगता है कि आपको सुझाए गए दो बाइट हेडर की तलाश करनी होगी।जैसे ही मुझे कुछ अच्छे नतीजे मिलते हैं मैं वापस आ जाता हूं, आपके समय और ब्याज के लिए बहुत बहुत धन्यवाद! – heltonbiker

+0

उत्कृष्ट! मुझे लगता है कि मेरा जवाब समस्या के विवरण और पृष्ठभूमि के बारे में कुछ शैक्षणिक मूल्य प्रदान कर सकता है, फिर भी @ cgohlke द्वारा प्रदान किया गया समाधान मेरा से अधिक सुरुचिपूर्ण है। यह प्रति फ़ाइल एकाधिक धाराओं के लिए खाता है और दो बाइट मार्कर पर भरोसा नहीं करता है। यदि आप zlib को आपके लिए यह काम करने दे सकते हैं जो इसे आसान बनाने से अधिक आसान और संभवतः अधिक विश्वसनीय है। –

+0

मैं आपकी समझ की सराहना करता हूं। असल में, मैंने उसका जवाब चुना है क्योंकि उसने कोड लाइनों के समूह के साथ सही ढंग से मेरे चेहरे पर सही प्लॉट किए गए परिणाम फेंक दिए हैं, भले ही मैं बड़ी फ़ाइलों पर ब्रूट-फोर्स का उपयोग करने की योजना नहीं बना रहा हूं, बल्कि इसके बजाय अपने हेडर बाइट्स का उपयोग करने की योजना नहीं बना रहा हूं धाराओं की शुरुआत सही तरीके से देखने के लिए। एक बार फिर धन्यवाद! – heltonbiker