Welcome to mirror list, hosted at ThFree Co, Russian Federation.

BZip2Decoder.cpp « BZip2Original « Compress « 7zip - github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5fb77d01dc59700103cdf941d9e5efc8bf678d5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// BZip2Decoder.cpp

#include "StdAfx.h"

#include "BZip2Decoder.h"

#include "../../../Common/Alloc.h"
#include "Original/bzlib.h"

namespace NCompress {
namespace NBZip2 {

static const UInt32 kBufferSize = (1 << 20);

CDecoder::~CDecoder()
{
  BigFree(m_InBuffer);
}

struct CBZip2Decompressor: public bz_stream
{
  int Init(int verbosity, int small) { return BZ2_bzDecompressInit(this, verbosity, small); }
  int Decompress()  { return BZ2_bzDecompress(this); }
  int End()  { return BZ2_bzDecompressEnd(this); }
  UInt64 GetTotalIn() const { return (UInt64(total_in_hi32) << 32) +  total_in_lo32; }
  UInt64 GetTotalOut() const { return (UInt64(total_out_hi32) << 32) +  total_out_lo32; }
};

class CBZip2DecompressorReleaser
{
  CBZip2Decompressor *m_Decompressor;
public:
  CBZip2DecompressorReleaser(CBZip2Decompressor *decompressor): m_Decompressor(decompressor) {}
  void Diable() { m_Decompressor = NULL; }
  ~CBZip2DecompressorReleaser()  { if (m_Decompressor != NULL) m_Decompressor->End(); }
};

STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
{
  m_InSize = 0;
  if (m_InBuffer == 0)
  {
    m_InBuffer = (Byte *)BigAlloc(kBufferSize * 2);
    if (m_InBuffer == 0)
      return E_OUTOFMEMORY;
  }
  Byte *outBuffer = m_InBuffer + kBufferSize;

  CBZip2Decompressor bzStream;
  bzStream.bzalloc = NULL;
  bzStream.bzfree = NULL;
  bzStream.opaque = NULL;

  int result = bzStream.Init(0, 0);
  switch(result)
  {
    case BZ_OK:
      break;
    case BZ_MEM_ERROR:
      return E_OUTOFMEMORY;
    default:
      return E_FAIL;
  }
  CBZip2DecompressorReleaser releaser(&bzStream);
  bzStream.avail_in = 0;
  for (;;)
  {
    if (bzStream.avail_in == 0)
    {
      bzStream.next_in = (char *)m_InBuffer;
      UInt32 processedSize;
      RINOK(inStream->Read(m_InBuffer, kBufferSize, &processedSize));
      bzStream.avail_in = processedSize;
    }

    bzStream.next_out = (char *)outBuffer;
    bzStream.avail_out = kBufferSize;
    result = bzStream.Decompress();
    UInt32 numBytesToWrite = kBufferSize - bzStream.avail_out;
    if (numBytesToWrite > 0)
    {
      UInt32 processedSize;
      RINOK(outStream->Write(outBuffer, numBytesToWrite, &processedSize));
      if (numBytesToWrite != processedSize)
        return E_FAIL;
    }

    if (result == BZ_STREAM_END)
      break;
    switch(result)
    {
      case BZ_DATA_ERROR:
      case BZ_DATA_ERROR_MAGIC:
        return S_FALSE;
      case BZ_OK:
        break;
      case BZ_MEM_ERROR:
        return E_OUTOFMEMORY;
      default:
        return E_FAIL;
    }
    if (progress != NULL)
    {
      UInt64 totalIn = bzStream.GetTotalIn();
      UInt64 totalOut = bzStream.GetTotalOut();
      RINOK(progress->SetRatioInfo(&totalIn, &totalOut));
    }
  }
  m_InSize = bzStream.GetTotalIn();
  return S_OK;
}

STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
{
  try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
  catch(...) { return S_FALSE; }
}

STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
{
  if (value == NULL)
    return E_INVALIDARG;
  *value = m_InSize;
  return S_OK;
}

}}