class ZCL_EXCEL_ABAP_ZIP definition public final create public . *"* public components of class ZCL_EXCEL_ABAP_ZIP *"* do not include other source files here!!! public section. type-pools IHTTP . types: BEGIN OF T_FILE, name TYPE string, date TYPE d, time TYPE t, size TYPE i, END OF T_FILE . types: T_FILES TYPE TABLE OF T_FILE . types: BEGIN OF T_SPLICE_ENTRY, name TYPE string, offset TYPE i, length TYPE i, compressed TYPE i, END OF T_SPLICE_ENTRY . types: T_SPLICE_ENTRIES TYPE STANDARD TABLE OF T_SPLICE_ENTRY WITH DEFAULT KEY . data FILES type T_FILES read-only . type-pools ABAP . data SUPPORT_UNICODE_NAMES type ABAP_BOOL value ABAP_FALSE. "#EC NOTEXT . methods LOAD importing !ZIP type XSTRING exceptions ZIP_PARSE_ERROR . methods SAVE returning value(ZIP) type XSTRING . methods GET importing !NAME type STRING optional value(INDEX) type I default 0 exporting !CONTENT type XSTRING exceptions ZIP_INDEX_ERROR ZIP_DECOMPRESSION_ERROR . methods ADD importing !NAME type STRING !CONTENT type XSEQUENCE . methods DELETE importing !NAME type STRING optional value(INDEX) type I default 0 exceptions ZIP_INDEX_ERROR . class-methods CRC32 importing !CONTENT type XSTRING returning value(CRC32) type I . class-methods SPLICE importing !ZIP type XSTRING returning value(ENTRIES) type T_SPLICE_ENTRIES . *"* protected components of class CL_ABAP_ZIP *"* do not include other source files here!!! protected section. *"* private components of class CL_ABAP_ZIP *"* do not include other source files here!!! private section. types: BEGIN OF T_EXT, min_extract_version TYPE i, gen_flags TYPE i, compressed TYPE i, compsize TYPE i, crc32(4) TYPE x, filename_len TYPE i, filename TYPE xstring, extra_len TYPE i, extra TYPE xstring, content TYPE xstring, END OF T_EXT . types: T_EXTS TYPE TABLE OF T_EXT . data EXTS type T_EXTS . class-data CRC32_MAP type XSTRING . CLASS msdos IMPLEMENTATION. METHOD from_date. " IMPORTING msdos_date TYPE i RETURNING value(date) TYPE d * MS-DOS format for date: * Bits 15:9 = year - 1980 * Bits 8:5 = month of year * Bits 4:0 = day of month CONSTANTS: mFE00(2) TYPE x VALUE 'FE00', m01E0(2) TYPE x VALUE '01E0', m001F(2) TYPE x VALUE '001F'. DATA: x(2) TYPE x, year TYPE i, month TYPE i, day TYPE i, c4(4) TYPE c, str TYPE string. * Bits 15:9 = year - 1980 x = msdos_date. x = x BIT-AND mFE00. x = x DIV 512. " >> 9 x = x BIT-AND m001F. year = x. year = year + 1980. WRITE year TO c4 USING EDIT MASK 'RR____'. CONCATENATE str c4 INTO str. * Bits 8:5 = month of year x = msdos_date. x = x BIT-AND m01E0. x = x DIV 32. " >> 5 x = x BIT-AND m001F. month = x. WRITE month TO c4 USING EDIT MASK 'RR__'. CONCATENATE str c4 INTO str. * Bits 4:0 = day of month x = msdos_date. x = x BIT-AND m001F. day = x. WRITE day TO c4 USING EDIT MASK 'RR__'. CONCATENATE str c4 INTO str. * Build date TRANSLATE str USING ' 0'. date = str. ENDMETHOD. METHOD from_time. " IMPORTING msdos_time TYPE i RETURNING value(time) TYPE t. * MS-DOS format for time: * Bits 15:11 = hour (24-hour clock) * Bits 10:5 = minute * Bits 4:0 = second/2 CONSTANTS: mF100(2) TYPE x VALUE 'F100', m07E0(2) TYPE x VALUE '07E0', m003F(2) TYPE x VALUE '003F', m001F(2) TYPE x VALUE '001F'. DATA: x(2) TYPE x, hour TYPE i, min TYPE i, c4(4) TYPE c, str TYPE string. * Bits 15:11 = hour (24-hour clock) x = msdos_time. x = x BIT-AND mF100. x = x DIV 2048. " >> 11 x = x BIT-AND m001F. hour = x. WRITE hour TO c4 USING EDIT MASK 'RR__'. CONCATENATE str c4 INTO str. * Bits 10:5 = minute x = msdos_time. x = x BIT-AND m07E0. x = x DIV 32. " >> 5 x = x BIT-AND m003F. min = x. WRITE min TO c4 USING EDIT MASK 'RR__'. CONCATENATE str c4 INTO str. * Bits 4:0 = second/2 CONCATENATE str '00' INTO str. * Build time TRANSLATE str USING ' 0'. time = str. ENDMETHOD. METHOD to_date. " IMPORTING date TYPE d RETURNING value(msdos_date) TYPE i. * MS-DOS format for date: * Bits 15:9 = year - 1980 * Bits 8:5 = month of year * Bits 4:0 = day of month DATA: xdate(2) TYPE x, x(2) TYPE x, year TYPE i, month TYPE i, day TYPE i. * Bits 15:9 = year - 1980 year = date+0(4). x = year - 1980. x = x * 512. " << 9 xdate = xdate BIT-OR x. * Bits 8:5 = month of year month = date+4(2). x = month. x = x * 32. " << 5 xdate = xdate BIT-OR x. * Bits 4:0 = day of month day = date+6(2). x = day. xdate = xdate BIT-OR x. msdos_date = xdate. ENDMETHOD. METHOD to_time. " IMPORTING time TYPE t RETURNING value(msdos_time) TYPE i. * MS-DOS format for time: * Bits 15:11 = hour (24-hour clock) * Bits 10:5 = minute * Bits 4:0 = second/2 DATA: xtime(2) TYPE x, x(2) TYPE x, hour TYPE i, min TYPE i, sec TYPE i. * Bits 15:11 = hour (24-hour clock) hour = time+0(2). x = hour. x = x * 2048. " << 11 xtime = xtime BIT-OR x. * Bits 10:5 = minute min = time+2(2). x = min. x = x * 32. " << 5 xtime = xtime BIT-OR x. * Bits 4:0 = seconds sec = time+4(2). x = sec / 2. xtime = xtime BIT-OR x. msdos_time = xtime. ENDMETHOD. ENDCLASS. CLASS msdos DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS: to_date IMPORTING date TYPE d RETURNING value(msdos_date) TYPE i. CLASS-METHODS: to_time IMPORTING time TYPE t RETURNING value(msdos_time) TYPE i. CLASS-METHODS: from_date IMPORTING msdos_date TYPE i RETURNING value(date) TYPE d. CLASS-METHODS: from_time IMPORTING msdos_time TYPE i RETURNING value(time) TYPE t. ENDCLASS. *"* use this source file for any macro definitions you need *"* in the implementation part of the class ABAP IHTTP METHOD ADD. FIELD-SYMBOLS: <file> TYPE t_file, <ext> TYPE t_ext. APPEND INITIAL LINE TO files ASSIGNING <file>. APPEND INITIAL LINE TO exts ASSIGNING <ext>. <file>-name = name. <file>-date = sy-datum. <file>-time = sy-uzeit. <file>-size = XSTRLEN( content ). * general purpose flag bit 11 (Language encoding flag (EFS) CONSTANTS: gen_flags_unicode(2) TYPE x VALUE '0800'. * see: http://www.pkware.com/documents/casestudies/APPNOTE.TXT, APPENDIX D * zip normaly used IBM Code Page 437 mapped to SAP Printer EPESCP IBM 437 DATA: conv TYPE REF TO cl_abap_conv_out_ce, conv_cp437 TYPE REF TO cl_abap_conv_out_ce, conv_utf8 TYPE REF TO cl_abap_conv_out_ce, cp437 TYPE abap_encoding value '1142', " IBM 437 utf8 TYPE abap_encoding value '4110'. " UTF-8 if support_unicode_names = abap_true. conv = cl_abap_conv_out_ce=>create( encoding = utf8 ignore_cerr = abap_true replacement = '#' ). else. conv = cl_abap_conv_out_ce=>create( encoding = cp437 ignore_cerr = abap_true replacement = '#' ). endif. conv->convert( EXPORTING data = <file>-name IMPORTING buffer = <ext>-filename ). <ext>-filename_len = XSTRLEN( <ext>-filename ). <ext>-extra_len = 0. <ext>-extra = ''. <ext>-min_extract_version = 20. if support_unicode_names = abap_true. <ext>-gen_flags = gen_flags_unicode. else. <ext>-gen_flags = 0. endif. IF <file>-size > 0. <ext>-compressed = 8. " gzip Deflate <ext>-crc32 = crc32( content ). cl_abap_gzip=>compress_binary( EXPORTING raw_in = content raw_in_len = <file>-size IMPORTING gzip_out = <ext>-content gzip_out_len = <ext>-compsize ). ELSE. " folder <ext>-compressed = 0. " gzip Stored <ext>-crc32 = 0. <ext>-compsize = 0. ENDIF. ENDMETHOD. METHOD CRC32. * Let us ask our friendly neighbour whether there is a CRC32 in the kernel (thanks guys!) IF cl_http_utility=>is_ict_system_call_implemented( ihttp_scid_crc32_checksum ) IS INITIAL. SYSTEM-CALL ict "#EC CI_SYSTEMCALL DID ihttp_scid_crc32_checksum PARAMETERS content " > xstr crc32. " < unsigned int RETURN. ENDIF. * Do the calculations by hand. This is going to be slow. This is going to be a pain. * What is a man to do? CONSTANTS: magic_nr(4) TYPE x VALUE 'EDB88320', mFFFFFFFF(4) TYPE x VALUE 'FFFFFFFF', m7FFFFFFF(4) TYPE x VALUE '7FFFFFFF', m00FFFFFF(4) TYPE x VALUE '00FFFFFF', m000000FF(4) TYPE x VALUE '000000FF', m000000(3) TYPE x VALUE '000000'. IF XSTRLEN( crc32_map ) = 0. DO 256 TIMES. DATA: c(4) TYPE x, low_bit(4) TYPE x. c = sy-index - 1. DO 8 TIMES. low_bit = '00000001'. low_bit = c BIT-AND low_bit. " c & 1 c = c DIV 2. c = c BIT-AND m7FFFFFFF. " c >> 1 (top is zero, but in ABAP signed!) IF low_bit IS NOT INITIAL. c = c BIT-XOR magic_nr. ENDIF. ENDDO. CONCATENATE crc32_map c INTO crc32_map IN BYTE MODE. ENDDO. ENDIF. DATA: len TYPE i, n TYPE i. "#EC * DATA: crc(4) TYPE x VALUE mFFFFFFFF, x4(4) TYPE x, idx(4) TYPE x. len = XSTRLEN( content ). DO len TIMES. n = sy-index - 1. CONCATENATE m000000 content+n(1) INTO idx IN BYTE MODE. idx = ( crc BIT-XOR idx ) BIT-AND m000000FF. idx = idx * 4. x4 = crc32_map+idx(4). crc = crc DIV 256. crc = crc BIT-AND m00FFFFFF. " c >> 8 crc = x4 BIT-XOR crc. ENDDO. crc = crc BIT-XOR mFFFFFFFF. crc32 = crc. ENDMETHOD. METHOD DELETE. IF index = 0. READ TABLE files TRANSPORTING NO FIELDS WITH KEY name = name. IF sy-subrc IS NOT INITIAL. RAISE zip_index_error. "#EC RAISE_OK ENDIF. index = sy-tabix. ENDIF. IF index < 1 OR index > LINES( files ). RAISE zip_index_error. "#EC RAISE_OK ENDIF. DELETE files INDEX index. DELETE exts INDEX index. ENDMETHOD. METHOD GET. FIELD-SYMBOLS: <ext> TYPE t_ext. IF index IS INITIAL. READ TABLE files TRANSPORTING NO FIELDS WITH KEY name = name. IF sy-subrc IS NOT INITIAL. RAISE zip_index_error. "#EC RAISE_OK ENDIF. index = sy-tabix. ENDIF. IF index < 1 OR index > LINES( files ). RAISE zip_index_error. "#EC RAISE_OK ENDIF. READ TABLE exts INDEX index ASSIGNING <ext>. IF <ext>-compressed IS INITIAL. content = <ext>-content. ELSE. cl_abap_gzip=>decompress_binary( EXPORTING gzip_in = <ext>-content gzip_in_len = <ext>-compsize IMPORTING raw_out = content ). ENDIF. IF crc32( content ) <> <ext>-crc32. RAISE zip_decompression_error. "#EC RAISE_OK ENDIF. ENDMETHOD. METHOD load. * Documentation from: http://www.pkware.com/company/standards/appnote/appnote.txt * Start to decode new ZIP file CLEAR: files, exts. REFRESH: files, exts. * Global offset for moving through file DATA: offset TYPE i. DEFINE next. " move offset offset = offset + &1. END-OF-DEFINITION. * DATA: l1(1) TYPE x, h1(1) TYPE x, l2(1) TYPE x, h2(1) TYPE x, xstr TYPE xstring. DATA: w2(2) TYPE x, w4(4) TYPE x, xstr TYPE xstring. DEFINE read2. " read two bytes as integer and move offset * l1 = zip+offset(1). offset = offset + 1. * h1 = zip+offset(1). offset = offset + 1. * CONCATENATE h1 l1 INTO xstr IN BYTE MODE. w2 = zip+offset(2). offset = offset + 2. concatenate w2+1(1) w2+0(1) into xstr in byte mode. &1 = xstr. END-OF-DEFINITION. DEFINE read4. " read four bytes as integer and move offset * l1 = zip+offset(1). offset = offset + 1. * h1 = zip+offset(1). offset = offset + 1. * l2 = zip+offset(1). offset = offset + 1. * h2 = zip+offset(1). offset = offset + 1. * CONCATENATE h2 l2 h1 l1 INTO xstr IN BYTE MODE. w4 = zip+offset(4). offset = offset + 4. concatenate w4+3(1) w4+2(1) w4+1(1) w4+0(1) into xstr in byte mode. &1 = xstr. END-OF-DEFINITION. CONSTANTS: gen_flags_encrypted(2) TYPE x VALUE '0001', gen_flags_unicode(2) TYPE x VALUE '0800'. " general purpose flag bit 11 DATA: gen_flags(2) TYPE x. * We convert all names from xstring into string * see: http://www.pkware.com/documents/casestudies/APPNOTE.TXT, APPENDIX D * zip normaly used IBM Code Page 437 mapped to SAP Printer EPESCP IBM 437 DATA: conv TYPE REF TO cl_abap_conv_in_ce, conv_cp437 TYPE REF TO cl_abap_conv_in_ce, conv_utf8 TYPE REF TO cl_abap_conv_in_ce, cp437 TYPE abap_encoding VALUE '1142', " IBM 437 utf8 TYPE abap_encoding VALUE '4110'. " UTF-8 conv_cp437 = cl_abap_conv_in_ce=>create( encoding = cp437 ignore_cerr = abap_true replacement = '#' ). conv_utf8 = cl_abap_conv_in_ce=>create( encoding = utf8 ignore_cerr = abap_true replacement = '#' ). * The maximum length of the ZIP file for scanning. DATA: max_length TYPE i. max_length = XSTRLEN( zip ) - 4. * Extract information about all files. DATA: msdos_date TYPE i, msdos_time TYPE i, file_no TYPE i VALUE 0. FIELD-SYMBOLS: <file> TYPE t_file, <ext> TYPE t_ext. *--------------------------------------------------------------------* * Insert Begin - Get local file headers by central directory record * Documentation: http://en.wikipedia.org/wiki/Zip_(file_format) *--------------------------------------------------------------------* * ### End of central directory record * 0 4 End of central directory signature = 0x06054b50 * 4 2 Number of this disk * 6 2 Disk where central directory starts * 8 2 Number of central directory records on this disk *10 ->2 Total number of central directory records *12 4 Size of central directory (bytes) *16 ->4 Offset of start of central directory,relative to start of archive *20 2 Comment length (n) *22 n Comment *--------------------------------------------------------------------* * ### Central directory file header * 0 4 Central directory file header signature = 0x02014b50 * 4 2 Version made by * 6 2 Version needed to extract (minimum) * 8 2 General purpose bit flag *10 2 Compression method *12 2 File last modification time *14 2 File last modification date *16 4 CRC-32 *20 4 Compressed size *24 4 Uncompressed size *28 2 File name length (n) *30 2 Extra field length (m) *32 2 File comment length (k) *34 2 Disk number where file starts *36 2 Internal file attributes *38 4 External file attributes *42 4 Relative offset of local file header. *46 n File name *46+n m Extra field *46+n+m k File comment *--------------------------------------------------------------------* CONSTANTS: cv_end_central_directory(4) TYPE x VALUE '504B0506'. DATA: lt_match_results TYPE match_result_tab, lv_match_count TYPE i, ls_match_result LIKE LINE OF lt_match_results, lv_entries_in_central_dir TYPE i, lv_offset_central_dir TYPE i, lv_offset_local_fileheader TYPE i, lv_file_name_length TYPE i, lv_extra_field_length TYPE i, lv_file_comment_length TYPE i, lv_file_length TYPE i. * Read "end of central directory record" to find "central directory record" FIND cv_end_central_directory IN zip IN BYTE MODE RESULTS lt_match_results MATCH COUNT lv_match_count . IF lv_match_count IS INITIAL. RAISE zip_parse_error. "#EC RAISE_OK ENDIF. READ TABLE lt_match_results INTO ls_match_result INDEX lv_match_count. offset = ls_match_result-offset + 10. read2 lv_entries_in_central_dir. offset = ls_match_result-offset + 16. read4 lv_offset_central_dir. offset = lv_offset_central_dir. DO lv_entries_in_central_dir TIMES. offset = lv_offset_central_dir + 24. read4 lv_file_length. " uncompressed size IF lv_file_length > 0. " Directoryentries in central file header have no local file header *--------------------------------------------------------------------* * Insert End - Get local file headers by central directory record *--------------------------------------------------------------------* * WHILE offset < max_length AND zip+offset(4) = '504B0304'. "-cdr file_no = file_no + 1. APPEND INITIAL LINE TO files ASSIGNING <file>. APPEND INITIAL LINE TO exts ASSIGNING <ext>. *--------------------------------------------------------------------* * Insert Begin - Get local file headers by central directory record *--------------------------------------------------------------------* * Get position of local file header * CRC32, filesize, compressed size are set in central directory header * but not necessarily in local file header --> use this here offset = lv_offset_central_dir + 16. read4 <ext>-crc32. " crc-32 read4 <ext>-compsize. " compressed size read4 <file>-size. " uncompressed size ENDIF. * Get offset of local file header to continue old coding offset = lv_offset_central_dir + 42. read4 lv_offset_local_fileheader. * and prepare next central directory entry offset = lv_offset_central_dir + 28. read2 lv_file_name_length . read2 lv_extra_field_length . read2 lv_file_comment_length. ADD 46 TO lv_offset_central_dir. ADD lv_file_name_length TO lv_offset_central_dir. ADD lv_extra_field_length TO lv_offset_central_dir. ADD lv_file_comment_length TO lv_offset_central_dir. CHECK lv_file_length > 0. " Directoryentries in central file header have no local file header offset = lv_offset_local_fileheader. *--------------------------------------------------------------------* * Insert End - Get local file headers by central directory record *--------------------------------------------------------------------* next 4. " local file header signature read2 <ext>-min_extract_version. " version needed to extract = 2.0 - File is compressed using Deflate read2 <ext>-gen_flags. " general purpose bit flag read2 <ext>-compressed. " compression method: deflated read2 msdos_time. " last mod file time read2 msdos_date. " last mod file date * read4 <ext>-crc32. " crc-32 "-cdr * read4 <ext>-compsize. " compressed size "-cdr * read4 <file>-size. " uncompressed size "-cdr next 12. "+cdr read2 <ext>-filename_len. " file name length read2 <ext>-extra_len. " extra field length gen_flags = <ext>-gen_flags. gen_flags = gen_flags BIT-AND gen_flags_unicode. " bit 11: Language encoding flag IF gen_flags <> 0 AND support_unicode_names = abap_true. conv = conv_utf8. " utf-8 filename extension ELSE. conv = conv_cp437. " IBM CP437 ENDIF. <ext>-filename = zip+offset(<ext>-filename_len). conv->convert( EXPORTING input = <ext>-filename IMPORTING data = <file>-name ). next <ext>-filename_len. <ext>-extra = zip+offset(<ext>-extra_len). next <ext>-extra_len. IF <ext>-gen_flags <> 8. <ext>-content = zip+offset(<ext>-compsize). next <ext>-compsize. ELSE. * Sometimes sequence in file and directory do not match. * READ TABLE markers INTO marker WITH KEY no = file_no. * DATA: cached_offset TYPE i. cached_offset = offset. offset = marker-offset + 16. DATA result_tab TYPE match_result_tab. FIELD-SYMBOLS <match> LIKE LINE OF result_tab. FIND ALL OCCURRENCES OF <ext>-filename IN zip RESULTS result_tab IN BYTE MODE. * --- start of modification: * The following modification was necessary to handle zip-archives containing files * where the name of one file is a sub-string of the name of another file * --- deleted code: * Loop till the end of the result_tab to get the entry from the Central Directory * LOOP at result_tab ASSIGNING <match>. * ENDLOOP . * DATA: cached_offset TYPE i. cached_offset = offset. offset = <match>-offset - 30. DATA: cached_offset TYPE i. cached_offset = offset. DATA: l_filename_length TYPE i. SORT result_tab BY offset DESCENDING. LOOP AT result_tab ASSIGNING <match>. offset = <match>-offset - 18. read2 l_filename_length. IF l_filename_length = XSTRLEN( <ext>-filename ). EXIT. ENDIF. ENDLOOP . offset = <match>-offset - 30. * --- end of modification read4 <ext>-crc32. read4 <ext>-compsize. read4 <file>-size. next 18. offset = cached_offset. <ext>-content = zip+offset(<ext>-compsize). next <ext>-compsize. next 16. " I032850 ENDIF. <file>-time = msdos=>from_time( msdos_time ). <file>-date = msdos=>from_date( msdos_date ). gen_flags = <ext>-gen_flags. gen_flags = gen_flags BIT-AND gen_flags_encrypted. IF NOT ( <ext>-min_extract_version <= 20 ) * OR NOT ( <ext>-gen_flags = 0 OR <ext>-gen_flags = 2 OR <ext>-gen_flags = 8 ) OR ( gen_flags = gen_flags_encrypted ) OR NOT ( <ext>-compressed = 0 OR <ext>-compressed = 8 ). RAISE zip_parse_error. "#EC RAISE_OK ENDIF. * ENDWHILE. "-cdr ENDDO. "+cdr ENDMETHOD. METHOD SAVE. * Documentation from: http://www.pkware.com/company/standards/appnote/appnote.txt DATA: x2(2) TYPE x, x4(4) TYPE x. DEFINE writeX4. " write xstring x4 = &2. CONCATENATE &1 x4 INTO &1 IN BYTE MODE. END-OF-DEFINITION. DEFINE write2. " write two bytes from integer x2 = &2. CONCATENATE &1 x2+1(1) x2+0(1) INTO &1 IN BYTE MODE. END-OF-DEFINITION. DEFINE write4. " write four bytes from integer x4 = &2. CONCATENATE &1 x4+3(1) x4+2(1) x4+1(1) x4+0(1) INTO &1 IN BYTE MODE. END-OF-DEFINITION. * Process all files. We write in parallel the zip and the central directory to use later DATA: msdos_date TYPE i, msdos_time TYPE i. FIELD-SYMBOLS: <file> TYPE t_file, <ext> TYPE t_ext. DATA: dir TYPE xstring, start_offset(4) TYPE x. LOOP AT files ASSIGNING <file>. READ TABLE exts INDEX sy-tabix ASSIGNING <ext>. start_offset = XSTRLEN( zip ). msdos_time = msdos=>to_time( <file>-time ). msdos_date = msdos=>to_date( <file>-date ). * zip data stream writeX4 zip '504B0304'. " local file header signature write2 zip <ext>-min_extract_version. " version needed to extract = 2.0 - File is compressed using Deflate write2 zip <ext>-gen_flags. " general purpose bit flag write2 zip <ext>-compressed. " compression method: deflated write2 zip msdos_time. " last mod file time write2 zip msdos_date. " last mod file date write4 zip <ext>-crc32. " crc-32 write4 zip <ext>-compsize. " compressed size write4 zip <file>-size. " uncompressed size write2 zip <ext>-filename_len. " file name length write2 zip <ext>-extra_len. " extra field length CONCATENATE zip <ext>-filename <ext>-extra <ext>-content INTO zip IN BYTE MODE. * central directory stream (which has a lare duplicate sequence of zip header) DATA: dup_offset TYPE i. dup_offset = start_offset + 4. writeX4 dir '504B0102'. " central file header signature write2 dir 19. " version made by (== pkzip 2.04g) CONCATENATE dir zip+dup_offset(26) INTO dir IN BYTE MODE. " part which matches exactly zip header write2 dir 0. " file comment length write2 dir 0. " disk number start write2 dir 0. " internal file attributes write4 dir 0. " external file attributes write4 dir start_offset. " relative offset of local header CONCATENATE dir <ext>-filename <ext>-extra INTO dir IN BYTE MODE. " file name + extra info ENDLOOP. * Write Central Directory DATA: lines_files TYPE i. lines_files = LINES( files ). DATA: xstrlen_dir TYPE i. xstrlen_dir = XSTRLEN( dir ). DATA: offset_dir TYPE i. offset_dir = XSTRLEN( zip ). CONCATENATE zip dir INTO zip IN BYTE MODE. writeX4 zip '504B0506'. " End of central directory write2 zip 0. " number of this disk write2 zip 0. " number of the disk with the start of the central directory write2 zip lines_files. " total number of entries in the central directory on this disk write2 zip lines_files. " total number of entries in the central directory write4 zip xstrlen_dir. " size of the central directory write4 zip offset_dir. " offset of start of central directory write2 zip 0. " ZIP file comment length ENDMETHOD. METHOD SPLICE. * Documentation from: http://www.pkware.com/company/standards/appnote/appnote.txt * Local variables. FIELD-SYMBOLS: <entry> LIKE LINE OF entries. DATA: filename_len TYPE i, extra_len TYPE i, filename TYPE xstring. * Start to decode new ZIP file CLEAR: entries. REFRESH: entries. * Global offset for moving through file DATA: offset TYPE i. DATA: w2(2) TYPE x, w4(4) TYPE x, xstr TYPE xstring. DEFINE read2. "#EC NEEDED read two bytes as integer and move offset w2 = zip+offset(2). offset = offset + 2. CONCATENATE w2+1(1) w2+0(1) INTO xstr IN BYTE MODE. &1 = xstr. END-OF-DEFINITION. DEFINE read4. "#EC NEEDED read four bytes as integer and move offset w4 = zip+offset(4). offset = offset + 4. CONCATENATE w4+3(1) w4+2(1) w4+1(1) w4+0(1) INTO xstr IN BYTE MODE. &1 = xstr. END-OF-DEFINITION. * We convert all names from xstring into string DATA: conv TYPE REF TO cl_abap_conv_in_ce. conv = cl_abap_conv_in_ce=>create( ). * Extract information about all files. WHILE zip+offset(4) = '504B0304'. " local file header signature APPEND INITIAL LINE TO entries ASSIGNING <entry>. offset = offset + 8. " next 4=(header). read2 <ext>-min_extract_version. read2 <ext>-gen_flags. read2 <entry>-compressed. " compression method: deflated offset = offset + 8. " read2 msdos_time. read2 msdos_date. read4 <ext>-crc32. read4 <entry>-length. " compressed size offset = offset + 4. " uncompressed size read2 filename_len. " file name length read2 extra_len. " extra field length filename = zip+offset(filename_len). conv->convert( EXPORTING input = filename IMPORTING data = <entry>-name ). <entry>-offset = offset + filename_len + extra_len. offset = <entry>-offset + <entry>-length. ENDWHILE. DELETE entries WHERE length = 0. ENDMETHOD.