2009-11-30 12 views
11

उम्मीद है कि आपने neat hack के बारे में सुना है जो आपको एक जेपीजी और ज़िप फ़ाइल को एक फ़ाइल में जोड़ती है और यह दोनों प्रारूपों के लिए एक मान्य (या कम से कम पठनीय) फ़ाइल है। खैर, मुझे एहसास हुआ कि चूंकि जेपीजी अंत में मनमाने ढंग से सामान देता है, और शुरुआत में ज़िप, आप बीच में एक और प्रारूप चिपक सकते हैं - बीच में। इस प्रश्न के प्रयोजनों के लिए, मान लें कि मध्यम डेटा मनमाना बाइनरी डेटा है जो जेपीजी या ज़िप प्रारूपों के साथ संघर्ष नहीं करता है (जिसका अर्थ है कि इसमें जादू ज़िप हेडर 0x04034b50 नहीं है)। उदाहरण:जेपी प्रारूप के साथ जेपीजी + ज़िप फ़ाइल संयोजन समस्या

0xFFD8 <- start jpg data end -> 0xFFD9 ... ARBITRARY BINARY DATA ... 0x04034b50 <- start zip file ... EOF 

मैं इस तरह catting हूँ:

बिल्ली "mss_1600.jpg" filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb "null.bytes" "randomzipfile.zip"> temp.zip

यह 6,318 केबी फ़ाइल बनाता है। यह 7-ज़िप में खुला नहीं है। हालांकि, जब मैं बिल्ली एक कम 'डबल' (ताकि बजाय 13 filea और ख के, 12):

बिल्ली "mss_1600.jpg" filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb "null.bytes" "randomzipfile.zip"> temp.zip

ऐसा नहीं है कि 7-Zip में खुला करता है एक 5996 KB फ़ाइल पैदा करता है।

तो मुझे पता है कि मेरे मनमाना बाइनरी डेटा में जादू ज़िप फ़ाइल शीर्षलेख इसे खराब करने के लिए नहीं है। मेरे पास working jpg+data+zip और non-working jpg+data+zip की संदर्भ फ़ाइलें हैं (सहेजने के कारण ब्राउज़र सोचता है कि वे छवियां हैं, और ज़िप एक्सटेंशन स्वयं जोड़ें)।

मैं जानना चाहता हूं कि यह 13 संयोजनों के साथ क्यों विफल रहता है और 12 के साथ नहीं है। बोनस अंक के लिए, मुझे किसी भी तरह से इसे प्राप्त करने की आवश्यकता है।

+1

बस यह इंगित करना चाहता था कि यह शायद 7Zip के एल्गोरिदम के साथ समस्या है, क्योंकि फ़ाइल रोलर गैर-कार्य उदाहरण भी खोलने में कामयाब रहा। – laginimaineb

+1

साफ चाल - अब से मैं अपने सभी जावा में अपने आप को एक तस्वीर डालने के लिए इस तकनीक का उपयोग करने जा रहा हूं .jar (निष्पादन योग्य जार-पेग्स :) – Seth

उत्तर

10

वास्तव में यह वास्तव में एक दो भाग जवाब :)

लोग कहते हैं कि ज़िप फ़ाइलों नहीं तकनीकी रूप से फ़ाइलों के अंत में शब्दशः रखा जा सकता है सबसे पहले कोई फर्क नहीं पड़ता है। केंद्रीय निर्देशिका रिकॉर्ड के अंत में एक मान होता है जो वर्तमान डिस्क की शुरुआत से बाइट ऑफसेट इंगित करता है (यदि आपके पास केवल एक .zip फ़ाइल है, जिसका अर्थ है वर्तमान फ़ाइल)। अब प्रोसेसर के बहुत सारे इस पर ध्यान नहीं देते हैं, हालांकि विंडोज़ ज़िप फ़ोल्डर ऐसा नहीं करता है, इसलिए आपको विंडोज एक्सप्लोरर में काम करने के लिए उस मान को सही करने की आवश्यकता है (नहीं कि आप परवाह कर सकते हैं; पी) फ़ाइल प्रारूप पर जानकारी के लिए Zip APPNOTE देखें। मूल रूप से आप प्रारंभिक डिस्क संख्या के संबंध में "केंद्रीय निर्देशिका की शुरुआत की ऑफसेट" मान को खोजने के लिए हेक्स संपादक (या एक उपकरण लिखते हैं) में पाते हैं। फिर पहले "केंद्रीय फ़ाइल शीर्षलेख हस्ताक्षर" (504b0102 का हेक्स) ढूंढें और उस ऑफ़सेट पर मान सेट करें।

अब यह 7zip को ठीक नहीं करता है, लेकिन जिस तरह से 7zip फ़ाइल प्रारूप का अनुमान लगाने की कोशिश करता है। असल में यह केवल बाइनरी अनुक्रम 504b0304 के लिए पहली ~ 4 एमआईबी खोजेगा, अगर ऐसा नहीं लगता है तो यह मानता है कि यह ज़िप नहीं है और इसके अन्य संग्रह प्रारूपों को आजमाता है। यह स्पष्ट रूप से एक और फ़ाइल जोड़ना चीजें क्यों जोड़ता है, यह खोज के लिए सीमा पर इसे धक्का देता है।

अब इसे ठीक करने के लिए आपको जो करना है वह है कि हेक्स स्ट्रिंग को तोड़ने के बिना जेपीईजी में जोड़ें। ऐसा करने का एक तरीका है एफएफडी 8 जेपीईजी एसओआई हेडर के बाद निम्नलिखित हेक्स डेटा, एफएफईएफ0005504 बी030400। यह आपके अनुक्रम के साथ एक कस्टम ब्लॉक जोड़ता है और सही है इसलिए जेपीईजी हेडर को इसे अनदेखा करना चाहिए।

+0

यह मिला मुझे रास्ते का 60%। मुझे उनके ऑफसेट को बदलने के लिए 504b0102 प्रविष्टियों को भी संशोधित करना था अन्यथा इसे खोला गया लेकिन आपने फ़ाइलों को निकालने की अनुमति नहीं दी। मैं ** सोचता हूं ** मेरे पास विंडोज एक्सप्लोरर और 7-ज़िप में एक काम कर रहे jpg/ज़िप है, लेकिन मुझे कल और परीक्षण करने की आवश्यकता है। –

20

मैंने 7-ज़िप के लिए स्रोत डाउनलोड किया और यह पता लगाया कि यह क्या हो रहा है।

सीपीपी/7zip/यूआई/आम/OpenArchive.cpp में, आपको निम्न देखेंगे:

// Static-SFX (for Linux) can be big. 
const UInt64 kMaxCheckStartPosition = 1 << 22; 

इसका मतलब है कि केवल पहले 4,194,304 फ़ाइल के बाइट्स हेडर के लिए खोज की जाएगी। यदि यह वहां नहीं मिला है, तो 7-ज़िप इसे एक अवैध फ़ाइल मानता है।

आप 1 << 22 से 1 << 23 पर बदलकर उस सीमा को दोगुना कर सकते हैं। मैंने 7-ज़िप पुनर्निर्माण करके उस परिवर्तन का परीक्षण किया और यह काम करता है।

EDIT: इस समस्या को हल करने के लिए, आप download the source कर सकते हैं, उपर्युक्त परिवर्तन कर सकते हैं और इसे बना सकते हैं। मैंने इसे वीएस 2008 का उपयोग करके बनाया है। वीएस कमांड प्रॉम्प्ट खोलें, निकाले गए-स्रोत-स्थान \ CPP \ 7zip \ Bundles पर जाएं और 'nmake' टाइप करें। फिर अकेले निर्देशिका में '7za टी nonworking चलाते हैं।jpg 'और आपको' सब कुछ ठीक है 'देखना चाहिए।

+0

अविश्वसनीय अच्छा सर। मुझे आश्चर्य है कि क्या मैं बाइट्स के पहले दौर में सही फॉर्म की एक नकली फ़ाइल डाल सकता हूं और 7-ज़िप की चाल कर सकता हूं ... मैं थोड़ी देर खेलने जा रहा हूं (और स्वीकार करने से पहले थोड़ा इंतजार कर रहा हूं, कोई अपराध नहीं) –

4
किसी और को इस सवाल को खोजने के लिए

तो, यहाँ कहानी है:

हाँ, एंडी क्यों 7-ज़िप फ़ाइल पर विफल हो रहा है के रूप में सचमुच सही है, लेकिन यह बाद से मैं यह कर सकते हैं मेरी समस्या मदद नहीं करता है ' लोगों को वास्तव में 7-ज़िप के मेरे संस्करण का उपयोग करने के लिए मिलता है।

tyranid हालांकि मुझे समाधान मिला।

  • सबसे पहले, जेपीजी को एक छोटे से बाइटिंग को जोड़कर, जैसा कि वह सुझाव देता है 7-ज़िप इसे खोल देगा। हालांकि, यह एक वैध जेपीजी खंड से थोड़ी दूर है, इसे FFEF00 504B030400 होना चाहिए - लंबाई 2 बाइट्स से बंद थी।
  • इससे 7-ज़िप इसे खोलने देता है, लेकिन फ़ाइलों को निकालने नहीं देता है, यह चुपचाप विफल रहता है। ऐसा इसलिए है क्योंकि केंद्रीय निर्देशिका में प्रविष्टियों में आंतरिक पॉइंटर्स/ऑफ़सेट होते हैं जो फ़ाइल के प्रवेश को इंगित करते हैं। चूंकि आप इससे पहले सामान का एक गुच्छा डालते हैं, आपको उन सभी पॉइंटर्स को सही करने की ज़रूरत है!
  • ज़िप समर्थन में बनाए गए विंडोज के साथ ज़िप खोलने के लिए, आपको टायरिनिड कहते हैं, "प्रारंभिक डिस्क संख्या के संबंध में केंद्रीय निर्देशिका की शुरुआत की ऑफसेट" को सही करने की आवश्यकता है। इधर, पिछले दो करने के लिए एक अजगर स्क्रिप्ट है, हालांकि यह एक टुकड़ा है, है ना copypasta के लिए तैयार के लिए उपयोग

#Now we need to read the file and rewrite all the zip headers. Fun! 
torewrite = open(magicfilename, 'rb') 
magicdata = torewrite.read() 
torewrite.close() 

#Change the Central Repository's Offset 
offsetOfCentralRepro = magicdata.find('\x50\x4B\x01\x02') #this is the beginning of the central repo 
start = len(magicdata) - 6 #it so happens, that on my files, the point is stored 2 bytes from the end. so datadatadatdaata OF FS ET !! 00 00 EOF where OFFSET!! is the 4 bytes 00 00 are the last two bytes, then EOF 
magicdata = magicdata[:start] + pack('I', offsetOfCentralRepro) + magicdata[start+4:] 

#Now change the individual offsets in the central directory files 
startOfCentralDirectoryEntry = magicdata.find('\x50\x4B\x01\x02', 0) #find the first central directory entry 
startOfFileDirectoryEntry = magicdata.find('\x50\x4B\x03\x04', 10) #find the first file entry (we start at 10 because we have to skip past the first fake entry in the jpg) 
while startOfCentralDirectoryEntry > 0: 
    #Now I move a magic number of bytes past the entry (really! It's 42!) 
    startOfCentralDirectoryEntry = startOfCentralDirectoryEntry + 42 

    #get the current offset just to output something to the terminal 
    (oldoffset,) = unpack('I', magicdata[startOfCentralDirectoryEntry : startOfCentralDirectoryEntry+4]) 
    print "Old Offset: ", oldoffset, " New Offset: ", startOfFileDirectoryEntry , " at ", startOfCentralDirectoryEntry 
    #now replace it 
    magicdata = magicdata[:startOfCentralDirectoryEntry] + pack('I', startOfFileDirectoryEntry) + magicdata[startOfCentralDirectoryEntry+4:] 

    #now I move to the next central directory entry, and the next file entry 
    startOfCentralDirectoryEntry = magicdata.find('\x50\x4B\x01\x02', startOfCentralDirectoryEntry) 
    startOfFileDirectoryEntry = magicdata.find('\x50\x4B\x03\x04', startOfFileDirectoryEntry+1) 

#Finally write the rewritten headers' data 
towrite = open(magicfilename, 'wb') 
towrite.write(magicdata) 
towrite.close() 
+0

अपना कोड साझा करने के लिए धन्यवाद (और यह खुलासा कि अर्थ 42 है;))। और समझाने की कोई ज़रूरत नहीं है - मैंने बहुत कुछ सीखा और यह वैसे भी मजेदार था। –

+0

क्षमा करें अगर मुझे कुछ चीजें मिल गईं। हालांकि धन्यवाद :) – tyranid

2

आप संकर जेपीजी + DotNetZip का उपयोग कर ज़िप फ़ाइलों का उत्पादन कर सकते हैं। DotNetZip एक स्ट्रीम में सहेज सकता है, और यह पूर्व-मौजूदा स्ट्रीम के मूल ऑफसेट को पहचानने से पहले बुद्धिमान है, इससे पहले कि इसमें ज़िप सामग्री लिखना शुरू हो जाए। इसलिए छद्म कोड में, आप एक JPG मिल + इस तरह से ज़िप कर सकते हैं:

open stream on an existing JPG file for update 
seek to the end of that stream 
open or create a zip file 
call ZipFile.Save to write zip content to the JPG stream 
close 

सभी ऑफसेट सही ढंग से समझ रहे हैं। एक ही तकनीक का उपयोग स्वयं निकालने वाले संग्रह का उत्पादन करने के लिए किया जाता है। आप EXE पर स्ट्रीम खोल सकते हैं, फिर अंत तक खोज सकते हैं, और उस स्ट्रीम में ज़िप सामग्री लिख सकते हैं। यदि आप इसे इस तरह करते हैं तो सभी ऑफ़सेट सही ढंग से गणना की जाती हैं।

एक और बात - किसी अन्य पोस्ट में टिप्पणियों में से एक के बारे में ... ज़िप फ़ाइल के अंत में और में अनियंत्रित डेटा हो सकता है। जहां तक ​​मुझे पता है कि ज़िप केंद्रीय निर्देशिका को फ़ाइल के अंत में होना आवश्यक है, हालांकि यह सामान्य है।

संबंधित मुद्दे