bzip_source.cc
1 // Copyright 2013, Beeri 15. All rights reserved.
2 // Author: Roman Gershman (romange@gmail.com)
3 //
4 #include <bzlib.h>
5 
6 #include "base/logging.h"
7 #include "util/bzip_source.h"
8 #include "strings/strcat.h"
9 
10 namespace util {
11 using strings::ByteRange;
12 
14  bz_stream stream;
15 
16  Rep() { memset(&stream, 0, sizeof(stream)); }
17 };
18 
19 BzipSource::BzipSource(Source* sub_source)
20  : sub_stream_(sub_source), rep_(new Rep) {
21  CHECK_EQ(BZ_OK, BZ2_bzDecompressInit(&rep_->stream, 0, 1));
22 }
23 
24 BzipSource::~BzipSource() {
25  BZ2_bzDecompressEnd(&rep_->stream);
26 }
27 
28 StatusObject<size_t> BzipSource::ReadInternal(const strings::MutableByteRange& range) {
29  std::array<unsigned char, 1024> buf;
30  char* const begin = reinterpret_cast<char*>(range.begin());
31 
32  rep_->stream.next_out = begin;
33  rep_->stream.avail_out = range.size();
34  do {
35  auto res = sub_stream_->Read(strings::MutableByteRange(buf));
36  if (!res.ok())
37  return res;
38 
39  if (res.obj == 0)
40  break;
41 
42  rep_->stream.next_in = reinterpret_cast<char*>(buf.begin());
43  rep_->stream.avail_in = res.obj;
44  int res_code = BZ2_bzDecompress(&rep_->stream);
45  if (res_code != BZ_OK && res_code != BZ_STREAM_END) {
46  return Status(StatusCode::IO_ERROR, absl::StrCat("BZip error ", res_code));
47  }
48 
49  if (rep_->stream.avail_in > 0) {
50  CHECK_EQ(0, rep_->stream.avail_out);
51 
52  sub_stream_->Prepend(ByteRange(reinterpret_cast<unsigned char*>(rep_->stream.next_in),
53  rep_->stream.avail_in));
54  }
55  } while (reinterpret_cast<unsigned char*>(rep_->stream.next_out) != range.end());
56 
57  return rep_->stream.next_out - begin;
58 }
59 
60 
61 bool BzipSource::IsBzipSource(Source* source) {
62  std::array<unsigned char, 3> buf;
63  auto res = source->Read(strings::MutableByteRange(buf));
64  if (!res.ok())
65  return false;
66 
67  bool is_bzip = res.obj == 3 && (buf[0] == 'B') && (buf[1] == 'Z') && (buf[2] == 'h');
68  source->Prepend(strings::ByteRange(buf));
69 
70  return is_bzip;
71 }
72 } // namespace util