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_enc.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 BrotliEncoder::InitStructs() {
24 SAPI_ASSIGN_OR_RETURN(
25 BrotliEncoderState * state,
26 api_.BrotliEncoderCreateInstance(&null_ptr_, &null_ptr_, &null_ptr_));
27
28 state_.SetRemote(state);
29
30 return absl::OkStatus();
31 }
32
~BrotliEncoder()33 BrotliEncoder::~BrotliEncoder() {
34 if (state_.GetRemote() != nullptr) {
35 api_.BrotliEncoderDestroyInstance(state_.PtrNone()).IgnoreError();
36 }
37 }
38
IsInit()39 bool BrotliEncoder::IsInit() {
40 if (state_.GetRemote() == nullptr) {
41 return false;
42 }
43
44 return true;
45 }
46
CheckIsInit()47 absl::Status BrotliEncoder::CheckIsInit() {
48 if (!IsInit()) {
49 return absl::UnavailableError("The encoder is not initialized");
50 }
51
52 return absl::OkStatus();
53 }
54
SetParameter(enum BrotliEncoderParameter param,uint32_t value)55 absl::Status BrotliEncoder::SetParameter(enum BrotliEncoderParameter param,
56 uint32_t value) {
57 SAPI_RETURN_IF_ERROR(CheckIsInit());
58
59 SAPI_ASSIGN_OR_RETURN(
60 int ret, api_.BrotliEncoderSetParameter(state_.PtrNone(), param, value));
61 if (!ret) {
62 return absl::UnavailableError("Unable to set parameter");
63 }
64
65 return absl::OkStatus();
66 }
67
Compress(std::vector<uint8_t> & buf_in,BrotliEncoderOperation op)68 absl::Status BrotliEncoder::Compress(std::vector<uint8_t>& buf_in,
69 BrotliEncoderOperation op) {
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 // BrotliEncoderCompress requires a pointer to a pointer,
76 // as function moves to pointer to indicate how much data
77 // was compressed.
78 // Un 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 bool ret, api_.BrotliEncoderCompressStream(
89 state_.PtrNone(), op, sapi_size_in.PtrBefore(),
90 sapi_opaque_buf_in.PtrBefore(),
91 sapi_avilable_out.PtrBefore(), &null_ptr_, &null_ptr_));
92 if (!ret) {
93 return absl::UnavailableError("Unable to compress input");
94 }
95
96 return absl::OkStatus();
97 }
98
TakeOutput()99 absl::StatusOr<std::vector<uint8_t>> BrotliEncoder::TakeOutput() {
100 SAPI_RETURN_IF_ERROR(CheckIsInit());
101
102 sapi::v::IntBase<size_t> sapi_size_out(0);
103
104 SAPI_ASSIGN_OR_RETURN(
105 uint8_t * sapi_out_buf_ptr,
106 api_.BrotliEncoderTakeOutput(state_.PtrNone(), sapi_size_out.PtrAfter()));
107 if (sapi_out_buf_ptr == nullptr) {
108 return std::vector<uint8_t>(0);
109 }
110 if (sapi_size_out.GetValue() > kFileMaxSize) {
111 return absl::UnavailableError("Output to large");
112 }
113
114 std::vector<uint8_t> buf_out(sapi_size_out.GetValue());
115 sapi::v::Array<uint8_t> sapi_buf_out(buf_out.data(), buf_out.size());
116 sapi_buf_out.SetRemote(sapi_out_buf_ptr);
117
118 SAPI_RETURN_IF_ERROR(sandbox_->TransferFromSandboxee(&sapi_buf_out));
119
120 return buf_out;
121 }
122