1 /* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
2 2009-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 
SzAlloc(void * p,size_t size)14 static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
SzFree(void * p,void * address)15 static void SzFree(void *p, void *address) { p = p; MyFree(address); }
16 
Lzma86_Encode(Byte * dest,size_t * destLen,const Byte * src,size_t srcLen,int level,UInt32 dictSize,int filterMode)17 int 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