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