text: /*!The Treasure Box Library
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * Copyright (C) 2009-present, TBOOX Open Source Group.
   *
   * @author      ruki
   * @file        zlibraw.c
   * @ingroup     zip
   *
   */
  /* //////////////////////////////////////////////////////////////////////////////////////
   * trace
   */
  #define TB_TRACE_MODULE_NAME                "zlibraw"
  #define TB_TRACE_MODULE_DEBUG               (0)
  
  /* //////////////////////////////////////////////////////////////////////////////////////
   * includes
   */
  #include "zlibraw.h"
  
  /* //////////////////////////////////////////////////////////////////////////////////////
   * implements
   */
  static __tb_inline__ tb_zip_zlibraw_t* tb_zip_zlibraw_cast(tb_zip_ref_t zip)
  {
      tb_assert_and_check_return_val(zip && zip->algo == TB_ZIP_ALGO_ZLIBRAW, tb_null);
      return (tb_zip_zlibraw_t*)zip;
  }
  static tb_long_t tb_zip_zlibraw_spak_deflate(tb_zip_ref_t zip, tb_static_stream_ref_t ist, tb_static_stream_ref_t ost, tb_long_t sync)
  {
      tb_zip_zlibraw_t* zlibraw = tb_zip_zlibraw_cast(zip);
      tb_assert_and_check_return_val(zlibraw && ist && ost, -1);
  
      // the input stream
      tb_byte_t* ip = ist->p;
      tb_byte_t* ie = ist->e;
      tb_check_return_val(ip && ip < ie, 0);
  
      // the output stream
      tb_byte_t* op = ost->p;
      tb_byte_t* oe = ost->e;
      tb_assert_and_check_return_val(op && oe, -1);
  
      // attach zstream
      zlibraw->zstream.next_in = (Bytef*)ip;
      zlibraw->zstream.avail_in = (uInt)(ie - ip);
  
      zlibraw->zstream.next_out = (Bytef*)op;
      zlibraw->zstream.avail_out = (uInt)(oe - op);
  
      // deflate
      tb_int_t r = deflate(&zlibraw->zstream, !sync? Z_NO_FLUSH : Z_SYNC_FLUSH);
      tb_assertf_and_check_return_val(r == Z_OK || r == Z_STREAM_END, -1, "sync: %ld, error: %d", sync, r);
      tb_trace_d("deflate: %u => %u, sync: %ld", ie - ip, (tb_byte_t*)zlibraw->zstream.next_out - op, sync);
  
      // update
      ist->p = (tb_byte_t*)zlibraw->zstream.next_in;
      ost->p = (tb_byte_t*)zlibraw->zstream.next_out;
  
      // end?
      tb_check_return_val(r != Z_STREAM_END || ost->p > op, -1);
  
      // ok?
      return (ost->p - op);
  }
  static tb_long_t tb_zip_zlibraw_spak_inflate(tb_zip_ref_t zip, tb_static_stream_ref_t ist, tb_static_stream_ref_t ost, tb_long_t sync)
  {
      tb_zip_zlibraw_t* zlibraw = tb_zip_zlibraw_cast(zip);
      tb_assert_and_check_return_val(zlibraw && ist && ost, -1);
  
      // the input stream
      tb_byte_t* ip = ist->p;
      tb_byte_t* ie = ist->e;
      tb_check_return_val(ip && ip < ie, 0);
  
      // the output stream
      tb_byte_t* op = ost->p;
      tb_byte_t* oe = ost->e;
      tb_assert_and_check_return_val(op && oe, -1);
  
      // attach zstream
      zlibraw->zstream.next_in = (Bytef*)ip;
      zlibraw->zstream.avail_in = (uInt)(ie - ip);
  
      zlibraw->zstream.next_out = (Bytef*)op;
      zlibraw->zstream.avail_out = (uInt)(oe - op);
  
      // inflate
      tb_int_t r = inflate(&zlibraw->zstream, !sync? Z_NO_FLUSH : Z_SYNC_FLUSH);
      tb_assertf_and_check_return_val(r == Z_OK || r == Z_STREAM_END, -1, "sync: %ld, error: %d", sync, r);
      tb_trace_d("inflate: %u => %u, sync: %ld", ie - ip, (tb_byte_t*)zlibraw->zstream.next_out - op, sync);
  
      // update
      ist->p = (tb_byte_t*)zlibraw->zstream.next_in;
      ost->p = (tb_byte_t*)zlibraw->zstream.next_out;
  
      // end?
      tb_check_return_val(r != Z_STREAM_END || ost->p > op, -1);
  
      // ok?
      return (ost->p - op);
  }
  
  /* //////////////////////////////////////////////////////////////////////////////////////
   * interfaces
   */
  tb_zip_ref_t tb_zip_zlibraw_init(tb_size_t action)
  {
      // done
      tb_bool_t           ok = tb_false;
      tb_zip_zlibraw_t*   zip = tb_null;
      do
      {
          // make zip
          zip = tb_malloc0_type(tb_zip_zlibraw_t);
          tb_assert_and_check_break(zip);
  
          // init algo
          zip->base.algo = TB_ZIP_ALGO_ZLIBRAW;
  
          // open zstream
          if (action == TB_ZIP_ACTION_INFLATE)
          {
              // init spak
              zip->base.spak = tb_zip_zlibraw_spak_inflate;
  
              // init zstream, no zlib header
              if (inflateInit(&((tb_zip_zlibraw_t*)zip)->zstream) != Z_OK) break;
          }
          else if (action == TB_ZIP_ACTION_DEFLATE)
          {
              // init spak
              zip->base.spak = tb_zip_zlibraw_spak_deflate;
  
              // init zstream
              if (deflateInit(&((tb_zip_zlibraw_t*)zip)->zstream, Z_DEFAULT_COMPRESSION) != Z_OK) break;
          }
  
          // init action after initializing zstream
          zip->base.action = (tb_uint16_t)action;
  
          // ok
          ok = tb_true;
  
      } while (0);
  
      // failed?
      if (!ok)
      {
          // exit it
          if (zip) tb_zip_zlibraw_exit((tb_zip_ref_t)zip);
          zip = tb_null;
      }
  
      // ok?
      return (tb_zip_ref_t)zip;
  }
  tb_void_t tb_zip_zlibraw_exit(tb_zip_ref_t zip)
  {
      // check
      tb_zip_zlibraw_t* zlibraw = tb_zip_zlibraw_cast(zip);
      tb_assert_and_check_return(zlibraw);
  
      // exit zstream
      if (zip->action == TB_ZIP_ACTION_INFLATE) inflateEnd(&(zlibraw->zstream));
      else if (zip->action == TB_ZIP_ACTION_DEFLATE) deflateEnd(&(zlibraw->zstream));
  
      // free it
      tb_free(zlibraw);
  }
  
  