00001 // $Id: f_ut_compress.c 478 2009-10-29 12:26:09Z linev $ 00002 //----------------------------------------------------------------------- 00003 // The GSI Online Offline Object Oriented (Go4) Project 00004 // Experiment Data Processing at EE department, GSI 00005 //----------------------------------------------------------------------- 00006 // Copyright (C) 2000- GSI Helmholtzzentrum für Schwerionenforschung GmbH 00007 // Planckstr. 1, 64291 Darmstadt, Germany 00008 // Contact: http://go4.gsi.de 00009 //----------------------------------------------------------------------- 00010 // This software can be used under the license agreements as stated 00011 // in Go4License.txt file which is part of the distribution. 00012 //----------------------------------------------------------------------- 00013 00014 /* type definitions */ 00015 #include "typedefs.h" 00016 #include "f_ut_compress.h" 00017 #include <stdio.h> 00018 00019 #define PACK(bit) if(*pc_in != 0){*pl_mask += bit ; *pc_out++ = *pc_in; } pc_in++; 00020 00021 #ifdef GSI__LINUX 00022 #define UNPACK(bit) if(l_mask & bit ) *pc_out++ = *pc_in++; else *pc_out++ = 0; 00023 #endif 00024 #ifdef GSI__NT 00025 #define UNPACK(bit) if(l_mask & bit ) *pc_out++ = *pc_in++; else *pc_out++ = 0; 00026 #endif 00027 #ifdef GSI__WINNT 00028 #define UNPACK(bit) if(l_mask & bit ) *pc_out++ = *pc_in++; else *pc_out++ = 0; 00029 #endif 00030 #ifdef GSI__VMS 00031 #define UNPACK(bit) if(l_mask & bit ) *pc_out = *pc_in++; pc_out++; 00032 #endif 00033 #ifdef GSI__AIX 00034 #define UNPACK(bit) if(l_mask & bit ) *pc_out = *pc_in++; pc_out++; 00035 #endif 00036 #ifdef GSI__SOLARIS 00037 #define UNPACK(bit) if(l_mask & bit ) *pc_out = *pc_in++; pc_out++; 00038 #endif 00039 #ifdef GSI__LYNX 00040 #define UNPACK(bit) if(l_mask & bit ) *pc_out = *pc_in++; pc_out++; 00041 #endif 00042 /*****************+***********+****************************************/ 00043 /* */ 00044 /* GSI, Gesellschaft fuer Schwerionenforschung mbH */ 00045 /* Postfach 11 05 41 */ 00046 /* D-6100 Darmstadt 11 */ 00047 /* */ 00048 /*1+ C Procedure ***********+******************************************/ 00049 /* */ 00050 /*+ Module : f_ut_compr_size */ 00051 /* */ 00052 /*--------------------------------------------------------------------*/ 00053 /*+ CALLING : size=f_ut_compr_size(*input,inlen) */ 00054 /*--------------------------------------------------------------------*/ 00055 /* */ 00056 /*+ PURPOSE : return size of compressed data field. */ 00057 /* */ 00058 /*+ ARGUMENTS : */ 00059 /* */ 00060 /*+ input : (INTU1 *) Pointer to data field. */ 00061 /*+ inlen : (INTS4) Length of input data field [bytes]. */ 00062 /* */ 00063 /*+ Return type : INTS4 */ 00064 /*+ return : Number of bytes of compressed output */ 00065 /*+ Include name: f_ut_compress.h */ 00066 /* */ 00067 /*2+Implementation************+****************************************/ 00068 /* */ 00069 /*+ Version : 1.01 */ 00070 /*+ Author : H.G.Essel */ 00071 /*+ Last Update : 13-Jul-2000 */ 00072 /* */ 00073 /*2+Internals*****+***********+****************************************/ 00074 /* */ 00075 /*+ Utility : UTIL */ 00076 /*+ Created : 07-Jul-2000 */ 00077 /* */ 00078 /*1- C Procedure ***********+******************************************/ 00079 INTS4 f_ut_compr_size(INTU1 *pc_input,INTS4 l_inlen) 00080 { 00081 INTU4 I,J,K,L,M,N; 00082 INTU4 l_bytes; 00083 INTU4 l_masks; 00084 INTU4 *pl_mask,*pl_end; 00085 INTU1 *pc_out,*pc_in; 00086 s_compress *ps_compress; 00087 00088 pc_in =pc_input; 00089 l_bytes=0; 00090 pl_mask=(INTU4 *)pc_input; 00091 pl_end=pl_mask+l_inlen/4; 00092 while(pl_mask!=pl_end) 00093 { 00094 if(*pl_mask&0x000000ff) l_bytes++; 00095 if(*pl_mask&0x0000ff00) l_bytes++; 00096 if(*pl_mask&0x00ff0000) l_bytes++; 00097 if(*pl_mask&0xff000000) l_bytes++; 00098 pl_mask++; 00099 } 00100 if(l_bytes%4 != 0) l_bytes=l_bytes+4-l_bytes%4; 00101 l_masks=(l_inlen >> 5); 00102 if(l_inlen%32 != 0) l_masks++; 00103 return(l_bytes+4*l_masks+sizeof(s_compress)); 00104 } 00105 00106 /*1+ C Procedure ***********+******************************************/ 00107 /* */ 00108 /*+ Module : f_ut_compr_zeros */ 00109 /* */ 00110 /*--------------------------------------------------------------------*/ 00111 /*+ CALLING : zeros=f_ut_compr_zeros(*input,inlen) */ 00112 /*--------------------------------------------------------------------*/ 00113 /* */ 00114 /*+ PURPOSE : return % zero bytes. */ 00115 /* */ 00116 /*+ ARGUMENTS : */ 00117 /* */ 00118 /*+ input : (INTU1 *) Pointer to data field. */ 00119 /*+ inlen : (INTS4) Length of input data field [bytes]. */ 00120 /* */ 00121 /*+ Return type : INTS4 */ 00122 /*+ return : % of zero bytes */ 00123 /*+ Include name: f_ut_compress.h */ 00124 /* */ 00125 /*2+Implementation************+****************************************/ 00126 /* */ 00127 /*+ Version : 1.01 */ 00128 /*+ Author : H.G.Essel */ 00129 /*+ Last Update : 13-Jul-2000 */ 00130 /* */ 00131 /*2+Internals*****+***********+****************************************/ 00132 /* */ 00133 /*+ Utility : UTIL */ 00134 /*+ Created : 07-Jul-2000 */ 00135 /* */ 00136 /*1- C Procedure ***********+******************************************/ 00137 INTS4 f_ut_compr_zeros(INTU1 *pc_input,INTS4 l_inlen) 00138 { 00139 INTU4 I,J,K,L,M,N; 00140 INTU4 l_bytes; 00141 INTU4 l_mask; 00142 INTU4 *pl_mask; 00143 INTU1 *pc_out,*pc_in; 00144 s_compress *ps_compress; 00145 00146 pc_in =pc_input; 00147 l_bytes=0; 00148 for(I=1;I<=l_inlen;I++) if(*pc_in++ == 0) l_bytes++; 00149 return (l_bytes*100/l_inlen); 00150 } 00151 00152 /*1+ C Procedure ***********+******************************************/ 00153 /* */ 00154 /*+ Module : f_ut_compr_pack */ 00155 /* */ 00156 /*--------------------------------------------------------------------*/ 00157 /*+ CALLING : size=f_ut_compr_pack(*input,inlen,*output,outlen) */ 00158 /*--------------------------------------------------------------------*/ 00159 /* */ 00160 /*+ PURPOSE : Compress data field by removing zero bytes */ 00161 /* */ 00162 /*+ ARGUMENTS : */ 00163 /* */ 00164 /*+ input : (INTU1 *) Pointer to input data field. */ 00165 /*+ inlen : (INTS4) Length of input data field in bytes. */ 00166 /*+ output : (INTU1 *) Pointer to compressed output data field. */ 00167 /*+ outlen : (INTS4) Length of output data field. */ 00168 /* */ 00169 /*+ Return type : INTS4 */ 00170 /*+ return : Number of bytes of compressed output */ 00171 /*+ return : -1: output buffer may be too small */ 00172 /*+ Include name: f_ut_compress.h */ 00173 /* */ 00174 /*2+Description***+***********+****************************************/ 00175 /* */ 00176 /*+ CALLING : size=f_ut_compr_pack(*input,inlen,*output,outlen) */ 00177 /* */ 00178 /*+ ARGUMENTS : */ 00179 /* */ 00180 /*+ input : (INTU1 *) Pointer to input data field. The field */ 00181 /* must be longword aligned. */ 00182 /*+ inlen : (INTS4) Length of input data field in bytes. */ 00183 /*+ output : (INTU1 *) Pointer to output data field. */ 00184 /* The output field must be 12.5% bigger than input. */ 00185 /*+ outlen : (INTS4) Length of output data field in bytes. */ 00186 /* */ 00187 /*+ FUNCTION : The output field begins with structure s_compress: */ 00188 /* */ 00189 /*- INTU4 l_endian: set to 1 by creator */ 00190 /*- INTU4 l_length: total size [b] of compr. buffer */ 00191 /*- INTU4 l_masks: # of masks following this header */ 00192 /*- INTU4 l_full_bytes: # of bytes of uncompressed buffer */ 00193 /*- INTU4 l_comp_bytes: # of non zero bytes */ 00194 /*- INTU4 l_pattern: COMPR__PATTERN */ 00195 /*+ : */ 00196 /* Then there follow inbytes/32 pattern longwords. */ 00197 /* Then follow all non zero bytes. */ 00198 /* Zero bytes are suppressed. The overhead is about */ 00199 /* 13% of input, i.e. if no zeros are found, output is */ 00200 /* 13% bigger than input. In the patterns, bits are */ 00201 /* set for following nonzero bytes, not set for */ 00202 /* suppressed zero bytes. */ 00203 /*+ endian : When receiving a compressed buffer one must check */ 00204 /* the endian. If it is not 1, one must swap */ 00205 /* s_compress and then s_sompress.l_masks longwords. */ 00206 /* Then the buffer can be uncompressed. The */ 00207 /* uncompressed buffer must be checked again for right */ 00208 /* endian, and eventually swapped. */ 00209 /* */ 00210 /*+ EXAMPLE : l=f_ut_compr_pack(pl_data,1024,pl_comp,2000); */ 00211 /* l=f_ut_compr_unpack(pl_comp,pl_data,1024); */ 00212 /* pl_data should be the same now. */ 00213 /* */ 00214 /*+ NOTE : Output data field must be 13% bigger than input. */ 00215 /* */ 00216 /*2+Implementation************+****************************************/ 00217 /* */ 00218 /*+ Version : 1.01 */ 00219 /*+ Author : H.G.Essel */ 00220 /*+ Last Update : 13-Jul-2000 */ 00221 /* */ 00222 /*2+Internals*****+***********+****************************************/ 00223 /* */ 00224 /*+ Utility : UTIL */ 00225 /*+ Created : 07-Jul-2000 */ 00226 /* */ 00227 /*1- C Procedure ***********+******************************************/ 00228 INTS4 f_ut_compr_pack(INTU1 *pc_input,INTS4 l_inlen,INTU1 *pc_output,INTS4 l_outlen) 00229 { 00230 INTU4 I,J,K,L,M,N; 00231 INTU4 l_bytes; 00232 INTU4 l_mask,l_masks; 00233 INTU4 *pl_mask; 00234 INTU1 *pc_out,*pc_in,*pc_1; 00235 s_compress *ps_compress; 00236 00237 /* how many masks do we need: one for 32 bytes */ 00238 l_masks=(l_inlen >> 5); 00239 if(l_inlen%32 != 0) l_masks++; 00240 /* on output we need the header, the masks, and maybe all bytes */ 00241 if(l_outlen < 4*l_masks+sizeof(s_compress)+l_inlen) return -1; 00242 pc_out=pc_output; 00243 pc_in =pc_input; 00244 ps_compress=(s_compress *)pc_out; /* header */ 00245 pl_mask=(INTU4 *)(ps_compress+1); /* first mask behind header */ 00246 pc_out = (INTU1 *)(pl_mask+l_masks);/* first data byte behind all masks */ 00247 pc_1=pc_out; 00248 *pl_mask=0; 00249 l_mask=1; 00250 l_bytes=0; 00251 /* loop over all masks -1 */ 00252 for(I=1;I<l_masks;I++) 00253 { 00254 PACK(0x00000001); 00255 PACK(0x00000002); 00256 PACK(0x00000004); 00257 PACK(0x00000008); 00258 PACK(0x00000010); 00259 PACK(0x00000020); 00260 PACK(0x00000040); 00261 PACK(0x00000080); 00262 PACK(0x00000100); 00263 PACK(0x00000200); 00264 PACK(0x00000400); 00265 PACK(0x00000800); 00266 PACK(0x00001000); 00267 PACK(0x00002000); 00268 PACK(0x00004000); 00269 PACK(0x00008000); 00270 PACK(0x00010000); 00271 PACK(0x00020000); 00272 PACK(0x00040000); 00273 PACK(0x00080000); 00274 PACK(0x00100000); 00275 PACK(0x00200000); 00276 PACK(0x00400000); 00277 PACK(0x00800000); 00278 PACK(0x01000000); 00279 PACK(0x02000000); 00280 PACK(0x04000000); 00281 PACK(0x08000000); 00282 PACK(0x10000000); 00283 PACK(0x20000000); 00284 PACK(0x40000000); 00285 PACK(0x80000000); 00286 pl_mask++; 00287 *pl_mask=0; 00288 } 00289 l_bytes=pc_out-pc_1 ; 00290 /* last mask could be less than 32 bytes */ 00291 l_mask=1; 00292 for(I=0;I<(l_inlen-l_masks*32+32);I++) 00293 { 00294 if(*pc_in != 0){*pl_mask += l_mask; *pc_out++ = *pc_in; l_bytes++; } l_mask = l_mask << 1; pc_in++; 00295 } 00296 /* add the number of last fragment bytes */ 00297 ps_compress->l_endian = 1; 00298 ps_compress->l_length = l_bytes+4*l_masks+sizeof(s_compress); 00299 ps_compress->l_pattern = COMPR__PATTERN; 00300 ps_compress->l_masks = l_masks; 00301 ps_compress->l_full_bytes = l_inlen; 00302 ps_compress->l_comp_bytes = l_bytes; /* without header and masks */ 00303 00304 return (l_bytes+4*l_masks+sizeof(s_compress)); 00305 } 00306 00307 /*1+ C Procedure ***********+******************************************/ 00308 /* */ 00309 /*+ Module : f_ut_compr_unpack */ 00310 /* */ 00311 /*--------------------------------------------------------------------*/ 00312 /*+ CALLING : size=f_ut_compr_unpack(*input,*output,outlen) */ 00313 /*--------------------------------------------------------------------*/ 00314 /* */ 00315 /*+ PURPOSE : Deompress data field. */ 00316 /* */ 00317 /*+ ARGUMENTS : */ 00318 /* */ 00319 /*+ input : (INTU1 *) Pointer to compressed data field. */ 00320 /*+ output : (INTU1 *) Pointer to uncompressed output data field.*/ 00321 /*+ outlen : (INTS4) Length of output data field. */ 00322 /* */ 00323 /*+ Return type : INTS4 */ 00324 /*+ return : 0 : OK */ 00325 /*+ return : -1: output buffer may be too small */ 00326 /*+ Include name: f_ut_compress.h */ 00327 /* */ 00328 /*2+Description***************+****************************************/ 00329 /* Receiving a compressed buffer which could have */ 00330 /* a different endian, proceed as follows: */ 00331 /* Receive sizeof(s_compress) bytes and check */ 00332 /* s_compress.l_endian. If not 1 swap s_compress. */ 00333 /* Get s_compress.l_length-sizeof(s_compress) bytes. */ 00334 /* Swap next s_compress.l_masks longwords. */ 00335 /* Call f_ut_compr_unpack to compress the buffer. */ 00336 /* The uncompressed buffer must be checked for correct */ 00337 /* endian again. The method is up to the sender. */ 00338 /* */ 00339 /*2+Implementation************+****************************************/ 00340 /* */ 00341 /*+ Version : 1.01 */ 00342 /*+ Author : H.G.Essel */ 00343 /*+ Last Update : 13-Jul-2000 */ 00344 /* */ 00345 /*2+Internals*****+***********+****************************************/ 00346 /* */ 00347 /*+ Utility : UTIL */ 00348 /*+ Created : 07-Jul-2000 */ 00349 /* */ 00350 /*1- C Procedure ***********+******************************************/ 00351 INTS4 f_ut_compr_unpack(INTU1 *pc_input,INTU1 *pc_output,INTS4 l_outlen) 00352 { 00353 INTU4 I,J,K,L,M,N; 00354 INTU4 l_mask; 00355 INTU4 *pl_mask,*pl_tmp,*pl_out; 00356 INTU1 *pc_out,*pc_in; 00357 s_compress *ps_compress; 00358 00359 ps_compress=(s_compress *)pc_input; 00360 /* is output buffer big enough? */ 00361 if(ps_compress->l_full_bytes > l_outlen) return -1; 00362 00363 #ifdef GSI__VMS 00364 pl_out=(INTU4 *) pc_output; 00365 pl_tmp=pl_out+(ps_compress->l_full_bytes>>2); 00366 while(pl_out != pl_tmp) *pl_out++ = 0; 00367 #endif 00368 #ifdef GSI__LYNX 00369 pl_out=(INTU4 *) pc_output; 00370 pl_tmp=pl_out+(ps_compress->l_full_bytes>>2); 00371 while(pl_out != pl_tmp) *pl_out++ = 0; 00372 #endif 00373 #ifdef GSI__AIX 00374 memset(pc_output,0,ps_compress->l_full_bytes); 00375 #endif 00376 00377 pl_mask=(INTU4 *)(ps_compress+1); 00378 pc_in = (INTU1 *)(pl_mask+ps_compress->l_masks); 00379 pc_out=pc_output; 00380 /* all masks -1 */ 00381 for(L=1;L<ps_compress->l_masks;L++) 00382 { 00383 l_mask=*pl_mask; 00384 UNPACK(0x00000001); 00385 UNPACK(0x00000002); 00386 UNPACK(0x00000004); 00387 UNPACK(0x00000008); 00388 UNPACK(0x00000010); 00389 UNPACK(0x00000020); 00390 UNPACK(0x00000040); 00391 UNPACK(0x00000080); 00392 UNPACK(0x00000100); 00393 UNPACK(0x00000200); 00394 UNPACK(0x00000400); 00395 UNPACK(0x00000800); 00396 UNPACK(0x00001000); 00397 UNPACK(0x00002000); 00398 UNPACK(0x00004000); 00399 UNPACK(0x00008000); 00400 UNPACK(0x00010000); 00401 UNPACK(0x00020000); 00402 UNPACK(0x00040000); 00403 UNPACK(0x00080000); 00404 UNPACK(0x00100000); 00405 UNPACK(0x00200000); 00406 UNPACK(0x00400000); 00407 UNPACK(0x00800000); 00408 UNPACK(0x01000000); 00409 UNPACK(0x02000000); 00410 UNPACK(0x04000000); 00411 UNPACK(0x08000000); 00412 UNPACK(0x10000000); 00413 UNPACK(0x20000000); 00414 UNPACK(0x40000000); 00415 UNPACK(0x80000000); 00416 pl_mask++; 00417 } 00418 l_mask=*pl_mask; 00419 /* restore bytes of last mask (could be less than 32) */ 00420 for(L=0;L<ps_compress->l_full_bytes-ps_compress->l_masks*32+32;L++) 00421 { 00422 if(l_mask%2 != 0) *pc_out++ = *pc_in++; else *pc_out++=0; 00423 l_mask = l_mask >> 1; 00424 } 00425 return 0; 00426 }