1/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
22009-08-14 : Igor Pavlov : Public domain */
3
4#include <string.h>
5
6#include "Lzma86.h"
7
8#include "Alloc.h"
9#include "Bra.h"
10#include "LzmaEnc.h"
11
12#define SZE_OUT_OVERFLOW SZE_DATA_ERROR
13
14static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
15static void SzFree(void *p, void *address) { p = p; MyFree(address); }
16
17int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
18    int level, UInt32 dictSize, int filterMode)
19{
20  ISzAlloc g_Alloc = { SzAlloc, SzFree };
21  size_t outSize2 = *destLen;
22  Byte *filteredStream;
23  Bool useFilter;
24  int mainResult = SZ_ERROR_OUTPUT_EOF;
25  CLzmaEncProps props;
26  LzmaEncProps_Init(&props);
27  props.level = level;
28  props.dictSize = dictSize;
29
30  *destLen = 0;
31  if (outSize2 < LZMA86_HEADER_SIZE)
32    return SZ_ERROR_OUTPUT_EOF;
33
34  {
35    int i;
36    UInt64 t = srcLen;
37    for (i = 0; i < 8; i++, t >>= 8)
38      dest[LZMA86_SIZE_OFFSET + i] = (Byte)t;
39  }
40
41  filteredStream = 0;
42  useFilter = (filterMode != SZ_FILTER_NO);
43  if (useFilter)
44  {
45    if (srcLen != 0)
46    {
47      filteredStream = (Byte *)MyAlloc(srcLen);
48      if (filteredStream == 0)
49        return SZ_ERROR_MEM;
50      memcpy(filteredStream, src, srcLen);
51    }
52    {
53      UInt32 x86State;
54      x86_Convert_Init(x86State);
55      x86_Convert(filteredStream, srcLen, 0, &x86State, 1);
56    }
57  }
58
59  {
60    size_t minSize = 0;
61    Bool bestIsFiltered = False;
62
63    /* passes for SZ_FILTER_AUTO:
64        0 - BCJ + LZMA
65        1 - LZMA
66        2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better.
67    */
68    int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
69
70    int i;
71    for (i = 0; i < numPasses; i++)
72    {
73      size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE;
74      size_t outPropsSize = 5;
75      SRes curRes;
76      Bool curModeIsFiltered = (numPasses > 1 && i == numPasses - 1);
77      if (curModeIsFiltered && !bestIsFiltered)
78        break;
79      if (useFilter && i == 0)
80        curModeIsFiltered = True;
81
82      curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed,
83          curModeIsFiltered ? filteredStream : src, srcLen,
84          &props, dest + 1, &outPropsSize, 0,
85          NULL, &g_Alloc, &g_Alloc);
86
87      if (curRes != SZ_ERROR_OUTPUT_EOF)
88      {
89        if (curRes != SZ_OK)
90        {
91          mainResult = curRes;
92          break;
93        }
94        if (outSizeProcessed <= minSize || mainResult != SZ_OK)
95        {
96          minSize = outSizeProcessed;
97          bestIsFiltered = curModeIsFiltered;
98          mainResult = SZ_OK;
99        }
100      }
101    }
102    dest[0] = (bestIsFiltered ? 1 : 0);
103    *destLen = LZMA86_HEADER_SIZE + minSize;
104  }
105  if (useFilter)
106    MyFree(filteredStream);
107  return mainResult;
108}
109