xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/DeflateDecoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // DeflateDecoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "DeflateDecoder.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
8*f6dc9357SAndroid Build Coastguard Worker namespace NDeflate {
9*f6dc9357SAndroid Build Coastguard Worker namespace NDecoder {
10*f6dc9357SAndroid Build Coastguard Worker 
CCoder(bool deflate64Mode)11*f6dc9357SAndroid Build Coastguard Worker CCoder::CCoder(bool deflate64Mode):
12*f6dc9357SAndroid Build Coastguard Worker     _deflateNSIS(false),
13*f6dc9357SAndroid Build Coastguard Worker     _deflate64Mode(deflate64Mode),
14*f6dc9357SAndroid Build Coastguard Worker     _keepHistory(false),
15*f6dc9357SAndroid Build Coastguard Worker     _needFinishInput(false),
16*f6dc9357SAndroid Build Coastguard Worker     _needInitInStream(true),
17*f6dc9357SAndroid Build Coastguard Worker     _outSizeDefined(false),
18*f6dc9357SAndroid Build Coastguard Worker     _outStartPos(0)
19*f6dc9357SAndroid Build Coastguard Worker     {}
20*f6dc9357SAndroid Build Coastguard Worker 
ReadBits(unsigned numBits)21*f6dc9357SAndroid Build Coastguard Worker UInt32 CCoder::ReadBits(unsigned numBits)
22*f6dc9357SAndroid Build Coastguard Worker {
23*f6dc9357SAndroid Build Coastguard Worker   return m_InBitStream.ReadBits(numBits);
24*f6dc9357SAndroid Build Coastguard Worker }
25*f6dc9357SAndroid Build Coastguard Worker 
ReadAlignedByte()26*f6dc9357SAndroid Build Coastguard Worker Byte CCoder::ReadAlignedByte()
27*f6dc9357SAndroid Build Coastguard Worker {
28*f6dc9357SAndroid Build Coastguard Worker   return m_InBitStream.ReadAlignedByte();
29*f6dc9357SAndroid Build Coastguard Worker }
30*f6dc9357SAndroid Build Coastguard Worker 
DecodeLevels(Byte * levels,unsigned numSymbols)31*f6dc9357SAndroid Build Coastguard Worker bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
32*f6dc9357SAndroid Build Coastguard Worker {
33*f6dc9357SAndroid Build Coastguard Worker   unsigned i = 0;
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker   do
36*f6dc9357SAndroid Build Coastguard Worker   {
37*f6dc9357SAndroid Build Coastguard Worker     unsigned sym = m_LevelDecoder.Decode(&m_InBitStream);
38*f6dc9357SAndroid Build Coastguard Worker     if (sym < kTableDirectLevels)
39*f6dc9357SAndroid Build Coastguard Worker       levels[i++] = (Byte)sym;
40*f6dc9357SAndroid Build Coastguard Worker     else
41*f6dc9357SAndroid Build Coastguard Worker     {
42*f6dc9357SAndroid Build Coastguard Worker       if (sym >= kLevelTableSize)
43*f6dc9357SAndroid Build Coastguard Worker         return false;
44*f6dc9357SAndroid Build Coastguard Worker 
45*f6dc9357SAndroid Build Coastguard Worker       unsigned num;
46*f6dc9357SAndroid Build Coastguard Worker       unsigned numBits;
47*f6dc9357SAndroid Build Coastguard Worker       Byte symbol;
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker       if (sym == kTableLevelRepNumber)
50*f6dc9357SAndroid Build Coastguard Worker       {
51*f6dc9357SAndroid Build Coastguard Worker         if (i == 0)
52*f6dc9357SAndroid Build Coastguard Worker           return false;
53*f6dc9357SAndroid Build Coastguard Worker         numBits = 2;
54*f6dc9357SAndroid Build Coastguard Worker         num = 0;
55*f6dc9357SAndroid Build Coastguard Worker         symbol = levels[(size_t)i - 1];
56*f6dc9357SAndroid Build Coastguard Worker       }
57*f6dc9357SAndroid Build Coastguard Worker       else
58*f6dc9357SAndroid Build Coastguard Worker       {
59*f6dc9357SAndroid Build Coastguard Worker         sym -= kTableLevel0Number;
60*f6dc9357SAndroid Build Coastguard Worker         sym <<= 2;
61*f6dc9357SAndroid Build Coastguard Worker         numBits = 3 + (unsigned)sym;
62*f6dc9357SAndroid Build Coastguard Worker         num = ((unsigned)sym << 1);
63*f6dc9357SAndroid Build Coastguard Worker         symbol = 0;
64*f6dc9357SAndroid Build Coastguard Worker       }
65*f6dc9357SAndroid Build Coastguard Worker 
66*f6dc9357SAndroid Build Coastguard Worker       num += i + 3 + ReadBits(numBits);
67*f6dc9357SAndroid Build Coastguard Worker       if (num > numSymbols)
68*f6dc9357SAndroid Build Coastguard Worker         return false;
69*f6dc9357SAndroid Build Coastguard Worker       do
70*f6dc9357SAndroid Build Coastguard Worker         levels[i++] = symbol;
71*f6dc9357SAndroid Build Coastguard Worker       while (i < num);
72*f6dc9357SAndroid Build Coastguard Worker     }
73*f6dc9357SAndroid Build Coastguard Worker   }
74*f6dc9357SAndroid Build Coastguard Worker   while (i < numSymbols);
75*f6dc9357SAndroid Build Coastguard Worker 
76*f6dc9357SAndroid Build Coastguard Worker   return true;
77*f6dc9357SAndroid Build Coastguard Worker }
78*f6dc9357SAndroid Build Coastguard Worker 
79*f6dc9357SAndroid Build Coastguard Worker #define RIF(x) { if (!(x)) return false; }
80*f6dc9357SAndroid Build Coastguard Worker 
ReadTables(void)81*f6dc9357SAndroid Build Coastguard Worker bool CCoder::ReadTables(void)
82*f6dc9357SAndroid Build Coastguard Worker {
83*f6dc9357SAndroid Build Coastguard Worker   m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
84*f6dc9357SAndroid Build Coastguard Worker   if (m_InBitStream.ExtraBitsWereRead())
85*f6dc9357SAndroid Build Coastguard Worker     return false;
86*f6dc9357SAndroid Build Coastguard Worker   const UInt32 blockType = ReadBits(kBlockTypeFieldSize);
87*f6dc9357SAndroid Build Coastguard Worker   if (blockType > NBlockType::kDynamicHuffman)
88*f6dc9357SAndroid Build Coastguard Worker     return false;
89*f6dc9357SAndroid Build Coastguard Worker   if (m_InBitStream.ExtraBitsWereRead())
90*f6dc9357SAndroid Build Coastguard Worker     return false;
91*f6dc9357SAndroid Build Coastguard Worker 
92*f6dc9357SAndroid Build Coastguard Worker   if (blockType == NBlockType::kStored)
93*f6dc9357SAndroid Build Coastguard Worker   {
94*f6dc9357SAndroid Build Coastguard Worker     m_StoredMode = true;
95*f6dc9357SAndroid Build Coastguard Worker     m_InBitStream.AlignToByte();
96*f6dc9357SAndroid Build Coastguard Worker     m_StoredBlockSize = ReadAligned_UInt16(); // ReadBits(kStoredBlockLengthFieldSize)
97*f6dc9357SAndroid Build Coastguard Worker     if (_deflateNSIS)
98*f6dc9357SAndroid Build Coastguard Worker       return true;
99*f6dc9357SAndroid Build Coastguard Worker     return (m_StoredBlockSize == (UInt16)~ReadAligned_UInt16());
100*f6dc9357SAndroid Build Coastguard Worker   }
101*f6dc9357SAndroid Build Coastguard Worker 
102*f6dc9357SAndroid Build Coastguard Worker   m_StoredMode = false;
103*f6dc9357SAndroid Build Coastguard Worker 
104*f6dc9357SAndroid Build Coastguard Worker   CLevels levels;
105*f6dc9357SAndroid Build Coastguard Worker   if (blockType == NBlockType::kFixedHuffman)
106*f6dc9357SAndroid Build Coastguard Worker   {
107*f6dc9357SAndroid Build Coastguard Worker     levels.SetFixedLevels();
108*f6dc9357SAndroid Build Coastguard Worker     _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
109*f6dc9357SAndroid Build Coastguard Worker   }
110*f6dc9357SAndroid Build Coastguard Worker   else
111*f6dc9357SAndroid Build Coastguard Worker   {
112*f6dc9357SAndroid Build Coastguard Worker     const unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
113*f6dc9357SAndroid Build Coastguard Worker     _numDistLevels = (unsigned)ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
114*f6dc9357SAndroid Build Coastguard Worker     const unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
115*f6dc9357SAndroid Build Coastguard Worker 
116*f6dc9357SAndroid Build Coastguard Worker     if (!_deflate64Mode)
117*f6dc9357SAndroid Build Coastguard Worker       if (_numDistLevels > kDistTableSize32)
118*f6dc9357SAndroid Build Coastguard Worker         return false;
119*f6dc9357SAndroid Build Coastguard Worker 
120*f6dc9357SAndroid Build Coastguard Worker     Byte levelLevels[kLevelTableSize];
121*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < kLevelTableSize; i++)
122*f6dc9357SAndroid Build Coastguard Worker     {
123*f6dc9357SAndroid Build Coastguard Worker       const unsigned position = kCodeLengthAlphabetOrder[i];
124*f6dc9357SAndroid Build Coastguard Worker       if (i < numLevelCodes)
125*f6dc9357SAndroid Build Coastguard Worker         levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
126*f6dc9357SAndroid Build Coastguard Worker       else
127*f6dc9357SAndroid Build Coastguard Worker         levelLevels[position] = 0;
128*f6dc9357SAndroid Build Coastguard Worker     }
129*f6dc9357SAndroid Build Coastguard Worker 
130*f6dc9357SAndroid Build Coastguard Worker     if (m_InBitStream.ExtraBitsWereRead())
131*f6dc9357SAndroid Build Coastguard Worker       return false;
132*f6dc9357SAndroid Build Coastguard Worker 
133*f6dc9357SAndroid Build Coastguard Worker     RIF(m_LevelDecoder.Build(levelLevels, false)) // full
134*f6dc9357SAndroid Build Coastguard Worker 
135*f6dc9357SAndroid Build Coastguard Worker     Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
136*f6dc9357SAndroid Build Coastguard Worker     if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels))
137*f6dc9357SAndroid Build Coastguard Worker       return false;
138*f6dc9357SAndroid Build Coastguard Worker 
139*f6dc9357SAndroid Build Coastguard Worker     if (m_InBitStream.ExtraBitsWereRead())
140*f6dc9357SAndroid Build Coastguard Worker       return false;
141*f6dc9357SAndroid Build Coastguard Worker 
142*f6dc9357SAndroid Build Coastguard Worker     levels.SubClear();
143*f6dc9357SAndroid Build Coastguard Worker     memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
144*f6dc9357SAndroid Build Coastguard Worker     memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
145*f6dc9357SAndroid Build Coastguard Worker   }
146*f6dc9357SAndroid Build Coastguard Worker   RIF(m_MainDecoder.Build(levels.litLenLevels))
147*f6dc9357SAndroid Build Coastguard Worker   return m_DistDecoder.Build(levels.distLevels);
148*f6dc9357SAndroid Build Coastguard Worker }
149*f6dc9357SAndroid Build Coastguard Worker 
150*f6dc9357SAndroid Build Coastguard Worker 
InitInStream(bool needInit)151*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::InitInStream(bool needInit)
152*f6dc9357SAndroid Build Coastguard Worker {
153*f6dc9357SAndroid Build Coastguard Worker   if (needInit)
154*f6dc9357SAndroid Build Coastguard Worker   {
155*f6dc9357SAndroid Build Coastguard Worker     // for HDD-Windows:
156*f6dc9357SAndroid Build Coastguard Worker     // (1 << 15) - best for reading only prefetch
157*f6dc9357SAndroid Build Coastguard Worker     // (1 << 22) - best for real reading / writing
158*f6dc9357SAndroid Build Coastguard Worker     if (!m_InBitStream.Create(1 << 20))
159*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
160*f6dc9357SAndroid Build Coastguard Worker     m_InBitStream.Init();
161*f6dc9357SAndroid Build Coastguard Worker     _needInitInStream = false;
162*f6dc9357SAndroid Build Coastguard Worker   }
163*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
164*f6dc9357SAndroid Build Coastguard Worker }
165*f6dc9357SAndroid Build Coastguard Worker 
166*f6dc9357SAndroid Build Coastguard Worker 
CodeSpec(UInt32 curSize,bool finishInputStream,UInt32 inputProgressLimit)167*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit)
168*f6dc9357SAndroid Build Coastguard Worker {
169*f6dc9357SAndroid Build Coastguard Worker   if (_remainLen == kLenIdFinished)
170*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
171*f6dc9357SAndroid Build Coastguard Worker 
172*f6dc9357SAndroid Build Coastguard Worker   if (_remainLen == kLenIdNeedInit)
173*f6dc9357SAndroid Build Coastguard Worker   {
174*f6dc9357SAndroid Build Coastguard Worker     if (!_keepHistory)
175*f6dc9357SAndroid Build Coastguard Worker       if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
176*f6dc9357SAndroid Build Coastguard Worker         return E_OUTOFMEMORY;
177*f6dc9357SAndroid Build Coastguard Worker     RINOK(InitInStream(_needInitInStream))
178*f6dc9357SAndroid Build Coastguard Worker     m_OutWindowStream.Init(_keepHistory);
179*f6dc9357SAndroid Build Coastguard Worker 
180*f6dc9357SAndroid Build Coastguard Worker     m_FinalBlock = false;
181*f6dc9357SAndroid Build Coastguard Worker     _remainLen = 0;
182*f6dc9357SAndroid Build Coastguard Worker     _needReadTable = true;
183*f6dc9357SAndroid Build Coastguard Worker   }
184*f6dc9357SAndroid Build Coastguard Worker 
185*f6dc9357SAndroid Build Coastguard Worker   // _remainLen >= 0
186*f6dc9357SAndroid Build Coastguard Worker   while (_remainLen && curSize)
187*f6dc9357SAndroid Build Coastguard Worker   {
188*f6dc9357SAndroid Build Coastguard Worker     _remainLen--;
189*f6dc9357SAndroid Build Coastguard Worker     const Byte b = m_OutWindowStream.GetByte(_rep0);
190*f6dc9357SAndroid Build Coastguard Worker     m_OutWindowStream.PutByte(b);
191*f6dc9357SAndroid Build Coastguard Worker     curSize--;
192*f6dc9357SAndroid Build Coastguard Worker   }
193*f6dc9357SAndroid Build Coastguard Worker 
194*f6dc9357SAndroid Build Coastguard Worker   UInt64 inputStart = 0;
195*f6dc9357SAndroid Build Coastguard Worker   if (inputProgressLimit != 0)
196*f6dc9357SAndroid Build Coastguard Worker     inputStart = m_InBitStream.GetProcessedSize();
197*f6dc9357SAndroid Build Coastguard Worker 
198*f6dc9357SAndroid Build Coastguard Worker   while (curSize || finishInputStream)
199*f6dc9357SAndroid Build Coastguard Worker   {
200*f6dc9357SAndroid Build Coastguard Worker     if (m_InBitStream.ExtraBitsWereRead())
201*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
202*f6dc9357SAndroid Build Coastguard Worker 
203*f6dc9357SAndroid Build Coastguard Worker     if (_needReadTable)
204*f6dc9357SAndroid Build Coastguard Worker     {
205*f6dc9357SAndroid Build Coastguard Worker       if (m_FinalBlock)
206*f6dc9357SAndroid Build Coastguard Worker       {
207*f6dc9357SAndroid Build Coastguard Worker         _remainLen = kLenIdFinished;
208*f6dc9357SAndroid Build Coastguard Worker         break;
209*f6dc9357SAndroid Build Coastguard Worker       }
210*f6dc9357SAndroid Build Coastguard Worker 
211*f6dc9357SAndroid Build Coastguard Worker       if (inputProgressLimit != 0)
212*f6dc9357SAndroid Build Coastguard Worker         if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit)
213*f6dc9357SAndroid Build Coastguard Worker           return S_OK;
214*f6dc9357SAndroid Build Coastguard Worker 
215*f6dc9357SAndroid Build Coastguard Worker       if (!ReadTables())
216*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
217*f6dc9357SAndroid Build Coastguard Worker       if (m_InBitStream.ExtraBitsWereRead())
218*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
219*f6dc9357SAndroid Build Coastguard Worker       _needReadTable = false;
220*f6dc9357SAndroid Build Coastguard Worker     }
221*f6dc9357SAndroid Build Coastguard Worker 
222*f6dc9357SAndroid Build Coastguard Worker     if (m_StoredMode)
223*f6dc9357SAndroid Build Coastguard Worker     {
224*f6dc9357SAndroid Build Coastguard Worker       if (finishInputStream && curSize == 0 && m_StoredBlockSize != 0)
225*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
226*f6dc9357SAndroid Build Coastguard Worker       /* NSIS version contains some bits in bitl bits buffer.
227*f6dc9357SAndroid Build Coastguard Worker          So we must read some first bytes via ReadAlignedByte */
228*f6dc9357SAndroid Build Coastguard Worker       UInt32 num = m_StoredBlockSize;
229*f6dc9357SAndroid Build Coastguard Worker       if (num > curSize)
230*f6dc9357SAndroid Build Coastguard Worker           num = curSize;
231*f6dc9357SAndroid Build Coastguard Worker       m_StoredBlockSize -= num;
232*f6dc9357SAndroid Build Coastguard Worker       curSize -= num;
233*f6dc9357SAndroid Build Coastguard Worker       for (; num && m_InBitStream.ThereAreDataInBitsBuffer(); num--)
234*f6dc9357SAndroid Build Coastguard Worker         m_OutWindowStream.PutByte(ReadAlignedByte());
235*f6dc9357SAndroid Build Coastguard Worker       if (num)
236*f6dc9357SAndroid Build Coastguard Worker       {
237*f6dc9357SAndroid Build Coastguard Worker #if 1
238*f6dc9357SAndroid Build Coastguard Worker         // fast code
239*f6dc9357SAndroid Build Coastguard Worker         do
240*f6dc9357SAndroid Build Coastguard Worker         {
241*f6dc9357SAndroid Build Coastguard Worker           size_t a;
242*f6dc9357SAndroid Build Coastguard Worker           Byte *buf = m_OutWindowStream.GetOutBuffer(a);
243*f6dc9357SAndroid Build Coastguard Worker           // a != 0
244*f6dc9357SAndroid Build Coastguard Worker           if (a > num)
245*f6dc9357SAndroid Build Coastguard Worker               a = num;
246*f6dc9357SAndroid Build Coastguard Worker           // a != 0
247*f6dc9357SAndroid Build Coastguard Worker           a = m_InBitStream.ReadDirectBytesPart(buf, a);
248*f6dc9357SAndroid Build Coastguard Worker           if (a == 0)
249*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
250*f6dc9357SAndroid Build Coastguard Worker           m_OutWindowStream.SkipWrittenBytes(a);
251*f6dc9357SAndroid Build Coastguard Worker           num -= (UInt32)a;
252*f6dc9357SAndroid Build Coastguard Worker         }
253*f6dc9357SAndroid Build Coastguard Worker         while (num);
254*f6dc9357SAndroid Build Coastguard Worker #else
255*f6dc9357SAndroid Build Coastguard Worker         // slow code:
256*f6dc9357SAndroid Build Coastguard Worker         do
257*f6dc9357SAndroid Build Coastguard Worker           m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte());
258*f6dc9357SAndroid Build Coastguard Worker         while (--num);
259*f6dc9357SAndroid Build Coastguard Worker #endif
260*f6dc9357SAndroid Build Coastguard Worker       }
261*f6dc9357SAndroid Build Coastguard Worker       _needReadTable = (m_StoredBlockSize == 0);
262*f6dc9357SAndroid Build Coastguard Worker       continue;
263*f6dc9357SAndroid Build Coastguard Worker     }
264*f6dc9357SAndroid Build Coastguard Worker 
265*f6dc9357SAndroid Build Coastguard Worker     while (curSize)
266*f6dc9357SAndroid Build Coastguard Worker     {
267*f6dc9357SAndroid Build Coastguard Worker       if (m_InBitStream.ExtraBitsWereRead_Fast())
268*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
269*f6dc9357SAndroid Build Coastguard Worker       unsigned sym;
270*f6dc9357SAndroid Build Coastguard Worker #if 0
271*f6dc9357SAndroid Build Coastguard Worker       sym = m_MainDecoder.Decode(&m_InBitStream);
272*f6dc9357SAndroid Build Coastguard Worker #else
273*f6dc9357SAndroid Build Coastguard Worker       Z7_HUFF_DECODE_CHECK(sym, &m_MainDecoder, kNumHuffmanBits, kNumTableBits_Main, &m_InBitStream, { return S_FALSE; })
274*f6dc9357SAndroid Build Coastguard Worker #endif
275*f6dc9357SAndroid Build Coastguard Worker 
276*f6dc9357SAndroid Build Coastguard Worker       if (sym < 0x100)
277*f6dc9357SAndroid Build Coastguard Worker       {
278*f6dc9357SAndroid Build Coastguard Worker         m_OutWindowStream.PutByte((Byte)sym);
279*f6dc9357SAndroid Build Coastguard Worker         curSize--;
280*f6dc9357SAndroid Build Coastguard Worker         continue;
281*f6dc9357SAndroid Build Coastguard Worker       }
282*f6dc9357SAndroid Build Coastguard Worker       if (sym == kSymbolEndOfBlock)
283*f6dc9357SAndroid Build Coastguard Worker       {
284*f6dc9357SAndroid Build Coastguard Worker         _needReadTable = true;
285*f6dc9357SAndroid Build Coastguard Worker         break;
286*f6dc9357SAndroid Build Coastguard Worker       }
287*f6dc9357SAndroid Build Coastguard Worker #if 0
288*f6dc9357SAndroid Build Coastguard Worker       if (sym >= kMainTableSize)
289*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
290*f6dc9357SAndroid Build Coastguard Worker #endif
291*f6dc9357SAndroid Build Coastguard Worker       {
292*f6dc9357SAndroid Build Coastguard Worker         sym -= kSymbolMatch;
293*f6dc9357SAndroid Build Coastguard Worker         UInt32 len;
294*f6dc9357SAndroid Build Coastguard Worker         {
295*f6dc9357SAndroid Build Coastguard Worker           unsigned numBits;
296*f6dc9357SAndroid Build Coastguard Worker           if (_deflate64Mode)
297*f6dc9357SAndroid Build Coastguard Worker           {
298*f6dc9357SAndroid Build Coastguard Worker             len = kLenStart64[sym];
299*f6dc9357SAndroid Build Coastguard Worker             numBits = kLenDirectBits64[sym];
300*f6dc9357SAndroid Build Coastguard Worker           }
301*f6dc9357SAndroid Build Coastguard Worker           else
302*f6dc9357SAndroid Build Coastguard Worker           {
303*f6dc9357SAndroid Build Coastguard Worker             len = kLenStart32[sym];
304*f6dc9357SAndroid Build Coastguard Worker             numBits = kLenDirectBits32[sym];
305*f6dc9357SAndroid Build Coastguard Worker           }
306*f6dc9357SAndroid Build Coastguard Worker           len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
307*f6dc9357SAndroid Build Coastguard Worker         }
308*f6dc9357SAndroid Build Coastguard Worker 
309*f6dc9357SAndroid Build Coastguard Worker #if 0
310*f6dc9357SAndroid Build Coastguard Worker         sym = m_DistDecoder.Decode(&m_InBitStream);
311*f6dc9357SAndroid Build Coastguard Worker         if (sym >= _numDistLevels)
312*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
313*f6dc9357SAndroid Build Coastguard Worker #else
314*f6dc9357SAndroid Build Coastguard Worker         Z7_HUFF_DECODE_CHECK(sym, &m_DistDecoder, kNumHuffmanBits, kNumTableBits_Dist, &m_InBitStream, { return S_FALSE; })
315*f6dc9357SAndroid Build Coastguard Worker #endif
316*f6dc9357SAndroid Build Coastguard Worker 
317*f6dc9357SAndroid Build Coastguard Worker #if 1
318*f6dc9357SAndroid Build Coastguard Worker         sym = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
319*f6dc9357SAndroid Build Coastguard Worker #else
320*f6dc9357SAndroid Build Coastguard Worker         if (sym >= 4)
321*f6dc9357SAndroid Build Coastguard Worker         {
322*f6dc9357SAndroid Build Coastguard Worker           // sym &= 31;
323*f6dc9357SAndroid Build Coastguard Worker           const unsigned numDirectBits = (sym - 2) >> 1;
324*f6dc9357SAndroid Build Coastguard Worker           sym = (2u | (sym & 1)) << numDirectBits;
325*f6dc9357SAndroid Build Coastguard Worker           sym += m_InBitStream.ReadBits(numDirectBits);
326*f6dc9357SAndroid Build Coastguard Worker         }
327*f6dc9357SAndroid Build Coastguard Worker #endif
328*f6dc9357SAndroid Build Coastguard Worker         UInt32 locLen = len;
329*f6dc9357SAndroid Build Coastguard Worker         if (locLen > curSize)
330*f6dc9357SAndroid Build Coastguard Worker           locLen = (UInt32)curSize;
331*f6dc9357SAndroid Build Coastguard Worker         if (!m_OutWindowStream.CopyBlock(sym, locLen))
332*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
333*f6dc9357SAndroid Build Coastguard Worker         curSize -= locLen;
334*f6dc9357SAndroid Build Coastguard Worker         len -= locLen;
335*f6dc9357SAndroid Build Coastguard Worker         if (len != 0)
336*f6dc9357SAndroid Build Coastguard Worker         {
337*f6dc9357SAndroid Build Coastguard Worker           _remainLen = (Int32)len;
338*f6dc9357SAndroid Build Coastguard Worker           _rep0 = sym;
339*f6dc9357SAndroid Build Coastguard Worker           break;
340*f6dc9357SAndroid Build Coastguard Worker         }
341*f6dc9357SAndroid Build Coastguard Worker       }
342*f6dc9357SAndroid Build Coastguard Worker     }
343*f6dc9357SAndroid Build Coastguard Worker 
344*f6dc9357SAndroid Build Coastguard Worker     if (finishInputStream && curSize == 0)
345*f6dc9357SAndroid Build Coastguard Worker     {
346*f6dc9357SAndroid Build Coastguard Worker       if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock)
347*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
348*f6dc9357SAndroid Build Coastguard Worker       _needReadTable = true;
349*f6dc9357SAndroid Build Coastguard Worker     }
350*f6dc9357SAndroid Build Coastguard Worker   }
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker   if (m_InBitStream.ExtraBitsWereRead())
353*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
354*f6dc9357SAndroid Build Coastguard Worker 
355*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
356*f6dc9357SAndroid Build Coastguard Worker }
357*f6dc9357SAndroid Build Coastguard Worker 
358*f6dc9357SAndroid Build Coastguard Worker 
359*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_NO_EXCEPTIONS
360*f6dc9357SAndroid Build Coastguard Worker 
361*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_BEGIN
362*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_END(res)
363*f6dc9357SAndroid Build Coastguard Worker 
364*f6dc9357SAndroid Build Coastguard Worker #else
365*f6dc9357SAndroid Build Coastguard Worker 
366*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_BEGIN try {
367*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_END(res) } \
368*f6dc9357SAndroid Build Coastguard Worker   catch(const CSystemException &e) { res = e.ErrorCode; } \
369*f6dc9357SAndroid Build Coastguard Worker   catch(...) { res = S_FALSE; }
370*f6dc9357SAndroid Build Coastguard Worker 
371*f6dc9357SAndroid Build Coastguard Worker   // catch(const CInBufferException &e)  { res = e.ErrorCode; }
372*f6dc9357SAndroid Build Coastguard Worker   // catch(const CLzOutWindowException &e)  { res = e.ErrorCode; }
373*f6dc9357SAndroid Build Coastguard Worker 
374*f6dc9357SAndroid Build Coastguard Worker #endif
375*f6dc9357SAndroid Build Coastguard Worker 
376*f6dc9357SAndroid Build Coastguard Worker 
CodeReal(ISequentialOutStream * outStream,ICompressProgressInfo * progress)377*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress)
378*f6dc9357SAndroid Build Coastguard Worker {
379*f6dc9357SAndroid Build Coastguard Worker   HRESULT res;
380*f6dc9357SAndroid Build Coastguard Worker 
381*f6dc9357SAndroid Build Coastguard Worker   DEFLATE_TRY_BEGIN
382*f6dc9357SAndroid Build Coastguard Worker 
383*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.SetStream(outStream);
384*f6dc9357SAndroid Build Coastguard Worker   CCoderReleaser flusher(this);
385*f6dc9357SAndroid Build Coastguard Worker 
386*f6dc9357SAndroid Build Coastguard Worker   const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
387*f6dc9357SAndroid Build Coastguard Worker 
388*f6dc9357SAndroid Build Coastguard Worker   for (;;)
389*f6dc9357SAndroid Build Coastguard Worker   {
390*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kInputProgressLimit = 1 << 21;
391*f6dc9357SAndroid Build Coastguard Worker     UInt32 curSize = 1 << 20;
392*f6dc9357SAndroid Build Coastguard Worker     bool finishInputStream = false;
393*f6dc9357SAndroid Build Coastguard Worker     if (_outSizeDefined)
394*f6dc9357SAndroid Build Coastguard Worker     {
395*f6dc9357SAndroid Build Coastguard Worker       const UInt64 rem = _outSize - GetOutProcessedCur();
396*f6dc9357SAndroid Build Coastguard Worker       if (curSize >= rem)
397*f6dc9357SAndroid Build Coastguard Worker       {
398*f6dc9357SAndroid Build Coastguard Worker         curSize = (UInt32)rem;
399*f6dc9357SAndroid Build Coastguard Worker         if (_needFinishInput)
400*f6dc9357SAndroid Build Coastguard Worker           finishInputStream = true;
401*f6dc9357SAndroid Build Coastguard Worker         else if (curSize == 0)
402*f6dc9357SAndroid Build Coastguard Worker           break;
403*f6dc9357SAndroid Build Coastguard Worker       }
404*f6dc9357SAndroid Build Coastguard Worker     }
405*f6dc9357SAndroid Build Coastguard Worker 
406*f6dc9357SAndroid Build Coastguard Worker     RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0))
407*f6dc9357SAndroid Build Coastguard Worker 
408*f6dc9357SAndroid Build Coastguard Worker     if (_remainLen == kLenIdFinished)
409*f6dc9357SAndroid Build Coastguard Worker       break;
410*f6dc9357SAndroid Build Coastguard Worker 
411*f6dc9357SAndroid Build Coastguard Worker     if (progress)
412*f6dc9357SAndroid Build Coastguard Worker     {
413*f6dc9357SAndroid Build Coastguard Worker       const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
414*f6dc9357SAndroid Build Coastguard Worker       const UInt64 nowPos64 = GetOutProcessedCur();
415*f6dc9357SAndroid Build Coastguard Worker       RINOK(progress->SetRatioInfo(&inSize, &nowPos64))
416*f6dc9357SAndroid Build Coastguard Worker     }
417*f6dc9357SAndroid Build Coastguard Worker   }
418*f6dc9357SAndroid Build Coastguard Worker 
419*f6dc9357SAndroid Build Coastguard Worker   flusher.NeedFlush = false;
420*f6dc9357SAndroid Build Coastguard Worker   res = Flush();
421*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
422*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
423*f6dc9357SAndroid Build Coastguard Worker 
424*f6dc9357SAndroid Build Coastguard Worker   DEFLATE_TRY_END(res)
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker   return res;
427*f6dc9357SAndroid Build Coastguard Worker }
428*f6dc9357SAndroid Build Coastguard Worker 
429*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress))430*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
431*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
432*f6dc9357SAndroid Build Coastguard Worker {
433*f6dc9357SAndroid Build Coastguard Worker   SetInStream(inStream);
434*f6dc9357SAndroid Build Coastguard Worker   SetOutStreamSize(outSize);
435*f6dc9357SAndroid Build Coastguard Worker   const HRESULT res = CodeReal(outStream, progress);
436*f6dc9357SAndroid Build Coastguard Worker   ReleaseInStream();
437*f6dc9357SAndroid Build Coastguard Worker   /*
438*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK)
439*f6dc9357SAndroid Build Coastguard Worker     if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize())
440*f6dc9357SAndroid Build Coastguard Worker       res = S_FALSE;
441*f6dc9357SAndroid Build Coastguard Worker   */
442*f6dc9357SAndroid Build Coastguard Worker   return res;
443*f6dc9357SAndroid Build Coastguard Worker }
444*f6dc9357SAndroid Build Coastguard Worker 
445*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::SetFinishMode (UInt32 finishMode))446*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode))
447*f6dc9357SAndroid Build Coastguard Worker {
448*f6dc9357SAndroid Build Coastguard Worker   Set_NeedFinishInput(finishMode != 0);
449*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
450*f6dc9357SAndroid Build Coastguard Worker }
451*f6dc9357SAndroid Build Coastguard Worker 
452*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize (UInt64 * value))453*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value))
454*f6dc9357SAndroid Build Coastguard Worker {
455*f6dc9357SAndroid Build Coastguard Worker   *value = m_InBitStream.GetStreamSize();
456*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
457*f6dc9357SAndroid Build Coastguard Worker }
458*f6dc9357SAndroid Build Coastguard Worker 
459*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf (void * data,UInt32 size,UInt32 * processedSize))460*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize))
461*f6dc9357SAndroid Build Coastguard Worker {
462*f6dc9357SAndroid Build Coastguard Worker   AlignToByte();
463*f6dc9357SAndroid Build Coastguard Worker   UInt32 i = 0;
464*f6dc9357SAndroid Build Coastguard Worker   {
465*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < size; i++)
466*f6dc9357SAndroid Build Coastguard Worker     {
467*f6dc9357SAndroid Build Coastguard Worker       if (!m_InBitStream.ReadAlignedByte_FromBuf(((Byte *)data)[i]))
468*f6dc9357SAndroid Build Coastguard Worker         break;
469*f6dc9357SAndroid Build Coastguard Worker     }
470*f6dc9357SAndroid Build Coastguard Worker   }
471*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
472*f6dc9357SAndroid Build Coastguard Worker     *processedSize = i;
473*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
474*f6dc9357SAndroid Build Coastguard Worker }
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::SetInStream (ISequentialInStream * inStream))477*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetInStream(ISequentialInStream *inStream))
478*f6dc9357SAndroid Build Coastguard Worker {
479*f6dc9357SAndroid Build Coastguard Worker   m_InStreamRef = inStream;
480*f6dc9357SAndroid Build Coastguard Worker   m_InBitStream.SetStream(inStream);
481*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
482*f6dc9357SAndroid Build Coastguard Worker }
483*f6dc9357SAndroid Build Coastguard Worker 
484*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::ReleaseInStream ())485*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::ReleaseInStream())
486*f6dc9357SAndroid Build Coastguard Worker {
487*f6dc9357SAndroid Build Coastguard Worker   m_InStreamRef.Release();
488*f6dc9357SAndroid Build Coastguard Worker   m_InBitStream.ClearStreamPtr();
489*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
490*f6dc9357SAndroid Build Coastguard Worker }
491*f6dc9357SAndroid Build Coastguard Worker 
492*f6dc9357SAndroid Build Coastguard Worker 
SetOutStreamSizeResume(const UInt64 * outSize)493*f6dc9357SAndroid Build Coastguard Worker void CCoder::SetOutStreamSizeResume(const UInt64 *outSize)
494*f6dc9357SAndroid Build Coastguard Worker {
495*f6dc9357SAndroid Build Coastguard Worker   _outSizeDefined = (outSize != NULL);
496*f6dc9357SAndroid Build Coastguard Worker   _outSize = 0;
497*f6dc9357SAndroid Build Coastguard Worker   if (_outSizeDefined)
498*f6dc9357SAndroid Build Coastguard Worker     _outSize = *outSize;
499*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.Init(_keepHistory);
500*f6dc9357SAndroid Build Coastguard Worker   _outStartPos = m_OutWindowStream.GetProcessedSize();
501*f6dc9357SAndroid Build Coastguard Worker   _remainLen = kLenIdNeedInit;
502*f6dc9357SAndroid Build Coastguard Worker }
503*f6dc9357SAndroid Build Coastguard Worker 
504*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::SetOutStreamSize (const UInt64 * outSize))505*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetOutStreamSize(const UInt64 *outSize))
506*f6dc9357SAndroid Build Coastguard Worker {
507*f6dc9357SAndroid Build Coastguard Worker   /*
508*f6dc9357SAndroid Build Coastguard Worker     18.06:
509*f6dc9357SAndroid Build Coastguard Worker     We want to support GetInputProcessedSize() before CCoder::Read()
510*f6dc9357SAndroid Build Coastguard Worker     So we call m_InBitStream.Init() even before buffer allocations
511*f6dc9357SAndroid Build Coastguard Worker     m_InBitStream.Init() just sets variables to default values
512*f6dc9357SAndroid Build Coastguard Worker     But later we will call m_InBitStream.Init() again with real buffer pointers
513*f6dc9357SAndroid Build Coastguard Worker   */
514*f6dc9357SAndroid Build Coastguard Worker   m_InBitStream.Init();
515*f6dc9357SAndroid Build Coastguard Worker   _needInitInStream = true;
516*f6dc9357SAndroid Build Coastguard Worker   SetOutStreamSizeResume(outSize);
517*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
518*f6dc9357SAndroid Build Coastguard Worker }
519*f6dc9357SAndroid Build Coastguard Worker 
520*f6dc9357SAndroid Build Coastguard Worker 
521*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_NO_READ_FROM_CODER
522*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CCoder::Read (void * data,UInt32 size,UInt32 * processedSize))523*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::Read(void *data, UInt32 size, UInt32 *processedSize))
524*f6dc9357SAndroid Build Coastguard Worker {
525*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
526*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
527*f6dc9357SAndroid Build Coastguard Worker   const UInt64 outPos = GetOutProcessedCur();
528*f6dc9357SAndroid Build Coastguard Worker 
529*f6dc9357SAndroid Build Coastguard Worker   bool finishInputStream = false;
530*f6dc9357SAndroid Build Coastguard Worker   if (_outSizeDefined)
531*f6dc9357SAndroid Build Coastguard Worker   {
532*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = _outSize - outPos;
533*f6dc9357SAndroid Build Coastguard Worker     if (size >= rem)
534*f6dc9357SAndroid Build Coastguard Worker     {
535*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
536*f6dc9357SAndroid Build Coastguard Worker       if (_needFinishInput)
537*f6dc9357SAndroid Build Coastguard Worker         finishInputStream = true;
538*f6dc9357SAndroid Build Coastguard Worker     }
539*f6dc9357SAndroid Build Coastguard Worker   }
540*f6dc9357SAndroid Build Coastguard Worker   if (!finishInputStream && size == 0)
541*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
542*f6dc9357SAndroid Build Coastguard Worker 
543*f6dc9357SAndroid Build Coastguard Worker   HRESULT res;
544*f6dc9357SAndroid Build Coastguard Worker   DEFLATE_TRY_BEGIN
545*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.SetMemStream((Byte *)data);
546*f6dc9357SAndroid Build Coastguard Worker   res = CodeSpec(size, finishInputStream);
547*f6dc9357SAndroid Build Coastguard Worker   DEFLATE_TRY_END(res)
548*f6dc9357SAndroid Build Coastguard Worker   {
549*f6dc9357SAndroid Build Coastguard Worker     const HRESULT res2 = Flush();
550*f6dc9357SAndroid Build Coastguard Worker     if (res2 != S_OK)
551*f6dc9357SAndroid Build Coastguard Worker       res = res2;
552*f6dc9357SAndroid Build Coastguard Worker   }
553*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
554*f6dc9357SAndroid Build Coastguard Worker     *processedSize = (UInt32)(GetOutProcessedCur() - outPos);
555*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.SetMemStream(NULL);
556*f6dc9357SAndroid Build Coastguard Worker   return res;
557*f6dc9357SAndroid Build Coastguard Worker }
558*f6dc9357SAndroid Build Coastguard Worker 
559*f6dc9357SAndroid Build Coastguard Worker #endif
560*f6dc9357SAndroid Build Coastguard Worker 
561*f6dc9357SAndroid Build Coastguard Worker 
CodeResume(ISequentialOutStream * outStream,const UInt64 * outSize,ICompressProgressInfo * progress)562*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
563*f6dc9357SAndroid Build Coastguard Worker {
564*f6dc9357SAndroid Build Coastguard Worker   SetOutStreamSizeResume(outSize);
565*f6dc9357SAndroid Build Coastguard Worker   return CodeReal(outStream, progress);
566*f6dc9357SAndroid Build Coastguard Worker }
567*f6dc9357SAndroid Build Coastguard Worker 
568*f6dc9357SAndroid Build Coastguard Worker }}}
569