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