/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
 
2008-08-05
 
Igor Pavlov
 
Public domain */
 
 
 
#include <string.h>
 
 
 
#include "Lzma86Enc.h"
 
 
 
#include "Alloc.h"
 
#include "Bra.h"
 
#include "LzmaEnc.h"
 
 
 
#define SZE_OUT_OVERFLOW SZE_DATA_ERROR
 
 
 
static void *SzAlloc(void *p, size_t size) { return MyAlloc(size); }
 
static void SzFree(void *p, void *address) { MyFree(address); }
 
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
 
 
 
#define LZMA86_SIZE_OFFSET (1 + LZMA_PROPS_SIZE)
 
#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
 
 
 
int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
 
    int level, UInt32 dictSize, int filterMode)
 
{
 
  size_t outSize2 = *destLen;
 
  Byte *filteredStream;
 
  Bool useFilter;
 
  int mainResult = SZ_ERROR_OUTPUT_EOF;
 
  CLzmaEncProps props;
 
  LzmaEncProps_Init(&props);
 
  props.level = level;
 
  props.dictSize = dictSize;
 
 
 
  *destLen = 0;
 
  if (outSize2 < LZMA86_HEADER_SIZE)
 
    return SZ_ERROR_OUTPUT_EOF;
 
 
 
  {
 
    int i;
 
    UInt64 t = srcLen;
 
    for (i = 0; i < 8; i++, t >>= 8)
 
      dest[LZMA86_SIZE_OFFSET + i] = (Byte)t;
 
  }
 
 
 
  filteredStream = 0;
 
  useFilter = (filterMode != SZ_FILTER_NO);
 
  if (useFilter)
 
  {
 
    if (srcLen != 0)
 
    {
 
      filteredStream = (Byte *)MyAlloc(srcLen);
 
      if (filteredStream == 0)
 
        return SZ_ERROR_MEM;
 
      memcpy(filteredStream
, src
, srcLen
);  
    }
 
    {
 
      UInt32 x86State;
 
      x86_Convert_Init(x86State);
 
      x86_Convert(filteredStream, srcLen, 0, &x86State, 1);
 
    }
 
  }
 
 
 
  {
 
    size_t minSize = 0;
 
    Bool bestIsFiltered = False;
 
 
 
    /* passes for SZ_FILTER_AUTO:
 
        0 - BCJ + LZMA
 
        1 - LZMA
 
        2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better.
 
    */
 
    int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
 
 
 
    int i;
 
    for (i = 0; i < numPasses; i++)
 
    {
 
      size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE;
 
      size_t outPropsSize = 5;
 
      SRes curRes;
 
      Bool curModeIsFiltered = (numPasses > 1 && i == numPasses - 1);
 
      if (curModeIsFiltered && !bestIsFiltered)
 
        break;
 
      if (useFilter && i == 0)
 
        curModeIsFiltered = True;
 
 
 
      curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed,
 
          curModeIsFiltered ? filteredStream : src, srcLen,
 
          &props, dest + 1, &outPropsSize, 0,
 
          NULL, &g_Alloc, &g_Alloc);
 
 
 
      if (curRes != SZ_ERROR_OUTPUT_EOF)
 
      {
 
        if (curRes != SZ_OK)
 
        {
 
          mainResult = curRes;
 
          break;
 
        }
 
        if (outSizeProcessed <= minSize || mainResult != SZ_OK)
 
        {
 
          minSize = outSizeProcessed;
 
          bestIsFiltered = curModeIsFiltered;
 
          mainResult = SZ_OK;
 
        }
 
      }
 
    }
 
    dest[0] = (unsigned char) (bestIsFiltered ? 1 : 0); /*MAB: Cast to silence compiler */
 
    *destLen = LZMA86_HEADER_SIZE + minSize;
 
  }
 
  if (useFilter)
 
    MyFree(filteredStream);
 
  return mainResult;
 
}