/* 
// Copyright 2015 2018 Intel Corporation All Rights Reserved.
// 
// The source code, information and material ("Material") contained herein is
// owned by Intel Corporation or its suppliers or licensors, and title
// to such Material remains with Intel Corporation or its suppliers or
// licensors. The Material contains proprietary information of Intel
// or its suppliers and licensors. The Material is protected by worldwide
// copyright laws and treaty provisions. No part of the Material may be used,
// copied, reproduced, modified, published, uploaded, posted, transmitted,
// distributed or disclosed in any way without Intel's prior express written
// permission. No license under any patent, copyright or other intellectual
// property rights in the Material is granted to or conferred upon you,
// either expressly, by implication, inducement, estoppel or otherwise.
// Any license under such intellectual property rights must be express and
// approved by Intel in writing.
// 
// Unless otherwise agreed by Intel in writing,
// you may not remove or alter this notice or any other notice embedded in
// Materials by Intel or Intel's suppliers or licensors in any way.
*/

// The example below shows how to use the function ippsEncodeLZSS_8u and supporting functions:
//     ippsLZSSGetSize_8u, ippsEncodeLZSSInit_8u
//     ippsEncodeLZSS_8u
//     ippsEncodeLZSSFlush_8u

#include <stdio.h>
#include "ipp.h"

#define INBLOCKSIZE 65536
#define OUTBLOCKSIZE 16384

/* Next two defines are created to simplify code reading and understanding */
#define EXIT_MAIN exitLine:                                  /* Label for Exit */
#define check_sts(st) if((st) != ippStsNoErr) goto exitLine; /* Go to Exit if Intel(R) Integrated Primitives (Intel(R) IPP) function returned status different from ippStsNoErr */

/* Results of ippMalloc() are not validated because Intel(R) IPP functions perform bad arguments check and will return an appropriate status  */


int main(void)
{
   FILE *inFile = NULL, *outFile = NULL;
   Ipp8u *pSrc  = NULL, *pDst    = NULL, *startpSrc = NULL, *startpDst = NULL;
   int srcLen, dstLen = 0;
   int commonDstLen = 0;
   IppLZSSState_8u *pLZSSState = NULL;
   int szState = 0;
   IppStatus status = ippStsNoErr;

   inFile = fopen("EncodeLZSSFlush.c", "rb");
   if ( !inFile )
   {
      printf("\nCan't open input data file ""EncodeLZSSFlush.c"". program terminated.\n");
      goto exitLine;
   }
   outFile = fopen("EncodeLZSSFlush.bin", "wb");
   if ( !outFile ) {
      printf("\nCan't open output data file ""EncodeLZSSFlush.bin"". program terminated.\n");
      goto exitLine;
   }

   /*************************************************************/
   /* Memory allocation for input data and output code buffers, */
   /* and for the internal encoding state structure:            */
   /*************************************************************/
   startpSrc = ippsMalloc_8u( (INBLOCKSIZE) * sizeof(char) );
   startpDst = ippsMalloc_8u( (OUTBLOCKSIZE) * sizeof(char) );

   check_sts( status = ippsLZSSGetSize_8u( &szState ) )

   pLZSSState = (IppLZSSState_8u*)ippsMalloc_8u( szState );

   check_sts( status = ippsEncodeLZSSInit_8u( pLZSSState ) )

   /*************************************************************/
   /* Initializing the arguments, reading srcLen bytes of       */
   /* input data from input data file to startpSrc:             */
   /*************************************************************/
   commonDstLen = (OUTBLOCKSIZE);
   pDst = startpDst;
   dstLen = commonDstLen;
   srcLen = fread( startpSrc, sizeof(Ipp8u), INBLOCKSIZE, inFile );

   if (srcLen <= 0) {
      printf("\nInput data file ""EncodeLZSSFlush.c"" is corrupted. program terminated.\n");
      goto exitLine;
   }
   pSrc = startpSrc;

   /**************************************************************/
   /* The main loop. In every iteration program calls the        */
   /* ippsEncodeLZSS_8u. ippsEncodeLZSS_8u changes the values    */
   /* of pSrc, srcLen, pDst and dstLen. ippsEncodeLZSS_8u        */
   /* returns ippStsDstSizeLessExpected if there is no           */
   /* room in the destination buffer pDst to continue encoding.  */
   /* In this case dstLen == 0. Such case is handled by          */
   /* flushing the pDst to the output file. If ippsEncodeLZSS_8u */
   /* returns ippStsNoErr, then the program flushes the current  */
   /* pDst of length of (commonDstLen - dstLen) bytes to         */
   /* the output file and reads next srcLen bytes of input data  */
   /* to startpSrc.                                              */
   /**************************************************************/
   for( ; ; ) {
      status = ippsEncodeLZSS_8u(&pSrc, &srcLen, &pDst, &dstLen, pLZSSState);
      if( status == ippStsDstSizeLessExpected ) {
         fwrite( startpDst, sizeof(Ipp8u), (commonDstLen - dstLen), outFile );
         dstLen = commonDstLen;
         pDst = startpDst;

      } else if( status == ippStsNoErr ) {
         fwrite( startpDst, sizeof(Ipp8u), (commonDstLen - dstLen), outFile );
         pDst = startpDst;
         dstLen = commonDstLen;
         srcLen = fread( startpSrc, sizeof(Ipp8u), INBLOCKSIZE, inFile );
         if( srcLen <= 0 )
            break;
         pSrc = startpSrc;
      } else {
          check_sts( status )
      }
   }

   /**************************************************************/
   /*  The call of ippsEncodeLZSSFlush_8u flushes the last few   */
   /*  bits of code to the destination buffer:                   */
   /**************************************************************/
   check_sts( ippsEncodeLZSSFlush_8u(&pDst, &dstLen, pLZSSState) ) 
   fwrite( startpDst, sizeof(Ipp8u), (commonDstLen - dstLen), outFile );
   printf( "\n EncodeLZSSFlush.c successfully encoded to EncodeLZSSFlush.bin \n");

EXIT_MAIN
   ippsFree( pLZSSState );
   ippsFree( startpSrc );
   ippsFree( startpDst );
   if ( inFile ) fclose( inFile );
   if ( outFile ) fclose( outFile );
   printf("Exit status %d (%s)\n", (int)status, ippGetStatusString(status));
   return (int)status;
}