/*
简单说明:
针对libzip库,封装了两个接口,compressString 压缩字符串 ,uncompressString 解压字符串
zhangtao /2016/06/13   使用者请联系[email protected]
测试代码:
char inbuf[]="HELLOWORLD";
int  inLen=strlen(inbuf);
char outbuf[8192];
int outLen=0;    
compressString(inbuf,inLen,outbuf,8192,&outLen) ;   

char outbuf2[8192];
int outLen2=0;    
uncompressString(outbuf,outLen,outbuf2,8192,&outLen2);
printf("uncompressString %d %s\n",outLen2,outbuf2);
*/
static  const  char* ziparchive="data.zip";
static  const  char* archive="data";

static  void saveZip( char* apOutBuf, int auOutBufSize)
{
    FILE* fp;
     if ((fp=fopen(ziparchive, "wb")) == NULL) {
        fprintf(stderr, "fopen failed: %s\n", strerror(errno));            
         return ;
    }
    printf("fwrite size:%d\n",auOutBufSize);
     if (fwrite(apOutBuf, auOutBufSize, 1, fp) < 1) {
        fprintf(stderr, "fwrite failed: %s\n", strerror(errno));            
        fclose(fp);
         return;
    }

     if (fclose(fp) != 0) {
        fprintf(stderr, "fclose failed: %s\n", strerror(errno));
         return;
    }
}

static  int compressString( const  char* apData, int auDataSize, char* apOutBuf, int auOutBufSize, int* apOutBufLen)
{    
     int ret=-1;
    *apOutBufLen=0;
    
    zip_t *za;
    zip_source_t *zs;
    zip_stat_t zst;    
     struct stat st;
    zip_source_t *src;    
    zip_error_t error;    
     int err;

    
     do 
    {
        src = zip_source_buffer_create(NULL,0, 0, &error);
         if (src == NULL) {
            err = zip_error_code_zip(&error);
            errno = zip_error_code_system(&error);
            fprintf(stderr, "zip_source_buffer_create faild: %d\n",err);
             break;
        }

        za = zip_open_from_source(src, 1, &error);
         if (za == NULL) {
            err = zip_error_code_zip(&error);
            errno = zip_error_code_system(&error);            
            fprintf(stderr, "zip_open_from_source faild: %d\n",err);
             break;
        }
        
        zip_source_keep(src);

         if ((zs=zip_source_buffer(za, apData, auDataSize, 0)) == NULL) {
            fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za));
             break;
        }

         if (zip_add(za, archive, zs) == -1) {            
            fprintf(stderr, "can't add file '%s': %s\n", archive, zip_strerror(za));
             break;
        }

         if (zip_close(za) == -1) {
            fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za));
             break;
        }

        za=NULL;

         if (zip_source_stat(src, &zst) < 0) {
            fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
             break;
        }

         if (zst.size <=0){
            printf(" size error 000\n");
             break;
        }

         if (zst.size >= auOutBufSize){
            printf(" size error 111\n");
             break;
        }
                
         if (zip_source_open(src) < 0) {
             if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) {
                 if (unlink(archive) < 0 && errno != ENOENT) {
                    fprintf(stderr, "unlink failed: %s\n", strerror(errno));
                     break;
                }
                 break;
            }
            fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
             break;
        }
        

         if (zip_source_read(src, apOutBuf, zst.size) < (zip_int64_t)zst.size) {
            fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
            zip_source_close(src);            
             break;
        }
                
        zip_source_close(src);    
        *apOutBufLen = ( int)(zst.size);
        ret=0;    

         // saveZip(apOutBuf,*apOutBufLen );

    }  while (0);

     if (NULL != src)
    {
        zip_source_free(src);
        src=NULL;
    }

     if (NULL != za)
    {
        zip_close(za);
        za=NULL;
    }


     return ret;
}


static  int uncompressString( const  char* apData, int auDataSize, char* apOutBuf, int auOutBufSize, int* apOutBufLen)
{
     int ret=-1;

    *apOutBufLen=0;
    zip_error_t error;    
     int err=0;
     char* buf=apOutBuf;    
     int   totalSize=0;
    zip_int64_t n = 0;    
    zip_source_t *src=NULL;
    zip_t *za=NULL;
     struct zip_file *f=NULL;


     do 
    {
        zip_error_init(&error);
        
         /*  create source from buffer  */
         if ((src = zip_source_buffer_create(apData, auDataSize, 1, &error)) == NULL) {
            fprintf(stderr, "can't create source: %s\n", zip_error_strerror(&error));        
            zip_error_fini(&error);
             break;
        }

         /*  open zip archive from source  */
         if ((za = zip_open_from_source(src, 0, &error)) == NULL) {
            fprintf(stderr, "can't open zip from source: %s\n", zip_error_strerror(&error));            
            zip_error_fini(&error);
             break;
        }


        zip_error_fini(&error);    
        zip_source_keep(src);

        zip_int64_t  c = zip_get_num_entries(za, ZIP_FL_UNCHANGED);
         if ( c != 1)
        {
            printf("zip_get_num_entries 0 \n");
             break;
        }

         const  char * name = zip_get_name(za, 0, ZIP_FL_ENC_GUESS);
         if (NULL == name)
        {
            printf("zip_get_name 0 \n");
             break;
        }

        f = zip_fopen(za, name, 0);
         if (NULL == f)
        {
            printf("zip_fopen 0 \n");
             break;
        }
        
         if ( auOutBufSize < 4096)
        {
            printf("auOutBufSize < 4096 \n");
             break;
        }
        
        totalSize=0;
         while( totalSize < auOutBufSize)
        {
            buf = apOutBuf+ totalSize;    
            n = zip_fread(f, buf, 4096);
             if (n <=0 )
            {
                 break;
            }

            totalSize += n;        
        }

         if (totalSize >= auOutBufSize)
        {
            printf("totalSize too big \n");
             break;
        }

        *apOutBufLen=totalSize;
        ret=0;

    }  while (0);
    

     if (NULL != f)
    {
        zip_fclose(f);
        f=NULL;
    }

     if (NULL != za)
    {
         // lt-in-memory: free(): invalid pointer: 0x00007fff9c75c6d0 ***
        
// zip_close(za);
        za=NULL;
    }

     if (NULL != src)
    {
        zip_source_free(src);
        src=NULL;
    }

     return ret;
}