move getMapIdByValue to FieldMask.h
[hiphop-php.git] / hphp / util / brotli.cpp
blob1285880850bf50d665d487c8669c512d2a8ed9d5
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/util/brotli.h"
19 #include "hphp/util/alloc.h"
20 #include "hphp/util/exception.h"
21 #include "hphp/util/logger.h"
23 #include <brotli/encode.h>
25 namespace HPHP {
26 ///////////////////////////////////////////////////////////////////////////////
28 bool g_brotliUseLocalArena = false;
30 namespace {
31 void *brotlialloc(void * /*opaque*/, size_t size) {
32 if (g_brotliUseLocalArena) {
33 return local_malloc(size);
34 } else {
35 return malloc(size);
39 void brotlifree(void * /*opaque*/, void *address) {
40 if (g_brotliUseLocalArena) {
41 local_free(address);
42 } else {
43 free(address);
46 } // namespace
48 BrotliCompressor::BrotliCompressor(BrotliEncoderMode mode, uint32_t quality, uint32_t lgWin) {
49 if (quality < BROTLI_MIN_QUALITY || quality > BROTLI_MAX_QUALITY) {
50 Logger::Info("brotli compression quality (%d) must be within %d..%d, clamping...", quality, BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY);
51 if (quality < BROTLI_MIN_QUALITY) {
52 quality = BROTLI_MIN_QUALITY;
53 } else {
54 quality = BROTLI_MAX_QUALITY;
58 if (lgWin < BROTLI_MIN_WINDOW_BITS || lgWin > BROTLI_MAX_WINDOW_BITS) {
59 Logger::Info("brotli window size (%d) must be within %d..%d, clamping...", lgWin, BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS);
60 if (lgWin < BROTLI_MIN_WINDOW_BITS) {
61 lgWin = BROTLI_MIN_WINDOW_BITS;
62 } else {
63 lgWin = BROTLI_MAX_WINDOW_BITS;
67 m_encState.reset(BrotliEncoderCreateInstance(brotlialloc, brotlifree, nullptr));
68 if (!m_encState) {
69 throw Exception("Failed to create brotli encoder instance");
72 if (BrotliEncoderSetParameter(m_encState.get(), BROTLI_PARAM_MODE, mode) != BROTLI_TRUE) {
73 throw Exception("Failed to set brotli mode(%d)", static_cast<uint32_t>(mode));
76 if (BrotliEncoderSetParameter(m_encState.get(), BROTLI_PARAM_QUALITY, quality) != BROTLI_TRUE) {
77 throw Exception("Failed to set quality(%d)", quality);
80 if (BrotliEncoderSetParameter(m_encState.get(), BROTLI_PARAM_LGWIN, lgWin) != BROTLI_TRUE) {
81 throw Exception("Failed to set lgWin(%d)", lgWin);
85 StringHolder BrotliCompressor::compress(const void* data,
86 size_t& len,
87 bool last) {
88 // Brotli does not have a utility to compute max size of the buffer
89 // for the stream-based API. Below link discusses some numbers
90 // and formula where 16MB block would use only 6 extra bytes.
91 // For all practical usage we should be fine with 20 bytes.
92 // https://github.com/google/brotli/issues/274
93 // We should also allow 6 extra bytes for an empty meta-block at
94 // the end of each chunk to force "flush".
95 size_t availableBytes = len + 30;
97 StringHolder available;
98 void* availablePtr;
99 if (g_brotliUseLocalArena) {
100 availablePtr = local_malloc(availableBytes);
101 available = StringHolder(static_cast<char*>(availablePtr),
102 availableBytes,
103 FreeType::LocalFree);
104 } else {
105 availablePtr = malloc(availableBytes);
106 available = StringHolder(static_cast<char*>(availablePtr),
107 availableBytes,
108 FreeType::Free);
111 auto buf = static_cast<uint8_t*>(availablePtr);
112 size_t inLength = len;
113 auto inBuf = static_cast<const uint8_t *>(data);
114 size_t remainingOut = availableBytes;
116 // This ought to complete in one call
117 if (BrotliEncoderCompressStream(
118 m_encState.get(),
119 last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_FLUSH,
120 &inLength,
121 &inBuf,
122 &remainingOut,
123 &buf,
124 nullptr) != BROTLI_TRUE) {
125 Logger::Error("Compression encountered an error");
126 return nullptr;
129 // This means the encoder didn't successfully encode + flush all data.
130 if (inLength != 0 ||
131 BrotliEncoderHasMoreOutput(m_encState.get())) {
132 Logger::Error("Compression didn't flush all data");
133 return nullptr;
136 len = availableBytes - remainingOut;
137 available.shrinkTo(len);
139 return available;
142 ///////////////////////////////////////////////////////////////////////////////