Compare commits

...
49 Commits
Author SHA1 Message Date
Moonchild dabdec3b3a Merge branch 'redwood' into release 2020-12-15 15:09:30 +00:00
Moonchild cd17592001 [toolkit] Handle corner case confusion of downloaded files without extension.
See code comment for details.
2020-12-15 13:39:34 +00:00
Moonchild 62d550e22d Issue #1696 - Propagate flex sizes to the table wrapper
This avoids overlapping of table styled elements inside flexboxes as used on
some websites.

Resolves #1696
2020-12-15 13:39:19 +00:00
Moonchild 2f60cae35e [network] Update port blacklist.
See BZ bugs 1674735, 1677047, 1677940 and 1676868 for details.
2020-12-15 13:39:01 +00:00
Moonchild 65bbd1acb6 Issue #1695 - Add clamping to websocket polling timeouts. 2020-12-13 18:14:40 +00:00
Moonchild 3edea8e9e0 Revert "Issue #1391 - Disable DOM Filesystem/dirpicker APIs by default."
This reverts commit 45a976a5f1.
2020-12-13 18:14:22 +00:00
Moonchild fc539ba189 Issue #1695 - Fix socket timeout logic. 2020-12-13 18:14:12 +00:00
Moonchild 68299c8613 Issue #1694 - Part 2: Use scriptabledateformat for Update History display. 2020-12-13 18:14:00 +00:00
Moonchild d0b7069d1c Issue #1694 - Part 1: Use scriptabledateformat for the Cookie Accept dialog. 2020-12-13 18:13:49 +00:00
Moonchild 55dbbe4d16 Issue #1624 - flip the inlining pref.
The default is now set to the more stable but slower global setting.
2020-12-13 18:13:39 +00:00
Moonchild a52529970f Nuke erroneously added vim line. 2020-12-13 18:13:28 +00:00
Moonchild bcb46bf65e Issue #1624 - Make ion inlining optimizations a pref.
This also adds it to JS_SetGlobalJitCompilerOption()
2020-12-13 18:13:03 +00:00
Moonchild 176f4fe206 Issue #1624 - Globally disable inlining optimizations in the JS JIT compiler. 2020-12-02 07:21:27 +00:00
Brian Smith aed41dc542 Issue #1690 - Part 2: Update MacOS Blocklist support from 10.13 to 11.0.
Changes based on Mozilla bug 1678061.
2020-12-02 07:21:03 +00:00
Brian Smith a7a521e378 Issue #1690 - Part 1: Fix MacOS version detection above 10.15.
Changes based on Mozilla bug 1616404 but supporting back to 10.7.
2020-12-02 07:20:45 +00:00
Moonchild e9b56e301c Clobber for NSS update. 2020-12-02 07:20:26 +00:00
Moonchild 57debb342a [NSS] Version and build bump 2020-12-02 07:20:16 +00:00
Moonchild 78219cdbf1 [NSS] Update root certificates. 2020-12-02 07:20:04 +00:00
Moonchild c68e97f01c Issue #1684 - Move global user-agent override to networking component.
Since this is a http protocol networking feature, it belongs in the networking
branch of our preferences.
2020-12-02 07:19:17 +00:00
Moonchild 5165ed0228 Merge branch 'redwood' into release 2020-11-20 09:47:03 +00:00
Moonchild ca9abcdf17 [webrtc] Only init WebRtcAec callbacks once 2020-11-19 22:47:40 +00:00
Werner Lemberg 459c36b9df [sfnt] Fix heap buffer overflow.
This is CVE-2020-15999.

* src/sfnt/pngshim.c (Load_SBit_Png): Test bitmap size earlier.
2020-11-19 22:47:19 +00:00
Henri Sivonen c9508464d5 [dom] Remove attributes from descendants when setting sanitized style.
This avoids a number of problems with incomplete sanitation.
2020-11-19 22:47:05 +00:00
Moonchild 2219a336dd [http] Use a copy of nsHttpConnectionInfo.
The root cause in this bug is that the connection info used by
'SpdyConnectTransaction' is the same instance as the connection info in
'nsHttpTransaction', so we should clone it and let 'SpdyConnectTransaction' use
the cloned one.
2020-11-19 22:46:51 +00:00
Moonchild a6763e7451 [xpcom] Don't use realloc for shrinking nsTArrays when allowRealloc is false.
The original patch handled the grow case but not the shrink case. When the
current and new allocation sizes are in different size classes, jemalloc's
realloc will move the allocation when shrinking, not just truncate the existing
one.

Based on work by Jon Coppeard.
2020-11-19 22:46:22 +00:00
Henri Sivonen 727f4372a9 [parser] Make the refcount of nsHtml5OwningUTF16Buffer atomic. 2020-11-19 22:46:06 +00:00
David Major 556a15567d [xpcom] Fix GetWindowsFolder storage 2020-11-19 22:45:53 +00:00
Moonchild 95d93b55c9 [gfx][Skia] Hold mutex while accessing shared SkImage data. 2020-11-19 22:45:34 +00:00
Alessio Vanni 693dc6a5fc Issue #1686 - Align a keybinding definition with the others 2020-11-19 22:45:00 +00:00
Brian Smith 08cc9cd558 Issue #1667 - Part 3: Fix OpenGL load and runtime issues on Big Sur
This fix is included in NSPR 4.27 and Mozilla bug 1652330.
Also put a main thread check in the cocoa draw callback.
2020-11-19 22:44:41 +00:00
Brian Smith 4f0f4aa879 Issue #1667 - Part 2: Add MacOS 11.0 Big Sur widget compatibility
This involves refactoring the vibrancy and OpenGL/Pixel rendering changes contained
in the following Mozilla meta bugs: 1496823 and 1491445
Also add Big Sur to the features tests and update popup menu look and feel based
on Mozilla bug 1656301.
2020-11-19 22:44:22 +00:00
Brian Smith 53ca366d2b Issue #1667 - Part 1: Define _pthread_self if it is not already defined in jemalloc 2020-11-19 22:44:09 +00:00
Moonchild 14f7bec523 [UA] Change default compatibility mode version to 68.0
Since several entities have started to ban .9 versions, even if they are valid
ESR versions.
2020-11-18 10:59:33 +00:00
Matt A. Tobin 976ccaa922 Issue #251 - Move chrome packaging options to ac configure
Also adds options for new functionality in #1683
2020-11-18 10:59:16 +00:00
Moonchild 8b3375e2c2 [packager] Optimize archive accesses. 2020-11-18 10:58:48 +00:00
Moonchild 8fefeee3c3 Issue #1683 - Update libjar module. 2020-11-18 10:58:35 +00:00
Moonchild b645d59b1e Issue #1683 - Update Brotli lib to 1.0.9 2020-11-18 10:58:22 +00:00
Moonchild 71e0814af2 [libjar] Fix inflation logic.
This has been broken for 11 years. About time it's fixed.
Tag #1683
2020-11-18 10:58:08 +00:00
Moonchild 5744d59188 Issue #1682 - Remove vibrator DOM interface and support code. 2020-11-18 10:57:53 +00:00
Moonchild 45a976a5f1 Issue #1391 - Disable DOM Filesystem/dirpicker APIs by default.
There don't seem to be any drawbacks to this; tested for the past month disabled
and there have been no issues with any sites visited. Adoption seems very low.
2020-11-18 10:55:12 +00:00
adesh 06f9b815ce Issue #1280 - Follow-up: Get rid of HPKP pinning mode.
This was a leftover from HPKP removal.

Also remove a couple of unused variables from security/manager/ssl/nsSiteSecurityService.cpp.
2020-11-18 10:54:47 +00:00
Matt A. Tobin 0032e8313d Bug 1466909 - Use AddLvalueReference for UniquePtr's operator*().
This is required for UniquePtr to accept <void>,
which is required for PseudoHandle = mozilla::UniquePtr<T, JS::FreePolicy>;
in turn for mozilla::SegmentedVector<PseudoHandle<void>> uniquePtrArena_;

Tag #1679
2020-11-18 10:54:19 +00:00
Matt A. Tobin d7df9b336a Bug 1328948 - Add is(), as() to Cell.
Tag #1679
2020-11-18 10:54:04 +00:00
athenian200 6c1b1bd18f Issue #1673 - Part 5: Fix brace style and missed -moz-tab-size reference. 2020-11-18 10:51:58 +00:00
athenian200 770cb9a4b9 Issue #1673 - Part 4: Unprefix -moz-tab-size.
While we do fail a couple of tests, the other mainstream browsers also fail them and I think our implementation of tab-size is good enough to be unprefixed at this point. Having this patch also makes testing easier.
2020-11-18 10:51:45 +00:00
athenian200 90309c01a8 Issue #1673 - Part 3: Bring minimum tab advance up to spec.
This provides a clearer rule for the minimum tab advance that brings us to alignment with the spec and both major browsers.
2020-11-18 10:51:34 +00:00
athenian200 4de0e9c68d Issue #1673 - Part 2: Make tab-size animatable and fix typos.
There were a few typos in the previous patch and this patch also makes tab-size animatable which didn't really require much of a change at all.
2020-11-18 10:51:22 +00:00
athenian200 4dae04e594 Issue #1673 - Part 1: Allow tab-size to accept <length>.
Currently -moz-tab-size only accepts <number> values, and both Chrome and Firefox currently support <length> values and have for some time now. So with this you would be able to support sizes in px or em, for instance. This was implemented in Firefox 53 and was trivial to backport.
2020-11-18 10:51:09 +00:00
Moonchild b9c41e2624 [devtools] More gracefully (than a crash) handle stack capture failures. 2020-10-31 17:33:08 +01:00
179 changed files with 6939 additions and 6252 deletions

No files matched your search

+1 -1
View File
@@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Clobber for CSS flow-root implementation
Clobber for NSS update
+3
View File
@@ -162,6 +162,8 @@ def old_configure_options(*options):
'--enable-b2g-camera',
'--enable-b2g-ril',
'--enable-bundled-fonts',
'--enable-chrome-compression',
'--enable-chrome-format',
'--enable-clang-plugin',
'--enable-content-sandbox',
'--enable-cookies',
@@ -263,6 +265,7 @@ def old_configure_options(*options):
'--with-app-name',
'--with-arch',
'--with-branding',
'--with-chrome-name',
'--with-crashreporter-enable-percent',
'--with-cross-lib',
'--with-debug-label',
+1 -1
View File
@@ -216,7 +216,7 @@ endif # NO_PROFILE_GUIDED_OPTIMIZE
MAKE_JARS_FLAGS = \
-t $(topsrcdir) \
-f $(MOZ_JAR_MAKER_FILE_FORMAT) \
-f $(MOZ_CHROME_FILE_FORMAT) \
$(NULL)
ifdef USE_EXTENSION_MANIFEST
-1
View File
@@ -526,7 +526,6 @@ hardware/lights.h
hardware/power.h
hardware_legacy/power.h
hardware_legacy/uevent.h
hardware_legacy/vibrator.h
#endif
HIToolbox/HIToolbox.h
hlink.h
+1 -1
View File
@@ -22,7 +22,7 @@ REF_MANIFEST = $(if $(USE_EXTENSION_MANIFEST),chrome.manifest,test.manifest)
check-%::
if test -d $(FINAL_TARGET); then rm -rf $(FINAL_TARGET); fi;
$(MAKE) realchrome MOZ_JAR_MAKER_FILE_FORMAT=$*
$(MAKE) realchrome MOZ_CHROME_FILE_FORMAT=$*
@echo 'Comparing manifests...'
@if ! sort $(MY_MANIFEST) | diff --text -U 0 $(srcdir)/../$(REF_MANIFEST).$* - ; then \
echo 'TEST-UNEXPECTED-FAIL | config/tests/$(REF_MANIFEST).$* | differing content in manifest!' ; \
+1 -1
View File
@@ -94,7 +94,7 @@ exports.menuitems = [
},
key: {
id: "browserToolbox",
modifiers: "accel,alt,shift",
modifiers: isMac ? "accel,alt" : "accel,shift",
keytext: true
}
},
+19 -2
View File
@@ -1233,7 +1233,7 @@ exports.CSS_PROPERTIES = {
"-moz-tab-size": {
"isInherited": true,
"subproperties": [
"-moz-tab-size"
"tab-size"
],
"supports": [
7
@@ -3052,7 +3052,7 @@ exports.CSS_PROPERTIES = {
"stroke-opacity",
"stroke-width",
"-x-system-font",
"-moz-tab-size",
"tab-size",
"table-layout",
"text-align",
"text-align-last",
@@ -8650,6 +8650,23 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"tab-size": {
"isInherited": true,
"subproperties": [
"tab-size"
],
"supports": [
6,
7
],
"values": [
"-moz-calc",
"calc",
"inherit",
"initial",
"unset"
]
},
"table-layout": {
"isInherited": false,
"subproperties": [
@@ -75,11 +75,6 @@ const gMozillaSpecificProperties = {
from: "ignore",
to: "stretch-to-fit"
},
"-moz-tab-size": {
// https://drafts.csswg.org/css-text-3/#propdef-tab-size
from: "1",
to: "5"
},
"-moz-text-size-adjust": {
// https://drafts.csswg.org/css-size-adjust/#propdef-text-size-adjust
from: "none",
+1 -192
View File
@@ -98,11 +98,6 @@
namespace mozilla {
namespace dom {
static bool sVibratorEnabled = false;
static uint32_t sMaxVibrateMS = 0;
static uint32_t sMaxVibrateListLen = 0;
static const char* kVibrationPermissionType = "vibration";
static void
AddPermission(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPermission,
uint32_t aExpireType, int64_t aExpireTime)
@@ -153,12 +148,7 @@ GetPermission(nsIPrincipal* aPrincipal, const char* aType)
void
Navigator::Init()
{
Preferences::AddBoolVarCache(&sVibratorEnabled,
"dom.vibrator.enabled", true);
Preferences::AddUintVarCache(&sMaxVibrateMS,
"dom.vibrator.max_vibrate_ms", 10000);
Preferences::AddUintVarCache(&sMaxVibrateListLen,
"dom.vibrator.max_vibrate_list_len", 128);
// Add any Preferences::Add*VarCache(&sPref, "pref", default) here if needed.
}
Navigator::Navigator(nsPIDOMWindowInner* aWindow)
@@ -706,82 +696,6 @@ Navigator::RefreshMIMEArray()
}
}
namespace {
class VibrateWindowListener : public nsIDOMEventListener
{
public:
VibrateWindowListener(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument)
{
mWindow = do_GetWeakReference(aWindow);
mDocument = do_GetWeakReference(aDocument);
NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
aDocument->AddSystemEventListener(visibilitychange,
this, /* listener */
true, /* use capture */
false /* wants untrusted */);
}
void RemoveListener();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
private:
virtual ~VibrateWindowListener()
{
}
nsWeakPtr mWindow;
nsWeakPtr mDocument;
};
NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
static bool
MayVibrate(nsIDocument* doc) {
// Hidden documents cannot start or stop a vibration.
return (doc && !doc->Hidden());
}
NS_IMETHODIMP
VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDocument> doc =
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
if (!MayVibrate(doc)) {
// It's important that we call CancelVibrate(), not Vibrate() with an
// empty list, because Vibrate() will fail if we're no longer focused, but
// CancelVibrate() will succeed, so long as nobody else has started a new
// vibration pattern.
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
hal::CancelVibrate(window);
RemoveListener();
gVibrateWindowListener = nullptr;
// Careful: The line above might have deleted |this|!
}
return NS_OK;
}
void
VibrateWindowListener::RemoveListener()
{
nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
if (!target) {
return;
}
NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
target->RemoveSystemEventListener(visibilitychange, this,
true /* use capture */);
}
} // namespace
void
Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
{
@@ -810,111 +724,6 @@ Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
}
}
void
Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<uint32_t> pattern;
pattern.SwapElements(mRequestedVibrationPattern);
if (!mWindow) {
return;
}
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
if (!MayVibrate(doc)) {
return;
}
if (aPermitted) {
// Add a listener to cancel the vibration if the document becomes hidden,
// and remove the old visibility listener, if there was one.
if (!gVibrateWindowListener) {
// If gVibrateWindowListener is null, this is the first time we've vibrated,
// and we need to register a listener to clear gVibrateWindowListener on
// shutdown.
ClearOnShutdown(&gVibrateWindowListener);
} else {
gVibrateWindowListener->RemoveListener();
}
gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
hal::Vibrate(pattern, mWindow);
}
if (aPersistent) {
AddPermission(doc->NodePrincipal(), kVibrationPermissionType,
aPermitted ? nsIPermissionManager::ALLOW_ACTION :
nsIPermissionManager::DENY_ACTION,
nsIPermissionManager::EXPIRE_SESSION, 0);
}
}
bool
Navigator::Vibrate(uint32_t aDuration)
{
AutoTArray<uint32_t, 1> pattern;
pattern.AppendElement(aDuration);
return Vibrate(pattern);
}
bool
Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mWindow) {
return false;
}
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
if (!MayVibrate(doc)) {
return false;
}
nsTArray<uint32_t> pattern(aPattern);
if (pattern.Length() > sMaxVibrateListLen) {
pattern.SetLength(sMaxVibrateListLen);
}
for (size_t i = 0; i < pattern.Length(); ++i) {
pattern[i] = std::min(sMaxVibrateMS, pattern[i]);
}
// The spec says we check sVibratorEnabled after we've done the sanity
// checking on the pattern.
if (!sVibratorEnabled) {
return true;
}
mRequestedVibrationPattern.SwapElements(pattern);
uint32_t permission = GetPermission(mWindow, kVibrationPermissionType);
if (permission == nsIPermissionManager::ALLOW_ACTION ||
mRequestedVibrationPattern.IsEmpty() ||
(mRequestedVibrationPattern.Length() == 1 &&
mRequestedVibrationPattern[0] == 0)) {
// Always allow cancelling vibration and respect session permissions.
SetVibrationPermission(true /* permitted */, false /* persistent */);
return true;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs || permission == nsIPermissionManager::DENY_ACTION) {
// Abort without observer service or on denied session permission.
SetVibrationPermission(false /* permitted */, false /* persistent */);
return true;
}
// Request user permission.
obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr);
return true;
}
//*****************************************************************************
// Pointer Events interface
//*****************************************************************************
-3
View File
@@ -150,9 +150,6 @@ public:
// NavigatorBinding::ClearCachedUserAgentValue(this);
void ClearUserAgentCache();
bool Vibrate(uint32_t aDuration);
bool Vibrate(const nsTArray<uint32_t>& aDuration);
void SetVibrationPermission(bool aPermitted, bool aPersistent);
uint32_t MaxTouchPoints();
void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
{
+3 -2
View File
@@ -298,10 +298,11 @@ nsJSUtils::CompileModule(JSContext* aCx,
NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
bool compileResult = JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule);
if (!compileResult) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
+13
View File
@@ -1385,6 +1385,8 @@ nsTreeSanitizer::SanitizeChildren(nsINode* aRoot)
nsAutoString styleText;
nsContentUtils::GetNodeTextContent(node, false, styleText);
RemoveAllAttributesFromDescendants(elt);
nsAutoString sanitizedStyle;
nsCOMPtr<nsIURI> baseURI = node->GetBaseURI();
if (SanitizeStyleSheet(styleText,
@@ -1480,6 +1482,17 @@ nsTreeSanitizer::RemoveAllAttributes(nsIContent* aElement)
}
}
void nsTreeSanitizer::RemoveAllAttributesFromDescendants(mozilla::dom::Element* aElement) {
nsIContent* node = aElement->GetFirstChild();
while (node) {
if (node->IsElement()) {
mozilla::dom::Element* elt = node->AsElement();
RemoveAllAttributes(elt);
}
node = node->GetNextNode(aElement);
}
}
void
nsTreeSanitizer::InitializeStatics()
{
+6
View File
@@ -183,6 +183,12 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
*/
void RemoveAllAttributes(nsIContent* aElement);
/**
* Removes all attributes from the descendants of an element but not from
* the element itself.
*/
void RemoveAllAttributesFromDescendants(mozilla::dom::Element* aElement);
/**
* The whitelist of HTML elements.
*/
@@ -122,7 +122,6 @@ run-if = e10s
[test_storagePermissionsReject.html]
[test_storagePermissionsRejectForeign.html]
[test_stylesheetPI.html]
[test_vibrator.html]
[test_WebKitCSSMatrix.html]
[test_windowedhistoryframes.html]
[test_windowProperties.html]
@@ -1,93 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Vibrator</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<!-- Although we can't test that the vibrator works properly, we can test that
navigator.vibrate throws an exception where appropriate. -->
<script class="testbody" type="text/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
var result;
function expectFailure(param) {
result = navigator.vibrate(param);
is(result, false, 'vibrate(' + param + ') should have failed.');
}
function expectSuccess(param) {
result = navigator.vibrate(param);
is(result, true, 'vibrate(' + param + ') must succeed.');
}
function tests(aEnabled) {
// Some edge cases that the bindings should handle for us.
expectSuccess(null);
expectSuccess(undefined);
// -1 will be converted to the highest unsigned long then clamped.
expectSuccess(-1);
expectSuccess('a');
// -1 will be converted to the highest unsigned long then clamped.
expectSuccess([100, -1]);
expectSuccess([100, 'a']);
var maxVibrateMs = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_ms');
var maxVibrateListLen = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_list_len');
// If we pass a vibration pattern with a value higher than max_vibrate_ms or a
// pattern longer than max_vibrate_list_len, the call should succeed but the
// pattern should be modified to match the restrictions.
// Values will be clamped to dom.vibrator.max_vibrate_ms.
expectSuccess(maxVibrateMs + 1);
expectSuccess([maxVibrateMs + 1]);
var arr = [];
for (var i = 0; i < maxVibrateListLen + 1; i++) {
arr[i] = 0;
}
// The array will be truncated to have a length equal to dom.vibrator.max_vibrate_list_len.
expectSuccess(arr);
expectSuccess(0);
expectSuccess([]);
expectSuccess('1000');
expectSuccess(1000);
expectSuccess(1000.1);
expectSuccess([0, 0, 0]);
expectSuccess(['1000', 1000]);
expectSuccess([1000, 1000]);
expectSuccess([1000, 1000.1]);
// The following loop shouldn't cause us to crash. See bug 701716.
for (var i = 0; i < 10000; i++) {
navigator.vibrate([100, 100]);
}
ok(true, "Didn't crash after issuing a lot of vibrate() calls.");
if(!aEnabled)
SimpleTest.finish();
}
SpecialPowers.pushPermissions([
{type: 'vibration', allow: true, context: document}
], function() {
// Test with the vibrator pref enabled.
SpecialPowers.pushPrefEnv({"set": [['dom.vibrator.enabled', true]]}, function() {
tests(true);
SpecialPowers.pushPrefEnv({"set": [['dom.vibrator.enabled', false]]}, tests(false));
});
// Everything should be the same when the vibrator is disabled -- in
// particular, a disabled vibrator shouldn't eat failures we'd otherwise
// observe.
}
);
</script>
</body>
</html>
+3 -22
View File
@@ -13,9 +13,9 @@
* http://www.w3.org/TR/beacon/#sec-beacon-method
* https://html.spec.whatwg.org/#navigatorconcurrenthardware
*
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
* © Copyright 2004-2020 Apple Computer, Inc., Mozilla Foundation,
* Opera Software ASA and Moonchild Productions. You are granted a license to use,
* reproduce and create derivative works of this document.
*/
// http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
@@ -124,14 +124,6 @@ interface NavigatorGeolocation {
};
Navigator implements NavigatorGeolocation;
// http://www.w3.org/TR/vibration/#vibration-interface
partial interface Navigator {
// We don't support sequences in unions yet
//boolean vibrate ((unsigned long or sequence<unsigned long>) pattern);
boolean vibrate(unsigned long duration);
boolean vibrate(sequence<unsigned long> pattern);
};
// http://www.w3.org/TR/pointerevents/#extensions-to-the-navigator-interface
partial interface Navigator {
[Pref="dom.w3c_pointer_events.enabled"]
@@ -140,17 +132,6 @@ partial interface Navigator {
// Mozilla-specific extensions
// Chrome-only interface for Vibration API permission handling.
partial interface Navigator {
/* Set permission state to device vibration.
* @param permitted permission state (true for allowing vibration)
* @param persistent make the permission session-persistent
*/
[ChromeOnly]
void setVibrationPermission(boolean permitted,
optional boolean persistent = true);
};
callback interface MozIdleObserver {
// Time is in seconds and is read only when idle observers are added
// and removed.
+30 -16
View File
@@ -212,7 +212,7 @@ VerifyRGBXCorners(uint8_t* aData, const IntSize &aSize, const int32_t aStride, S
#endif
static sk_sp<SkImage>
GetSkImageForSurface(SourceSurface* aSurface)
GetSkImageForSurface(SourceSurface* aSurface, Maybe<MutexAutoLock>* aLock)
{
if (!aSurface) {
gfxDebug() << "Creating null Skia image from null SourceSurface";
@@ -220,7 +220,7 @@ GetSkImageForSurface(SourceSurface* aSurface)
}
if (aSurface->GetType() == SurfaceType::SKIA) {
return static_cast<SourceSurfaceSkia*>(aSurface)->GetImage();
return static_cast<SourceSurfaceSkia*>(aSurface)->GetImage(aLock);
}
DataSourceSurface* surf = aSurface->GetDataSurface().take();
@@ -390,9 +390,9 @@ ExtractAlphaBitmap(sk_sp<SkImage> aImage, SkBitmap* aResultBitmap)
}
static sk_sp<SkImage>
ExtractAlphaForSurface(SourceSurface* aSurface)
ExtractAlphaForSurface(SourceSurface* aSurface, Maybe<MutexAutoLock>& aLock)
{
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &aLock);
if (!image) {
return nullptr;
}
@@ -411,7 +411,11 @@ ExtractAlphaForSurface(SourceSurface* aSurface)
}
static void
SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0, Point aOffset = Point(0, 0))
SetPaintPattern(SkPaint& aPaint,
const Pattern& aPattern,
Maybe<MutexAutoLock>& aLock,
Float aAlpha = 1.0,
Point aOffset = Point(0, 0))
{
switch (aPattern.GetType()) {
case PatternType::COLOR: {
@@ -473,7 +477,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0, Po
}
case PatternType::SURFACE: {
const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
sk_sp<SkImage> image = GetSkImageForSurface(pat.mSurface);
sk_sp<SkImage> image = GetSkImageForSurface(pat.mSurface, &aLock);
if (!image) {
aPaint.setColor(SK_ColorTRANSPARENT);
break;
@@ -525,7 +529,7 @@ struct AutoPaintSetup {
: mNeedsRestore(false), mAlpha(1.0)
{
Init(aCanvas, aOptions, aMaskBounds, false);
SetPaintPattern(mPaint, aPattern, mAlpha, aOffset);
SetPaintPattern(mPaint, aPattern, mLock, mAlpha, aOffset);
}
AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds = nullptr, bool aForceGroup = false)
@@ -579,6 +583,7 @@ struct AutoPaintSetup {
SkPaint mPaint;
bool mNeedsRestore;
SkCanvas* mCanvas;
Maybe<MutexAutoLock> mLock;
Float mAlpha;
};
@@ -601,7 +606,8 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
MarkChanged();
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
if (!image) {
return;
}
@@ -654,7 +660,8 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
MarkChanged();
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
if (!image) {
return;
}
@@ -1407,8 +1414,9 @@ DrawTargetSkia::Mask(const Pattern &aSource,
MarkChanged();
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
Maybe<MutexAutoLock> lock;
SkPaint maskPaint;
SetPaintPattern(maskPaint, aMask);
SetPaintPattern(maskPaint, aMask, lock);
SkLayerRasterizer::Builder builder;
builder.addLayer(maskPaint);
@@ -1427,7 +1435,8 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource,
MarkChanged();
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource, nullptr, -aOffset);
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(aMask);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(aMask, lock);
if (!alphaMask) {
gfxDebug() << *this << ": MaskSurface() failed to extract alpha for mask";
return;
@@ -1456,7 +1465,8 @@ DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& a
fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
// Read in the source data.
sk_sp<SkImage> srcImage = GetSkImageForSurface(aSurface);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> srcImage = GetSkImageForSurface(aSurface, &lock);
if (!srcImage) {
return true;
}
@@ -1515,7 +1525,8 @@ DrawTargetSkia::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x
MarkChanged();
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
if (!image) {
return true;
}
@@ -1599,7 +1610,8 @@ already_AddRefed<SourceSurface>
DrawTargetSkia::OptimizeGPUSourceSurface(SourceSurface *aSurface) const
{
// Check if the underlying SkImage already has an associated GrTexture.
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
if (!image || image->isTextureBacked()) {
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
@@ -1716,7 +1728,8 @@ DrawTargetSkia::CopySurface(SourceSurface *aSurface,
{
MarkChanged();
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
if (!image) {
return;
}
@@ -2061,7 +2074,8 @@ DrawTargetSkia::PopLayer()
paint.setColor(SK_ColorTRANSPARENT);
}
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(layer.mMask);
Maybe<MutexAutoLock> lock;
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(layer.mMask, lock);
if (!alphaMask) {
gfxDebug() << *this << ": PopLayer() failed to extract alpha for mask";
} else {
+19
View File
@@ -40,6 +40,25 @@ SourceSurfaceSkia::GetFormat() const
return mFormat;
}
sk_sp<SkImage>
SourceSurfaceSkia::GetImage(Maybe<MutexAutoLock>* aLock) {
// If we were provided a lock object, we can let the caller access
// a shared SkImage and we know it won't go away while the lock is held.
if (aLock) {
// We are locked, so now we can check mDrawTarget.
// If it's null, then we're not shared and we can unlock eagerly.
if (!mDrawTarget) {
aLock->reset();
}
} else {
// Otherwise we need to call DrawTargetWillChange to ensure we have our
// own copy of the SkImage.
DrawTargetWillChange();
}
sk_sp<SkImage> image = mImage;
return image;
}
static sk_sp<SkData>
MakeSkData(unsigned char* aData, const IntSize& aSize, int32_t aStride)
{
+5 -1
View File
@@ -10,6 +10,10 @@
#include <vector>
#include "skia/include/core/SkCanvas.h"
#include "skia/include/core/SkImage.h"
#include "mozilla/Maybe.h"
#include "mozilla/Mutex.h"
typedef mozilla::MutexAutoLock MutexAutoLock;
namespace mozilla {
@@ -28,7 +32,7 @@ public:
virtual IntSize GetSize() const;
virtual SurfaceFormat GetFormat() const;
sk_sp<SkImage>& GetImage() { return mImage; }
sk_sp<SkImage> GetImage(Maybe<MutexAutoLock>* aLock);
bool InitFromData(unsigned char* aData,
const IntSize &aSize,
+2 -2
View File
@@ -1858,8 +1858,8 @@ GLContext::InitExtensions()
// textures with glCompressedTexSubImage2D. Works on Intel HD 4000
// and Intel HD 5000/Iris that I tested.
// Bug 1124996: Appears to be the same on OSX Yosemite (10.10)
if (nsCocoaFeatures::OSXVersionMajor() == 10 &&
nsCocoaFeatures::OSXVersionMinor() >= 9 &&
if (nsCocoaFeatures::macOSVersionMajor() == 10 &&
nsCocoaFeatures::macOSVersionMinor() >= 9 &&
Renderer() == GLRenderer::IntelHD3000)
{
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
-79
View File
@@ -95,87 +95,8 @@ WindowIsActive(nsPIDOMWindowInner* aWindow)
return !document->Hidden();
}
StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
void InitLastIDToVibrate()
{
gLastIDToVibrate = new WindowIdentifier::IDArrayType();
ClearOnShutdown(&gLastIDToVibrate);
}
} // namespace
void
Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window)
{
Vibrate(pattern, WindowIdentifier(window));
}
void
Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
{
AssertMainThread();
// Only active windows may start vibrations. If |id| hasn't gone
// through the IPC layer -- that is, if our caller is the outside
// world, not hal_proxy -- check whether the window is active. If
// |id| has gone through IPC, don't check the window's visibility;
// only the window corresponding to the bottommost process has its
// visibility state set correctly.
if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
return;
}
if (!InSandbox()) {
if (!gLastIDToVibrate) {
InitLastIDToVibrate();
}
*gLastIDToVibrate = id.AsArray();
}
// Don't forward our ID if we are not in the sandbox, because hal_impl
// doesn't need it, and we don't want it to be tempted to read it. The
// empty identifier will assert if it's used.
PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
}
void
CancelVibrate(nsPIDOMWindowInner* window)
{
CancelVibrate(WindowIdentifier(window));
}
void
CancelVibrate(const WindowIdentifier &id)
{
AssertMainThread();
// Although only active windows may start vibrations, a window may
// cancel its own vibration even if it's no longer active.
//
// After a window is marked as inactive, it sends a CancelVibrate
// request. We want this request to cancel a playing vibration
// started by that window, so we certainly don't want to reject the
// cancellation request because the window is now inactive.
//
// But it could be the case that, after this window became inactive,
// some other window came along and started a vibration. We don't
// want this window's cancellation request to cancel that window's
// actively-playing vibration!
//
// To solve this problem, we keep track of the id of the last window
// to start a vibration, and only accepts cancellation requests from
// the same window. All other cancellation requests are ignored.
if (InSandbox() || (gLastIDToVibrate && *gLastIDToVibrate == id.AsArray())) {
// Don't forward our ID if we are not in the sandbox, because hal_impl
// doesn't need it, and we don't want it to be tempted to read it. The
// empty identifier will assert if it's used.
PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
}
}
template <class InfoType>
class ObserversManager
{
-35
View File
@@ -51,41 +51,6 @@ typedef Observer<SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
namespace MOZ_HAL_NAMESPACE {
/**
* Turn the default vibrator device on/off per the pattern specified
* by |pattern|. Each element in the pattern is the number of
* milliseconds to turn the vibrator on or off. The first element in
* |pattern| is an "on" element, the next is "off", and so on.
*
* If |pattern| is empty, any in-progress vibration is canceled.
*
* Only an active window within an active tab may call Vibrate; calls
* from inactive windows and windows on inactive tabs do nothing.
*
* If you're calling hal::Vibrate from the outside world, pass an
* nsIDOMWindow* in place of the WindowIdentifier parameter.
* The method with WindowIdentifier will be called automatically.
*/
void Vibrate(const nsTArray<uint32_t>& pattern,
nsPIDOMWindowInner* aWindow);
void Vibrate(const nsTArray<uint32_t>& pattern,
const hal::WindowIdentifier &id);
/**
* Cancel a vibration started by the content window identified by
* WindowIdentifier.
*
* If the window was the last window to start a vibration, the
* cancellation request will go through even if the window is not
* active.
*
* As with hal::Vibrate(), if you're calling hal::CancelVibrate from the outside
* world, pass an nsIDOMWindow*. The method with WindowIdentifier will be called
* automatically.
*/
void CancelVibrate(nsPIDOMWindowInner* aWindow);
void CancelVibrate(const hal::WindowIdentifier &id);
/**
* Determine whether the device's screen is currently enabled.
*/
-23
View File
@@ -1,23 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
using mozilla::hal::WindowIdentifier;
namespace mozilla {
namespace hal_impl {
void
Vibrate(const nsTArray<uint32_t>& pattern, const hal::WindowIdentifier &)
{}
void
CancelVibrate(const hal::WindowIdentifier &)
{}
} // namespace hal_impl
} // namespace mozilla
-5
View File
@@ -30,7 +30,6 @@ if CONFIG['OS_TARGET'] == 'Linux':
'fallback/FallbackAlarm.cpp',
'fallback/FallbackScreenConfiguration.cpp',
'fallback/FallbackSensor.cpp',
'fallback/FallbackVibration.cpp',
'linux/LinuxMemory.cpp',
'linux/LinuxPower.cpp',
]
@@ -40,7 +39,6 @@ elif CONFIG['OS_TARGET'] == 'WINNT':
'fallback/FallbackMemory.cpp',
'fallback/FallbackPower.cpp',
'fallback/FallbackScreenConfiguration.cpp',
'fallback/FallbackVibration.cpp',
'windows/WindowsSensor.cpp',
]
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
@@ -49,7 +47,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
'fallback/FallbackMemory.cpp',
'fallback/FallbackPower.cpp',
'fallback/FallbackScreenConfiguration.cpp',
'fallback/FallbackVibration.cpp',
]
elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
UNIFIED_SOURCES += [
@@ -58,7 +55,6 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
'fallback/FallbackPower.cpp',
'fallback/FallbackScreenConfiguration.cpp',
'fallback/FallbackSensor.cpp',
'fallback/FallbackVibration.cpp',
]
else:
UNIFIED_SOURCES += [
@@ -67,7 +63,6 @@ else:
'fallback/FallbackPower.cpp',
'fallback/FallbackScreenConfiguration.cpp',
'fallback/FallbackSensor.cpp',
'fallback/FallbackVibration.cpp',
]
UNIFIED_SOURCES += [
-3
View File
@@ -70,9 +70,6 @@ child:
async NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo);
parent:
async Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser);
async CancelVibrate(uint64_t[] id, PBrowser browser);
async EnableNetworkNotifications();
async DisableNetworkNotifications();
sync GetCurrentNetworkInformation()
-52
View File
@@ -46,28 +46,6 @@ Hal()
return sHal;
}
void
Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
{
HAL_LOG("Vibrate: Sending to parent process.");
AutoTArray<uint32_t, 8> p(pattern);
WindowIdentifier newID(id);
newID.AppendProcessID();
Hal()->SendVibrate(p, newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
}
void
CancelVibrate(const WindowIdentifier &id)
{
HAL_LOG("CancelVibrate: Sending to parent process.");
WindowIdentifier newID(id);
newID.AppendProcessID();
Hal()->SendCancelVibrate(newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
}
void
EnableNetworkNotifications()
{
@@ -380,36 +358,6 @@ public:
hal::UnregisterSystemTimezoneChangeObserver(this);
}
virtual bool
RecvVibrate(InfallibleTArray<unsigned int>&& pattern,
InfallibleTArray<uint64_t>&& id,
PBrowserParent *browserParent) override
{
// We give all content vibration permission.
// TabParent *tabParent = TabParent::GetFrom(browserParent);
/* xxxkhuey wtf
nsCOMPtr<nsIDOMWindow> window =
do_QueryInterface(tabParent->GetBrowserDOMWindow());
*/
WindowIdentifier newID(id, nullptr);
hal::Vibrate(pattern, newID);
return true;
}
virtual bool
RecvCancelVibrate(InfallibleTArray<uint64_t> &&id,
PBrowserParent *browserParent) override
{
//TabParent *tabParent = TabParent::GetFrom(browserParent);
/* XXXkhuey wtf
nsCOMPtr<nsIDOMWindow> window =
tabParent->GetBrowserDOMWindow();
*/
WindowIdentifier newID(id, nullptr);
hal::CancelVibrate(newID);
return true;
}
virtual bool
RecvEnableNetworkNotifications() override {
// We give all content access to this network-status information.
+18
View File
@@ -29,6 +29,7 @@
#include "js/HeapAPI.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
#include "js/TraceKind.h"
struct JSRuntime;
@@ -273,6 +274,23 @@ struct Cell
static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
template <class T>
inline bool is() const {
return getTraceKind() == JS::MapTypeToTraceKind<T>::kind;
}
template<class T>
inline T* as() {
MOZ_ASSERT(is<T>());
return static_cast<T*>(this);
}
template <class T>
inline const T* as() const {
MOZ_ASSERT(is<T>());
return static_cast<const T*>(this);
}
#ifdef DEBUG
inline bool isAligned() const;
void dump(FILE* fp) const;
+6 -1
View File
@@ -6608,6 +6608,9 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v
case JSJITCOMPILER_ION_INTERRUPT_WITHOUT_SIGNAL:
jit::JitOptions.ionInterruptWithoutSignals = !!value;
break;
case JSJITCOMPILER_ION_INLINING:
jit::JitOptions.disableInlining = !value;
break;
default:
break;
}
@@ -7040,7 +7043,9 @@ JS::CaptureCurrentStack(JSContext* cx, JS::MutableHandleObject stackp,
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
if (!cx->compartment()) {
return false;
}
JSCompartment* compartment = cx->compartment();
Rooted<SavedFrame*> frame(cx);
+1
View File
@@ -5906,6 +5906,7 @@ JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled);
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
Register(ION_INLINING, "ion.inlining") \
Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \
Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
Register(BASELINE_ENABLE, "baseline.enable") \
+4 -1
View File
@@ -1,5 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -1429,6 +1428,8 @@ ReloadPrefsCallback(const char* pref, void* data)
bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
bool inlining = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion.inlining");
sSharedMemoryEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory");
#ifdef DEBUG
@@ -1459,6 +1460,8 @@ ReloadPrefsCallback(const char* pref, void* data)
useIonEager ? 0 : -1);
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_UNBOXED_OBJECTS,
unboxedObjects);
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_INLINING,
inlining);
}
XPCJSContext::~XPCJSContext()
+70 -35
View File
@@ -1718,6 +1718,16 @@ GetSpaceWidthAppUnits(const gfxTextRun* aTextRun)
return spaceWidthAppUnits;
}
static gfxFloat
GetMinTabAdvanceAppUnits(const gfxTextRun* aTextRun)
{
gfxFloat chWidthAppUnits =
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(),
aTextRun->IsVertical()).zeroOrAveCharWidth *
aTextRun->GetAppUnitsPerDevUnit());
return 0.5 * chWidthAppUnits;
}
static nscoord
LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nullptr)
{
@@ -3092,6 +3102,7 @@ public:
mLength(aLength),
mWordSpacing(WordSpacing(aFrame, mTextRun, aTextStyle)),
mLetterSpacing(LetterSpacing(aFrame, aTextStyle)),
mMinTabAdvance(-1.0),
mHyphenWidth(-1),
mOffsetFromBlockOriginForTabs(aOffsetFromBlockOriginForTabs),
mReflowing(true),
@@ -3116,6 +3127,7 @@ public:
mLength(aFrame->GetContentLength()),
mWordSpacing(WordSpacing(aFrame, mTextRun)),
mLetterSpacing(LetterSpacing(aFrame)),
mMinTabAdvance(-1.0),
mHyphenWidth(-1),
mOffsetFromBlockOriginForTabs(0),
mReflowing(false),
@@ -3178,7 +3190,14 @@ public:
return mFontMetrics;
}
void CalcTabWidths(Range aTransformedRange);
void CalcTabWidths(Range aTransformedRange, gfxFloat aTabWidth);
gfxFloat MinTabAdvance() {
if (mMinTabAdvance < 0.0) {
mMinTabAdvance = GetMinTabAdvanceAppUnits(mTextRun);
}
return mMinTabAdvance;
}
const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; }
@@ -3212,6 +3231,7 @@ protected:
int32_t mLength; // DOM string length, may be INT32_MAX
gfxFloat mWordSpacing; // space for each whitespace char
gfxFloat mLetterSpacing; // space for each letter
gfxFloat mMinTabAdvance; // min advance for <tab> char
gfxFloat mHyphenWidth;
gfxFloat mOffsetFromBlockOriginForTabs;
@@ -3364,6 +3384,28 @@ CanAddSpacingAfter(const gfxTextRun* aTextRun, uint32_t aOffset)
aTextRun->IsLigatureGroupStart(aOffset + 1);
}
static gfxFloat
ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
{
const nsStyleText* textStyle = aFrame->StyleText();
if (textStyle->mTabSize.GetUnit() != eStyleUnit_Factor) {
nscoord w = textStyle->mTabSize.GetCoordValue();
MOZ_ASSERT(w >= 0);
return w;
}
gfxFloat spaces = textStyle->mTabSize.GetFactorValue();
MOZ_ASSERT(spaces >= 0);
// Round the space width when converting to appunits the same way
// textruns do.
gfxFloat spaceWidthAppUnits =
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(),
aTextRun->IsVertical()).spaceWidth *
aTextRun->GetAppUnitsPerDevUnit());
return spaces * spaceWidthAppUnits;
}
void
PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
bool aIgnoreTabs)
@@ -3411,17 +3453,16 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
}
}
// Ignore tab spacing rather than computing it, if the tab size is 0
if (!aIgnoreTabs)
aIgnoreTabs = mFrame->StyleText()->mTabSize == 0;
// Now add tab spacing, if there is any
if (!aIgnoreTabs) {
CalcTabWidths(aRange);
if (mTabWidths) {
mTabWidths->ApplySpacing(aSpacing,
aRange.start - mStart.GetSkippedOffset(),
aRange.Length());
gfxFloat tabWidth = ComputeTabWidthAppUnits(mFrame, mTextRun);
if (tabWidth > 0) {
CalcTabWidths(aRange, tabWidth);
if (mTabWidths) {
mTabWidths->ApplySpacing(aSpacing,
aRange.start - mStart.GetSkippedOffset(),
aRange.Length());
}
}
}
@@ -3444,33 +3485,22 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
}
}
static gfxFloat
ComputeTabWidthAppUnits(nsIFrame* aFrame, const gfxTextRun* aTextRun)
{
// Get the number of spaces from CSS -moz-tab-size
const nsStyleText* textStyle = aFrame->StyleText();
return textStyle->mTabSize * GetSpaceWidthAppUnits(aTextRun);
}
// aX and the result are in whole appunits.
static gfxFloat
AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame,
const gfxTextRun* aTextRun, gfxFloat* aCachedTabWidth)
AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, gfxTextRun* aTextRun,
gfxFloat aTabWidth, gfxFloat aMinAdvance)
{
if (*aCachedTabWidth < 0) {
*aCachedTabWidth = ComputeTabWidthAppUnits(aFrame, aTextRun);
}
// Advance aX to the next multiple of *aCachedTabWidth. We must advance
// by at least 1 appunit.
// XXX should we make this 1 CSS pixel?
return ceil((aX + 1)/(*aCachedTabWidth))*(*aCachedTabWidth);
// Advance aX to the next multiple of aTabWidth. We must advance
// by at least aMinAdvance.
return ceil((aX + aMinAdvance) / aTabWidth) * aTabWidth;
}
void
PropertyProvider::CalcTabWidths(Range aRange)
PropertyProvider::CalcTabWidths(Range aRange, gfxFloat aTabWidth)
{
MOZ_ASSERT(aTabWidth > 0);
if (!mTabWidths) {
if (mReflowing && !mLineContainer) {
// Intrinsic width computation does its own tab processing. We
@@ -3505,7 +3535,6 @@ PropertyProvider::CalcTabWidths(Range aRange)
NS_ASSERTION(mReflowing,
"We need precomputed tab widths, but don't have enough.");
gfxFloat tabWidth = -1;
for (uint32_t i = tabsEnd; i < aRange.end; ++i) {
Spacing spacing;
GetSpacingInternal(Range(i, i + 1), &spacing, true);
@@ -3527,7 +3556,7 @@ PropertyProvider::CalcTabWidths(Range aRange)
mFrame->SetProperty(TabWidthProperty(), mTabWidths);
}
double nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs,
mFrame, mTextRun, &tabWidth);
mFrame, mTextRun, aTabWidth, MinTabAdvance());
mTabWidths->mWidths.AppendElement(TabWidth(i - startOffset,
NSToIntRound(nextTab - mOffsetFromBlockOriginForTabs)));
mOffsetFromBlockOriginForTabs = nextTab;
@@ -8321,9 +8350,12 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
PropertyProvider::Spacing spacing;
provider.GetSpacing(Range(i, i + 1), &spacing);
aData->mCurrentLine += nscoord(spacing.mBefore);
if (tabWidth < 0) {
tabWidth = ComputeTabWidthAppUnits(this, textRun);
}
gfxFloat afterTab =
AdvanceToNextTab(aData->mCurrentLine, this,
textRun, &tabWidth);
AdvanceToNextTab(aData->mCurrentLine, this, textRun, tabWidth,
provider.MinTabAdvance());
aData->mCurrentLine = nscoord(afterTab + spacing.mAfter);
wordStart = i + 1;
} else if (i < flowEndInTextRun ||
@@ -8480,9 +8512,12 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext,
PropertyProvider::Spacing spacing;
provider.GetSpacing(Range(i, i + 1), &spacing);
aData->mCurrentLine += nscoord(spacing.mBefore);
if (tabWidth < 0) {
tabWidth = ComputeTabWidthAppUnits(this, textRun);
}
gfxFloat afterTab =
AdvanceToNextTab(aData->mCurrentLine, this,
textRun, &tabWidth);
AdvanceToNextTab(aData->mCurrentLine, this, textRun, tabWidth,
provider.MinTabAdvance());
aData->mCurrentLine = nscoord(afterTab + spacing.mAfter);
lineStart = i + 1;
} else if (preformattedNewline) {
+4
View File
@@ -223,6 +223,10 @@ CSS_PROP_ALIAS(-moz-columns,
columns,
MozColumns,
"")
CSS_PROP_ALIAS(-moz-tab-size,
tab_size,
MozTabSize,
"")
#define WEBKIT_PREFIX_PREF "layout.css.prefixes.webkit"
+5 -5
View File
@@ -3879,16 +3879,16 @@ CSS_PROP_FONT(
eStyleAnimType_None)
#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_TEXT(
-moz-tab-size,
_moz_tab_size,
CSS_PROP_DOMPROP_PREFIXED(TabSize),
tab-size,
tab_size,
TabSize,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_VALUE_NONNEGATIVE,
"",
VARIANT_HI,
VARIANT_INHERIT | VARIANT_LNCALC,
nullptr,
offsetof(nsStyleText, mTabSize),
eStyleAnimType_Discrete)
eStyleAnimType_Coord)
CSS_PROP_TABLE(
table-layout,
table_layout,
+1 -1
View File
@@ -3972,7 +3972,7 @@ already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetTabSize()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetNumber(StyleText()->mTabSize);
SetValueToCoord(val, StyleText()->mTabSize, true);
return val.forget();
}
@@ -228,6 +228,7 @@ COMPUTED_STYLE_PROP(scroll_snap_type_x, ScrollSnapTypeX)
COMPUTED_STYLE_PROP(scroll_snap_type_y, ScrollSnapTypeY)
COMPUTED_STYLE_PROP(shape_outside, ShapeOutside)
//// COMPUTED_STYLE_PROP(size, Size)
COMPUTED_STYLE_PROP(tab_size, TabSize)
COMPUTED_STYLE_PROP(table_layout, TableLayout)
COMPUTED_STYLE_PROP(text_align, TextAlign)
COMPUTED_STYLE_PROP(text_align_last, TextAlignLast)
@@ -295,7 +296,6 @@ COMPUTED_STYLE_PROP(_moz_outline_radius_bottomRight,OutlineRadiusBottomRight)
COMPUTED_STYLE_PROP(_moz_outline_radius_topLeft, OutlineRadiusTopLeft)
COMPUTED_STYLE_PROP(_moz_outline_radius_topRight, OutlineRadiusTopRight)
COMPUTED_STYLE_PROP(stack_sizing, StackSizing)
COMPUTED_STYLE_PROP(_moz_tab_size, TabSize)
COMPUTED_STYLE_PROP(text_size_adjust, TextSizeAdjust)
COMPUTED_STYLE_PROP(user_focus, UserFocus)
COMPUTED_STYLE_PROP(user_input, UserInput)
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -3807,10 +3807,10 @@ nsStyleText::nsStyleText(StyleStructContext aContext)
, mControlCharacterVisibility(nsCSSParser::ControlCharVisibilityDefault())
, mTextEmphasisStyle(NS_STYLE_TEXT_EMPHASIS_STYLE_NONE)
, mTextRendering(NS_STYLE_TEXT_RENDERING_AUTO)
, mTabSize(NS_STYLE_TABSIZE_INITIAL)
, mTextEmphasisColor(StyleComplexColor::CurrentColor())
, mWebkitTextFillColor(StyleComplexColor::CurrentColor())
, mWebkitTextStrokeColor(StyleComplexColor::CurrentColor())
, mTabSize(float(NS_STYLE_TABSIZE_INITIAL), eStyleUnit_Factor)
, mWordSpacing(0, nsStyleCoord::CoordConstructor)
, mLetterSpacing(eStyleUnit_Normal)
, mLineHeight(eStyleUnit_Normal)
@@ -3845,10 +3845,10 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
, mTextEmphasisPosition(aSource.mTextEmphasisPosition)
, mTextEmphasisStyle(aSource.mTextEmphasisStyle)
, mTextRendering(aSource.mTextRendering)
, mTabSize(aSource.mTabSize)
, mTextEmphasisColor(aSource.mTextEmphasisColor)
, mWebkitTextFillColor(aSource.mWebkitTextFillColor)
, mWebkitTextStrokeColor(aSource.mWebkitTextStrokeColor)
, mTabSize(aSource.mTabSize)
, mWordSpacing(aSource.mWordSpacing)
, mLetterSpacing(aSource.mLetterSpacing)
, mLineHeight(aSource.mLineHeight)
+1 -1
View File
@@ -2088,11 +2088,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
uint8_t mTextEmphasisPosition; // [inherited] see nsStyleConsts.h
uint8_t mTextEmphasisStyle; // [inherited] see nsStyleConsts.h
uint8_t mTextRendering; // [inherited] see nsStyleConsts.h
int32_t mTabSize; // [inherited] see nsStyleConsts.h
mozilla::StyleComplexColor mTextEmphasisColor; // [inherited]
mozilla::StyleComplexColor mWebkitTextFillColor; // [inherited]
mozilla::StyleComplexColor mWebkitTextStrokeColor; // [inherited]
nsStyleCoord mTabSize; // [inherited] coord, factor, calc
nsStyleCoord mWordSpacing; // [inherited] coord, percent, calc
nsStyleCoord mLetterSpacing; // [inherited] coord, normal
nsStyleCoord mLineHeight; // [inherited] coord, factor, normal
+3
View File
@@ -46,6 +46,9 @@
backface-visibility: inherit;
clip: inherit;
/* When the table wrapper is a Flex/Grid item we need these: */
flex-grow: inherit;
flex-shrink: inherit;
flex-basis: inherit;
align-self: inherit;
justify-self: inherit;
grid-column-start: inherit;
+13 -4
View File
@@ -2028,13 +2028,22 @@ var gCSSProperties = {
other_values: [ "ignore" ],
invalid_values: []
},
"-moz-tab-size": {
domProp: "MozTabSize",
"tab-size": {
domProp: "TabSize",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "8" ],
other_values: [ "0", "3", "99", "12000" ],
invalid_values: [ "-1", "-808", "3.0", "17.5" ]
other_values: [ "0", "2.5", "3", "99", "12000", "0px", "1em",
"calc(1px + 1em)", "calc(1px - 2px)", "calc(1 + 1)", "calc(-2.5)" ],
invalid_values: [ "9%", "calc(9% + 1px)", "calc(1 + 1em)", "-1", "-808",
"auto" ]
},
"-moz-tab-size": {
domProp: "MozTabSize",
inherited: true,
type: CSS_TYPE_SHORTHAND_AND_LONGHAND
alias_for: "tab-size",
subproperties: [ "tab-size" ]
},
"-moz-text-size-adjust": {
domProp: "MozTextSizeAdjust",
@@ -248,6 +248,8 @@ var supported_properties = {
// test_length_percent_calc_transition.
"stroke-width": [ test_length_transition_svg, test_percent_transition,
test_length_clamped_svg, test_percent_clamped ],
"tab-size": [ test_float_zeroToOne_transition,
test_float_aboveOne_transition, test_length_clamped ],
"text-decoration": [ test_color_shorthand_transition,
test_true_currentcolor_shorthand_transition ],
"text-decoration-color": [ test_color_transition,
@@ -23,6 +23,7 @@
#include <stddef.h> // size_t
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "webrtc/common_audio/ring_buffer.h"
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
@@ -1573,33 +1574,36 @@ AecCore* WebRtcAec_CreateAec() {
#endif
aec->extended_filter_enabled = 0;
// Assembly optimization
WebRtcAec_FilterFar = FilterFar;
WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
WebRtcAec_FilterAdaptation = FilterAdaptation;
WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppress;
WebRtcAec_ComfortNoise = ComfortNoise;
WebRtcAec_SubbandCoherence = SubbandCoherence;
static bool initted = false;
if (!initted) {
initted = true;
// Assembly optimization
WebRtcAec_FilterFar = FilterFar;
WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
WebRtcAec_FilterAdaptation = FilterAdaptation;
WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppress;
WebRtcAec_ComfortNoise = ComfortNoise;
WebRtcAec_SubbandCoherence = SubbandCoherence;
#if defined(WEBRTC_ARCH_X86_FAMILY)
if (WebRtc_GetCPUInfo(kSSE2)) {
WebRtcAec_InitAec_SSE2();
}
if (WebRtc_GetCPUInfo(kSSE2)) {
WebRtcAec_InitAec_SSE2();
}
#endif
#if defined(MIPS_FPU_LE)
WebRtcAec_InitAec_mips();
WebRtcAec_InitAec_mips();
#endif
#if defined(WEBRTC_ARCH_ARM_NEON)
WebRtcAec_InitAec_neon();
#elif defined(WEBRTC_DETECT_ARM_NEON)
if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
WebRtcAec_InitAec_neon();
}
#elif defined(WEBRTC_DETECT_ARM_NEON)
if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
WebRtcAec_InitAec_neon();
}
#endif
aec_rdft_init();
aec_rdft_init();
}
return aec;
}
+3
View File
@@ -302,6 +302,9 @@ typedef long ssize_t;
#include <mach/mach_init.h>
#include <mach/vm_map.h>
#include <malloc/malloc.h>
#ifndef _pthread_self
#define _pthread_self() pthread_self()
#endif
#endif
#endif
+1 -1
View File
@@ -314,7 +314,7 @@ public:
return *this;
}
T& operator*() const { return *get(); }
typename AddLvalueReference<T>::Type operator*() const { return *get(); }
Pointer operator->() const
{
MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr");
+1 -1
View File
@@ -11,4 +11,4 @@ The in-tree copy is updated by running
sh update.sh
from within the modules/brotli directory.
Current version: [commit d6d98957ca8ccb1ef45922e978bb10efca0ea541].
Current version: 1.0.9 Re-release [commit e61745a6b7add50d380cfd7d3883dd6c62fc2c71].
+15
View File
@@ -0,0 +1,15 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
#include "./constants.h"
const BrotliPrefixCodeRange
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
{1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3},
{33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4},
{113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6},
{369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
{8433, 13}, {16625, 24}};
+136
View File
@@ -4,9 +4,18 @@
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/**
* @file
* Common constants used in decoder and encoder API.
*/
#ifndef BROTLI_COMMON_CONSTANTS_H_
#define BROTLI_COMMON_CONSTANTS_H_
#include "./platform.h"
#include <brotli/port.h>
#include <brotli/types.h>
/* Specification: 7.3. Encoding of the context map */
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
@@ -29,12 +38,31 @@
#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
/* "Large Window Brotli" */
/**
* The theoretical maximum number of distance bits specified for large window
* brotli, for 64-bit encoders and decoders. Even when in practice 32-bit
* encoders and decoders only support up to 30 max distance bits, the value is
* set to 62 because it affects the large window brotli file format.
* Specifically, it affects the encoding of simple huffman tree for distances,
* see Specification RFC 7932 chapter 3.4.
*/
#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
#define BROTLI_LARGE_MIN_WBITS 10
/**
* The maximum supported large brotli window bits by the encoder and decoder.
* Large window brotli allows up to 62 bits, however the current encoder and
* decoder, designed for 32-bit integers, only support up to 30 bits maximum.
*/
#define BROTLI_LARGE_MAX_WBITS 30
/* Specification: 4. Encoding of distances */
#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
/**
* Maximal number of "postfix" bits.
*
* Number of "postfix" bits is stored as 2 bits in meta-block header.
*/
#define BROTLI_MAX_NPOSTFIX 3
#define BROTLI_MAX_NDIRECT 120
#define BROTLI_MAX_DISTANCE_BITS 24U
@@ -45,9 +73,22 @@
#define BROTLI_NUM_DISTANCE_SYMBOLS \
BROTLI_DISTANCE_ALPHABET_SIZE( \
BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932
brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and
NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */
#define BROTLI_MAX_DISTANCE 0x3FFFFFC
/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit
allows safe distance calculation without overflows, given the distance
alphabet size is limited to corresponding size
(see kLargeWindowDistanceCodeLimits). */
#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */
#define BROTLI_NUM_INS_COPY_CODES 24
/* 7.1. Context modes and context ID lookup for literals */
/* "context IDs for literals are in the range of 0..63" */
#define BROTLI_LITERAL_CONTEXT_BITS 6
@@ -61,4 +102,99 @@
#define BROTLI_WINDOW_GAP 16
#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
typedef struct BrotliDistanceCodeLimit {
uint32_t max_alphabet_size;
uint32_t max_distance;
} BrotliDistanceCodeLimit;
/* This function calculates maximal size of distance alphabet, such that the
distances greater than the given values can not be represented.
This limits are designed to support fast and safe 32-bit decoders.
"32-bit" means that signed integer values up to ((1 << 31) - 1) could be
safely expressed.
Brotli distance alphabet symbols do not represent consecutive distance
ranges. Each distance alphabet symbol (excluding direct distances and short
codes), represent interleaved (for NPOSTFIX > 0) range of distances.
A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved
range. Two consecutive groups require the same amount of "extra bits".
It is important that distance alphabet represents complete "groups".
To avoid complex logic on encoder side about interleaved ranges
it was decided to restrict both sides to complete distance code "groups".
*/
BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit(
uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) {
BrotliDistanceCodeLimit result;
/* Marking this function as unused, because not all files
including "constants.h" use it -> compiler warns about that. */
BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit);
if (max_distance <= ndirect) {
/* This case never happens / exists only for the sake of completeness. */
result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES;
result.max_distance = max_distance;
return result;
} else {
/* The first prohibited value. */
uint32_t forbidden_distance = max_distance + 1;
/* Subtract "directly" encoded region. */
uint32_t offset = forbidden_distance - ndirect - 1;
uint32_t ndistbits = 0;
uint32_t tmp;
uint32_t half;
uint32_t group;
/* Postfix for the last dcode in the group. */
uint32_t postfix = (1u << npostfix) - 1;
uint32_t extra;
uint32_t start;
/* Remove postfix and "head-start". */
offset = (offset >> npostfix) + 4;
/* Calculate the number of distance bits. */
tmp = offset / 2;
/* Poor-man's log2floor, to avoid extra dependencies. */
while (tmp != 0) {ndistbits++; tmp = tmp >> 1;}
/* One bit is covered with subrange addressing ("half"). */
ndistbits--;
/* Find subrange. */
half = (offset >> ndistbits) & 1;
/* Calculate the "group" part of dcode. */
group = ((ndistbits - 1) << 1) | half;
/* Calculated "group" covers the prohibited distance value. */
if (group == 0) {
/* This case is added for correctness; does not occur for limit > 128. */
result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES;
result.max_distance = ndirect;
return result;
}
/* Decrement "group", so it is the last permitted "group". */
group--;
/* After group was decremented, ndistbits and half must be recalculated. */
ndistbits = (group >> 1) + 1;
/* The last available distance in the subrange has all extra bits set. */
extra = (1u << ndistbits) - 1;
/* Calculate region start. NB: ndistbits >= 1. */
start = (1u << (ndistbits + 1)) - 4;
/* Move to subregion. */
start += (group & 1) << ndistbits;
/* Calculate the alphabet size. */
result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect +
BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
/* Calculate the maximal distance representable by alphabet. */
result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1;
return result;
}
}
/* Represents the range of values belonging to a prefix code:
[offset, offset + 2^nbits) */
typedef struct {
uint16_t offset;
uint8_t nbits;
} BrotliPrefixCodeRange;
/* "Soft-private", it is exported, but not "advertised" as API. */
BROTLI_COMMON_API extern const BrotliPrefixCodeRange
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
#endif /* BROTLI_COMMON_CONSTANTS_H_ */
+156
View File
@@ -0,0 +1,156 @@
#include "./context.h"
#include <brotli/types.h>
/* Common context lookup table for all context modes. */
const uint8_t _kBrotliContextLookupTable[2048] = {
/* CONTEXT_LSB6, last byte. */
0, 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,
0, 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,
0, 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,
0, 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,
/* CONTEXT_LSB6, second last byte, */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* CONTEXT_MSB6, last byte. */
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
/* CONTEXT_MSB6, second last byte, */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* CONTEXT_UTF8, last byte. */
/* ASCII range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
/* UTF8 continuation byte range. */
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
/* UTF8 lead byte range. */
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
/* CONTEXT_UTF8 second last byte. */
/* ASCII range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
/* UTF8 continuation byte range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* UTF8 lead byte range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
/* CONTEXT_SIGNED, second last byte. */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
};
+4 -152
View File
@@ -88,6 +88,7 @@
#ifndef BROTLI_COMMON_CONTEXT_H_
#define BROTLI_COMMON_CONTEXT_H_
#include <brotli/port.h>
#include <brotli/types.h>
typedef enum ContextType {
@@ -97,163 +98,14 @@ typedef enum ContextType {
CONTEXT_SIGNED = 3
} ContextType;
/* "Soft-private", it is exported, but not "advertised" as API. */
/* Common context lookup table for all context modes. */
static const uint8_t kContextLookup[2048] = {
/* CONTEXT_LSB6, last byte. */
0, 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,
0, 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,
0, 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,
0, 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,
/* CONTEXT_LSB6, second last byte, */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* CONTEXT_MSB6, last byte. */
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
/* CONTEXT_MSB6, second last byte, */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* CONTEXT_UTF8, last byte. */
/* ASCII range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
/* UTF8 continuation byte range. */
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
/* UTF8 lead byte range. */
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
/* CONTEXT_UTF8 second last byte. */
/* ASCII range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
/* UTF8 continuation byte range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* UTF8 lead byte range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
/* CONTEXT_SIGNED, second last byte. */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
};
BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048];
typedef const uint8_t* ContextLut;
/* typeof(MODE) == ContextType; returns ContextLut */
#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9])
#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9])
/* typeof(LUT) == ContextLut */
#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
+10 -1
View File
@@ -5,12 +5,13 @@
*/
#include "./dictionary.h"
#include "./platform.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#ifndef BROTLI_EXTERNAL_DICTIONARY_DATA
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
static const uint8_t kBrotliDictionaryData[] =
{
116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99,
@@ -5862,7 +5863,11 @@ static const uint8_t kBrotliDictionaryData[] =
;
#endif /* !BROTLI_EXTERNAL_DICTIONARY_DATA */
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
static const BrotliDictionary kBrotliDictionary = {
#else
static BrotliDictionary kBrotliDictionary = {
#endif
/* size_bits_by_length */
{
0, 0, 0, 0, 10, 10, 11, 11,
@@ -5895,9 +5900,13 @@ const BrotliDictionary* BrotliGetDictionary() {
}
void BrotliSetDictionaryData(const uint8_t* data) {
#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
if (!!data && !kBrotliDictionary.data) {
kBrotliDictionary.data = data;
}
#else
BROTLI_UNUSED(data); // Appease -Werror=unused-parameter
#endif
}
#if defined(__cplusplus) || defined(c_plusplus)
+22
View File
@@ -0,0 +1,22 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
#include <stdlib.h>
#include "./platform.h"
#include <brotli/types.h>
/* Default brotli_alloc_func */
void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
BROTLI_UNUSED(opaque);
return malloc(size);
}
/* Default brotli_free_func */
void BrotliDefaultFreeFunc(void* opaque, void* address) {
BROTLI_UNUSED(opaque);
free(address);
}
+43 -17
View File
@@ -24,12 +24,11 @@
#define BROTLI_COMMON_PLATFORM_H_
#include <string.h> /* memcpy */
#include <stdlib.h> /* malloc, free */
#include <brotli/port.h>
#include <brotli/types.h>
#if defined(OS_LINUX) || defined(OS_CYGWIN)
#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__)
#include <endian.h>
#elif defined(OS_FREEBSD)
#include <machine/endian.h>
@@ -41,6 +40,10 @@
#define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
#endif
#if BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
#include <intrin.h>
#endif
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
#include <assert.h>
#include <stdio.h>
@@ -308,8 +311,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
}
#else /* BROTLI_ALIGNED_READ */
/* Unaligned memory access is allowed: just cast pointer to requested type. */
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
defined(MEMORY_SANITIZER)
#if BROTLI_SANITIZED
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
will miss a bug if 08 is the first unaddressable byte.
@@ -334,7 +336,7 @@ extern "C" {
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
#else
#else /* BROTLI_SANITIZED */
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
return *(const uint16_t*)p;
}
@@ -356,7 +358,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
return (uint64_t) ((const brotli_unaligned_uint64_t*) p)[0];
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
@@ -374,7 +376,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
}
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
#endif /* BROTLI_64_BITS */
#endif /* ASAN / TSAN / MSAN */
#endif /* BROTLI_SANITIZED */
#endif /* BROTLI_ALIGNED_READ */
#if BROTLI_LITTLE_ENDIAN
@@ -466,20 +468,20 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
#endif
#if defined(BROTLI_ENABLE_LOG)
#define BROTLI_DCHECK(x) assert(x)
#define BROTLI_LOG(x) printf x
#else
#define BROTLI_DCHECK(x)
#define BROTLI_LOG(x)
#endif
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
#define BROTLI_DCHECK(x) assert(x)
static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
fflush(stderr);
}
#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
#else
#define BROTLI_DCHECK(x)
#define BROTLI_DUMP() (void)(0)
#endif
@@ -523,17 +525,41 @@ BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
(A)[(J)] = __brotli_swap_tmp; \
}
/* Default brotli_alloc_func */
static void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
BROTLI_UNUSED(opaque);
return malloc(size);
#if BROTLI_64_BITS
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
#define BROTLI_TZCNT64 __builtin_ctzll
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
#if defined(BROTLI_TARGET_X64)
#define BROTLI_TZCNT64 _tzcnt_u64
#else /* BROTLI_TARGET_X64 */
static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
uint32_t lsb;
_BitScanForward64(&lsb, x);
return lsb;
}
#define BROTLI_TZCNT64 BrotliBsf64Msvc
#endif /* BROTLI_TARGET_X64 */
#endif /* __builtin_ctzll */
#endif /* BROTLI_64_BITS */
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x))
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) {
unsigned long msb;
_BitScanReverse(&msb, x);
return (uint32_t)msb;
}
#define BROTLI_BSR32 BrotliBsr32Msvc
#endif /* __builtin_clz */
/* Default brotli_alloc_func */
BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size);
/* Default brotli_free_func */
static void BrotliDefaultFreeFunc(void* opaque, void* address) {
BROTLI_UNUSED(opaque);
free(address);
}
BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address);
BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
+59 -3
View File
@@ -24,8 +24,8 @@ static const char kPrefixSuffix[217] =
/* 8x _0 _ _3 _8 _C _E _ _1 _7 _F */
" not \3er \3al \4ful \4ive \5less \4es"
/* Ax _5 _9 _D _2 _7 _D */
"t \4ize \2\xc2\xa0\4ous \5 the \2e \0";
/* Cx _2 _7___ ___ _A _F _5 _8 */
"t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */
/* Cx _2 _7___ ___ _A _F _5 _8 */
static const uint16_t kPrefixSuffixMap[50] = {
0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25,
@@ -160,12 +160,13 @@ static const uint8_t kTransformsData[] = {
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
};
static BrotliTransforms kBrotliTransforms = {
static const BrotliTransforms kBrotliTransforms = {
sizeof(kPrefixSuffix),
(const uint8_t*)kPrefixSuffix,
kPrefixSuffixMap,
sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])),
kTransformsData,
NULL, /* no extra parameters */
{0, 12, 27, 23, 42, 63, 56, 48, 59, 64}
};
@@ -190,6 +191,48 @@ static int ToUpperCase(uint8_t* p) {
return 3;
}
static int Shift(uint8_t* word, int word_len, uint16_t parameter) {
/* Limited sign extension: scalar < (1 << 24). */
uint32_t scalar =
(parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u));
if (word[0] < 0x80) {
/* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
scalar += (uint32_t)word[0];
word[0] = (uint8_t)(scalar & 0x7Fu);
return 1;
} else if (word[0] < 0xC0) {
/* Continuation / 10AAAAAA. */
return 1;
} else if (word[0] < 0xE0) {
/* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
if (word_len < 2) return 1;
scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u));
word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F));
word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F));
return 2;
} else if (word[0] < 0xF0) {
/* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
if (word_len < 3) return word_len;
scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) |
((word[0] & 0x0Fu) << 12u));
word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F));
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F));
word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F));
return 3;
} else if (word[0] < 0xF8) {
/* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
if (word_len < 4) return word_len;
scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) |
((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u));
word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07));
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F));
word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F));
word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F));
return 4;
}
return 1;
}
int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
const BrotliTransforms* transforms, int transform_idx) {
int idx = 0;
@@ -221,6 +264,19 @@ int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
uppercase += step;
len -= step;
}
} else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) {
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
+ (transforms->params[transform_idx * 2 + 1] << 8u));
Shift(&dst[idx - len], len, param);
} else if (t == BROTLI_TRANSFORM_SHIFT_ALL) {
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
+ (transforms->params[transform_idx * 2 + 1] << 8u));
uint8_t* shift = &dst[idx - len];
while (len > 0) {
int step = Shift(shift, len, param);
shift += step;
len -= step;
}
}
}
{
+5
View File
@@ -37,6 +37,8 @@ enum BrotliWordTransformType {
BROTLI_TRANSFORM_OMIT_FIRST_7 = 18,
BROTLI_TRANSFORM_OMIT_FIRST_8 = 19,
BROTLI_TRANSFORM_OMIT_FIRST_9 = 20,
BROTLI_TRANSFORM_SHIFT_FIRST = 21,
BROTLI_TRANSFORM_SHIFT_ALL = 22,
BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */
};
@@ -50,6 +52,9 @@ typedef struct BrotliTransforms {
uint32_t num_transforms;
/* Each entry is a [prefix_id, transform, suffix_id] triplet. */
const uint8_t* transforms;
/* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL,
must be NULL if and only if no such transforms are present. */
const uint8_t* params;
/* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""].
0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""].
-1, if cut-off transform does not exist. */
+2 -2
View File
@@ -14,13 +14,13 @@
BrotliEncoderVersion methods. */
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
#define BROTLI_VERSION 0x1000007
#define BROTLI_VERSION 0x1000009
/* This macro is used by build system to produce Libtool-friendly soname. See
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
*/
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
#define BROTLI_ABI_VERSION 0x1007000
#define BROTLI_ABI_VERSION 0x1009000
#endif /* BROTLI_COMMON_VERSION_H_ */
+28
View File
@@ -15,6 +15,17 @@
extern "C" {
#endif
const uint32_t kBrotliBitMask[33] = { 0x00000000,
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
};
void BrotliInitBitReader(BrotliBitReader* const br) {
br->val_ = 0;
br->bit_pos_ = sizeof(br->val_) << 3;
@@ -43,6 +54,23 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
return BROTLI_TRUE;
}
BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br,
uint32_t n_bits, uint32_t* val) {
uint32_t low_val;
uint32_t high_val;
BrotliBitReaderState memento;
BROTLI_DCHECK(n_bits <= 32);
BROTLI_DCHECK(n_bits > 24);
BrotliBitReaderSaveState(br, &memento);
if (!BrotliSafeReadBits(br, 16, &low_val) ||
!BrotliSafeReadBits(br, n_bits - 16, &high_val)) {
BrotliBitReaderRestoreState(br, &memento);
return BROTLI_FALSE;
}
*val = low_val | (high_val << 16);
return BROTLI_TRUE;
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
+58 -16
View File
@@ -11,6 +11,7 @@
#include <string.h> /* memcpy */
#include "../common/constants.h"
#include "../common/platform.h"
#include <brotli/types.h>
@@ -20,16 +21,7 @@ extern "C" {
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
static const uint32_t kBitMask[33] = { 0x00000000,
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
};
BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33];
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
@@ -37,7 +29,7 @@ static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
return ~((0xFFFFFFFFu) << n);
} else {
return kBitMask[n];
return kBrotliBitMask[n];
}
}
@@ -65,6 +57,12 @@ BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
reading. */
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
the main code-path. Never called for RFC brotli streams, required only for
"large-window" mode and other extensions. */
BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val);
static BROTLI_INLINE void BrotliBitReaderSaveState(
BrotliBitReader* const from, BrotliBitReaderState* to) {
to->val_ = from->val_;
@@ -87,8 +85,11 @@ static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
}
/* Returns amount of unread bytes the bit reader still has buffered from the
BrotliInput, including whole bytes in br->val_. */
BrotliInput, including whole bytes in br->val_. Result is capped with
maximal ring-buffer size (larger number won't be utilized anyway). */
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS;
if (br->avail_in > kCap) return kCap;
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
}
@@ -237,15 +238,17 @@ static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
static BROTLI_INLINE void BrotliTakeBits(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
BROTLI_LOG(("[BrotliReadBits] %d %d %d val: %6x\n",
BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n",
(int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val));
BrotliDropBits(br, n_bits);
}
/* Reads the specified number of bits from |br| and advances the bit pos.
Assumes that there is enough input to perform BrotliFillBitWindow. */
static BROTLI_INLINE uint32_t BrotliReadBits(
Assumes that there is enough input to perform BrotliFillBitWindow.
Up to 24 bits are allowed to be requested from this method. */
static BROTLI_INLINE uint32_t BrotliReadBits24(
BrotliBitReader* const br, uint32_t n_bits) {
BROTLI_DCHECK(n_bits <= 24);
if (BROTLI_64_BITS || (n_bits <= 16)) {
uint32_t val;
BrotliFillBitWindow(br, n_bits);
@@ -262,10 +265,32 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
}
}
/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
static BROTLI_INLINE uint32_t BrotliReadBits32(
BrotliBitReader* const br, uint32_t n_bits) {
BROTLI_DCHECK(n_bits <= 32);
if (BROTLI_64_BITS || (n_bits <= 16)) {
uint32_t val;
BrotliFillBitWindow(br, n_bits);
BrotliTakeBits(br, n_bits, &val);
return val;
} else {
uint32_t low_val;
uint32_t high_val;
BrotliFillBitWindow(br, 16);
BrotliTakeBits(br, 16, &low_val);
BrotliFillBitWindow(br, 16);
BrotliTakeBits(br, n_bits - 16, &high_val);
return low_val | (high_val << 16);
}
}
/* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there
is not enough input. |n_bits| MUST be positive. */
is not enough input. |n_bits| MUST be positive.
Up to 24 bits are allowed to be requested from this method. */
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
BROTLI_DCHECK(n_bits <= 24);
while (BrotliGetAvailableBits(br) < n_bits) {
if (!BrotliPullByte(br)) {
return BROTLI_FALSE;
@@ -275,6 +300,23 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
return BROTLI_TRUE;
}
/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
BROTLI_DCHECK(n_bits <= 32);
if (BROTLI_64_BITS || (n_bits <= 24)) {
while (BrotliGetAvailableBits(br) < n_bits) {
if (!BrotliPullByte(br)) {
return BROTLI_FALSE;
}
}
BrotliTakeBits(br, n_bits, val);
return BROTLI_TRUE;
} else {
return BrotliSafeReadBits32Slow(br, n_bits, val);
}
}
/* Advances the bit reader position to the next byte boundary and verifies
that any skipped bits are set to zero. */
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
+353 -251
View File
@@ -41,7 +41,8 @@ extern "C" {
/* We need the slack region for the following reasons:
- doing up to two 16-byte copies for fast backward copying
- inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
- inserting transformed dictionary word:
5 prefix + 24 base + 8 suffix */
static const uint32_t kRingBufferWriteAheadSlack = 42;
static const uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = {
@@ -274,7 +275,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
s->loop_counter = i;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
if (i + 1 == s->size_nibbles && s->size_nibbles > 4 && bits == 0) {
if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 4 &&
bits == 0) {
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
}
s->meta_block_remaining_len |= (int)(bits << (i * 4));
@@ -323,7 +325,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
s->loop_counter = i;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
if (i + 1 == s->size_nibbles && s->size_nibbles > 1 && bits == 0) {
if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 1 &&
bits == 0) {
return BROTLI_FAILURE(
BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
}
@@ -470,32 +473,34 @@ static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) {
Totally 1..4 symbols are read, 1..11 bits each.
The list of symbols MUST NOT contain duplicates. */
static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols(
uint32_t alphabet_size, uint32_t max_symbol, BrotliDecoderState* s) {
uint32_t alphabet_size_max, uint32_t alphabet_size_limit,
BrotliDecoderState* s) {
/* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
BrotliBitReader* br = &s->br;
uint32_t max_bits = Log2Floor(alphabet_size - 1);
uint32_t i = s->sub_loop_counter;
uint32_t num_symbols = s->symbol;
BrotliMetablockHeaderArena* h = &s->arena.header;
uint32_t max_bits = Log2Floor(alphabet_size_max - 1);
uint32_t i = h->sub_loop_counter;
uint32_t num_symbols = h->symbol;
while (i <= num_symbols) {
uint32_t v;
if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) {
s->sub_loop_counter = i;
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
h->sub_loop_counter = i;
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
if (v >= max_symbol) {
if (v >= alphabet_size_limit) {
return
BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
}
s->symbols_lists_array[i] = (uint16_t)v;
BROTLI_LOG_UINT(s->symbols_lists_array[i]);
h->symbols_lists_array[i] = (uint16_t)v;
BROTLI_LOG_UINT(h->symbols_lists_array[i]);
++i;
}
for (i = 0; i < num_symbols; ++i) {
uint32_t k = i + 1;
for (; k <= num_symbols; ++k) {
if (s->symbols_lists_array[i] == s->symbols_lists_array[k]) {
if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) {
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
}
}
@@ -588,27 +593,28 @@ static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len,
static BrotliDecoderErrorCode ReadSymbolCodeLengths(
uint32_t alphabet_size, BrotliDecoderState* s) {
BrotliBitReader* br = &s->br;
uint32_t symbol = s->symbol;
uint32_t repeat = s->repeat;
uint32_t space = s->space;
uint32_t prev_code_len = s->prev_code_len;
uint32_t repeat_code_len = s->repeat_code_len;
uint16_t* symbol_lists = s->symbol_lists;
uint16_t* code_length_histo = s->code_length_histo;
int* next_symbol = s->next_symbol;
BrotliMetablockHeaderArena* h = &s->arena.header;
uint32_t symbol = h->symbol;
uint32_t repeat = h->repeat;
uint32_t space = h->space;
uint32_t prev_code_len = h->prev_code_len;
uint32_t repeat_code_len = h->repeat_code_len;
uint16_t* symbol_lists = h->symbol_lists;
uint16_t* code_length_histo = h->code_length_histo;
int* next_symbol = h->next_symbol;
if (!BrotliWarmupBitReader(br)) {
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
while (symbol < alphabet_size && space > 0) {
const HuffmanCode* p = s->table;
const HuffmanCode* p = h->table;
uint32_t code_len;
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
s->symbol = symbol;
s->repeat = repeat;
s->prev_code_len = prev_code_len;
s->repeat_code_len = repeat_code_len;
s->space = space;
h->symbol = symbol;
h->repeat = repeat;
h->prev_code_len = prev_code_len;
h->repeat_code_len = repeat_code_len;
h->space = space;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
BrotliFillBitWindow16(br);
@@ -630,16 +636,17 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths(
symbol_lists, code_length_histo, next_symbol);
}
}
s->space = space;
h->space = space;
return BROTLI_DECODER_SUCCESS;
}
static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
uint32_t alphabet_size, BrotliDecoderState* s) {
BrotliBitReader* br = &s->br;
BrotliMetablockHeaderArena* h = &s->arena.header;
BROTLI_BOOL get_byte = BROTLI_FALSE;
while (s->symbol < alphabet_size && s->space > 0) {
const HuffmanCode* p = s->table;
while (h->symbol < alphabet_size && h->space > 0) {
const HuffmanCode* p = h->table;
uint32_t code_len;
uint32_t available_bits;
uint32_t bits = 0;
@@ -659,9 +666,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p));
ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space,
&s->prev_code_len, s->symbol_lists, s->code_length_histo,
s->next_symbol);
ProcessSingleCodeLength(code_len, &h->symbol, &h->repeat, &h->space,
&h->prev_code_len, h->symbol_lists, h->code_length_histo,
h->next_symbol);
} else { /* code_len == 16..17, extra_bits == 2..3 */
uint32_t extra_bits = code_len - 14U;
uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) &
@@ -672,9 +679,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
}
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits);
ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
&s->symbol, &s->repeat, &s->space, &s->prev_code_len,
&s->repeat_code_len, s->symbol_lists, s->code_length_histo,
s->next_symbol);
&h->symbol, &h->repeat, &h->space, &h->prev_code_len,
&h->repeat_code_len, h->symbol_lists, h->code_length_histo,
h->next_symbol);
}
}
return BROTLI_DECODER_SUCCESS;
@@ -684,9 +691,10 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
Each code is 2..4 bits long. In total 30..72 bits are used. */
static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
BrotliBitReader* br = &s->br;
uint32_t num_codes = s->repeat;
unsigned space = s->space;
uint32_t i = s->sub_loop_counter;
BrotliMetablockHeaderArena* h = &s->arena.header;
uint32_t num_codes = h->repeat;
unsigned space = h->space;
uint32_t i = h->sub_loop_counter;
for (; i < BROTLI_CODE_LENGTH_CODES; ++i) {
const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
uint32_t ix;
@@ -699,21 +707,21 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
ix = 0;
}
if (kCodeLengthPrefixLength[ix] > available_bits) {
s->sub_loop_counter = i;
s->repeat = num_codes;
s->space = space;
s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
h->sub_loop_counter = i;
h->repeat = num_codes;
h->space = space;
h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
}
v = kCodeLengthPrefixValue[ix];
BrotliDropBits(br, kCodeLengthPrefixLength[ix]);
s->code_length_code_lengths[code_len_idx] = (uint8_t)v;
BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx);
h->code_length_code_lengths[code_len_idx] = (uint8_t)v;
BROTLI_LOG_ARRAY_INDEX(h->code_length_code_lengths, code_len_idx);
if (v != 0) {
space = space - (32U >> v);
++num_codes;
++s->code_length_histo[v];
++h->code_length_histo[v];
if (space - 1U >= 32U) {
/* space is 0 or wrapped around. */
break;
@@ -737,49 +745,48 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
encoded with predefined entropy code. 32 - 74 bits are used.
B.2) Decoded table is used to decode code lengths of symbols in resulting
Huffman table. In worst case 3520 bits are read. */
static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
uint32_t max_symbol,
static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max,
uint32_t alphabet_size_limit,
HuffmanCode* table,
uint32_t* opt_table_size,
BrotliDecoderState* s) {
BrotliBitReader* br = &s->br;
/* Unnecessary masking, but might be good for safety. */
alphabet_size &= 0x7FF;
BrotliMetablockHeaderArena* h = &s->arena.header;
/* State machine. */
for (;;) {
switch (s->substate_huffman) {
switch (h->substate_huffman) {
case BROTLI_STATE_HUFFMAN_NONE:
if (!BrotliSafeReadBits(br, 2, &s->sub_loop_counter)) {
if (!BrotliSafeReadBits(br, 2, &h->sub_loop_counter)) {
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
BROTLI_LOG_UINT(s->sub_loop_counter);
BROTLI_LOG_UINT(h->sub_loop_counter);
/* The value is used as follows:
1 for simple code;
0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
if (s->sub_loop_counter != 1) {
s->space = 32;
s->repeat = 0; /* num_codes */
memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo[0]) *
if (h->sub_loop_counter != 1) {
h->space = 32;
h->repeat = 0; /* num_codes */
memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo[0]) *
(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1));
memset(&s->code_length_code_lengths[0], 0,
sizeof(s->code_length_code_lengths));
s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
memset(&h->code_length_code_lengths[0], 0,
sizeof(h->code_length_code_lengths));
h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
continue;
}
/* Fall through. */
case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE:
/* Read symbols, codes & code lengths directly. */
if (!BrotliSafeReadBits(br, 2, &s->symbol)) { /* num_symbols */
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
if (!BrotliSafeReadBits(br, 2, &h->symbol)) { /* num_symbols */
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
s->sub_loop_counter = 0;
h->sub_loop_counter = 0;
/* Fall through. */
case BROTLI_STATE_HUFFMAN_SIMPLE_READ: {
BrotliDecoderErrorCode result =
ReadSimpleHuffmanSymbols(alphabet_size, max_symbol, s);
ReadSimpleHuffmanSymbols(alphabet_size_max, alphabet_size_limit, s);
if (result != BROTLI_DECODER_SUCCESS) {
return result;
}
@@ -788,21 +795,21 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: {
uint32_t table_size;
if (s->symbol == 3) {
if (h->symbol == 3) {
uint32_t bits;
if (!BrotliSafeReadBits(br, 1, &bits)) {
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
s->symbol += bits;
h->symbol += bits;
}
BROTLI_LOG_UINT(s->symbol);
BROTLI_LOG_UINT(h->symbol);
table_size = BrotliBuildSimpleHuffmanTable(
table, HUFFMAN_TABLE_BITS, s->symbols_lists_array, s->symbol);
table, HUFFMAN_TABLE_BITS, h->symbols_lists_array, h->symbol);
if (opt_table_size) {
*opt_table_size = table_size;
}
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
return BROTLI_DECODER_SUCCESS;
}
@@ -813,44 +820,45 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
if (result != BROTLI_DECODER_SUCCESS) {
return result;
}
BrotliBuildCodeLengthsHuffmanTable(s->table,
s->code_length_code_lengths,
s->code_length_histo);
memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo));
BrotliBuildCodeLengthsHuffmanTable(h->table,
h->code_length_code_lengths,
h->code_length_histo);
memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo));
for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) {
s->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
s->symbol_lists[s->next_symbol[i]] = 0xFFFF;
h->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
h->symbol_lists[h->next_symbol[i]] = 0xFFFF;
}
s->symbol = 0;
s->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
s->repeat = 0;
s->repeat_code_len = 0;
s->space = 32768;
s->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
h->symbol = 0;
h->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
h->repeat = 0;
h->repeat_code_len = 0;
h->space = 32768;
h->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
}
/* Fall through. */
case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: {
uint32_t table_size;
BrotliDecoderErrorCode result = ReadSymbolCodeLengths(max_symbol, s);
BrotliDecoderErrorCode result = ReadSymbolCodeLengths(
alphabet_size_limit, s);
if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
result = SafeReadSymbolCodeLengths(max_symbol, s);
result = SafeReadSymbolCodeLengths(alphabet_size_limit, s);
}
if (result != BROTLI_DECODER_SUCCESS) {
return result;
}
if (s->space != 0) {
BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)s->space));
if (h->space != 0) {
BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)h->space));
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
}
table_size = BrotliBuildHuffmanTable(
table, HUFFMAN_TABLE_BITS, s->symbol_lists, s->code_length_histo);
table, HUFFMAN_TABLE_BITS, h->symbol_lists, h->code_length_histo);
if (opt_table_size) {
*opt_table_size = table_size;
}
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
return BROTLI_DECODER_SUCCESS;
}
@@ -867,8 +875,8 @@ static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table,
uint32_t code;
uint32_t nbits;
code = ReadSymbol(table, br);
nbits = kBlockLengthPrefixCode[code].nbits; /* nbits == 2..24 */
return kBlockLengthPrefixCode[code].offset + BrotliReadBits(br, nbits);
nbits = _kBrotliPrefixCodeRanges[code].nbits; /* nbits == 2..24 */
return _kBrotliPrefixCodeRanges[code].offset + BrotliReadBits24(br, nbits);
}
/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
@@ -886,13 +894,14 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength(
}
{
uint32_t bits;
uint32_t nbits = kBlockLengthPrefixCode[index].nbits; /* nbits == 2..24 */
uint32_t nbits = _kBrotliPrefixCodeRanges[index].nbits;
uint32_t offset = _kBrotliPrefixCodeRanges[index].offset;
if (!BrotliSafeReadBits(br, nbits, &bits)) {
s->block_length_index = index;
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX;
return BROTLI_FALSE;
}
*result = kBlockLengthPrefixCode[index].offset + bits;
*result = offset + bits;
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
return BROTLI_TRUE;
}
@@ -952,22 +961,22 @@ static BROTLI_NOINLINE void InverseMoveToFrontTransform(
/* Decodes a series of Huffman table using ReadHuffmanCode function. */
static BrotliDecoderErrorCode HuffmanTreeGroupDecode(
HuffmanTreeGroup* group, BrotliDecoderState* s) {
if (s->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
s->next = group->codes;
s->htree_index = 0;
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
BrotliMetablockHeaderArena* h = &s->arena.header;
if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
h->next = group->codes;
h->htree_index = 0;
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
}
while (s->htree_index < group->num_htrees) {
while (h->htree_index < group->num_htrees) {
uint32_t table_size;
BrotliDecoderErrorCode result =
ReadHuffmanCode(group->alphabet_size, group->max_symbol,
s->next, &table_size, s);
BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max,
group->alphabet_size_limit, h->next, &table_size, s);
if (result != BROTLI_DECODER_SUCCESS) return result;
group->htrees[s->htree_index] = s->next;
s->next += table_size;
++s->htree_index;
group->htrees[h->htree_index] = h->next;
h->next += table_size;
++h->htree_index;
}
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
return BROTLI_DECODER_SUCCESS;
}
@@ -985,15 +994,16 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
BrotliDecoderState* s) {
BrotliBitReader* br = &s->br;
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
BrotliMetablockHeaderArena* h = &s->arena.header;
switch ((int)s->substate_context_map) {
switch ((int)h->substate_context_map) {
case BROTLI_STATE_CONTEXT_MAP_NONE:
result = DecodeVarLenUint8(s, br, num_htrees);
if (result != BROTLI_DECODER_SUCCESS) {
return result;
}
(*num_htrees)++;
s->context_index = 0;
h->context_index = 0;
BROTLI_LOG_UINT(context_map_size);
BROTLI_LOG_UINT(*num_htrees);
*context_map_arg =
@@ -1005,7 +1015,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
memset(*context_map_arg, 0, (size_t)context_map_size);
return BROTLI_DECODER_SUCCESS;
}
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
/* Fall through. */
case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: {
@@ -1016,38 +1026,38 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
if ((bits & 1) != 0) { /* Use RLE for zeros. */
s->max_run_length_prefix = (bits >> 1) + 1;
h->max_run_length_prefix = (bits >> 1) + 1;
BrotliDropBits(br, 5);
} else {
s->max_run_length_prefix = 0;
h->max_run_length_prefix = 0;
BrotliDropBits(br, 1);
}
BROTLI_LOG_UINT(s->max_run_length_prefix);
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
BROTLI_LOG_UINT(h->max_run_length_prefix);
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
}
/* Fall through. */
case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: {
uint32_t alphabet_size = *num_htrees + s->max_run_length_prefix;
uint32_t alphabet_size = *num_htrees + h->max_run_length_prefix;
result = ReadHuffmanCode(alphabet_size, alphabet_size,
s->context_map_table, NULL, s);
h->context_map_table, NULL, s);
if (result != BROTLI_DECODER_SUCCESS) return result;
s->code = 0xFFFF;
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
h->code = 0xFFFF;
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
}
/* Fall through. */
case BROTLI_STATE_CONTEXT_MAP_DECODE: {
uint32_t context_index = s->context_index;
uint32_t max_run_length_prefix = s->max_run_length_prefix;
uint32_t context_index = h->context_index;
uint32_t max_run_length_prefix = h->max_run_length_prefix;
uint8_t* context_map = *context_map_arg;
uint32_t code = s->code;
uint32_t code = h->code;
BROTLI_BOOL skip_preamble = (code != 0xFFFF);
while (context_index < context_map_size || skip_preamble) {
if (!skip_preamble) {
if (!SafeReadSymbol(s->context_map_table, br, &code)) {
s->code = 0xFFFF;
s->context_index = context_index;
if (!SafeReadSymbol(h->context_map_table, br, &code)) {
h->code = 0xFFFF;
h->context_index = context_index;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
BROTLI_LOG_UINT(code);
@@ -1068,8 +1078,8 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
{
uint32_t reps;
if (!BrotliSafeReadBits(br, code, &reps)) {
s->code = code;
s->context_index = context_index;
h->code = code;
h->context_index = context_index;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
reps += 1U << code;
@@ -1089,13 +1099,13 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: {
uint32_t bits;
if (!BrotliSafeReadBits(br, 1, &bits)) {
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
if (bits != 0) {
InverseMoveToFrontTransform(*context_map_arg, context_map_size, s);
}
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
return BROTLI_DECODER_SUCCESS;
}
@@ -1457,32 +1467,28 @@ static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) {
}
static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) {
if (s->distance_code == 0) {
--s->dist_rb_idx;
s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
int offset = s->distance_code - 3;
if (s->distance_code <= 3) {
/* Compensate double distance-ring-buffer roll for dictionary items. */
s->distance_context = 1;
s->distance_context = 1 >> s->distance_code;
s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3];
s->dist_rb_idx -= s->distance_context;
} else {
int distance_code = s->distance_code << 1;
/* kDistanceShortCodeIndexOffset has 2-bit values from LSB:
3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
const uint32_t kDistanceShortCodeIndexOffset = 0xAAAFFF1B;
/* kDistanceShortCodeValueOffset has 2-bit values from LSB:
-0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */
const uint32_t kDistanceShortCodeValueOffset = 0xFA5FA500;
int v = (s->dist_rb_idx +
(int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3;
s->distance_code = s->dist_rb[v];
v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3;
if ((distance_code & 0x3) != 0) {
s->distance_code += v;
int index_delta = 3;
int delta;
int base = s->distance_code - 10;
if (s->distance_code < 10) {
base = s->distance_code - 4;
} else {
s->distance_code -= v;
if (s->distance_code <= 0) {
/* A huge distance will cause a BROTLI_FAILURE() soon.
This is a little faster than failing here. */
s->distance_code = 0x7FFFFFFF;
}
index_delta = 2;
}
/* Unpack one of six 4-bit values. */
delta = ((0x605142 >> (4 * base)) & 0xF) - 3;
s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta;
if (s->distance_code <= 0) {
/* A huge distance will cause a BROTLI_FAILURE() soon.
This is a little faster than failing here. */
s->distance_code = 0x7FFFFFFF;
}
}
}
@@ -1497,62 +1503,153 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBits(
}
}
static BROTLI_INLINE BROTLI_BOOL SafeReadBits32(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
if (n_bits != 0) {
return BrotliSafeReadBits32(br, n_bits, val);
} else {
*val = 0;
return BROTLI_TRUE;
}
}
/*
RFC 7932 Section 4 with "..." shortenings and "[]" emendations.
Each distance ... is represented with a pair <distance code, extra bits>...
The distance code is encoded using a prefix code... The number of extra bits
can be 0..24... Two additional parameters: NPOSTFIX (0..3), and ...
NDIRECT (0..120) ... are encoded in the meta-block header...
The first 16 distance symbols ... reference past distances... ring buffer ...
Next NDIRECT distance symbols ... represent distances from 1 to NDIRECT...
[For] distance symbols 16 + NDIRECT and greater ... the number of extra bits
... is given by the following formula:
[ xcode = dcode - NDIRECT - 16 ]
ndistbits = 1 + [ xcode ] >> (NPOSTFIX + 1)
...
*/
/*
RFC 7932 Section 9.2 with "..." shortenings and "[]" emendations.
... to get the actual value of the parameter NDIRECT, left-shift this
four-bit number by NPOSTFIX bits ...
*/
/* Remaining formulas from RFC 7932 Section 4 could be rewritten as following:
alphabet_size = 16 + NDIRECT + (max_distbits << (NPOSTFIX + 1))
half = ((xcode >> NPOSTFIX) & 1) << ndistbits
postfix = xcode & ((1 << NPOSTFIX) - 1)
range_start = 2 * (1 << ndistbits - 1 - 1)
distance = (range_start + half + extra) << NPOSTFIX + postfix + NDIRECT + 1
NB: ndistbits >= 1 -> range_start >= 0
NB: range_start has factor 2, as the range is covered by 2 "halves"
NB: extra -1 offset in range_start formula covers the absence of
ndistbits = 0 case
NB: when NPOSTFIX = 0, NDIRECT is not greater than 15
In other words, xcode has the following binary structure - XXXHPPP:
- XXX represent the number of extra distance bits
- H selects upper / lower range of distances
- PPP represent "postfix"
"Regular" distance encoding has NPOSTFIX = 0; omitting the postfix part
simplifies distance calculation.
Using NPOSTFIX > 0 allows cheaper encoding of regular structures, e.g. where
most of distances have the same reminder of division by 2/4/8. For example,
the table of int32_t values that come from different sources; if it is likely
that 3 highest bytes of values from the same source are the same, then
copy distance often looks like 4x + y.
Distance calculation could be rewritten to:
ndistbits = NDISTBITS(NDIRECT, NPOSTFIX)[dcode]
distance = OFFSET(NDIRECT, NPOSTFIX)[dcode] + extra << NPOSTFIX
NDISTBITS and OFFSET could be pre-calculated, as NDIRECT and NPOSTFIX could
change only once per meta-block.
*/
/* Calculates distance lookup table.
NB: it is possible to have all 64 tables precalculated. */
static void CalculateDistanceLut(BrotliDecoderState* s) {
BrotliMetablockBodyArena* b = &s->arena.body;
uint32_t npostfix = s->distance_postfix_bits;
uint32_t ndirect = s->num_direct_distance_codes;
uint32_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit;
uint32_t postfix = 1u << npostfix;
uint32_t j;
uint32_t bits = 1;
uint32_t half = 0;
/* Skip short codes. */
uint32_t i = BROTLI_NUM_DISTANCE_SHORT_CODES;
/* Fill direct codes. */
for (j = 0; j < ndirect; ++j) {
b->dist_extra_bits[i] = 0;
b->dist_offset[i] = j + 1;
++i;
}
/* Fill regular distance codes. */
while (i < alphabet_size_limit) {
uint32_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
/* Always fill the complete group. */
for (j = 0; j < postfix; ++j) {
b->dist_extra_bits[i] = (uint8_t)bits;
b->dist_offset[i] = base + j;
++i;
}
bits = bits + half;
half = half ^ 1;
}
}
/* Precondition: s->distance_code < 0. */
static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal(
int safe, BrotliDecoderState* s, BrotliBitReader* br) {
int distval;
BrotliMetablockBodyArena* b = &s->arena.body;
uint32_t code;
uint32_t bits;
BrotliBitReaderState memento;
HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index];
if (!safe) {
s->distance_code = (int)ReadSymbol(distance_tree, br);
code = ReadSymbol(distance_tree, br);
} else {
uint32_t code;
BrotliBitReaderSaveState(br, &memento);
if (!SafeReadSymbol(distance_tree, br, &code)) {
return BROTLI_FALSE;
}
s->distance_code = (int)code;
}
--s->block_length[2];
/* Convert the distance code to the actual distance by possibly
looking up past distances from the s->ringbuffer. */
looking up past distances from the s->dist_rb. */
s->distance_context = 0;
if ((s->distance_code & ~0xF) == 0) {
if ((code & ~0xFu) == 0) {
s->distance_code = (int)code;
TakeDistanceFromRingBuffer(s);
--s->block_length[2];
return BROTLI_TRUE;
}
distval = s->distance_code - (int)s->num_direct_distance_codes;
if (distval >= 0) {
uint32_t nbits;
int postfix;
int offset;
if (!safe && (s->distance_postfix_bits == 0)) {
nbits = ((uint32_t)distval >> 1) + 1;
offset = ((2 + (distval & 1)) << nbits) - 4;
s->distance_code = (int)s->num_direct_distance_codes + offset +
(int)BrotliReadBits(br, nbits);
} else {
/* This branch also works well when s->distance_postfix_bits == 0. */
uint32_t bits;
postfix = distval & s->distance_postfix_mask;
distval >>= s->distance_postfix_bits;
nbits = ((uint32_t)distval >> 1) + 1;
if (safe) {
if (!SafeReadBits(br, nbits, &bits)) {
s->distance_code = -1; /* Restore precondition. */
BrotliBitReaderRestoreState(br, &memento);
return BROTLI_FALSE;
}
} else {
bits = BrotliReadBits(br, nbits);
}
offset = ((2 + (distval & 1)) << nbits) - 4;
s->distance_code = (int)s->num_direct_distance_codes +
((offset + (int)bits) << s->distance_postfix_bits) + postfix;
if (!safe) {
bits = BrotliReadBits32(br, b->dist_extra_bits[code]);
} else {
if (!SafeReadBits32(br, b->dist_extra_bits[code], &bits)) {
++s->block_length[2];
BrotliBitReaderRestoreState(br, &memento);
return BROTLI_FALSE;
}
}
s->distance_code = s->distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
--s->block_length[2];
s->distance_code =
(int)(b->dist_offset[code] + (bits << s->distance_postfix_bits));
return BROTLI_TRUE;
}
@@ -1588,9 +1685,9 @@ static BROTLI_INLINE BROTLI_BOOL ReadCommandInternal(
*insert_length = v.insert_len_offset;
if (!safe) {
if (BROTLI_PREDICT_FALSE(v.insert_len_extra_bits != 0)) {
insert_len_extra = BrotliReadBits(br, v.insert_len_extra_bits);
insert_len_extra = BrotliReadBits24(br, v.insert_len_extra_bits);
}
copy_length = BrotliReadBits(br, v.copy_len_extra_bits);
copy_length = BrotliReadBits24(br, v.copy_len_extra_bits);
} else {
if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) ||
!SafeReadBits(br, v.copy_len_extra_bits, &copy_length)) {
@@ -1935,21 +2032,6 @@ static BROTLI_NOINLINE BrotliDecoderErrorCode SafeProcessCommands(
return ProcessCommandsInternal(1, s);
}
/* Returns the maximum number of distance symbols which can only represent
distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */
static uint32_t BrotliMaxDistanceSymbol(uint32_t ndirect, uint32_t npostfix) {
static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
static const uint32_t diff[BROTLI_MAX_NPOSTFIX + 1] = {73, 126, 228, 424};
uint32_t postfix = 1U << npostfix;
if (ndirect < bound[npostfix]) {
return ndirect + diff[npostfix] + postfix;
} else if (ndirect > bound[npostfix] + postfix) {
return ndirect + diff[npostfix];
} else {
return bound[npostfix] + diff[npostfix] + postfix;
}
}
BrotliDecoderResult BrotliDecoderDecompress(
size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
uint8_t* decoded_buffer) {
@@ -2167,33 +2249,23 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
s->state = BROTLI_STATE_UNCOMPRESSED;
break;
}
s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER;
/* Fall through. */
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: {
BrotliMetablockHeaderArena* h = &s->arena.header;
s->loop_counter = 0;
/* Initialize compressed metablock header arena. */
h->sub_loop_counter = 0;
/* Make small negative indexes addressable. */
h->symbol_lists =
&h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
s->state = BROTLI_STATE_HUFFMAN_CODE_0;
break;
case BROTLI_STATE_UNCOMPRESSED: {
result = CopyUncompressedBlockToOutput(
available_out, next_out, total_out, s);
if (result != BROTLI_DECODER_SUCCESS) {
break;
}
s->state = BROTLI_STATE_METABLOCK_DONE;
break;
}
case BROTLI_STATE_METADATA:
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
uint32_t bits;
/* Read one byte and ignore it. */
if (!BrotliSafeReadBits(br, 8, &bits)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
break;
}
}
if (result == BROTLI_DECODER_SUCCESS) {
s->state = BROTLI_STATE_METABLOCK_DONE;
}
break;
/* Fall through. */
case BROTLI_STATE_HUFFMAN_CODE_0:
if (s->loop_counter >= 3) {
@@ -2247,6 +2319,30 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
break;
}
case BROTLI_STATE_UNCOMPRESSED: {
result = CopyUncompressedBlockToOutput(
available_out, next_out, total_out, s);
if (result != BROTLI_DECODER_SUCCESS) {
break;
}
s->state = BROTLI_STATE_METABLOCK_DONE;
break;
}
case BROTLI_STATE_METADATA:
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
uint32_t bits;
/* Read one byte and ignore it. */
if (!BrotliSafeReadBits(br, 8, &bits)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
break;
}
}
if (result == BROTLI_DECODER_SUCCESS) {
s->state = BROTLI_STATE_METABLOCK_DONE;
}
break;
case BROTLI_STATE_METABLOCK_HEADER_2: {
uint32_t bits;
if (!BrotliSafeReadBits(br, 6, &bits)) {
@@ -2255,11 +2351,9 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
}
s->distance_postfix_bits = bits & BitMask(2);
bits >>= 2;
s->num_direct_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES +
(bits << s->distance_postfix_bits);
s->num_direct_distance_codes = bits << s->distance_postfix_bits;
BROTLI_LOG_UINT(s->num_direct_distance_codes);
BROTLI_LOG_UINT(s->distance_postfix_bits);
s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
s->context_modes =
(uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]);
if (s->context_modes == 0) {
@@ -2291,17 +2385,19 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
/* Fall through. */
case BROTLI_STATE_CONTEXT_MAP_2: {
uint32_t num_direct_codes =
s->num_direct_distance_codes - BROTLI_NUM_DISTANCE_SHORT_CODES;
uint32_t num_distance_codes = BROTLI_DISTANCE_ALPHABET_SIZE(
s->distance_postfix_bits, num_direct_codes,
(s->large_window ? BROTLI_LARGE_MAX_DISTANCE_BITS :
BROTLI_MAX_DISTANCE_BITS));
uint32_t max_distance_symbol = (s->large_window ?
BrotliMaxDistanceSymbol(
num_direct_codes, s->distance_postfix_bits) :
num_distance_codes);
uint32_t npostfix = s->distance_postfix_bits;
uint32_t ndirect = s->num_direct_distance_codes;
uint32_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
uint32_t distance_alphabet_size_limit = distance_alphabet_size_max;
BROTLI_BOOL allocation_success = BROTLI_TRUE;
if (s->large_window) {
BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
distance_alphabet_size_limit = limit.max_alphabet_size;
}
result = DecodeContextMap(
s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS,
&s->num_dist_htrees, &s->dist_context_map, s);
@@ -2315,8 +2411,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
s, &s->insert_copy_hgroup, BROTLI_NUM_COMMAND_SYMBOLS,
BROTLI_NUM_COMMAND_SYMBOLS, s->num_block_types[1]);
allocation_success &= BrotliDecoderHuffmanTreeGroupInit(
s, &s->distance_hgroup, num_distance_codes,
max_distance_symbol, s->num_dist_htrees);
s, &s->distance_hgroup, distance_alphabet_size_max,
distance_alphabet_size_limit, s->num_dist_htrees);
if (!allocation_success) {
return SaveErrorCode(s,
BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS));
@@ -2338,18 +2434,24 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
result = HuffmanTreeGroupDecode(hgroup, s);
if (result != BROTLI_DECODER_SUCCESS) break;
s->loop_counter++;
if (s->loop_counter >= 3) {
PrepareLiteralDecoding(s);
s->dist_context_map_slice = s->dist_context_map;
s->htree_command = s->insert_copy_hgroup.htrees[0];
if (!BrotliEnsureRingBuffer(s)) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
break;
}
s->state = BROTLI_STATE_COMMAND_BEGIN;
if (s->loop_counter < 3) {
break;
}
break;
s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY;
}
/* Fall through. */
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY:
PrepareLiteralDecoding(s);
s->dist_context_map_slice = s->dist_context_map;
s->htree_command = s->insert_copy_hgroup.htrees[0];
if (!BrotliEnsureRingBuffer(s)) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
break;
}
CalculateDistanceLut(s);
s->state = BROTLI_STATE_COMMAND_BEGIN;
/* Fall through. */
case BROTLI_STATE_COMMAND_BEGIN:
/* Fall through. */
+6 -12
View File
@@ -18,12 +18,6 @@ extern "C" {
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
/* Maximum possible Huffman table size for an alphabet size of (index * 32),
max code length 15 and root table bits 8. */
static const uint16_t kMaxHuffmanTableSize[] = {
256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,
854, 886, 920, 952, 984, 1016, 1048, 1080, 1112, 1144, 1176, 1208, 1240, 1272,
1304, 1336, 1368, 1400, 1432, 1464, 1496, 1528};
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
@@ -82,7 +76,7 @@ typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
const uint16_t value) {
return ((value & 0xFFFF) << 16) | (bits & 0xFF);
return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF);
}
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
@@ -100,7 +94,7 @@ BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
/* Builds Huffman lookup table assuming code lengths are in symbol order.
Returns size of resulting table. */
BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg);
int root_bits, const uint16_t* const symbol_lists, uint16_t* count);
/* Builds a simple Huffman table. The |num_symbols| parameter is to be
interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
@@ -110,13 +104,13 @@ BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
int root_bits, uint16_t* symbols, uint32_t num_symbols);
/* Contains a collection of Huffman trees with the same alphabet size. */
/* max_symbol is needed due to simple codes since log2(alphabet_size) could be
greater than log2(max_symbol). */
/* alphabet_size_limit is needed due to simple codes, since
log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
typedef struct {
HuffmanCode** htrees;
HuffmanCode* codes;
uint16_t alphabet_size;
uint16_t max_symbol;
uint16_t alphabet_size_max;
uint16_t alphabet_size_limit;
uint16_t num_htrees;
} HuffmanTreeGroup;
-18
View File
@@ -13,24 +13,6 @@
#include "../common/constants.h"
#include <brotli/types.h>
/* Represents the range of values belonging to a prefix code:
[offset, offset + 2^nbits) */
struct PrefixCodeRange {
uint16_t offset;
uint8_t nbits;
};
static const struct PrefixCodeRange
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
{ 1, 2}, { 5, 2}, { 9, 2}, { 13, 2},
{ 17, 3}, { 25, 3}, { 33, 3}, { 41, 3},
{ 49, 4}, { 65, 4}, { 81, 4}, { 97, 4},
{ 113, 5}, { 145, 5}, { 177, 5}, { 209, 5},
{ 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
{ 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12},
{8433, 13}, {16625, 24}
};
typedef struct CmdLutElement {
uint8_t insert_len_extra_bits;
uint8_t copy_len_extra_bits;
+9 -14
View File
@@ -33,10 +33,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
s->state = BROTLI_STATE_UNINITED;
s->large_window = 0;
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
@@ -59,8 +56,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
s->context_map_slice = NULL;
s->dist_context_map_slice = NULL;
s->sub_loop_counter = 0;
s->literal_hgroup.codes = NULL;
s->literal_hgroup.htrees = NULL;
s->insert_copy_hgroup.codes = NULL;
@@ -84,9 +79,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
s->block_type_trees = NULL;
s->block_len_trees = NULL;
/* Make small negative indexes addressable. */
s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
s->mtf_upper_bound = 63;
s->dictionary = BrotliGetDictionary();
@@ -142,17 +134,20 @@ void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
}
BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t max_symbol,
uint32_t ntrees) {
/* Pack two allocations into one */
const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
HuffmanTreeGroup* group, uint32_t alphabet_size_max,
uint32_t alphabet_size_limit, uint32_t ntrees) {
/* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables)
This number is discovered "unlimited" "enough" calculator; it is actually
a wee bigger than required in several cases (especially for alphabets with
less than 16 symbols). */
const size_t max_table_size = alphabet_size_limit + 376;
const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
/* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
code_size + htree_size);
group->alphabet_size = (uint16_t)alphabet_size;
group->max_symbol = (uint16_t)max_symbol;
group->alphabet_size_max = (uint16_t)alphabet_size_max;
group->alphabet_size_limit = (uint16_t)alphabet_size_limit;
group->num_htrees = (uint16_t)ntrees;
group->htrees = p;
group->codes = (HuffmanCode*)(&p[ntrees]);
+144 -37
View File
@@ -21,6 +21,95 @@
extern "C" {
#endif
/* Graphviz diagram that describes state transitions:
digraph States {
graph [compound=true]
concentrate=true
node [shape="box"]
UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE}
subgraph cluster_metablock_workflow {
style="rounded"
label=< <B>METABLOCK CYCLE</B> >
METABLOCK_BEGIN -> METABLOCK_HEADER
METABLOCK_HEADER:sw -> METADATA
METABLOCK_HEADER:s -> UNCOMPRESSED
METABLOCK_HEADER:se -> METABLOCK_DONE:ne
METADATA:s -> METABLOCK_DONE:w
UNCOMPRESSED:s -> METABLOCK_DONE:n
METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"]
}
INITIALIZE -> METABLOCK_BEGIN
METABLOCK_DONE -> DONE
subgraph cluster_compressed_metablock {
style="rounded"
label=< <B>COMPRESSED METABLOCK</B> >
subgraph cluster_command {
style="rounded"
label=< <B>HOT LOOP</B> >
_METABLOCK_DONE_PORT_ [shape=point style=invis]
{
// Set different shape for nodes returning from "compressed metablock".
node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS;
CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1;
}
CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY
// IO ("write") nodes are not in the hot loop!
CMD_INNER_WRITE [style=dashed]
CMD_INNER -> CMD_INNER_WRITE
CMD_POST_WRITE_1 [style=dashed]
CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1
CMD_POST_WRITE_2 [style=dashed]
CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2
CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"]
CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS}
[constraint="false"]
CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"]
CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"]
CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"]
CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"]
{rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS;
CMD_POST_WRAP_COPY}
{rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2}
{CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} ->
_METABLOCK_DONE_PORT_ [style=invis]
{CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_
[constraint="false" style=invis]
}
BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n
HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3
HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1
CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP
TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e
BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n
HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"]
{rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3}
{rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2;
TREE_GROUP}
}
METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n
_METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se
[constraint="false" ltail=cluster_command]
UNINITED [shape=Mdiamond];
DONE [shape=Msquare];
}
*/
typedef enum {
BROTLI_STATE_UNINITED,
BROTLI_STATE_LARGE_WINDOW_BITS,
@@ -39,6 +128,7 @@ typedef enum {
BROTLI_STATE_METABLOCK_DONE,
BROTLI_STATE_COMMAND_POST_WRITE_1,
BROTLI_STATE_COMMAND_POST_WRITE_2,
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
BROTLI_STATE_HUFFMAN_CODE_0,
BROTLI_STATE_HUFFMAN_CODE_1,
BROTLI_STATE_HUFFMAN_CODE_2,
@@ -46,6 +136,7 @@ typedef enum {
BROTLI_STATE_CONTEXT_MAP_1,
BROTLI_STATE_CONTEXT_MAP_2,
BROTLI_STATE_TREE_GROUP,
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
BROTLI_STATE_DONE
} BrotliRunningState;
@@ -98,6 +189,50 @@ typedef enum {
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
} BrotliRunningReadBlockLengthState;
typedef struct BrotliMetablockHeaderArena {
BrotliRunningTreeGroupState substate_tree_group;
BrotliRunningContextMapState substate_context_map;
BrotliRunningHuffmanState substate_huffman;
uint32_t sub_loop_counter;
uint32_t repeat_code_len;
uint32_t prev_code_len;
/* For ReadHuffmanCode. */
uint32_t symbol;
uint32_t repeat;
uint32_t space;
/* Huffman table for "histograms". */
HuffmanCode table[32];
/* List of heads of symbol chains. */
uint16_t* symbol_lists;
/* Storage from symbol_lists. */
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
BROTLI_NUM_COMMAND_SYMBOLS];
/* Tails of symbol chains. */
int next_symbol[32];
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
/* Population counts for the code lengths. */
uint16_t code_length_histo[16];
/* For HuffmanTreeGroupDecode. */
int htree_index;
HuffmanCode* next;
/* For DecodeContextMap. */
uint32_t context_index;
uint32_t max_run_length_prefix;
uint32_t code;
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
} BrotliMetablockHeaderArena;
typedef struct BrotliMetablockBodyArena {
uint8_t dist_extra_bits[544];
uint32_t dist_offset[544];
} BrotliMetablockBodyArena;
struct BrotliDecoderStateStruct {
BrotliRunningState state;
@@ -110,7 +245,8 @@ struct BrotliDecoderStateStruct {
brotli_free_func free_func;
void* memory_manager_opaque;
/* Temporary storage for remaining input. */
/* Temporary storage for remaining input. Brotli stream format is designed in
a way, that 64 bits are enough to make progress in decoding. */
union {
uint64_t u64;
uint8_t u8[8];
@@ -125,7 +261,6 @@ struct BrotliDecoderStateStruct {
int dist_rb_idx;
int dist_rb[4];
int error_code;
uint32_t sub_loop_counter;
uint8_t* ringbuffer;
uint8_t* ringbuffer_end;
HuffmanCode* htree_command;
@@ -153,13 +288,10 @@ struct BrotliDecoderStateStruct {
uint32_t block_type_rb[6];
uint32_t distance_postfix_bits;
uint32_t num_direct_distance_codes;
int distance_postfix_mask;
uint32_t num_dist_htrees;
uint8_t* dist_context_map;
HuffmanCode* literal_htree;
uint8_t dist_htree_index;
uint32_t repeat_code_len;
uint32_t prev_code_len;
int copy_length;
int distance_code;
@@ -168,33 +300,6 @@ struct BrotliDecoderStateStruct {
size_t rb_roundtrips; /* how many times we went around the ring-buffer */
size_t partial_pos_out; /* how much output to the user in total */
/* For ReadHuffmanCode. */
uint32_t symbol;
uint32_t repeat;
uint32_t space;
HuffmanCode table[32];
/* List of heads of symbol chains. */
uint16_t* symbol_lists;
/* Storage from symbol_lists. */
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
BROTLI_NUM_COMMAND_SYMBOLS];
/* Tails of symbol chains. */
int next_symbol[32];
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
/* Population counts for the code lengths. */
uint16_t code_length_histo[16];
/* For HuffmanTreeGroupDecode. */
int htree_index;
HuffmanCode* next;
/* For DecodeContextMap. */
uint32_t context_index;
uint32_t max_run_length_prefix;
uint32_t code;
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
/* For InverseMoveToFrontTransform. */
uint32_t mtf_upper_bound;
uint32_t mtf[64 + 1];
@@ -203,10 +308,7 @@ struct BrotliDecoderStateStruct {
/* States inside function calls. */
BrotliRunningMetablockHeaderState substate_metablock_header;
BrotliRunningTreeGroupState substate_tree_group;
BrotliRunningContextMapState substate_context_map;
BrotliRunningUncompressedState substate_uncompressed;
BrotliRunningHuffmanState substate_huffman;
BrotliRunningDecodeUint8State substate_decode_uint8;
BrotliRunningReadBlockLengthState substate_read_block_length;
@@ -229,6 +331,11 @@ struct BrotliDecoderStateStruct {
const BrotliTransforms* transforms;
uint32_t trivial_literal_contexts[8]; /* 256 bits */
union {
BrotliMetablockHeaderArena header;
BrotliMetablockBodyArena body;
} arena;
};
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
@@ -241,8 +348,8 @@ BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
BrotliDecoderState* s);
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size,
uint32_t max_symbol, uint32_t ntrees);
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
uint32_t alphabet_size_limit, uint32_t ntrees);
#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
+8 -7
View File
@@ -9,6 +9,7 @@
#include "./backward_references.h"
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
@@ -119,17 +120,17 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
#undef CAT
#undef EXPAND_CAT
void BrotliCreateBackwardReferences(
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask, const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
void BrotliCreateBackwardReferences(size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals) {
switch (params->hasher.type) {
#define CASE_(N) \
case N: \
CreateBackwardReferencesNH ## N( \
num_bytes, position, ringbuffer, \
ringbuffer_mask, params, hasher, dist_cache, \
CreateBackwardReferencesNH ## N(num_bytes, \
position, ringbuffer, ringbuffer_mask, \
literal_context_lut, params, hasher, dist_cache, \
last_insert_len, commands, num_commands, num_literals); \
return;
FOR_GENERIC_HASHERS(CASE_)
+5 -4
View File
@@ -10,6 +10,7 @@
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
@@ -25,10 +26,10 @@ extern "C" {
initially the total amount of commands output by previous
CreateBackwardReferences calls, and must be incremented by the amount written
by this call. */
BROTLI_INTERNAL void BrotliCreateBackwardReferences(
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask, const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals);
#if defined(__cplusplus) || defined(c_plusplus)
+51 -33
View File
@@ -11,6 +11,7 @@
#include <string.h> /* memcpy, memset */
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./command.h"
@@ -26,6 +27,7 @@
extern "C" {
#endif
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
@@ -86,14 +88,10 @@ typedef struct ZopfliCostModel {
static void InitZopfliCostModel(
MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
size_t num_bytes) {
uint32_t distance_histogram_size = dist->alphabet_size;
if (distance_histogram_size > BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE) {
distance_histogram_size = BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE;
}
self->num_bytes_ = num_bytes;
self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size);
self->distance_histogram_size = distance_histogram_size;
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
self->distance_histogram_size = dist->alphabet_size_limit;
if (BROTLI_IS_OOM(m)) return;
}
@@ -408,9 +406,12 @@ static size_t UpdateNodes(
const int* starting_dist_cache, const size_t num_matches,
const BackwardMatch* matches, const ZopfliCostModel* model,
StartPosQueue* queue, ZopfliNode* nodes) {
const size_t stream_offset = params->stream_offset;
const size_t cur_ix = block_start + pos;
const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
const size_t dictionary_start = BROTLI_MIN(size_t,
cur_ix + stream_offset, max_backward_limit);
const size_t max_len = num_bytes - pos;
const size_t max_zopfli_len = MaxZopfliLen(params);
const size_t max_iters = MaxZopfliCandidates(params);
@@ -419,8 +420,8 @@ static size_t UpdateNodes(
size_t k;
size_t gap = 0;
EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
model, queue, nodes);
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
starting_dist_cache, model, queue, nodes);
{
const PosData* posdata = StartPosQueueAt(queue, 0);
@@ -453,7 +454,7 @@ static size_t UpdateNodes(
if (cur_ix_masked + best_len > ringbuffer_mask) {
break;
}
if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
/* Word dictionary -> ignore. */
continue;
}
@@ -472,6 +473,8 @@ static size_t UpdateNodes(
&ringbuffer[cur_ix_masked],
max_len);
} else {
/* "Gray" area. It is addressable by decoder, but this encoder
instance does not have that data -> should not touch it. */
continue;
}
{
@@ -506,7 +509,7 @@ static size_t UpdateNodes(
BackwardMatch match = matches[j];
size_t dist = match.distance;
BROTLI_BOOL is_dictionary_match =
TO_BROTLI_BOOL(dist > max_distance + gap);
TO_BROTLI_BOOL(dist > dictionary_start + gap);
/* We already tried all possible last distance matches, so we can use
normal distance code here. */
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
@@ -569,6 +572,7 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
size_t* last_insert_len, const BrotliEncoderParams* params,
Command* commands, size_t* num_literals) {
const size_t stream_offset = params->stream_offset;
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
size_t pos = 0;
uint32_t offset = nodes[0].u.next;
@@ -587,9 +591,10 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
{
size_t distance = ZopfliNodeCopyDistance(next);
size_t len_code = ZopfliNodeLengthCode(next);
size_t max_distance =
BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
size_t dictionary_start = BROTLI_MIN(size_t,
block_start + pos + stream_offset, max_backward_limit);
BROTLI_BOOL is_dictionary =
TO_BROTLI_BOOL(distance > dictionary_start + gap);
size_t dist_code = ZopfliNodeDistanceCode(next);
InitCommand(&commands[i], &params->dist, insert_length,
copy_length, (int)len_code - (int)copy_length, dist_code);
@@ -613,6 +618,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
const ZopfliCostModel* model, const uint32_t* num_matches,
const BackwardMatch* matches, ZopfliNode* nodes) {
const size_t stream_offset = params->stream_offset;
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
const size_t max_zopfli_len = MaxZopfliLen(params);
StartPosQueue queue;
@@ -637,7 +643,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
while (skip) {
i++;
if (i + 3 >= num_bytes) break;
EvaluateNode(position, i, max_backward_limit, gap,
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
dist_cache, model, &queue, nodes);
cur_match_pos += num_matches[i];
skip--;
@@ -650,8 +656,9 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params,
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes) {
ContextLut literal_context_lut, const BrotliEncoderParams* params,
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
const size_t stream_offset = params->stream_offset;
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
const size_t max_zopfli_len = MaxZopfliLen(params);
ZopfliCostModel model;
@@ -662,6 +669,7 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
size_t i;
size_t gap = 0;
size_t lz_matches_offset = 0;
BROTLI_UNUSED(literal_context_lut);
nodes[0].length = 0;
nodes[0].u.cost = 0;
InitZopfliCostModel(m, &model, &params->dist, num_bytes);
@@ -672,12 +680,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
const size_t pos = position + i;
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
const size_t dictionary_start = BROTLI_MIN(size_t,
pos + stream_offset, max_backward_limit);
size_t skip;
size_t num_matches;
num_matches = FindAllMatchesH10(hasher,
num_matches = FindAllMatchesH10(&hasher->privat._H10,
&params->dictionary,
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
gap, params, &matches[lz_matches_offset]);
dictionary_start + gap, params, &matches[lz_matches_offset]);
if (num_matches > 0 &&
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
matches[0] = matches[num_matches - 1];
@@ -692,13 +702,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
}
if (skip > 1) {
/* Add the tail of the copy to the hasher. */
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
StoreRangeH10(&hasher->privat._H10,
ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
size_t, pos + skip, store_end));
skip--;
while (skip) {
i++;
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
EvaluateNode(position, i, max_backward_limit, gap,
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
dist_cache, &model, &queue, nodes);
skip--;
}
@@ -710,15 +721,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals) {
ZopfliNode* nodes;
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
if (BROTLI_IS_OOM(m)) return;
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
BrotliInitZopfliNodes(nodes, num_bytes + 1);
*num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
position, ringbuffer, ringbuffer_mask, params,
position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
dist_cache, hasher, nodes);
if (BROTLI_IS_OOM(m)) return;
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
@@ -728,9 +738,10 @@ void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals) {
const size_t stream_offset = params->stream_offset;
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
size_t matches_size = 4 * num_bytes;
@@ -747,10 +758,16 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
size_t gap = 0;
size_t shadow_matches = 0;
if (BROTLI_IS_OOM(m)) return;
BROTLI_UNUSED(literal_context_lut);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
BROTLI_IS_NULL(matches)) {
return;
}
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
const size_t pos = position + i;
size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
size_t dictionary_start = BROTLI_MIN(size_t,
pos + stream_offset, max_backward_limit);
size_t max_length = num_bytes - i;
size_t num_found_matches;
size_t cur_match_end;
@@ -759,10 +776,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
if (BROTLI_IS_OOM(m)) return;
num_found_matches = FindAllMatchesH10(hasher,
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
&params->dictionary,
ringbuffer, ringbuffer_mask, pos, max_length,
max_distance, gap, params,
max_distance, dictionary_start + gap, params,
&matches[cur_match_pos + shadow_matches]);
cur_match_end = cur_match_pos + num_found_matches;
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
@@ -777,7 +794,8 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
matches[cur_match_pos++] = matches[cur_match_end - 1];
num_matches[i] = 1;
/* Add the tail of the copy to the hasher. */
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
StoreRangeH10(&hasher->privat._H10,
ringbuffer, ringbuffer_mask, pos + 1,
BROTLI_MIN(size_t, pos + match_len, store_end));
memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
i += skip;
@@ -791,7 +809,7 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
orig_num_commands = *num_commands;
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
InitZopfliCostModel(m, &model, &params->dist, num_bytes);
if (BROTLI_IS_OOM(m)) return;
for (i = 0; i < 2; i++) {
+11 -8
View File
@@ -10,6 +10,7 @@
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
@@ -23,15 +24,17 @@ extern "C" {
#endif
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask, const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals);
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask, const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals);
typedef struct ZopfliNode {
@@ -77,8 +80,8 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
MemoryManager* m, size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params,
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes);
ContextLut literal_context_lut, const BrotliEncoderParams* params,
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
+24 -14
View File
@@ -10,11 +10,13 @@
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
size_t num_bytes, size_t position,
const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals) {
HASHER()* privat = &hasher->privat.FN(_);
/* Set maximum distance, see section 9.1. of the spec. */
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
const size_t position_offset = params->stream_offset;
const Command* const orig_commands = commands;
size_t insert_length = *last_insert_len;
@@ -31,19 +33,23 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
/* Minimum score to accept a backward reference. */
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
FN(PrepareDistanceCache)(hasher, dist_cache);
BROTLI_UNUSED(literal_context_lut);
FN(PrepareDistanceCache)(privat, dist_cache);
while (position + FN(HashTypeLength)() < pos_end) {
size_t max_length = pos_end - position;
size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
size_t dictionary_start = BROTLI_MIN(size_t,
position + position_offset, max_backward_limit);
HasherSearchResult sr;
sr.len = 0;
sr.len_code_delta = 0;
sr.distance = 0;
sr.score = kMinScore;
FN(FindLongestMatch)(hasher, &params->dictionary,
FN(FindLongestMatch)(privat, &params->dictionary,
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
max_distance, gap, params->dist.max_distance, &sr);
max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
if (sr.score > kMinScore) {
/* Found a match. Let's look for something even better ahead. */
int delayed_backward_references_in_row = 0;
@@ -57,10 +63,13 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
sr2.distance = 0;
sr2.score = kMinScore;
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
FN(FindLongestMatch)(hasher,
dictionary_start = BROTLI_MIN(size_t,
position + 1 + position_offset, max_backward_limit);
FN(FindLongestMatch)(privat,
&params->dictionary,
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
max_distance, gap, params->dist.max_distance, &sr2);
max_distance, dictionary_start + gap, params->dist.max_distance,
&sr2);
if (sr2.score >= sr.score + cost_diff_lazy) {
/* Ok, let's just write one byte for now and start a match from the
next byte. */
@@ -76,18 +85,19 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
}
apply_random_heuristics =
position + 2 * sr.len + random_heuristics_window_size;
max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
dictionary_start = BROTLI_MIN(size_t,
position + position_offset, max_backward_limit);
{
/* The first 16 codes are special short-codes,
and the minimum offset is 1. */
size_t distance_code = ComputeDistanceCode(
sr.distance, max_distance + gap, dist_cache);
if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
sr.distance, dictionary_start + gap, dist_cache);
if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
dist_cache[3] = dist_cache[2];
dist_cache[2] = dist_cache[1];
dist_cache[1] = dist_cache[0];
dist_cache[0] = (int)sr.distance;
FN(PrepareDistanceCache)(hasher, dist_cache);
FN(PrepareDistanceCache)(privat, dist_cache);
}
InitCommand(commands++, &params->dist, insert_length,
sr.len, sr.len_code_delta, distance_code);
@@ -105,7 +115,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
range_start, position + sr.len - (sr.distance << 2)));
}
FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, range_start,
FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
range_end);
}
position += sr.len;
@@ -131,7 +141,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
size_t pos_jump =
BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
for (; position < pos_jump; position += 4) {
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
insert_length += 4;
}
} else {
@@ -140,7 +150,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
size_t pos_jump =
BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
for (; position < pos_jump; position += 2) {
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
insert_length += 2;
}
}
+3 -3
View File
@@ -132,7 +132,7 @@ void BrotliSplitBlock(MemoryManager* m,
{
size_t literals_count = CountLiterals(cmds, num_commands);
uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return;
/* Create a continuous array of literals. */
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
/* Create the block split on the array of literals.
@@ -150,7 +150,7 @@ void BrotliSplitBlock(MemoryManager* m,
/* Compute prefix codes for commands. */
uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
size_t i;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return;
for (i = 0; i < num_commands; ++i) {
insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
}
@@ -170,7 +170,7 @@ void BrotliSplitBlock(MemoryManager* m,
uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
size_t j = 0;
size_t i;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return;
for (i = 0; i < num_commands; ++i) {
const Command* cmd = &cmds[i];
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
+15 -6
View File
@@ -219,7 +219,12 @@ static void FN(ClusterBlocks)(MemoryManager* m,
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) ||
BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
BROTLI_IS_NULL(pairs)) {
return;
}
memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
@@ -278,11 +283,11 @@ static void FN(ClusterBlocks)(MemoryManager* m,
if (pairs_capacity < max_num_pairs + 1) {
BROTLI_FREE(m, pairs);
pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
}
clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
for (i = 0; i < num_clusters; ++i) {
clusters[i] = (uint32_t)i;
}
@@ -294,7 +299,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
BROTLI_FREE(m, cluster_size);
new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
pos = 0;
{
@@ -386,7 +391,7 @@ static void FN(SplitByteVector)(MemoryManager* m,
return;
}
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
/* Find good entropy codes. */
FN(InitialEntropyCodes)(data, length,
sampling_stride_length,
@@ -405,7 +410,11 @@ static void FN(SplitByteVector)(MemoryManager* m,
uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
size_t i;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
return;
}
for (i = 0; i < iters; ++i) {
num_blocks = FN(FindBlocks)(data, length,
block_switch_cost,
+13 -30
View File
@@ -34,33 +34,18 @@ extern "C" {
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
/* Represents the range of values belonging to a prefix code:
[offset, offset + 2^nbits) */
typedef struct PrefixCodeRange {
uint32_t offset;
uint32_t nbits;
} PrefixCodeRange;
static const PrefixCodeRange
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
{ 1, 2}, { 5, 2}, { 9, 2}, {13, 2}, {17, 3}, { 25, 3}, { 33, 3},
{41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, {113, 5}, {145, 5},
{177, 5}, { 209, 5}, { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
{753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, {8433, 13}, {16625, 24}
};
static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code;
return code;
}
static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
uint32_t* n_extra, uint32_t* extra) {
*code = BlockLengthPrefixCode(len);
*n_extra = kBlockLengthPrefixCode[*code].nbits;
*extra = len - kBlockLengthPrefixCode[*code].offset;
*n_extra = _kBrotliPrefixCodeRanges[*code].nbits;
*extra = len - _kBrotliPrefixCodeRanges[*code].offset;
}
typedef struct BlockTypeCodeCalculator {
@@ -450,7 +435,7 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
const size_t max_tree_size = 2 * length + 1;
HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
uint32_t count_limit;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
for (count_limit = 1; ; count_limit *= 2) {
HuffmanTree* node = tree;
size_t l;
@@ -714,7 +699,7 @@ static void EncodeContextMap(MemoryManager* m,
}
rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return;
MoveToFrontTransform(context_map, context_map_size, rle_symbols);
RunLengthCodeZeros(context_map_size, rle_symbols,
&num_rle_symbols, &max_run_length_prefix);
@@ -956,23 +941,21 @@ void BrotliStoreMetaBlock(MemoryManager* m,
size_t pos = start_pos;
size_t i;
uint32_t num_distance_symbols = params->dist.alphabet_size;
uint32_t num_effective_distance_symbols = num_distance_symbols;
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
HuffmanTree* tree;
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
BlockEncoder literal_enc;
BlockEncoder command_enc;
BlockEncoder distance_enc;
const BrotliDistanceParams* dist = &params->dist;
if (params->large_window &&
num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
}
BROTLI_DCHECK(
num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
mb->literal_split.num_types, mb->literal_split.types,
mb->literal_split.lengths, mb->literal_split.num_blocks);
@@ -1163,7 +1146,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
HuffmanTree* tree;
uint32_t num_distance_symbols = params->dist.alphabet_size;
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
@@ -1177,7 +1160,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
BrotliWriteBits(13, 0, storage_ix, storage);
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
BROTLI_NUM_LITERAL_SYMBOLS, tree,
lit_depth, lit_bits,
@@ -1206,7 +1189,7 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
const Command* commands, size_t n_commands,
size_t* storage_ix, uint8_t* storage) {
uint32_t num_distance_symbols = params->dist.alphabet_size;
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
uint32_t distance_alphabet_bits =
Log2FloorNonZero(num_distance_symbols - 1) + 1;
+6 -3
View File
@@ -215,7 +215,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
uint32_t next_index;
HistogramType* tmp;
size_t i;
if (BROTLI_IS_OOM(m)) return 0;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
for (i = 0; i < length; ++i) {
new_index[i] = kInvalidIndex;
}
@@ -229,7 +229,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
tmp and reduce the number of copying by the factor of 2. */
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
if (BROTLI_IS_OOM(m)) return 0;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
next_index = 0;
for (i = 0; i < length; ++i) {
if (new_index[symbols[i]] == next_index) {
@@ -259,7 +259,10 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
size_t i;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
return;
}
for (i = 0; i < in_size; ++i) {
cluster_size[i] = 1;
+28
View File
@@ -0,0 +1,28 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
#include "./command.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = {
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26,
34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594};
const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = {
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24};
const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = {
2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18,
22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118};
const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24};
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
+12 -12
View File
@@ -20,14 +20,14 @@
extern "C" {
#endif
static uint32_t kInsBase[] = { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50,
66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
static uint32_t kInsExtra[] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
static uint32_t kCopyBase[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30,
38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
static uint32_t kCopyExtra[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
BROTLI_INTERNAL extern const uint32_t
kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
BROTLI_INTERNAL extern const uint32_t
kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
BROTLI_INTERNAL extern const uint32_t
kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
BROTLI_INTERNAL extern const uint32_t
kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
if (insertlen < 6) {
@@ -89,19 +89,19 @@ static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
}
static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
return kInsBase[inscode];
return kBrotliInsBase[inscode];
}
static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
return kInsExtra[inscode];
return kBrotliInsExtra[inscode];
}
static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
return kCopyBase[copycode];
return kBrotliCopyBase[copycode];
}
static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
return kCopyExtra[copycode];
return kBrotliCopyExtra[copycode];
}
typedef struct Command {
@@ -524,7 +524,7 @@ static void StoreCommands(MemoryManager* m,
static BROTLI_BOOL ShouldCompress(
const uint8_t* input, size_t input_size, size_t num_literals) {
double corpus_size = (double)input_size;
if (num_literals < MIN_RATIO * corpus_size) {
if ((double)num_literals < MIN_RATIO * corpus_size) {
return BROTLI_TRUE;
} else {
uint32_t literal_histo[256] = { 0 };
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -15,7 +15,8 @@
extern "C" {
#endif
extern const uint16_t kStaticDictionaryHash[32768];
extern const uint16_t kStaticDictionaryHashWords[32768];
extern const uint8_t kStaticDictionaryHashLengths[32768];
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
+104 -39
View File
@@ -54,12 +54,19 @@ typedef enum BrotliEncoderStreamState {
BROTLI_STREAM_METADATA_BODY = 4
} BrotliEncoderStreamState;
typedef enum BrotliEncoderFlintState {
BROTLI_FLINT_NEEDS_2_BYTES = 2,
BROTLI_FLINT_NEEDS_1_BYTE = 1,
BROTLI_FLINT_WAITING_FOR_PROCESSING = 0,
BROTLI_FLINT_WAITING_FOR_FLUSHING = -1,
BROTLI_FLINT_DONE = -2
} BrotliEncoderFlintState;
typedef struct BrotliEncoderStateStruct {
BrotliEncoderParams params;
MemoryManager memory_manager_;
HasherHandle hasher_;
uint64_t input_pos_;
RingBuffer ringbuffer_;
size_t cmd_alloc_size_;
@@ -73,10 +80,17 @@ typedef struct BrotliEncoderStateStruct {
int saved_dist_cache_[4];
uint16_t last_bytes_;
uint8_t last_bytes_bits_;
/* "Flint" is a tiny uncompressed block emitted before the continuation
block to unwire literal context from previous data. Despite being int8_t,
field is actually BrotliEncoderFlintState enum. */
int8_t flint_;
uint8_t prev_byte_;
uint8_t prev_byte2_;
size_t storage_size_;
uint8_t* storage_;
Hasher hasher_;
/* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */
int small_table_[1 << 10]; /* 4KiB */
int* large_table_; /* Allocated only when needed */
@@ -114,8 +128,6 @@ typedef struct BrotliEncoderStateStruct {
BROTLI_BOOL is_initialized_;
} BrotliEncoderStateStruct;
static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s);
static size_t InputBlockSize(BrotliEncoderState* s) {
return (size_t)1 << s->params.lgblock;
}
@@ -174,6 +186,11 @@ BROTLI_BOOL BrotliEncoderSetParameter(
state->params.dist.num_direct_distance_codes = value;
return BROTLI_TRUE;
case BROTLI_PARAM_STREAM_OFFSET:
if (value > (1u << 30)) return BROTLI_FALSE;
state->params.stream_offset = value;
return BROTLI_TRUE;
default: return BROTLI_FALSE;
}
}
@@ -195,7 +212,7 @@ static uint8_t* GetBrotliStorage(BrotliEncoderState* s, size_t size) {
if (s->storage_size_ < size) {
BROTLI_FREE(m, s->storage_);
s->storage_ = BROTLI_ALLOC(m, uint8_t, size);
if (BROTLI_IS_OOM(m)) return NULL;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL;
s->storage_size_ = size;
}
return s->storage_;
@@ -234,7 +251,7 @@ static int* GetHashTable(BrotliEncoderState* s, int quality,
s->large_table_size_ = htsize;
BROTLI_FREE(m, s->large_table_);
s->large_table_ = BROTLI_ALLOC(m, int, htsize);
if (BROTLI_IS_OOM(m)) return 0;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0;
}
table = s->large_table_;
}
@@ -499,7 +516,7 @@ static BROTLI_BOOL ShouldCompress(
/* TODO: find more precise minimal block overhead. */
if (bytes <= 2) return BROTLI_FALSE;
if (num_commands < (bytes >> 8) + 2) {
if (num_literals > 0.99 * (double)bytes) {
if ((double)num_literals > 0.99 * (double)bytes) {
uint32_t literal_histo[256] = { 0 };
static const uint32_t kSampleRate = 13;
static const double kMinEntropy = 7.92;
@@ -617,11 +634,7 @@ static void WriteMetaBlockInternal(MemoryManager* m,
/* The number of distance symbols effectively used for distance
histograms. It might be less than distance alphabet size
for "Large Window Brotli" (32-bit). */
uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
}
BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
}
BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask,
prev_byte, prev_byte2,
@@ -678,12 +691,23 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
s->last_bytes_bits_ = 0;
s->last_bytes_ = 0;
s->flint_ = BROTLI_FLINT_DONE;
s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
SanitizeParams(&s->params);
s->params.lgblock = ComputeLgBlock(&s->params);
ChooseDistanceParams(&s->params);
if (s->params.stream_offset != 0) {
s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES;
/* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */
s->dist_cache_[0] = -16;
s->dist_cache_[1] = -16;
s->dist_cache_[2] = -16;
s->dist_cache_[3] = -16;
memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
}
RingBufferSetup(&s->params, &s->ringbuffer_);
/* Initialize last byte with stream header. */
@@ -693,8 +717,14 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
lgwin = BROTLI_MAX(int, lgwin, 18);
}
EncodeWindowBits(lgwin, s->params.large_window,
&s->last_bytes_, &s->last_bytes_bits_);
if (s->params.stream_offset == 0) {
EncodeWindowBits(lgwin, s->params.large_window,
&s->last_bytes_, &s->last_bytes_bits_);
} else {
/* Bigger values have the same effect, but could cause overflows. */
s->params.stream_offset = BROTLI_MIN(size_t,
s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin));
}
}
if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
@@ -712,13 +742,15 @@ static void BrotliEncoderInitParams(BrotliEncoderParams* params) {
params->quality = BROTLI_DEFAULT_QUALITY;
params->lgwin = BROTLI_DEFAULT_WINDOW;
params->lgblock = 0;
params->stream_offset = 0;
params->size_hint = 0;
params->disable_literal_context_modeling = BROTLI_FALSE;
BrotliInitEncoderDictionary(&params->dictionary);
params->dist.distance_postfix_bits = 0;
params->dist.num_direct_distance_codes = 0;
params->dist.alphabet_size =
params->dist.alphabet_size_max =
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS);
params->dist.alphabet_size_limit = params->dist.alphabet_size_max;
params->dist.max_distance = BROTLI_MAX_DISTANCE;
}
@@ -734,7 +766,7 @@ static void BrotliEncoderInitState(BrotliEncoderState* s) {
s->prev_byte2_ = 0;
s->storage_size_ = 0;
s->storage_ = 0;
s->hasher_ = NULL;
HasherInit(&s->hasher_);
s->large_table_ = NULL;
s->large_table_size_ = 0;
s->cmd_code_numbits_ = 0;
@@ -902,6 +934,7 @@ static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes,
(*bytes)--;
(*wrapped_last_processed_pos)++;
}
} else {
}
/* The copy length is at most the metablock size, and thus expressible. */
GetLengthCode(last_command->insert_len_,
@@ -934,6 +967,7 @@ static BROTLI_BOOL EncodeData(
uint32_t mask;
MemoryManager* m = &s->memory_manager_;
ContextType literal_context_mode;
ContextLut literal_context_lut;
data = s->ringbuffer_.buffer_;
mask = s->ringbuffer_.mask_;
@@ -951,7 +985,10 @@ static BROTLI_BOOL EncodeData(
BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
s->literal_buf_ =
BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
BROTLI_IS_NULL(s->literal_buf_)) {
return BROTLI_FALSE;
}
}
if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
@@ -1009,7 +1046,7 @@ static BROTLI_BOOL EncodeData(
newsize += (bytes / 4) + 16;
s->cmd_alloc_size_ = newsize;
new_commands = BROTLI_ALLOC(m, Command, newsize);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE;
if (s->commands_) {
memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_);
BROTLI_FREE(m, s->commands_);
@@ -1024,6 +1061,7 @@ static BROTLI_BOOL EncodeData(
literal_context_mode = ChooseContextMode(
&s->params, data, WrapPosition(s->last_flush_pos_),
mask, (size_t)(s->input_pos_ - s->last_flush_pos_));
literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
@@ -1034,20 +1072,23 @@ static BROTLI_BOOL EncodeData(
if (s->params.quality == ZOPFLIFICATION_QUALITY) {
BROTLI_DCHECK(s->params.hasher.type == 10);
BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
data, mask, &s->params, s->hasher_, s->dist_cache_,
data, mask, literal_context_lut, &s->params,
&s->hasher_, s->dist_cache_,
&s->last_insert_len_, &s->commands_[s->num_commands_],
&s->num_commands_, &s->num_literals_);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
} else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
BROTLI_DCHECK(s->params.hasher.type == 10);
BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
data, mask, &s->params, s->hasher_, s->dist_cache_,
data, mask, literal_context_lut, &s->params,
&s->hasher_, s->dist_cache_,
&s->last_insert_len_, &s->commands_[s->num_commands_],
&s->num_commands_, &s->num_literals_);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
} else {
BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
data, mask, &s->params, s->hasher_, s->dist_cache_,
data, mask, literal_context_lut, &s->params,
&s->hasher_, s->dist_cache_,
&s->last_insert_len_, &s->commands_[s->num_commands_],
&s->num_commands_, &s->num_literals_);
}
@@ -1072,7 +1113,7 @@ static BROTLI_BOOL EncodeData(
s->num_commands_ < max_commands) {
/* Merge with next input block. Everything will happen later. */
if (UpdateLastProcessedPos(s)) {
HasherReset(s->hasher_);
HasherReset(&s->hasher_);
}
*out_size = 0;
return BROTLI_TRUE;
@@ -1113,7 +1154,7 @@ static BROTLI_BOOL EncodeData(
s->last_bytes_bits_ = storage_ix & 7u;
s->last_flush_pos_ = s->input_pos_;
if (UpdateLastProcessedPos(s)) {
HasherReset(s->hasher_);
HasherReset(&s->hasher_);
}
if (s->last_flush_pos_ > 0) {
s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask];
@@ -1174,7 +1215,6 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
size_t total_out_size = 0;
uint16_t last_bytes;
uint8_t last_bytes_bits;
HasherHandle hasher = NULL;
const size_t hasher_eff_size = BROTLI_MIN(size_t,
input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
@@ -1190,6 +1230,9 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
uint8_t prev_byte = 0;
uint8_t prev_byte2 = 0;
Hasher hasher;
HasherInit(&hasher);
BrotliEncoderInitParams(&params);
params.quality = 10;
params.lgwin = lgwin;
@@ -1226,6 +1269,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
ContextType literal_context_mode = ChooseContextMode(&params,
input_buffer, metablock_start, mask, metablock_end - metablock_start);
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
size_t block_start;
for (block_start = metablock_start; block_start < metablock_end; ) {
@@ -1234,12 +1278,12 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1);
size_t path_size;
size_t new_cmd_alloc_size;
if (BROTLI_IS_OOM(m)) goto oom;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom;
BrotliInitZopfliNodes(nodes, block_size + 1);
StitchToPreviousBlockH10(hasher, block_size, block_start,
StitchToPreviousBlockH10(&hasher.privat._H10, block_size, block_start,
input_buffer, mask);
path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
input_buffer, mask, &params, dist_cache, hasher,
input_buffer, mask, literal_context_lut, &params, dist_cache, &hasher,
nodes);
if (BROTLI_IS_OOM(m)) goto oom;
/* We allocate a command buffer in the first iteration of this loop that
@@ -1254,7 +1298,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
num_commands + path_size + 1);
if (cmd_alloc_size != new_cmd_alloc_size) {
Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size);
if (BROTLI_IS_OOM(m)) goto oom;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom;
cmd_alloc_size = new_cmd_alloc_size;
if (commands) {
memcpy(new_commands, commands, sizeof(Command) * num_commands);
@@ -1286,7 +1330,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
if (metablock_size == 0) {
/* Write the ISLAST and ISEMPTY bits. */
storage = BROTLI_ALLOC(m, uint8_t, 16);
if (BROTLI_IS_OOM(m)) goto oom;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
storage[0] = (uint8_t)last_bytes;
storage[1] = (uint8_t)(last_bytes >> 8);
BrotliWriteBits(2, 3, &storage_ix, storage);
@@ -1297,7 +1341,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
CreateBackwardReferences is now unused. */
memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
if (BROTLI_IS_OOM(m)) goto oom;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
storage[0] = (uint8_t)last_bytes;
storage[1] = (uint8_t)(last_bytes >> 8);
BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
@@ -1318,14 +1362,10 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
/* The number of distance symbols effectively used for distance
histograms. It might be less than distance alphabet size
for "Large Window Brotli" (32-bit). */
uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
}
BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
}
storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
if (BROTLI_IS_OOM(m)) goto oom;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
storage[0] = (uint8_t)last_bytes;
storage[1] = (uint8_t)(last_bytes >> 8);
BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
@@ -1576,7 +1616,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
s->literal_buf_ =
BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
BROTLI_IS_NULL(s->literal_buf_)) {
return BROTLI_FALSE;
}
}
if (s->command_buf_) {
command_buf = s->command_buf_;
@@ -1584,7 +1627,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
} else {
tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size);
tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) ||
BROTLI_IS_NULL(tmp_literal_buf)) {
return BROTLI_FALSE;
}
command_buf = tmp_command_buf;
literal_buf = tmp_literal_buf;
}
@@ -1640,8 +1686,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
&storage_ix, storage);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
}
*next_in += block_size;
*available_in -= block_size;
if (block_size != 0) {
*next_in += block_size;
*available_in -= block_size;
}
if (inplace) {
size_t out_bytes = storage_ix >> 3;
BROTLI_DCHECK(out_bytes <= *available_out);
@@ -1786,6 +1834,10 @@ BROTLI_BOOL BrotliEncoderCompressStream(
}
while (BROTLI_TRUE) {
size_t remaining_block_size = RemainingInputBlockSize(s);
/* Shorten input to flint size. */
if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) {
remaining_block_size = (size_t)s->flint_;
}
if (remaining_block_size != 0 && *available_in != 0) {
size_t copy_input_size =
@@ -1793,10 +1845,18 @@ BROTLI_BOOL BrotliEncoderCompressStream(
CopyInputToRingBuffer(s, copy_input_size, *next_in);
*next_in += copy_input_size;
*available_in -= copy_input_size;
if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size);
continue;
}
if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
/* Exit the "emit flint" workflow. */
if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) {
CheckFlushComplete(s);
if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
s->flint_ = BROTLI_FLINT_DONE;
}
}
continue;
}
@@ -1810,6 +1870,11 @@ BROTLI_BOOL BrotliEncoderCompressStream(
BROTLI_BOOL force_flush = TO_BROTLI_BOOL(
(*available_in == 0) && op == BROTLI_OPERATION_FLUSH);
BROTLI_BOOL result;
/* Force emitting (uncompressed) piece containing flint. */
if (!is_last && s->flint_ == 0) {
s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING;
force_flush = BROTLI_TRUE;
}
UpdateSizeHint(s, *available_in);
result = EncodeData(s, is_last, force_flush,
&s->available_out_, &s->next_out_);
+3 -2
View File
@@ -17,14 +17,15 @@ extern "C" {
void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
dict->words = BrotliGetDictionary();
dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms;
dict->hash_table = kStaticDictionaryHash;
dict->hash_table_words = kStaticDictionaryHashWords;
dict->hash_table_lengths = kStaticDictionaryHashLengths;
dict->buckets = kStaticDictionaryBuckets;
dict->dict_words = kStaticDictionaryWords;
dict->cutoffTransformsCount = kCutoffTransformsCount;
dict->cutoffTransforms = kCutoffTransforms;
}
#if defined(__cplusplus) || defined(c_plusplus)
+3 -1
View File
@@ -19,13 +19,15 @@ extern "C" {
/* Dictionary data (words and transforms) for 1 possible context */
typedef struct BrotliEncoderDictionary {
const BrotliDictionary* words;
uint32_t num_transforms;
/* cut off for fast encoder */
uint32_t cutoffTransformsCount;
uint64_t cutoffTransforms;
/* from dictionary_hash.h, for fast encoder */
const uint16_t* hash_table;
const uint16_t* hash_table_words;
const uint8_t* hash_table_lengths;
/* from static_dict_lut.h, for slow encoder */
const uint16_t* buckets;
+2
View File
@@ -18,6 +18,8 @@
extern "C" {
#endif
const size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1};
BROTLI_BOOL BrotliSetDepth(
int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
int stack[16];
+2 -2
View File
@@ -76,12 +76,12 @@ BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
size_t len,
uint16_t* bits);
BROTLI_INTERNAL extern const size_t kBrotliShellGaps[6];
/* Input size optimized Shell sort. */
typedef BROTLI_BOOL (*HuffmanTreeComparator)(
const HuffmanTree*, const HuffmanTree*);
static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
const size_t n, HuffmanTreeComparator comparator) {
static const size_t gaps[] = {132, 57, 23, 10, 4, 1};
if (n < 13) {
/* Insertion sort. */
size_t i;
@@ -101,7 +101,7 @@ static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
/* Shell sort. */
int g = n < 57 ? 2 : 0;
for (; g < 6; ++g) {
size_t gap = gaps[g];
size_t gap = kBrotliShellGaps[g];
size_t i;
for (i = gap; i < n; ++i) {
size_t j = i;
+105
View File
@@ -0,0 +1,105 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
#include "./fast_log.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = {
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
7.9943534368588578f
};
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
+20 -101
View File
@@ -19,10 +19,8 @@ extern "C" {
#endif
static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
/* TODO: generalize and move to platform.h */
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
return 31u ^ (uint32_t)__builtin_clz((uint32_t)n);
#if defined(BROTLI_BSR32)
return BROTLI_BSR32((uint32_t)n);
#else
uint32_t result = 0;
while (n >>= 1) result++;
@@ -30,110 +28,31 @@ static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
#endif
}
/* A lookup table for small values of log2(int) to be used in entropy
computation.
#define BROTLI_LOG2_TABLE_SIZE 256
", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
static const float kLog2Table[] = {
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
7.9943534368588578f
};
/* A lookup table for small values of log2(int) to be used in entropy
computation. */
BROTLI_INTERNAL extern const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
* function defined, so we use log() and a multiplication instead. */
#if !defined(BROTLI_HAVE_LOG2)
#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \
(defined(__ANDROID_API__) && __ANDROID_API__ < 18))
#define BROTLI_HAVE_LOG2 0
#else
#define BROTLI_HAVE_LOG2 1
#endif
#endif
#define LOG_2_INV 1.4426950408889634
/* Faster logarithm for small integers, with the property of log2(0) == 0. */
static BROTLI_INLINE double FastLog2(size_t v) {
if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) {
return kLog2Table[v];
if (v < BROTLI_LOG2_TABLE_SIZE) {
return kBrotliLog2Table[v];
}
#if (defined(_MSC_VER) && _MSC_VER <= 1700) || \
(defined(__ANDROID_API__) && __ANDROID_API__ < 18)
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
* function defined, so we use log() and a multiplication instead. */
#if !(BROTLI_HAVE_LOG2)
return log((double)v) * LOG_2_INV;
#else
return log2((double)v);
+2 -3
View File
@@ -17,8 +17,7 @@ extern "C" {
#endif
/* Separate implementation for little-endian 64-bit targets, for speed. */
#if defined(__GNUC__) && defined(_LP64) && defined(BROTLI_LITTLE_ENDIAN)
#if defined(BROTLI_TZCNT64) && BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
const uint8_t* s2,
size_t limit) {
@@ -32,7 +31,7 @@ static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
} else {
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
size_t matching_bits = (size_t)__builtin_ctzll(x);
size_t matching_bits = (size_t)BROTLI_TZCNT64(x);
matched += matching_bits >> 3;
return matched;
}
+80 -90
View File
@@ -27,34 +27,19 @@
extern "C" {
#endif
/* Pointer to hasher data.
*
* Excluding initialization and destruction, hasher can be passed as
* HasherHandle by value.
*
* Typically hasher data consists of 3 sections:
* * HasherCommon structure
* * private structured hasher data, depending on hasher type
* * private dynamic hasher data, depending on hasher type and parameters
*
* Using "define" instead of "typedef", because on MSVC __restrict does not work
* on typedef pointer types. */
#define HasherHandle uint8_t*
typedef struct {
/* Dynamically allocated area; first member for quickest access. */
void* extra;
size_t dict_num_lookups;
size_t dict_num_matches;
BrotliHasherParams params;
/* False if hasher needs to be "prepared" before use. */
BROTLI_BOOL is_prepared_;
size_t dict_num_lookups;
size_t dict_num_matches;
} HasherCommon;
static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) {
return (HasherCommon*)handle;
}
#define score_t size_t
static const uint32_t kCutoffTransformsCount = 10;
@@ -149,17 +134,13 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
}
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
const BrotliEncoderDictionary* dictionary, size_t item,
const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
const uint8_t* data, size_t max_length, size_t max_backward,
size_t max_distance, HasherSearchResult* out) {
size_t len;
size_t word_idx;
size_t offset;
size_t matchlen;
size_t backward;
score_t score;
len = item & 0x1F;
word_idx = item >> 5;
offset = dictionary->words->offsets_by_length[len] + len * word_idx;
if (len > max_length) {
return BROTLI_FALSE;
@@ -193,25 +174,24 @@ static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
static BROTLI_INLINE void SearchInStaticDictionary(
const BrotliEncoderDictionary* dictionary,
HasherHandle handle, const uint8_t* data, size_t max_length,
HasherCommon* common, const uint8_t* data, size_t max_length,
size_t max_backward, size_t max_distance,
HasherSearchResult* out, BROTLI_BOOL shallow) {
size_t key;
size_t i;
HasherCommon* self = GetHasherCommon(handle);
if (self->dict_num_matches < (self->dict_num_lookups >> 7)) {
if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
return;
}
key = Hash14(data) << 1;
for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
size_t item = dictionary->hash_table[key];
self->dict_num_lookups++;
if (item != 0) {
common->dict_num_lookups++;
if (dictionary->hash_table_lengths[key] != 0) {
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
dictionary, item, data,
dictionary, dictionary->hash_table_lengths[key],
dictionary->hash_table_words[key], data,
max_length, max_backward, max_distance, out);
if (item_matches) {
self->dict_num_matches++;
common->dict_num_matches++;
}
}
}
@@ -260,37 +240,37 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
#define MAX_NUM_MATCHES_H10 128
/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression
/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression
a little faster (0.5% - 1%) and it compresses 0.15% better on small text
and HTML inputs. */
#define HASHER() H2
#define BUCKET_BITS 16
#define BUCKET_SWEEP 1
#define BUCKET_SWEEP_BITS 0
#define HASH_LEN 5
#define USE_DICTIONARY 1
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef BUCKET_SWEEP
#undef BUCKET_SWEEP_BITS
#undef USE_DICTIONARY
#undef HASHER
#define HASHER() H3
#define BUCKET_SWEEP 2
#define BUCKET_SWEEP_BITS 1
#define USE_DICTIONARY 0
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef USE_DICTIONARY
#undef BUCKET_SWEEP
#undef BUCKET_SWEEP_BITS
#undef BUCKET_BITS
#undef HASHER
#define HASHER() H4
#define BUCKET_BITS 17
#define BUCKET_SWEEP 4
#define BUCKET_SWEEP_BITS 2
#define USE_DICTIONARY 1
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef USE_DICTIONARY
#undef HASH_LEN
#undef BUCKET_SWEEP
#undef BUCKET_SWEEP_BITS
#undef BUCKET_BITS
#undef HASHER
@@ -334,13 +314,13 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
#define HASHER() H54
#define BUCKET_BITS 20
#define BUCKET_SWEEP 4
#define BUCKET_SWEEP_BITS 2
#define HASH_LEN 7
#define USE_DICTIONARY 0
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef USE_DICTIONARY
#undef HASH_LEN
#undef BUCKET_SWEEP
#undef BUCKET_SWEEP_BITS
#undef BUCKET_BITS
#undef HASHER
@@ -393,97 +373,107 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
#undef CAT
#undef EXPAND_CAT
#define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)\
H(35) H(55) H(65)
#define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
static BROTLI_INLINE void DestroyHasher(
MemoryManager* m, HasherHandle* handle) {
if (*handle == NULL) return;
BROTLI_FREE(m, *handle);
typedef struct {
HasherCommon common;
union {
#define MEMBER_(N) \
H ## N _H ## N;
FOR_ALL_HASHERS(MEMBER_)
#undef MEMBER_
} privat;
} Hasher;
/* MUST be invoked before any other method. */
static BROTLI_INLINE void HasherInit(Hasher* hasher) {
hasher->common.extra = NULL;
}
static BROTLI_INLINE void HasherReset(HasherHandle handle) {
if (handle == NULL) return;
GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE;
static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
if (hasher->common.extra == NULL) return;
BROTLI_FREE(m, hasher->common.extra);
}
static BROTLI_INLINE void HasherReset(Hasher* hasher) {
hasher->common.is_prepared_ = BROTLI_FALSE;
}
static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
BROTLI_BOOL one_shot, const size_t input_size) {
size_t result = sizeof(HasherCommon);
switch (params->hasher.type) {
#define SIZE_(N) \
case N: \
result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \
break;
#define SIZE_(N) \
case N: \
return HashMemAllocInBytesH ## N(params, one_shot, input_size);
FOR_ALL_HASHERS(SIZE_)
#undef SIZE_
default:
break;
}
return result;
return 0; /* Default case. */
}
static BROTLI_INLINE void HasherSetup(MemoryManager* m, HasherHandle* handle,
static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
BrotliEncoderParams* params, const uint8_t* data, size_t position,
size_t input_size, BROTLI_BOOL is_last) {
HasherHandle self = NULL;
HasherCommon* common = NULL;
BROTLI_BOOL one_shot = (position == 0 && is_last);
if (*handle == NULL) {
if (hasher->common.extra == NULL) {
size_t alloc_size;
ChooseHasher(params, &params->hasher);
alloc_size = HasherSize(params, one_shot, input_size);
self = BROTLI_ALLOC(m, uint8_t, alloc_size);
if (BROTLI_IS_OOM(m)) return;
*handle = self;
common = GetHasherCommon(self);
common->params = params->hasher;
switch (common->params.type) {
#define INITIALIZE_(N) \
case N: \
InitializeH ## N(*handle, params); \
hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return;
hasher->common.params = params->hasher;
switch (hasher->common.params.type) {
#define INITIALIZE_(N) \
case N: \
InitializeH ## N(&hasher->common, \
&hasher->privat._H ## N, params); \
break;
FOR_ALL_HASHERS(INITIALIZE_);
#undef INITIALIZE_
default:
break;
}
HasherReset(*handle);
HasherReset(hasher);
}
self = *handle;
common = GetHasherCommon(self);
if (!common->is_prepared_) {
switch (common->params.type) {
#define PREPARE_(N) \
case N: \
PrepareH ## N(self, one_shot, input_size, data); \
if (!hasher->common.is_prepared_) {
switch (hasher->common.params.type) {
#define PREPARE_(N) \
case N: \
PrepareH ## N( \
&hasher->privat._H ## N, \
one_shot, input_size, data); \
break;
FOR_ALL_HASHERS(PREPARE_)
#undef PREPARE_
default: break;
}
if (position == 0) {
common->dict_num_lookups = 0;
common->dict_num_matches = 0;
hasher->common.dict_num_lookups = 0;
hasher->common.dict_num_matches = 0;
}
common->is_prepared_ = BROTLI_TRUE;
hasher->common.is_prepared_ = BROTLI_TRUE;
}
}
static BROTLI_INLINE void InitOrStitchToPreviousBlock(
MemoryManager* m, HasherHandle* handle, const uint8_t* data, size_t mask,
MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask,
BrotliEncoderParams* params, size_t position, size_t input_size,
BROTLI_BOOL is_last) {
HasherHandle self;
HasherSetup(m, handle, params, data, position, input_size, is_last);
HasherSetup(m, hasher, params, data, position, input_size, is_last);
if (BROTLI_IS_OOM(m)) return;
self = *handle;
switch (GetHasherCommon(self)->params.type) {
#define INIT_(N) \
case N: \
StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \
switch (hasher->common.params.type) {
#define INIT_(N) \
case N: \
StitchToPreviousBlockH ## N( \
&hasher->privat._H ## N, \
input_size, position, data, mask); \
break;
FOR_ALL_HASHERS(INIT_)
#undef INIT_
+51 -62
View File
@@ -28,20 +28,25 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
}
typedef struct HashComposite {
HasherHandle ha;
HasherHandle hb;
HASHER_A ha;
HASHER_B hb;
HasherCommon hb_common;
/* Shortcuts. */
void* extra;
HasherCommon* common;
BROTLI_BOOL fresh;
const BrotliEncoderParams* params;
} HashComposite;
static BROTLI_INLINE HashComposite* FN(Self)(HasherHandle handle) {
return (HashComposite*)&(GetHasherCommon(handle)[1]);
}
static void FN(Initialize)(HasherCommon* common,
HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
self->common = common;
self->extra = common->extra;
static void FN(Initialize)(
HasherHandle handle, const BrotliEncoderParams* params) {
HashComposite* self = FN(Self)(handle);
self->ha = 0;
self->hb = 0;
self->hb_common = *self->common;
self->fresh = BROTLI_TRUE;
self->params = params;
/* TODO: Initialize of the hashers is defered to Prepare (and params
remembered here) because we don't get the one_shot and input_size params
@@ -49,87 +54,71 @@ static void FN(Initialize)(
those params to all hashers FN(Initialize) */
}
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* data) {
HashComposite* self = FN(Self)(handle);
if (!self->ha) {
HasherCommon* common_a;
HasherCommon* common_b;
static void FN(Prepare)(
HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
if (self->fresh) {
self->fresh = BROTLI_FALSE;
self->hb_common.extra = (uint8_t*)self->extra +
FN_A(HashMemAllocInBytes)(self->params, one_shot, input_size);
self->ha = handle + sizeof(HasherCommon) + sizeof(HashComposite);
common_a = (HasherCommon*)self->ha;
common_a->params = self->params->hasher;
common_a->is_prepared_ = BROTLI_FALSE;
common_a->dict_num_lookups = 0;
common_a->dict_num_matches = 0;
FN_A(Initialize)(self->ha, self->params);
self->hb = self->ha + sizeof(HasherCommon) + FN_A(HashMemAllocInBytes)(
self->params, one_shot, input_size);
common_b = (HasherCommon*)self->hb;
common_b->params = self->params->hasher;
common_b->is_prepared_ = BROTLI_FALSE;
common_b->dict_num_lookups = 0;
common_b->dict_num_matches = 0;
FN_B(Initialize)(self->hb, self->params);
FN_A(Initialize)(self->common, &self->ha, self->params);
FN_B(Initialize)(&self->hb_common, &self->hb, self->params);
}
FN_A(Prepare)(self->ha, one_shot, input_size, data);
FN_B(Prepare)(self->hb, one_shot, input_size, data);
FN_A(Prepare)(&self->ha, one_shot, input_size, data);
FN_B(Prepare)(&self->hb, one_shot, input_size, data);
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
return sizeof(HashComposite) + 2 * sizeof(HasherCommon) +
FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
return FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
}
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
HashComposite* self = FN(Self)(handle);
FN_A(Store)(self->ha, data, mask, ix);
FN_B(Store)(self->hb, data, mask, ix);
FN_A(Store)(&self->ha, data, mask, ix);
FN_B(Store)(&self->hb, data, mask, ix);
}
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix_start,
static BROTLI_INLINE void FN(StoreRange)(
HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix_start,
const size_t ix_end) {
HashComposite* self = FN(Self)(handle);
FN_A(StoreRange)(self->ha, data, mask, ix_start, ix_end);
FN_B(StoreRange)(self->hb, data, mask, ix_start, ix_end);
FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end);
FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end);
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashComposite* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ring_buffer_mask) {
HashComposite* self = FN(Self)(handle);
FN_A(StitchToPreviousBlock)(self->ha, num_bytes, position, ringbuffer,
ring_buffer_mask);
FN_B(StitchToPreviousBlock)(self->hb, num_bytes, position, ringbuffer,
ring_buffer_mask);
FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position,
ringbuffer, ring_buffer_mask);
FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position,
ringbuffer, ring_buffer_mask);
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
HashComposite* self = FN(Self)(handle);
FN_A(PrepareDistanceCache)(self->ha, distance_cache);
FN_B(PrepareDistanceCache)(self->hb, distance_cache);
HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) {
FN_A(PrepareDistanceCache)(&self->ha, distance_cache);
FN_B(PrepareDistanceCache)(&self->hb, distance_cache);
}
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
static BROTLI_INLINE void FN(FindLongestMatch)(
HashComposite* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t gap, const size_t max_distance,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
HashComposite* self = FN(Self)(handle);
FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask,
distance_cache, cur_ix, max_length, max_backward, gap,
FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask,
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
max_distance, out);
FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask,
distance_cache, cur_ix, max_length, max_backward, gap,
FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask,
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
max_distance, out);
}
+88 -49
View File
@@ -28,7 +28,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
/* HashBytes is the function that chooses the bucket to place the address in.*/
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* data) {
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
@@ -45,28 +45,56 @@ typedef struct FN(Bank) {
} FN(Bank);
typedef struct HashForgetfulChain {
uint32_t addr[BUCKET_SIZE];
uint16_t head[BUCKET_SIZE];
/* Truncated hash used for quick rejection of "distance cache" candidates. */
uint8_t tiny_hash[65536];
FN(Bank) banks[NUM_BANKS];
uint16_t free_slot_idx[NUM_BANKS];
uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */
size_t max_hops;
/* Shortcuts. */
void* extra;
HasherCommon* common;
/* --- Dynamic size members --- */
/* uint32_t addr[BUCKET_SIZE]; */
/* uint16_t head[BUCKET_SIZE]; */
/* Truncated hash used for quick rejection of "distance cache" candidates. */
/* uint8_t tiny_hash[65536];*/
/* FN(Bank) banks[NUM_BANKS]; */
} HashForgetfulChain;
static BROTLI_INLINE HashForgetfulChain* FN(Self)(HasherHandle handle) {
return (HashForgetfulChain*)&(GetHasherCommon(handle)[1]);
static uint32_t* FN(Addr)(void* extra) {
return (uint32_t*)extra;
}
static uint16_t* FN(Head)(void* extra) {
return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]);
}
static uint8_t* FN(TinyHash)(void* extra) {
return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]);
}
static FN(Bank)* FN(Banks)(void* extra) {
return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]);
}
static void FN(Initialize)(
HasherHandle handle, const BrotliEncoderParams* params) {
FN(Self)(handle)->max_hops =
(params->quality > 6 ? 7u : 8u) << (params->quality - 4);
HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common = common;
self->extra = common->extra;
self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
}
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* data) {
HashForgetfulChain* self = FN(Self)(handle);
static void FN(Prepare)(
HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
if (one_shot && input_size <= partial_prepare_threshold) {
@@ -74,17 +102,17 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
for (i = 0; i < input_size; ++i) {
size_t bucket = FN(HashBytes)(&data[i]);
/* See InitEmpty comment. */
self->addr[bucket] = 0xCCCCCCCC;
self->head[bucket] = 0xCCCC;
addr[bucket] = 0xCCCCCCCC;
head[bucket] = 0xCCCC;
}
} else {
/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
processed by hasher never reaches 3GB + 64M; this makes all new chains
to be terminated after the first node. */
memset(self->addr, 0xCC, sizeof(self->addr));
memset(self->head, 0, sizeof(self->head));
memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE);
}
memset(self->tiny_hash, 0, sizeof(self->tiny_hash));
memset(tiny_hash, 0, sizeof(uint8_t) * 65536);
memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
}
@@ -94,51 +122,58 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
BROTLI_UNUSED(params);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(HashForgetfulChain);
return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE +
sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS;
}
/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
node to corresponding chain; also update tiny_hash for current position. */
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
HashForgetfulChain* self = FN(Self)(handle);
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
const size_t key = FN(HashBytes)(&data[ix & mask]);
const size_t bank = key & (NUM_BANKS - 1);
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
size_t delta = ix - self->addr[key];
self->tiny_hash[(uint16_t)ix] = (uint8_t)key;
size_t delta = ix - addr[key];
tiny_hash[(uint16_t)ix] = (uint8_t)key;
if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
self->banks[bank].slots[idx].delta = (uint16_t)delta;
self->banks[bank].slots[idx].next = self->head[key];
self->addr[key] = (uint32_t)ix;
self->head[key] = (uint16_t)idx;
banks[bank].slots[idx].delta = (uint16_t)delta;
banks[bank].slots[idx].next = head[key];
addr[key] = (uint32_t)ix;
head[key] = (uint16_t)idx;
}
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix_start,
const size_t ix_end) {
static BROTLI_INLINE void FN(StoreRange)(
HashForgetfulChain* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(handle, data, mask, i);
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashForgetfulChain* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ring_buffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 3);
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 2);
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 1);
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(handle);
HashForgetfulChain* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(self);
PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
}
@@ -153,14 +188,18 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
Does not look for matches further away than max_backward.
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
static BROTLI_INLINE void FN(FindLongestMatch)(
HashForgetfulChain* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache,
const size_t cur_ix, const size_t max_length, const size_t max_backward,
const size_t gap, const size_t max_distance,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
HashForgetfulChain* self = FN(Self)(handle);
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra);
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
/* Don't accept a short copy from far away. */
score_t min_score = out->score;
@@ -176,7 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
const size_t backward = (size_t)distance_cache[i];
size_t prev_ix = (cur_ix - backward);
/* For distance code 0 we want to consider 2-byte matches. */
if (i > 0 && self->tiny_hash[(uint16_t)prev_ix] != tiny_hash) continue;
if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue;
if (prev_ix >= cur_ix || backward > max_backward) {
continue;
}
@@ -204,16 +243,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
const size_t bank = key & (NUM_BANKS - 1);
size_t backward = 0;
size_t hops = self->max_hops;
size_t delta = cur_ix - self->addr[key];
size_t slot = self->head[key];
size_t delta = cur_ix - addr[key];
size_t slot = head[key];
while (hops--) {
size_t prev_ix;
size_t last = slot;
backward += delta;
if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
prev_ix = (cur_ix - backward) & ring_buffer_mask;
slot = self->banks[bank].slots[last].next;
delta = self->banks[bank].slots[last].delta;
slot = banks[bank].slots[last].next;
delta = banks[bank].slots[last].delta;
if (cur_ix_masked + best_len > ring_buffer_mask ||
prev_ix + best_len > ring_buffer_mask ||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
@@ -238,11 +277,11 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
}
}
}
FN(Store)(handle, data, ring_buffer_mask, cur_ix);
FN(Store)(self, data, ring_buffer_mask, cur_ix);
}
if (out->score == min_score) {
SearchInStaticDictionary(dictionary,
handle, &data[cur_ix_masked], max_length, max_backward + gap,
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_FALSE);
}
}
+50 -50
View File
@@ -20,7 +20,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
/* HashBytes is the function that chooses the bucket to place the address in. */
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* data,
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
const uint64_t mask,
const int shift) {
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
@@ -42,43 +42,43 @@ typedef struct HashLongestMatch {
/* Mask for accessing entries in a block (in a ring-buffer manner). */
uint32_t block_mask_;
int block_bits_;
int num_last_distances_to_check_;
/* Shortcuts. */
HasherCommon* common_;
/* --- Dynamic size members --- */
/* Number of entries in a particular bucket. */
/* uint16_t num[bucket_size]; */
uint16_t* num_; /* uint16_t[bucket_size]; */
/* Buckets containing block_size_ of backward references. */
/* uint32_t* buckets[bucket_size * block_size]; */
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
} HashLongestMatch;
static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
}
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
return (uint16_t*)(&self[1]);
}
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
}
static void FN(Initialize)(
HasherHandle handle, const BrotliEncoderParams* params) {
HasherCommon* common = GetHasherCommon(handle);
HashLongestMatch* self = FN(Self)(handle);
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common_ = common;
BROTLI_UNUSED(params);
self->hash_shift_ = 64 - common->params.bucket_bits;
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
self->block_bits_ = common->params.block_bits;
self->block_size_ = (size_t)1 << common->params.block_bits;
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
self->num_last_distances_to_check_ =
common->params.num_last_distances_to_check;
self->num_ = (uint16_t*)common->extra;
self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
}
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* data) {
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
static void FN(Prepare)(
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint16_t* BROTLI_RESTRICT num = self->num_;
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
if (one_shot && input_size <= partial_prepare_threshold) {
@@ -100,50 +100,52 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
size_t block_size = (size_t)1 << params->hasher.block_bits;
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
return sizeof(uint16_t) * bucket_size +
sizeof(uint32_t) * bucket_size * block_size;
}
/* Look at 4 bytes at &data[ix & mask].
Compute a hash from these, and store the value of ix at that position. */
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
static BROTLI_INLINE void FN(Store)(
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix) {
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
uint16_t* BROTLI_RESTRICT num = self->num_;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
self->hash_shift_);
const size_t minor_ix = num[key] & self->block_mask_;
const size_t offset =
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
FN(Buckets)(self)[offset] = (uint32_t)ix;
const size_t offset = minor_ix + (key << self->block_bits_);
++num[key];
buckets[offset] = (uint32_t)ix;
}
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix_start,
const size_t ix_end) {
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(handle, data, mask, i);
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashLongestMatch* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
PrepareDistanceCache(distance_cache,
GetHasherCommon(handle)->params.num_last_distances_to_check);
HashLongestMatch* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
}
/* Find a longest backward match of &data[cur_ix] up to the length of
@@ -157,17 +159,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
Does not look for matches further away than max_backward.
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
static BROTLI_INLINE void FN(FindLongestMatch)(
HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t gap, const size_t max_distance,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
HasherCommon* common = GetHasherCommon(handle);
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
uint32_t* buckets = FN(Buckets)(self);
uint16_t* BROTLI_RESTRICT num = self->num_;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
/* Don't accept a short copy from far away. */
score_t min_score = out->score;
@@ -177,7 +178,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
out->len = 0;
out->len_code_delta = 0;
/* Try last distance first. */
for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
const size_t backward = (size_t)distance_cache[i];
size_t prev_ix = (size_t)(cur_ix - backward);
if (prev_ix >= cur_ix) {
@@ -218,8 +219,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
{
const uint32_t key = FN(HashBytes)(
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
uint32_t* BROTLI_RESTRICT bucket =
&buckets[key << common->params.block_bits];
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
const size_t down =
(num[key] > self->block_size_) ?
(num[key] - self->block_size_) : 0u;
@@ -259,7 +259,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
}
if (min_score == out->score) {
SearchInStaticDictionary(dictionary,
handle, &data[cur_ix_masked], max_length, max_backward + gap,
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_FALSE);
}
}
+53 -50
View File
@@ -20,7 +20,8 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
/* HashBytes is the function that chooses the bucket to place the address in. */
static uint32_t FN(HashBytes)(const uint8_t* data, const int shift) {
static uint32_t FN(HashBytes)(
const uint8_t* BROTLI_RESTRICT data, const int shift) {
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
@@ -38,42 +39,46 @@ typedef struct HashLongestMatch {
/* Mask for accessing entries in a block (in a ring-buffer manner). */
uint32_t block_mask_;
int block_bits_;
int num_last_distances_to_check_;
/* Shortcuts. */
HasherCommon* common_;
/* --- Dynamic size members --- */
/* Number of entries in a particular bucket. */
/* uint16_t num[bucket_size]; */
uint16_t* num_; /* uint16_t[bucket_size]; */
/* Buckets containing block_size_ of backward references. */
/* uint32_t* buckets[bucket_size * block_size]; */
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
} HashLongestMatch;
static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
}
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
return (uint16_t*)(&self[1]);
}
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
return (uint16_t*)extra;
}
static void FN(Initialize)(
HasherHandle handle, const BrotliEncoderParams* params) {
HasherCommon* common = GetHasherCommon(handle);
HashLongestMatch* self = FN(Self)(handle);
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common_ = common;
BROTLI_UNUSED(params);
self->hash_shift_ = 32 - common->params.bucket_bits;
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
self->block_size_ = (size_t)1 << common->params.block_bits;
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
self->num_ = (uint16_t*)common->extra;
self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
self->block_bits_ = common->params.block_bits;
self->num_last_distances_to_check_ =
common->params.num_last_distances_to_check;
}
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* data) {
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
static void FN(Prepare)(
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint16_t* BROTLI_RESTRICT num = self->num_;
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
if (one_shot && input_size <= partial_prepare_threshold) {
@@ -94,49 +99,49 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
size_t block_size = (size_t)1 << params->hasher.block_bits;
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
return sizeof(uint16_t) * bucket_size +
sizeof(uint32_t) * bucket_size * block_size;
}
/* Look at 4 bytes at &data[ix & mask].
Compute a hash from these, and store the value of ix at that position. */
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
static BROTLI_INLINE void FN(Store)(
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix) {
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
const size_t minor_ix = num[key] & self->block_mask_;
const size_t offset =
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
FN(Buckets)(self)[offset] = (uint32_t)ix;
++num[key];
const size_t minor_ix = self->num_[key] & self->block_mask_;
const size_t offset = minor_ix + (key << self->block_bits_);
self->buckets_[offset] = (uint32_t)ix;
++self->num_[key];
}
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix_start,
const size_t ix_end) {
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(handle, data, mask, i);
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashLongestMatch* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
PrepareDistanceCache(distance_cache,
GetHasherCommon(handle)->params.num_last_distances_to_check);
HashLongestMatch* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
}
/* Find a longest backward match of &data[cur_ix] up to the length of
@@ -150,17 +155,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
Does not look for matches further away than max_backward.
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
static BROTLI_INLINE void FN(FindLongestMatch)(
HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t gap, const size_t max_distance,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
HasherCommon* common = GetHasherCommon(handle);
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
uint32_t* buckets = FN(Buckets)(self);
uint16_t* BROTLI_RESTRICT num = self->num_;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
/* Don't accept a short copy from far away. */
score_t min_score = out->score;
@@ -170,7 +174,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
out->len = 0;
out->len_code_delta = 0;
/* Try last distance first. */
for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
const size_t backward = (size_t)distance_cache[i];
size_t prev_ix = (size_t)(cur_ix - backward);
if (prev_ix >= cur_ix) {
@@ -211,8 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
{
const uint32_t key =
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
uint32_t* BROTLI_RESTRICT bucket =
&buckets[key << common->params.block_bits];
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
const size_t down =
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
for (i = num[key]; i > down;) {
@@ -251,7 +254,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
}
if (min_score == out->score) {
SearchInStaticDictionary(dictionary,
handle, &data[cur_ix_masked], max_length, max_backward + gap,
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_FALSE);
}
}
@@ -5,15 +5,16 @@
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP, HASH_LEN,
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN,
USE_DICTIONARY
*/
#define HashLongestMatchQuickly HASHER()
#define BUCKET_SIZE (1 << BUCKET_BITS)
#define HASH_MAP_SIZE (4 << BUCKET_BITS)
#define BUCKET_MASK (BUCKET_SIZE - 1)
#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS)
#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3)
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
@@ -32,39 +33,50 @@ static uint32_t FN(HashBytes)(const uint8_t* data) {
/* A (forgetful) hash table to the data seen by the compressor, to
help create backward references to previous data.
This is a hash map of fixed size (BUCKET_SIZE). Starting from the
given index, BUCKET_SWEEP buckets are used to store values of a key. */
This is a hash map of fixed size (BUCKET_SIZE). */
typedef struct HashLongestMatchQuickly {
uint32_t buckets_[BUCKET_SIZE + BUCKET_SWEEP];
/* Shortcuts. */
HasherCommon* common;
/* --- Dynamic size members --- */
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
} HashLongestMatchQuickly;
static BROTLI_INLINE HashLongestMatchQuickly* FN(Self)(HasherHandle handle) {
return (HashLongestMatchQuickly*)&(GetHasherCommon(handle)[1]);
}
static void FN(Initialize)(
HasherHandle handle, const BrotliEncoderParams* params) {
BROTLI_UNUSED(handle);
HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common = common;
BROTLI_UNUSED(params);
self->buckets_ = (uint32_t*)common->extra;
}
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* data) {
HashLongestMatchQuickly* self = FN(Self)(handle);
static void FN(Prepare)(
HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = HASH_MAP_SIZE >> 7;
size_t partial_prepare_threshold = BUCKET_SIZE >> 5;
if (one_shot && input_size <= partial_prepare_threshold) {
size_t i;
for (i = 0; i < input_size; ++i) {
const uint32_t key = FN(HashBytes)(&data[i]);
memset(&self->buckets_[key], 0, BUCKET_SWEEP * sizeof(self->buckets_[0]));
if (BUCKET_SWEEP == 1) {
buckets[key] = 0;
} else {
uint32_t j;
for (j = 0; j < BUCKET_SWEEP; ++j) {
buckets[(key + (j << 3)) & BUCKET_MASK] = 0;
}
}
}
} else {
/* It is not strictly necessary to fill this buffer here, but
not filling will make the results of the compression stochastic
(but correct). This is because random data would cause the
system to find accidentally good backward references here and there. */
memset(&self->buckets_[0], 0, sizeof(self->buckets_));
memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE);
}
}
@@ -74,45 +86,53 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
BROTLI_UNUSED(params);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(HashLongestMatchQuickly);
return sizeof(uint32_t) * BUCKET_SIZE;
}
/* Look at 5 bytes at &data[ix & mask].
Compute a hash from these, and store the value somewhere within
[ix .. ix+3]. */
static BROTLI_INLINE void FN(Store)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix) {
static BROTLI_INLINE void FN(Store)(
HashLongestMatchQuickly* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
const uint32_t key = FN(HashBytes)(&data[ix & mask]);
/* Wiggle the value with the bucket sweep range. */
const uint32_t off = (ix >> 3) % BUCKET_SWEEP;
FN(Self)(handle)->buckets_[key + off] = (uint32_t)ix;
if (BUCKET_SWEEP == 1) {
self->buckets_[key] = (uint32_t)ix;
} else {
/* Wiggle the value with the bucket sweep range. */
const uint32_t off = ix & BUCKET_SWEEP_MASK;
self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix;
}
}
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix_start,
const size_t ix_end) {
static BROTLI_INLINE void FN(StoreRange)(
HashLongestMatchQuickly* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(handle, data, mask, i);
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HasherHandle handle, size_t num_bytes, size_t position,
HashLongestMatchQuickly* BROTLI_RESTRICT self,
size_t num_bytes, size_t position,
const uint8_t* ringbuffer, size_t ringbuffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(handle);
HashLongestMatchQuickly* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(self);
BROTLI_UNUSED(distance_cache);
}
@@ -125,17 +145,19 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(
HasherHandle handle, const BrotliEncoderDictionary* dictionary,
HashLongestMatchQuickly* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data,
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
const size_t cur_ix, const size_t max_length, const size_t max_backward,
const size_t gap, const size_t max_distance,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
HashLongestMatchQuickly* self = FN(Self)(handle);
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const size_t best_len_in = out->len;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
int compare_char = data[cur_ix_masked + best_len_in];
size_t key = FN(HashBytes)(&data[cur_ix_masked]);
size_t key_out;
score_t min_score = out->score;
score_t best_score = out->score;
size_t best_len = best_len_in;
@@ -145,21 +167,21 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
if (prev_ix < cur_ix) {
prev_ix &= (uint32_t)ring_buffer_mask;
if (compare_char == data[prev_ix + best_len]) {
size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
const size_t len = FindMatchLengthWithLimit(
&data[prev_ix], &data[cur_ix_masked], max_length);
if (len >= 4) {
const score_t score = BackwardReferenceScoreUsingLastDistance(len);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = len;
out->distance = cached_backward;
out->score = best_score;
compare_char = data[cur_ix_masked + best_len];
out->score = score;
if (BUCKET_SWEEP == 1) {
self->buckets_[key] = (uint32_t)cur_ix;
buckets[key] = (uint32_t)cur_ix;
return;
} else {
best_len = len;
best_score = score;
compare_char = data[cur_ix_masked + len];
}
}
}
@@ -169,8 +191,8 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
size_t backward;
size_t len;
/* Only one to look for, don't bother to prepare for a loop. */
prev_ix = self->buckets_[key];
self->buckets_[key] = (uint32_t)cur_ix;
prev_ix = buckets[key];
buckets[key] = (uint32_t)cur_ix;
backward = cur_ix - prev_ix;
prev_ix &= (uint32_t)ring_buffer_mask;
if (compare_char != data[prev_ix + best_len_in]) {
@@ -192,12 +214,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
}
}
} else {
uint32_t* bucket = self->buckets_ + key;
int i;
prev_ix = *bucket++;
for (i = 0; i < BUCKET_SWEEP; ++i, prev_ix = *bucket++) {
const size_t backward = cur_ix - prev_ix;
size_t keys[BUCKET_SWEEP];
size_t i;
for (i = 0; i < BUCKET_SWEEP; ++i) {
keys[i] = (key + (i << 3)) & BUCKET_MASK;
}
key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
for (i = 0; i < BUCKET_SWEEP; ++i) {
size_t len;
size_t backward;
prev_ix = buckets[keys[i]];
backward = cur_ix - prev_ix;
prev_ix &= (uint32_t)ring_buffer_mask;
if (compare_char != data[prev_ix + best_len]) {
continue;
@@ -211,25 +238,29 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
if (len >= 4) {
const score_t score = BackwardReferenceScore(len, backward);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->len = len;
compare_char = data[cur_ix_masked + len];
best_score = score;
out->score = score;
compare_char = data[cur_ix_masked + best_len];
out->distance = backward;
}
}
}
}
if (USE_DICTIONARY && min_score == out->score) {
SearchInStaticDictionary(dictionary,
handle, &data[cur_ix_masked], max_length, max_backward + gap,
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_TRUE);
}
self->buckets_[key + ((cur_ix >> 3) % BUCKET_SWEEP)] = (uint32_t)cur_ix;
if (BUCKET_SWEEP != 1) {
buckets[key_out] = (uint32_t)cur_ix;
}
}
#undef HASH_MAP_SIZE
#undef BUCKET_SWEEP_MASK
#undef BUCKET_SWEEP
#undef BUCKET_MASK
#undef BUCKET_SIZE
#undef HashLongestMatchQuickly
+23 -27
View File
@@ -51,13 +51,9 @@ typedef struct HashRolling {
uint32_t factor_remove;
} HashRolling;
static BROTLI_INLINE HashRolling* FN(Self)(HasherHandle handle) {
return (HashRolling*)&(GetHasherCommon(handle)[1]);
}
static void FN(Initialize)(
HasherHandle handle, const BrotliEncoderParams* params) {
HashRolling* self = FN(Self)(handle);
HasherCommon* common, HashRolling* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
size_t i;
self->state = 0;
self->next_ix = 0;
@@ -71,7 +67,7 @@ static void FN(Initialize)(
self->factor_remove *= self->factor;
}
self->table = (uint32_t*)((HasherHandle)self + sizeof(HashRolling));
self->table = (uint32_t*)common->extra;
for (i = 0; i < NUMBUCKETS; i++) {
self->table[i] = FN(kInvalidPos);
}
@@ -79,9 +75,8 @@ static void FN(Initialize)(
BROTLI_UNUSED(params);
}
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* data) {
HashRolling* self = FN(Self)(handle);
static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
size_t i;
/* Too small size, cannot use this hasher. */
if (input_size < CHUNKLEN) return;
@@ -96,36 +91,36 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
return sizeof(HashRolling) + NUMBUCKETS * sizeof(uint32_t);
return NUMBUCKETS * sizeof(uint32_t);
BROTLI_UNUSED(params);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
}
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
BROTLI_UNUSED(handle);
BROTLI_UNUSED(self);
BROTLI_UNUSED(data);
BROTLI_UNUSED(mask);
BROTLI_UNUSED(ix);
}
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix_start,
const size_t ix_end) {
BROTLI_UNUSED(handle);
static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
BROTLI_UNUSED(self);
BROTLI_UNUSED(data);
BROTLI_UNUSED(mask);
BROTLI_UNUSED(ix_start);
BROTLI_UNUSED(ix_end);
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashRolling* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ring_buffer_mask) {
/* In this case we must re-initialize the hasher from scratch from the
current position. */
HashRolling* self = FN(Self)(handle);
size_t position_masked;
size_t available = num_bytes;
if ((position & (JUMP - 1)) != 0) {
@@ -139,28 +134,29 @@ static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
available = ring_buffer_mask - position_masked;
}
FN(Prepare)(handle, BROTLI_FALSE, available,
FN(Prepare)(self, BROTLI_FALSE, available,
ringbuffer + (position & ring_buffer_mask));
self->next_ix = position;
BROTLI_UNUSED(num_bytes);
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(handle);
HashRolling* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(self);
BROTLI_UNUSED(distance_cache);
}
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
static BROTLI_INLINE void FN(FindLongestMatch)(
HashRolling* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t gap, const size_t max_distance,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
HashRolling* self = FN(Self)(handle);
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
size_t pos = self->next_ix;
size_t pos;
if ((cur_ix & (JUMP - 1)) != 0) return;
@@ -209,7 +205,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
backup-hasher, the main hasher already searches in it. */
BROTLI_UNUSED(dictionary);
BROTLI_UNUSED(distance_cache);
BROTLI_UNUSED(gap);
BROTLI_UNUSED(dictionary_distance);
BROTLI_UNUSED(max_distance);
}
+39 -38
View File
@@ -24,7 +24,7 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
return MAX_TREE_COMP_LENGTH;
}
static uint32_t FN(HashBytes)(const uint8_t* data) {
static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
@@ -38,7 +38,7 @@ typedef struct HashToBinaryTree {
/* Hash table that maps the 4-byte hashes of the sequence to the last
position where this hash was found, which is the root of the binary
tree of sequences that share this hash bucket. */
uint32_t buckets_[BUCKET_SIZE];
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
/* A position used to mark a non-existent sequence, i.e. a tree is empty if
its root is at invalid_pos_ and a node is a leaf if both its children
@@ -51,34 +51,30 @@ typedef struct HashToBinaryTree {
corresponding to a hash is a sequence starting at buckets_[hash] and
the left and right children of a sequence starting at pos are
forest_[2 * pos] and forest_[2 * pos + 1]. */
/* uint32_t forest[2 * num_nodes] */
uint32_t* forest_; /* uint32_t[2 * num_nodes] */
} HashToBinaryTree;
static BROTLI_INLINE HashToBinaryTree* FN(Self)(HasherHandle handle) {
return (HashToBinaryTree*)&(GetHasherCommon(handle)[1]);
}
static BROTLI_INLINE uint32_t* FN(Forest)(HashToBinaryTree* self) {
return (uint32_t*)(&self[1]);
}
static void FN(Initialize)(
HasherHandle handle, const BrotliEncoderParams* params) {
HashToBinaryTree* self = FN(Self)(handle);
HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->buckets_ = (uint32_t*)common->extra;
self->forest_ = &self->buckets_[BUCKET_SIZE];
self->window_mask_ = (1u << params->lgwin) - 1u;
self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
}
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* data) {
HashToBinaryTree* self = FN(Self)(handle);
static void FN(Prepare)
(HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint32_t invalid_pos = self->invalid_pos_;
uint32_t i;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
BROTLI_UNUSED(data);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
for (i = 0; i < BUCKET_SIZE; i++) {
self->buckets_[i] = invalid_pos;
buckets[i] = invalid_pos;
}
}
@@ -89,15 +85,17 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
if (one_shot && input_size < num_nodes) {
num_nodes = input_size;
}
return sizeof(HashToBinaryTree) + 2 * sizeof(uint32_t) * num_nodes;
return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes;
}
static BROTLI_INLINE size_t FN(LeftChildIndex)(HashToBinaryTree* self,
static BROTLI_INLINE size_t FN(LeftChildIndex)(
HashToBinaryTree* BROTLI_RESTRICT self,
const size_t pos) {
return 2 * (pos & self->window_mask_);
}
static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self,
static BROTLI_INLINE size_t FN(RightChildIndex)(
HashToBinaryTree* BROTLI_RESTRICT self,
const size_t pos) {
return 2 * (pos & self->window_mask_) + 1;
}
@@ -113,7 +111,7 @@ static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self,
This function must be called with increasing cur_ix positions. */
static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
HashToBinaryTree* self, const uint8_t* const BROTLI_RESTRICT data,
HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,
const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
BackwardMatch* BROTLI_RESTRICT matches) {
@@ -123,8 +121,9 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
const BROTLI_BOOL should_reroot_tree =
TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
uint32_t* forest = FN(Forest)(self);
size_t prev_ix = self->buckets_[key];
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
uint32_t* BROTLI_RESTRICT forest = self->forest_;
size_t prev_ix = buckets[key];
/* The forest index of the rightmost node of the left subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t node_left = FN(LeftChildIndex)(self, cur_ix);
@@ -139,7 +138,7 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
size_t best_len_right = 0;
size_t depth_remaining;
if (should_reroot_tree) {
self->buckets_[key] = (uint32_t)cur_ix;
buckets[key] = (uint32_t)cur_ix;
}
for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {
const size_t backward = cur_ix - prev_ix;
@@ -199,11 +198,13 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
matches in matches[0] to matches[*num_matches - 1]. The matches will be
sorted by strictly increasing length and (non-strictly) increasing
distance. */
static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
static BROTLI_INLINE size_t FN(FindAllMatches)(
HashToBinaryTree* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data,
const size_t ring_buffer_mask, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t gap, const BrotliEncoderParams* params,
const size_t dictionary_distance, const BrotliEncoderParams* params,
BackwardMatch* matches) {
BackwardMatch* const orig_matches = matches;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
@@ -236,7 +237,7 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
}
}
if (best_len < max_length) {
matches = FN(StoreAndFindMatches)(FN(Self)(handle), data, cur_ix,
matches = FN(StoreAndFindMatches)(self, data, cur_ix,
ring_buffer_mask, max_length, max_backward, &best_len, matches);
}
for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
@@ -252,7 +253,7 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
for (l = minlen; l <= maxlen; ++l) {
uint32_t dict_id = dict_matches[l];
if (dict_id < kInvalidMatch) {
size_t distance = max_backward + gap + (dict_id >> 5) + 1;
size_t distance = dictionary_distance + (dict_id >> 5) + 1;
if (distance <= params->dist.max_distance) {
InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
}
@@ -266,18 +267,18 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
current sequence, without returning any matches.
REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix) {
HashToBinaryTree* self = FN(Self)(handle);
/* Maximum distance is window size - 16, see section 9.1. of the spec. */
const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
max_backward, NULL, NULL);
}
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
const uint8_t* data, const size_t mask, const size_t ix_start,
const size_t ix_end) {
static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i = ix_start;
size_t j = ix_start;
if (ix_start + 63 <= ix_end) {
@@ -285,18 +286,18 @@ static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
}
if (ix_start + 512 <= i) {
for (; j < i; j += 8) {
FN(Store)(handle, data, mask, j);
FN(Store)(self, data, mask, j);
}
}
for (; i < ix_end; ++i) {
FN(Store)(handle, data, mask, i);
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashToBinaryTree* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask) {
HashToBinaryTree* self = FN(Self)(handle);
if (num_bytes >= FN(HashTypeLength)() - 1 &&
position >= MAX_TREE_COMP_LENGTH) {
/* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
+24 -12
View File
@@ -56,6 +56,18 @@ BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p);
#define BROTLI_IS_OOM(M) (!!(M)->is_oom)
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
/*
BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting.
The only purpose of it is to explain static analyzers the state of things.
NB: use ONLY together with BROTLI_IS_OOM
AND ONLY for allocations in the current scope.
*/
#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM)
#define BROTLI_IS_NULL(A) ((A) == nullptr)
#else /* defined(__clang_analyzer__) */
#define BROTLI_IS_NULL(A) (!!0)
#endif /* defined(__clang_analyzer__) */
BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
/*
@@ -66,18 +78,18 @@ A: array
C: capacity
R: requested size
*/
#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \
if (C < (R)) { \
size_t _new_size = (C == 0) ? (R) : C; \
T* new_array; \
while (_new_size < (R)) _new_size *= 2; \
new_array = BROTLI_ALLOC((M), T, _new_size); \
if (!BROTLI_IS_OOM(M) && C != 0) \
memcpy(new_array, A, C * sizeof(T)); \
BROTLI_FREE((M), A); \
A = new_array; \
C = _new_size; \
} \
#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \
if (C < (R)) { \
size_t _new_size = (C == 0) ? (R) : C; \
T* new_array; \
while (_new_size < (R)) _new_size *= 2; \
new_array = BROTLI_ALLOC((M), T, _new_size); \
if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \
memcpy(new_array, A, C * sizeof(T)); \
BROTLI_FREE((M), A); \
A = new_array; \
C = _new_size; \
} \
}
/*
+23 -27
View File
@@ -28,34 +28,30 @@ extern "C" {
void BrotliInitDistanceParams(BrotliEncoderParams* params,
uint32_t npostfix, uint32_t ndirect) {
BrotliDistanceParams* dist_params = &params->dist;
uint32_t alphabet_size, max_distance;
uint32_t alphabet_size_max;
uint32_t alphabet_size_limit;
uint32_t max_distance;
dist_params->distance_postfix_bits = npostfix;
dist_params->num_direct_distance_codes = ndirect;
alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
alphabet_size_limit = alphabet_size_max;
max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
(1U << (npostfix + 2));
if (params->large_window) {
static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
uint32_t postfix = 1U << npostfix;
alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
/* The maximum distance is set so that no distance symbol used can encode
a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all
its extra bits set. */
if (ndirect < bound[npostfix]) {
max_distance = BROTLI_MAX_ALLOWED_DISTANCE - (bound[npostfix] - ndirect);
} else if (ndirect >= bound[npostfix] + postfix) {
max_distance = (3U << 29) - 4 + (ndirect - bound[npostfix]);
} else {
max_distance = BROTLI_MAX_ALLOWED_DISTANCE;
}
alphabet_size_limit = limit.max_alphabet_size;
max_distance = limit.max_distance;
}
dist_params->alphabet_size = alphabet_size;
dist_params->alphabet_size_max = alphabet_size_max;
dist_params->alphabet_size_limit = alphabet_size_limit;
dist_params->max_distance = max_distance;
}
@@ -200,7 +196,7 @@ void BrotliBuildMetaBlock(MemoryManager* m,
literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
literal_context_modes =
BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
for (i = 0; i < mb->literal_split.num_types; ++i) {
literal_context_modes[i] = literal_context_mode;
}
@@ -210,21 +206,21 @@ void BrotliBuildMetaBlock(MemoryManager* m,
mb->literal_split.num_types * literal_context_multiplier;
literal_histograms =
BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
distance_histograms_size =
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
distance_histograms =
BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
ClearHistogramsDistance(distance_histograms, distance_histograms_size);
BROTLI_DCHECK(mb->command_histograms == 0);
mb->command_histograms_size = mb->command_split.num_types;
mb->command_histograms =
BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
BrotliBuildHistogramsWithContext(cmds, num_commands,
@@ -238,13 +234,13 @@ void BrotliBuildMetaBlock(MemoryManager* m,
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
mb->literal_context_map =
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
BROTLI_DCHECK(mb->literal_histograms == 0);
mb->literal_histograms_size = mb->literal_context_map_size;
mb->literal_histograms =
BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
kMaxNumberOfHistograms, mb->literal_histograms,
@@ -269,13 +265,13 @@ void BrotliBuildMetaBlock(MemoryManager* m,
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
mb->distance_context_map =
BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
BROTLI_DCHECK(mb->distance_histograms == 0);
mb->distance_histograms_size = mb->distance_context_map_size;
mb->distance_histograms =
BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
BrotliClusterHistogramsDistance(m, distance_histograms,
mb->distance_context_map_size,
@@ -373,7 +369,7 @@ static void InitContextBlockSplitter(
*histograms_size = max_num_types * num_contexts;
*histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
self->histograms_ = *histograms;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
/* Clear only current histogram. */
ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
@@ -423,7 +419,7 @@ static void ContextBlockSplitterFinishBlock(
double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
double diff[2] = { 0.0 };
size_t i;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
for (i = 0; i < num_contexts; ++i) {
size_t curr_histo_ix = self->curr_histogram_ix_ + i;
size_t j;
@@ -527,7 +523,7 @@ static void MapStaticContexts(MemoryManager* m,
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
mb->literal_context_map =
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
for (i = 0; i < mb->literal_split.num_types; ++i) {
uint32_t offset = (uint32_t)(i * num_contexts);
+1 -1
View File
@@ -71,7 +71,7 @@ static void FN(InitBlockSplitter)(
*histograms_size = max_num_types;
*histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size);
self->histograms_ = *histograms;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
/* Clear only current histogram. */
FN(HistogramClear)(&self->histograms_[0]);
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
+3 -1
View File
@@ -23,7 +23,8 @@ typedef struct BrotliHasherParams {
typedef struct BrotliDistanceParams {
uint32_t distance_postfix_bits;
uint32_t num_direct_distance_codes;
uint32_t alphabet_size;
uint32_t alphabet_size_max;
uint32_t alphabet_size_limit;
size_t max_distance;
} BrotliDistanceParams;
@@ -33,6 +34,7 @@ typedef struct BrotliEncoderParams {
int quality;
int lgwin;
int lgblock;
size_t stream_offset;
size_t size_hint;
BROTLI_BOOL disable_literal_context_modeling;
BROTLI_BOOL large_window;
+4 -1
View File
@@ -75,7 +75,7 @@ static BROTLI_INLINE void RingBufferInitBuffer(
uint8_t* new_data = BROTLI_ALLOC(
m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
size_t i;
if (BROTLI_IS_OOM(m)) return;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return;
if (rb->data_) {
memcpy(new_data, rb->data_,
2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
@@ -125,6 +125,9 @@ static BROTLI_INLINE void RingBufferWrite(
later when we copy the last two bytes to the first two positions. */
rb->buffer_[rb->size_ - 2] = 0;
rb->buffer_[rb->size_ - 1] = 0;
/* Initialize tail; might be touched by "best_len++" optimization when
ring buffer is "full". */
rb->buffer_[rb->size_] = 241;
}
{
const size_t masked_pos = rb->pos_ & rb->mask_;
+1 -1
View File
@@ -77,7 +77,7 @@ BROTLI_BOOL BrotliIsMostlyUTF8(
i += bytes_read;
if (symbol < 0x110000) size_utf8 += bytes_read;
}
return TO_BROTLI_BOOL(size_utf8 > min_fraction * (double)length);
return TO_BROTLI_BOOL((double)size_utf8 > min_fraction * (double)length);
}
#if defined(__cplusplus) || defined(c_plusplus)
+27 -25
View File
@@ -16,8 +16,6 @@
extern "C" {
#endif
/*#define BIT_WRITER_DEBUG */
/* This function writes bits into bytes in increasing addresses, and within
a byte least-significant-bit first.
@@ -28,7 +26,7 @@ extern "C" {
0000 0RRR 0000 0000 0000 0000
Now, we could write 5 or less bits in MSB by just sifting by 3
Now, we could write 5 or less bits in MSB by just shifting by 3
and OR'ing to BYTE-0.
For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
@@ -37,37 +35,41 @@ static BROTLI_INLINE void BrotliWriteBits(size_t n_bits,
uint64_t bits,
size_t* BROTLI_RESTRICT pos,
uint8_t* BROTLI_RESTRICT array) {
BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits,
(uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF),
(int)*pos));
BROTLI_DCHECK((bits >> n_bits) == 0);
BROTLI_DCHECK(n_bits <= 56);
#if defined(BROTLI_LITTLE_ENDIAN)
/* This branch of the code can write up to 56 bits at a time,
7 bits are lost by being perhaps already in *p and at least
1 bit is needed to initialize the bit-stream ahead (i.e. if 7
bits are in *p and we write 57 bits, then the next write will
access a byte that was never initialized). */
uint8_t* p = &array[*pos >> 3];
uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */
BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits,
(uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF),
(int)*pos));
BROTLI_DCHECK((bits >> n_bits) == 0);
BROTLI_DCHECK(n_bits <= 56);
v |= bits << (*pos & 7);
BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
*pos += n_bits;
{
uint8_t* p = &array[*pos >> 3];
uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */
v |= bits << (*pos & 7);
BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
*pos += n_bits;
}
#else
/* implicit & 0xFF is assumed for uint8_t arithmetics */
uint8_t* array_pos = &array[*pos >> 3];
const size_t bits_reserved_in_first_byte = (*pos & 7);
size_t bits_left_to_write;
bits <<= bits_reserved_in_first_byte;
*array_pos++ |= (uint8_t)bits;
for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
bits_left_to_write >= 9;
bits_left_to_write -= 8) {
bits >>= 8;
*array_pos++ = (uint8_t)bits;
{
uint8_t* array_pos = &array[*pos >> 3];
const size_t bits_reserved_in_first_byte = (*pos & 7);
size_t bits_left_to_write;
bits <<= bits_reserved_in_first_byte;
*array_pos++ |= (uint8_t)bits;
for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
bits_left_to_write >= 9;
bits_left_to_write -= 8) {
bits >>= 8;
*array_pos++ = (uint8_t)bits;
}
*array_pos = 0;
*pos += n_bits;
}
*array_pos = 0;
*pos += n_bits;
#endif
}
+22 -1
View File
@@ -201,7 +201,23 @@ typedef enum BrotliEncoderParameter {
*
* Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX).
*/
BROTLI_PARAM_NDIRECT = 8
BROTLI_PARAM_NDIRECT = 8,
/**
* Number of bytes of input stream already processed by a different instance.
*
* @note It is important to configure all the encoder instances with same
* parameters (except this one) in order to allow all the encoded parts
* obey the same restrictions implied by header.
*
* If offset is not 0, then stream header is omitted.
* In any case output start is byte aligned, so for proper streams stitching
* "predecessor" stream must be flushed.
*
* Range is not artificially limited, but all the values greater or equal to
* maximal window size have the same effect. Values greater than 2**30 are not
* allowed.
*/
BROTLI_PARAM_STREAM_OFFSET = 9
} BrotliEncoderParameter;
/**
@@ -274,6 +290,11 @@ BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size);
* @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero
* value, then output is guaranteed to be no longer than that.
*
* @note If @p lgwin is greater than ::BROTLI_MAX_WINDOW_BITS then resulting
* stream might be incompatible with RFC 7932; to decode such streams,
* decoder should be configured with
* ::BROTLI_DECODER_PARAM_LARGE_WINDOW = @c 1
*
* @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY
* @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW
* @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE
Loaded 100 of 179 files, more files were not shown because too many files have changed in this diff. Show more