Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Zippex. Native Apex Zip Library

Zippex. Native Apex Zip Library

Open source Zip library in Apex for Salesforce.com. https://github.com/pdalcol/Zippex

Pedro Dal Col

March 15, 2016
Tweet

Other Decks in Programming

Transcript

  1. Challenges in Apex • No Zip support out of the

    box • No binary operations (Blob class) • Governor limits
  2. Working With Binary Data Blob b = data; // data

    contains [0x0c] String hexStr = EncodingUtil.convertToHex(b); // '0c' Integer i = hexToInt(hexStr); // '0c' => 12 i = i + 2; // 12 + 2 = 14 hexStr = intToHex(i, 1); // 14 => '0e' b = EncodingUtil.convertFromHex(hexStr); //[0x0e]
  3. Converting ASCII to Decimal Hex ASCII Dec '0' 48 0

    '1' 49 1 '2' 50 2 '3' 51 3 '4' 52 4 '5' 53 5 '6' 54 6 '7' 55 7 '8' 56 8 '9' 57 9 'a' 97 10 'b' 98 11 'c' 99 12 'd' 100 13 'e' 101 14 'f' 102 15 Bin 0110000 0110001 0110010 0110011 0110100 0110101 0110110 0110111 0111000 0111001 1100001 1100010 1100011 1100100 1100101 1100110 Bin 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 + 0 = + 0 = + 0 = + 0 = + 0 = + 0 = + 0 = + 0 = + 0 = + 0 = + 1001 = + 1001 = + 1001 = + 1001 = + 1001 = + 1001 = String value Integer value
  4. Converting ASCII to Decimal String hexStr = 'c'; // 'c'

    = 99 = 0b1100011 Integer char = hexStr.charAt(0); // = 99 ('c' in ASCII) Integer i = (char & 15) + (char >>> 6) * 9; // (0b1100011 & 0b1111) + (0b1100011>>>6) * 9 // 0b0011 + 0b1 * 9 // 3 + 1 * 9 // 12 (in Decimal)
  5. Zip Structure 3 Header types: • Local Header • Central

    Directory Header • End of Central Directory
  6. Local Header Signature (PK0304) Extra Field (variable size) Compressed Size

    Uncompressed size CRC-32 Version Flags Compression Mod Time File Name Len Mod Date Extra Field Len CRC-32 File Name (variable size) 0 1 2 3 4 5 6 7 8 9 A B C D E F 0_ 1_ 2_ 3_
  7. Central Directory Header Signature (PK0102) Extra Field (variable size) Compressed

    Size Uncompressed size Version Flags Compression Mod Time File Name Len Mod Date Extra Field Len Crc-32 File Name (variable size) 0_ 1_ 2_ 3_ Vers Needed File Comm Len Disk # start Internal Atr External Attributes Offset of local header File Comment (variable size) 4_ 5_ 0 1 2 3 4 5 6 7 8 9 A B C D E F
  8. End of Central Directory Signature (PK0506) ZIP file comment (Variable)

    Offset of Central Dir Disk Number Disk # w/cd Disk Entries Total Entries 0 1 2 3 4 5 6 7 8 9 A B C D E F 0_ 1_ Central Directory Size Comment len
  9. Overall Zip structure Local File Header 1 File Data 1

    Local File Header 2 File Data 2 Local File Header … File Data … End of Central Directory Central Directory Headers File 1 File 2 … Local File Header n File Data n File n
  10. Add a file Local File Header 1 File Data 1

    Local File Header 2 File Data 2 End of Central Directory Central Directory File 1 File 2 File object 1 File object 2 File Info File object 1 File Info File object 1 Memory representation of file data need to create local and central directory headers File 3 object File Info File Data Local File Header 3 File Data 3 File 3 object File Info End of Central Directory Central Directory File 1 File 2 File 3 Blob Zip Archive String Collection of File Objects
  11. Local File Header 1 File Data 1 Remove a file

    Zip Archive String File object 1 Collection of File Objects File Info File object 1 Local File Header 2 File Data 2 File object 2 File Info File object 1 File 1 File 2 Local File Header 3 File Data 3 File 3 object File Info End of Central Directory Central Directory File 1 File 3
  12. One.txt 7 Three.txt 9 FileName Length Three.txt One.txt Rename a

    file Zip Archive String Collection of File Objects End of Central Directory Central Directory File 1 File 3 Local File Header 1 File Data 1 File object 1 File Info File object 1 Local File Header 3 File Data 3 File 3 object File Info Three.txt One.txt Change One.txt to First.txt Signature Compressed Size Uncompressed size Crc-32 Version Flags Compression Mod Time File Name Len Mod Date Extra Field Len Crc-32 File Name (7 bytes) 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 _ 1 _ 2 _ Signature Compressed Size Uncompressed size Crc-32 Version Flags Compression Mod Time File Name Len Mod Date Extra Field Len Crc-32 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 _ 1 _ 2 _ Local Header File name len = 7 File name = One.txt File name len = 9 File name = First.txt File Name (9 bytes)
  13. One.txt 7 Three.txt 9 FileName Length Three.txt One.txt Rename a

    file Zip Archive String Collection of File Objects End of Central Directory Central Directory File 1 File 3 Local File Header 1 File Data 1 File object 1 File Info File object 1 Local File Header 3 File Data 3 File 3 object File Info Three.txt One.txt Change One.txt to First.txt Signature Compressed Size Uncompressed size Crc-32 Version Flags Compression Mod Time File Name Len Mod Date Extra Field Len Crc-32 File Name (7 bytes) 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 _ 1 _ 2 _ Signature Compressed Size Uncompressed size Crc-32 Version Flags Compression Mod Time File Name Len Mod Date Extra Field Len Crc-32 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 _ 1 _ 2 _ Local Header File name len = 7 File name = One.txt File name len = 9 File name = First.txt File Name (9 bytes)
  14. Rename a file First.txt 9 Zip Archive String Collection of

    File Objects Local File Header 1 File Data 1 File object 1 File Info File object 1 Local File Header 3 File Data 3 File 3 object File Info FileName Length First.txt Three.txt 9 Three.txt First.txt End of Central Directory Central Directory File 1 File 3 Three.txt
  15. Zippex Methods: Add, Remove, and Rename files addFile(fileName, fileData, crc32)

    Example: Zippex sampleZip = new Zippex(); Blob fileData = Blob.valueOf('Sample text.'); sampleZip.addFile('file1.txt', fileData, null);
  16. Zippex Methods: Add, Remove, and Rename files addFile(fileName, fileData, crc32)

    removeFile(fileName) Example: Zippex sampleZip = new Zippex(); Blob fileData = Blob.valueOf('Sample text.'); sampleZip.addFile(‘file1.txt', fileData, null); sampleZip.addFile('file2.txt', Blob.valueOf('text two.'), null); sampleZip.removeFile('file1.txt'); file2
  17. Zippex Methods: Add, Remove, and Rename files addFile(fileName, fileData, crc32)

    removeFile(fileName) renameFile(oldName, newName) Example: Zippex sampleZip = new Zippex(); Blob fileData = Blob.valueOf('Sample text.'); sampleZip.addFile(‘file1.txt', fileData, null); sampleZip.addFile('file2.txt', Blob.valueOf('text two.'), null); sampleZip.removeFile('file1.txt'); sampleZip.renameFile(‘file2.txt’,’newName.txt'); Blob zipData = sampleZip.getZipArchive(); file2 new Name
  18. Zippex Methods: getFileNames and getFile List<String> getFileNames() Example: Zippex myZip

    = new Zippex(zipArchive); System.debug(myZip.getFileNames()); //{'file1.txt', 'file2.txt'} End of Central Dir Central Dir File 1 File 2 Local File Header 1 File Data 1 Local File Header 2 File Data 2 file1.txt file2.txt zipArchive
  19. Zippex Methods: getFileNames and getFile List<String> getFileNames() Blob getFile(fileName) Example:

    Zippex myZip = new Zippex(zipArchive); System.debug(myZip.getFileNames()); //{'file1.txt', 'file2.txt'} Blob data = myZip.getFile('file2.txt'); End of Central Dir Central Dir File 1 File 2 Local File Header 1 File Data 1 Local File Header 2 File Data 2 file1.txt file2.txt zipArchive
  20. Demo — Create a Zip Archive and Add Files —

    Open an Existing Zip Archive From an Attachment — Extract Text From a Word File — Merge Fields in Word File
  21. DEMO: Create a Zip Archive and Add Files Zippex sampleZip

    = new Zippex();sampleZip.addFile('sampleFolder/file1.txt', Blob.valueOf('Sample text1b.'), null); sampleZip.addFile('sampleFolder/file2.txt', Blob.valueOf('Sample text2.'), null); sampleZip.addFile('topfolder/innerFolder/file1.txt', Blob.valueOf('Sample text1a.'), null); sampleZip.addFile('sampleFolder/file3.txt', Blob.valueOf('Sample text3.'), null); sampleZip.addFile('topfolder/innerFolder/file4.txt', Blob.valueOf('Sample text4.'), null); insert new Attachment(Name = 'SampleZip.zip', Body = sampleZip.getZipArchive(), ParentId = '00Qj000000KIckN');
  22. DEMO: Open an Existing Zip Archive From an Attachment Blob

    wordBlob = [SELECT Body FROM Attachment WHERE Name = 'TestData.docx' LIMIT 1].Body; Zippex sampleZip = new Zippex(wordBlob); for (String fileName : sampleZip.getFileNames()) System.debug(fileName);
  23. DEMO: Extract Text From a Word File Zippex myZip =

    new Zippex(TestData.wordTemplate); String wordDoc = myZip.getFile('word/document.xml’).toString(); System.debug(wordDoc.stripHtmlTags());
  24. DEMO: Merge Fields in Word File Id leadId = '00Qj0000004p4rgEAA’;

    Zippex myZip = new Zippex(TestData.wordTemplate); String wordDoc = myZip.getFile('word/document.xml').toString(); wordDoc = mergeFields(wordDoc, leadId); myZip.addFile('word/document.xml', Blob.valueOf(wordDoc), null); insert new Attachment(Name = 'Letter.docx', Body = myZip.getZipArchive(), ParentId = leadId); String mergeFields(String doc, Id sObjId) { Lead lead = [SELECT Name, Company, Owner.Name FROM Lead WHERE Id=:sObjId]; doc = doc.replace('{!Lead.Name}', lead.Name) .replace('{!Lead.Company}', lead.Company) .replace('{!Lead.Owner.Name}', lead.Owner.Name); return doc; }
  25. Pedro Dal Col [email protected] @pedrodalcol (Twitter) Pliny Smith [email protected] @PlinyASmith(Twitter)

    Project Repository: https://github.com/pdalcol/Zippex Zip File Format Specification: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT