1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "contrib/brotli/utils/utils_brotli_dec.h"
16
17 #include <fstream>
18 #include <string>
19
20 #include "contrib/brotli/sandboxed.h"
21 #include "contrib/brotli/utils/utils_brotli.h"
22
InitStructs()23 absl::Status BrotliDecoder::InitStructs() {
24 SAPI_ASSIGN_OR_RETURN(
25 BrotliDecoderState * state,
26 api_.BrotliDecoderCreateInstance(&null_ptr_, &null_ptr_, &null_ptr_));
27
28 state_.SetRemote(state);
29
30 return absl::OkStatus();
31 }
32
~BrotliDecoder()33 BrotliDecoder::~BrotliDecoder() {
34 if (state_.GetRemote() != nullptr) {
35 api_.BrotliDecoderDestroyInstance(state_.PtrNone()).IgnoreError();
36 }
37 }
38
IsInit()39 bool BrotliDecoder::IsInit() {
40 if (state_.GetRemote() == nullptr) {
41 return false;
42 }
43
44 return true;
45 }
46
CheckIsInit()47 absl::Status BrotliDecoder::CheckIsInit() {
48 if (!IsInit()) {
49 return absl::UnavailableError("The decoder is not initialized");
50 }
51
52 return absl::OkStatus();
53 }
54
SetParameter(enum BrotliDecoderParameter param,uint32_t value)55 absl::Status BrotliDecoder::SetParameter(enum BrotliDecoderParameter param,
56 uint32_t value) {
57 SAPI_RETURN_IF_ERROR(CheckIsInit());
58
59 SAPI_ASSIGN_OR_RETURN(
60 int ret, api_.BrotliDecoderSetParameter(state_.PtrNone(), param, value));
61 if (!ret) {
62 return absl::UnavailableError("Unable to set parameter");
63 }
64
65 return absl::OkStatus();
66 }
67
Decompress(std::vector<uint8_t> & buf_in)68 absl::StatusOr<BrotliDecoderResult> BrotliDecoder::Decompress(
69 std::vector<uint8_t>& buf_in) {
70 SAPI_RETURN_IF_ERROR(CheckIsInit());
71
72 sapi::v::Array<uint8_t> sapi_buf_in(buf_in.data(), buf_in.size());
73 sapi::v::IntBase<size_t> sapi_size_in(buf_in.size());
74
75 // BrotliDecoderCompress requires a pointer to a pointer,
76 // as function moves to pointer to indicate how much data
77 // was compressed.
78 // In this case we compress whole buffer so we don't use it
79 // but we still have to allocate buffer remotely and gets
80 // a pointer.
81 SAPI_RETURN_IF_ERROR(sandbox_->Allocate(&sapi_buf_in));
82 SAPI_RETURN_IF_ERROR(sandbox_->TransferToSandboxee(&sapi_buf_in));
83 sapi::v::GenericPtr sapi_opaque_buf_in(sapi_buf_in.GetRemote());
84
85 sapi::v::IntBase<size_t> sapi_avilable_out(0);
86
87 SAPI_ASSIGN_OR_RETURN(
88 BrotliDecoderResult ret,
89 api_.BrotliDecoderDecompressStream(
90 state_.PtrNone(), sapi_size_in.PtrBefore(),
91 sapi_opaque_buf_in.PtrBefore(), sapi_avilable_out.PtrBefore(),
92 &null_ptr_, &null_ptr_));
93
94 // Ignore output error, as we didn't provide any buffer.
95 if (ret == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
96 ret = BROTLI_DECODER_RESULT_SUCCESS;
97 }
98
99 return ret;
100 }
101
TakeOutput()102 absl::StatusOr<std::vector<uint8_t>> BrotliDecoder::TakeOutput() {
103 SAPI_RETURN_IF_ERROR(CheckIsInit());
104
105 sapi::v::IntBase<size_t> sapi_size_out(0);
106
107 SAPI_ASSIGN_OR_RETURN(
108 uint8_t * sapi_out_buf_ptr,
109 api_.BrotliDecoderTakeOutput(state_.PtrNone(), sapi_size_out.PtrAfter()));
110 if (sapi_out_buf_ptr == nullptr || sapi_size_out.GetValue() == 0) {
111 return std::vector<uint8_t>(0);
112 }
113 if (sapi_size_out.GetValue() > kFileMaxSize) {
114 return absl::UnavailableError("Output to large");
115 }
116
117 std::vector<uint8_t> buf_out(sapi_size_out.GetValue());
118 sapi::v::Array<uint8_t> sapi_buf_out(buf_out.data(), buf_out.size());
119 sapi_buf_out.SetRemote(sapi_out_buf_ptr);
120
121 SAPI_RETURN_IF_ERROR(sandbox_->TransferFromSandboxee(&sapi_buf_out));
122
123 return buf_out;
124 }
125