LCOV - code coverage report
Current view: top level - src - serialization.cpp (source / functions) Hit Total Coverage
Test: report Lines: 34 129 26.4 %
Date: 2015-07-11 18:23:49 Functions: 3 8 37.5 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "serialization.h"
      21             : 
      22             : #include "util/serialize.h"
      23             : #ifdef _WIN32
      24             :         #define ZLIB_WINAPI
      25             : #endif
      26             : #include "zlib.h"
      27             : 
      28             : /* report a zlib or i/o error */
      29           0 : void zerr(int ret)
      30             : {   
      31           0 :     dstream<<"zerr: ";
      32           0 :     switch (ret) {
      33             :     case Z_ERRNO:
      34           0 :         if (ferror(stdin))
      35           0 :             dstream<<"error reading stdin"<<std::endl;
      36           0 :         if (ferror(stdout))
      37           0 :             dstream<<"error writing stdout"<<std::endl;
      38           0 :         break;
      39             :     case Z_STREAM_ERROR:
      40           0 :         dstream<<"invalid compression level"<<std::endl;
      41           0 :         break;
      42             :     case Z_DATA_ERROR:
      43           0 :         dstream<<"invalid or incomplete deflate data"<<std::endl;
      44           0 :         break;
      45             :     case Z_MEM_ERROR:
      46           0 :         dstream<<"out of memory"<<std::endl;
      47           0 :         break;
      48             :     case Z_VERSION_ERROR:
      49           0 :         dstream<<"zlib version mismatch!"<<std::endl;
      50           0 :                 break;
      51             :         default:
      52           0 :                 dstream<<"return value = "<<ret<<std::endl;
      53             :     }
      54           0 : }
      55             : 
      56           0 : void compressZlib(SharedBuffer<u8> data, std::ostream &os, int level)
      57             : {
      58             :         z_stream z;
      59           0 :         const s32 bufsize = 16384;
      60             :         char output_buffer[bufsize];
      61           0 :         int status = 0;
      62             :         int ret;
      63             : 
      64           0 :         z.zalloc = Z_NULL;
      65           0 :         z.zfree = Z_NULL;
      66           0 :         z.opaque = Z_NULL;
      67             : 
      68           0 :         ret = deflateInit(&z, level);
      69           0 :         if(ret != Z_OK)
      70           0 :                 throw SerializationError("compressZlib: deflateInit failed");
      71             :         
      72             :         // Point zlib to our input buffer
      73           0 :         z.next_in = (Bytef*)&data[0];
      74           0 :         z.avail_in = data.getSize();
      75             :         // And get all output
      76           0 :         for(;;)
      77             :         {
      78           0 :                 z.next_out = (Bytef*)output_buffer;
      79           0 :                 z.avail_out = bufsize;
      80             :                 
      81           0 :                 status = deflate(&z, Z_FINISH);
      82           0 :                 if(status == Z_NEED_DICT || status == Z_DATA_ERROR
      83           0 :                                 || status == Z_MEM_ERROR)
      84             :                 {
      85           0 :                         zerr(status);
      86           0 :                         throw SerializationError("compressZlib: deflate failed");
      87             :                 }
      88           0 :                 int count = bufsize - z.avail_out;
      89           0 :                 if(count)
      90           0 :                         os.write(output_buffer, count);
      91             :                 // This determines zlib has given all output
      92           0 :                 if(status == Z_STREAM_END)
      93           0 :                         break;
      94             :         }
      95             : 
      96           0 :         deflateEnd(&z);
      97           0 : }
      98             : 
      99           0 : void compressZlib(const std::string &data, std::ostream &os, int level)
     100             : {
     101           0 :         SharedBuffer<u8> databuf((u8*)data.c_str(), data.size());
     102           0 :         compressZlib(databuf, os, level);
     103           0 : }
     104             : 
     105        1574 : void decompressZlib(std::istream &is, std::ostream &os)
     106             : {
     107             :         z_stream z;
     108        1574 :         const s32 bufsize = 16384;
     109             :         char input_buffer[bufsize];
     110             :         char output_buffer[bufsize];
     111        1574 :         int status = 0;
     112             :         int ret;
     113        1574 :         int bytes_read = 0;
     114        1574 :         int input_buffer_len = 0;
     115             : 
     116        1574 :         z.zalloc = Z_NULL;
     117        1574 :         z.zfree = Z_NULL;
     118        1574 :         z.opaque = Z_NULL;
     119             : 
     120        1574 :         ret = inflateInit(&z);
     121        1574 :         if(ret != Z_OK)
     122           0 :                 throw SerializationError("dcompressZlib: inflateInit failed");
     123             :         
     124        1574 :         z.avail_in = 0;
     125             :         
     126             :         //dstream<<"initial fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
     127             : 
     128         463 :         for(;;)
     129             :         {
     130        2037 :                 z.next_out = (Bytef*)output_buffer;
     131        2037 :                 z.avail_out = bufsize;
     132             : 
     133        2037 :                 if(z.avail_in == 0)
     134             :                 {
     135        1587 :                         z.next_in = (Bytef*)input_buffer;
     136        1587 :                         input_buffer_len = is.readsome(input_buffer, bufsize);
     137        1587 :                         z.avail_in = input_buffer_len;
     138             :                         //dstream<<"read fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
     139             :                 }
     140        2037 :                 if(z.avail_in == 0)
     141             :                 {
     142             :                         //dstream<<"z.avail_in == 0"<<std::endl;
     143           0 :                         break;
     144             :                 }
     145             :                         
     146             :                 //dstream<<"1 z.avail_in="<<z.avail_in<<std::endl;
     147        2037 :                 status = inflate(&z, Z_NO_FLUSH);
     148             :                 //dstream<<"2 z.avail_in="<<z.avail_in<<std::endl;
     149        2037 :                 bytes_read += is.gcount() - z.avail_in;
     150             :                 //dstream<<"bytes_read="<<bytes_read<<std::endl;
     151             : 
     152        2037 :                 if(status == Z_NEED_DICT || status == Z_DATA_ERROR
     153        2037 :                                 || status == Z_MEM_ERROR)
     154             :                 {
     155           0 :                         zerr(status);
     156           0 :                         throw SerializationError("decompressZlib: inflate failed");
     157             :                 }
     158        2037 :                 int count = bufsize - z.avail_out;
     159             :                 //dstream<<"count="<<count<<std::endl;
     160        2037 :                 if(count)
     161        2037 :                         os.write(output_buffer, count);
     162        2037 :                 if(status == Z_STREAM_END)
     163             :                 {
     164             :                         //dstream<<"Z_STREAM_END"<<std::endl;
     165             :                         
     166             :                         //dstream<<"z.avail_in="<<z.avail_in<<std::endl;
     167             :                         //dstream<<"fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
     168             :                         // Unget all the data that inflate didn't take
     169      331418 :                         for(u32 i=0; i < z.avail_in; i++)
     170             :                         {
     171      329844 :                                 is.unget();
     172      329844 :                                 if(is.fail() || is.bad())
     173             :                                 {
     174           0 :                                         dstream<<"unget #"<<i<<" failed"<<std::endl;
     175           0 :                                         dstream<<"fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
     176           0 :                                         throw SerializationError("decompressZlib: unget failed");
     177             :                                 }
     178             :                         }
     179             :                         
     180        1574 :                         break;
     181             :                 }
     182             :         }
     183             : 
     184        1574 :         inflateEnd(&z);
     185        1574 : }
     186             : 
     187           0 : void compress(SharedBuffer<u8> data, std::ostream &os, u8 version)
     188             : {
     189           0 :         if(version >= 11)
     190             :         {
     191           0 :                 compressZlib(data, os);
     192           0 :                 return;
     193             :         }
     194             : 
     195           0 :         if(data.getSize() == 0)
     196           0 :                 return;
     197             :         
     198             :         // Write length (u32)
     199             : 
     200             :         u8 tmp[4];
     201           0 :         writeU32(tmp, data.getSize());
     202           0 :         os.write((char*)tmp, 4);
     203             :         
     204             :         // We will be writing 8-bit pairs of more_count and byte
     205           0 :         u8 more_count = 0;
     206           0 :         u8 current_byte = data[0];
     207           0 :         for(u32 i=1; i<data.getSize(); i++)
     208             :         {
     209           0 :                 if(
     210           0 :                         data[i] != current_byte
     211           0 :                         || more_count == 255
     212             :                 )
     213             :                 {
     214             :                         // write count and byte
     215           0 :                         os.write((char*)&more_count, 1);
     216           0 :                         os.write((char*)&current_byte, 1);
     217           0 :                         more_count = 0;
     218           0 :                         current_byte = data[i];
     219             :                 }
     220             :                 else
     221             :                 {
     222           0 :                         more_count++;
     223             :                 }
     224             :         }
     225             :         // write count and byte
     226           0 :         os.write((char*)&more_count, 1);
     227           0 :         os.write((char*)&current_byte, 1);
     228             : }
     229             : 
     230           0 : void decompress(std::istream &is, std::ostream &os, u8 version)
     231             : {
     232           0 :         if(version >= 11)
     233             :         {
     234           0 :                 decompressZlib(is, os);
     235           0 :                 return;
     236             :         }
     237             : 
     238             :         // Read length (u32)
     239             : 
     240             :         u8 tmp[4];
     241           0 :         is.read((char*)tmp, 4);
     242           0 :         u32 len = readU32(tmp);
     243             :         
     244             :         // We will be reading 8-bit pairs of more_count and byte
     245           0 :         u32 count = 0;
     246           0 :         for(;;)
     247             :         {
     248           0 :                 u8 more_count=0;
     249           0 :                 u8 byte=0;
     250             : 
     251           0 :                 is.read((char*)&more_count, 1);
     252             :                 
     253           0 :                 is.read((char*)&byte, 1);
     254             : 
     255           0 :                 if(is.eof())
     256           0 :                         throw SerializationError("decompress: stream ended halfway");
     257             : 
     258           0 :                 for(s32 i=0; i<(u16)more_count+1; i++)
     259           0 :                         os.write((char*)&byte, 1);
     260             : 
     261           0 :                 count += (u16)more_count+1;
     262             : 
     263           0 :                 if(count == len)
     264           0 :                         break;
     265             :         }
     266           3 : }
     267             : 
     268             : 

Generated by: LCOV version 1.11