ABAP_GZIP

ABAP Class to gzip and gunzip

This class is now available in the standard SAP shipment as /SNP/PXUX_CL_ABAP_GZIP from 750SP9

© 2006 SAP AG The SAP Developer Network: http://sdn.sap.com 1

Applies To:

SAP R/3 4.7 and above

Summary

ABAP Implementation of GZIP

By: Otto Frost

Company: Capgemini

Date: 17 March 2006

GZIP / GUNZIP

The zcl_abap_gzip ABAP class implements gzip and gunzip as described in RFC 1952 - GZIP file format specification version 4.3 http://www.faqs.org/rfcs/rfc1952.html.

Gzip/Gunzip is a lossless compressed data format that

    • Is independent of CPU type, operating system, file system, and character set, and hence can be used for interchange
    • Can compress or decompress a data stream (as opposed to a randomly accessible file) to produce another data stream, using only an a priori bounded amount of intermediate storage, and hence can be used in data communications or similar structures such as Unix filters
    • Compresses data with efficiency comparable to the best currently available general-purpose compression methods, and in particular considerably better than the "compress" program
    • Can be implemented readily in a manner not covered by patents, and hence can be practiced freely
    • Is compatible with the file format produced by the current widely used gzip utility, in that conforming decompressors will be able to read data produced by the existing gzip compressor.

The zcl_abap_gzip ABAP class is intended for use by implementers of software to compress data into gzip format and/or decompress data from gzip format.

If you need more information about gzip, try a google search. On a unix box the command "man gzip" or "gzip --help" may work too. On windows gzip is available in the CygWin package from RedHat. On http://www.gnu.org/ you should be able to find a manual for gzip. You ,ay also be able to download pre compiled binaries from the unix utils package from sourceforge.

Example code

* ABAP Class to gzip and gunzip * * You may use gui_upload and gui_download to * transfer the data in binary mode, but that is not included * in this example. This example first executes ungzip * and then gzip. Normally you would use gzip or ungzip, not both. * This example is also available in the method example. DATA xstringin TYPE xstring. DATA xstringout TYPE xstring. DATA file TYPE zcl_abap_gzip=>t_file. DATA obj TYPE REF TO zcl_abap_gzip. CREATE OBJECT obj. * file without filename with content AAAAAA xstringin = '1F8B0800FBAF0D44020373740401007EDE1CAA06000000'. * a gzipped file with filename testa.txt, with content AAAAAA and a char with hex val x0A xstringin = '1F8B0808B4331044020374657374612E74787400737404012E007646C08507000000'. xstringout = obj->gunzip( gzip_in = xstringin ) .. file = obj->get_file_attributes( ). if obj->get_error( ) <> 0. * error handling code. endif. xstringin = xstringout. " content AAAAAA and a char with hex val x0A CREATE OBJECT obj. obj->set_name( name = file-name ). obj->set_compress_level( 9 ). xstringout = obj->gzip( raw_in = xstringin ). if obj->get_error( ) <> 0. * error handling code. endif.

(The cl_abap_gzip handle deflate/inflate/compression, but not member header and trailer in the gzip format. See RFC 1952

ABAP class to gzip and gunzip. The cl_abap_gzip handle deflate, but not head and tail in gzip format. This sample was developed to be able to process big files in SAP XI. See the example method for usage.

Code sample:

CLASS zcl_abap_gzip DEFINITION PUBLIC. * RFC 1952 - GZIP file format specification version 4.3 * http://www.faqs.org/rfcs/rfc1952.html * Author: Otto Frost * Possible improvements * Check input * ID1, ID2, has correct values * CM is correct * Name, within ISO-8859-1 charset encoding * Comment, within ISO-8859-1 charset encoding * Set mtime to processingtime * Check that length of xlen < 256 * Handle CRC16 * Error handling * Tested with * gnu gzip/gunzip 1.3.5 under cygwin * winzip 8.1 SR1 can open the produced file * Test run on SAP XI 3.0 SP14, on windows platform. * Function modules gui_upload and gui_download may be used for * up and download of data * See example method for how to use the class PUBLIC SECTION. TYPES: t_flg(1) TYPE x. * flags CONSTANTS: ftext TYPE i VALUE 0. CONSTANTS: fhcrc TYPE i VALUE 1. CONSTANTS: fextra TYPE i VALUE 2. CONSTANTS: fname TYPE i VALUE 3. CONSTANTS: fcomment TYPE i VALUE 4. * 5, 6, 7 are reserved CONSTANTS: null(1) TYPE x VALUE '00'. TYPES: BEGIN OF t_file, id1(1) TYPE x, id2(1) TYPE x, cm(1) TYPE x, flg TYPE t_flg, mtime(4) TYPE x, xfl(1) TYPE x, os(1) TYPE x, xlen TYPE i, " 2 bytes xlenbytes TYPE xstring, name TYPE string, " zero terminated comment TYPE string, " zero terminated namex TYPE xstring, " zero terminated commentx TYPE xstring, " zero terminated crc16(2) TYPE x, compress TYPE xstring, crc32(4) TYPE x, isize TYPE i, " 4 bytes END OF t_file . DATA file TYPE t_file. METHODS constructor. METHODS: gzip IMPORTING raw_in TYPE xstring RETURNING value(gzip_out) TYPE xstring EXCEPTIONS zip_parse_error cx_parameter_invalid_range cx_sy_buffer_overflow. METHODS: gunzip IMPORTING gzip_in TYPE xstring RETURNING value(raw_out) TYPE xstring EXCEPTIONS zip_decompression_error cx_parameter_invalid_range cx_sy_buffer_overflow. METHODS: bit_swap IMPORTING x TYPE t_flg RETURNING value(y) TYPE t_flg. METHODS: get_flagbit IMPORTING x TYPE t_flg flag TYPE i RETURNING value(b) TYPE i. METHODS: set_flagbit IMPORTING x TYPE t_flg flag TYPE i RETURNING value(y) TYPE i. METHODS: get_file_attributes RETURNING value(file_attributes) TYPE t_file. METHODS set_name IMPORTING name TYPE string. METHODS set_comment IMPORTING comment TYPE string. METHODS set_xlenbytes IMPORTING xlenbytes TYPE xstring. METHODS set_mtime IMPORTING mtime TYPE xstring. METHODS set_compress_level IMPORTING compress_level TYPE i. METHODS example. PROTECTED SECTION. PRIVATE SECTION. DATA compress_level TYPE i. ENDCLASS. CLASS ZCL_ABAP_GZIP IMPLEMENTATION. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->CONSTRUCTOR * +-------------------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD constructor. compress_level = 6. ENDMETHOD. "constructor * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->GZIP * +-------------------------------------------------------------------------------------------------+ * | [--->] RAW_IN TYPE XSTRING * | [<-()] GZIP_OUT TYPE XSTRING * | [EXC!] ZIP_PARSE_ERROR * | [EXC!] CX_PARAMETER_INVALID_RANGE * | [EXC!] CX_SY_BUFFER_OVERFLOW * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD gzip. 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. DATA oconv TYPE REF TO cl_abap_conv_out_ce. * TRY. CALL METHOD cl_abap_conv_out_ce=>create EXPORTING encoding = 'UTF-8' * ENDIAN = * REPLACEMENT = '#' * IGNORE_CERR = ABAP_FALSE RECEIVING conv = oconv. . * CATCH CX_PARAMETER_INVALID_RANGE . * CATCH CX_SY_CODEPAGE_CONVERTER_INIT . * ENDTRY. file-id1 = '1F'. file-id2 = '8B'. file-cm = '08'. file-os = 'FF'. " 255 Unknown ( ABAP ) file-isize = XSTRLEN( raw_in ). * TRY. CALL METHOD cl_abap_gzip=>compress_binary EXPORTING raw_in = raw_in raw_in_len = file-isize compress_level = compress_level IMPORTING gzip_out = file-compress * GZIP_OUT_LEN = . * CATCH CX_PARAMETER_INVALID_RANGE . * CATCH CX_SY_BUFFER_OVERFLOW . * ENDTRY. file-crc32 = cl_abap_zip=>crc32( raw_in ). CONCATENATE file-id1 file-id2 file-cm file-flg INTO gzip_out IN BYTE MODE. write4 gzip_out file-mtime. CONCATENATE gzip_out file-xfl file-os INTO gzip_out IN BYTE MODE. IF 1 = me->get_flagbit( x = file-flg flag = fextra ). file-xlen = XSTRLEN( file-xlenbytes ). write2 gzip_out file-xlen. CONCATENATE gzip_out file-xlenbytes INTO gzip_out IN BYTE MODE. ENDIF. IF 1 = me->get_flagbit( x = file-flg flag = fname ). * TRY. CALL METHOD oconv->convert EXPORTING data = file-name * N = -1 IMPORTING buffer = file-namex * LEN = . * CATCH CX_SY_CODEPAGE_CONVERTER_INIT . * CATCH CX_SY_CONVERSION_CODEPAGE . * CATCH CX_PARAMETER_INVALID_TYPE . * ENDTRY. CONCATENATE gzip_out file-namex null INTO gzip_out IN BYTE MODE. ENDIF. IF 1 = me->get_flagbit( x = file-flg flag = fcomment ). * TRY. CALL METHOD oconv->convert EXPORTING data = file-comment * N = -1 IMPORTING buffer = file-commentx * LEN = . * CATCH CX_SY_CODEPAGE_CONVERTER_INIT . * CATCH CX_SY_CONVERSION_CODEPAGE . * CATCH CX_PARAMETER_INVALID_TYPE . * ENDTRY. CONCATENATE gzip_out file-commentx null INTO gzip_out IN BYTE MODE. ENDIF. CONCATENATE gzip_out file-compress INTO gzip_out IN BYTE MODE. CLEAR file-compress. write4 gzip_out file-crc32. write4 gzip_out file-isize. ENDMETHOD. "gunzip * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->GUNZIP * +-------------------------------------------------------------------------------------------------+ * | [--->] GZIP_IN TYPE XSTRING * | [<-()] RAW_OUT TYPE XSTRING * | [EXC!] ZIP_DECOMPRESSION_ERROR * | [EXC!] CX_PARAMETER_INVALID_RANGE * | [EXC!] CX_SY_BUFFER_OVERFLOW * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD gunzip. 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. DEFINE read2. " read two bytes as integer and move offset l1 = gzip_in+offset(1). offset = offset + 1. h1 = gzip_in+offset(1). offset = offset + 1. concatenate h1 l1 into xstr in byte mode. &1 = xstr. END-OF-DEFINITION. DEFINE read4. " read four bytes as integer and move offset l1 = gzip_in+offset(1). offset = offset + 1. h1 = gzip_in+offset(1). offset = offset + 1. l2 = gzip_in+offset(1). offset = offset + 1. h2 = gzip_in+offset(1). offset = offset + 1. concatenate h2 l2 h1 l1 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( ). DATA: msdos_date TYPE i, msdos_time TYPE i. * FIELD-SYMBOLS: <file> TYPE t_file, * <ext> TYPE t_ext. DATA b TYPE i. " BIT DATA: max_length TYPE i. DATA file TYPE t_file. DATA crc32 TYPE i. file-id1 = gzip_in+offset(1). next 1. file-id2 = gzip_in+offset(1). next 1. file-cm = gzip_in+offset(1). next 1. file-flg = gzip_in+offset(1). next 1. read4 file-mtime. file-xfl = gzip_in+offset(1). next 1. file-os = gzip_in+offset(1). next 1. * DO 8 TIMES. * GET BIT sy-index OF file-flg INTO b. * WRITE b NO-GAP. * ENDDO. b = me->get_flagbit( x = file-flg flag = fextra ). IF b = 1. read2 file-xlen. file-xlenbytes = gzip_in+offset(file-xlen). next file-xlen. ENDIF. b = me->get_flagbit( x = file-flg flag = fname ). IF b = 1. WHILE gzip_in+offset(1) <> '00'. CONCATENATE file-namex gzip_in+offset(1) INTO file-namex IN BYTE MODE. next 1. ENDWHILE. next 1. " skip 00 conv->convert( EXPORTING input = file-namex IMPORTING data = file-name ). ENDIF. b = me->get_flagbit( x = file-flg flag = fcomment ). IF b = 1. WHILE gzip_in+offset(1) <> '00'. CONCATENATE file-commentx gzip_in+offset(1) INTO file-commentx IN BYTE MODE. next 1. ENDWHILE. next 1. " skip 00 conv->convert( EXPORTING input = file-commentx IMPORTING data = file-comment ). ENDIF. b = me->get_flagbit( x = file-flg flag = fhcrc ). IF b = 1. read2 file-crc16. ENDIF. max_length = XSTRLEN( gzip_in ). max_length = max_length - offset. max_length = max_length - 8. " trailer length file-compress = gzip_in+offset(max_length). next max_length. read4 file-crc32. read4 file-isize. cl_abap_gzip=>decompress_binary( EXPORTING gzip_in = file-compress gzip_in_len = max_length IMPORTING raw_out = raw_out ). crc32 = cl_abap_zip=>crc32( raw_out ). IF crc32 <> file-crc32. RAISE zip_decompression_error. ENDIF. CLEAR file-compress. me->file = file. ENDMETHOD. "gunzip * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->BIT_SWAP * +-------------------------------------------------------------------------------------------------+ * | [--->] X TYPE T_FLG * | [<-()] Y TYPE T_FLG * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD bit_swap. * in abap bytes are indexed * 1,2,3,4,5,6,7,8 * in gzip spec * 7,6,5,4,3,2,1,0 * why order is reversed * and 1 added to index in get_flagbit method DATA b TYPE i. " BIT DATA i TYPE i. i = 8. DO 8 TIMES. GET BIT sy-index OF x INTO b. SET BIT i OF y TO b. i = i - 1. ENDDO. ENDMETHOD. "bit_swap * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->GET_FLAGBIT * +-------------------------------------------------------------------------------------------------+ * | [--->] X TYPE T_FLG * | [--->] FLAG TYPE I * | [<-()] B TYPE I * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD get_flagbit. DATA byte(1) TYPE x. DATA index TYPE i. byte = me->bit_swap( x = x ). index = 1 + flag. GET BIT index OF byte INTO b. ENDMETHOD. "get_flagbit * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->SET_FLAGBIT * +-------------------------------------------------------------------------------------------------+ * | [--->] X TYPE T_FLG * | [--->] FLAG TYPE I * | [<-()] Y TYPE I * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD set_flagbit. DATA index TYPE i. DATA byte(1) TYPE x. index = flag + 1. byte = me->bit_swap( x = x ). SET BIT index OF byte. byte = me->bit_swap( x = byte ). y = byte. ENDMETHOD. "set_flagbit * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->GET_FILE_ATTRIBUTES * +-------------------------------------------------------------------------------------------------+ * | [<-()] FILE_ATTRIBUTES TYPE T_FILE * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD get_file_attributes. file_attributes = me->file. ENDMETHOD. "get_file_attributes * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->SET_NAME * +-------------------------------------------------------------------------------------------------+ * | [--->] NAME TYPE STRING * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD set_name. * methods set_name importing name type string. file-name = name. file-flg = me->set_flagbit( x = file-flg flag = fname ). ENDMETHOD. "set_name * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->SET_COMMENT * +-------------------------------------------------------------------------------------------------+ * | [--->] COMMENT TYPE STRING * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD set_comment. * methods set_comment importing comment type string. file-comment = comment. file-flg = me->set_flagbit( x = file-flg flag = fcomment ). ENDMETHOD. "set_comment * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->SET_XLENBYTES * +-------------------------------------------------------------------------------------------------+ * | [--->] XLENBYTES TYPE XSTRING * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD set_xlenbytes. * methods set_xlenbytes importing xlenbytes type xstring. file-xlenbytes = xlenbytes. file-flg = me->set_flagbit( x = file-flg flag = fextra ). ENDMETHOD. "set_xlenbytes * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->SET_MTIME * +-------------------------------------------------------------------------------------------------+ * | [--->] MTIME TYPE XSTRING * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD set_mtime. file-mtime = mtime. ENDMETHOD. "set_mtime * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_ABAP_GZIP->SET_COMPRESS_LEVEL * +-------------------------------------------------------------------------------------------------+ * | [--->] COMPRESS_LEVEL TYPE I * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD set_compress_level. me->compress_level = compress_level. IF compress_level = 9. file-xfl = '02'. ELSEIF compress_level = 1. file-xfl = '04'. ENDIF. ENDMETHOD. "set_compress_level * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_ABAP_GZIP=>EXAMPLE * +-------------------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD example. * You may use gui_upload and gui_download to * transfer the data, but that is not included * in this example DATA xstringin TYPE xstring. DATA xstringout TYPE xstring. DATA file TYPE zcl_abap_gzip=>t_file. DATA obj TYPE REF TO zcl_abap_gzip. CREATE OBJECT obj. * file without filename with content AAAAAA xstringin = '1F8B0800FBAF0D44020373740401007EDE1CAA06000000'. * a gzipped file with filename testa.txt, with content AAAAAA and a char with hex val x0A xstringin = '1F8B0808B4331044020374657374612E74787400737404012E007646C08507000000'. xstringout = obj->gunzip( gzip_in = xstringin ) . file = obj->get_file_attributes( ). xstringin = xstringout. CREATE OBJECT obj. obj->set_name( name = file-name ). obj->set_compress_level( 9 ). xstringout = obj->gzip( raw_in = xstringin ). ENDMETHOD. "example ENDCLASS.

Author Bio

A developer working in various languages and systems. Started with ABAP in 2002. Senior consultant in EDI integrations. He is also a certified SAP XI consultant.