summaryrefslogblamecommitdiff
path: root/src/lib/emile/emile_compress.c
blob: 0d2e605795c6270c1dc4a1bebd71a6d178acb166 (plain) (tree)
1
2
3
4
5
6
7
8
9
                    
                   
      


                 
                    

                  
     

                  

      



                  
          
                                                                             



                      

                                                                 

                       

                                                               
              
                  



                  


                                        
 
                        
              
                 

                             
                                                 

                            

                 



                     


                                                                         

                                                                                              
                                 
 

                         

              
                       


                                                                           


                                        

                         

              
                      






                                                                                                                                             







                      
                                                              


              
                                                                              
 

                       




                       










                                                                            
                      







                                                                                                                                             
              
                          





                    


                                          




                                  

                 
 
                                                                   

                   
 
                                   



                   




                           

               
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <zlib.h>

#ifdef ENABLE_LIBLZ4
#include <lz4.h>
#include <lz4hc.h>
#else
#include "lz4.h"
#include "lz4hc.h"
#endif

#include <Eina.h>

#include "Emile.h"

static int
_emile_compress_buffer_size(const Eina_Binbuf *data, Emile_Compressor_Type t)
{
   switch (t)
     {
      case EMILE_ZLIB:
        return 12 + ((eina_binbuf_length_get(data) * 101) / 100);

      case EMILE_LZ4:
      case EMILE_LZ4HC:
        return LZ4_compressBound(eina_binbuf_length_get(data));

      default:
        return -1;
     }
}

EAPI Eina_Binbuf *
emile_compress(const Eina_Binbuf *data,
               Emile_Compressor_Type t,
               Emile_Compressor_Level l)
{
   void *compact, *temp;
   int length;
   int level = l;
   Eina_Bool ok = EINA_FALSE;

   length = _emile_compress_buffer_size(data, t);

   compact = malloc(length);
   if (!compact)
     return NULL;

   switch (t)
     {
      case EMILE_LZ4:
        length = LZ4_compress((const char *)eina_binbuf_string_get(data),
                              compact,
                              eina_binbuf_length_get(data));
        /* It is going to be smaller and should never fail, if it does you are in deep poo. */
        temp = realloc(compact, length);
        if (temp) compact = temp;

        if (length > 0)
          ok = EINA_TRUE;
        break;

      case EMILE_LZ4HC:
        length = LZ4_compressHC((const char *)eina_binbuf_string_get(data),
                                compact,
                                eina_binbuf_length_get(data));
        temp = realloc(compact, length);
        if (temp) compact = temp;

        if (length > 0)
          ok = EINA_TRUE;
        break;

      case EMILE_ZLIB:
      {
         uLongf buflen = (uLongf)length;

         if (compress2((Bytef *)compact, &buflen, (Bytef *)eina_binbuf_string_get(data), (uLong)eina_binbuf_length_get(data), level) == Z_OK)
           ok = EINA_TRUE;
         length = (int)buflen;
      }
     }

   if (!ok)
     {
        free(compact);
        return NULL;
     }

   return eina_binbuf_manage_new(compact, length, EINA_FALSE);
}

EAPI Eina_Bool
emile_expand(const Eina_Binbuf *in, Eina_Binbuf *out, Emile_Compressor_Type t)
{
   if (!in || !out)
     return EINA_FALSE;

   switch (t)
     {
      case EMILE_LZ4:
      case EMILE_LZ4HC:
      {
         int ret;

         ret = LZ4_decompress_fast((const char *)eina_binbuf_string_get(in),
                                   (char *)eina_binbuf_string_get(out),
                                   eina_binbuf_length_get(out));
         if ((unsigned int)ret != eina_binbuf_length_get(in))
           return EINA_FALSE;
         break;
      }

      case EMILE_ZLIB:
      {
         uLongf dlen = eina_binbuf_length_get(out);

         if (uncompress((Bytef *)eina_binbuf_string_get(out), &dlen, eina_binbuf_string_get(in), (uLongf)eina_binbuf_length_get(in)) != Z_OK)
           return EINA_FALSE;
         break;
      }

      default:
        return EINA_FALSE;
     }

   return EINA_TRUE;
}

EAPI Eina_Binbuf *
emile_decompress(const Eina_Binbuf *data,
                 Emile_Compressor_Type t,
                 unsigned int dest_length)
{
   Eina_Binbuf *out;
   void *expanded;

   expanded = malloc(dest_length);
   if (!expanded)
     return NULL;

   out = eina_binbuf_manage_new(expanded, dest_length, EINA_FALSE);
   if (!out)
     goto on_error;

   if (!emile_expand(data, out, t))
     goto on_error;

   return out;

on_error:
   if (!out)
     free(expanded);
   if (out)
     eina_binbuf_free(out);
   return NULL;
}